click.mp3
- 18 kb to host, cache, and version
- A network request before the first play
- Fixed pitch and length — retuning means re-editing audio
- A license to re-check on every rebrand
A UI sound does not need an MP3, a CDN, or a loading state. The Web Audio API can synthesize a click, a toggle, or a notification tone directly in the browser, in a few lines, the instant a user interacts.
A downloaded sample is a file: something to host, load, and keep in sync with a design change. A synthesized sound is a function call — there is nothing to fetch before it can play, nothing to re-export when you want it half a tone brighter or ten milliseconds shorter. That is also why it is small: an oscillator and a gain envelope compile to a few hundred bytes of code, not a WAV file.
The clock and the output device. One per page, created on the first user gesture so autoplay policy never blocks it.
new AudioContext()The pitch. A ramp from a higher frequency to a lower one over 80 ms is what makes a click read as a click rather than a beep.
ctx.createOscillator()The envelope. Without a fast fade in and out, starting and stopping the oscillator produces a step in the waveform you hear as a pop.
ctx.createGain()The speakers. Connecting the chain here is the whole of the routing — no buffer to decode, no network request to wait on.
ctx.destinationconst ctx = new (window.AudioContext || window.webkitAudioContext)();
function playClick() {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(880, ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(220, ctx.currentTime + 0.08);
gain.gain.setValueAtTime(0.0001, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.6, ctx.currentTime + 0.005);
gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.12);
osc.connect(gain).connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 0.12);
}
document.querySelector('button').addEventListener('click', playClick);The pattern above is the whole idea: an AudioContext, an OscillatorNode for pitch, a GainNode shaped into an attack-and-decay envelope so the click does not pop, and a single connect chain to the speakers. Swap the frequency ramp and envelope shape and the same four objects become a toggle, a soft tap, or an error buzz.
Blip Blip is a browser-based studio built around exactly this graph — oscillator, filter, envelope, and effects — with faders instead of raw Web Audio parameters. Shape a sound by ear, preview it instantly, then export the finished result as ready-to-paste Web Audio JavaScript: the full version, with per-play variation and any filter, drive, delay, or reverb you added, not just the four-line sketch above. The same code runs unchanged in an Electron app’s renderer process. Take the full studio walkthrough to see every mode, or go straight to state-specific sounds like loading, success, and error tones.
// blip blip — click
// web audio, generated from the studio
const SAMPLE_RATE = 44100;
const DURATION = 0.11;
export function playClick(ctx) {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
const filter = ctx.createBiquadFilter();
osc.type = 'triangle';
osc.frequency.setValueAtTime(1029, ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(933, ctx.currentTime + 0.056);
filter.type = 'lowpass';
filter.frequency.value = 3300;
filter.Q.value = 0.7;
…No. Everything above is generated at runtime by the Web Audio API — there is no MP3, WAV, or CDN request involved, and nothing to add to your asset pipeline.
Yes, all current browsers support it. Older Safari versions needed the webkitAudioContext prefix, which is why the example above checks for both.
Yes. Design the sound in the studio with Simple or Pro controls, then export it as ready-to-use Web Audio JavaScript. Designing and previewing needs no account; exporting the code does, and the first five exports are free.
Open Blip Blip and give it a voice.