planetsim/docs/fauna-flora-plan.md
Jonas Reith acc0e5eec9 Initial commit: fanworgen planet sim
C++/raylib semi-realistic fantasy/sci-fi planet generator on a fixed icosphere
grid (Eulerian: properties flow over fixed cells). World-creation stages:
tectonics, continental drift & erosion, hydrology (rivers/lakes), climate
(temperature + orographic precipitation), and biome classification. Engine in
src/sim (raylib-free, headless-testable), viewer in src/render. See CLAUDE.md
and docs/ (design-notes.md, fauna-flora-plan.md = next step).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:08:25 +02:00

4.9 KiB
Raw Blame History

Next step — Fauna & Flora (derived carrying-capacity densities)

Status: planned, not yet implemented. This is the next World-Creation stage after climate. Approved design captured here so it can be picked up verbatim (e.g. after the project moves to another machine — the auto-memory does not travel, this doc does).

Decision summary

  • Derived carrying-capacity map, not a live simulation: vegetation + wildlife density scalars recomputed each tick from the climate fields + terrain, exactly like biomes/climate. It answers "what could live here", not "what is living/evolving here".
  • The actual time-evolving ecosystem (population growth, migration, predator-prey, extinction, seasons, species) is reserved for the future Live World real-time mode (year/season timescales — not the My geological clock).
  • Fauna uses a herbivore + carnivore food-chain split.
  • Fields are derived / not saved (deterministic functions of climate) → no save-format change. New config knobs ride the v6 self-describing save with no break.

Part A — Biosphere fields (src/sim/, raylib-free)

  • Planet.hpp: declare void computeBiosphere(); + accessors const std::vector<double>& vegetation()/herbivores()/carnivores() const. Add scratch members std::vector<double> sVeg, sHerb, sCarn; (not saved).
  • New src/sim/PlanetBiosphere.cppPlanet::computeBiosphere() (run after computeClimate(); reads sTemp + sMoist):
    • Vegetation (flora) sVeg[i] ∈ [0,1]: 0 on water (elev ≤ seaLevel). On land, an NPP-style Liebig minimum of a temperature factor and a moisture factor:
      • tF = clamp((sTemp[i] bioVegTempMin)/(bioVegTempOpt bioVegTempMin), 0, 1)
      • mF = clamp(sMoist[i]/bioVegMoistRef, 0, 1)
      • sVeg = min(tF, mF) → lush warm-wet, ~0 in ice/desert/alpine (cold- or water-limited), matching the biomes.
    • Herbivores sHerb[i] = clamp(sVeg[i] · bioHerbProductivity, 0, 1) (capacity scales with plant productivity).
    • Carnivores sCarn[i]: present only where prey is abundant, ramping with it: sCarn = sHerb > bioCarnPreyMin ? clamp((sHerb bioCarnPreyMin)/(1 bioCarnPreyMin) · bioCarnScale, 0, 1) : 0 → concentrated in the richest regions (an energy-pyramid feel, visually distinct from the broader herbivore pattern).
  • src/sim/Planet.cpp generate(): call computeBiosphere() after classifyBiomes().

Part B — Config knobs (PlanetTypes.hpp + PlanetIO.cpp)

Add to PlanetConfig + CONFIG_FIELDS + validateConfig:

key default meaning
bioVegTempMin 5 °C below this, no plant growth
bioVegTempOpt 15 °C at/above this, temperature isn't limiting
bioVegMoistRef 0.5 normalized moisture at which water isn't limiting
bioHerbProductivity 0.9 herbivore capacity per unit vegetation
bioCarnPreyMin 0.30 min herbivore density to support carnivores
bioCarnScale 1.0 carnivore density ramp above the prey threshold

Part C — Rendering (src/render/)

  • Colors.{hpp,cpp}: ColorMode += Vegetation, Herbivores, Carnivores; add vegColor (barren tan → lush green), herbColor (pale → amber/orange), carnColor (pale → red/violet); extend colorModeName.
  • Viewer.cpp: recolor() adds the three cases (read the accessors, empty-guarded); refreshView() calls planet.computeBiosphere() after classifyBiomes().
  • ViewerInput.cpp: KEY_EIGHT → Vegetation, KEY_NINE → Herbivores, KEY_ZERO → Carnivores (each recolor()). The top-center view-name label already shows the mode.
  • ViewerRender.cpp renderHUD: controls line gains 8 veg 9 herbiv 0 carniv.
  • Panels.cpp cellInfo(): add a life line — vegetation X% herbivores Y% carnivores Z% (guarded on the arrays being sized).

Verification (headless — extend the src/sim test set with PlanetBiosphere.cpp)

  • Vegetation: 0 on ocean & Ice cells; near-0 on Desert; high (>0.6) on warm-wet Forest; all in [0,1]; finite; deterministic.
  • Fauna food chain: sHerb correlates with sVeg; sCarn[i] > 0 ⇒ sHerb[i] > bioCarnPreyMin and carnivore-positive cells are a strict subset of herbivore-rich cells; all in [0,1]; deterministic.
  • test_logic, biomes+config, climate suites still pass; app builds clean; no save change.
  • GUI: 8 lush green continents thinning to barren in deserts/poles/peaks; 9 grazer density following productivity; 0 predators concentrated in the richest belts; cell info shows vegetation/herbivore/carnivore %.

Out of scope (future / Live World)

Time-evolving populations (growth, migration, predator-prey, extinction), seasons, and species/typed organisms — all part of the future Live World real-time simulation that runs the finished planet at hours/days/weeks/months with dynamic weather + life.