Devlog #1 — a voxel engine that fits in a browser tab

July 5, 2026 · the Playpit devlog

Playpit’s first game is a 3-D voxel sandbox, which means the first thing we had to build wasn’t a game at all — it was an engine. This post is a tour of the interesting parts. Everything below runs in a plain browser tab, no downloads, and targets 60 FPS on a mid-range laptop with integrated graphics.

Chunks, and why the mesher lives in a worker

The world is made of 16×16×256 chunks of block IDs. The naive way to draw blocks is one cube per block — that dies at a few thousand blocks. The standard fix (and ours) is greedy meshing: merge every run of identical, visible block faces into as few rectangles as possible, so a flat 64-block wall becomes two triangles instead of 128.

Meshing is the hottest CPU path in a voxel engine, so ours runs in a Web Worker. The main thread snapshots a chunk (plus a 1-block border from its neighbors) into a padded volume, hands it to the worker as a transferable buffer — no copying — and gets triangles back a frame or two later. The render loop never stalls, even when you sprint across ungenerated terrain and a dozen chunks mesh at once.

Light as a flood fill

Lighting is two breadth-first floods over the block grid: skylight pours straight down from the sky and spreads sideways into overhangs, and blocklight radiates outward from glowing blocks, losing one level per step. Both feed the mesher, which bakes light into vertex colors — so caves are actually dark, torch-lit rooms actually glow, and none of it costs anything per frame.

The part that took care: edits. Place a block over a shaft of light and the engine doesn’t recompute the world — it runs an incremental un-flood/re-flood from the edit outward, touching only the blocks whose light actually changed.

A world from one number

There are no level files. A world is a seed: fractal noise stacks terrain, a temperature/ humidity pair picks biomes, 3-D noise carves caves, and a scattering pass plants trees, ores, and the occasional ruined tower. The same seed produces the same world on every device, block for block — which turns out to be the foundation of our favorite feature (more on that in the next post).

Your edits are stored as deltas in IndexedDB: the engine replays your changes over freshly generated terrain on load. A hand-built base costs kilobytes, not megabytes, and “save” is instant.

Streaming, physics, the rest

Chunks stream in nearest-first around you on a time-sliced budget, distant rings drop to a lower level of detail, and far chunks unload entirely — the world feels infinite while memory stays flat. The player is a real physics body (an AABB with gravity and collision, not a floating camera), and a fixed-tick entity system runs the critters. A day/night clock drives the sun, the sky, and the skylight.

All of it is imperative Three.js — no framework in the hot path — and all of it is original, clean-room code. Next post: the game we built on top, and the postcard trick that deterministic worldgen makes possible.


← more devlog · play the games