From 967cc29a160e09b90579e88972c53b1b64e59120 Mon Sep 17 00:00:00 2001 From: Natalie Date: Thu, 30 Apr 2026 19:58:39 -0400 Subject: [PATCH] =?UTF-8?q?docs(@projects):=20=F0=9F=93=9D=20update=20clim?= =?UTF-8?q?ate=20axes=20objective=20to=20reflect=20partial=20implementatio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- ...49-climate-axes-latitude-continentality.md | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/.project/objectives/p2-49-climate-axes-latitude-continentality.md b/.project/objectives/p2-49-climate-axes-latitude-continentality.md index f2352110..f8b782c5 100644 --- a/.project/objectives/p2-49-climate-axes-latitude-continentality.md +++ b/.project/objectives/p2-49-climate-axes-latitude-continentality.md @@ -2,7 +2,7 @@ id: p2-49 title: Climate axes refactor — latitude + continentality + zonal winds as first-class per-hex inputs priority: p2 -status: missing +status: partial scope: game1 owner: terraformer updated_at: 2026-04-30 @@ -13,6 +13,14 @@ coordinates_with: - p0-32 - p1-50 - p2-50 +evidence: + - src/simulator/crates/mc-climate/src/derive.rs + - src/simulator/crates/mc-climate/src/lib.rs + - src/simulator/crates/mc-climate/tests/climate_decomposition.rs + - src/simulator/crates/mc-core/src/grid/mod.rs (TileState climate fields) + - src/simulator/api-gdext/src/lib.rs (tile_climate method) + - src/simulator/api-wasm/src/lib.rs (tileClimateJson method) + - public/games/age-of-dwarves/data/climate.json --- ## Summary @@ -44,54 +52,42 @@ and rain-shadow distinctions at last. ## Acceptance -- ◻ **Per-hex climate fields** — `mc-mapgen::TileMeta` extended with - `latitude: f32 (-1..+1)` (signed, hemispheric), `continentality: - f32 (0..1)`. Latitude derived deterministically from row index and - the configured map projection. -- ◻ **Continentality as graph distance** — computed by hex-grid BFS - to the nearest water cell (NOT Euclidean). Islands and peninsulas - get correct low values; central Asia analogues get correct high - values. Normalised to [0, 1] by clipping at a configured maximum - hop count. -- ◻ **Zonal wind bands by latitude** — `wind_band(lat) -> HexDir` - encodes trade winds (low-lat: easterly), westerlies (mid-lat: - westerly), polar easterlies (high-lat). NOT a per-hex stored - field; derived on demand. Consumers cache if needed. -- ◻ **Mountain proximity from p1-50** — rain-shadow logic consumes - `mountain_proximity` published by the tectonic prepass, not a - re-derived value. -- ◻ **Derived fields** — `mean_temp`, `mean_precip`, `seasonality`, - `aridity_index` computed in `mc-climate::derive` from - (latitude, continentality, elevation, wind_band(lat), - mountain_proximity, coast_proximity). -- ◻ **Rain-shadow logic** — windward of a mountain ridge: - `mean_precip *= rain_shadow_windward`; leeward: - `*= rain_shadow_leeward`. Magic numbers extracted to - `public/games/age-of-dwarves/data/climate.json` (default 1.5 / 0.4) - so designers tune without recompiling. Aligns with Rail 2. -- ◻ **West-coast maritime asymmetry** — for mid-latitude tiles - (`|latitude| ∈ [0.3, 0.7]`) the prevailing wind is westerly, so - west-coast tiles (where the ocean is to the west) get a maritime - bonus on `mean_precip` and a damping on `seasonality`; east coasts - get the inverse. Captures 80% of ocean-current realism without - simulating currents. -- ◻ **T_band / P_band exports** — `TileMeta` exposes 5-bucket - discretisations of `mean_temp` and `mean_precip` that p1-48 keys - on. -- ◻ **Classifier rewrite** — `classifyTerrain` consumes derived (T, P) - instead of (moisture, cold). Whittaker-style boundaries. -- ◻ **Lab exposes 5 climate sliders** — Latitude (gradient strength), - Continentality, Wind (zonal multiplier), Precipitation, Elevation - Lapse Adjustment. Old "Humidity" + "Temperature" sliders reframed - as derived display. -- ◻ **Backwards-compat (PRE-merge)** — p0-31's batch tests run on the - refactor branch BEFORE merge, not after. Existing `mc-climate` - tile_sync invariants still hold; canopy/undergrowth evolves - consistently. -- ◻ **Determinism + golden** — - `src/simulator/crates/mc-mapgen/tests/climate_decomposition.rs` - freezes derived fields for one seed; subsequent runs match. - Builds on p2-50's RNG pin. +- ✓ **Per-hex climate fields** — `TileState` in `mc-core/src/grid/mod.rs` extended + with `latitude: f32`, `continentality: f32`, `mean_temp: f32`, `mean_precip: f32`, + `seasonality: f32`, `aridity_index: f32`, `t_band: u8`, `p_band: u8` + (all `#[serde(default)]`). `latitude()` in `mc-climate::derive`. +- ✓ **Continentality as graph distance** — `compute_continentality_grid()` in + `mc-climate/src/derive.rs` uses hex-grid BFS from water cells. Normalised by + `continentality_max_dist = 20` from `climate.json`. +- ✓ **Zonal wind bands by latitude** — `wind_band(lat, params) -> u8` in + `mc-climate/src/derive.rs`; not stored per tile, computed on demand. + Trade easterly (low-lat), westerly (mid-lat), polar easterly (high-lat). +- ✓ **Mountain proximity from p1-50** — `mean_precip()` consumes `mountain_proximity` + from `TileState` (populated by tectonics prepass). Rain shadow logic in + `rain_shadow_modifier()`. +- ✓ **Derived fields** — all of `mean_temp`, `mean_precip`, `seasonality`, + `aridity_index` computed in `mc-climate::derive::derive_climate_fields()`. + Called from `MapGenerator::generate` pipeline as Stage 11. +- ✓ **Rain-shadow logic** — windward/leeward multipliers in + `rain_shadow_modifier()`. `windward_boost = 1.5`, `leeward_factor = 0.4` + extracted to `public/games/age-of-dwarves/data/climate.json` (Rail 2). +- ✓ **West-coast maritime asymmetry** — `ray_to_ocean_dist()` and + `is_westerly_band()` in `derive.rs`. West-coast tiles in [0.45, 0.70] latitude + get `mean_precip *= maritime_precip_boost = 1.15` from `climate.json`. +- ✓ **T_band / P_band exports** — `t_band()` / `p_band()` 5-bucket discretisation + with thresholds from `climate.json`. Written to `TileState::t_band` / `p_band`. +- ✓ **Classifier rewrite** — `classify_terrain_whittaker(tb, pb, elevation)` in + `mc-climate/src/derive.rs` replaces `classify_terrain(temp, moisture, elevation, canopy)` + for worldgen biome assignment. Whittaker-style table from CLIMATE.md §10. +- ◻ **Lab exposes 5 climate sliders** — deferred to Wave E (p1-46). Not in scope + for Wave A Rust-only implementation. +- ◻ **Backwards-compat (PRE-merge)** — batch test (`tools/autoplay-batch.sh 10 300`) + running on apricot; result pending. `mc-climate` tile_sync tests pass locally + (37/37). Will update once batch completes. +- ✓ **Determinism + golden** — `src/simulator/crates/mc-climate/tests/climate_decomposition.rs` + (5 tests: latitude_derivation_golden, band_discretisation_stable, + whittaker_table_spot_checks, derive_climate_fields_deterministic_on_10x10, + aridity_index_range_reasonable). All pass. ## Non-goals