# 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 to `server/` and `client/`. 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) 1. **The per-tile content requirements list** — the target (reverse-derivation). 2. **Biome authority** — `planet-gen` reliefmap coloring vs in-cascade `subbiome::classify`; which is canonical, and what that implies for where water (and other features) is authored. 3. **The atlas dataset family** — which layers are prebaked; format; determinism. 4. **Dual artifact** — baked reliefmap ↔ semantic model: representation + how they stay in sync (regen pipeline). 5. **The refinement contract** — the inter-layer hint+seed→geometry API; anti-squaring; how each layer hands constraints to the next. 6. **Context-driven morphology** — the algorithm families + the context inputs they require; the have-vs-owe data fork. 7. **Cascade placement + `gamedata/` restructure** — where water/derivation is authored; restructure scope/timing. 8. **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: 1. Your contribution to the **reverse requirements list** — what must a tile (or the data feeding it) contain, from your lens. 2. The key **forks/risks** you see in the derivation model. 3. 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` (existing `depression_fill`, D8 routing, rivers/basins, the new Moore boundary trace), `server/src/atlas/layer1.rs` (`Layer1Output` incl. `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.