cellSize
number
Pixel size of each square soil grid cell, controlling grid resolution.
const cellSize = 10;
soilHeight
number
Height in pixels of the soil band at the bottom of the canvas.
const soilHeight = 150;
rows
number
Number of rows in the soil grid, computed from soilHeight and cellSize.
let rows;
cols
number
Number of columns in the soil grid, computed from canvas width and cellSize.
let cols;
soilGrid
array
2D array storing each cell's nutrient level (0-100), the core simulation state.
let soilGrid;
noiseOffset
number
Slowly incrementing z-coordinate for Perlin noise so the soil texture drifts over time.
let noiseOffset = 0;
noiseScale
number
Controls how zoomed-in the Perlin noise pattern is across the grid (chunkiness).
const noiseScale = 0.05;
noiseDriftRate
number
How fast noiseOffset advances each frame - governs the 'breathing' speed of the soil.
const noiseDriftRate = 0.0005;
noiseNutrientInfluence
number
Maximum nutrient swing caused by noise each frame.
const noiseNutrientInfluence = 2;
nutrientWells
array
List of nutrient well objects (x position and radius) that regenerate nearby soil.
let nutrientWells = [];
minWells
number
Minimum number of nutrient wells created at startup.
const minWells = 5;
maxWells
number
Maximum number of nutrient wells created at startup.
const maxWells = 8;
wellRadius
number
Radius in pixels of each nutrient well's influence.
const wellRadius = 70;
wellRegenRate
number
Amount of nutrient added per frame to cells near a well's center.
const wellRegenRate = 0.15;
diffusionRate
number
Fraction of each cell's nutrient value blended with its neighbors' average every frame.
const diffusionRate = 0.03;
seeds
array
All active Seed objects currently falling, dormant, or about to germinate.
let seeds = [];
seedSpawnTimer
number
Countdown of frames until the next single seed spawns.
let seedSpawnTimer = 0;
seedSpawnIntervalMin
number
Minimum frames between individual seed spawns.
const seedSpawnIntervalMin = 60;
seedSpawnIntervalMax
number
Maximum frames between individual seed spawns.
const seedSpawnIntervalMax = 120;
seedSize
number
Pixel size used to draw each seed shape.
const seedSize = 8;
seedGravity
number
Downward acceleration applied to falling seeds each frame.
const seedGravity = 0.1;
seedWindForce
number
Maximum random horizontal push applied to seeds each frame, simulating wind.
const seedWindForce = 0.05;
germinationNutrientThreshold
number
Minimum soil nutrient value required for a seed to germinate into a plant.
const germinationNutrientThreshold = 40;
nutrientConsumptionOnGermination
number
Nutrients subtracted from the soil the instant a seed germinates.
const nutrientConsumptionOnGermination = 30;
dormantRecheckInterval
number
Frames between a dormant seed rechecking whether soil nutrients are now high enough to germinate.
const dormantRecheckInterval = 60;
nutrientParticles
array
All active NutrientParticle objects falling or dissolving back into the soil.
let nutrientParticles = [];
particleSizeMin
number
Smallest possible size for a nutrient particle.
const particleSizeMin = 2;
particleSizeMax
number
Largest possible size for a nutrient particle.
const particleSizeMax = 4;
particleGravity
number
Downward acceleration applied to falling nutrient particles.
const particleGravity = 0.05;
particleLifeSpan
number
Frames a particle lingers, fading out, after it dissolves into the soil.
const particleLifeSpan = 120;
fungus
array
All active Fungus blob objects growing and spreading across decaying plant sites.
let fungus = [];
fungusSpawnChance
number
Probability that fungus appears when a plant finishes decaying.
const fungusSpawnChance = 0.3;
fungusInitialSize
number
Starting diameter of a newly spawned fungus blob.
const fungusInitialSize = 8;
fungusGrowthRate
number
How much a fungus blob's size increases every frame.
const fungusGrowthRate = 0.02;
fungusSpreadInterval
number
Frames between a fungus blob's attempts to spread to a neighboring soil cell.
const fungusSpreadInterval = 120;
fungusLifeSpan
number
Total frames a fungus blob exists before disappearing.
const fungusLifeSpan = 600;
fungusRapidDecayRate
number
How much extra decay a nearby fungus blob applies to a dead plant per frame.
const fungusRapidDecayRate = 0.1;
seedRainActive
boolean
Whether a temporary burst of extra seeds is currently falling.
let seedRainActive = false;
seedRainTimer
number
Countdown of remaining seeds to drop during an active seed rain event.
let seedRainTimer = 0;
seedRainCount
number
Total number of seeds dropped during one seed rain event.
const seedRainCount = 20;
seedRainInterval
number
Frames between the start of successive seed rain events.
const seedRainInterval = 1000;
droughtActive
boolean
Whether a drought event is currently reducing nutrient regeneration and depleting soil.
let droughtActive = false;
droughtTimer
number
Countdown of remaining frames in the current drought event.
let droughtTimer = 0;
droughtDuration
number
Total length in frames of a drought event.
const droughtDuration = 300;
bloomActive
boolean
Whether a bloom event is currently making living plants flower.
let bloomActive = false;
bloomTimer
number
Countdown of remaining frames in the current bloom event.
let bloomTimer = 0;
bloomDuration
number
Total length in frames of a bloom event.
const bloomDuration = 180;
bloomInterval
number
Frames between the start of successive bloom events.
const bloomInterval = 2000;
plants
array
All active Plant objects, alive or still decaying.
let plants = [];
plantIDMap
object
A Map from plant ID to Plant object, used to quickly look up parents/offspring for genealogy lines.
let plantIDMap = new Map();
totalPlantsAlive
number
Current count of living plants, recorded each frame for the timeline chart.
let totalPlantsAlive = 0;
totalPlantsDead
number
Cumulative count of plants that have fully decayed, used in the timeline chart.
let totalPlantsDead = 0;
plantGrowthInterval
number
Base number of frames between a plant's L-system growth steps.
const plantGrowthInterval = 30;
plantMaxIterations
number
Maximum number of L-system rewriting generations a plant can reach.
const plantMaxIterations = 4;
plantBaseLength
number
Initial branch segment length before length-decay is applied.
const plantBaseLength = 10;
plantLengthDecay
number
Multiplier applied to branch length at each growth iteration, shrinking twigs over generations.
const plantLengthDecay = 0.7;
plantBranchThickness
number
Stroke weight used to draw plant branch lines.
const plantBranchThickness = 1.5;
plantNutrientConsumptionBase
number
Base nutrient amount a plant consumes from its soil cell each frame.
const plantNutrientConsumptionBase = 0.05;
plantNutrientConsumptionMultiplier
number
Extra nutrient consumption added per L-system growth iteration a plant has reached.
const plantNutrientConsumptionMultiplier = 0.5;
plantDecayTime
number
Total frames it takes a dead plant to fully decay and disappear.
const plantDecayTime = 200;
plantCompostBonus
number
Multiplier applied to nutrients returned to the soil when a plant decays.
const plantCompostBonus = 1.5;
lightNoiseOffset
number
Drifting offset used to animate the shimmering light band overlay.
let lightNoiseOffset = 0;
lightNoiseScale
number
Controls how wide/frequent the drifting light bands appear.
const lightNoiseScale = 0.005;
lightDriftRate
number
How fast the light band pattern drifts across the soil each frame.
const lightDriftRate = 0.0001;
lightBrightnessMin
number
Minimum brightness/alpha for the light overlay strips.
const lightBrightnessMin = 0;
lightBrightnessMax
number
Maximum brightness/alpha for the light overlay strips.
const lightBrightnessMax = 10;
shadowThreshold
number
Light exposure level below which a plant's growth slows down.
const shadowThreshold = 0.6;
shadowDeathThreshold
number
Light exposure level below which a plant stops growing and starts a death countdown.
const shadowDeathThreshold = 0.3;
shadowDeathTimerMax
number
Frames a plant can survive in deep shade before dying.
const shadowDeathTimerMax = 180;
aliveHistory
array
Rolling record of totalPlantsAlive per frame, used to draw the timeline's green curve.
let aliveHistory = [];
deadHistory
array
Rolling record of totalPlantsDead per frame, used to draw the timeline's gray curve.
let deadHistory = [];
fertilityHistory
array
Rolling record of average soil fertility per frame, used to draw the timeline's amber curve.
let fertilityHistory = [];
historyLength
number
Maximum number of frames kept in each history array before old entries are shifted out.
const historyLength = 200;
timelineHeight
number
Pixel height of the timeline chart bar at the bottom of the screen.
const timelineHeight = 60;
showGenealogyWeb
boolean
Whether to draw connecting lines between parent and offspring plants, toggled by the G key.
let showGenealogyWeb = false;
fastForward
boolean
Whether the simulation should run multiple update steps per rendered frame, toggled by the F key.
let fastForward = false;
stars
array
Precomputed star objects (position, size, twinkle timing) for the night sky.
let stars = [];
numStars
number
How many stars are generated for the starfield.
const numStars = 200;
depletedHue
number
HSB hue used for nutrient-poor soil (brownish).
const depletedHue = 30;
richHue
number
HSB hue used for nutrient-rich soil (amber/reddish).
const richHue = 15;
plantColorMap
object
Lookup table mapping each seed shape to its starting hue/saturation/brightness color.
const plantColorMap = { triangle: { hue: 20, sat: 80, bright: 60 } };