The Living World
A forest that grows itself.
Plants in FloraForge are not placed and frozen. Every one is born, ages through four stages, and — once mature — casts seedlings of its own before it dies. A single world clock drives the whole simulation: growth, death and despawn are all computed from a plant's age, and one reproduction round runs each sim-day. Populations climb toward a full state, then keep turning over: old trees fall, gaps open, seedlings race in.
Life cycle
Four ages of a plant
Every plant carries a GrowthStage — Seedling,
Young, Mature, or Dead — and
nothing more about its age. The stage sets how it draws: a seedling renders at
0.15× its species' full size, a young plant at 0.50×, a mature plant at full
scale, and a dead one becomes a leafless grey-brown snag at 0.85× — crooked,
slightly leaning, easing smaller as it rots. The same oak recipe expands into
a sapling, a spreading giant, or a weathered skeleton depending only on which
stage it has reached.
The default schedule: seedling for 48 sim-hours, young for a further 96, and
mature at 144 sim-hours — roughly six sim-days from sprout to full size. A tree
then stands mature for its lifespan_hours (720 by default, jittered
±25% per plant so a generation never dies in one wave), spends
snag_hours (120) as a standing snag, and despawns. Each species
carries its own timings — shrubs live 360 hours and rot in 48, while the
base-only cattail is immortal (it cannot respawn through the spread pass, so
death would empty every reed bed for good).
The engine
The clock that drives it
The whole life cycle is analytic. A plant never accumulates a
timer — it stores only the sim-hour it was born, born_hour, and its
stage is a pure function of its age. Subtract birth from the world's
total_hours and compare against the species' thresholds; that one
calculation yields seedling, young, mature, dead, or gone with no per-tick
bookkeeping. The death and despawn thresholds are jittered per plant from a hash of
its identity, and base-world plants draw a uniform fraction of a full lifespan —
so the starting forest dies as a steady trickle, never a synchronized wave.
Growth tick 1 sim-hour
Cheap, off the hot path
- Skip the settled.Each chunk records the next sim-hour any of its plants crosses a threshold; a chunk whose hour hasn't come is skipped entirely.
- Recompute stages.For the rest, the stage — including death — is re-derived from age; no state to advance, just comparisons.
- Reap the gone.Plants past their despawn hour are removed, freeing their ground and waking the surrounding chunks for spread.
- Refresh on change.If anything changed, loaded chunks are told to re-draw at the new scale.
Spread pass 24 sim-hours
One reproduction round per sim-day
- Emit.Every mature plant may cast a seedling candidate near itself.
- Validate.Each candidate is point-tested against terrain, the species' rules, spacing, and house clearance.
- Append.Survivors are born at the current hour and start their own life cycle.
total_hours
and each plant's born_hour to reconstruct the whole living — and dying
— world.
Reproduction
The daily spread pass
Once a sim-day, mature plants reproduce. The pass is deliberately two-phase so it can run in parallel without two seedlings ever racing for the same patch of ground. Phase one only reads; phase two only writes, one chunk at a time.
Phase 1 (read-only, parallel): each mature plant rolls its spread_chance
(default 0.3) and, if it passes, throws one or two candidate seedlings within its
spread_radius (default 25 m — close by, but far enough to cross a
chunk border, so a seedling lands in the parent's own chunk or a direct
neighbour). Phase 2 validates every candidate against the target chunk's height,
moisture, slope, rivers and sea level, the species' placement rules, spacing
against existing plants, and a keep-clear ring around houses (10 m for trees,
5 m for shrubs) — then appends the survivors.
day_speed makes one frame span several sim-days, the runtime
replays the missed reproduction rounds (up to eight per frame) instead of
collapsing them into one. Births stay proportional to sim time, not frame
rate — without this, the analytic death rate would outrun a frame-throttled
birth rate, and every mortal species would slowly thin toward extinction.
Self-limiting
Why the forest stops growing
A simulation that touched every plant every sim-day would get more expensive as the world filled up — exactly backwards. FloraForge inverts that with saturation tracking: a chunk whose last spread pass added nothing, and which holds no immature plants, is flagged saturated. There is no open ground left and nothing still growing into a spreader, so it has nothing to contribute.
Because a plant can only spread into its own chunk or one of its eight neighbours, the pass skips a chunk only when it and all eight neighbours are saturated — a packed chunk still feeds a half-empty one across the border. Once a whole region fills in, that entire neighbourhood is skipped, so the simulation's cost falls as the world matures. A maturing seedling next door instantly clears the flag and reopens the chunk for reproduction.
Death is what keeps a saturated forest from freezing forever. A standing snag still holds its ground — seedlings can't sprout inside a dead trunk — but the moment it despawns, its chunk and the eight neighbours are un-saturated and the next spread pass competes for the gap. The forest settles into a dynamic equilibrium: a steady trickle of deaths opening ground, and a daily race of seedlings closing it again.
spread_radius 0 and spread_chance 0 — it never joins the
spread pass. Instead it is seated once, at world creation, in the wet river and lake
margins that land plants avoid: its aquatic flag inverts the usual wetness guard, so
it grows exactly where everything else is rejected.
Persistence
Saving only what changed
The base world — every plant placed at creation — is fully regenerable from the world seed, so it never needs to be written to disk. A running game only changes that world by spreading new seedlings on top of it.
total_hours. Reload regenerates the base from the seed, replays the saved
seedlings, and the analytic growth model resolves every plant's stage from its
born_hour — the whole living world reconstructed from a compact diff.
From growth to evolution.
Growth and spread are the foundation. The next step turns a species' fixed recipe into heritable traits — letting populations adapt to the terrain they grow on. See where the simulation is headed, or return to the field guide.
Evolution Roadmap Back to the Field Guide