{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "game-237",
  "type": "registry:block",
  "title": "Game 237",
  "description": "Game 237",
  "files": [
    {
      "path": "components/usages/game237usage.tsx",
      "content": "import Game from \"@/registry/open-source/game-237\";\r\n\r\nexport default function Usage() {\r\n\treturn <Game />;\r\n}\r\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/game237usage.tsx",
      "content": "import Game from \"@/registry/open-source/game-237\";\r\n\r\nexport default function Usage() {\r\n\treturn <Game />;\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/game-237.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { Physics, useBox, usePlane, useSphere } from \"@react-three/cannon\";\nimport {\n\tBox,\n\tKeyboardControls,\n\tOrbitControls,\n\tPerspectiveCamera,\n\tPlane,\n\tPointerLockControls,\n\tuseKeyboardControls,\n} from \"@react-three/drei\";\nimport { Canvas, useFrame, useLoader, useThree } from \"@react-three/fiber\";\nimport { gsap } from \"gsap\";\nimport * as THREE from \"three\";\n\nconst mazeLayout = [\n\t[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n\t[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],\n\t[1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1],\n\t[1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1],\n\t[1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1],\n\t[1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1],\n\t[1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1],\n\t[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1],\n\t[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1],\n\t[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1],\n\t[1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1],\n\t[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1],\n\t[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],\n\t[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],\n\t[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n];\n\nconst CELL_SIZE = 2;\nconst HEDGE_HEIGHT = 3 * 1.75;\nconst HEDGE_THICKNESS = 0.3;\nconst PLAYER_HEIGHT = 1.7;\nconst MOVEMENT_SPEED = 5;\nconst PLAYER_RADIUS = 0.3;\nconst AI_SPEED = 3;\nconst CHASE_DISTANCE = 1000;\n\nfunction HedgeMaterial() {\n\tconst [colorMap, normalMap, roughnessMap, aoMap] = useLoader(\n\t\tTHREE.TextureLoader,\n\t\t[\n\t\t\t\"https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Moss002_1K-JPG_Color-kfFgCRlBHy0CoS5TfgzMVaOT0u8OI4.jpg\",\n\t\t\t\"https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Moss002_1K-JPG_NormalGL-UqPfFqqaKR3Fz3QVRE0A3c4JJk0tnM.jpg\",\n\t\t\t\"https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Moss002_1K-JPG_Roughness-V6uedmVezVYGOMdoNYrRTuhiJgQ6DH.jpg\",\n\t\t\t\"https://hebbkx1anhila5yf.public.blob.vercel-storage.com/Moss002_1K-JPG_AmbientOcclusion-NFblk4lk0n9L4RrLyQ5ERjvoZDEjiw.jpg\",\n\t\t]\n\t);\n\n\tconst textures = [colorMap, normalMap, roughnessMap, aoMap];\n\ttextures.forEach((texture) => {\n\t\ttexture.wrapS = texture.wrapT = THREE.RepeatWrapping;\n\t\ttexture.repeat.set(1, HEDGE_HEIGHT / 2);\n\t});\n\n\treturn (\n\t\t<meshStandardMaterial\n\t\t\tmap={colorMap}\n\t\t\tnormalMap={normalMap}\n\t\t\troughnessMap={roughnessMap}\n\t\t\taoMap={aoMap}\n\t\t\tmetalness={0.1}\n\t\t\troughness={0.8}\n\t\t/>\n\t);\n}\n\nfunction GroundMaterial() {\n\tconst [colorMap, roughnessMap, normalMap, aoMap] = useLoader(\n\t\tTHREE.TextureLoader,\n\t\t[\n\t\t\t\"/placeholder.svg?height=512&width=512\",\n\t\t\t\"/placeholder.svg?height=512&width=512\",\n\t\t\t\"/placeholder.svg?height=512&width=512\",\n\t\t\t\"/placeholder.svg?height=512&width=512\",\n\t\t]\n\t);\n\n\tconst textures = [colorMap, roughnessMap, normalMap, aoMap];\n\ttextures.forEach((texture) => {\n\t\ttexture.wrapS = texture.wrapT = THREE.RepeatWrapping;\n\t\ttexture.repeat.set(21, 15);\n\t});\n\n\treturn (\n\t\t<meshStandardMaterial\n\t\t\tmap={colorMap}\n\t\t\troughnessMap={roughnessMap}\n\t\t\tnormalMap={normalMap}\n\t\t\taoMap={aoMap}\n\t\t\tmetalness={0.1}\n\t\t\troughness={0.8}\n\t\t/>\n\t);\n}\n\nfunction PhysicalMaze() {\n\treturn (\n\t\t<group>\n\t\t\t{mazeLayout.map((row, rowIndex) =>\n\t\t\t\trow.map((cell, colIndex) => {\n\t\t\t\t\tif (cell === 1) {\n\t\t\t\t\t\tconst x =\n\t\t\t\t\t\t\tcolIndex * CELL_SIZE -\n\t\t\t\t\t\t\t(mazeLayout[0].length * CELL_SIZE) / 2;\n\t\t\t\t\t\tconst z =\n\t\t\t\t\t\t\trowIndex * CELL_SIZE - (mazeLayout.length * CELL_SIZE) / 2;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Wall\n\t\t\t\t\t\t\t\tkey={`${colIndex}-${rowIndex}`}\n\t\t\t\t\t\t\t\tposition={[\n\t\t\t\t\t\t\t\t\tx + CELL_SIZE / 2,\n\t\t\t\t\t\t\t\t\tHEDGE_HEIGHT / 2,\n\t\t\t\t\t\t\t\t\tz + CELL_SIZE / 2,\n\t\t\t\t\t\t\t\t]}\n\t\t\t\t\t\t\t\tsize={[CELL_SIZE, HEDGE_HEIGHT, CELL_SIZE]}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t})\n\t\t\t)}\n\t\t\t<Ground />\n\t\t</group>\n\t);\n}\n\nfunction Wall({ position, size }) {\n\tconst [ref] = useBox(() => ({\n\t\ttype: \"Static\",\n\t\tposition,\n\t\targs: size,\n\t}));\n\n\treturn (\n\t\t<Box ref={ref} args={size} position={position}>\n\t\t\t<HedgeMaterial />\n\t\t</Box>\n\t);\n}\n\nfunction Ground() {\n\tconst [ref] = usePlane(() => ({\n\t\trotation: [-Math.PI / 2, 0, 0],\n\t\tposition: [0, 0, 0],\n\t}));\n\n\treturn (\n\t\t<Plane\n\t\t\tref={ref}\n\t\t\trotation={[-Math.PI / 2, 0, 0]}\n\t\t\tposition={[0, 0, 0]}\n\t\t\targs={[100, 100]}\n\t\t>\n\t\t\t<GroundMaterial />\n\t\t</Plane>\n\t);\n}\n\nfunction FadeEffect({ isGameOver }) {\n\tconst { scene } = useThree();\n\tconst fadeRef = useRef();\n\tconst [opacity, setOpacity] = useState(0);\n\n\tuseEffect(() => {\n\t\tif (isGameOver && fadeRef.current && fadeRef.current.material) {\n\t\t\tgsap.to(fadeRef.current.material.uniforms.opacity, {\n\t\t\t\tvalue: 1,\n\t\t\t\tduration: 2,\n\t\t\t\tease: \"power2.inOut\",\n\t\t\t});\n\t\t}\n\t}, [isGameOver]);\n\n\treturn (\n\t\t<mesh position={[0, 0, -1]} renderOrder={999}>\n\t\t\t<planeGeometry args={[2, 2]} />\n\t\t\t<shaderMaterial\n\t\t\t\tref={fadeRef}\n\t\t\t\ttransparent\n\t\t\t\tdepthTest={false}\n\t\t\t\tuniforms={{\n\t\t\t\t\topacity: { value: 0 },\n\t\t\t\t}}\n\t\t\t\tvertexShader={`\n          varying vec2 vUv;\n          void main() {\n            vUv = uv;\n            gl_Position = vec4(position, 1.0);\n          }\n        `}\n\t\t\t\tfragmentShader={`\n          uniform float opacity;\n          varying vec2 vUv;\n          void main() {\n            gl_FragColor = vec4(0.0, 0.0, 0.0, opacity);\n          }\n        `}\n\t\t\t/>\n\t\t</mesh>\n\t);\n}\n\nfunction Player({\n\tisGameOver,\n\tsetPlayerPosition,\n\tonWin,\n\thasLost,\n\tinitialPosition,\n}) {\n\tconst { camera } = useThree();\n\tconst [ref, api] = useSphere(() => ({\n\t\tmass: 1,\n\t\ttype: \"Dynamic\",\n\t\tposition: initialPosition,\n\t\targs: [PLAYER_RADIUS],\n\t}));\n\n\tconst [, get] = useKeyboardControls();\n\n\tuseFrame(() => {\n\t\tif (!isGameOver) {\n\t\t\tconst { forward, backward, left, right } = get();\n\t\t\tconst direction = new THREE.Vector3();\n\n\t\t\tconst frontVector = new THREE.Vector3(\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tNumber(backward) - Number(forward)\n\t\t\t);\n\t\t\tconst sideVector = new THREE.Vector3(\n\t\t\t\tNumber(left) - Number(right),\n\t\t\t\t0,\n\t\t\t\t0\n\t\t\t);\n\t\t\tdirection\n\t\t\t\t.subVectors(frontVector, sideVector)\n\t\t\t\t.normalize()\n\t\t\t\t.multiplyScalar(MOVEMENT_SPEED)\n\t\t\t\t.applyEuler(camera.rotation);\n\n\t\t\tapi.velocity.set(direction.x, 0, direction.z);\n\n\t\t\tconst position = ref.current.getWorldPosition(new THREE.Vector3());\n\t\t\tconst mazeWidth = mazeLayout[0].length * CELL_SIZE;\n\t\t\tconst mazeHeight = mazeLayout.length * CELL_SIZE;\n\t\t\tif (\n\t\t\t\tposition.x < -mazeWidth / 2 ||\n\t\t\t\tposition.x > mazeWidth / 2 ||\n\t\t\t\tposition.z < -mazeHeight / 2 ||\n\t\t\t\tposition.z > mazeHeight / 2\n\t\t\t) {\n\t\t\t\tonWin();\n\t\t\t}\n\t\t} else {\n\t\t\tapi.velocity.set(0, 0, 0);\n\t\t}\n\n\t\tref.current.getWorldPosition(camera.position);\n\t\tcamera.position.y = PLAYER_HEIGHT;\n\t\tsetPlayerPosition(camera.position.toArray());\n\t});\n\n\tuseEffect(() => {\n\t\tif (ref.current) {\n\t\t\tref.current.position.set(...initialPosition);\n\t\t\tcamera.position.set(...initialPosition);\n\t\t\tcamera.position.y = PLAYER_HEIGHT;\n\t\t}\n\t}, [initialPosition, camera]);\n\n\treturn <mesh ref={ref} />;\n}\n\nfunction findPath(start, end) {\n\tconst startNode = {\n\t\tx: Math.round(start[0] / CELL_SIZE),\n\t\tz: Math.round(start[2] / CELL_SIZE),\n\t};\n\tconst endNode = {\n\t\tx: Math.round(end[0] / CELL_SIZE),\n\t\tz: Math.round(end[2] / CELL_SIZE),\n\t};\n\n\tconst openSet = [startNode];\n\tconst closedSet = [];\n\tconst cameFrom = {};\n\tconst gScore = { [`${startNode.x},${startNode.z}`]: 0 };\n\tconst fScore = {\n\t\t[`${startNode.x},${startNode.z}`]: heuristic(startNode, endNode),\n\t};\n\n\twhile (openSet.length > 0) {\n\t\tlet current = openSet.reduce((a, b) =>\n\t\t\tfScore[`${a.x},${a.z}`] < fScore[`${b.x},${b.z}`] ? a : b\n\t\t);\n\n\t\tif (current.x === endNode.x && current.z === endNode.z) {\n\t\t\tconst path = [];\n\t\t\twhile (current) {\n\t\t\t\tpath.push([current.x * CELL_SIZE, 0, current.z * CELL_SIZE]);\n\t\t\t\tcurrent = cameFrom[`${current.x},${current.z}`];\n\t\t\t}\n\t\t\treturn path.reverse();\n\t\t}\n\n\t\topenSet.splice(openSet.indexOf(current), 1);\n\t\tclosedSet.push(current);\n\n\t\tconst neighbors = [\n\t\t\t{ x: current.x + 1, z: current.z },\n\t\t\t{ x: current.x - 1, z: current.z },\n\t\t\t{ x: current.x, z: current.z + 1 },\n\t\t\t{ x: current.x, z: current.z - 1 },\n\t\t];\n\n\t\tfor (const neighbor of neighbors) {\n\t\t\tif (\n\t\t\t\tclosedSet.some(\n\t\t\t\t\t(node) => node.x === neighbor.x && node.z === neighbor.z\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tcontinue;\n\t\t\tif (isWall(neighbor.x * CELL_SIZE, neighbor.z * CELL_SIZE)) continue;\n\n\t\t\tconst tentativeGScore = gScore[`${current.x},${current.z}`] + 1;\n\n\t\t\tif (\n\t\t\t\t!openSet.some(\n\t\t\t\t\t(node) => node.x === neighbor.x && node.z === neighbor.z\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\topenSet.push(neighbor);\n\t\t\t} else if (tentativeGScore >= gScore[`${neighbor.x},${neighbor.z}`]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcameFrom[`${neighbor.x},${neighbor.z}`] = current;\n\t\t\tgScore[`${neighbor.x},${neighbor.z}`] = tentativeGScore;\n\t\t\tfScore[`${neighbor.x},${neighbor.z}`] =\n\t\t\t\tgScore[`${neighbor.x},${neighbor.z}`] +\n\t\t\t\theuristic(neighbor, endNode);\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction heuristic(a, b) {\n\treturn Math.abs(a.x - b.x) + Math.abs(a.z - b.z);\n}\n\nfunction AICharacter({\n\tplayerPosition,\n\tonCatchPlayer,\n\tisGameOver,\n\tgameStarted,\n\tposition,\n}) {\n\tconst characterRef = useRef();\n\tconst [path, setPath] = useState([]);\n\tconst { camera } = useThree();\n\n\tuseFrame((state, delta) => {\n\t\tif (characterRef.current && !isGameOver && gameStarted) {\n\t\t\tconst currentPosition = characterRef.current.position;\n\t\t\tconst playerVector = new THREE.Vector3(...playerPosition);\n\n\t\t\tif (\n\t\t\t\tpath.length === 0 ||\n\t\t\t\tcurrentPosition.distanceTo(playerVector) > CHASE_DISTANCE\n\t\t\t) {\n\t\t\t\tconst newPath = findPath(\n\t\t\t\t\t[currentPosition.x, 0, currentPosition.z],\n\t\t\t\t\tplayerPosition\n\t\t\t\t);\n\t\t\t\tif (newPath) setPath(newPath);\n\t\t\t}\n\n\t\t\tif (path.length > 0) {\n\t\t\t\tconst targetPosition = new THREE.Vector3(...path[0]);\n\t\t\t\tconst direction = new THREE.Vector3()\n\t\t\t\t\t.subVectors(targetPosition, currentPosition)\n\t\t\t\t\t.normalize();\n\t\t\t\tconst newPosition = currentPosition\n\t\t\t\t\t.clone()\n\t\t\t\t\t.add(direction.multiplyScalar(AI_SPEED * delta));\n\n\t\t\t\tif (newPosition.distanceTo(targetPosition) < 0.1) {\n\t\t\t\t\tpath.shift();\n\t\t\t\t}\n\n\t\t\t\tcharacterRef.current.position.copy(newPosition);\n\t\t\t\tcharacterRef.current.lookAt(targetPosition);\n\t\t\t}\n\n\t\t\tconst aiMazeX = Math.floor(\n\t\t\t\t(currentPosition.x + (mazeLayout[0].length * CELL_SIZE) / 2) /\n\t\t\t\t\tCELL_SIZE\n\t\t\t);\n\t\t\tconst aiMazeZ = Math.floor(\n\t\t\t\t(currentPosition.z + (mazeLayout.length * CELL_SIZE) / 2) /\n\t\t\t\t\tCELL_SIZE\n\t\t\t);\n\t\t\tconst playerMazeX = Math.floor(\n\t\t\t\t(playerVector.x + (mazeLayout[0].length * CELL_SIZE) / 2) /\n\t\t\t\t\tCELL_SIZE\n\t\t\t);\n\t\t\tconst playerMazeZ = Math.floor(\n\t\t\t\t(playerVector.z + (mazeLayout.length * CELL_SIZE) / 2) / CELL_SIZE\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\taiMazeX === playerMazeX &&\n\t\t\t\taiMazeZ === playerMazeZ &&\n\t\t\t\t!isGameOver\n\t\t\t) {\n\t\t\t\tonCatchPlayer();\n\t\t\t}\n\t\t}\n\t});\n\n\treturn (\n\t\t<mesh ref={characterRef} position={position}>\n\t\t\t<cylinderGeometry args={[0.3, 0.3, 1.7, 8]} />\n\t\t\t<meshStandardMaterial color=\"red\" />\n\t\t</mesh>\n\t);\n}\n\nfunction getRandomEmptyPosition() {\n\tlet x, z;\n\tdo {\n\t\tx = Math.floor(Math.random() * (mazeLayout[0].length - 2)) + 1;\n\t\tz = Math.floor(Math.random() * (mazeLayout.length - 2)) + 1;\n\t} while (mazeLayout[z][x] !== 0 || (Math.abs(x) < 2 && Math.abs(z) < 2));\n\n\treturn [\n\t\t(x - mazeLayout[0].length / 2) * CELL_SIZE,\n\t\t0,\n\t\t(z - mazeLayout.length / 2) * CELL_SIZE,\n\t];\n}\n\nfunction isWall(x, z) {\n\tconst mazeX = Math.floor(\n\t\t(x + (mazeLayout[0].length * CELL_SIZE) / 2) / CELL_SIZE\n\t);\n\tconst mazeZ = Math.floor(\n\t\t(z + (mazeLayout.length * CELL_SIZE) / 2) / CELL_SIZE\n\t);\n\treturn mazeLayout[mazeZ] && mazeLayout[mazeZ][mazeX] === 1;\n}\n\nconst CirclePointsMaterial = {\n\tuniforms: {\n\t\tcolor: { value: new THREE.Color(\"white\") },\n\t\topacity: { value: 0.8 },\n\t},\n\tvertexShader: `\n    attribute float size;\n    varying vec3 vColor;\n    void main() {\n      vColor = vec3(1.0);\n      vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n      gl_PointSize = size * (300.0 / -mvPosition.z);\n      gl_Position = projectionMatrix * mvPosition;\n    }\n  `,\n\tfragmentShader: `\n    uniform vec3 color;\n    uniform float opacity;\n    varying vec3 vColor;\n    void main() {\n      float dist = length(gl_PointCoord - vec2(0.5));\n      if (dist > 0.5) discard;\n      gl_FragColor = vec4(color * vColor, opacity);\n    }\n  `,\n\ttransparent: true,\n};\n\nfunction Snow() {\n\tconst count = 500000;\n\tconst [positions, sizes] = useMemo(() => {\n\t\tconst positions = new Float32Array(count * 3);\n\t\tconst sizes = new Float32Array(count);\n\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tpositions[i * 3] = (Math.random() - 0.5) * 100;\n\t\t\tpositions[i * 3 + 1] = Math.random() * 50;\n\t\t\tpositions[i * 3 + 2] = (Math.random() - 0.5) * 100;\n\t\t\tsizes[i] = Math.random() * 0.1 + 0.05;\n\t\t}\n\n\t\treturn [positions, sizes];\n\t}, [count]);\n\n\tconst particlesRef = useRef();\n\n\tuseFrame(() => {\n\t\tif (particlesRef.current) {\n\t\t\tconst positions =\n\t\t\t\tparticlesRef.current.geometry.attributes.position.array;\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tpositions[i * 3 + 1] -= 0.1;\n\t\t\t\tif (positions[i * 3 + 1] < 0) {\n\t\t\t\t\tpositions[i * 3 + 1] = 50;\n\t\t\t\t}\n\t\t\t}\n\t\t\tparticlesRef.current.geometry.attributes.position.needsUpdate = true;\n\t\t}\n\t});\n\n\treturn (\n\t\t<points ref={particlesRef}>\n\t\t\t<bufferGeometry>\n\t\t\t\t<bufferAttribute\n\t\t\t\t\tattach=\"attributes-position\"\n\t\t\t\t\tcount={positions.length / 3}\n\t\t\t\t\tarray={positions}\n\t\t\t\t\titemSize={3}\n\t\t\t\t/>\n\t\t\t\t<bufferAttribute\n\t\t\t\t\tattach=\"attributes-size\"\n\t\t\t\t\tcount={sizes.length}\n\t\t\t\t\tarray={sizes}\n\t\t\t\t\titemSize={1}\n\t\t\t\t/>\n\t\t\t</bufferGeometry>\n\t\t\t<shaderMaterial\n\t\t\t\targs={[CirclePointsMaterial]}\n\t\t\t\ttransparent\n\t\t\t\tdepthWrite={false}\n\t\t\t/>\n\t\t</points>\n\t);\n}\n\nfunction Snow2D() {\n\treturn (\n\t\t<div className=\"fixed -inset-4 pointer-events-none z-1002\">\n\t\t\t{[...Array(100)].map((_, i) => (\n\t\t\t\t<div\n\t\t\t\t\tkey={i}\n\t\t\t\t\tclassName=\"snow-flake\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tleft: `${Math.random() * 100}vw`,\n\t\t\t\t\t\tanimationDuration: `${Math.random() * 3 + 2}s`,\n\t\t\t\t\t\tanimationDelay: `${Math.random() * 2}s`,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</div>\n\t);\n}\n\nfunction TitleScreenMusic() {\n\treturn null;\n}\n\nfunction BackgroundMusic({ gameStarted, isGameOver }) {\n\treturn null;\n}\n\nfunction PhantomChaseMusic({ isGameOver }) {\n\treturn null;\n}\n\nfunction Timer({ onGameOver }) {\n\tconst [timeLeft, setTimeLeft] = useState(60);\n\n\tuseEffect(() => {\n\t\tconst timerId = setInterval(() => {\n\t\t\tsetTimeLeft((prevTime) => {\n\t\t\t\tif (prevTime <= 1) {\n\t\t\t\t\tclearInterval(timerId);\n\t\t\t\t\tonGameOver();\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn prevTime - 1;\n\t\t\t});\n\t\t}, 1000);\n\n\t\treturn () => clearInterval(timerId);\n\t}, []);\n\n\treturn (\n\t\t<div className=\"absolute top-20 left-1/2 -translate-x-1/2 text-[48px] font-bold text-red-600 text-shadow-lg z-1000\">\n\t\t\t{timeLeft}\n\t\t</div>\n\t);\n}\n\nfunction GameOver({ onRestart }) {\n\tuseEffect(() => {\n\t\tconst handleKeyDown = (event) => {\n\t\t\tif (event.code === \"Space\") {\n\t\t\t\tonRestart();\n\t\t\t}\n\t\t};\n\t\twindow.addEventListener(\"keydown\", handleKeyDown);\n\t\treturn () => window.removeEventListener(\"keydown\", handleKeyDown);\n\t}, [onRestart]);\n\n\treturn (\n\t\t<div className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-[72px] font-bold text-red-600 text-shadow-lg z-1000 flex flex-col items-center gap-8\">\n\t\t\t<div>GAME OVER</div>\n\t\t\t<div className=\"text-2xl animate-pulse\">\n\t\t\t\tPress Spacebar to Try Again\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction YouSurvived() {\n\tconst [visible, setVisible] = useState(true);\n\n\tuseEffect(() => {\n\t\tconst timer = setTimeout(() => {\n\t\t\tsetVisible(false);\n\t\t}, 1500);\n\n\t\treturn () => clearTimeout(timer);\n\t}, []);\n\n\tif (!visible) return null;\n\n\treturn (\n\t\t<div className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-[72px] font-bold text-green-500 text-shadow-lg z-1000 transition-opacity duration-500 opacity-100\">\n\t\t\tYou Survived\n\t\t</div>\n\t);\n}\n\nfunction Credits() {\n\treturn (\n\t\t<div className=\"absolute inset-0 overflow-hidden z-1001\">\n\t\t\t<div className=\"absolute inset-0 flex items-center justify-center\">\n\t\t\t\t<div className=\"w-full max-w-4xl text-white font-sans text-center animate-credits\">\n\t\t\t\t\t<h2 className=\"text-6xl font-bold mb-8\">Credits</h2>\n\t\t\t\t\t<div className=\"grid grid-cols-2 gap-8 text-3xl\">\n\t\t\t\t\t\t<div className=\"font-bold text-right\">\n\t\t\t\t\t\t\t<p className=\"mb-4\">Created by</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Developed by</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Music by</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Sound effects by</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Skybox by</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Textures by</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Character model by</p>\n\t\t\t\t\t\t\t<p className=\"mb-8\">Hotel model by</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"text-left\">\n\t\t\t\t\t\t\t<p className=\"mb-4\">Chris Tate</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">v0</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Suno</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Eleven Labs</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Blockade Labs</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">ambientCG</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">Mixamo</p>\n\t\t\t\t\t\t\t<p className=\"mb-4\">\n\t\t\t\t\t\t\t\t@A9908244 Sketchfab\n\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t@DJohnson1 DeviantArt\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction TitleScreen({ onStart }) {\n\tconst { scene } = useThree();\n\n\tuseEffect(() => {\n\t\tconst handleKeyDown = (event) => {\n\t\t\tif (event.code === \"Space\") {\n\t\t\t\tonStart();\n\t\t\t}\n\t\t};\n\t\twindow.addEventListener(\"keydown\", handleKeyDown);\n\t\treturn () => window.removeEventListener(\"keydown\", handleKeyDown);\n\t}, [onStart]);\n\n\treturn (\n\t\t<>\n\t\t\t<color attach=\"background\" args={[\"#001122\"]} />\n\t\t\t<PerspectiveCamera makeDefault position={[0, 2, 8]} />\n\t\t\t<OrbitControls\n\t\t\t\tenableZoom\n\t\t\t\tenablePan={false}\n\t\t\t\tautoRotate\n\t\t\t\tautoRotateSpeed={0.5}\n\t\t\t/>\n\t\t\t<ambientLight intensity={0.5} />\n\t\t\t<pointLight position={[10, 10, 10]} />\n\t\t\t<Snow />\n\t\t</>\n\t);\n}\n\nfunction Hotel() {\n\treturn (\n\t\t<mesh position={[-50, 2, 0]}>\n\t\t\t<boxGeometry args={[8, 4, 6]} />\n\t\t\t<meshStandardMaterial color=\"#8B4513\" />\n\t\t</mesh>\n\t);\n}\n\nfunction Mountain() {\n\treturn (\n\t\t<mesh position={[-500, 50, -500]} scale={[100, 50, 100]}>\n\t\t\t<coneGeometry args={[1, 2, 8]} />\n\t\t\t<meshStandardMaterial color=\"#666666\" />\n\t\t</mesh>\n\t);\n}\n\nexport default function Game() {\n\tconst [isGameOver, setIsGameOver] = useState(false);\n\tconst [gameStarted, setGameStarted] = useState(false);\n\tconst [playerPosition, setPlayerPosition] = useState([0, PLAYER_HEIGHT, 0]);\n\tconst [aiPosition, setAIPosition] = useState(getRandomEmptyPosition());\n\tconst [hasWon, setHasWon] = useState(false);\n\tconst [hasLost, setHasLost] = useState(false);\n\n\tconst handleGameOver = () => {\n\t\tsetIsGameOver(true);\n\t\tsetHasLost(true);\n\t};\n\n\tconst handleRestart = () => {\n\t\tsetIsGameOver(false);\n\t\tsetHasWon(false);\n\t\tsetHasLost(false);\n\t\tsetPlayerPosition([0, PLAYER_HEIGHT, 0]);\n\t\tsetAIPosition(getRandomEmptyPosition());\n\t\tsetGameStarted(true);\n\t};\n\n\tconst handleWin = () => {\n\t\tsetHasWon(true);\n\t\tsetIsGameOver(true);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<style jsx global>{`\n\t\t\t\t@keyframes roll-credits {\n\t\t\t\t\t0% {\n\t\t\t\t\t\ttransform: translate(0, calc(100dvh));\n\t\t\t\t\t}\n\t\t\t\t\t100% {\n\t\t\t\t\t\ttransform: translate(0, -100dvh);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t.animate-credits {\n\t\t\t\t\tanimation: roll-credits 15s linear forwards;\n\t\t\t\t}\n\t\t\t\t@keyframes snowfall {\n\t\t\t\t\t0% {\n\t\t\t\t\t\ttransform: translateY(-10vh) translateX(0);\n\t\t\t\t\t\topacity: 1;\n\t\t\t\t\t}\n\t\t\t\t\t100% {\n\t\t\t\t\t\ttransform: translateY(100vh) translateX(20px);\n\t\t\t\t\t\topacity: 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t.snow-flake {\n\t\t\t\t\tposition: absolute;\n\t\t\t\t\twidth: 5px;\n\t\t\t\t\theight: 5px;\n\t\t\t\t\tbackground: white;\n\t\t\t\t\tborder-radius: 50%;\n\t\t\t\t\topacity: 0.8;\n\t\t\t\t\tanimation: snowfall linear infinite;\n\t\t\t\t}\n\t\t\t`}</style>\n\t\t\t<div className=\"w-full cursor-none h-screen\">\n\t\t\t\t{!gameStarted && (\n\t\t\t\t\t<div className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-[256px] font-bold pointer-events-none text-red-600 z-1000\">\n\t\t\t\t\t\t237\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t<KeyboardControls\n\t\t\t\t\tmap={[\n\t\t\t\t\t\t{ name: \"forward\", keys: [\"ArrowUp\", \"w\", \"W\"] },\n\t\t\t\t\t\t{ name: \"backward\", keys: [\"ArrowDown\", \"s\", \"S\"] },\n\t\t\t\t\t\t{ name: \"left\", keys: [\"ArrowLeft\", \"a\", \"A\"] },\n\t\t\t\t\t\t{ name: \"right\", keys: [\"ArrowRight\", \"d\", \"D\"] },\n\t\t\t\t\t]}\n\t\t\t\t>\n\t\t\t\t\t<Canvas\n\t\t\t\t\t\tcamera={{\n\t\t\t\t\t\t\tfov: 75,\n\t\t\t\t\t\t\tnear: 0.1,\n\t\t\t\t\t\t\tfar: 1000,\n\t\t\t\t\t\t\tposition: [0, PLAYER_HEIGHT, 0],\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{!gameStarted ? (\n\t\t\t\t\t\t\t<TitleScreen\n\t\t\t\t\t\t\t\tonStart={() => {\n\t\t\t\t\t\t\t\t\tsetGameStarted(true);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<Physics gravity={[0, -9.81, 0]}>\n\t\t\t\t\t\t\t\t<color attach=\"background\" args={[\"#001122\"]} />\n\t\t\t\t\t\t\t\t<ambientLight intensity={0.1} />\n\t\t\t\t\t\t\t\t<pointLight\n\t\t\t\t\t\t\t\t\tposition={[0, HEDGE_HEIGHT * 2, 0]}\n\t\t\t\t\t\t\t\t\tintensity={0.3}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<PhysicalMaze />\n\t\t\t\t\t\t\t\t<Player\n\t\t\t\t\t\t\t\t\tisGameOver={isGameOver}\n\t\t\t\t\t\t\t\t\tsetPlayerPosition={setPlayerPosition}\n\t\t\t\t\t\t\t\t\tonWin={handleWin}\n\t\t\t\t\t\t\t\t\thasLost={hasLost}\n\t\t\t\t\t\t\t\t\tinitialPosition={playerPosition}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<AICharacter\n\t\t\t\t\t\t\t\t\tplayerPosition={playerPosition}\n\t\t\t\t\t\t\t\t\tonCatchPlayer={handleGameOver}\n\t\t\t\t\t\t\t\t\tisGameOver={isGameOver}\n\t\t\t\t\t\t\t\t\tgameStarted={gameStarted}\n\t\t\t\t\t\t\t\t\tposition={aiPosition}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Hotel />\n\t\t\t\t\t\t\t\t<Mountain />\n\t\t\t\t\t\t\t\t<Snow />\n\t\t\t\t\t\t\t\t{!isGameOver && <PointerLockControls />}\n\t\t\t\t\t\t\t\t{isGameOver && <FadeEffect isGameOver={isGameOver} />}\n\t\t\t\t\t\t\t</Physics>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Canvas>\n\t\t\t\t</KeyboardControls>\n\t\t\t\t{!gameStarted && (\n\t\t\t\t\t<div className=\"absolute inset-x-0 bottom-10 flex justify-center pointer-events-none uppercase\">\n\t\t\t\t\t\t<p className=\"text-white text-lg animate-pulse\">\n\t\t\t\t\t\t\tPress Spacebar\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t<BackgroundMusic\n\t\t\t\t\tgameStarted={gameStarted}\n\t\t\t\t\tisGameOver={isGameOver}\n\t\t\t\t/>\n\t\t\t\t{gameStarted && !isGameOver && (\n\t\t\t\t\t<Timer onGameOver={handleGameOver} />\n\t\t\t\t)}\n\t\t\t\t{isGameOver && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{!hasWon && <GameOver onRestart={handleRestart} />}\n\t\t\t\t\t\t{hasWon && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<YouSurvived />\n\t\t\t\t\t\t\t\t<Credits />\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<PhantomChaseMusic isGameOver={isGameOver} />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</>\n\t);\n}\n",
      "type": "registry:ui"
    }
  ]
}