Files
settled-reach/tooling/planet-gen/biomes.toml
T
jpmschweitzerandClaude Opus 4.6 f84275edf3 feat(assets): planet generator pipeline — heightmap + globe from wiki data
Full terrain-to-render pipeline at tooling/planet-gen/:
- body_definition_parser: reads system index.md → body definitions
- planet_simulation: FBM + Voronoi ridges, Whittaker biome classification,
  D8 river routing, physics-driven craters (atmo × tectonics scaling)
- render_heightmap: 4096×2048 cartographic maps with hillshade
- planet_renderer: 512×512 globe with terrain UV mapping, clouds, rings
- biomes.toml: externalized color/classification tables (single source)
- scaffold_bodies: creates per-body index.md with YAML frontmatter
- batch: unattended processing with error handling, resume, determinism check

Supports all body types: temperate, arid, frozen, volcanic, barren,
oceanic, gas giant (banded + ringed), and moons (half-size, grey, cratered).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 15:54:15 +02:00

327 lines
13 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]
temperate = [275, 305]
oceanic = [278, 300]
forest = [275, 308]
arid = [295, 340]
frozen = [210, 265]
volcanic = [290, 380]
barren = [180, 380]
# ─────────────────────────────────────────────────────────────────────
# 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] }
# 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]
oceanic = [0.40, 0.60, 1.00]
forest = [0.42, 0.68, 0.80]
arid = [0.90, 0.72, 0.50]
martian = [0.82, 0.58, 0.40]
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