structures
Room
Four walls + floor with a doorway and fixed colliders; optional roof.
Install
npx runek add room
Pulls: core@react-three/rapier@^2.2.0
Props
export interface RoomProps {
position?: Vec3
/** Interior footprint `[width, depth]`, in units. */
size?: [number, number]
height?: number
thickness?: number
/** Opening width in the front (+z) wall; set to 0 for a sealed room. */
doorWidth?: number
roof?: boolean
/** Defaults to the world palette's `wall` slot. */
color?: string
} Source
Room.tsx
import { RigidBody } from '@react-three/rapier'
import { useWorld, type Vec3 } from '@runek/core'
export interface RoomProps {
position?: Vec3
/** Interior footprint `[width, depth]`, in units. */
size?: [number, number]
height?: number
thickness?: number
/** Opening width in the front (+z) wall; set to 0 for a sealed room. */
doorWidth?: number
roof?: boolean
/** Defaults to the world palette's `wall` slot. */
color?: string
}
export function Room({
position = [0, 0, 0],
size = [8, 8],
height = 3,
thickness = 0.2,
doorWidth = 1.4,
roof = false,
color,
}: RoomProps) {
const { unit, palette } = useWorld()
const wallColor = color ?? palette.wall
const w = size[0] * unit
const d = size[1] * unit
const h = height * unit
const t = thickness * unit
const door = Math.min(doorWidth * unit, w)
const doorHeight = Math.min(2 * unit, h - t)
const post = (w - door) / 2
const midY = h / 2
return (
<RigidBody type="fixed" colliders="cuboid" position={position}>
<mesh receiveShadow position={[0, -t / 2, 0]}>
<boxGeometry args={[w, t, d]} />
<meshStandardMaterial color={wallColor} />
</mesh>
<mesh castShadow receiveShadow position={[0, midY, -d / 2 + t / 2]}>
<boxGeometry args={[w, h, t]} />
<meshStandardMaterial color={wallColor} />
</mesh>
<mesh castShadow receiveShadow position={[-w / 2 + t / 2, midY, 0]}>
<boxGeometry args={[t, h, d]} />
<meshStandardMaterial color={wallColor} />
</mesh>
<mesh castShadow receiveShadow position={[w / 2 - t / 2, midY, 0]}>
<boxGeometry args={[t, h, d]} />
<meshStandardMaterial color={wallColor} />
</mesh>
{/* front wall: two posts + lintel framing a doorway */}
<mesh castShadow receiveShadow position={[-(door / 2 + post / 2), midY, d / 2 - t / 2]}>
<boxGeometry args={[post, h, t]} />
<meshStandardMaterial color={wallColor} />
</mesh>
<mesh castShadow receiveShadow position={[door / 2 + post / 2, midY, d / 2 - t / 2]}>
<boxGeometry args={[post, h, t]} />
<meshStandardMaterial color={wallColor} />
</mesh>
{h > doorHeight && (
<mesh castShadow receiveShadow position={[0, (h + doorHeight) / 2, d / 2 - t / 2]}>
<boxGeometry args={[door, h - doorHeight, t]} />
<meshStandardMaterial color={wallColor} />
</mesh>
)}
{roof && (
<mesh receiveShadow position={[0, h + t / 2, 0]}>
<boxGeometry args={[w, t, d]} />
<meshStandardMaterial color={wallColor} />
</mesh>
)}
</RigidBody>
)
}