From 57f35408340eea689792cb64de094ef10f80a54f Mon Sep 17 00:00:00 2001 From: Ameya Shenoy Date: Thu, 5 Jun 2025 02:17:50 +0530 Subject: [PATCH] feat: considerable progress Signed-off-by: Ameya Shenoy --- frontend/package-lock.json | 7 + frontend/package.json | 1 + frontend/src/app/blog/page.tsx | 2 +- frontend/src/app/globals.css | 11 ++ frontend/src/app/layout.tsx | 11 +- frontend/src/app/page.tsx | 5 +- frontend/src/app/portfolio/page.tsx | 2 +- frontend/src/app/talk/page.tsx | 7 + frontend/src/components/Navbar.tsx | 3 + frontend/src/components/PhysicsSimulation.tsx | 164 ++++++++++++++++++ 10 files changed, 204 insertions(+), 9 deletions(-) create mode 100644 frontend/src/app/talk/page.tsx create mode 100644 frontend/src/components/PhysicsSimulation.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 15f2a4f..4802164 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,6 +13,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.511.0", + "matter-js": "^0.20.0", "next": "15.3.3", "next-themes": "^0.4.6", "react": "^18.3.1", @@ -2025,6 +2026,12 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/matter-js": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/matter-js/-/matter-js-0.20.0.tgz", + "integrity": "sha512-iC9fYR7zVT3HppNnsFsp9XOoQdQN2tUyfaKg4CHLH8bN+j6GT4Gw7IH2rP0tflAebrHFw730RR3DkVSZRX8hwA==", + "license": "MIT" + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 2cf5a31..04d53af 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.511.0", + "matter-js": "^0.20.0", "next": "15.3.3", "next-themes": "^0.4.6", "react": "^18.3.1", diff --git a/frontend/src/app/blog/page.tsx b/frontend/src/app/blog/page.tsx index 13ee4e3..f71b5fa 100644 --- a/frontend/src/app/blog/page.tsx +++ b/frontend/src/app/blog/page.tsx @@ -1,4 +1,4 @@ -export default function Home() { +export default function Blog() { return (
This is blog list page diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index bbf8460..c841fb8 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -127,4 +127,15 @@ white-space: nowrap; box-sizing: border-box; } + .text-pill { + background: #e53e3e; + border-radius: 9999px; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.875rem; + font-weight: 500; + color: white; + pointer-events: none; + } } diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index fa2d610..47b3da4 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -42,12 +42,11 @@ export default function RootLayout({ enableSystem disableTransitionOnChange > -
- - {children} -
-
- +
+ + {children} +
+
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 29895dd..19636be 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,8 +1,11 @@ import { NameComponent } from "@/components/NameComponent"; +import { World } from "@/components/PhysicsSimulation"; export default function Home() { return ( -
+
+ +
); diff --git a/frontend/src/app/portfolio/page.tsx b/frontend/src/app/portfolio/page.tsx index ec7c08a..8a05596 100644 --- a/frontend/src/app/portfolio/page.tsx +++ b/frontend/src/app/portfolio/page.tsx @@ -1,4 +1,4 @@ -export default function Home() { +export default function Portfolio() { return (
This is portfolio diff --git a/frontend/src/app/talk/page.tsx b/frontend/src/app/talk/page.tsx new file mode 100644 index 0000000..0d60532 --- /dev/null +++ b/frontend/src/app/talk/page.tsx @@ -0,0 +1,7 @@ +export default function Talk() { + return ( +
+ This is talk +
+ ); +} diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index fb2dd51..f1fe58f 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -14,6 +14,9 @@ export function NavigationMenu() { + ); diff --git a/frontend/src/components/PhysicsSimulation.tsx b/frontend/src/components/PhysicsSimulation.tsx new file mode 100644 index 0000000..b60352a --- /dev/null +++ b/frontend/src/components/PhysicsSimulation.tsx @@ -0,0 +1,164 @@ +"use client"; + +import { useEffect, useRef } from "react"; +import { useTheme } from "next-themes"; +import Matter from "matter-js"; + +export function World() { + const containerRef = useRef(null); + const { resolvedTheme } = useTheme(); + + const getRandomXY = (width: number, height: number, radius: number) => { + const randomX = Math.floor(Math.random() * (width - 2 * radius)) + radius; + const randomY = Math.floor(Math.random() * (height - 2 * radius)) + radius; + return [randomX, randomY]; + }; + const getBgColor = () => { + if (typeof window !== "undefined") { + return ( + getComputedStyle(document.documentElement) + .getPropertyValue("--color-background") + .trim() || "#f0f0f0" + ); + } + return "#f0f0f0"; + }; + + useEffect(() => { + const container = containerRef.current; + const width = container.offsetWidth; + const height = container.offsetHeight; + const bgColor = getBgColor(); + + const { + Engine, + Render, + Bodies, + Composite, + Runner, + Mouse, + MouseConstraint, + } = Matter; + const engine = Engine.create(); + engine.gravity.y = 0.3; + engine.enableSleeping = false; + + const render = Render.create({ + element: container, + engine, + options: { + width, + height, + wireframes: false, + background: bgColor, + }, + }); + + // Bottom wall (ground) + const ground = Bodies.rectangle(width / 2, height - 10, width, 20, { + isStatic: true, + render: { fillStyle: bgColor }, + }); + + // Left wall + const leftWall = Bodies.rectangle(-10, height / 2, 20, height + 40, { + isStatic: true, + render: { fillStyle: bgColor }, + }); + + // Right wall + const rightWall = Bodies.rectangle( + width + 10, + height / 2, + 20, + height + 40, + { + isStatic: true, + render: { fillStyle: bgColor }, + }, + ); + + // Top wall + const topWall = Bodies.rectangle(width / 2, -10, width, 20, { + isStatic: true, + render: { fillStyle: bgColor }, + }); + + // Random ball position + const radius = 15; + + let [randomX, randomY] = getRandomXY(width, height, radius); + const ballRed = Bodies.circle(randomX, randomY, radius, { + restitution: 0.8, + render: { fillStyle: "red" }, + }); + [randomX, randomY] = getRandomXY(width, height, radius); + const ballBlue = Bodies.circle(randomX, randomY, radius, { + restitution: 0.8, + render: { fillStyle: "blue" }, + }); + [randomX, randomY] = getRandomXY(width, height, radius); + const ballGreen = Bodies.circle(randomX, randomY, radius, { + restitution: 0.8, + render: { fillStyle: "green" }, + }); + + const pillHeight = 50; + const pill = Matter.Bodies.rectangle(randomX, randomY, 200, pillHeight, { + chamfer: { radius: pillHeight / 2 }, + isStatic: false, + density: 0.001, + friction: 0.05, + frictionAir: 0.01, + render: { + fillStyle: "rgba(255, 255, 255, 0)", // transparent fill + strokeStyle: "#000000", // black border + lineWidth: 2, + + }, + }); + + // Mouse interaction + const mouse = Mouse.create(render.canvas); + const mouseConstraint = MouseConstraint.create(engine, { + mouse, + constraint: { + stiffness: 1, + angularStiffness: 0, + render: { visible: false }, + }, + }); + + // Add all elements to the world + Composite.add(engine.world, [ + ground, + leftWall, + rightWall, + topWall, + ballGreen, + ballBlue, + ballRed, + pill, + mouseConstraint, + ]); + + Render.run(render); + const runner = Runner.create(); + Runner.run(runner, engine); + + return () => { + Render.stop(render); + Runner.stop(runner); + Composite.clear(engine.world); + Engine.clear(engine); + render.canvas.remove(); + }; + }, [resolvedTheme]); + + return ( +
+ ); +}