"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 (
); }