{
  "slug": "web-audio-sfx-synth",
  "skill": "web-audio-sfx-synth",
  "upstream": "GameSkill original (onsite/<slug>/original)",
  "sourceHash": "3421362439cc0faaccf6ef9bf7f75f84b6998ab7a7f83c76d5cb0e430f9d8fd5",
  "date": "2026-10-28",
  "engine": "Web Audio API in Chrome 156 headless (OfflineAudioContext + AudioContext)",
  "env": [
    "Node v20.19.2",
    "No runtime dependencies (one ES module)",
    "puppeteer-core 24 from package-lock.json",
    "Google Chrome 156 headless"
  ],
  "trigger": "static",
  "passed": 46,
  "total": 46,
  "commands": [
    "(cd ../original && sh -c npm ci --silent --no-audit --no-fund && node --test --test-reporter=tap test/logic.test.mjs)",
    "(cd ../original && node test/browser.test.mjs)",
    "(cd . && cp ../original/shots/soundboard.png screenshot.png)"
  ],
  "checks": [
    {
      "criterion": "trigger",
      "name": "SKILL.md description says when to use it",
      "pass": true,
      "detail": "Make game sound effects in the browser from code with the Web Audio API, with no audio files: 12 ready recipes (shoot, l"
    },
    {
      "criterion": "trigger",
      "name": "triggers on: \"Add sound effects to my HTML5 web game without audio files using Web Audio\"",
      "pass": true,
      "detail": "rank 1/118, overlap 7"
    },
    {
      "criterion": "trigger",
      "name": "triggers on: \"Why is there no sound in my browser game until I click, and how do I synthesise SFX\"",
      "pass": true,
      "detail": "rank 1/118, overlap 7"
    },
    {
      "criterion": "trigger",
      "name": "triggers on: \"Procedural jsfxr style game sound effects in the browser with an oscillator and noise\"",
      "pass": true,
      "detail": "rank 1/118, overlap 8"
    },
    {
      "criterion": "trigger",
      "name": "does not trigger on: \"Make my Godot platformer jump feel better\"",
      "pass": true,
      "detail": "rank 9/118, overlap 1"
    },
    {
      "criterion": "trigger",
      "name": "does not trigger on: \"Write a launch checklist for release day\"",
      "pass": true,
      "detail": "rank 13/118, overlap 0"
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): all 12 recipes are valid",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): validator catches broken recipes",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): envelope: 0 at both ends, peak 1 after the attack, falls monotonically",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): semitones and decibels",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): variation stays within ±60 cents and ±1.5 dB, never above gain 1, and is seeded",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): pan: centre at the listener, clamped to ±1",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): distance gain: 1 inside ref, falls, 0 at max",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): limiter: minimum gap between starts of the same sound",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): limiter: steals the oldest copy when a sound is at its cap",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): limiter: finished voices free their slot; global cap holds",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): thunder plays at most once at a time",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): recipe durations are short enough for SFX (ambience aside)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "recipe and mixer tests (validator, envelope, variation, pan, distance, voice limiter): exits 0 with no script errors",
      "pass": true,
      "detail": "exit 0"
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: all 12 recipes render offline (OfflineAudioContext)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: shoot: audible, no clipping, no NaN, ends in silence (peak 0.49, rms 0.049)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: laser: audible, no clipping, no NaN, ends in silence (peak 0.17, rms 0.020)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: explosion: audible, no clipping, no NaN, ends in silence (peak 0.87, rms 0.071)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: hit: audible, no clipping, no NaN, ends in silence (peak 0.38, rms 0.037)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: jump: audible, no clipping, no NaN, ends in silence (peak 0.22, rms 0.035)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: pickup: audible, no clipping, no NaN, ends in silence (peak 0.23, rms 0.033)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: coin: audible, no clipping, no NaN, ends in silence (peak 0.19, rms 0.030)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: powerup: audible, no clipping, no NaN, ends in silence (peak 0.14, rms 0.017)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: uiClick: audible, no clipping, no NaN, ends in silence (peak 0.21, rms 0.026)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: uiConfirm: audible, no clipping, no NaN, ends in silence (peak 0.21, rms 0.034)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: footstep: audible, no clipping, no NaN, ends in silence (peak 0.11, rms 0.011)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: thunder: audible, no clipping, no NaN, ends in silence (peak 0.42, rms 0.025)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: AudioContext stays off until the first user gesture",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: a click unlocks audio and plays (context running)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: limiter: 10 fast footsteps are thinned out (8 of 10 skipped)",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: spatial: a shot on the left is panned left, on the right panned right",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: mute toggles without errors",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: screenshot written",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: no console errors, page errors or failed requests",
      "pass": true
    },
    {
      "criterion": "runs",
      "name": "soundboard in headless Chrome: exits 0 with no script errors",
      "pass": true,
      "detail": "exit 0"
    },
    {
      "criterion": "output",
      "name": "screenshot screenshot.png rendered",
      "pass": true
    },
    {
      "criterion": "output",
      "name": "self-check list has at least 3 items",
      "pass": true,
      "detail": "6 items"
    },
    {
      "criterion": "single",
      "name": "one job per skill (reviewed)",
      "pass": true,
      "detail": "One job: short game sound effects synthesised in the browser with Web Audio (recipes, master bus, unlock, variation, pan/distance, voice limits). Music, adaptive mixing and engine audio buses are left to audio-design and the engine skills."
    },
    {
      "criterion": "bilingual",
      "name": "English SKILL.md",
      "pass": true
    },
    {
      "criterion": "bilingual",
      "name": "Chinese SKILL.zh.md shipped next to SKILL.md",
      "pass": true,
      "detail": "2887 chars"
    },
    {
      "criterion": "bilingual",
      "name": "Chinese guide written",
      "pass": true,
      "detail": "1098 chars"
    }
  ]
}
