(() => { const { Bodies } = Matter; const scenes = [ { id: "scene1", name: "Balanced (default)", config: { gravity: 0.88, spawnIntervalMs: 520, minChain: 3, palette: ["#ff595e", "#ffca3a", "#8ac926", "#1982c4", "#6a4c93"], ballRadius: 38, link: { stiffness: 0.85, lengthScale: 1.05, damping: 0.08, lineWidth: 3, rope: true, renderType: "line", maxLengthMultiplier: 3.2, }, }, createBodies: (w, h) => { const floorHeight = Math.max(60, h * 0.12); const wallThickness = Math.max(32, w * 0.05); const wallHeight = h * 1.6; const platformHeight = Math.max(14, h * 0.025); const smallPlatformWidth = Math.max(140, w * 0.18); const largePlatformWidth = Math.max(180, w * 0.22); return [ Bodies.rectangle( w / 2, h + floorHeight / 2, w + wallThickness * 2, floorHeight, { isStatic: true, restitution: 0.8, render: { fillStyle: "#0ea5e9", strokeStyle: "#0ea5e9" }, }, ), Bodies.rectangle( -wallThickness / 2, h / 2, wallThickness, wallHeight, { isStatic: true, render: { fillStyle: "#f97316", strokeStyle: "#f97316" }, }, ), Bodies.rectangle( w + wallThickness / 2, h / 2, wallThickness, wallHeight, { isStatic: true, render: { fillStyle: "#f97316", strokeStyle: "#f97316" }, }, ), Bodies.rectangle( w * 0.25, h * 0.55, smallPlatformWidth, platformHeight, { isStatic: true, angle: -0.3, render: { fillStyle: "#22c55e", strokeStyle: "#22c55e" }, plugin: { rotSpeed: 0.1 }, }, ), Bodies.rectangle( w * 0.7, h * 0.4, largePlatformWidth, platformHeight * 1.2, { isStatic: true, angle: 0.26, render: { fillStyle: "#a855f7", strokeStyle: "#a855f7" }, plugin: { rotSpeed: -0.08 }, }, ), ]; }, }, { id: "scene2", name: "Low-G terraces", config: { gravity: 0.65, spawnIntervalMs: 600, minChain: 3, palette: ["#fb7185", "#fbbf24", "#34d399", "#38bdf8"], ballRadius: 22, link: { stiffness: 0.6, lengthScale: 1, damping: 0.01, lineWidth: 4, rope: false, renderType: "spring", maxLengthMultiplier: 4.7, }, }, createBodies: (w, h) => { const floorHeight = Math.max(70, h * 0.12); const wallThickness = Math.max(32, w * 0.05); const wallHeight = h * 1.8; const ledgeHeight = Math.max(14, h * 0.022); const leftWidth = Math.max(160, w * 0.18); const midWidth = Math.max(190, w * 0.26); const rightWidth = Math.max(150, w * 0.18); return [ Bodies.rectangle( w / 2, h + floorHeight / 2, w + wallThickness * 2, floorHeight, { isStatic: true, restitution: 0.9, render: { fillStyle: "#0ea5e9", strokeStyle: "#0ea5e9" }, }, ), Bodies.rectangle( -wallThickness / 2, h / 2, wallThickness, wallHeight, { isStatic: true, render: { fillStyle: "#7c3aed", strokeStyle: "#7c3aed" }, }, ), Bodies.rectangle( w + wallThickness / 2, h / 2, wallThickness, wallHeight, { isStatic: true, render: { fillStyle: "#7c3aed", strokeStyle: "#7c3aed" }, }, ), Bodies.rectangle(w * 0.2, h * 0.45, leftWidth, ledgeHeight, { isStatic: true, angle: 0.08, render: { fillStyle: "#f97316", strokeStyle: "#f97316" }, }), Bodies.rectangle(w * 0.5, h * 0.6, midWidth, ledgeHeight, { isStatic: true, angle: -0.04, render: { fillStyle: "#14b8a6", strokeStyle: "#14b8a6" }, }), Bodies.rectangle(w * 0.8, h * 0.42, rightWidth, ledgeHeight, { isStatic: true, angle: 0.14, render: { fillStyle: "#c084fc", strokeStyle: "#c084fc" }, }), ]; }, }, { id: "scene3", name: "Fast drop maze", config: { gravity: 1.25, spawnIntervalMs: 220, minChain: 3, palette: ["#e879f9", "#38bdf8", "#f97316", "#22c55e"], ballRadius: 16, link: { stiffness: 1, lengthScale: 0.85, damping: 0.15, lineWidth: 3, rope: false, renderType: "line", maxLengthMultiplier: 23.8, }, }, createBodies: (w, h) => { const floorHeight = Math.max(60, h * 0.1); const wallThickness = Math.max(28, w * 0.045); const wallHeight = h * 1.5; const pegRadius = Math.max(10, Math.min(22, Math.min(w, h) * 0.03)); const platformHeight = Math.max(12, h * 0.02); const leftPlatformWidth = Math.max(120, w * 0.16); const rightPlatformWidth = Math.max(130, w * 0.18); const bodies = [ Bodies.rectangle( w / 2, h + floorHeight / 2, w + wallThickness * 2, floorHeight, { isStatic: true, restitution: 0.75, render: { fillStyle: "#14b8a6", strokeStyle: "#14b8a6" }, }, ), Bodies.rectangle( -wallThickness / 2, h / 2, wallThickness, wallHeight, { isStatic: true, render: { fillStyle: "#f472b6", strokeStyle: "#f472b6" }, }, ), Bodies.rectangle( w + wallThickness / 2, h / 2, wallThickness, wallHeight, { isStatic: true, render: { fillStyle: "#f472b6", strokeStyle: "#f472b6" }, }, ), ]; for (let i = 0; i < 5; i += 1) { const x = (w * (i + 1)) / 6; const y = h * 0.35 + (i % 2 === 0 ? h * 0.06 : -h * 0.05); bodies.push( Bodies.circle(x, y, pegRadius, { isStatic: true, restitution: 0.9, render: { fillStyle: "#facc15", strokeStyle: "#facc15" }, }), ); } bodies.push( Bodies.rectangle( w * 0.3, h * 0.55, leftPlatformWidth, platformHeight, { isStatic: true, angle: -0.3, render: { fillStyle: "#8b5cf6", strokeStyle: "#8b5cf6" }, }, ), Bodies.rectangle( w * 0.7, h * 0.58, rightPlatformWidth, platformHeight * 1.05, { isStatic: true, angle: 0.28, render: { fillStyle: "#10b981", strokeStyle: "#10b981" }, }, ), ); return bodies; }, }, ]; window.PhysilinksScenes = { scenes, defaultSceneId: scenes[0]?.id || "scene1", }; })();