component

Bed

Bed with a frame, mattress, pillows, and a headboard.

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

Tune every prop in the workshop →

Add it

npx @runek/cli add bed

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

Use it

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

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

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

{ "type": "Bed", "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 1.4 Width, in units.
length number 2 Length, in units.
color color palette wood Frame color; defaults to the world palette’s wood slot.
beddingColor color palette fabric Bedding color; defaults to the world palette’s fabric slot.

Registry manifest

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

Browse the whole catalog in the gallery →.

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

export interface BedProps {
  position?: Vec3
  rotation?: Vec3
  /** Accepted for the component contract; this component has no seeded variation yet. */
  seed?: number
  width?: number
  length?: number
  /** Frame color; defaults to the world palette's `wood` slot. */
  color?: string
  /** Bedding color; defaults to the world palette's `fabric` slot. */
  beddingColor?: string
}

/** A bed: frame, mattress, pillows, and a headboard (at local -Z). Finishes a
 *  bedroom. Solid, so it owns one cuboid collider. */
export function Bed({
  position = [0, 0, 0],
  rotation = [0, 0, 0],
  width = 1.4,
  length = 2,
  color,
  beddingColor,
}: BedProps) {
  const { unit, palette } = useWorld()
  const wood = color ?? palette.wood
  const bedding = beddingColor ?? palette.fabric
  const W = width * unit
  const L = length * unit
  const frameH = 0.3 * unit
  const mattH = 0.22 * unit
  const headH = 0.9 * unit
  const topY = frameH + mattH

  return (
    <RigidBody type="fixed" colliders={false} position={position} rotation={rotation}>
      <CuboidCollider args={[W / 2, topY / 2, L / 2]} position={[0, topY / 2, 0]} />

      <mesh castShadow receiveShadow position={[0, frameH / 2, 0]}>
        <boxGeometry args={[W, frameH, L]} />
        <meshStandardMaterial color={wood} roughness={0.85} />
      </mesh>
      <mesh castShadow receiveShadow position={[0, frameH + mattH / 2, 0]}>
        <boxGeometry args={[W * 0.96, mattH, L * 0.94]} />
        <meshStandardMaterial color={bedding} roughness={0.9} />
      </mesh>
      {[-1, 1].map((s) => (
        <mesh
          key={`pillow-${s}`}
          castShadow
          position={[s * W * 0.24, topY + 0.04 * unit, -L / 2 + 0.28 * unit]}
        >
          <boxGeometry args={[W * 0.4, 0.1 * unit, 0.32 * unit]} />
          <meshStandardMaterial color="#f2ede2" roughness={0.95} />
        </mesh>
      ))}
      <mesh castShadow receiveShadow position={[0, headH / 2, -L / 2 - 0.04 * unit]}>
        <boxGeometry args={[W, headH, 0.1 * unit]} />
        <meshStandardMaterial color={wood} roughness={0.85} />
      </mesh>
    </RigidBody>
  )
}

Bed.groundSitting = true