guide
Worlds as data
Because every component is a pure function of props, a whole world serializes to plain JSON.
Every component is a deterministic function of its props, so an entire scene can be
described as data — a list of { type, props } — then rendered, saved, diffed,
and edited like any file.
The shape
interface WorldData {
version: 1
unit?: number
gravity?: [number, number, number]
palette?: Partial<WorldPalette> // color-slot overrides for the whole world
fog?: { color: string; near: number; far: number }
nodes: WorldNode[]
}
interface WorldNode {
type: string // a registry key, e.g. "Bookshelf"
props?: Record<string, JsonValue>
children?: WorldNode[]
}
A small world:
{
"version": 1,
"palette": { "wood": "#7a5a40" },
"nodes": [
{ "type": "Terrain", "props": { "size": [40, 40] } },
{ "type": "Bookshelf", "props": { "position": [0, 1, 0], "seed": 42 } },
{ "type": "Player" }
]
}
The look of a world is data too: palette re-themes every component at once and
fog sets the atmosphere — both diff as cleanly as any node.
Render it
<WorldRenderer> maps each node’s type through a registry of components:
import { WorldRenderer, parseWorld } from './runek/core'
import { registry } from './runek/registry'
const world = parseWorld(await (await fetch('/my.world.json')).text())
<WorldRenderer data={world} registry={registry} />
Save it
serializeWorld(data) returns pretty JSON. The runtime editor
(<WorldEditor>) edits a WorldData live and exports it with the same call —
so a world round-trips: render → edit → serialize → commit.