{
  "name": "gameconsole",
  "title": "GameConsole",
  "type": "registry:component",
  "description": "A games console (tower, slab, or cube) with up to four controllers laid out in front, to sit under a TV.",
  "dependencies": [
    "@runek/core@^0.15.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "GameConsole.tsx",
      "content": "import { pick, range, rng, sub, useWorld, type WorldComponentProps } from '@runek/core'\nimport { useMemo } from 'react'\n\n/** Standing upright (`tower`), lying flat (`slab`), or a small `cube`. */\nexport type GameConsoleStyle = 'tower' | 'slab' | 'cube'\n\nexport interface GameConsoleProps extends WorldComponentProps {\n  /** Seeded when unset. */\n  style?: GameConsoleStyle\n  /** Controllers laid out in front of the console, 0 to 4. Seeded (1 or 2) when unset. */\n  controllers?: number\n  /** Console and controllers. Seeded (black or white) when unset. */\n  color?: string\n  /** Power light and trim. Seeded when unset. */\n  accent?: string\n  /** Powered on: the light glows. */\n  on?: boolean\n}\n\nconst STYLES: GameConsoleStyle[] = ['tower', 'slab', 'cube']\nconst BODIES = ['#18191c', '#18191c', '#eceef0', '#2a2d33']\nconst LIGHTS = ['#38c6f4', '#7bd34f', '#e4405f', '#f0f0f0']\nconst BUTTONS = ['#7bd34f', '#e4405f', '#38c6f4', '#f0c419']\n\n// Body size in meters, [width, height, depth].\nconst SIZES: Record<GameConsoleStyle, [number, number, number]> = {\n  tower: [0.1, 0.33, 0.26],\n  slab: [0.36, 0.07, 0.26],\n  cube: [0.17, 0.15, 0.17],\n}\n\nfunction Controller({ color, accent, u }: { color: string; accent: string; u: number }) {\n  return (\n    <group>\n      <mesh position={[0, 0.02 * u, 0]} castShadow>\n        <boxGeometry args={[0.1 * u, 0.025 * u, 0.055 * u]} />\n        <meshStandardMaterial color={color} roughness={0.5} />\n      </mesh>\n      {/* grips: two rounded handles swept back toward the player */}\n      {[-1, 1].map((s) => (\n        <mesh\n          key={s}\n          position={[s * 0.052 * u, 0.018 * u, 0.025 * u]}\n          rotation={[Math.PI / 2 - 0.3, 0, s * 0.35]}\n          castShadow\n        >\n          <capsuleGeometry args={[0.017 * u, 0.04 * u, 4, 10]} />\n          <meshStandardMaterial color={color} roughness={0.5} />\n        </mesh>\n      ))}\n      {[-1, 1].map((s) => (\n        <mesh key={`stick${s}`} position={[s * 0.022 * u, 0.04 * u, 0.012 * u]}>\n          <cylinderGeometry args={[0.008 * u, 0.007 * u, 0.012 * u, 12]} />\n          <meshStandardMaterial color=\"#2a2a2e\" roughness={0.8} />\n        </mesh>\n      ))}\n      {BUTTONS.map((c, i) => {\n        const a = (i / 4) * Math.PI * 2\n        return (\n          <mesh\n            key={c}\n            position={[\n              0.042 * u + Math.cos(a) * 0.008 * u,\n              0.034 * u,\n              -0.008 * u + Math.sin(a) * 0.008 * u,\n            ]}\n          >\n            <sphereGeometry args={[0.004 * u, 8, 6]} />\n            <meshStandardMaterial color={c} roughness={0.3} />\n          </mesh>\n        )\n      })}\n      <mesh position={[-0.042 * u, 0.034 * u, -0.008 * u]}>\n        <boxGeometry args={[0.018 * u, 0.004 * u, 0.006 * u]} />\n        <meshStandardMaterial color=\"#2a2a2e\" />\n      </mesh>\n      <mesh position={[0, 0.0331 * u, -0.02 * u]}>\n        <boxGeometry args={[0.012 * u, 0.001 * u, 0.004 * u]} />\n        <meshBasicMaterial color={accent} toneMapped={false} />\n      </mesh>\n    </group>\n  )\n}\n\n/**\n * A games console with its controllers, to sit on the media console under a `Tv`: an upright\n * `tower`, a flat `slab`, or a small `cube`, with a power light and a vent, and up to four\n * controllers laid out in front of it (local +Z). Its origin is the console's foot. Decorative:\n * no collider.\n */\nexport function GameConsole({\n  position = [0, 0, 0],\n  rotation = [0, 0, 0],\n  seed = 1,\n  style,\n  controllers,\n  color,\n  accent,\n  on = true,\n}: GameConsoleProps) {\n  const { unit } = useWorld()\n  const u = unit\n\n  const look = useMemo(() => {\n    const r = rng(sub(seed, 0))\n    const rolled = {\n      style: pick(r, STYLES),\n      count: r() < 0.5 ? 1 : 2,\n      body: pick(r, BODIES),\n      light: pick(r, LIGHTS),\n    }\n    const count = Math.max(0, Math.min(4, Math.round(controllers ?? rolled.count)))\n    const pads = Array.from({ length: count }, (_, i) => ({\n      x: (i - (count - 1) / 2) * 0.16 * u + range(r, -0.015, 0.015) * u,\n      z: (0.23 + range(r, -0.02, 0.03)) * u,\n      turn: range(r, -0.35, 0.35),\n    }))\n    return {\n      style: style ?? rolled.style,\n      body: color ?? rolled.body,\n      light: accent ?? rolled.light,\n      pads,\n    }\n  }, [seed, style, controllers, color, accent, u])\n\n  const [w, h, d] = SIZES[look.style].map((v) => v * u)\n  const trim = look.body === '#eceef0' ? '#18191c' : '#3a3d44'\n\n  return (\n    <group position={position} rotation={rotation}>\n      {look.style === 'tower' && (\n        <mesh position={[0, 0.006 * u, 0]} receiveShadow>\n          <boxGeometry args={[w * 1.6, 0.012 * u, d * 0.7]} />\n          <meshStandardMaterial color={trim} roughness={0.6} />\n        </mesh>\n      )}\n      <group position={[0, (look.style === 'tower' ? 0.012 * u : 0) + h / 2, 0]}>\n        <mesh castShadow receiveShadow>\n          <boxGeometry args={[w, h, d]} />\n          <meshStandardMaterial color={look.body} roughness={0.35} metalness={0.1} />\n        </mesh>\n        {/* a dark vent band across the front, and the power light */}\n        <mesh position={[0, look.style === 'slab' ? 0 : h * 0.3, d / 2 + 0.0005 * u]}>\n          <planeGeometry args={[w * 0.92, look.style === 'slab' ? h * 0.3 : h * 0.08]} />\n          <meshStandardMaterial color={trim} roughness={0.8} />\n        </mesh>\n        <mesh\n          position={[\n            look.style === 'slab' ? w * 0.4 : 0,\n            look.style === 'slab' ? 0 : -h * 0.35,\n            d / 2 + 0.001 * u,\n          ]}\n        >\n          <circleGeometry args={[0.006 * u, 12]} />\n          {on ? (\n            <meshBasicMaterial color={look.light} toneMapped={false} />\n          ) : (\n            <meshStandardMaterial color=\"#333\" />\n          )}\n        </mesh>\n      </group>\n      {look.pads.map((p) => (\n        <group\n          key={`${p.x.toFixed(4)}:${p.z.toFixed(4)}`}\n          position={[p.x, 0, p.z]}\n          rotation={[0, p.turn, 0]}\n        >\n          <Controller color={look.body} accent={look.light} u={u} />\n        </group>\n      ))}\n    </group>\n  )\n}\n",
      "type": "registry:component"
    }
  ]
}
