// world/biomes.js (Lane A) — the biome registry. Palette/fog values are transcribed from // ART_BIBLE.md §Biome palettes; gameplay defaults (flow, coatDrain) are sane seeds that // Lane C overrides per-segment in level JSON (`segments[].flow`). C owns the tuning, this // owns the look. // // Canonical ids — level JSON `segments[].biome` must be one of these: // oral · esophagus · stomach · small_intestine · large_intestine · appendix // Unknown id => NEUTRAL fallback + one console warning, never a crash. // // `wave.amp` is displacement in units, inward, at the crest — and it is a GAMEPLAY number, not // just a look: world.wallRho() subtracts (amp + breathe) as its conservative margin, so raising // it narrows Lane B's flight envelope. Esophagus 1.4 was measured in the harness, not guessed: // the stub's 0.9 renders as a barely-legible ripple, and GDD §2 makes riding a crest for boost // the level's signature mechanic — B cannot surf a crest the player can't see. 1.4 reads as // distinct rings and still leaves ~78% of a radius-10 tube flyable. The other biomes are scaled // in proportion and are UNVERIFIED until each one is actually built and eyeballed. export const BIOMES = { oral: { id: 'oral', palette: { tint: 0xa8c4d8, rim: 0xdff2ff, void: 0x06090e }, fog: 0.016, // clinical, bright, tutorial-readable => you can see across the cavity flow: 5, coatDrain: 0.15, wave: { amp: 0.5, breathe: 0.10 }, // saliva tides, not real peristalsis }, esophagus: { id: 'esophagus', palette: { tint: 0x1e6e64, rim: 0x5affd2, void: 0x02100d }, fog: 0.028, flow: 14, coatDrain: 0.5, wave: { amp: 1.4, breathe: 0.15 }, // the signature: ribbed rings rushing past (measured) }, stomach: { id: 'stomach', palette: { tint: 0xb0571e, rim: 0xffb13a, void: 0x120801 }, fog: 0.020, flow: 4, coatDrain: 2.2, // the acid sea: brutal in open acid (GDD §Player systems) wave: { amp: 0.7, breathe: 0.25 }, // churn, not transit }, small_intestine: { id: 'small_intestine', palette: { tint: 0x7a2a6e, rim: 0xff6ad5, void: 0x0d0312 }, fog: 0.050, // dense: villi forest occludes sightlines flow: 9, coatDrain: 0.8, wave: { amp: 1.5, breathe: 0.18 }, }, large_intestine: { id: 'large_intestine', palette: { tint: 0x3a4a26, rim: 0x9dff4a, void: 0x050702 }, fog: 0.075, // darkness is the mechanic here; scanner light is the safety bubble flow: 5, coatDrain: 0.6, wave: { amp: 1.2, breathe: 0.2 }, }, appendix: { id: 'appendix', palette: { tint: 0x8a7020, rim: 0xffe066, void: 0x0a0800 }, fog: 0.030, flow: 2, coatDrain: 0.3, wave: { amp: 0.5, breathe: 0.12 }, }, }; const NEUTRAL = { id: 'neutral', palette: { tint: 0x557066, rim: 0x9fd8c8, void: 0x050a08 }, fog: 0.03, flow: 10, coatDrain: 0.4, wave: { amp: 0.9, breathe: 0.15 }, }; const warned = new Set(); export function biome(id) { const b = BIOMES[id]; if (b) return b; if (!warned.has(id)) { warned.add(id); console.warn(`[world] unknown biome "${id}" — falling back to neutral. Valid: ${Object.keys(BIOMES).join(', ')}`); } return NEUTRAL; }