Static & Noise is a label site whose signature trick is refusing to fake the music. There are no audio files in the repo. Press TRANSMIT and the page synthesizes a techno loop from raw oscillators, listens to itself through an AnalyserNode, and lets the signal shove the pixels around.
A label for experimental electronics can’t sell itself with stock photos of DJs. It has to
behave like the records sound: abrupt, loud, precise underneath the chaos.
So the identity is acid lime on true black with a hot magenta counterpunch, the easing is a
hard-cut cubic-bezier(.85,0,.15,1) that slams instead of settles, and the whole
page is wired to one audio graph. Every release in the catalog is a preset for the same
house synth — pressing play retunes it to that record’s BPM, key and pattern. A sketch,
not the master. Honest, and more fun than a fake <audio> tag.
requestAnimationFrame loop do everything.Browsers block autoplay, so the AudioContext is built lazily on the first press of
TRANSMIT (a real <button aria-pressed>). The graph is: sources →
compressor → master gain → analyser → speakers. Three voices, no samples:
// KICK — a sine that falls an octave and a half in 110ms
const o = ctx.createOscillator(), g = ctx.createGain();
o.type = 'sine';
o.frequency.setValueAtTime(155, t);
o.frequency.exponentialRampToValueAtTime(44, t + 0.11);
g.gain.setValueAtTime(0.0001, t);
g.gain.linearRampToValueAtTime(0.95, t + 0.004); // ramp in: no click
g.gain.exponentialRampToValueAtTime(0.0001, t + 0.3); // ramp out: no pop
o.connect(g); g.connect(comp);
o.start(t); o.stop(t + 0.32);
Hats are a shared 1.2-second white-noise buffer pushed through a 7.8 kHz highpass with a 2–160 ms envelope. The acid line is a sawtooth into a resonant lowpass whose cutoff dives four octaves per note — the classic 303 gesture in six lines. Underneath, two detuned saws drift through an LFO-swept lowpass as a drone. Every gain change is a ramp, never a jump: that’s the whole anti-click discipline.
Timing uses the standard lookahead scheduler — a 30 ms setInterval books
events ~120 ms ahead on the audio clock, so the groove never hiccups when the main
thread does:
while (nextTime < ctx.currentTime + 0.12) {
const step = pattern[stepIdx]; // 16 steps per bar
if (step.kick) kick(nextTime);
if (step.hat) hat(nextTime, step.open);
if (step.note !== null) acidNote(nextTime, step.note);
nextTime += 60 / bpm / 4; // one 16th note
stepIdx = (stepIdx + 1) % 16;
}
The full-viewport canvas runs two personalities. Idle: generative television static — drifting scan bands, mono ticks, the occasional acid fleck. Playing: 64 log-spaced frequency bars with fast-attack/slow-decay smoothing, jittered horizontally by high-band energy so they mutate into something more organic than a spectrum plot:
analyser.getByteFrequencyData(freq);
const bin = 2 + Math.floor(Math.pow(i / N, 1.7) * 330); // log-ish spacing
const v = freq[bin] / 255;
bars[i] += (v - bars[i]) * (v > bars[i] ? 0.5 : 0.1); // punchy up, lazy down
Beats aren’t “detected” — the scheduler knows when every kick lands, so it
queues the timestamps and the render loop consumes them on the audio clock. Each kick fires
a shockwave ring, a clamped shear on the bar field, and a slice-glitch on one line of the
Syne wordmark (two pseudo-element copies, clip-path keyframes, acid and magenta).
Every hero glyph also carries a per-glyph random vector; on the beat they scatter
≤6 px / ≤4° and snap back — enough to feel the bass, never enough to break legibility.
aria-hidden with a prose
alternative, and a <noscript> note explains why the button won’t sing.Relative paths, zero build. Three commands:
gh repo create static-and-noise --public --source . --push
gh api --method POST /repos/USER/static-and-noise/pages \
-f 'source[branch]=main' -f 'source[path]=/'
# live at https://USER.github.io/static-and-noise/ in ~1 min
A .nojekyll file keeps Pages from second-guessing the folder structure.