Designing Interactive Audio for the Web
I wanted sound effects on my site — hover sounds, click sounds, ambient noise. Nothing crazy. Just enough to make it feel alive.
Turns out the Web Audio API is pretty straightforward once you get past the initial weirdness. Here's what I learned.
The Audio Context Thing
Every sound you make needs an AudioContext. Think of it as a mixer board for your browser.
const getAudioContext = (): AudioContext => {
const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;
return new AudioContextClass();
};Browsers won't let you play sound until the user clicks something first. So you create the context but don't start it until the first interaction.
Making a Hover Sound
I wanted a soft blip when hovering over buttons. Here's what I ended up with:
export function playHoverSound(ctx: AudioContext) {
if (ctx.state === 'suspended') {
ctx.resume();
}
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(600, ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(800, ctx.currentTime + 0.05);
gain.gain.setValueAtTime(0.15, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.08);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start(ctx.currentTime);
osc.stop(ctx.currentTime + 0.1);
}The frequency goes up slightly (600→800) so it sounds like a rising blip. The gain drops to zero fast so it's short. That's basically it.
The Click Problem
Browsers block audio until user interaction. The way around it:
- Listen for the first click on the page
- Resume the AudioContext inside that handler
- Remove the listener after
Once the context is resumed, you can play sounds freely. Just don't expect audio to work before someone interacts with your page — it won't, and it shouldn't.