PATCHBAY is a fictional modular-synth shed behind a panel beater, and a real synthesizer: three oscillators, a lowpass filter, an LFO and a feedback delay, built live in the browser with the Web Audio API. The page has one job — get a visitor's hands on a cable within ninety seconds. Back to the bench.
01Palette
Everything is argued from workshop hardware under fluorescent light: graphite panels, machined silver jacks, and the three cable colours every synth shed actually stocks. The scope is the only luminous thing on the bench, because phosphor should win the dark.
#2A2D31 · panel graphiteBrushed module faceplates; every surface starts here.
#141619 · shed darkCorrugated wall behind the rack, striped by a repeating gradient.
#C9CED4 · jack silverMachined 6.35 mm sockets, rendered as radial gradients.
#FF5A1F · cable orangeFirst cable out of the drawer; also the selection colour.
#2EC4B6 · cable tealSecond cable; doubles as the wayfinding accent.
#FFC93C · cable yellowThird cable; LED indicators and focus rings.
#4FE0CF · phosphorOscilloscope trace and grid — the one glow in the room.
02Type
Patchbay
Archivo · 400–900
A grotesque with industrial bones. Black weight at heavy negative tracking for the wordmark — half solid, half stroked, like a module with the faceplate off.
FREQ · 65.4 Hz
JetBrains Mono · 400–700
Everything an instrument would silkscreen: knob labels, jack names, readouts, status line. Wide letter-spacing and uppercase to read as engraving, not text.
03Techniques
Web Audio graph, no libraries. Three OscillatorNodes with per-osc level gains, a BiquadFilterNode lowpass, an LFO with a depth gain, a feedback DelayNode, and a DynamicsCompressorNode seatbelt before the destination. The AudioContext is only created on the first pointer or key gesture, per autoplay policy.
Real patching — the signature. Every jack maps to a node port: outputs to source nodes, inputs to destination nodes or AudioParams (pitch and cutoff modulation go through calibration gains into detune, in cents). Dropping a cable calls source.connect(dest); pulling it calls disconnect. Nothing is faked — an unpatched OUT means silence, and stacking cables into one input is a free mixer, exactly like hardware.
SVG cables with spring physics. Each cable is a cubic Bézier whose sag is a damped spring toward a length-derived target, so a freshly-seated cable overshoots and settles like real rubber. A shadow path, core path and sheen highlight sell the roundness; plugs are silver-ringed circles at the endpoints.
Canvas 2D scope and spectrum. The scope draws getFloatTimeDomainData with a rising-edge trigger so waveforms hold still; XY mode plots oscillator A against B for Lissajous figures. The spectrum bins an FFT into 48 log-spaced bars with slow-decay peak-hold caps. DPR capped at 2, resize handled by ResizeObserver, rAF paused when the tab hides.
Procedural panel detail. Brushed-metal faceplates, screw heads, knurled knobs and jack sockets are all layered CSS gradients — no images anywhere on the page.
04Iteration log
Pass 1 · Craft
Audited every text colour against its real background: body faint-ink on shed dark measured 4.8:1, panel labels 5.2:1 — kept. The CRT screen labels measured under 3:1 and were lifted from 50% to 68% phosphor alpha.
Re-read all copy aloud. Kept the shed voice ("silence — the honest kind", "the kettle is not modular (asked)"); tightened nothing else — the draft was already specific.
Verified knob pointer angles, module seam borders and radius scale (6–10px) are consistent across all eight modules.
Pass 2 · Depth
Added peak-hold caps to the spectrum analyser — thin silver lines that ride each bar's maximum and decay slowly, the detail every hardware analyser has and most web ones skip.
Added a self-oscillation easter egg: push resonance past Q 14.5 and the status line admits "the filter is singing on its own".
Fixed the VU meter freezing in XY scope mode — it read a time-domain buffer that only refreshed in timebase mode.
Existing second-reads kept: the PATCHBAY burn-in ghost on the idle scope, drone-duration messages at 90 seconds and 7 minutes, the cable drawer that runs toward empty.
Pass 3 · Hardening
Jacks were pointer-only — keyboard users could focus but not patch. Added Enter/Space activation (click events with detail === 0) so the whole instrument is now playable from the keyboard: latch an out, land it on an in, Esc to drop.
Power-off now redraws the idle flat-line trace instead of freezing the last waveform mid-fade.
Removed a redundant window-resize listener (ResizeObserver already covers the rack) and, for the Chanel rule, the second radial colour wash on the shed wall — one glow was enough.
Verified with headless Chrome: drag-patch, click-patch, keyboard-patch, cable pull and Esc-drop all change the cable count and audio graph; 375px shows no horizontal scroll; reduced-motion kills the nudge pulse, intro rise and cable sway; zero console errors.