Files
settled-reach/tooling/domains/atlas/planet/biomes.toml
T
jpmschweitzerandClaude Opus 5.5 668772075c refactor(tooling): T-1288 — planet-gen becomes reach atlas planet
The 30-file tree moves under atlas as its third rung (D-243), ten verbs
fronting it. Each verb restates its module's options so `--help` describes
something; tooling/test_planet_router.py hands every declared option to the
module's own argparse and fails on drift, and now runs in make test-tooling.

The 2026-09-02 half of this move had converted the top-level imports and the
repo roots. Finishing it found what the half-move left:

- Lazy in-function imports, and all of sol_data/, still named siblings bare.
  They resolved only through sys.path.insert hacks, so under reach the first
  globe render in generate, batch or sol-import would have raised
  ModuleNotFoundError. Qualified; the hacks are gone.
- 247 print() calls and a stdout progress writer that fired once per 8 KB
  block. Report verbs (audit, quality) write through console.out, progress
  through console.event, and download progress is throttled to 10% steps
  so a job log is not tens of thousands of lines.
- Every error exit raises ReachError with a fix.

Two checks that could not fail:

- batch --verify-determinism printed a warning and exited 0 on a mismatch.
- import-provinces exited 0 with errors > 0.

Both now raise. The 271-body bake is only safe to re-run because the first
one holds.

sol-import --body is action="append" in the module but the router took one
value, so --body GJ0d --body GJ0e kept one. Now repeatable, and _flags repeats
list options.

test_conformance walked one level, so a nested group was reported as a verb
missing @command and its ten verbs were never checked. It recurses now;
proven by stripping @command from `planet quality` and watching it fail.

Stray PNGs from the 2026-09-03 runaway router-test run are parked in
.cache/t1288-stray-pngs/, not committed. Their reliefmaps differ from HEAD
while the heightmap regenerated byte-identical — filed as T-1291.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 16:08:02 +02:00

343 lines
14 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Planet Generator — Biome & Color Configuration
#
# Single source of truth for biome classification, color palettes,
# and rendering parameters. Loaded by planet_simulation.py,
# render_heightmap.py, and planet_renderer.py.
#
# Edit this file to adjust colors without touching Python code.
# ─────────────────────────────────────────────────────────────────────
# Whittaker biome classification table
#
# Temperature axis is ABSOLUTE KELVIN — not normalized per-world.
# Moisture axis is [0, 1].
# Order matters: first match wins.
# ─────────────────────────────────────────────────────────────────────
[[whittaker]]
id = 5
name = "tropical_rainforest"
temp_lo = 303
temp_hi = 999
moist_lo = 0.65
moist_hi = 1.00
[[whittaker]]
id = 6
name = "tropical_seasonal"
temp_lo = 303
temp_hi = 999
moist_lo = 0.35
moist_hi = 0.65
[[whittaker]]
id = 7
name = "savanna"
temp_lo = 293
temp_hi = 999
moist_lo = 0.18
moist_hi = 0.35
[[whittaker]]
id = 15
name = "hot_desert"
temp_lo = 303
temp_hi = 999
moist_lo = 0.00
moist_hi = 0.18
[[whittaker]]
id = 9
name = "temperate_deciduous"
temp_lo = 283
temp_hi = 308
moist_lo = 0.55
moist_hi = 1.00
[[whittaker]]
id = 8
name = "temperate_grassland"
temp_lo = 278
temp_hi = 303
moist_lo = 0.30
moist_hi = 0.55
[[whittaker]]
id = 10
name = "temperate_rainforest"
temp_lo = 278
temp_hi = 303
moist_lo = 0.60
moist_hi = 1.00
[[whittaker]]
id = 9
name = "temperate_deciduous_cool"
temp_lo = 273
temp_hi = 293
moist_lo = 0.30
moist_hi = 0.60
[[whittaker]]
id = 12
name = "shrubland"
temp_lo = 278
temp_hi = 303
moist_lo = 0.10
moist_hi = 0.30
[[whittaker]]
id = 14
name = "subtropical_desert"
temp_lo = 283
temp_hi = 308
moist_lo = 0.00
moist_hi = 0.18
[[whittaker]]
id = 13
name = "temperate_desert"
temp_lo = 273
temp_hi = 293
moist_lo = 0.00
moist_hi = 0.30
[[whittaker]]
id = 11
name = "boreal_taiga"
temp_lo = 253
temp_hi = 278
moist_lo = 0.40
moist_hi = 1.00
[[whittaker]]
id = 11
name = "boreal_dry"
temp_lo = 253
temp_hi = 278
moist_lo = 0.15
moist_hi = 0.40
[[whittaker]]
id = 16
name = "tundra"
temp_lo = 243
temp_hi = 263
moist_lo = 0.00
moist_hi = 1.00
[[whittaker]]
id = 16
name = "cold_tundra"
temp_lo = 233
temp_hi = 253
moist_lo = 0.20
moist_hi = 1.00
[[whittaker]]
id = 17
name = "ice_snow"
temp_lo = 200
temp_hi = 243
moist_lo = 0.00
moist_hi = 1.00
[[whittaker]]
id = 17
name = "ice_cold_dry"
temp_lo = 243
temp_hi = 273
moist_lo = 0.00
moist_hi = 0.15
# ─────────────────────────────────────────────────────────────────────
# Temperature bands per planet class (Kelvin)
# Fiction wins over physics — temperature is clamped to these bands.
# ─────────────────────────────────────────────────────────────────────
[temperature_bands]
# Core classes
temperate = [275, 305]
oceanic = [278, 300]
forest = [275, 308]
arid = [295, 340]
frozen = [210, 265]
volcanic = [290, 380]
barren = [180, 380]
# Extended classes
temperate_terminator = [260, 310] # sharp day/night gradient, wide band
cold_arid = [240, 290] # cold desert (Mars-analog)
hot_arid = [310, 360] # scorching desert
tropical = [295, 315] # hot and wet
boreal = [245, 278] # cold forest / taiga
# ─────────────────────────────────────────────────────────────────────
# Biome color palette
#
# Each biome class has two color modes:
# cartographic — map colors (National Geographic style, readable)
# photographic — orbital appearance (dark, muted, realistic)
#
# RGB values 0-255.
# ─────────────────────────────────────────────────────────────────────
[biome_colors]
# Ocean
0 = { name = "ocean_deep", cartographic = [ 80, 155, 190], photographic = [ 18, 45, 80] }
1 = { name = "ocean_mid", cartographic = [110, 185, 215], photographic = [ 28, 72, 115] }
2 = { name = "ocean_shallow", cartographic = [150, 210, 230], photographic = [ 42, 105, 145] }
# Coast / lowland
3 = { name = "coast", cartographic = [155, 185, 130], photographic = [ 90, 108, 75] }
4 = { name = "lowland", cartographic = [120, 165, 100], photographic = [ 72, 98, 58] }
# Tropical
5 = { name = "tropical_rainforest", cartographic = [ 50, 140, 65], photographic = [ 12, 38, 18] }
6 = { name = "tropical_seasonal", cartographic = [ 90, 170, 75], photographic = [ 28, 65, 28] }
7 = { name = "savanna", cartographic = [175, 210, 105], photographic = [108, 118, 55] }
# Temperate
8 = { name = "temperate_grassland", cartographic = [190, 210, 110], photographic = [118, 128, 62] }
9 = { name = "temperate_deciduous", cartographic = [ 70, 148, 70], photographic = [ 22, 55, 28] }
10 = { name = "temperate_rainforest", cartographic = [ 45, 125, 65], photographic = [ 15, 45, 22] }
11 = { name = "boreal_taiga", cartographic = [ 28, 88, 55], photographic = [ 8, 30, 18] }
12 = { name = "shrubland", cartographic = [168, 168, 95], photographic = [ 98, 88, 55] }
# Desert
13 = { name = "temperate_desert", cartographic = [215, 200, 155], photographic = [155, 138, 98] }
14 = { name = "subtropical_desert", cartographic = [210, 165, 85], photographic = [148, 108, 62] }
15 = { name = "hot_desert", cartographic = [215, 138, 55], photographic = [162, 98, 42] }
# Cold
16 = { name = "tundra", cartographic = [198, 185, 145], photographic = [ 95, 88, 72] }
17 = { name = "ice_snow", cartographic = [235, 238, 242], photographic = [218, 228, 238] }
18 = { name = "mountain_rock", cartographic = [148, 135, 120], photographic = [ 88, 80, 72] }
# Volcanic
19 = { name = "lava_field", cartographic = [ 55, 32, 22], photographic = [ 38, 22, 15] }
# Exotic / extremophile
20 = { name = "chemosynthetic_mat", cartographic = [ 45, 88, 52], photographic = [ 18, 38, 22] }
21 = { name = "thermophilic_field", cartographic = [118, 72, 40], photographic = [ 78, 45, 22] }
22 = { name = "sulfuric_scrub", cartographic = [148, 130, 58], photographic = [ 98, 85, 35] }
23 = { name = "cryptobiotic_crust", cartographic = [130, 118, 100], photographic = [ 78, 70, 58] }
24 = { name = "lithic_pioneer", cartographic = [138, 125, 110], photographic = [ 82, 75, 65] }
25 = { name = "ash_field", cartographic = [ 68, 58, 52], photographic = [ 42, 35, 30] }
26 = { name = "ice_shelf", cartographic = [245, 246, 248], photographic = [235, 238, 242] }
# Dry terrain (atmosphere gate — non-vegetated)
27 = { name = "dust_plain", cartographic = [195, 165, 115], photographic = [175, 142, 95] }
28 = { name = "rocky_highland", cartographic = [175, 145, 105], photographic = [152, 122, 85] }
29 = { name = "warm_dust", cartographic = [210, 175, 120], photographic = [188, 155, 105] }
30 = { name = "cold_rock", cartographic = [160, 140, 115], photographic = [135, 118, 95] }
# Ferric terrain (iron oxide — Mars, arid iron-rich worlds)
34 = { name = "ferric_dust", cartographic = [185, 110, 65], photographic = [158, 88, 48] }
35 = { name = "ferric_highland", cartographic = [165, 100, 60], photographic = [138, 78, 42] }
36 = { name = "ferric_lowland", cartographic = [200, 130, 75], photographic = [172, 105, 58] }
# Lunar terrain (grey rock)
31 = { name = "lunar_highland", cartographic = [165, 165, 162], photographic = [138, 138, 135] }
32 = { name = "lunar_mare", cartographic = [120, 120, 118], photographic = [100, 100, 98] }
33 = { name = "lunar_midland", cartographic = [145, 145, 142], photographic = [118, 118, 115] }
# ─────────────────────────────────────────────────────────────────────
# Rendering colors (not biome-specific)
# ─────────────────────────────────────────────────────────────────────
[render_colors]
river = [ 80, 140, 200]
coastline = [ 30, 45, 35]
# ─────────────────────────────────────────────────────────────────────
# Star tints — subtle color shift from stellar type
# Applied multiplicatively to surface lighting.
# ─────────────────────────────────────────────────────────────────────
[star_tints]
O = [0.90, 0.92, 1.00]
B = [0.94, 0.96, 1.00]
A = [0.97, 0.98, 1.00]
F = [1.00, 0.99, 0.97]
G = [1.00, 0.97, 0.93]
K = [1.00, 0.93, 0.85]
M = [1.00, 0.88, 0.78]
# ─────────────────────────────────────────────────────────────────────
# Atmosphere rim colors per planet class (globe renderer)
# null = no atmosphere glow
# ─────────────────────────────────────────────────────────────────────
[atmosphere_colors]
temperate = [0.45, 0.65, 1.00]
temperate_terminator = [0.48, 0.62, 0.95]
oceanic = [0.40, 0.60, 1.00]
forest = [0.42, 0.68, 0.80]
arid = [0.90, 0.72, 0.50]
cold_arid = [0.82, 0.58, 0.40]
hot_arid = [0.92, 0.68, 0.42]
tropical = [0.48, 0.72, 0.85]
boreal = [0.50, 0.68, 0.95]
frozen = [0.75, 0.88, 1.00]
volcanic = [0.55, 0.40, 0.30]
# ─────────────────────────────────────────────────────────────────────
# Gas giant band palettes (globe renderer)
# Each palette is a list of RGB band colors.
# ─────────────────────────────────────────────────────────────────────
[gas_palettes]
jovian = [[0.78, 0.62, 0.44], [0.60, 0.44, 0.30], [0.88, 0.76, 0.60],
[0.72, 0.55, 0.38], [0.92, 0.84, 0.70], [0.55, 0.40, 0.28]]
neptunian = [[0.25, 0.45, 0.75], [0.35, 0.58, 0.85], [0.18, 0.35, 0.65],
[0.42, 0.65, 0.90], [0.20, 0.40, 0.70], [0.50, 0.70, 0.92]]
saturnian = [[0.82, 0.74, 0.55], [0.75, 0.66, 0.48], [0.88, 0.80, 0.62],
[0.70, 0.62, 0.44], [0.92, 0.86, 0.68], [0.65, 0.58, 0.42]]
icy = [[0.78, 0.85, 0.92], [0.70, 0.80, 0.90], [0.85, 0.90, 0.95],
[0.65, 0.75, 0.88], [0.90, 0.93, 0.97], [0.60, 0.70, 0.85]]
sulfuric = [[0.88, 0.80, 0.22], [0.80, 0.65, 0.18], [0.92, 0.86, 0.35],
[0.75, 0.60, 0.15], [0.85, 0.75, 0.28], [0.70, 0.55, 0.12]]
infernal = [[0.65, 0.18, 0.12], [0.45, 0.12, 0.08], [0.80, 0.25, 0.15],
[0.55, 0.15, 0.10], [0.72, 0.20, 0.12], [0.38, 0.10, 0.06]]
# Locked selection list for deterministic random palette assignment.
# Order matters — changing this changes which body gets which palette.
# Only add to the end. Never reorder or remove.
selection_order = ["jovian", "neptunian", "saturnian", "icy", "sulfuric", "infernal"]
# ─────────────────────────────────────────────────────────────────────
# Crater scaling factors
# atmosphere: fraction of impactors that survive entry
# tectonics: fraction of craters preserved (not resurfaced)
# Final crater count = base_count × atmo_factor × tect_factor
# ─────────────────────────────────────────────────────────────────────
[crater_scaling]
base_count = 300
[crater_scaling.atmosphere]
none = 1.0
thin = 0.6
standard = 0.25
thick = 0.08
[crater_scaling.tectonics]
none = 1.0
low = 0.7
active = 0.3
extreme = 0.1
# ─────────────────────────────────────────────────────────────────────
# Exotic biome class IDs (modifier stack in compute_biome)
# ─────────────────────────────────────────────────────────────────────
[exotic_classes]
chemosynthetic_mat = 20
thermophilic_field = 21
sulfuric_scrub = 22
cryptobiotic_crust = 23
ash_field = 25
lava_field = 19
ice_shelf = 26