feat(engine-worker): Add new worker protocol messages and scenario definitions with supporting types

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-29 10:07:32 -07:00
parent 7df293ebfb
commit 9506935f24
4 changed files with 181 additions and 3 deletions

View file

@ -13,7 +13,7 @@ export interface BiomeEntry {
tags: readonly BiomeTag[]
}
export type BiomeCategory = 'water' | 'coastal' | 'ice' | 'cold' | 'temperate' | 'tropical' | 'elevation' | 'wetland' | 'special' | 'grassland'
export type BiomeCategory = 'water' | 'coastal' | 'ice' | 'cold' | 'temperate' | 'tropical' | 'elevation' | 'wetland' | 'special' | 'grassland' | 'volcanic' | 'arid'
// ── Canonical biome definitions ──────────────────────────────────────────
// Order matters: index position = encoded terrain value in snapshot textures.
@ -58,6 +58,17 @@ export const BIOME_REGISTRY: readonly BiomeEntry[] = [
// Special
{ id: 'volcanic', name: 'Volcanic', color: [0.65, 0.18, 0.08], category: 'special', tags: ['is_elevated', 'is_volcanic'] },
{ id: 'subterranean', name: 'Subterranean', color: [0.32, 0.24, 0.18], category: 'special', tags: ['is_subterranean'] },
// Volcanic worlds (Venus, flood basalt planets)
{ id: 'lava_field', name: 'Lava Field', color: [0.70, 0.15, 0.05], category: 'volcanic', tags: ['is_volcanic'] },
{ id: 'caldera', name: 'Caldera', color: [0.45, 0.10, 0.08], category: 'volcanic', tags: ['is_elevated', 'is_volcanic'] },
{ id: 'basalt_highland', name: 'Basalt Highland', color: [0.30, 0.25, 0.22], category: 'volcanic', tags: ['is_elevated', 'is_volcanic'] },
{ id: 'volcanic_plains', name: 'Volcanic Plains', color: [0.25, 0.18, 0.14], category: 'volcanic', tags: ['is_volcanic'] },
{ id: 'lowland_basin', name: 'Lowland Basin', color: [0.20, 0.12, 0.10], category: 'volcanic', tags: ['is_volcanic'] },
// Arid worlds (Mars, dry dead planets)
{ id: 'dust_plain', name: 'Dust Plain', color: [0.72, 0.42, 0.28], category: 'arid', tags: ['is_dry'] },
{ id: 'canyon', name: 'Canyon', color: [0.60, 0.28, 0.16], category: 'arid', tags: ['is_dry', 'is_elevated'] },
{ id: 'ancient_lakebed', name: 'Ancient Lakebed', color: [0.55, 0.45, 0.32], category: 'arid', tags: ['is_dry'] },
{ id: 'dune_field', name: 'Dune Field', color: [0.80, 0.55, 0.35], category: 'arid', tags: ['is_dry'] },
] as const
// ── Runtime biome tags (IDs created during simulation, not in registry) ───
@ -119,6 +130,8 @@ export const CARTO_CATEGORY_COLORS: Record<BiomeCategory, [number, number, numbe
wetland: [0.15, 0.35, 0.30],
special: [0.60, 0.20, 0.10],
grassland: [0.58, 0.65, 0.32],
volcanic: [0.55, 0.12, 0.04],
arid: [0.68, 0.38, 0.22],
}
/** Get cartographic color for an encoded biome index */
@ -175,6 +188,8 @@ export const BIOME_CHART_GROUPS: readonly { label: string; abbr: string; ids: st
{ label: 'Elevation', abbr: 'Elv', ids: idsForCategories('elevation'), color: 'rgb(158,153,148)' },
{ label: 'Wetland', abbr: 'Wet', ids: idsForCategories('wetland'), color: 'rgb(61,79,36)' },
{ label: 'Special', abbr: 'Spc', ids: idsForCategories('special'), color: 'rgb(191,51,20)' },
{ label: 'Volcanic', abbr: 'Vol', ids: idsForCategories('volcanic'), color: 'rgb(178,30,10)' },
{ label: 'Arid', abbr: 'Ard', ids: idsForCategories('arid'), color: 'rgb(174,97,56)' },
]
function idsForCategories(...cats: BiomeCategory[]): string[] {
@ -190,6 +205,8 @@ export const BIOME_LEGEND_SECTIONS: readonly { label: string; biomes: readonly B
{ label: 'Temperate', biomes: BIOME_REGISTRY.filter(b => b.category === 'temperate' || b.category === 'grassland') },
{ label: 'Tropical', biomes: BIOME_REGISTRY.filter(b => b.category === 'tropical') },
{ label: 'Elevation', biomes: BIOME_REGISTRY.filter(b => b.category === 'elevation') },
{ label: 'Wetland', biomes: BIOME_REGISTRY.filter(b => b.category === 'wetland') },
{ label: 'Special', biomes: BIOME_REGISTRY.filter(b => b.category === 'special') },
{ label: 'Wetland', biomes: BIOME_REGISTRY.filter(b => b.category === 'wetland') },
{ label: 'Special', biomes: BIOME_REGISTRY.filter(b => b.category === 'special') },
{ label: 'Volcanic Worlds', biomes: BIOME_REGISTRY.filter(b => b.category === 'volcanic') },
{ label: 'Arid Worlds', biomes: BIOME_REGISTRY.filter(b => b.category === 'arid') },
]

View file

@ -349,6 +349,157 @@ const volcanicWinter: ScenarioConfig = {
},
}
// ---------------------------------------------------------------------------
// Venus scenarios
// ---------------------------------------------------------------------------
/**
* Apply Venus baseline tile state: extreme temperature, zero moisture, high aerosol.
*/
function applyVenusBaseline(grid: GridState, tempBase: number, tempJitter: number): void {
applyBiologyTemplate(grid)
for (const tile of grid.tiles) {
tile.temperature = tempBase + (Math.random() * tempJitter - tempJitter / 2)
tile.moisture = 0.0
tile.surface_water = 0.0
tile.sulfate_aerosol = 0.45
tile.humidity = 0.0
tile.relative_humidity = 0.0
tile.dew_point = 0.0
tile.cape = 0.0
}
grid.total_ocean_water = 0.0
grid.o2_fraction = 0.0
grid.co2_ppm = 965000
}
const venusModern: ScenarioConfig = {
id: 'venus_modern',
planet: 'venus',
worldAge: DEFAULT_WORLD_AGE,
name: 'Venus Today',
description:
'Modern Venus: 460°C surface, 92 atm CO2 atmosphere, no water cycle, active volcanism. ' +
'Sulfuric acid clouds persist at 4570 km altitude. The planet is a cautionary tale of runaway greenhouse.',
startingAtmosphere: 'primordial',
abioticWorld: true,
initMap: (grid) => {
applyVenusBaseline(grid, 0.95, 0.04)
// Volcanic highlands are slightly cooler (higher elevation = less atmospheric pressure)
for (const tile of grid.tiles) {
if (tile.elevation > 0.65) {
tile.temperature = Math.max(0.88, tile.temperature - tile.elevation * 0.06)
}
}
},
}
const venusPrimordial: ScenarioConfig = {
id: 'venus_primordial',
planet: 'venus',
worldAge: 0,
name: 'Ancient Venus',
description:
'Venus 23 billion years ago, when solar output was lower and liquid water may have existed on the surface. ' +
'Watch the runaway greenhouse take hold as the simulation advances.',
startingAtmosphere: 'primordial',
abioticWorld: true,
initMap: (grid) => {
applyBiologyTemplate(grid)
for (const tile of grid.tiles) {
// Much cooler ancient Venus — near habitable but already warming
tile.temperature = 0.55 + (Math.random() * 0.10 - 0.05)
tile.moisture = 0.02 // trace water before boiloff
tile.surface_water = 0.0
tile.sulfate_aerosol = 0.05
tile.humidity = 0.0
tile.relative_humidity = 0.0
tile.dew_point = 0.0
tile.cape = 0.0
}
grid.total_ocean_water = 0.0
grid.co2_ppm = 50000
},
}
// ---------------------------------------------------------------------------
// Mars scenarios
// ---------------------------------------------------------------------------
/**
* Apply Mars baseline tile state: cold, dry, minimal aerosol.
*/
function applyMarsBaseline(grid: GridState, tempBase: number, tempJitter: number): void {
applyBiologyTemplate(grid)
for (const tile of grid.tiles) {
tile.temperature = tempBase + (Math.random() * tempJitter - tempJitter / 2)
tile.moisture = 0.0
tile.surface_water = 0.0
tile.sulfate_aerosol = 0.008
tile.humidity = 0.0
tile.relative_humidity = 0.0
tile.dew_point = 0.0
tile.cape = 0.0
}
grid.total_ocean_water = 0.0
grid.o2_fraction = 0.0
grid.co2_ppm = 953000
}
const marsModern: ScenarioConfig = {
id: 'mars_modern',
planet: 'mars',
worldAge: DEFAULT_WORLD_AGE,
name: 'Mars Today',
description:
'Modern Mars: -60°C average, 6 mbar CO2 atmosphere, no water cycle, global dust storms. ' +
'Seasonal CO2 sublimation drives polar cap dynamics. Dust aerosols reshape the regolith plains.',
startingAtmosphere: 'primordial',
abioticWorld: true,
initMap: (grid) => {
applyMarsBaseline(grid, 0.10, 0.06)
// Polar caps: freeze tiles at high/low latitudes
for (const tile of grid.tiles) {
if (tile.row < 3 || tile.row >= grid.height - 3) {
tile.temperature = Math.max(0.01, tile.temperature * 0.5)
}
// Tharsis / Olympus Mons: elevated region runs warmer by day
if (tile.elevation > 0.70) {
tile.temperature = Math.max(0.04, tile.temperature - 0.03)
}
}
},
}
const marsAncient: ScenarioConfig = {
id: 'mars_ancient',
planet: 'mars',
worldAge: 0,
name: 'Ancient Mars',
description:
'Noachian-era Mars 3.8 billion years ago: warmer, wetter, with a thicker atmosphere and liquid water flowing through river valleys into shallow seas. ' +
'Watch the water cycle collapse as the magnetic field fails and the atmosphere is stripped.',
startingAtmosphere: 'primordial',
abioticWorld: true,
initMap: (grid) => {
applyBiologyTemplate(grid)
for (const tile of grid.tiles) {
// Warmer ancient Mars — liquid water was possible
tile.temperature = 0.28 + (Math.random() * 0.10 - 0.05)
// Low-lying areas have trace moisture (ancient river/sea basins)
tile.moisture = tile.elevation < 0.30 ? 0.15 : 0.02
tile.surface_water = 0.0
tile.sulfate_aerosol = 0.004
tile.humidity = 0.0
tile.relative_humidity = 0.0
tile.dew_point = 0.0
tile.cape = 0.0
}
grid.total_ocean_water = 0.0
grid.co2_ppm = 200000
},
}
// ---------------------------------------------------------------------------
// Export — classic first, then advanced scenarios
// ---------------------------------------------------------------------------
@ -368,4 +519,8 @@ export const SCENARIOS: ScenarioConfig[] = [
trophicCascade,
methaneRunaway,
supervolcano,
venusModern,
venusPrimordial,
marsModern,
marsAncient,
]

View file

@ -266,6 +266,8 @@ export interface ScenarioConfig {
startingAtmosphere?: 'modern' | 'depleted' | 'lush' | 'primordial'
/** Skip ecology engine entirely — used for pre-biotic worlds where life cannot spontaneously arise. */
abioticWorld?: boolean
/** Which planet this scenario belongs to. Defaults to 'earth' if omitted. */
planet?: string
}
/** Opaque handle for continuing a simulation beyond its initial run. */

View file

@ -20,6 +20,10 @@ export interface InitCommand {
spec?: Record<string, unknown>
/** Easter egg seed table from game data (seed_easter_eggs.json). Keys are seed integers as strings. */
easterEggs?: Record<string, EasterEggSeed>
/** Per-planet climate params keyed by planet id. If present, overrides `params` for non-earth scenarios. */
allPlanetParams?: Record<string, Record<string, number>>
/** Per-planet climate spec keyed by planet id. */
allPlanetSpecs?: Record<string, Record<string, unknown>>
}
export interface RunCommand {