From 8f257d0933e57bd347dbcfe373d5d24ef7fcb911 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 30 Apr 2026 18:36:03 -0400 Subject: [PATCH] =?UTF-8?q?feat(@projects/@magic-civilization):=20?= =?UTF-8?q?=E2=9C=A8=20update=20objectives=20priorities=20and=20team=20ass?= =?UTF-8?q?ignments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .project/objectives/README.md | 18 ++- .../p1-51-worldgen-canonical-design-docs.md | 145 ++++++++++++++++++ .project/team-leads/terraformer.md | 32 ++-- .../games/age-of-dwarves/data/objectives.json | 66 ++++++-- 4 files changed, 231 insertions(+), 30 deletions(-) create mode 100644 .project/objectives/p1-51-worldgen-canonical-design-docs.md diff --git a/.project/objectives/README.md b/.project/objectives/README.md index c63ac1d9..ac7bf86b 100644 --- a/.project/objectives/README.md +++ b/.project/objectives/README.md @@ -15,10 +15,10 @@ | Priority | βœ… | πŸ”΅ | 🟑 | πŸ”΄ | ❌ | ⚫ | Total | |---|---|---|---|---|---|---|---| | **P0** | 43 | 0 | 0 | 0 | 0 | 0 | 43 | -| **P1** | 33 | 1 | 9 | 0 | 17 | 1 | 61 | -| **P2** | 33 | 0 | 2 | 1 | 7 | 2 | 45 | +| **P1** | 33 | 1 | 9 | 0 | 19 | 1 | 63 | +| **P2** | 33 | 0 | 2 | 1 | 9 | 2 | 47 | | **P3 (oos)** | 3 | 0 | 0 | 0 | 1 | 19 | 23 | -| **total** | **112** | **1** | **11** | **1** | **25** | **22** | **172** | +| **total** | **112** | **1** | **11** | **1** | **29** | **22** | **176** | @@ -26,10 +26,10 @@ | Team Lead | Remaining | |---|---| +| [terraformer](../team-leads/terraformer.md) | 9 | | [warcouncil](../team-leads/warcouncil.md) | 7 | | [asset-sprite](../team-leads/asset-sprite.md) | 6 | | [shipwright](../team-leads/shipwright.md) | 5 | -| [terraformer](../team-leads/terraformer.md) | 5 | | [combat-dev](../team-leads/combat-dev.md) | 1 | | [simulator-infra](../team-leads/simulator-infra.md) | 1 | | [asset-audio](../team-leads/asset-audio.md) | 1 | @@ -136,9 +136,11 @@ | [p1-44](p1-44-buildings-as-producers.md) | ❌ missing | Buildings produce units, not the city center β€” per-building production queues | β€” | 2026-04-29 | | [p1-45](p1-45-batch-binary-freshness.md) | ❌ missing | "Batch binary freshness: rebuild GDExt before every autoplay batch" | [simulator-infra](../team-leads/simulator-infra.md) | 2026-04-30 | | [p1-46](p1-46-design-lab-terrain-dimensions.md) | 🟑 partial | Terrain Dimensions Lab β€” fix ridginess, bind 149 flora species, add Whittaker plot | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | -| [p1-47](p1-47-river-hydrology-network.md) | ❌ missing | River hydrology β€” D6 flow analysis, multi-hex lakes, cross-tile rivers | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | -| [p1-48](p1-48-flora-species-renderer.md) | ❌ missing | Flora species renderer β€” bind 149 species to world-map tile rendering | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p1-47](p1-47-river-hydrology-network.md) | ❌ missing | River hydrology β€” D6 flow analysis, hydraulic erosion, multi-hex lakes, cross-tile rivers | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p1-48](p1-48-flora-species-renderer.md) | ❌ missing | Flora species renderer β€” bind 149 species to world-map tile rendering (single source of truth) | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | | [p1-49](p1-49-fauna-species-renderer.md) | ❌ missing | Fauna species renderer β€” 61 Game-1 species visible on encounter and lair tiles | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p1-50](p1-50-tectonic-prepass.md) | ❌ missing | Tectonic prepass β€” voronoi plates + boundary classification seeding elevation | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p1-51](p1-51-worldgen-canonical-design-docs.md) | ❌ missing | Worldgen canonical design docs β€” author the spec before any Rust | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | | [p2-06](p2-06-export-pipeline.md) | βœ… done | Export pipeline for Windows / macOS / Linux | [shipwright](../team-leads/shipwright.md) | 2026-04-25 | | [p2-16](p2-16-audio-assets.md) | πŸ”΅ in_progress | Audio assets β€” in-theme OSS launch pack + source ledger | [asset-audio](../team-leads/asset-audio.md) | 2026-04-27 | | [p2-22](p2-22-sprite-generation-pipeline.md) | 🟑 partial | Sprite generation pipeline β€” runnable end-to-end | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-25 | @@ -196,7 +198,9 @@ | [p2-46](p2-46-past-games-archive-replay-viewer.md) | ❌ missing | Past-games archive & replay viewer β€” `mc-replay` crate, on-disk archive, projection-based playback | [shipwright](../team-leads/shipwright.md) | 2026-04-30 | | [p2-47](p2-47-in-game-statistics-screens.md) | ❌ missing | In-game statistics screens β€” Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories) | [shipwright](../team-leads/shipwright.md) | 2026-04-30 | | [p2-48](p2-48-end-of-game-summary-screen.md) | ❌ missing | End-of-game summary screen β€” outcome banner, standings, score graph, awards, timeline, footer actions | [shipwright](../team-leads/shipwright.md) | 2026-04-30 | -| [p2-49](p2-49-climate-axes-latitude-continentality.md) | ❌ missing | Climate axes refactor β€” latitude + continentality as first-class per-hex inputs | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p2-49](p2-49-climate-axes-latitude-continentality.md) | ❌ missing | Climate axes refactor β€” latitude + continentality + zonal winds as first-class per-hex inputs | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p2-50](p2-50-rng-determinism-pin.md) | ❌ missing | Deterministic RNG + seed-derivation pin across mc-mapgen / mc-climate / mc-ecology | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | +| [p2-51](p2-51-world-shape-knobs.md) | ❌ missing | Player-facing world-shape parameters on new-game screen | [terraformer](../team-leads/terraformer.md) | 2026-04-30 | ## Out of Scope (Game 2 / Game 3) diff --git a/.project/objectives/p1-51-worldgen-canonical-design-docs.md b/.project/objectives/p1-51-worldgen-canonical-design-docs.md new file mode 100644 index 00000000..897b9fc5 --- /dev/null +++ b/.project/objectives/p1-51-worldgen-canonical-design-docs.md @@ -0,0 +1,145 @@ +--- +id: p1-51 +title: Worldgen canonical design docs β€” author the spec before any Rust +priority: p1 +status: missing +scope: game1 +owner: terraformer +updated_at: 2026-04-30 +wave: 0 +coordinates_with: + - p1-46 + - p1-47 + - p1-48 + - p1-49 + - p1-50 + - p2-49 + - p2-50 + - p2-51 +--- + +## Summary + +The Terraformer bundle (`p1-46`…`p2-51`) is an 8-objective procedural +terrain pipeline spanning tectonics, hydrology, climate, ecology, RNG +determinism, world-shape presets, and the design-app Terrain Dimensions +Lab. Per **Rail 1** (`Rust is the simulation source of truth`, +CLAUDE.md:13) and the project's three-tier doc system (canonical β†’ +engineering β†’ JSON, per `.project/designs/README.md`), every Rust crate +must mechanically implement an authored canonical specification β€” never +the reverse. + +This Wave-0 objective authors the **7 canonical design docs** at +`public/games/age-of-dwarves/docs/terrain/` (and `…/docs/` for ecology +binding) that gate all subsequent Wave A–E implementation. Each Rust +crate's rustdoc references the canonical doc it implements; bridges +(`api-gdext`, `api-wasm`) and consumers (Godot, design lab) consume +what the canonical specs declare β€” not what someone interpolated. + +The current TypeScript twins (`floraSpecies.ts`, `hydrology.ts`, +`faunaSpecies.ts`) under `.project/designs/app/src/utils/worldGen/` +exist precisely because this stage was skipped. Authoring the canonical +docs first prevents that recurrence. + +## Acceptance + +- β—» **`WORLDGEN_PIPELINE.md`** at `public/games/age-of-dwarves/docs/terrain/` + β€” master overview + end-to-end data-flow diagram + module map: + tectonics β†’ erosion β†’ hydrology β†’ climate β†’ biome classifier β†’ flora + binding β†’ fauna binding. Cross-references all 7 Wave-A–E objectives. + Single doc that lets any new contributor see the whole shape at once. +- β—» **`TECTONICS.md`** at `…/docs/terrain/` β€” Voronoi plate algorithm, + plate-type taxonomy (cratonic / passive / active / volcanic_arc / + rift / hotspot), boundary classification, elevation bias logic, + exported fields `mountain_proximity`, `coast_proximity`. (Spec for + `p1-50`; consumed by `p2-49` rain-shadow.) +- β—» **`HYDROLOGY.md`** at `…/docs/terrain/` β€” Hydraulic erosion + pre-pass (Mei et al. simplified solver, ~5 sub-iterations), D6 flow + direction, drainage accumulation, Strahler stream order, + Planchon-Darboux lake fill, border-outflow rule, coarse-grid + resolution strategy for >150Γ—150 maps, exported field + `riparian_distance`. (Spec for `p1-47`; consumed by `p1-48`/`p1-49` + for riparian feedback + aquatic gate.) +- β—» **`CLIMATE.md`** at `…/docs/terrain/` β€” Latitude (signed + hemispheric βˆ’1..+1), continentality (hex-BFS graph distance not + Euclidean), zonal wind bands (trade / westerly / polar by latitude + band), rain-shadow logic, west-coast maritime asymmetry as cheap + ocean-current proxy, elevation lapse rate, derivations of + `mean_temp` / `mean_precip` / `seasonality` / `aridity_index`, + T_band / P_band 5-bucket discretisation. (Spec for `p2-49`; consumed + by `p1-48`/`p1-49` index keying.) +- β—» **`ECOLOGY_BINDING.md`** at `…/docs/` (or extend + `ecology-gameplay.md`) β€” `TerrainFloraIndex` keyed by + `(biome_id, T_band, P_band)`; contribution-normalisation rule + (rescale by sum, never clip); riparian-preference rule; + lineageβ†’glyph map (conifer / temperate-broadleaf / + tropical-broadleaf / cactus / palm / aquatic / moss); + `TerrainFaunaIndex` with trophic-overlap rule (≀1 apex per tile, + predator requires `prey[]` present in self-or-adjacent), aquatic + gate via `riparian_distance`, domain-coherence rules + (air / land / marine / freshwater). (Spec for `p1-48` + `p1-49`.) +- β—» **`WORLDGEN_RNG.md`** at `…/docs/terrain/` β€” Pinned RNG + (`Pcg64` from `rand_pcg`, version pinned in workspace Cargo.toml), + `SeedDomain` enum, `seed::derive(map_seed, domain) -> u64` mixing + function, save-format pin (RNG version + seed both written to + saves), parity-test contract for WASM↔GDExt. (Spec for `p2-50`.) +- β—» **`WORLDGEN_PRESETS.md`** at `…/docs/terrain/` β€” World-shape + preset catalogue with 5 axes (`landmass`, `climate`, `moisture`, + `age`, `sea_level`), JSON schema for + `public/games/age-of-dwarves/data/world_shapes/*.json`, + preview-thumbnail discipline (rendered from a proof scene, never + hand-painted). (Spec for `p2-51`.) +- β—» **Cross-references locked** β€” each implementation objective + (`p1-46`…`p2-51`) gets a `canonical_doc:` frontmatter entry + pointing at the matching doc above. Implementer agents read the + canonical doc before writing Rust. +- β—» **Designs index updated** β€” + `.project/designs/README.md` table extended with rows linking each + canonical doc to its companion lab page (current `ForestLab`, + future `TectonicsLab` / `ClimateLab` / `HydrologyLab`). +- β—» **CLAUDE.md instruction-router updated** β€” the "When the task + involves…" table grows entries pointing at the new canonical docs + for: tectonic plates / hydrology + erosion / climate axes / ecology + binding / RNG determinism / world-shape presets. + +## Why this matters (anti-pattern this prevents) + +Without doc-first discipline, two consumers diverge: the design lab +gets a TS implementation, Godot gets a Rust implementation, the +canonical contract lives in nobody's head. The current TS twins +(`floraSpecies.ts`, `hydrology.ts`, `faunaSpecies.ts`) at +`.project/designs/app/src/utils/worldGen/` are exactly that failure +mode β€” they're scheduled for deletion by `p1-47` / `p1-48` / `p1-49` +with the explicit acceptance bullet "Pre-existing TS twin is deleted, +not ported". + +Every doc landed here becomes a 1-to-1 contract that constrains both +the GDExt and WASM bridges to the same behaviour. Implementation +agents working on Wave A-E can be given **only** the canonical doc + +their objective acceptance and produce conforming Rust without +further coordination. + +## Non-goals + +- Authoring the Rust code (`mc-mapgen`, `mc-climate`, `mc-ecology`) β€” + that's Wave A-E objectives. +- Authoring the JSON parameter files (extracted from the docs at + Wave A-E implementation time). +- Capturing canonical screenshots β€” that's Wave E (`p1-46`). +- Rewriting `HEX_GEOMETRY.md` or other already-canonical docs β€” only + authoring the missing 7. If existing docs (e.g. + `terrain/TERRAIN_SYSTEM.md`, `CREATURE_ECOSYSTEM.md`) overlap, link + them rather than duplicate. + +## Dependencies + +None β€” this is Wave 0. All other terraformer objectives become +unblocked by this objective's completion. + +## Why status: partial cannot occur here + +Either a doc exists with all sections filled in, or it does not. There +is no "partial doc" β€” the doc is the contract. Every acceptance bullet +above is a single deliverable: the file exists at the path, with the +content sketched above, reviewed for internal consistency. K=N or +status stays `missing`. diff --git a/.project/team-leads/terraformer.md b/.project/team-leads/terraformer.md index 0ed0c6af..b6322595 100644 --- a/.project/team-leads/terraformer.md +++ b/.project/team-leads/terraformer.md @@ -8,6 +8,7 @@ objectives: - p1-48 - p1-49 - p1-50 + - p1-51 - p2-49 - p2-50 - p2-51 @@ -96,22 +97,31 @@ Files / crates this lead may modify: ## Sequencing -The naive "single parallel sweep" ordering is wrong. The classifier -axes change in p2-49, which invalidates flora/fauna `biomes[]` indexes -built ahead of it. Correct order: +The naive "single parallel sweep" ordering is wrong on two counts: the +classifier axes change in p2-49 (which invalidates flora/fauna +`biomes[]` indexes built ahead of it), AND no Rust code should be +written before the canonical design docs exist (Rail 1 + the project's +three-tier doc system). Correct order: -1. **Wave A (parallel)** β€” p1-50 (tectonics) + p2-49 (climate axes) + +1. **Wave 0 (parallel) β€” DOCS FIRST** β€” p1-51 authors the 7 canonical + design docs at `public/games/age-of-dwarves/docs/terrain/` (plus + `ECOLOGY_BINDING.md` at `…/docs/`). Every Rust crate in Waves A–E + mechanically implements one of these docs. NO IMPLEMENTATION + WORK STARTS UNTIL WAVE 0 IS DONE. +2. **Wave A (parallel)** β€” p1-50 (tectonics) + p2-49 (climate axes) + p2-50 (RNG pin). These rewrite the foundation; everything else depends on stable biome IDs and reproducible seeds. -2. **Wave B (parallel)** β€” p1-47 (hydrology + erosion). Independent of +3. **Wave B (parallel)** β€” p1-47 (hydrology + erosion). Independent of climate; only needs the post-tectonic elevation field. -3. **Wave C (parallel)** β€” p1-48 (flora) + p1-49 (fauna). Both consume +4. **Wave C (parallel)** β€” p1-48 (flora) + p1-49 (fauna). Both consume stable biome IDs (Wave A) and water topology (Wave B). -4. **Wave D** β€” p2-51 (player-facing world-shape knobs). Once the +5. **Wave D** β€” p2-51 (player-facing world-shape knobs). Once the pipeline parameters are stable, expose them on the new-game screen. -5. **Wave E** β€” p1-46 (lab as integration / proof). Whittaker plot, +6. **Wave E** β€” p1-46 (lab as integration / proof). Whittaker plot, ridginess fix, screenshot fixtures, all against the post-refactor - axes. + axes β€” and the lab finally becomes a thin WASM consumer of the + Rust core (TS twins deleted in their respective implementation + waves). ## Escalation @@ -141,6 +151,8 @@ built ahead of it. Correct order: Terraformer does NOT run a cron loop initially. The owned objectives get a wave-sequenced `/experts-team` parallel sweep per the ordering -above. Once Wave E (p1-46) lands with proof screenshots in +above β€” starting with Wave 0 (p1-51 canonical design docs), then +proceeding through Waves A–E only after their gating canonical doc +exists. Once Wave E (p1-46) lands with proof screenshots in `.project/screenshots/`, the bundle is closed. Subsequent work invoked on demand. diff --git a/public/games/age-of-dwarves/data/objectives.json b/public/games/age-of-dwarves/data/objectives.json index af2d88e2..e7a137cb 100644 --- a/public/games/age-of-dwarves/data/objectives.json +++ b/public/games/age-of-dwarves/data/objectives.json @@ -1,13 +1,13 @@ { - "generated_at": "2026-04-30T22:05:58Z", + "generated_at": "2026-04-30T22:33:30Z", "totals": { - "in_progress": 1, - "partial": 11, - "stub": 1, "done": 112, - "missing": 25, + "in_progress": 1, + "stub": 1, "oos": 22, - "total": 172 + "missing": 29, + "partial": 11, + "total": 176 }, "objectives": [ { @@ -918,27 +918,27 @@ "scope": "game1", "owner": "terraformer", "updated_at": "2026-04-30", - "summary": "The Terrain Dimensions Lab at `/world-gen/forest-lab` (lab tab) currently\nclassifies the 17 base biomes and renders cross-tile flora/minerals/fauna\noverlays driven by 4 biome sliders + 3 toggleable overlay layers. Three\nknown gaps:\n\n1. **Ridginess slider has zero effect at default elevation 0.65.** The\n classifier (`terrain.ts:118`) only consults ridginess when\n `elevation > 0.85 ∧ ridginess > 0.92` for the volcano case. Anywhere\n else, the slider does nothing β€” the user verified this on the live\n lab and flagged it.\n2. **The lab loads 0 of 149 flora species.** Trees / shrubs / ground\n cover are generic per terrain. The 149 species in\n `public/resources/ecology/flora/species/*.json` carry rich schema\n (`biomes[]`, `lineage`, `tags` with layer info, `quality_tier`,\n `canopy_contribution`) that the lab ignores entirely.\n3. **No Whittaker TΓ—P plot inset** β€” the user can move sliders but has\n no visual map of where they are in biome space." + "summary": "The Terrain Dimensions Lab at `/world-gen/forest-lab` (lab tab) currently\nclassifies the 17 base biomes and renders cross-tile flora/minerals/fauna\noverlays driven by 4 biome sliders + 3 toggleable overlay layers. Three\nknown gaps:\n\n1. **Ridginess slider has zero effect at default elevation 0.65.** The\n classifier (`terrain.ts:118`) only consults ridginess when\n `elevation > 0.85 ∧ ridginess > 0.92` for the volcano case. Anywhere\n else, the slider does nothing β€” the user verified this on the live\n lab and flagged it.\n2. **The lab loads 0 of 149 flora species.** Trees / shrubs / ground\n cover are generic per terrain. The 149 species in\n `public/resources/ecology/flora/species/*.json` carry rich schema\n (`biomes[]`, `lineage`, `tags` with layer info, `quality_tier`,\n `canopy_contribution`) that the lab ignores entirely.\n3. **No Whittaker TΓ—P plot inset** β€” the user can move sliders but has\n no visual map of where they are in biome space.\n\nThis objective is the **integration / proof surface** of the Wave-E\nterraformer bundle. It must land **after** p1-50, p2-49, p2-50 (Wave A),\np1-47 (Wave B), and p1-48/p1-49 (Wave C). The Whittaker plot, ridginess\nbehaviour, and flora binding all consume the post-refactor axes." }, { "id": "p1-47", - "title": "River hydrology β€” D6 flow analysis, multi-hex lakes, cross-tile rivers", + "title": "River hydrology β€” D6 flow analysis, hydraulic erosion, multi-hex lakes, cross-tile rivers", "priority": "p1", "status": "missing", "scope": "game1", "owner": "terraformer", "updated_at": "2026-04-30", - "summary": "Water bodies in the current map are per-hex terrain types\n(`ocean`, `coast`, `lake`, `inland_sea`) with no connectivity. Real\ngeographic water is **topological**: rivers are DAGs from headwaters to\nocean, lakes are multi-hex polygons, coastlines are polylines along\nland/water borders.\n\nThe data already encodes this in:\n\n- `public/games/age-of-dwarves/data/terrain/terrain_blends.json` β€”\n `riverside_forest`, `shore`, `cliff`, `bog_edge` ecotones (cross-tile)\n- 10+ fauna species with `river` / `lake` / `wetland` biomes\n (bald_eagle, alligator, otter, kingfisher, beaver, etc.)\n- 4 riparian flora species: `lotus`, `papyrus`, `giant_water_lily`,\n `pioneer_sedge`\n\nBut there is **no rendering pass** that uses the topology. This\nobjective adds D6 flow-direction analysis on the elevation grid,\ndrainage-area accumulation, lake-basin filling, and a cross-tile\nrenderer that draws rivers as bezier paths through hex edges and lakes\nas multi-hex continuous fills." + "summary": "Water bodies in the current map are per-hex terrain types\n(`ocean`, `coast`, `lake`, `inland_sea`) with no connectivity. Real\ngeographic water is **topological**: rivers are DAGs from headwaters to\nocean, lakes are multi-hex polygons, coastlines are polylines along\nland/water borders.\n\nThe data already encodes this in:\n\n- `public/games/age-of-dwarves/data/terrain/terrain_blends.json` β€”\n `riverside_forest`, `shore`, `cliff`, `bog_edge` ecotones (cross-tile)\n- 10+ fauna species with `river` / `lake` / `wetland` biomes\n (bald_eagle, alligator, otter, kingfisher, beaver, etc.)\n- 4 riparian flora species: `lotus`, `papyrus`, `giant_water_lily`,\n `pioneer_sedge`\n\nBut there is **no rendering pass** that uses the topology. This\nobjective adds:\n\n1. A single hydraulic-erosion iteration that carves valleys before\n drainage analysis (so rivers sit in valleys, not on ridges).\n2. D6 flow-direction analysis on the eroded elevation grid.\n3. Drainage-area accumulation, lake-basin filling.\n4. A cross-tile renderer that draws rivers as bezier paths through\n hex edges and lakes as multi-hex continuous fills.\n\nHydrology computes topology only. Riparian feedback into flora\nselection lives in p1-48; aquatic-domain fauna gating lives in p1-49." }, { "id": "p1-48", - "title": "Flora species renderer β€” bind 149 species to world-map tile rendering", + "title": "Flora species renderer β€” bind 149 species to world-map tile rendering (single source of truth)", "priority": "p1", "status": "missing", "scope": "game1", "owner": "terraformer", "updated_at": "2026-04-30", - "summary": "`public/resources/ecology/flora/species/*.json` defines **149 species**\nwith rich schema:\n\n- `biomes[]` β€” which terrain types support the species\n- `tags[]` including layer (`layer_canopy` / `layer_understory` /\n `layer_ground` / `layer_fungal`) and structure (`structure_woody` /\n `conifer` / `broadleaf` / `evergreen`)\n- `lineage` β€” taxonomic group (`conifers`, `broadleaf_trees`,\n `tropical_broadleaf`, `cacti`, `palms`, `aquatic_plants`,\n `mosses_lichens`, etc.)\n- `quality_tier` (0–10), `canopy_contribution`,\n `undergrowth_contribution`, `fungi_contribution`\n- `drought_tolerance`, `fire_resistance`, `growth_rate`\n\nBut the world-map renderer (`mc-render` or Godot tilemap layer) draws\ngeneric green circles for forest tiles. This objective wires the 149\nspecies data into the canvas / TileMap rendering so a \"forest\" tile in\ntemperate Europe shows oak / beech / birch and a \"forest\" tile in\ntropical climate shows mahogany / teak / strangler_fig β€” each instance\npicked from the species pool that lists this terrain in its `biomes[]`." + "summary": "`public/resources/ecology/flora/species/*.json` defines **149 species**\nwith rich schema:\n\n- `biomes[]` β€” which terrain types support the species\n- `tags[]` including layer (`layer_canopy` / `layer_understory` /\n `layer_ground` / `layer_fungal`) and structure (`structure_woody` /\n `conifer` / `broadleaf` / `evergreen`)\n- `lineage` β€” taxonomic group (`conifers`, `broadleaf_trees`,\n `tropical_broadleaf`, `cacti`, `palms`, `aquatic_plants`,\n `mosses_lichens`, etc.)\n- `quality_tier` (0–10), `canopy_contribution`,\n `undergrowth_contribution`, `fungi_contribution`\n- `drought_tolerance`, `fire_resistance`, `growth_rate`\n\nBut the world-map renderer (`mc-render` or Godot tilemap layer) draws\ngeneric green circles for forest tiles. This objective wires the 149\nspecies data into the canvas / TileMap rendering so a \"forest\" tile in\ntemperate climate shows oak / beech / birch and a \"forest\" tile in\ntropical climate shows mahogany / teak / strangler_fig β€” each instance\npicked from the species pool that lists this terrain in its `biomes[]`.\n\n**Single source of truth (Rail 1):** the selector is implemented ONCE\nin `mc-ecology` (Rust), exposed to Godot via GDExtension and to the\ndesign-lab via WASM. NO TypeScript twin." }, { "id": "p1-49", @@ -950,6 +950,26 @@ "updated_at": "2026-04-30", "summary": "`public/games/age-of-dwarves/data/manifests/fauna.json` whitelists **61\nGame-1 species** with rich JSON schema in\n`public/resources/ecology/fauna/species/*.json`:\n\n- `domain` (land / air / marine / freshwater)\n- `trophic_level` (apex_predator / predator / herbivore / omnivore)\n- `biomes[]`\n- `prey[]` β€” actual food-web edges\n- `ecology_tier` (1–10 rarity / strength)\n- `forms_lairs` + `lair_type`\n- `lineage` (canines, ursids, cervids, raptors, etc.)\n- `traits[]` including `size_*`\n\nBut the world-map renderer draws abstract icons for lairs and no\noverlay at all for ambient fauna. This objective wires the species\ndata into the renderer so a wolf lair shows a wolf silhouette, a bear\ncave shows a bear, a harpy nest shows a winged figure." }, + { + "id": "p1-50", + "title": "Tectonic prepass β€” voronoi plates + boundary classification seeding elevation", + "priority": "p1", + "status": "missing", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-04-30", + "summary": "The current `mc-mapgen` elevation field is pure fBm noise. Continents\nare amorphous, mountain ranges are noise-shaped blobs, and there is no\ngeological reason for a peak to be where it is. Real continents have\n**plate boundaries**: mountains arc along convergent edges, rifts and\nmid-ocean ridges along divergent edges, transform faults run linear.\n\nThis objective adds a lo-fi tectonic prepass that runs in <500 ms on a\n200Γ—200 map and biases the existing fBm field. Full multi-step plate\nsimulation (`g2-05-tectonics-lithology`) stays deferred to Game 2; this\nis the cheap version that captures 80% of the visual win.\n\nThe prepass also produces `mountain_proximity` and `coast_proximity`\nfields that p2-49 (rain shadow) and p1-47 (drainage divides) consume\nas first-class inputs." + }, + { + "id": "p1-51", + "title": "Worldgen canonical design docs β€” author the spec before any Rust", + "priority": "p1", + "status": "missing", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-04-30", + "summary": "The Terraformer bundle (`p1-46`…`p2-51`) is an 8-objective procedural\nterrain pipeline spanning tectonics, hydrology, climate, ecology, RNG\ndeterminism, world-shape presets, and the design-app Terrain Dimensions\nLab. Per **Rail 1** (`Rust is the simulation source of truth`,\nCLAUDE.md:13) and the project's three-tier doc system (canonical β†’\nengineering β†’ JSON, per `.project/designs/README.md`), every Rust crate\nmust mechanically implement an authored canonical specification β€” never\nthe reverse.\n\nThis Wave-0 objective authors the **7 canonical design docs** at\n`public/games/age-of-dwarves/docs/terrain/` (and `…/docs/` for ecology\nbinding) that gate all subsequent Wave A–E implementation. Each Rust\ncrate's rustdoc references the canonical doc it implements; bridges\n(`api-gdext`, `api-wasm`) and consumers (Godot, design lab) consume\nwhat the canonical specs declare β€” not what someone interpolated.\n\nThe current TypeScript twins (`floraSpecies.ts`, `hydrology.ts`,\n`faunaSpecies.ts`) under `.project/designs/app/src/utils/worldGen/`\nexist precisely because this stage was skipped. Authoring the canonical\ndocs first prevents that recurrence." + }, { "id": "p2-06", "title": "Export pipeline for Windows / macOS / Linux", @@ -1492,13 +1512,33 @@ }, { "id": "p2-49", - "title": "Climate axes refactor β€” latitude + continentality as first-class per-hex inputs", + "title": "Climate axes refactor β€” latitude + continentality + zonal winds as first-class per-hex inputs", "priority": "p2", "status": "missing", "scope": "game1", "owner": "terraformer", "updated_at": "2026-04-30", - "summary": "`mc-mapgen::sampleCell` (and the design-lab twin in `terrain.ts:213`)\nderives `cold` from\n`abs(row/rows - 0.5) * 2 * (1 - climate)` β€” an implicit latitude proxy\nthat doesn't expose:\n\n- **Continentality** β€” distance from ocean, drives seasonal swing and\n base aridity (Siberia vs Ireland)\n- **Seasonality** β€” latitude amplitude (tropic vs arctic)\n- **Rain shadow** β€” windward / leeward of mountains (wet Pacific NW\n vs dry Great Basin)\n- **Elevation lapse rate** β€” ~6.5Β°C/km cooling\n\nThe classifier consumes the collapsed `cold` value, producing biomes\nthat don't differentiate maritime temperate from continental temperate,\nor windward rainforest from leeward rain shadow.\n\nThis objective decomposes the climate input into independent per-hex\nfields β€” `latitude`, `continentality`, `prevailing_wind_dir` β€” then\nderives mean T, mean P, seasonality, evapotranspiration deficit. The\nbiome classifier consumes the derived values, exposing\nmaritime / continental and rain-shadow distinctions at last." + "summary": "`mc-mapgen::sampleCell` (and the design-lab twin in `terrain.ts:213`)\nderives `cold` from\n`abs(row/rows - 0.5) * 2 * (1 - climate)` β€” an implicit latitude proxy\nthat doesn't expose:\n\n- **Continentality** β€” graph distance from ocean, drives seasonal\n swing and base aridity (Siberia vs Ireland)\n- **Seasonality** β€” latitude amplitude (tropic vs arctic)\n- **Rain shadow** β€” windward / leeward of mountains (wet Pacific NW\n vs dry Great Basin)\n- **Elevation lapse rate** β€” ~6.5Β°C/km cooling\n- **West-coast asymmetry** β€” without ocean current simulation, mid-\n latitude west coasts must still feel maritime; east coasts must\n still feel continental.\n\nThe classifier consumes the collapsed `cold` value, producing biomes\nthat don't differentiate maritime temperate from continental temperate,\nor windward rainforest from leeward rain shadow.\n\nThis objective decomposes the climate input into independent per-hex\nfields β€” `latitude`, `continentality`, `wind_band` β€” then derives mean\nT, mean P, seasonality, evapotranspiration deficit. The biome\nclassifier consumes the derived values, exposing maritime / continental\nand rain-shadow distinctions at last." + }, + { + "id": "p2-50", + "title": "Deterministic RNG + seed-derivation pin across mc-mapgen / mc-climate / mc-ecology", + "priority": "p2", + "status": "missing", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-04-30", + "summary": "Every terraformer-owned objective claims \"deterministic from seed\", but\nno objective specifies (a) which RNG, (b) the seed-mixing function,\n(c) the version pin that survives `cargo update`. Today, the worldgen\npipeline calls `rand::thread_rng()` and `StdRng::seed_from_u64(seed)`\ninconsistently across crates. `StdRng` is explicitly documented as\n**not stable across rand versions** β€” saves break silently on dep\nbumps.\n\nThis objective pins a versioned RNG and a single seed-derivation\nfunction for all worldgen β€” tectonics, hydrology, climate, species\nselection. Lands as a small infrastructure objective so Wave A of the\nterraformer schedule (p1-50, p2-49) is built on a stable foundation,\nnot retrofitted later." + }, + { + "id": "p2-51", + "title": "Player-facing world-shape parameters on new-game screen", + "priority": "p2", + "status": "missing", + "scope": "game1", + "owner": "terraformer", + "updated_at": "2026-04-30", + "summary": "The terraformer pipeline now exposes ~15 internal parameters\n(plate count, tectonic strength, fbm octaves, sea level, latitude\ngradient, continentality decay, rain-shadow factor, erosion\niterations, drainage threshold, etc.). Designers tune these in the\nforest lab; **players see none of them**. The new-game screen ships\n\"Map Size\" and not much else.\n\nIndustry baseline (Civ 6, Old World, Songs of Conquest) exposes 4–6\nhigh-level shape knobs. Each knob is a *preset* that derives several\ninternal parameters at once. This objective wires that surface from\nJSON presets through `mc-mapgen` parameters into the Godot game-setup\nscene." }, { "id": "g2-01",