diff --git a/app/(core)/data/articles/inclinedPlane.js b/app/(core)/data/articles/inclinedPlane.js new file mode 100644 index 00000000..9854b189 --- /dev/null +++ b/app/(core)/data/articles/inclinedPlane.js @@ -0,0 +1,130 @@ +import TAGS from "../tags.js"; + +export const inclinedPlaneBlog = { + id: "bb-008", + slug: "mastering-the-inclined-plane", + name: "Friction & Gravity Lab", + desc: "Master the forces of nature. Manipulate gravity, friction, and angles to predict the perfect slide.", + tags: [TAGS.MEDIUM, TAGS.DYNAMICS, TAGS.FORCES, TAGS.FRICTION], + + theory: { + sections: [ + { + title: "Introduction", + blocks: [ + { + type: "paragraph", + text: "An inclined plane is a flat surface tilted at an angle to the horizontal. It is a simple machine that allows objects to be raised or lowered using less force compared to vertical lifting. The motion of an object on an inclined plane is analyzed by resolving gravitational force into components parallel and perpendicular to the surface.", + }, + { + type: "paragraph", + text: "The weight of an object (mg) acts vertically downward. On an incline of angle θ, this force is resolved into two components: one parallel to the slope (mg sin θ), which causes motion, and one perpendicular to the slope (mg cos θ), which is balanced by the normal force.", + }, + ], + }, + + { + title: "Forces on an Inclined Plane", + blocks: [ + { + type: "list", + ordered: false, + items: [ + "Parallel component of gravity: F∥ = mg sin(θ)", + "Perpendicular component of gravity: F⊥ = mg cos(θ)", + "Normal force: N = mg cos(θ)", + "Kinetic friction: fk = μk N = μk mg cos(θ)", + "Static friction (maximum): fs(max) = μs mg cos(θ)", + ], + }, + ], + }, + + { + title: "Equations of Motion", + blocks: [ + { + type: "list", + ordered: false, + items: [ + "Acceleration without friction: a = g sin(θ)", + "Acceleration with friction: a = g (sin(θ) − μ cos(θ))", + "Velocity along the slope: v = a t", + "Distance travelled along the slope: s = ½ a t²", + ], + }, + { + type: "formula", + latex: + "\\begin{aligned} a &= g \\sin\\theta \\\\ a &= g(\\sin\\theta - \\mu \\cos\\theta) \\\\ v &= at \\\\ s &= \\tfrac{1}{2}at^2 \\end{aligned}", + }, + ], + }, + + { + title: "Energy Viewpoint", + blocks: [ + { + type: "paragraph", + text: "From an energy perspective, an inclined plane converts gravitational potential energy into kinetic energy. In the absence of friction, mechanical energy is conserved. When friction is present, some energy is dissipated as heat.", + }, + { + type: "formula", + latex: "U = mgh, \\quad K = \\tfrac{1}{2}mv^2", + }, + { + type: "note", + text: "With friction, the work done by friction reduces the final kinetic energy of the object.", + }, + ], + }, + + { + title: "Angle of Repose", + blocks: [ + { + type: "paragraph", + text: "The angle of repose is the minimum angle of inclination at which an object just begins to slide down the plane. At this angle, the component of gravity parallel to the plane equals the maximum static friction.", + }, + { + type: "formula", + latex: "\\tan\\theta = \\mu_s", + }, + ], + }, + + { + title: "Practical Observations", + blocks: [ + { + type: "list", + ordered: false, + items: [ + "Increasing the angle θ increases acceleration down the slope.", + "Higher friction coefficients reduce acceleration and may prevent motion entirely.", + "An object slides only if mg sin(θ) > μ mg cos(θ).", + "The mechanical advantage of an incline is MA = L / h = 1 / sin(θ).", + ], + }, + ], + }, + + { + title: "Try It Yourself", + blocks: [ + { + type: "callout", + calloutType: "tip", + text: "Set friction to zero and observe uniform acceleration down the slope. Gradually increase friction and note how the acceleration decreases. Adjust the angle to find the angle of repose.", + }, + { + type: "callout", + calloutType: "info", + title: "Interactive Controls", + text: "Change the incline angle to study its effect on acceleration. Adjust the friction coefficient to compare ideal and realistic motion. Enable force guides to visualize gravity, normal force, and friction components.", + }, + ], + }, + ], + }, +}; diff --git a/app/(core)/data/articles/index.js b/app/(core)/data/articles/index.js index 3226ee72..2d7a2272 100644 --- a/app/(core)/data/articles/index.js +++ b/app/(core)/data/articles/index.js @@ -1,4 +1,3 @@ -// (core)/data/articles/index.js import { bouncingBallBlog } from "./physics-bouncing-ball-comprehensive-educational-guide.js"; import { operationVectorsBlog } from "./comprehensive-guide-to-vector-operations.js"; import { ballAcceleratingBlog } from "./ball-uniformly-accelerated-motion.js"; @@ -6,6 +5,7 @@ import { ballFreeFallBlog } from "./ball-free-fall-comprehensive-guide.js"; import { springConnectionBlog } from "./spring-connection.js"; import { pendulumBlog } from "./physics-of-pendulum-explained.js"; import { projectileParabolicBlog } from "./projectile-parabolic-motion.js"; +import { inclinedPlaneBlog } from "./inclinedPlane.js"; export const allBlogs = { [bouncingBallBlog.slug]: bouncingBallBlog, @@ -15,6 +15,7 @@ export const allBlogs = { [springConnectionBlog.slug]: springConnectionBlog, [pendulumBlog.slug]: pendulumBlog, [projectileParabolicBlog.slug]: projectileParabolicBlog, + [inclinedPlaneBlog.slug]: inclinedPlaneBlog, }; export const blogsArray = Object.values(allBlogs); diff --git a/app/(core)/data/blogs [INACTIVE].js b/app/(core)/data/blogs [INACTIVE].js index 02424fd6..c6c6128e 100644 --- a/app/(core)/data/blogs [INACTIVE].js +++ b/app/(core)/data/blogs [INACTIVE].js @@ -1,67 +1,17 @@ -// THIS FILE GOT REPLACED BY NEW SYSTEM FOR BLOG HANDLING: -// check articles/ folder and articles/index.js for more +// ⚠️ DEPRECATED FILE +// This file is no longer used. +// Blog handling has moved to `articles/` and `articles/index.js`. +// Kept only for reference/testing purposes. import TAGS from "./tags.js"; const INACTIVE_BLOGS = [ { - id: 1, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", + id: "inactive-001", + name: "Sample Physics Blog (Inactive)", + desc: "Deprecated example blog used for testing UI components.", + slug: "inactive-sample-blog", tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - isPinned: true, - - theory: { - sections: [ - { - title: "Introduction", - blocks: [ - { - type: "paragraph", - text: "This section demonstrates the physics behind the Bouncing Ball simulation.", - }, - ], - }, - { - title: "Tips and Tricks", - blocks: [ - { - type: "callout", - calloutType: "info", - title: "Did you know", - text: "This simulation is a basic form of motion physics used in most 2D games and animation engines.", - }, - { - type: "callout", - calloutType: "warning", - title: "Common Mistake", - text: "Forgetting to reverse the velocity component upon collision will result in the ball getting stuck at the wall.", - }, - { - type: "callout", - calloutType: "tip", - title: "Try It Yourself!", - text: "Experiment by changing velocity values or ball size to see how motion patterns change.", - }, - { - type: "callout", - calloutType: "success", - title: "Success!", - text: "You've learned the basics of 2D motion and collision handling!", - }, - ], - }, - ], - }, - }, - { - id: 2, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - theory: { sections: [ { @@ -69,36 +19,7 @@ const INACTIVE_BLOGS = [ blocks: [ { type: "paragraph", - text: "This section demonstrates the physics behind the Bouncing Ball simulation.", - }, - ], - }, - { - title: "Tips and Tricks", - blocks: [ - { - type: "callout", - calloutType: "info", - title: "Did you know", - text: "This simulation is a basic form of motion physics used in most 2D games and animation engines.", - }, - { - type: "callout", - calloutType: "warning", - title: "Common Mistake", - text: "Forgetting to reverse the velocity component upon collision will result in the ball getting stuck at the wall.", - }, - { - type: "callout", - calloutType: "tip", - title: "Try It Yourself!", - text: "Experiment by changing velocity values or ball size to see how motion patterns change.", - }, - { - type: "callout", - calloutType: "success", - title: "Success!", - text: "You've learned the basics of 2D motion and collision handling!", + text: "This is a deprecated blog example retained only for reference.", }, ], }, @@ -107,87 +28,11 @@ const INACTIVE_BLOGS = [ }, { - id: 3, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - - theory: {}, - }, - { - id: 4, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - - theory: {}, - }, - { - id: 5, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - - theory: {}, - }, - { - id: 3, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - isPinned: true, - - theory: {}, - }, - { - id: 4, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - isPinned: true, - - theory: {}, - }, - { - id: 5, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - isPinned: true, - - theory: {}, - }, - { - id: 3, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - - theory: {}, - }, - { - id: 4, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - - theory: {}, - }, - { - id: 5, - name: "Blog Test", - desc: "This is a blog example.", - slug: "this-is-a-blog-example", - tags: [TAGS.EASY, TAGS.PHYSICS, TAGS.COLLISION, TAGS.ANIMATIONS], - + id: "inactive-002", + name: "Empty Blog Shell", + desc: "Placeholder blog with no theory content.", + slug: "inactive-empty-blog", + tags: [TAGS.MEDIUM, TAGS.DYNAMICS], theory: {}, }, ]; diff --git a/app/(core)/data/chapters.js b/app/(core)/data/chapters.js index afb525b7..8341156b 100644 --- a/app/(core)/data/chapters.js +++ b/app/(core)/data/chapters.js @@ -66,11 +66,12 @@ const chapters = [ }, { id: 8, - name: "Inclined Plane", - desc: "Block sliding on an inclined plane.", + name: "Friction & Gravity Lab", + desc: "Master the forces of nature. Manipulate gravity, friction, and angles to predict the perfect slide.", link: "/simulations/InclinedPlane", tags: [TAGS.MEDIUM, TAGS.DYNAMICS, TAGS.FORCES, TAGS.FRICTION], icon: "/icons/inclined.png", + relatedBlogSlug: "mastering-the-inclined-plane", }, { id: 0, diff --git a/app/(pages)/blog/[slug]/page.jsx b/app/(pages)/blog/[slug]/page.jsx index 521deb74..d875c692 100644 --- a/app/(pages)/blog/[slug]/page.jsx +++ b/app/(pages)/blog/[slug]/page.jsx @@ -22,13 +22,25 @@ export async function generateStaticParams() { } export async function generateMetadata({ params }) { - const { slug } = await params; + const { slug } = params; const blog = blogsArray.find((b) => b.slug === slug); + if (!blog) return { title: "Blog Not Found" }; return { title: blog.name, description: blog.desc, + + keywords: [ + "Physics", + "PhysicsHub", + "Inclined Plane", + "Physics concepts", + "Physics tutorial", + "Physics students", + ...(blog.tags || []), + ], + openGraph: { title: blog.name, description: blog.desc, diff --git a/package-lock.json b/package-lock.json index a33dda26..b0a95d75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -400,18 +400,6 @@ "node": ">=6.9.0" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -14899,21 +14887,6 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", diff --git a/public/screenshots/inclined_plane_blog/main.png b/public/screenshots/inclined_plane_blog/main.png new file mode 100644 index 00000000..e69de29b diff --git a/public/sitemap.xml b/public/sitemap.xml index ed6f324e..d7cd07fa 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -100,4 +100,9 @@ monthly 0.8 + + https://physicshub.github.io/blog/inclinedPlane + monthly + 0.8 + \ No newline at end of file diff --git a/routes.js b/routes.js index 68ee0f30..9f7b2d39 100644 --- a/routes.js +++ b/routes.js @@ -1,3 +1,5 @@ +import path from "path"; + // routes.js export const routes = [ { path: "/", component: "Home", changefreq: "weekly", priority: 1.0 }, @@ -63,4 +65,10 @@ export const routes = [ changefreq: "weekly", priority: 0.7, }, + { + path: "/blog/:slug", + component: "BlogPost", + changefreq: "weekly", + priority: 0.8, + }, ];