component

Chair

Chair with seat, back, and legs.

⌖ Explore the library in 3D → · View as Markdown

Tune every prop in the workshop →

Add it

npx @runek/cli add chair

Pulls @react-three/rapier@^2.2.0, @runek/core@^0.15.0.

Use it

import { Chair } from './runek/Chair'

<Chair position={[0, 0, 0]} />

Or as a node in a world file (worlds as data):

{ "type": "Chair", "props": { "position": [0, 0, 0] } }

Props

Prop Type Default Description
position [x, y, z] [0, 0, 0] Position [x, y, z] in units (1 unit = 1 m, Y-up).
rotation [x, y, z] [0, 0, 0] Euler rotation [x, y, z] in radians.
seed number Accepted for the component contract; this component has no seeded variation yet.
width number 0.45 Width, in units.
depth number 0.45 Depth, in units.
seatHeight number 0.45
backHeight number 0.5
color color palette wood Defaults to the world palette’s wood slot.

Registry manifest

registry manifest /r/components/chair.json Self-contained JSON: inlined source plus resolved dependencies, exactly what runek add chair fetches.

Browse the whole catalog in the gallery →.

Source (Chair.tsx)
import { CuboidCollider, RigidBody } from '@react-three/rapier'
import { useWorld, type Vec3 } from '@runek/core'

export interface ChairProps {
  position?: Vec3
  rotation?: Vec3
  /** Accepted for the component contract; this component has no seeded variation yet. */
  seed?: number
  width?: number
  depth?: number
  seatHeight?: number
  backHeight?: number
  /** Defaults to the world palette's `wood` slot. */
  color?: string
}

export function Chair({
  position = [0, 0, 0],
  rotation = [0, 0, 0],
  width = 0.45,
  depth = 0.45,
  seatHeight = 0.45,
  backHeight = 0.5,
  color,
}: ChairProps) {
  const { unit, palette } = useWorld()
  const woodColor = color ?? palette.wood
  const w = width * unit
  const d = depth * unit
  const seatY = seatHeight * unit
  const backH = backHeight * unit
  const t = 0.04 * unit
  const leg = 0.04 * unit
  const lx = w / 2 - leg
  const lz = d / 2 - leg
  const legs: Vec3[] = [
    [-lx, seatY / 2, -lz],
    [lx, seatY / 2, -lz],
    [-lx, seatY / 2, lz],
    [lx, seatY / 2, lz],
  ]

  return (
    <RigidBody type="fixed" colliders={false} position={position} rotation={rotation}>
      <CuboidCollider args={[w / 2, t, d / 2]} position={[0, seatY, 0]} />
      <mesh castShadow receiveShadow position={[0, seatY, 0]}>
        <boxGeometry args={[w, t, d]} />
        <meshStandardMaterial color={woodColor} />
      </mesh>
      <mesh castShadow receiveShadow position={[0, seatY + backH / 2, -d / 2 + t / 2]}>
        <boxGeometry args={[w, backH, t]} />
        <meshStandardMaterial color={woodColor} />
      </mesh>
      {legs.map((p) => (
        <mesh key={`leg-${p[0].toFixed(3)}:${p[2].toFixed(3)}`} castShadow position={p}>
          <boxGeometry args={[leg, seatY, leg]} />
          <meshStandardMaterial color={woodColor} />
        </mesh>
      ))}
    </RigidBody>
  )
}

Chair.groundSitting = true