Game of Life
Conway's Game of Life, running at up to 60 generations a second on a wrap-around canvas you can paint into and watch evolve.
Conway's Game of Life is four lines of rules that produce endless behavior, and the appeal is almost entirely in watching it move. A lot of versions I tried slowed down past a small grid, or didn't expose the controls that make it worth poking at: pausing mid-pattern, stepping one generation at a time, or dropping in a glider gun to see where it goes.
I wanted one that stayed smooth at a full screen of cells and let me drive it like an instrument. So the simulation runs on a flat typed array with a second buffer it swaps each tick, the canvas redraws every frame, and everything (speed, grid size, patterns, painting) is wired to controls and keyboard shortcuts so you can stay in the loop while it runs.
Under the grid
- Typed-array grid: the board lives in a flat
Uint8Arraywith a reused scratch buffer for the next generation, so each tick computes into the scratch and swaps rather than allocating, keeping the renderer steady up to 180×108 cells. - Toroidal neighbours: the edges wrap, so a glider that runs off the right side reappears on the left and spaceships glide forever instead of dying at a wall.
- Drive it live: play, pause, step a single generation, clear, and randomize. The speed slider runs 1 to 60 generations per second and starts at 12, and it is decoupled from the display refresh rate through a tick accumulator, so it changes the simulation rather than the animation. Click toggles a cell and dragging paints or erases a run of them.
- Four grid sizes: 60×36, 100×60, 140×84 and 180×108, with 100×60 the default. Resizing keeps whatever overlaps the new bounds instead of wiping the board.
- Six patterns, or your own: the menu centres a Glider, Lightweight Spaceship, Pulsar, Pentadecathlon, R-pentomino or Gosper Glider Gun on the grid, and the page opens with the gun already loaded. Import RLE parses a run-length-encoded pattern pasted from conwaylife.com and stamps that instead; if the pattern is wider or taller than the current grid it says so and names the size, rather than clipping it silently.
- Turf Wars changes the rules: cells belong to one of ten coloured teams, and only same-team neighbours count toward survival and birth. A dead cell is born into a team only if exactly three of its neighbours share that team, so factions grow into each other and take ground.
- Stats and shortcuts: generation count, live cells, measured frame rate and current grid size update as it runs. Space plays and pauses,
Ssteps while paused,Rrandomizes at 28% density,Cclears.
The rules
B3/S23. A live cell with two or three live neighbours survives; a dead cell with exactly three live neighbours is born; everything else dies or stays dead. That is the entire rule set. Out of it come the Pulsar, a period-3 oscillator of 48 cells; the R-pentomino, five cells that stay chaotic for 1,103 generations before settling; and the Gosper Glider Gun, the first pattern anyone found that grows without bound.
Stack
Vite · React · TypeScript · Tailwind, rendering to a raw Canvas at up to 2× device pixel ratio. The simulation is plain typed-array logic kept out of React's render path, so the component tree only handles controls while the grid steps and draws on its own loop. Static build on GitHub Pages, nothing to install and nothing to sign into.