ReadonlychunksRow-major chunk grid: chunks[cy * chunksX + cx].
ReadonlychunkEdge length of each chunk in pixels.
ReadonlychunksXNumber of chunks along the X axis.
ReadonlychunksYNumber of chunks along the Y axis.
ReadonlyheightWorld height in pixels.
ReadonlymaterialsMaterial registry shared with this bitmap.
ReadonlywidthWorld width in pixels.
Sparse set of cell indices (y * width + x) the cellular-
automaton step should visit on its next call.
Lazy-allocated on first access. Once it exists, every
setPixel mutation auto-marks the changed cell and its
8 neighbors. The sim consumes this set at the start of each
step (snapshot + clear), then the same set fills back up
during processing via setPixel calls and explicit
markActive calls for cells with ongoing state (fire
timers, settling sand counters).
Lazy-allocated Uint8Array(width * height) of per-cell counters
used by CellularAutomaton.step for features that need state
across ticks (sand-rest counter, fire-burn timer, etc.).
On first read, the array is zero-initialized. Subsequent reads
return the same instance. setPixel auto-resets the cell's
timer to 0 because the cell's content just changed; the
cellular-automaton step manages increments and threshold checks
on cells that didn't move this tick.
Caps at 255 per cell (Uint8Array max); threshold checks above 255 saturate.
Whether active-cell tracking has been initialized on this bitmap. Used by sim helpers that want to peek without lazy- initializing the set.
Lazy-allocated Uint16Array(width * height) of per-cell
horizontal-flow source-X memory used by the v2.7.6 anti-
oscillation rule in CellularAutomaton.step. 0xFFFF
means "no recent horizontal move."
On first read the array is initialized to all-0xFFFF.
The sim writes to it after every successful horizontal
flow move (flowSource[targetIdx] = sourceX); reading
back at the next call lets the moved cell skip a flow
back to the same source — preventing 2-tick oscillation
cycles that would otherwise force a conservative
same-rank-beyond guard.
setPixel resets the cell's entry to 0xFFFF because the
occupant changed.
Internal fast-path used by CellularAutomaton.stepLiquid.
Returns the underlying mass array (allocating + seeding it
on first use). Callers MUST treat the array read-only for
cells they don't own and MUST call _markCellChanged
after writing so chunk dirty / active-cell tracking stay
consistent.
Bypasses the validation overhead of setMass; safe only inside the well-behaved sim loop. Public users should stick to getMass / setMass.
Internal fast-path: returns the per-cell pool-id sidecar
(Uint16Array(width × height)), allocating it lazily on
first access and filling with the NO_POOL = 0xFFFF
sentinel. Used by the v3.1 pool-detection step in
CellularAutomaton. Public callers don't have a use for
this — it's pool-id tracking, not material id.
Internal fast-path companion to _getMassArrayUnchecked.
Marks the chunk owning (x, y) visually dirty and adds the
cell to the active set if active-cell tracking is on.
Skips the 8-neighbor mark — pass idChanged: true only
when the cell's material id transitions (air ↔ fluid),
which warrants neighbor wake-up. For mass-only changes,
leave it false.
Critically, does NOT set chunk.dirty (the collider-
rebuild flag). Only static-material id changes affect the
static contour, and those always go through setPixel.
Fluid mass changes / fluid id transitions only need a
visual repaint.
Bypasses bounds checks; caller guarantees (x, y) is in
range.
Internal fast-path id writer for the sim. Writes
materialId to the bitmap cell at (x, y) and resets the
cell's per-cell timer + horizontal-flow source memory.
Skips bounds + integer validation, the no-op-on-same-id
check, and the active-set / dirty-chunk bookkeeping —
caller is responsible for following up with
_markCellChanged.
Use only inside the sim hot path. Public callers use setPixel.
Clears the collider dirty flag on a chunk. Called by the physics
adapter after a successful rebuild. Does not touch visualDirty.
Clears the visual dirty flag on a chunk. Called by the renderer after
a successful texture upload. Does not touch dirty.
Idempotent. Initializes the active-cell set and seeds it with
every non-air, non-static cell currently in the bitmap so the
sim can pick up cells that were placed before tracking turned
on. The first CellularAutomaton.step call invokes this; you
can also call it eagerly if you need the auto-mark side-effect
on setPixel before the first step runs.
Visits every currently-dirty chunk in stable row-major (cy, cx) order.
The callback may not mutate the dirty flag during iteration (call
clearDirty afterwards). Iteration order is fixed so consumers
(Box2D rebuild, GPU upload) see a deterministic sequence — useful
for replay debugging and best-effort determinism (architecture doc
§ Determinism).
Reads the mass of the cell at (x, y).
For binary cells (air, static, sand, fire) returns 0 for
air and 1 for any registered material — same as
getPixel(x, y) === 0 ? 0 : 1. For mass-tracked fluid
cells (water, oil, gas under the v3 rules) returns the
actual stored mass, which can be 0..MAX_MASS + MAX_COMPRESS.
Out-of-bounds returns 0 (treats outside-the-world as
air-equivalent), matching getPixel's behavior.
Adds (x, y) to the active-cell set so the next step will
visit it. Used by the cellular automaton to keep cells with
ongoing state (fire timer ticking, sand rest counter
incrementing) in the rotation when setPixel wasn't called.
No-op when active-cell tracking hasn't been initialized
(callers in the sim run after enableActiveCellTracking so
the guard is conservative). Out-of-bounds coordinates are
silently ignored.
Writes the mass for the cell at (x, y). The cell's material
id is updated as a side effect:
mass <= 0, the cell becomes air (id = 0).mass > 0, the cell keeps its current id (or, if the
cell was previously air, takes the id from the optional
idIfAir argument).Lazy-allocates the mass array on first call. Marks the
owning chunk dirty and propagates active-cell activation
(same as setPixel).
Used by CellularAutomaton.step's mass-transfer rules; not
typically called by application code.
Writes a cell.
(x, y) is outside the bitmap. Carve / deposit ops are
responsible for clipping their footprint before calling.materialId is not an integer in 0..255.On any real change, marks the owning chunk's dirty and visualDirty
flags. This is the single mutation primitive that satisfies CLAUDE.md
hard rule #5.
Maps a world coordinate to the enclosing chunk's grid coordinates. Does not validate the input is within the world; callers in the algorithm layer may need to query out-of-bounds positions.
The world bitmap, partitioned into fixed-size square chunks.
ChunkedBitmapis the source of truth for terrain state. Every cell stores a single material id (0= air,1..255= registered material). Mutations dirty the owning chunk; consumers (renderers, physics adapter) walk dirty chunks at end-of-frame to project the bitmap into colliders and textures.The bitmap is dependency-free and framework-agnostic; it can be used outside Phaser (e.g. with PixiJS or in a headless tool chain).