A Go simulation core with a REST + WebSocket streaming API and a React/WebGL2 UI — all shipped in one small distroless container. State lives in SQLite, so the world survives restarts.
$ docker run -d -p 8050:8050
mist941/b3s23-engine
// features
A complete, production-shaped Game of Life: simulation engine, streaming API, interactive UI and persistence — with zero configuration.
Draw cells with the mouse — paint, erase, toggle — or stamp classic patterns with a live ghost preview.
Bit-packed frames are unpacked on the GPU. Smooth pan and zoom even on large grids.
Full control surface — play, pause, step, reseed, resize, tick rate, cell editing — plus binary frame streaming with per-client backpressure.
The grid is snapshotted to SQLite and restored on restart. Pause, redeploy, continue.
Bit-packed toroidal grid — one bit per cell, up to 16384×16384 — stepped in parallel across CPU cores.
One small distroless Docker image (amd64 + arm64), health check included, no configuration required.
// quick start
One command. The UI and the API are served from the same port — open localhost:8050 when it's up.
# the /data volume keeps the SQLite database, so the world
survives restarts
docker run -d --name b3s23 -p 8050:8050 -v b3s23_data:/data
mist941/b3s23-engine:latest
Clone the repository, then:
docker compose up -d
# pulls the published image docker
compose up -d --build
# or build it from source
Engine (Go ≥ 1.26, no CGO) and the UI dev server (Node ≥ 24) with hot reload:
# engine — API on :8050
cd engine go run ./cmd/engined
# UI dev server, proxies /api to the engine
cd ui npm install npm run dev
Or build the UI once and serve it straight from the engine binary:
cd ui && npm install && npm run build cd
../engine && go run ./cmd/engined -static ../ui/dist
// examples
Eight classics ship with the UI — pick one, hover for a ghost preview, click to stamp it onto the grid.
The smallest spaceship — glides diagonally forever.
Cruises across the grid at half the speed of light.
Five cells that erupt into a thousand generations of chaos.
Seven cells that take 5,206 generations to settle down.
Vanishes without a trace after exactly 130 generations.
The best-known period-3 oscillator.
Blinks through a fifteen-generation cycle.
Fires a fresh glider every 30 generations — forever.
Everything the UI does goes through the public API — script it with
anything that speaks HTTP. Frames stream over WebSocket at
/api/v1/ws.
# current state
curl localhost:8050/api/v1/status
# pause the loop
curl -X POST localhost:8050/api/v1/pause
# draw a glider, cell by cell
curl -X POST localhost:8050/api/v1/cells \ -d
'{"cells":[[11,10,1],[12,11,1],[10,12,1],[11,12,1],[12,12,1]]}'
# reseed the whole world at 30% density
curl -X POST localhost:8050/api/v1/reseed -d
'{"probability":0.3}'