CascadeCore — the simulation itself.
Deliberately generic: nothing in here knows about forests or fire. Cells
carry a potential, disturbances propagate through connectivity, and the
world self-organises toward a state where large cascades are inevitable.
The same engine models infection, grid failure, insurgency, contagion.
This module owns NO engine API. It is pure Luau over flat arrays, so it
can be stepped headless (baseline agents, batch experiments) at the same
speed it steps on screen.
clamp(v: number, lo: number, hi: number) → number
| arg | type | description |
|---|
| v | number | |
| lo | number | |
| hi | number | |
mergeParams(over: any) → any
| arg | type | description |
|---|
| over | any | |
idx(sim: any, x: number, y: number) → number
--!desc The flat index of grid coordinate (x, y). The array is padded by
--! one BLOCKED ring, so neighbours are a plain index offset and no
--! propagation step ever needs a bounds check.
| arg | type | description |
|---|
| sim | any | |
| x | number | |
| y | number | |
classify(sim: any, size: number) → string
--!desc Classify a completed cascade by its size.
| arg | type | description |
|---|
| sim | any | |
| size | number | |
new(opts: any) → any
--!desc Build a fresh simulation.
--!arg opts { width, height, seed, params }
--!return The simulation state table.
| arg | type | description |
|---|
| opts | any | |
rebuildNeighbors(sim: any) → void
--!desc Rebuild the offset tables from the current neighbour mode and
--! propagation model.
buildSet(radius: number, chebyshev: boolean) → any
| arg | type | description |
|---|
| radius | number | |
| chebyshev | boolean | |
reset(sim: any, seed: number?) → void
--!desc Clear the board, seed the world, and reset every tally. The run
--! clock, energy and statistics all start over.
| arg | type | description |
|---|
| sim | any | |
| seed | number? | |
recount(sim: any) → void
--!desc Recount every cell state. Cheap enough to run after a reset or a
--! bulk edit, and the safety net against incremental drift.
generateTerrain(sim: any) → void
--!desc Lay down BLOCKED terrain (Phase 16). Rivers, walls, ridges and a
--! couple of roads, all from the barrier parameters and seed.
fbm(x: number, y: number, seed: number, octaves: number) → number
--!desc Fractal value noise in [0, 1]. The one procedural primitive every
--! field in this module is built from.
| arg | type | description |
|---|
| x | number | |
| y | number | |
| seed | number | |
| octaves | number | |
vnoise(x: number, y: number, seed: number) → number
--!desc Smoothed value noise in [0, 1].
| arg | type | description |
|---|
| x | number | |
| y | number | |
| seed | number | |
buildGrowthField(sim: any) → void
--!desc Build the spatially varying growth field (Phase 15).
rebuildFields(sim: any) → void
--!desc Recompose growth / spread modifier fields from the live zone list
--! (Phase 19). Run on any zone change, not per tick.
placeZone(sim: any, kind: string, cx: number, cy: number, radius: number, ticks: number, strength: number) → any
--!desc Place a timed intervention zone (Phase 19). Returns the zone, or
--! nil when the brush landed outside the board.
| arg | type | description |
|---|
| sim | any | |
| kind | string | |
| cx | number | |
| cy | number | |
| radius | number | |
| ticks | number | |
| strength | number | |
expireZones(sim: any) → void
newCascade(sim: any, source: string) → any
Merge policy: when two live cascades meet, the LOWEST cascade id
survives and absorbs the other; the absorbed record is retired without
being counted as an event of its own, so its cells are counted exactly
once — inside the surviving cascade. A merged cascade inherits PLAYER
as its trigger source if either participant was player-started.
| arg | type | description |
|---|
| sim | any | |
| source | string | |
resolveId(sim: any, id: number) → number
| arg | type | description |
|---|
| sim | any | |
| id | number | |
pushBurning(sim: any, i: number) → void
| arg | type | description |
|---|
| sim | any | |
| i | number | |
removeBurning(sim: any, i: number) → void
| arg | type | description |
|---|
| sim | any | |
| i | number | |
finalizeCascade(sim: any, rec: any) → void
| arg | type | description |
|---|
| sim | any | |
| rec | any | |
igniteInto(sim: any, i: number, rec: any) → void
| arg | type | description |
|---|
| sim | any | |
| i | number | |
| rec | any | |
mergeCascades(sim: any, keepId: number, dropId: number) → void
| arg | type | description |
|---|
| sim | any | |
| keepId | number | |
| dropId | number | |
setAdaptive(sim: any, enabled: boolean, rampSeconds: number?) → void
--!desc Turn the difficulty ramp on or off. Enabling snapshots the five
--! parameters it drives; disabling restores them exactly.
--!arg rampSeconds How long the ramp takes to reach its full strength.
| arg | type | description |
|---|
| sim | any | |
| enabled | boolean | |
| rampSeconds | number? | |
updateDifficulty(sim: any) → void
--!desc Apply the ramp. Called per tick; the change per call is tiny by
--! design, so the world never jumps.
step(sim: any) → void
--!desc Advance the world by one simulation tick.
afterTick(sim: any, dtSeconds: number) → void
--!desc Per-tick housekeeping the driver schedules at its own cadence:
--! production accrual, connectivity, pressure, history sampling.
--!arg dtSeconds Wall-clock seconds since the last call.
| arg | type | description |
|---|
| sim | any | |
| dtSeconds | number | |
computeConnectivity(sim: any) → void
--!desc Label every connected region of OCCUPIED cells and record the
--! largest, the second largest and the component count.
triggerBrush(sim: any, cx: number, cy: number, radius: number, source: string?) → number
--!desc Ignite every OCCUPIED cell inside a circular brush. The burn
--! propagates by exactly the same rules as a spontaneous one — only the
--! trigger source differs.
--!return Number of cells ignited.
| arg | type | description |
|---|
| sim | any | |
| cx | number | |
| cy | number | |
| radius | number | |
| source | string? | |
removeBrush(sim: any, cx: number, cy: number, radius: number) → number
--!desc Remove cells inside a circular brush, cutting connectivity without
--! lighting anything. OCCUPIED and COOLDOWN cells become EMPTY; live
--! burners inside the brush are extinguished.
--!return Number of cells removed.
| arg | type | description |
|---|
| sim | any | |
| cx | number | |
| cy | number | |
| radius | number | |
retainedCascades(sim: any) → any
--!desc Every completed cascade still retained, oldest first. The ring is
--! walked in time order so callers never see it wrap.
sizeStats(sim: any) → any
--!desc Size percentiles over the retained cascade window.
--!return { n, mean, median, p90, p95, p99, max, min }
pick(q: number) → number
| arg | type | description |
|---|
| q | number | |
sizeHistogram(sim: any) → any
--!desc Log-binned histogram of cascade size (Phase 11). One bucket per
--! doubling, which is the only binning that shows a heavy tail honestly.
--!return { bins = { { lo, hi, count } }, total, maxSize }
runHeadless(sim: any, ticks: number, policy: any, decideEvery: number?) → any
--!desc Run `ticks` simulation ticks with no rendering and no player, so a
--! strategy can be measured far faster than it can be watched.
--!arg policy Optional { decide(sim, tick) -> action } hook, called every
--! `decideEvery` ticks.
--!return A summary table of the run.
| arg | type | description |
|---|
| sim | any | |
| ticks | number | |
| policy | any | |
| decideEvery | number? | |
summary(sim: any) → any
--!desc The run's headline numbers, for the dashboard and the agents.
efficiencyScore(sim: any) → number
--!desc The single headline score, kept strictly beside every raw number
--! it is derived from (Phase 7): nothing is hidden behind it.
pack(r: number, g: number, b: number, a: number) → number
One u32 write per cell into a shared RGBA buffer, which the driver hands
to the GPU texture. The colour for each state is packed once; a plain
frame is then a table read and a store per cell.
| arg | type | description |
|---|
| r | number | |
| g | number | |
| b | number | |
| a | number | |
renderInto(sim: any, buf: any, opts: any) → any
--!desc Rasterise the board into an RGBA byte buffer.
--!arg opts { connectivity, minCompSize, cursor = { x, y, r, kind }, flash }
| arg | type | description |
|---|
| sim | any | |
| buf | any | |
| opts | any | |