Editorial poster: the Wolfram Rule 30 triangle above four generations of a Conway glider.
Engineering

Cellular automata runtime

StatusLive
RoleEngineering
Year2024
Stack
canvas 2dtypescriptreact

Overview

A Conway and Wolfram engine on Canvas 2D, with live controls and preloaded patterns, embedded inside the lab entries.

Why Canvas rather than WebGL

At this grid resolution the bottleneck is the logic, not the paint. Counting neighbours for every cell is CPU work, and moving it to the GPU does not make it faster: it spreads it out, and then charges for the trip back.

There is a more stubborn reason. These engines live embedded inside the lab entries, and some of them appear in preview cards. Standing up a WebGL context for a thumbnail nobody may look at is expensive in a way that is not measured in frames per second, but in memory and in contexts the browser caps per tab.

Two automata, two ways to paint

Both engines draw grids of cells, and neither draws the same way. Not by oversight: they do not change the same amount per frame.

Conway repaints the entire world every generation — any cell can be born or die — so painting cell by cell would be thousands of draw calls for one frame. Instead it writes pixels by hand into an ImageData and blits it once with putImageData.

Wolfram does not. An elementary automaton adds one row per generation and never touches what is already drawn; history accumulates downward like a log. There, fillRect per cell is the right call, and standing up a whole pixel buffer to write a single row would be more code and more work.

Figure pending/media/projects/conway-canvas-runtime/01-painting.webp

The rule is a number

My favourite part of elementary automata is that the rule is not programmed, it is counted. There are eight possible neighbourhoods — three cells, two states — and the rule says what comes out of each. Eight binary answers are eight bits, which is to say a number between 0 and 255.

So "Rule 30" is not a name: it is the table itself, written in decimal. Building it is reading its bits.

ts
const table = new Uint8Array(8);
for (let index = 0; index < 8; index += 1) {
  table[index] = (rule >> index) & 1;
}

Every bit of variety in the system — from Rule 30's chaotic triangle to Rule 184's traffic — comes out of those three lines.

The four classes

Wolfram sorted these behaviours into four families, and the runtime shows the class next to the rule because that is what turns the toy into an instrument: uniform, periodic, chaotic, and — the interesting one — class IV, where localised structures appear that travel and interact. Rule 110 is there, and it is Turing complete.

Figure pending/media/projects/conway-canvas-runtime/02-classes.webp

Embedded in the lab

Neither engine knows a page exists. They take their configuration — cell size, initial density, rule, speed — from the lab's own record, and what is stored there is one configuration object per entry.

That is what lets a single lab entry publish several demonstrations without duplicating the engine, and what makes a card's preview and the full-screen runtime literally the same code with different numbers.

More projects



SESSION_ELAPSED00:00:00
LOCALE: ENENV: PROD