A Drossel–Schwabl forest-fire model, built as a scientific instrument rather than a game. The board accumulates connectivity; small disturbances happen constantly; large cascades happen rarely. Your job is to keep the world productive without letting the rare one get big.
Press Play and the instrument takes the screen.
observe → predict → intervene → accept controlled damage → prevent catastrophe → recover
The design question it exists to answer: can a player learn to recognise when a self-organising system is approaching dangerous connectivity, and intervene intelligently before a huge cascade?
What is on screen
- The board. 256 × 256 cells. Near-black is nothing, pale is fuel, orange is burning, grey is spent ground recovering, dark blue is terrain that will never grow. The brush ring follows the pointer.
- The readout. Three levels, cycled with H:
- A · Full Debug — density, connectivity, component statistics, cascade statistics, the size distribution, production, damage, energy, intervention tallies, the strategy comparison and the internal pressure.
- B · Player Information — production, energy, density and recent event sizes. Only what a person could plausibly be told.
- C · Minimal — production, energy, score.
- Two charts. Event size against frequency, one bucket per doubling, log–log; and event size over time on a log axis with density and largest-component share drawn underneath. The first shows the shape of the danger; the second shows whether it is approaching.
The point of three readout levels is to find out how much direct information a player actually needs, because the destination is a player who reads the world visually.
Controls
SPACE | pause / resume — N steps one tick |
+ / - | time scale, 0.25× … 64× |
C | connectivity view — shade the board by connected region |
H | cycle the readout level |
1–6 | arm a tool |
| LMB | apply the armed tool · RMB always the firebreak |
| wheel | brush radius |
F / G | new seed / replay this seed |
V / P / T | environmental feedback · regrowth memory · propagation model |
Y | adaptive difficulty on / off |
O | cycle the objective |
E | export the run as CSV + JSON |
B | run the baseline strategies headless, in the background |
, / . | smaller / larger grid (128 … 1024) |
The six tools
Trigger (cheap) causes a cascade on purpose. Firebreak (priced per cell) removes connectivity without lighting anything. Temporary Barrier, Suppression Zone, Growth Boost and Growth Suppression place timed zones that change how the world behaves locally.
Two fundamentally different strategies fall out of that: release the pressure now, on your terms or break the structure and release nothing. Every tool costs energy and every tool has its own cooldown, so a player is never able to control everything.
What it actually does
Measured at the default parameters, 2000 ticks (≈80 s simulated), no intervention:
- The board settles at 41.6% occupancy on average — the density at which this rule set is critically self-organised.
- 1043 cascades: 824 small, 196 medium, 13 large, 10 catastrophic.
- Median event 5 cells, 90th percentile 59, 99th percentile 671, largest 41,189 cells.
- The size distribution falls roughly by half per doubling across five orders of magnitude — many tiny events, fewer moderate, rare large, very rare enormous. Nothing in the code produces that shape; it is emergent.
Five non-human baselines are built in (B), each paying the same energy costs
a player does. On a short run they separate cleanly: doing nothing scores 94.5
efficiency, intervening at random scores 94.5 (it costs production for
nothing), and burning the densest region on a threshold scores 133.2 while
roughly halving the damage. Cutting structure is not the same as releasing it —
the firebreak strategy holds damage down but leaves the single largest event
high. None of them is the right answer; they are the floor a player has to beat.
What is deliberately absent
- No disaster probability on screen. The player should think "this place feels dangerous", not read "74%". The board's frame warms and a slow pulse rises with a hidden internal reading, and nothing is quantified.
- No branch anywhere that spawns a catastrophe.
system_pressureis observational only; catastrophic events remain emergent consequences of the cellular system. The optional difficulty ramp (Y) works the same way — it changes the environment over ten minutes so the system becomes harder to keep below dangerous connectivity, and never spawns a larger disaster. - No game-over on a catastrophic event. It is a setback. The recovery period afterwards is part of the experiment, and one of the five objectives is literally get back to 70%.
Under the hood
| asset | job |
|---|---|
CascadeCore.module | the model — pure Luau over flat arrays, no engine API |
CascadeRng.module | deterministic, seed-reproducible numbers |
CascadeStats.module | every number measured, and CSV/JSON export |
CascadeHud.module | the screen: board, readout, charts |
CascadeObjectives.module | the five challenge scenarios, as data |
CascadeAgents.module | the five non-human baselines |
CascadeSim.component | the instrument: texture, screen, input, driver |
The model is deliberately generic. Nothing in it knows about forests: the states are potential, burning, spent and blocked, and the same machine stands in for infection, grid failure, contagion, insurgency or traffic. The propagation rules are modular — adjacency, probabilistic, distance and directional — behind one interface. The run is seed-reproducible: same seed, same parameters, same actions, same run.
Simulation state is flat arrays and the board is rasterised one u32 per cell —
no entity per cell anywhere. 256 × 256 costs 7.5 ms per tick, 512 × 512 costs
30.9 ms, both linear in cell count; 256² runs continuously at 25 ticks/s for
around 19% of one core.
Full detail, including the cascade merge policy, exactly what
cells_affected counts, and the known limitations, is in
CascadeSim.component/README.md.
Comments · 0
Open discussion, no rating attached. Ask questions, swap notes, follow threads.