Groundwork for the demo becoming a splash TEMPLATE. Two things the script
surface could not express, so the demo had to stay in Rust.
**`game.terrain` carried its own single-octave value noise.** That meant the
terrain an AI could reach from splash was strictly worse than the terrain the
engine could make, and the two drifted independently — every fix to
`libs/game/gen/terrain.rs` (fBm, domain warp, world-unit frequency,
slope-aware colour, rim relief) was invisible to any authored game. It now
calls that generator. One generator, one set of bugs.
New params exposed: `feature` (distance between hills, in world units —
answerable, unlike "what is a good freq"), `octaves`, `warp`, `ridged`,
`flatten`, `rim`/`rim_start`.
Two compatibility decisions worth stating:
- `freq` still works. It meant cycles per CELL INDEX, so its wavelength in
world units is span/((cells-1)*freq); translating rather than ignoring it
keeps an existing world looking like itself.
- `step` now defaults to 0, not 1.0. The old default quantised every smooth
slope into one-unit stairs, so a script asking for smooth terrain got a
contour map. Scripts that want terraces still ask for them.
**`Car` now carries a model**, as `Character` already did, and `game.car`
takes `{model}`. Without it a host could only ever draw ONE kind of car —
which is exactly why the arcade fleet had to live in Rust, and why a
splash-authored world could not have more than a single vehicle shape.
The renderer prefers the car block's own model and falls back to walking the
`parked_car` role, so the same code path serves an authored game and the
built-in demo without the script needing to know the fallback exists.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>