{
  "name": "monitor",
  "title": "Monitor",
  "type": "registry:component",
  "description": "A desk monitor on a foot, plate, or legs. Switched on, the screen glows in its own color with a few seeded windows and lines of text on it, all geometry.",
  "dependencies": [
    "@react-three/rapier@^2.2.0",
    "@runek/core@^0.13.0",
    "three@^0.184.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "Monitor.tsx",
      "content": "import { CuboidCollider, RigidBody } from '@react-three/rapier'\nimport { pick, range, rng, sub, useWorld, type Vec3, type WorldComponentProps } from '@runek/core'\nimport { useMemo } from 'react'\nimport { Color } from 'three'\n\n/** A round `foot` with a neck, a flat `plate` with a neck, or two splayed `legs`. */\nexport type MonitorStand = 'foot' | 'plate' | 'legs'\n\nexport interface MonitorProps extends WorldComponentProps {\n  /** Screen width, in units. */\n  width?: number\n  /** Width over height. */\n  aspect?: number\n  /** Seeded when unset. */\n  stand?: MonitorStand\n  /** The screen's glow when on. Seeded from a few calm tints when unset. */\n  screen?: string\n  /** Lit, showing a few seeded windows; off, a dark glass. */\n  on?: boolean\n  /** Bezel and stand; defaults to the palette's `metal`. */\n  color?: string\n}\n\ninterface Panel {\n  pos: Vec3\n  size: [number, number]\n  color: string\n}\n\nconst STANDS: MonitorStand[] = ['foot', 'plate', 'legs']\nconst TINTS = ['#7fa8d6', '#8cc7b8', '#b3a6e0', '#e0c58f', '#9ab8c9']\nconst OFF = '#121417'\n\n/**\n * A desk monitor: a thin screen in a bezel on a stand, its origin at the foot so it sits on a\n * `Desk` top. Switched on, the screen glows in its `screen` color with a few seeded windows and\n * lines of text on it, all geometry (no textures), so a busy office can light up desk by desk.\n * One small cuboid collider; not ground-standing.\n */\nexport function Monitor({\n  position = [0, 0, 0],\n  rotation = [0, 0, 0],\n  seed = 1,\n  width = 0.6,\n  aspect = 16 / 9,\n  stand,\n  screen,\n  on = true,\n  color,\n}: MonitorProps) {\n  const { unit, palette } = useWorld()\n  const frame = color ?? palette.metal\n  const W = width * unit\n  const Hs = W / aspect\n  const bezel = 0.012 * unit\n  const thick = 0.025 * unit\n  const lift = 0.1 * unit + Hs * 0.1\n\n  const look = useMemo(() => {\n    const r = rng(sub(seed, 0))\n    const rolled = { stand: pick(r, STANDS), tint: pick(r, TINTS) }\n    const glow = screen ?? rolled.tint\n    const base = new Color(glow)\n    const shade = (k: number) => base.clone().multiplyScalar(k).getStyle()\n    // A couple of windows, each with a title bar and a few lines of \"text\".\n    const panels: Panel[] = []\n    const count = 1 + Math.floor(r() * 3)\n    for (let i = 0; i < count; i++) {\n      const w = range(r, 0.35, 0.7) * W\n      const h = range(r, 0.4, 0.75) * Hs\n      const x = range(r, -W / 2 + w / 2 + 0.02 * W, W / 2 - w / 2 - 0.02 * W)\n      const y = range(r, -Hs / 2 + h / 2 + 0.04 * Hs, Hs / 2 - h / 2 - 0.04 * Hs)\n      const z = 0.0006 * unit * (i + 1)\n      panels.push({ pos: [x, y, z], size: [w, h], color: shade(1.35) })\n      panels.push({\n        pos: [x, y + h / 2 - 0.05 * h, z + 0.0002 * unit],\n        size: [w, 0.1 * h],\n        color: shade(0.75),\n      })\n      const lines = 2 + Math.floor(r() * 4)\n      for (let l = 0; l < lines; l++) {\n        const lw = range(r, 0.3, 0.85) * w * 0.85\n        panels.push({\n          pos: [x - w * 0.42 + lw / 2, y + h * 0.28 - l * h * 0.14, z + 0.0002 * unit],\n          size: [lw, 0.045 * h],\n          color: shade(0.6),\n        })\n      }\n    }\n    return { stand: stand ?? rolled.stand, glow, panels }\n  }, [seed, stand, screen, W, Hs, unit])\n\n  const cy = lift + Hs / 2 + bezel\n  const total = cy + Hs / 2 + bezel\n\n  return (\n    <RigidBody type=\"fixed\" colliders={false} position={position} rotation={rotation}>\n      <CuboidCollider args={[W / 2 + bezel, total / 2, 0.09 * unit]} position={[0, total / 2, 0]} />\n      {/* screen: bezel shell, then the glass just proud of it */}\n      <mesh position={[0, cy, 0]} castShadow>\n        <boxGeometry args={[W + bezel * 2, Hs + bezel * 2, thick]} />\n        <meshStandardMaterial color={frame} roughness={0.45} metalness={0.3} />\n      </mesh>\n      <group position={[0, cy, thick / 2 + 0.0005 * unit]}>\n        <mesh>\n          <planeGeometry args={[W, Hs]} />\n          {on ? (\n            <meshBasicMaterial color={look.glow} toneMapped={false} />\n          ) : (\n            <meshStandardMaterial color={OFF} roughness={0.15} metalness={0.4} />\n          )}\n        </mesh>\n        {on &&\n          look.panels.map((p) => (\n            <mesh\n              key={`${p.pos[0].toFixed(4)}:${p.pos[1].toFixed(4)}:${p.pos[2].toFixed(5)}`}\n              position={p.pos}\n            >\n              <planeGeometry args={p.size} />\n              <meshBasicMaterial color={p.color} toneMapped={false} />\n            </mesh>\n          ))}\n      </group>\n      {/* stand */}\n      <mesh position={[0, (lift + Hs * 0.3) / 2, -thick]} castShadow>\n        <boxGeometry args={[0.05 * unit, lift + Hs * 0.3, 0.025 * unit]} />\n        <meshStandardMaterial color={frame} roughness={0.5} metalness={0.3} />\n      </mesh>\n      {look.stand === 'foot' && (\n        <mesh position={[0, 0.006 * unit, -thick]} castShadow receiveShadow>\n          <cylinderGeometry args={[0.11 * unit, 0.12 * unit, 0.012 * unit, 24]} />\n          <meshStandardMaterial color={frame} roughness={0.5} metalness={0.3} />\n        </mesh>\n      )}\n      {look.stand === 'plate' && (\n        <mesh position={[0, 0.005 * unit, -thick]} castShadow receiveShadow>\n          <boxGeometry args={[0.24 * unit, 0.01 * unit, 0.17 * unit]} />\n          <meshStandardMaterial color={frame} roughness={0.5} metalness={0.3} />\n        </mesh>\n      )}\n      {look.stand === 'legs' &&\n        [-1, 1].map((s) => (\n          <mesh\n            key={s}\n            position={[s * 0.08 * unit, 0.008 * unit, -thick + 0.02 * unit]}\n            rotation={[0, s * 0.5, 0]}\n            castShadow\n          >\n            <boxGeometry args={[0.025 * unit, 0.016 * unit, 0.2 * unit]} />\n            <meshStandardMaterial color={frame} roughness={0.5} metalness={0.3} />\n          </mesh>\n        ))}\n    </RigidBody>\n  )\n}\n",
      "type": "registry:component"
    }
  ]
}
