docs(decisions): atlas-to-tile derivation model — D-227/D-228 + Q-100..105
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>
This commit is contained in:
@@ -1530,4 +1530,41 @@ Technical foundation decisions that constrain implementation: engine, client-ser
|
||||
|
||||
---
|
||||
|
||||
*86 decisions (D-001 through D-226, excluding gaps). Last updated: 2026-05-24 (D-226 — live-pause inspection harness)*
|
||||
### D-227: Deterministic-rebuild world model — derive-don't-store, cache, tile mutators, volumetric
|
||||
- **Date:** 2026-05-25
|
||||
- **Decision:** The walkable world is a **pure function of `seed + atlas`**, materialised on demand and cached, never persisted as a tile grid.
|
||||
- **Derive-don't-store.** `subtile(x,y,z) = derive(seed, atlas, position)` — deterministic (D-010), recomputed on demand, held in a transient by-chunk/region cache for performance, evictable (eviction → recompute, always valid). No generated tile/voxel is ever saved.
|
||||
- **Volumetric, in voxels.** Unit vocabulary, fixed here: a **voxel** is the 1 m cube (the 3-D framing of D-222's tile); a **subvoxel** is its 0.5 m subdivision — eight per voxel, the finest derivation/dig granularity, in all three axes. Derivation is 3-D — surface *and* subsurface — over this grid. The heightmap/atlas sets the top; below it a deterministic geology model (strata by depth → bedrock; per-region lithology; ore / aquifer / cave as 3-D noise) fills downward. Digging reveals `derive(...)` for newly-exposed subvoxels — never "generated on dig"; the hole merely stops hiding seed-math.
|
||||
- **Floors are semantic and variable-height, not a fixed voxel count.** A *floor* — a walkable story, the z-level of D-049 / D-110 — groups voxels and **defaults to 3 voxels (3 m)** but is **not locked**: a cathedral nave or a hangar is one ~10 m floor, and that must be expressible. The voxel/subvoxel substrate is uniform and continuous in z; a floor exists wherever the volume is **walkable void**, and that void can be **built** (buildings), **excavated** (basements, mines), or **natural** (caves, lava tubes, caverns — derived in the geology model as 3-D voids). A cave is as much a floor as a basement; only truly solid rock is floorless. z-level addressing indexes stories whose real height in voxels varies.
|
||||
- **Vertical extent is physical, not a floor count.** The old "±50 floors" framing was a *stored-grid* artifact (each z-level was a filled, stored layer with memory/fill cost). Derive-don't-store eliminates that cost, so: **down** is bound by the body's own geology (crust → bedrock → pressure/heat-impassable interior, a per-body depth tied to radius / `max_elevation`); **up** is bound by *max built-structure height* (towers are built/authored or player-placed, not natural-derived) over free-to-derive air. This **supersedes any ±50 cap** — none was ever recorded as a D-record; it survived only as a 50-floor-skyscraper *example* in the generator-architecture workshop.
|
||||
- **Persistence = tile mutators only.** A save is `seed + a sparse log of tile mutators` — the additions and destructions the player or simulation made (pave a road, build a wall, dig a shaft, fell a tree, demolish a structure). Load = re-derive the base, then replay mutators over it. Saves are tiny regardless of world size. (Mutator op schema → Q-103.)
|
||||
- **Determinism reclassified safety-critical.** Because mutators reference derived state, any derivation drift (a non-deterministic algorithm, an f32 comparison/ordering, `HashMap` iteration) desyncs the whole save — not merely a cosmetic difference. D-010's integer-only + ordered-collection discipline is load-bearing for *saves*, not just for golden tests.
|
||||
- **Rationale:** A world that stores its tiles cannot scale to body-sized 3-D volumes and bloats saves; a pure-function world with a transient cache + a sparse mutator log scales to any size, makes saves trivially small, and is the only model under which "dig anywhere, to any depth" is free (the subsurface was always computable — digging just reveals it). It also forces the determinism discipline the whole cascade needs anyway. The downward floor cap fell because it was solving a problem — per-layer storage cost — that derive-don't-store eliminates.
|
||||
- **Open sub-questions:** the geology-model fidelity (simple depth-horizon stack vs tectonic-grade folding/faults) and how far `FloorMaterial` is derived now vs deferred to the city layers (both tracked in D-228 / Q-101); the mutator op schema (Q-103).
|
||||
- **Implementation:** Phase 4+ (epic #750). The caching substrate exists at the atlas level (`BodyWorldStateCache`, D-203/D-225); the tile/voxel cache, mutator overlay, and geology derivation land as the cascade reaches the tile layers. No migration needed pre-save (D-202 `schema_version` lineage covers future drift once saves exist).
|
||||
- **Raised by:** Jeroen (derive-don't-store, volumetric, drop-the-floor-cap directives) + Claude, atlas-derivation workshop, 2026-05-25.
|
||||
- **Cross-reference:** [D-010](#d-010) (determinism — now save-critical), [D-222](#d-222) (subtile/tile/chunk hierarchy), [D-110](#d-110) (signed z-levels), [D-225](#d-225) (layer-stream proxy + cache pattern), [D-203](#d-203) (LRU cache tier), [D-224](#d-224) (SeedChain — feeds `derive`), [D-228](#d-228) (composite tile schema — the derived value type), [Q-101](questions-architecture.md#q-101) (refinement contract), [Q-103](questions-architecture.md#q-103) (mutator op schema), [Q-104](questions-architecture.md#q-104) (floor↔voxel-z mapping)
|
||||
- **Dissent:** None
|
||||
|
||||
---
|
||||
|
||||
### D-228: Composite tile schema — orthogonal axes, derived shape, region-level morphology
|
||||
- **Date:** 2026-05-25
|
||||
- **Decision:** A tile's "type" is **not a flat enum** but a small bundle of **orthogonal axes** (all *derived* per D-227 — this is the cache's value type, not stored state). Named types ("fjord wall", "mountain pass", "river bank") are **derived display labels, never stored**: a fjord wall and a sea cliff are identical to the simulation (`Cliff + Rock + DeepWater`), differing only in name.
|
||||
- **Per-subtile axes:** `TerrainMaterial` (natural ground — Soil / Sand / Gravel / Rock / Wetland / Snow / Ice / Lava) · `FloorMaterial` (built surface over the ground — None / Concrete / Pavement / Carpet / Metal / …) · `Vegetation` (ground cover — Barren / Grass / Scrub / Thicket / Forest / Crop / Cleared / …) · `Water` (local depth *state* — Dry / Shallow / Deep) · `elevation` (scalar, metres). The `FloorMaterial` / `Vegetation` vocabularies stay open, extended by the layers that own them.
|
||||
- **`FloorMaterial` and `Vegetation` are override stacks, not single derivations.** Each resolves in precedence **wild/natural (biome + climate) → economic (managed: farmland, plantation, paving, clearance — from the settlement layer) → user (mutators: chopped, planted, built, demolished)**; the topmost present layer wins — the same derive-don't-store + mutator pattern (D-227) as the rest of the world. `Vegetation` carries cover/concealment, the movement sound profile, *and* economic yield (timber / crops) on one axis — and managed crops follow the region seasonal cycle (sown → growing → ripe → harvested → fallow), so farmland visibly turns over with the year (Q-105).
|
||||
- **`Water` is a dynamic depth state, plus derived flow.** The axis is depth/wetness only; the water *feature semantics* (river / ocean / lake / sea / tidal-flat / delta) are the **region morphology zone** (below), not a per-tile value, and **flow direction** derives from the D8 network where moving water applies. Depth is **time-varying** via a deliberately cheap, deterministic, **clock-bound** water-height — a **seasonal** term phased by hemisphere (latitude sign) and a **tidal** term that exists only if the body has a moon (no satellite → no tide), amplitudes as body parameters. The water-height is a **region property computed once per phase** (not per tile, not per frame); per-tile flood state is then just `region-water-height vs local elevation`. So **floodplain / tidal-flat / seasonal-river *emerge*** rather than being placed — a low `alluvial-plain` floods at high water and recedes at low. The static world stays static; only this region water-height carries the clock overlay (sim-time as the derivation input), recomputed on phase change — the dynamic-state path D-226 anticipates. Passability derives from `Water` + `elevation` + `material` together. (Model → Q-105.)
|
||||
- **Derived, not stored:** **shape / geometry** (flat / angled / drop / cliff) = `f(elevation-step × material)` — sand slumps to an angle of repose, rock breaks to a vertical face on the same 1 m step; drives the rendered tile geometry. **Tactical form** (crest / hollow / channel / bank — cover, sightline, concealment) read from elevation curvature + water adjacency on demand. Storing either would mean updating 8 neighbours per elevation change, and both are clean functions of data the tile already holds.
|
||||
- **Region-level (shared by all tiles in a region, not stored per-tile):** **morphology zone** — fjord / delta / meander-reach / **alluvial-plain** / open-ocean / lake / sea / … — the whole-shape decision a single tile cannot see; it (a) governs which tile-tags get laid down, (b) carries affordances a tile can't (this inlet is a sheltered harbour), and (c) **owns the water-feature semantics** (river vs ocean vs lake vs sea) the per-tile `Water` axis deliberately omits. **Morphology resolves top-down (region → tile), never bottom-up** — a tile cannot know it is in a fjord from its neighbours; deriving it per-tile would produce the squaring the model exists to avoid. **Sub-biome, province, and the region's seasonal/clock state are likewise region properties** — the season is computed *once* per region per phase and inherited by its tiles. That single cheap seasonal state drives **water-height (flooding / tides), seasonal snow cover, weather, and the farmland crop cycle** alike — one calculation, many dynamic overlays (→ Q-105).
|
||||
- **Separate axes:** biome (climate / sub-biome — region-level, authority unresolved, Q-100; distinct from, but informs, the per-tile `Vegetation` cover), resource hints (bitmask: fertile / mineral / timber / groundwater).
|
||||
- **Cohesion matrix (anti-squaring at the material layer):** intra-region material + sub-biome scatter (a dirt patch in grass, a lone rock in beach sand) comes from a **global, position-keyed continuous noise field — never per-chunk** — so transitions never reveal chunk/grid seams. Straight lines appear **only when authored** (roads, plazas, field edges); a straight line must always have a placed cause, never be a generation-grid artifact. (Algorithm → Q-102.)
|
||||
- **Rationale:** A flat enum explodes combinatorially (≈5×5×8 ≈ 200 mostly-incoherent variants), can't be queried by axis ("all water-adjacent tiles"), and grows a new variant for every new mechanic. Orthogonal axes are set independently by different cascade passes (material from sub-biome, water from drainage, shape from elevation), independently queryable, cheap to serialize, and compose without explosion. Names are visual/narrative and belong downstream of the simulation.
|
||||
- **Open sub-questions:** how far the `FloorMaterial` / `Vegetation` vocabularies are enumerated now vs deferred to the settlement layers; the exact morphology-zone vocabulary; the dynamic water-height model (→ Q-105).
|
||||
- **Implementation:** Phase 4+ (epic #750), as the cascade reaches the tile layers. Today's `TileKind` (D-049 render stack) is the seed of the per-subtile axes; `SubBiomeVariant` (D-210) is the region biome axis.
|
||||
- **Raised by:** Jeroen (FloorMaterial, shape-from-material, cohesion-matrix directives) + Claude, with the atlas-derivation workshop four — Tyre (composite data-structure), Gestalt (tag model + tactical form), Nigel (morphology-as-character), Burnelli (economic distinctions), 2026-05-25.
|
||||
- **Cross-reference:** [D-227](#d-227) (derive-don't-store — these axes are the derived value type), [D-010](#d-010), [D-210](#d-210) (sub-biome — region biome axis), [D-222](#d-222) (subtile/tile), [D-049](#d-049) (z-stack render — `TileKind` seed), [D-208](#d-208) (D8 — flow-direction source), [D-226](#d-226) (dynamic-state inspection — the water overlay), [Q-100](questions-architecture.md#q-100) (biome authority), [Q-101](questions-architecture.md#q-101) (refinement contract), [Q-102](questions-architecture.md#q-102) (cohesion-matrix algorithm), [Q-105](questions-architecture.md#q-105) (dynamic water-height)
|
||||
- **Dissent:** None
|
||||
|
||||
---
|
||||
|
||||
*88 decisions (D-001 through D-228, excluding gaps). Last updated: 2026-05-25 (D-227 deterministic-rebuild world model, D-228 composite tile schema — atlas-derivation workshop)*
|
||||
|
||||
@@ -347,4 +347,52 @@ Technical foundation questions: engine, protocols, data structures, performance,
|
||||
|
||||
---
|
||||
|
||||
*48 questions (9 resolved, 1 partially resolved, 38 open). Last updated: 2026-05-23.*
|
||||
### Q-100: Biome authority — Python sim vs Rust cascade
|
||||
- **Status:** Open — raised in the atlas-derivation workshop (2026-05-25)
|
||||
- **Question:** Two independent biome systems exist. `planet_simulation.py` (build-time) computes biome from a Whittaker table + sim-derived temperature/moisture and colours `reliefmap.png` — the authoritative *visual*. `subbiome::classify` (Rust, runtime, D-210) re-derives `SubBiomeVariant` from proxies (elevation percentile, slope, river-distance moisture, latitude temperature). They diverge — a cold fjord coast reads `CoastalLowland` in Rust, which lacks the temperature field. Which is canonical? (A) Python canonical → bake temperature + moisture as additional atlas layers the Rust cascade reads (richer; more storage/pipeline; mod-friendly per D-225); (B) Rust canonical → re-render reliefmaps from cascade output at bake time (simpler; loses the atmospheric sim; regenerates ~267 reliefmaps); (C) keep split (pragmatic; contradicts the dual-artifact principle, D-226). Related sub-fork: the Python river-carve (colours the reliefmap) and the Rust D8 network (D-208) also diverge — the dual artifact requires reconciling them.
|
||||
- **Context:** Tyre's top integration snag. Blocks the biome axis of D-228 and the dual-artifact reconciliation. Tyre's lean: A long-term, B for Phase 4, with the expansion path designed in.
|
||||
- **Cross-reference:** [D-228](architecture.md#d-228), [D-226](architecture.md#d-226), [D-210](architecture.md#d-210), [D-208](architecture.md#d-208), [D-225](architecture.md#d-225), `tooling/planet-gen/planet_simulation.py`, `server/src/atlas/subbiome.rs`
|
||||
|
||||
---
|
||||
|
||||
### Q-101: Refinement / derivation contract — coarse hint → fine geometry + morphology algorithm family
|
||||
- **Status:** Open — the atlas-derivation workshop's primary technical output, not yet specified (2026-05-25)
|
||||
- **Question:** How does a coarse, map-scale hint (a ~78 km Layer-1 cell) plus a seed become fine, ~1 m-voxel coherent geometry — deterministically, without squaring — across ~3 scale jumps (78 km cell → ~1 km region → 64 m chunk → 1 m voxel)? Needs: the inter-layer hint+seed→geometry API (Tyre sketched a `RegionHint`); a **context-driven morphology algorithm family** selected by local context (rivers meander in lowlands / incise in mountains; coasts dune / crag / fjord by slope + lithology + glaciation), ≥6 distinct generators (meander, incised gorge, braided delta, dune strand, cliff coast, fjord, mountain pass); integer-only *structural* decisions (D-010), f64 confined to within-voxel interpolation; clean transitions between adjacent morphology families. **Unowned dependency:** the ocean/lake mask — D-223 stripped the markers.json polygons that D-209 `CoastalAccess`/`LakeShore` extraction referenced, so the mask must instead be derived from the heightmap sea-level threshold or a baked water-bodies layer. Lithology is a required input (promoted load-bearing by the volumetric subsurface, D-227). Also in scope: **body-class parameters** (hydrosphere, tectonic activity, atmosphere) must modulate river-network *density* — the effective river threshold — so an arid body and an oceanic body differ in *how many* rivers, not just where they run (today `RIVER_THRESHOLD` is a global constant, Nigel); and **river flow direction** (upstream/downstream — gates effort vs speed, and feeds the seasonal water model) derives from the D8 network at query time.
|
||||
- **Context:** The heart of the atlas→tile derivation; surfaces as the cascade builds the region → chunk → voxel layers.
|
||||
- **Cross-reference:** [D-227](architecture.md#d-227), [D-228](architecture.md#d-228), [D-208](architecture.md#d-208), [D-209](architecture.md#d-209), [D-223](architecture.md#d-223), [D-010](architecture.md#d-010), [D-222](architecture.md#d-222)
|
||||
|
||||
---
|
||||
|
||||
### Q-102: Cohesion-matrix algorithm — seam-free continuous variation
|
||||
- **Status:** Open — deferred from D-228 (2026-05-25)
|
||||
- **Question:** D-228 mandates that intra-region material / sub-biome scatter come from a **global, position-keyed continuous noise field** so chunk/region boundaries never read as grid seams, while authored straight lines (roads, plazas) stay crisp. Concretely: the noise basis (value / Perlin / simplex / worley); keying on world position (not chunk index) to stay continuous across boundaries; how material / sub-biome thresholds map onto it; integer-only / determinism (D-010); and how authored linear features composite over the continuous field without bleeding.
|
||||
- **Context:** The anti-squaring principle pushed down to the material layer.
|
||||
- **Cross-reference:** [D-228](architecture.md#d-228), [D-227](architecture.md#d-227), [D-010](architecture.md#d-010)
|
||||
|
||||
---
|
||||
|
||||
### Q-103: Tile-mutator op schema
|
||||
- **Status:** Open — deferred from D-227 (2026-05-25)
|
||||
- **Question:** D-227 makes tile mutators the sole persisted state (save = `seed + mutator log`). What does one mutator record — a full per-voxel override, or typed ops (`Dig`, `Build(FloorMaterial)`, `Place(object)`, `Destroy(object)`, `SetMaterial`)? Typed ops are compact, semantic, replayable, but need a fixed op vocabulary; full overrides are simple but heavier and lose intent. Also: replay ordering / conflict semantics, and confirmation that a position-keyed mutator stays valid across re-derivation (determinism guarantees an identical base — to be pinned).
|
||||
- **Context:** Needed when the save system is built (Phase 5+).
|
||||
- **Cross-reference:** [D-227](architecture.md#d-227), [D-010](architecture.md#d-010)
|
||||
|
||||
---
|
||||
|
||||
### Q-104: Floor-index ↔ absolute voxel-z coordinate mapping
|
||||
- **Status:** Open — flagged by Tyre in the atlas-derivation workshop (2026-05-25)
|
||||
- **Question:** D-227 introduces an absolute physical z coordinate (metres, continuous over the voxel grid) alongside D-110's floor-*index* addressing (`base_z: i8`, a story-counting integer). The two coexist but the bridge is undefined: "the floor at `base_z = -2`" → which absolute voxel-z values does it span? With variable-height floors (D-227 — default 3 voxels, a cathedral ~10), the mapping is **non-linear** (a floor's voxel-z depends on the heights of the floors below it). What is the mapping function, and where is it owned (a per-building floor table? a region floor-height index?)? Needed before anything queries both systems (Phase 5 building interiors / vertical movement). Gap, not contradiction — D-227 and D-110 do not conflict.
|
||||
- **Context:** Raised in the atlas-derivation workshop (Tyre, Round 2 review of D-227).
|
||||
- **Cross-reference:** [D-227](architecture.md#d-227), [D-110](architecture.md#d-110), [D-049](architecture.md#d-049), [D-222](architecture.md#d-222)
|
||||
|
||||
---
|
||||
|
||||
### Q-105: Region seasonal/clock state — the shared cheap-dynamism source
|
||||
- **Status:** Open — committed in principle (D-228); model details open (2026-05-25)
|
||||
- **Question:** D-228 commits to a deliberately cheap, deterministic, **region-level seasonal/clock state** — computed *once* per region per phase, inherited by its tiles — from which several dynamic overlays derive: **water-height** (floodplain / tidal-flat / seasonal-river), **seasonal snow cover**, **weather**, and the **farmland crop cycle** (sown → growing → ripe → harvested → fallow). The model must stay "nearly free" — simple deterministic functions of the in-game clock + body/region parameters, no per-tile or per-frame simulation. Open: the exact phase functions — a **seasonal** term phased by hemisphere (latitude sign), driven by the year clock; a **tidal** term only when the body has a moon (no satellite → no tide), driven by the lunar/day clock with amplitude from the satellite config; how snow-depth, weather, and the crop cycle each read the same state; the **static-vs-seasonal split** (permanent snow/ice is `TerrainMaterial`, seasonal snow is this dynamic overlay); determinism (state = `f(clock, region)` → reproducible) and its interaction with the cache + the D-226 pause/inspection (a frozen phase for stable inspection); and recompute cadence (per phase-change, not per frame).
|
||||
- **Context:** Grew from the floodplain dependency — "floodplain is only feasible if water heights move" — into a general cheap-dynamism source. Jeroen's constraints: clock + hemisphere bound, moon-gated tides, computed once per region, simple rules; snow / weather / crop cycle ride the same calculation.
|
||||
- **Cross-reference:** [D-228](architecture.md#d-228), [D-227](architecture.md#d-227), [D-226](architecture.md#d-226) (dynamic-state inspection), [D-010](architecture.md#d-010)
|
||||
|
||||
---
|
||||
|
||||
*54 questions (9 resolved, 1 partially resolved, 44 open). Last updated: 2026-05-25.*
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user