Atlas-derivation workshop output (Jeroen + Tyre / Nigel / Burnelli / Gestalt). The foundational world-derivation model: - D-227 deterministic-rebuild world model: world = pure function of seed+atlas, derived on demand + cached, only tile mutators persisted, fully volumetric (voxel / subvoxel), vertical extent physical not floor-count, variable-height floors (cave/basement/built all count). - D-228 composite tile schema: orthogonal axes (TerrainMaterial / FloorMaterial / Vegetation / Water / elevation), derived shape + tactical form, region-level morphology zones, cohesion matrix, dynamic clock-bound region seasonal state (water-height / snow / weather / crop-cycle from one cheap per-region calc). - Q-100..Q-105: biome authority, refinement contract (+ body-class river density + ocean mask), cohesion-matrix algorithm, mutator op schema, floor-to-voxel-z mapping, region seasonal/clock state. - Workshop brief: docs/workshops/atlas-derivation-model.md. Epic #974 + ocean-mask story #975 track implementation (Phase 4 milestone). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.6 KiB
Workshop — The Atlas → Tile Derivation Model
Driven by the water model, but the water model is only the forcing instance.
Why this, why now
We are building the generation cascade (Phase 4). The viewer (#960) surfaced a problem that looks like "lakes" but is actually the inter-level derivation contract: how coarse, map-scale planetary data becomes fine, coherent, per-tile geometry without squared/blocky artifacts. This is cascade-first: if we bake the wrong derivation model now, every layer below (economic → settlement → quarters → tiles) inherits it and it becomes very expensive to unwind. Decide it before those layers exist. Stations are out of scope here — bodies first.
The methodology: reverse the derivation
Do not start from "what can the cascade derive?" Start from the target:
Build the complete list of everything a tile on a body must contain. Then work backward: for each item, how do we derive it deterministically from (a) a prebaked atlas dataset and/or (b) a seeded algorithm?
The requirements list is the spec. The cascade is the mechanism that satisfies it. We want the list first so the cascade is designed to a known target, not grown by accretion.
The three legs (generalized from the water instance)
1. Dual artifact — baked render ↔ semantic model. The reliefmap should have lakes/rivers/coastlines baked in (authoritative visual, no toggles — yes, that means regenerating reliefmaps). Separately, there is a semantic model (rivers as flow-carrying paths, lakes as regions, coasts as curves) that is the authoritative generation input. The reliefmap is a render of the model at map scale; the model is what lower levels consume.
2. Multi-scale refinement contract — hint, not squared truth. A reliefmap pixel is a map-scale rendering, not ground truth to copy downward. A 2-px river (sized for map visibility) is kilometers wide at tile scale; a land/water pixel edge is a staircase coastline. So coarse data is a semantic hint + a seed, and each lower level deterministically refines it into smooth, ~1-tile-scale geometry that respects the hint without copying its resolution. "Somewhere in this band a coherent coastline passes"; "a river of roughly this flow threads this corridor."
3. Context-driven algorithm family — selection is part of generation. Refinement is not one algorithm. The choice is driven by local context:
- Rivers: low slope → meandering, wide, lazy, floodplains/oxbows; steep → incised, straighter, gorges, knickpoint waterfalls; (braided/deltaic at the extremes).
- Coasts: low relief + sediment → smooth dune-lined strands; hard rock + high relief → craggy cliffs; drowned glaciated valleys → fjords.
Contract: hint + local context + seed → algorithm selection → geometry. Same hint, different terrain, genuinely different feature.
The expanding atlas (a key consideration for the brief)
Satisfying the per-tile list will almost certainly require more prebaked planetary layers than heightmap + reliefmap — plausibly: lithology distribution, a water-bodies layer, prevailing winds, temperature/precipitation, glaciation history, biomes. The workshop must take a position on:
- Which layers are prebaked vs runtime-derived (storage + determinism + the modding story — D-225's mod-first intent applies).
- Context data we have vs owe: slope/relief derive from the heightmap, but lithology (crag-vs-dune) and glaciation (fjords) may not exist yet. Decide whether morphology is selected from proxies we have, or a thin new context layer is owed (with its determinism + ownership cost).
- Organizational (future, "at some point"): moving all wiki content +
heightmaps into a new
gamedata/atlas subtree sitting next toserver/andclient/. Not a round-1 deliverable, but flag whether the data model implies it and roughly when.
Questions to resolve (each → a D-record or a tracked open question)
- The per-tile content requirements list — the target (reverse-derivation).
- Biome authority —
planet-genreliefmap coloring vs in-cascadesubbiome::classify; which is canonical, and what that implies for where water (and other features) is authored. - The atlas dataset family — which layers are prebaked; format; determinism.
- Dual artifact — baked reliefmap ↔ semantic model: representation + how they stay in sync (regen pipeline).
- The refinement contract — the inter-layer hint+seed→geometry API; anti-squaring; how each layer hands constraints to the next.
- Context-driven morphology — the algorithm families + the context inputs they require; the have-vs-owe data fork.
- Cascade placement +
gamedata/restructure — where water/derivation is authored; restructure scope/timing. - Determinism — D-010 integer-only must hold across all refinement + selection (seed → identical geometry).
Team angles
- Tyre — architecture: the derivation/refinement contract, dual raster +
semantic data structures, deterministic downscaling, atlas-layer storage, the
gamedata/restructure feasibility, performance/memory at tile scale. - Nigel — procedural variety/emergence: does the algorithm family + reverse-derivation yield rich, sensible, non-repetitive worlds across seeds? Where does sameness creep in? What's the second-playthrough payoff?
- Gestalt — systems meaning: drive the per-tile requirements list from "what creates interesting decisions / gameplay," and the consequences of morphology (a fjord is a deep defensible harbor; a meandering river is fertile + bridgeable; a craggy coast resists landing).
- Burnelli — economic layer needs: what the economy reads from the atlas — water as trade corridor vs barrier, ports/harbors, resource distribution, the regional scale the economy actually operates at.
Round 1 task (each agent)
Read this brief + the pointed code/decisions, then post an opening position on your angle that includes:
- Your contribution to the reverse requirements list — what must a tile (or the data feeding it) contain, from your lens.
- The key forks/risks you see in the derivation model.
- Anything in the current code/decisions that constrains or contradicts the approach.
This is investigation + position, not final design. Flag blockers early (heartbeat rule below).
Reading
- Code:
server/src/atlas/heightmap.rs(normalized elevation +sea_level, downsample),server/src/atlas/drainage.rs(existingdepression_fill, D8 routing, rivers/basins, the new Moore boundary trace),server/src/atlas/layer1.rs(Layer1Outputincl.grid_w/grid_h),server/src/atlas/layer_proxy.rs(D-225 proxy).tooling/planet-gen/—render_heightmap.py,planet_renderer.py(ocean colors, biome coloring),planet_simulation.py(max_elevation_km, biome assignment). - Decisions: D-202 (canonical 16-bit heightmap), D-208 (drainage), D-209 /
D-210 (attractors / sub-biomes), D-225 (layer-stream proxy, mod-first),
D-166 (generation-before-player). The cascade phase table in
CLAUDE.md. - Constraints: D-010 (determinism, integer-only), cascade-first (no detail from a later phase), the no-squaring principle above.
Process
Round-based. The lead synthesizes after each round and pulls Jeroen in — he decides when to dismiss. Close only when D-record(s) + ticket(s) exist (hard deliverables). Teammates edit files; the lead does all git.
Heartbeat rule: if you work a single task >15 min without progress, message the lead with what's blocking you. Do not silently retry.