Skip to content

About

Conway's Game of Life with time as the third axis: every generation is a horizontal slice, stacked into a spacetime block. A glider becomes a diagonal thread. Single self-contained HTML file, no dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Spacetime Life

Conway's Game of Life with time as the third axis. Every generation is a horizontal slice, stacked upward as the simulation runs — so instead of watching cells flicker, you watch the history accumulate into a solid.

The R-pentomino building its spacetime block

A single self-contained HTML file. No build step, no dependencies, no canvas library — the 3D is a hand-rolled orthographic projection over plain Canvas 2D.

What you're looking at

The bright frame is the present. Everything below it already happened.

In the grid In the block
Still life a straight vertical column
Glider a diagonal thread — motion in space becomes a tilt in time
Oscillator a braid: threads that split and rejoin on its period
A cell being born one cold blue mark, the only cool hue in a warm field
Extinction a thread that simply stops

The Gosper glider gun is the clearest demonstration: the gun itself is a knot of braided threads, and each glider it emits leaves at a constant angle, forever.

Gosper glider gun, light theme

Run it

open index.html

Or serve it, if your browser is strict about file://:

python3 -m http.server 8000

It also works as a GitHub Pages site with zero configuration — index.html is at the repo root, so Settings → Pages → Deploy from branch → main / (root) is all it takes.

Controls

Input Action
Drag orbit the camera
Scroll / pinch zoom
Space run / pause
S single step
R reseed the current pattern
C clear the grid

The rail on the right holds the rest:

  • Speed — 1 to 30 generations per second.
  • Seed — glider, Gosper glider gun, R-pentomino, acorn, diehard, pulsar, lightweight spaceship, random soup.
  • Present state — a 2D plate of the newest slice. Draw on it to edit the present; the past stays where it is.
  • Depth — how many generations stay on the axis, 6 to 110. Older slices fall off the bottom.
  • Spacing — the height of one generation relative to one cell. At 1.00× a glider's thread is steep, because it only travels one cell every four generations; drop it toward 0.30× and gliders lean into obvious diagonals.
  • Slices / Both / Threads — draw the filled generations, the worldlines connecting a cell to its own next state, or both.
  • Wrap — toroidal grid on, bounded grid off. Note that with wrapping on, the glider gun's output eventually comes back around and collides with the gun.

The full instrument

How it works

The automaton is unremarkable on purpose: a 44×44 grid in a Uint8Array, standard B3/S23, double-buffered per step, with an optional toroidal wrap. Each step also records which cells were born that generation, which is what drives the blue accent.

The history is a ring buffer of snapshots, trimmed to the depth setting. Editing the present slice writes through to the newest snapshot without disturbing anything below it.

The renderer is where the work is. Three things keep it cheap enough to run at 60 fps while drawing tens of thousands of quads:

  1. Orthographic projection, computed once per frame. The projection is affine, so a cell's position is origin + i·e₁ + j·e₂ + t·e₃ with the three basis vectors derived once from the camera angles. Per cell it's two multiplies and two adds — no matrix stack, no per-vertex transform.

  2. No depth sorting. Cells within one generation are coplanar and disjoint, so their orthographic projections can never overlap — they can be drawn in any order. Only the slices themselves need ordering, and that's a single comparison against the camera elevation to decide whether to walk the time axis up or down.

  3. Two paths per slice. Every live cell in a generation shares one colour and one alpha, so the whole slice goes into a single Path2D (survivors) plus one more (births) and gets filled twice, instead of once per cell. A hundred slices cost ~200 fill calls regardless of population.

Measured worst case — 110 slices, ~14,000 quads and ~11,000 worldline segments at 1900×1500 — renders in 6.4 ms, comfortably inside a 60 fps budget.

Colour encodes age. The ramp runs from a hot near-white at the present through amber and mulberry to a deep indigo at the oldest kept generation, with alpha falling off alongside it, so depth in time reads as depth in the image. Births are the single cool hue so that new growth pops against the warm field. The light theme rebuilds the same structure as plotter ink on cool paper rather than inverting it.

Layout

index.html      the entire app — markup, styles, simulation and renderer
docs/           README assets
LICENSE         MIT

License

MIT — see LICENSE.

About

Conway's Game of Life with time as the third axis: every generation is a horizontal slice, stacked into a spacetime block. A glider becomes a diagonal thread. Single self-contained HTML file, no dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages