Game of Life: Tribes

#WGSL Shaders

#Simulation Compute Shader

The simulation shader is generated at runtime by generateComputeWgsl. It specializes the shader for the current ruleset, rule probabilities, random seed, tribe order, grid dimensions, grid topology, virtual boundary tribe, packed grid format, and dispatch plan.

For the persisted rule, selector, clause, outcome, and tribe JSON shapes that feed shader generation, see Rule expressions. For runtime evaluation order and normalization before shader generation, see Rule engine internals.

Key properties:

  • It reads from gridIn and writes to gridOut.
  • Workgroup size is 16×1616\times16.
  • Each invocation processes 11 packed word column and 11 row.
  • Inside the invocation, it loops over the cells packed into that word.
  • It reads the 88 Moore-neighborhood cells according to the compiled topology.
  • Toroidal shaders keep the fast wrapping neighbor reads.
  • Bounded shaders return the selected boundary tribe for off-grid neighbor reads.
  • Bounded shaders use a packed-word interior fast path when every valid cell in the word is away from the edge. Edge-containing words fall back to per-cell interior checks and virtual boundary-aware reads.
  • It precomputes unique neighbor count selectors used by non-trivial rule predicates.
  • It reduces count-clause predicates to the smallest equivalent check: equality for exact counts, one-sided comparisons for min and max, two-sided ranges only for partial intervals, and true for always-true ranges such as count 0..8, min 0, and max 8.
  • It evaluates active unmuted rules as a first-match-wins if / else if chain.
  • It wraps probabilistic rules in deterministic hash/threshold checks. Rules with probability 100%100\% skip the hash check and apply directly when their clause matches. Failed probability rolls continue to later rule branches.
  • It starts each cell result as the dead tribe, so no matching rule means dead.
  • It packs each resulting cell back into the output word with the active cell mask and shift.

The shader emits packing constants such as CELLS_PER_WORD, WORD_SHIFT, CELL_SHIFT, CELL_INDEX_MASK, and CELL_MASK. This avoids generic bit math branches at runtime.

When at least 11 active rule has probability between 0%0\% and 100%100\%, the generated shader also emits a RANDOM_SEED constant and a probability hash helper. Fully deterministic rules do not need that extra probability branch. In mixed rule chains, only rules whose probability is >0%>0\% and <100%<100\% call the hash helper; active 100%100\% rules use the direct assignment fast path, and 0%0\% rules are filtered out before code generation.

If the logical dispatch dimensions exceed the device per-dimension limit, plan2DDispatch remaps logical workgroups into a flattened dispatch grid and reconstructs logical coordinates inside WGSL.

#Render Shader

render.wgsl draws a full-screen triangle and maps pixels into grid cells using camera scale, integer offset, and fractional offset. Separating integer and fractional camera offset avoids float precision loss on wide grids.

The fragment shader:

  • Converts UV to local cell coordinates.
  • Wraps coordinates in toroidal mode.
  • Clips off-grid pixels in bounded mode.
  • Reads the packed cell value from the active grid buffer.
  • Looks up the tribe color from a storage buffer packed as 0x00BBGGRR.
  • Draws a light brush-preview outline when enabled.
  • Draws visual export framing markers while a PNG or MP4 download is being prepared.

The render shader is a template. generateRenderWgsl replaces packing placeholders with constants for the active grid format and injects topology-specific coordinate, preview-distance, and export-overlay code. The worker builds the active render pipeline from the shader variant matching the current topology.

#Brush Shader

The brush shader is generated by generateBrushWgsl. It writes directly into the active packed grid buffer.

Key properties:

  • Workgroup size is 8×88\times8.
  • In toroidal mode, a brush stroke is split into non-wrapping rectangles before dispatch so it can wrap across grid edges.
  • In bounded mode, a brush stroke is clipped to the grid edge and does not wrap to the opposite side.
  • The shader handles square, round, diamond, vertical line, and horizontal line shapes.
  • Full considers every cell in the shape.
  • Outline considers only cells on the border of the shape.
  • Density uses a PCG-style hash to decide which considered cells are written.
  • In Full and Outline, cells skipped by density are left unchanged.
  • In Spray, cells skipped by density are written as the dead tribe.
  • Multiple selected tribes are selected by hashing into the tribeIds array for cells selected by density.

The brush uniform carries the active density percentage and reserves 3232 selected tribe IDs.

#Metric Shaders

Live metrics generate separate WGSL compute shaders:

  • Histogram metrics count cells by tribe into 256256 atomic counters.
  • Boundary metrics count right and bottom cross-state edges into an atomic counter. Toroidal metrics wrap those reads, while bounded metrics skip reads beyond the finite grid edge.

Both use 16×1616\times16 workgroups and the same dispatch remapping strategy as simulation when needed. Histogram results feed population and diversity metrics. Boundary results feed interface metrics.

Game of Life: Tribes · Simulation v1.0.0 · Open source