The Web Audio API is a criminally underused tool for generating dynamic, real-time sound. This post walks through creating a mini synth from scratch — no libraries, no UI frameworks, just pure browser-native sound generation using JavaScript. Ideal for game devs, creative coders, or anyone who wants to learn procedural audio at a low level.

Why Use Web Audio API Directly?


  • No external libraries or builds needed
  • Precise control over oscillators, filters, and timing
  • Useful in games, interactive apps, or generative art

Step 1: Create the Audio Context and Oscillator


The AudioContext is your entry point to the Web Audio graph:


const ctx = new (window.AudioContext || window.webkitAudioContext)();
const osc = ctx.createOscillator();
osc.type = 'sawtooth'; // Try sine, square, triangle, etc.
osc.frequency.value = 440; // A4
osc.start();

Step 2: Add Envelope Control (ADSR)


We'll use a GainNode to fade the volume in and out for each note:


const gain = ctx.createGain();
gain.gain.setValueAtTime(0, ctx.currentTime);
gain.gain.linearRampToValueAtTime(1, ctx.currentTime + 0.1); // attack
gain.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.6); // decay + release
osc.connect(gain).connect(ctx.destination);

Step 3: Wire It to a Key Press


Basic synth: play a tone on key press, release it after a fixed time:


document.addEventListener('keydown', (e) => {
const note = e.key.toUpperCase();
const freqMap = { A: 440, W: 466, S: 494, D: 523 }; // add more

if (!freqMap[note]) return;

const o = ctx.createOscillator();
const g = ctx.createGain();
o.type = 'square';
o.frequency.value = freqMap[note];
g.gain.setValueAtTime(0, ctx.currentTime);
g.gain.linearRampToValueAtTime(0.9, ctx.currentTime + 0.05);
g.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.4);

o.connect(g).connect(ctx.destination);
o.start();
o.stop(ctx.currentTime + 0.5);
});

Step 4: Add Filter for Character


A low-pass filter can shape the tone:


const filter = ctx.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 800;
osc.connect(filter).connect(gain).connect(ctx.destination);

Pros and Cons


✅ Pros


  • Completely free, native to every modern browser
  • Fine-grained control of sound generation
  • Great for games, audio toys, or learning synthesis

⚠️ Cons


  • No polyphony unless manually managed
  • Inconsistent latency across devices
  • Touch event restrictions on mobile (needs user interaction)

🚀 Alternatives


  • Tone.js — high-level abstraction of Web Audio
  • Howler.js — great for sample playback, less for synths
  • SuperCollider (via WebAssembly) — if you need serious sound design

Summary


With just a few lines of JavaScript and zero dependencies, you can build a surprisingly expressive browser synth. This technique is useful not just for fun, but for building educational tools, generative art, and sound-rich web experiences without ever leaving the frontend.

If this was useful, you can support me here: buymeacoffee.com/hexshift