{
  "name": "officechair",
  "title": "OfficeChair",
  "type": "registry:component",
  "description": "A swivel office chair: five-star base on casters, gas column, padded seat, low or high back, optional arms. Seats a Person in sit or type pose.",
  "dependencies": [
    "@react-three/drei@^10.7.7",
    "@react-three/rapier@^2.2.0",
    "@runek/core@^0.13.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "OfficeChair.tsx",
      "content": "import { RoundedBox } from '@react-three/drei'\nimport { CuboidCollider, RigidBody } from '@react-three/rapier'\nimport { pick, rng, sub, useWorld, type WorldComponentProps } from '@runek/core'\nimport { useMemo } from 'react'\n\n/** A `low` back that stops at the shoulder blades, or a `high` one up to the head. */\nexport type OfficeChairBack = 'low' | 'high'\n\nexport interface OfficeChairProps extends WorldComponentProps {\n  /** Top of the seat cushion, in units. */\n  seatHeight?: number\n  /** Seeded when unset. */\n  back?: OfficeChairBack\n  /** Armrests. Seeded when unset. */\n  arms?: boolean\n  /** Seat and back; defaults to the palette's `fabric`. */\n  color?: string\n  /** Base, column, and arms; defaults to the palette's `metal`. */\n  frameColor?: string\n}\n\nconst LEGS = 5\n\n/**\n * A swivel office chair: a five-star base on casters, a gas column, a padded seat, and a back,\n * with or without arms. Seat faces local +Z, so `pose=\"sit\"` or `pose=\"type\"` on a `Person` at the\n * same position and rotation sits in it. One cuboid collider for the seat.\n */\nexport function OfficeChair({\n  position = [0, 0, 0],\n  rotation = [0, 0, 0],\n  seed = 1,\n  seatHeight = 0.47,\n  back,\n  arms,\n  color,\n  frameColor,\n}: OfficeChairProps) {\n  const { unit, palette } = useWorld()\n  const cloth = color ?? palette.fabric\n  const frame = frameColor ?? palette.metal\n  const u = unit\n\n  const look = useMemo(() => {\n    const r = rng(sub(seed, 0))\n    const rolled = { back: pick<OfficeChairBack>(r, ['low', 'high', 'high']), arms: r() < 0.7 }\n    return { back: back ?? rolled.back, arms: arms ?? rolled.arms }\n  }, [seed, back, arms])\n\n  const seatY = seatHeight * u\n  const cushion = 0.08 * u\n  const base = 0.09 * u\n  const backH = (look.back === 'high' ? 0.68 : 0.46) * u\n  const legs = Array.from({ length: LEGS }, (_, i) => (i / LEGS) * Math.PI * 2)\n\n  return (\n    <RigidBody type=\"fixed\" colliders={false} position={position} rotation={rotation}>\n      <CuboidCollider args={[0.26 * u, seatY / 2, 0.26 * u]} position={[0, seatY / 2, 0]} />\n\n      {/* five-star base on casters */}\n      {legs.map((a) => (\n        <group key={a} rotation={[0, a, 0]}>\n          <mesh position={[0, base, 0.17 * u]} rotation={[0.12, 0, 0]} castShadow>\n            <boxGeometry args={[0.04 * u, 0.03 * u, 0.32 * u]} />\n            <meshStandardMaterial color={frame} roughness={0.4} metalness={0.5} />\n          </mesh>\n          <mesh position={[0, 0.03 * u, 0.31 * u]} castShadow>\n            <sphereGeometry args={[0.03 * u, 10, 8]} />\n            <meshStandardMaterial color=\"#1c1c1e\" roughness={0.6} />\n          </mesh>\n        </group>\n      ))}\n      {/* gas column */}\n      <mesh position={[0, (base + seatY - cushion) / 2, 0]} castShadow>\n        <cylinderGeometry args={[0.028 * u, 0.034 * u, seatY - cushion - base, 12]} />\n        <meshStandardMaterial color={frame} roughness={0.3} metalness={0.7} />\n      </mesh>\n      {/* seat */}\n      <RoundedBox\n        args={[0.5 * u, cushion, 0.48 * u]}\n        radius={0.03 * u}\n        smoothness={3}\n        position={[0, seatY - cushion / 2, 0.01 * u]}\n        castShadow\n        receiveShadow\n      >\n        <meshStandardMaterial color={cloth} roughness={0.9} />\n      </RoundedBox>\n      {/* back, on a spine up from under the seat, reclined a touch */}\n      <mesh position={[0, seatY + 0.06 * u, -0.25 * u]} castShadow>\n        <boxGeometry args={[0.05 * u, 0.22 * u, 0.025 * u]} />\n        <meshStandardMaterial color={frame} roughness={0.4} metalness={0.5} />\n      </mesh>\n      <RoundedBox\n        args={[0.46 * u, backH, 0.07 * u]}\n        radius={0.03 * u}\n        smoothness={3}\n        position={[0, seatY + 0.1 * u + backH / 2, -0.28 * u]}\n        rotation={[-0.12, 0, 0]}\n        castShadow\n        receiveShadow\n      >\n        <meshStandardMaterial color={cloth} roughness={0.9} />\n      </RoundedBox>\n      {look.arms &&\n        [-1, 1].map((s) => (\n          <group key={s} position={[s * 0.27 * u, seatY, -0.02 * u]}>\n            <mesh position={[0, 0.1 * u, 0]} castShadow>\n              <boxGeometry args={[0.03 * u, 0.2 * u, 0.03 * u]} />\n              <meshStandardMaterial color={frame} roughness={0.4} metalness={0.5} />\n            </mesh>\n            <mesh position={[0, 0.21 * u, 0.02 * u]} castShadow>\n              <boxGeometry args={[0.06 * u, 0.03 * u, 0.26 * u]} />\n              <meshStandardMaterial color=\"#232326\" roughness={0.7} />\n            </mesh>\n          </group>\n        ))}\n    </RigidBody>\n  )\n}\n\nOfficeChair.groundSitting = true\n",
      "type": "registry:component"
    }
  ]
}
