A numbers-station radio you can actually tune. Drag the dial from 4000 to 8000 kHz and five stations surface out of synthesized static — every hiss, chime and half-human voice generated by WebAudio at the moment you hear it. The page has one job: make you slow down when the static bends.
WAVELENGTH is a fictional listening post for shortwave oddities — the buzzers, beacons and numbers stations that really do haunt the high-frequency bands. The audience is anyone who has ever fallen down the UVB-76 rabbit hole. The site is not a page about a radio; it is the radio, with a frequency log that fills itself as you hunt.
The discipline: amber means the machine, green means a signal. Nothing else gets a colour. When a card turns green in the log, the meaning arrives before the words do.
The signature element is the tuning itself. One noise buffer feeds a bandpass filter for the static bed. Each station is a live WebAudio subgraph whose gain follows a Gaussian of the dial's distance from its carrier — so stations fade in through the noise rather than switching on. Three details sell the physics: an AGC gain that ducks the static under a strong carrier, a heterodyne whistle whose pitch is proportional to your offset from the carrier (the classic falling whine as you centre a signal), and a slow two-phase sine product simulating ionospheric QSB fade. Everything passes through a highpass–peaking–lowpass chain so the whole band sounds like a small valve-radio speaker.
The stations: a Morse beacon is a gated sine with 4 ms envelopes; the
buzzer is a sawtooth through a resonant bandpass, gated every two seconds; the
radiofax is a 1900 Hz carrier frequency-modulated by a 2 Hz sawtooth
LFO; the interval signal is eleven detuned triangle-wave notes through a feedback
delay. The numbers voice is formant synthesis — a sawtooth source split into
three parallel bandpass filters whose centre frequencies jump between vowel formant triples
(F1/F2/F3), with highpassed noise bursts for fricatives. It is deliberately not quite human,
which is exactly what a numbers station should be. Traffic is seeded from today's date, so the
groups change every day. A scheduler pump keeps ~1.6 s of events queued per station using
setTargetAtTime automation, so loops survive tab jank.
Visuals are canvas 2D (dial scale, needle bloom, phosphor-persistence oscilloscope fed by an
AnalyserNode), SVG (the S-meter), and CSS gradients (the bakelite cabinet, its
screws, the toggle). No raster images anywhere.
First headless render at 375px showed the dial's megacycle labels colliding at the band edges ("4.04.5") — the scale now thins to 1 MHz labels when the canvas gives each label under 48px. Removed a dead second angle system left in the S-meter tick generator. Re-checked copy against the discipline rule — amber is the machine, green is a signal — and confirmed the body ink (#DCCFBB on #120D09) sits well past 4.5:1. Locked log cards were rewritten from dead "???" placeholders into genuine hunting hints: approximate megacycles plus what to listen for.
Two additions for the hands, three for the second visit. Hands: a tuning rush — the static's bandpass centre rides your dial velocity, so sweeping the band audibly "rushes" the way a real receiver does; and the needle blooms from amber to signal green as you lock a carrier, tying the two-colour rule into the instrument itself. Second visit: every seventh cycle the buzzer stops and a formant voice reads its own frequency back — 4 6 2 5; MAGPIE's five-figure groups are seeded from today's date, so tomorrow's traffic differs; and an unlisted sixth carrier hides at 7212 kHz keying "73" — the operators' goodbye — whose log card doesn't exist until you find it.
Full headless QA: powered on, tuned to 5732 by tap-jump plus keyboard, verified the
discovery pipeline (toast, card flip, localStorage), scope pixel-diff confirmed
live audio, zero console errors, no horizontal overflow at 375/768/1440, reduced-motion path
renders the hero fully visible with damping removed and scope refresh dropped to ~11 fps.
rAF loop and AudioContext both suspend on document.hidden; DPR capped at 2; resize
debounced. Chanel rule: cut the animated dust-speckle on the dial glass — the needle bloom was
already doing that work. Full keyboard path: the dial is a real role="slider"
with arrows, paging and Home/End.
The formant voice is eerie rather than intelligible — a deliberate trade (real numbers-station
voices are the uncanny valley anyway), but worth hearing with headphones. Discovery state
persists in localStorage; clearing site data resets the log.