Skip to content
Back to skills

Web Audio Api Synthesis

ASecurity

Design and implement low-latency browser audio synthesis, sound effects, audio node graphs, convolver reverbs, and custom AudioWorklet processors using the W3C Web Audio API. Trigger when building interactive web synthesizers, in-browser audio editors, sound engines for games, or real-time audio visualization.

  • 8 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentsjavascripttypescriptgojavanodegitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add hamzabellouch/agent-skills --skill web-audio-api-synthesis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Web Audio Api Synthesis?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Web Audio Api Synthesis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hamzabellouch-web-audio-api-synthesis/badge)](https://www.skillsdirectory.com/skills/hamzabellouch-web-audio-api-synthesis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: web-audio-api-synthesis
metadata:
  category: Audio Engineering and Digital Signal Processing
description: Design and implement low-latency browser audio synthesis, sound effects, audio node graphs, convolver reverbs, and custom AudioWorklet processors using the W3C Web Audio API. Trigger when building interactive web synthesizers, in-browser audio editors, sound engines for games, or real-time audio visualization.
compatibility: W3C Web Audio API Recommendation, Modern Browsers (Chrome, Firefox, Safari)
---

# Web Audio API Synthesis Skill Guide

This skill governs standard practices for building high-fidelity audio synthesis, modular audio node graphs, and real-time AudioWorklet processors in web applications.

---

## 1. Audio Node Graph Architecture

The Web Audio API connects modular `AudioNode` instances into a directed graph routing into `AudioDestinationNode` (speakers).

```text
[ OscillatorNode (VCO) ] -----> [ BiquadFilterNode (VCF) ] -----> [ GainNode (VCA) ]
                                          ^                                |
                                          |                                v
[ AudioBufferSourceNode (Noise) ] ---------+                     [ DynamicsCompressorNode ]
                                                                           |
                                                                           v
                                                            [ AudioDestinationNode ] (Speakers)
```

---

## 2. Production Code Standards

### A. Subtractive Polyphonic Synthesizer Voice (TypeScript)

```typescript
export class SynthVoice {
  private ctx: AudioContext;
  private osc: OscillatorNode;
  private filter: BiquadFilterNode;
  private ampGain: GainNode;

  constructor(ctx: AudioContext) {
    this.ctx = ctx;

    // 1. Voltage Controlled Oscillator (VCO)
    this.osc = this.ctx.createOscillator();
    this.osc.type = "sawtooth";

    // 2. Voltage Controlled Filter (VCF)
    this.filter = this.ctx.createBiquadFilter();
    this.filter.type = "lowpass";
    this.filter.frequency.value = 800; // Cutoff
    this.filter.Q.value = 6;           // Resonance

    // 3. Voltage Controlled Amplifier (VCA)
    this.ampGain = this.ctx.createGain();
    this.ampGain.gain.setValueAtTime(0.0001, this.ctx.currentTime);

    // 4. Connect Audio Graph
    this.osc.connect(this.filter);
    this.filter.connect(this.ampGain);
  }

  public connect(destination: AudioNode): void {
    this.ampGain.connect(destination);
  }

  public triggerAttack(frequency: number, velocity: number = 0.8): void {
    const now = this.ctx.currentTime;
    this.osc.frequency.setValueAtTime(frequency, now);

    // ADSR Envelope (Attack & Decay)
    this.ampGain.gain.cancelScheduledValues(now);
    this.ampGain.gain.setValueAtTime(0.0001, now);
    this.ampGain.gain.exponentialRampToValueAtTime(velocity, now + 0.02); // 20ms Attack
    this.ampGain.gain.exponentialRampToValueAtTime(velocity * 0.7, now + 0.15); // 130ms Decay

    // Filter Envelope Sweep
    this.filter.frequency.cancelScheduledValues(now);
    this.filter.frequency.setValueAtTime(300, now);
    this.filter.frequency.exponentialRampToValueAtTime(3500, now + 0.05);
    this.filter.frequency.exponentialRampToValueAtTime(800, now + 0.3);

    this.osc.start(now);
  }

  public triggerRelease(): void {
    const now = this.ctx.currentTime;
    // Release Stage
    this.ampGain.gain.cancelScheduledValues(now);
    this.ampGain.gain.setValueAtTime(this.ampGain.gain.value, now);
    this.ampGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.3); // 300ms Release

    this.osc.stop(now + 0.35);
  }
}
```

### B. Custom DSP AudioWorklet Processor (`bitcrusher-processor.js`)

```javascript
class BitcrusherProcessor extends AudioWorkletProcessor {
  static get parameterDescriptors() {
    return [
      { name: "bitDepth", defaultValue: 8, minValue: 1, maxValue: 16 },
      { name: "reduction", defaultValue: 4, minValue: 1, maxValue: 32 },
    ];
  }

  constructor() {
    super();
    this.phase = 0;
    this.lastSample = 0;
  }

  process(inputs, outputs, parameters) {
    const input = inputs[0];
    const output = outputs[0];

    if (!input || !input[0]) return true;

    const bitDepth = parameters.bitDepth[0];
    const reduction = parameters.reduction[0];
    const step = Math.pow(0.5, bitDepth);

    for (let channel = 0; channel < input.length; ++channel) {
      const inputChannel = input[channel];
      const outputChannel = output[channel];

      for (let i = 0; i < inputChannel.length; ++i) {
        this.phase += 1;
        if (this.phase >= reduction) {
          this.phase = 0;
          // Quantize amplitude to bit depth
          this.lastSample = step * Math.floor(inputChannel[i] / step + 0.5);
        }
        outputChannel[i] = this.lastSample;
      }
    }
    return true;
  }
}

registerProcessor("bitcrusher-processor", BitcrusherProcessor);
```

---

## 3. Best Practices & User Interaction

1. **User Gesture Requirement:** Modern browsers block `AudioContext` from starting until a user gesture (click/keydown). Always resume suspended context on initial interaction:
   ```typescript
   if (audioCtx.state === "suspended") {
     await audioCtx.resume();
   }
   ```
2. **Exponential Ramps:** Always use `exponentialRampToValueAtTime` for frequency and gain to match human logarithmic perception, avoiding zero as a target (`0.0001` minimum).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…