05Studio — Self-initiated

Longwave

Bureau of Lost Frequencies

Six dead signals — a shipping forecast, a numbers station, a pirate broadcast, a satellite's last telemetry — held on one band from 100 kHz to 18 MHz. There are no sections to scroll between. There is a dial.

Longwave — a ribbon microphone in a dim archive room beneath the words 'Bureau of Lost Frequencies, archival band 100 kHz – 18 MHz.'
Role
Concept · Art direction · Interaction design · Shader engineering · Audio engineering
Stack
Next.js 16 · React 19 · OGL · Web Audio API · GSAP Observer / Draggable / Inertia · Zustand · Vitest
Year
2026
Discipline
Interaction R&D · Web Audio
Navigation modelTuning, not scrolling
Band100 kHz – 18 MHz, continuous
StationsSix, each with its own dossier
Shader passesOne — everything composited in it
01

The argument is the interaction

Longwave exists to make one claim: that this studio invents interaction models rather than assembling pages. So the site has no scroll navigation between sections at all. The entire experience is a single continuous frequency band, and moving through it means tuning — dragging, wheeling, or arrowing along the spectrum while shader static and adaptive audio resolve into readable content as you lock onto a station.

That single novel interaction has to feel real, because if it feels like a gimmick the argument collapses. Everything else in the build was subordinated to making the dial feel like a physical object.

02

Six signals on file

Each station is a full dossier — call sign, first and last broadcast, origin, and a written record in the Bureau's flat institutional voice.

147 kHz — The Shipping Ledger
A marine forecast broadcast twice daily from 1924 to 1998, reading sea areas that appear on no Admiralty chart. It ceased without a sign-off.
500 kHz — Bureau Internal
The frequency the Bureau reserves for itself. No content, only the maintenance traffic of an institution that catalogues what the air has forgotten.
4625 kHz — Station Echo-9
A numbers station, still on file, long past its purpose.
6300 kHz — Radio Meridiana
A pirate station that vanished mid-schedule.
12700 kHz — OSPREY-1
The last telemetry of a decommissioned satellite.
17200 kHz — The Night Auction
A broadcast that sold things no listener could identify.
03

Making a dial feel like an object

GSAP's Observer unifies wheel, touch and pointer input into one delta model, so the dial responds identically to a trackpad flick and a thumb drag rather than needing three reconciled handlers. Release velocity hands off to InertiaPlugin, which glides the value to rest and snaps to the nearest of the six station frequencies — momentum and overshoot with detents, not a scroll-snap approximation.

The frequency value updates every frame, which makes it the wrong thing to keep in React state. It lives in a small external store instead: the shader uniforms and the audio gains subscribe to it imperatively outside the render cycle, while the DOM chrome reads it reactively. Sixty frames a second of dial movement never touches the component tree.

04

The audio engine

One AudioContext, opened only on an explicit power-on gesture — which the browser autoplay policy requires anyway, and which happens to be exactly what a radio does. Seven buffers (a noise bed and six station stems) are decoded up front behind a loader, then each loops through its own gain node into a master bus.

Every stem's target gain is recomputed each animation frame from the distance between the dial and that station's frequency, on an equal-power curve rather than a linear one — a linear crossfade produces an audible dip where two sources overlap. The gains are applied with setTargetAtTime, whose exponential approach smooths high-frequency target changes for free and caps how fast any gain can physically move. The result is that no matter how violently you throw the dial, the crossfade can never accelerate unnaturally.

05

One shader pass, and a way in without it

The static, the noise, the grain, the vignette and the resolve blend are all composited inside a single fullscreen fragment shader in OGL. There is no scene graph and no multi-pass compositor, because there is only ever one effect — adding a renderer with a camera and a transform hierarchy would have been paying for abstractions the piece does not use.

For anyone who cannot or does not want to use the dial, an INDEX view lists the full archive as plain navigable content. Reduced motion is honoured throughout, and nothing plays until you turn the radio on.

A case study is a summary. The site is the argument.

Longwave is live — go and use it, then tell us what you want built.