guide
The component contract
Every Runek component is a pure, deterministic function of its props — here are the rules.
Runek components all follow the same small contract. Honor it and a component is composable, serializable, and swappable with any other.
The rules
- Accept
position,rotation,seed. These are the shared base props (WorldComponentProps). Geometry is generated from them — nothing else. - Generate geometry in
useMemo, keyed on every geometry-affecting prop (includingseed). Same inputs → same mesh, no rebuild on unrelated renders. - Register your own colliders — a Rapier
RigidBody. Keep collider count proportional to gameplay surface, not visual detail (one cuboid for a bookshelf, not one per book). - Respect
unitfromuseWorld()so the component scales with the world. - No assets. Geometry and color come from code; no
.glb, no textures. - Default colors from the palette. Read
palettefromuseWorld()and use its slots (wood,wall,foliage, …) as your color defaults; an explicit color prop always wins. One palette swap then re-themes the whole world. - Instance repeated geometry. Books, branches, blades — render them as one
InstancedMesh, not one mesh per piece, so worlds stay cheap at scale.
A minimal compliant component
import { RigidBody } from '@react-three/rapier'
import { rng, useWorld, type Vec3 } from './runek/core'
import { useMemo } from 'react'
export interface CrateProps {
position?: Vec3
rotation?: Vec3
size?: number
seed?: number
}
export function Crate({ position = [0, 0, 0], rotation = [0, 0, 0], size = 1, seed = 1 }: CrateProps) {
const { unit } = useWorld()
const s = size * unit
const hue = useMemo(() => rng(seed)() * 0.1 + 0.05, [seed])
return (
<RigidBody type="fixed" colliders="cuboid" position={position} rotation={rotation}>
<mesh castShadow receiveShadow>
<boxGeometry args={[s, s, s]} />
<meshStandardMaterial color={`hsl(30, 40%, ${40 + hue * 100}%)`} />
</mesh>
</RigidBody>
)
}
Because the contract is uniform, a world is just a list of
{ type, props } — see worlds as data.
Contributing a component? The normative spec (with a conformance checklist) is
CONTRACT.md, and the
step-by-step workflow is
CONTRIBUTING.md.