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

83 lines
4.9 KiB
Markdown
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.

# 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.cpp`** — `Planet::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.