Zero Sound Files — Synthesizing SFX with Web Audio
I kept external assets to a minimum throughout the rebuild.
Only the background music (BGM) uses mp3s; the sound effects (SFX) use no files at all — every effect (collect, jump, hit, combo) is synthesized on the spot with the Web Audio API.
There are only two basic tools: an oscillator (which generates a waveform) and gain (volume).
Add a starting frequency, a duration, a waveform type, and an envelope that decays the volume toward zero over time, and you've got one short sound effect.
I reuse this single function for everything.
function blip(freq, dur, type, gain = 0.15, slide = 0) {
const c = ac(); // lazily-created AudioContext (browser/SSR guard)
const o = c.createOscillator();
const g = c.createGain();
o.type = type;
o.frequency.setValueAtTime(freq, c.currentTime);
if (slide !== 0) // glide the pitch over the duration
o.frequency.exponentialRampToValueAtTime(freq + slide, c.currentTime + dur);
g.gain.setValueAtTime(gain, c.currentTime);
g.gain.exponentialRampToValueAtTime(0.0001, c.currentTime + dur); // envelope
o.connect(g).connect(c.destination);
o.start();
o.stop(c.currentTime + dur);
}
I split the timbres: a low sine wave for jumps, a gritty sawtooth for taking a hit.
My favorite detail is the collect sound — the pitch rises as your combo climbs.
export const playCollect = (combo: number) =>
blip(520 + Math.min(combo, 24) * 40, 0.18, "triangle", 0.18, 120);
520 + min(combo,24)*40Hz.
Grab one and it's 520Hz; as the combo builds it steps up a notch at a time and caps out at the ceiling.
When you collect a streak in a row, the pitch trickles upward — and that rising feel was more thrilling than the combo itself.
There's no way I'd have gotten that satisfaction from replaying the same canned sound.
I also covered the browser environment check.
If window or AudioContext is missing, every function quietly falls back to a no-op.
That keeps things from blowing up under SSR or unsupported environments.
That wraps up the rebuild dev log.
The takeaway is simple — even with zero sound-effect files, code alone was enough to make sounds that feel cute and satisfying to play.