← open the piece

Isomorph, model 01

A control deck for a recursive Game of Life, built like a piece of studio hardware.

Brenner Cruvinel, design and engineeringHoff Research, 2026WebGL2, Haxe, vanilla JS, CSS

Isomorph is a Game of Life you can zoom into forever. Every cell is itself a machine running the same rules, so zooming in never reaches a bottom and zooming out never reaches a top. It renders in real time in WebGL2 with an HDR pipeline, motion trails and a glyph layer bound to the simulation.

This case study is about the part people touch: the control deck. It replaced a set of floating glass panels that looked like every other generated interface and did not feel like an instrument.

0runtime dependencies in the interface
~21 KBgzipped, all interface scripts together
2fluid tokens every key, LED, radius and LCD dot derives from

The constraint: a shell over a sealed renderer

The renderer is written in Haxe and compiled into one JavaScript bundle. For this work the compiler and the engine library were not available, so the interface could not change a line of the renderer. Everything had to live in a shell around it.

The shell talks to the renderer through three narrow bridges:

From glass to hardware

The visual language comes from dark IBM keyboards and the Roland MC-500 sequencer: flat plastic, keycaps with physical depth, LEDs, a dot-matrix LCD and a floppy drive slot. There is no blur and no translucency anywhere.

The LCD is a canvas with a hand-drawn 5 by 7 font. It shows the rate, the zoom, the lens and a frame-rate band scaled to the refresh rate of the display, and it takes over for short messages when something changes.

The deck has two layouts with the same keys. The panel sits in a corner. The strip is one row of keys along the bottom, like a keyboard resting on a desk, and it can be switched with one key.

No fixed sizes

Every dimension in the deck derives from two fluid tokens defined with clamp(): the size of a key and the pitch of an LCD dot. The key grows with the viewport inside a range and grows again for coarse pointers, which is an adaptation to the input, not to a device.

Loading is part of the machine

The deck appears at once, but inert. While the simulation data loads, the drive LED blinks and the LCD reads READING DISK and TRACK 2/3. The progress is real: a PerformanceObserver watches the three data files arrive. When the renderer is ready, the deck runs a LED test and powers on. The layout never changes size at that moment, because every decision about it was made before loading started.

Coarse and fine

The rate runs from almost frozen to about 65,000 times the base speed on an exponential curve. A fader alone cannot be both fast and precise across that range, so next to it sits a jog wheel: an endless encoder with no absolute position. Each detent moves the rate by about four percent. It turns by circular drag, by mouse wheel, by arrow keys or by the bracket keys.

Building it exposed a bug. The fader had a magnetic detent at 1×, and a keyboard step from 1× landed inside the detent and snapped back, so the arrow keys could never leave 1×. Now only a drag snaps; discrete steps stop on 1× when they cross it and move on with the next step.

Capture

Sound

All sound is synthesized with Web Audio; there are no audio files. Keys click on the way down and up, switches thunk, the jog ticks on each detent. A music layer, a synthesized drone, listens to the simulation: it samples the canvas at eight by eight pixels four times a second, and the brightness opens its filter while the movement between samples raises a layer of hiss. Both stay off until the visitor presses the sound key.

State you can send

The URL hash carries only what differs from the default, in readable form, for example #lens=plate&rate=2.3&ink=amber. Opening that link reproduces the setup once the renderer is running. A link key copies it.

A shift key on the strip gives each action key a second function printed in ink on the keycap. It brings to the strip what only the panel had: zoom drive, scanlines and link. Icon and legend of both functions share one grid cell, so a key never changes width when the layer switches. Sound has one key with the system keys, visible in both layouts, because on a phone there is no keyboard shortcut to fall back on. It turns on the music and the key clicks together.

Accessibility

Delivery

The site is static files behind Caddy. The content security policy allows scripts only from the site itself plus two hashed inline snippets, and fonts only from the site itself, so Inclusive Sans is self-hosted. One lesson from shipping: a script named after a smart-home word was blocked by content blockers on the name alone, and with it the whole speed control. Shell scripts now get neutral names.