feat(simulation): T-1127 glaciation ice tint + Marine color in zoom-ladder probe

aliveness_probe --render gains a 6th glaciation panel; glaciated
districts get an ice tint keyed on GlaciationGrade, and Marine
vegetation renders [0,96,172] — distinct from the morphology water
tones so district-carrier vs voxel-generator disagreement stays
visible in ladders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 08:21:27 +02:00
co-authored by Claude Fable 5
parent fef422bf01
commit 6aafa77583
+60 -5
View File
@@ -37,7 +37,8 @@ use settled_reach_server::atlas::believability::{
use settled_reach_server::atlas::body_world_state::BodyWorldState;
use settled_reach_server::atlas::chunk_context::derive_chunk_context;
use settled_reach_server::atlas::district_profile::{
derive_district, BodyParams, ClimateConstants, DistrictProfile, VegetationClass,
derive_district, BodyParams, ClimateConstants, DistrictProfile, GlaciationGrade,
VegetationClass,
};
use settled_reach_server::atlas::features::TerrainAnalysis;
use settled_reach_server::atlas::scale::{
@@ -335,8 +336,17 @@ const MORPHOLOGY_RGB: [[u8; 3]; 17] = [
[64, 115, 102], // 16 Wetland
];
/// The five attribute panels, in output order.
const PANEL_NAMES: [&str; 5] = ["morphology", "elev", "temp", "moisture", "veg"];
/// The attribute panels, in output order. `glaciation` is T-1127's dedicated
/// panel; the morphology panel additionally carries a per-pixel ice tint keyed
/// on the same field (see [`apply_ice_tint`]).
const PANEL_NAMES: [&str; 6] = [
"morphology",
"elev",
"temp",
"moisture",
"veg",
"glaciation",
];
/// Render the district window around the principal settlement and write one PNG
/// per panel to `out_dir`, plus a one-line manifest per image and a determinism
@@ -447,7 +457,7 @@ fn render_window_panels(
) -> Vec<(&'static str, Vec<u8>)> {
let n_i = n as i32;
let half = n_i / 2;
let mut bufs: [Vec<u8>; 5] = std::array::from_fn(|_| vec![0u8; (n * n) as usize * 3]);
let mut bufs: [Vec<u8>; 6] = std::array::from_fn(|_| vec![0u8; (n * n) as usize * 3]);
for row in 0..n_i {
for col in 0..n_i {
// Row 0 = northmost: smaller dy = further north (derive_district maps
@@ -455,11 +465,19 @@ fn render_window_panels(
let dp = (centre.0 - half + col, centre.1 - half + row);
let prof = derive_district(seed, body_id, params, ta, dp, climate);
let i = ((row * n_i + col) * 3) as usize;
set_rgb(&mut bufs[0], i, morphology_rgb(prof.morphology_zone));
// T-1127: the morphology color carries a per-pixel ice tint keyed on
// glaciation_grade (a render modifier — the frozen D-239 §6 zone
// vocabulary is untouched; tint = classifier-tuning territory).
set_rgb(
&mut bufs[0],
i,
apply_ice_tint(morphology_rgb(prof.morphology_zone), prof.glaciation_grade),
);
set_rgb(&mut bufs[1], i, gray_rgb(prof.elev_q));
set_rgb(&mut bufs[2], i, temperature_rgb(prof.temperature_c));
set_rgb(&mut bufs[3], i, moisture_rgb(prof.moisture_q));
set_rgb(&mut bufs[4], i, vegetation_rgb(prof.vegetation_class));
set_rgb(&mut bufs[5], i, glaciation_rgb(prof.glaciation_grade));
}
}
for buf in &mut bufs {
@@ -566,6 +584,43 @@ fn vegetation_rgb(v: VegetationClass) -> [u8; 3] {
VegetationClass::Forest => [30, 110, 40], // closed canopy
VegetationClass::RiparianScrub => [70, 170, 120], // waterway band (open)
VegetationClass::RiparianThicket => [10, 130, 90], // waterway band (dense)
// T-1126: open water — an ocean blue deliberately DISTINCT from the
// morphology water tones (OpenOcean 26,51,115 / Lake 51,102,166) so a
// veg-panel Marine cell is never mistaken for a morphology overlay.
VegetationClass::Marine => [0, 96, 172],
}
}
/// T-1127: blend the morphology color toward glacial ice-white by
/// `glaciation_grade` — a RENDER modifier only (the D-239 §6 frozen 17-zone
/// vocabulary is untouched; an actual ice zone would need its own D-amendment).
///
/// `Light` deliberately does NOT tint: grade 1 is glacial-erosion *signatures*
/// (U-valleys, moraines — landform history on coasts as warm as +5 °C mean),
/// not ice cover; visible ice starts where D-239 §5 gates glacial forms,
/// grade ≥ Moderate. The dedicated glaciation panel still shows Light.
fn apply_ice_tint(base: [u8; 3], grade: GlaciationGrade) -> [u8; 3] {
let t = match grade {
GlaciationGrade::None | GlaciationGrade::Light => return base,
GlaciationGrade::Moderate => 0.30,
GlaciationGrade::Heavy => 0.50,
GlaciationGrade::IceCap => 0.70,
};
lerp_rgb(
[base[0] as f32, base[1] as f32, base[2] as f32],
[228.0, 240.0, 250.0], // glacial ice white-blue
t,
)
}
/// T-1127: dedicated glaciation panel — categorical dark→ice ramp.
fn glaciation_rgb(grade: GlaciationGrade) -> [u8; 3] {
match grade {
GlaciationGrade::None => [30, 30, 30],
GlaciationGrade::Light => [96, 120, 150],
GlaciationGrade::Moderate => [150, 180, 210],
GlaciationGrade::Heavy => [200, 222, 240],
GlaciationGrade::IceCap => [240, 248, 255],
}
}