#Rules Engine Internals
#Rule Semantics
Each generation evaluates every real grid cell independently against the current grid. Edge behavior depends on the selected topology:
Toroidal: neighbor reads wrap across opposite edges.Bounded: neighbor positions outside the grid resolve to the selected virtual boundary tribe.
Bounded boundary cells are virtual. They are not stored in the frame and are not evaluated as cells; they only affect off-grid neighbor reads.
Rules are evaluated in order:
- Muted rules or rules with probability are skipped.
- A rule whose clause matches performs its probability roll.
- The first matching rule whose probability roll passes assigns the next state.
- If no rule matches, or if matching probabilistic rules all fail their rolls, the cell becomes
dead.
A rule has behavioral parts:
- Clause: boolean expression over the current cell and its neighbors.
- Probability: percentage chance that a matched rule applies.
- Outcome: expression that computes the next tribe id.
For the full selector, clause, outcome, tribe, and rule JSON reference, see Rule expressions. This page focuses on evaluation behavior and shader generation.
Probability uses deterministic randomness. The roll is derived from the cell coordinates, generation, rule index, and ruleset random seed, so the same snapshot, rules, seed, and generation reproduce the same outcomes. Rules with probability do not roll; once their clause matches, they apply through the same direct path as a deterministic rule. Failed probability rolls fall through to later rules instead of ending the first-match chain.
Top-level rules use bounded -branch chains, to prevent reaching shader chaining length limit. An applied flag is checked only between chunks, so when a matching branch sets it, later chunks are skipped. For probabilistic rules, the probability roll is part of the branch condition, so a failed roll continues to later rules.
#Expression Handling
Selectors, clauses, and outcomes are normalized before comparison, persistence, and shader generation. The normalized form keeps equivalent editor states stable and gives shader generation predictable inputs.
- Explicit tribe selector signatures sort and deduplicate selected tribe IDs for stable lookup keys.
- Count-style clauses operate on the Moore neighbors, and count values are clamped to through .
- Count-style clause bounds compile to the smallest equivalent boolean expression:
noneandexactlyuse equality,minuses only a lower-bound check,maxuses only an upper-bound check, partialcountintervals use a two-sided range, and always-true ranges such ascount 0..8,min 0, andmax 8compile totrue. - Empty clauses are editor placeholders. They compile as false, and the editor rejects applied rules that still contain empty placeholders.
#Dynamic Outcomes
Ranked outcomes evaluate eligible neighbor tribes selected by the outcome selector:
majoritychooses the most common eligible neighbor tribe.minoritychooses the least common eligible neighbor tribe with a non-zero count.
The generated shader tracks the best candidate, best count, and tie count. A single winner writes that candidate. A tie evaluates the configured tie outcome. If no candidate exists, the fallback outcome is evaluated. Either branch may keep the current tribe, write a fixed tribe, or use a Combine lookup.
Combine outcomes build a bit mask of participating non-dead inputs. A row requires every listed input to be present and rejects every non-dead input it does not list. dead remains a separate presence requirement, so it can coexist with any matching non-dead combination. Lookup rows are sorted so rows explicitly requiring dead are checked before less specific rows. Rows are emitted, like rules, in bounded -row first-match chains, so large lookup tables remain compilable without giving up early-match performance. If no row matches, the default outcome is evaluated.
#Shader Generation
generateComputeWgsl converts the normalized rule list and grid topology into WGSL:
- It specializes neighbor reads for toroidal or bounded topology.
- In toroidal topology, it emits the fast wrapping reads.
- In bounded topology, it emits virtual off-grid reads that return the selected boundary tribe.
- In bounded topology, packed words whose valid cells are all interior use direct neighbor reads for every lane. Edge-containing words keep per-cell interior checks and use boundary-aware reads only where needed.
- It collects unique count selectors to avoid repeating the same neighbor-count expression. Always-true count clauses do not collect a selector unless another clause needs the same count.
- It collects comparison selectors and reuses count variables when possible.
- It emits a local variable for each unique count selector.
- It emits clause expressions as optimized WGSL boolean expressions, including direct equality or one-sided comparisons for count clauses when a full two-sided range is unnecessary.
- It emits outcomes as assignments to
result. - It emits bounded first-match-wins branch chains over active rules, with deterministic probability guards where needed.
- It waits for simulation shader diagnostics and asynchronous pipeline creation, surfacing compiler warnings separately from pipeline failures.
- It emits direct assignment branches for rules, even when other active rules in the same shader are probabilistic.
- It emits a random-seed constant and hash helper only when active probabilistic rules require probability rolls.
Unknown rule tribe references log an error and fall back to the dead tribe index. The editor tries to prevent those cases before rules are applied.