← SplineCONTENT HISTORY
WHAT CHANGED
Update to Spline
Snapshot Oct 24, 2026 · 13:29 UTC · version 1.2.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Save Spline and check future changes in Following.
Up to 10 plugins free · no card required.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Procedural WebAudio sound effects for games and interactive scenes (no audio assets): the shared synth helpers, AudioContext resume-on-gesture wiring, and per-effect recipes — engine hum, weapons, footsteps, pickups, win/lose stingers. Load alongside the games skill when writing the sound code.",
"included_files": [],
"name": "spline-3d-game-audio",
"skill_md_contents": "---\nname: spline-3d-game-audio\ndescription: \"Procedural WebAudio sound effects for games and interactive scenes (no audio assets): the shared synth helpers, AudioContext resume-on-gesture wiring, and per-effect recipes — engine hum, weapons, footsteps, pickups, win/lose stingers. Load alongside the games skill when writing the sound code.\"\n---\n\n## Procedural sound effects (WebAudio — on by default)\n\nGames ship with sound unless the user says otherwise, and every sound is\nSYNTHESIZED in the document with the WebAudio API: the sandbox has no\nguaranteed network, so there are no audio assets to fetch — and none are\nneeded. Oscillators, one noise buffer and gain envelopes cover the whole\nclassic game palette for zero bytes. (The scene's own `'Audio'` actions\nneed uploaded sound assets — they are not part of a code-driven game.)\n\nPlumbing rules:\n- ONE `AudioContext`, created — or `ctx.resume()`d — INSIDE the Start\n click handler. Browsers block audio until a user gesture, which the\n start gate provides by design; never create the context at boot.\n- ONE master gain (~0.2) between everything and `ctx.destination` — SFX\n stack fast and headroom prevents clipping. A HUD mute toggle is just\n flipping `master.gain.value`.\n- One-shots build fresh nodes per trigger: oscillator or noise source →\n gain envelope → master. Envelope = `gain.setValueAtTime(vol, t)` then\n `gain.exponentialRampToValueAtTime(0.001, t + dur)` (never ramp to\n exactly 0), and `stop(t + dur)` so the nodes free themselves.\n- Continuous sources (engine, wind) are created ONCE at init, run forever\n through their own gain starting at 0, and the game loop writes their\n frequency/gain every frame — this is all inside the iframe, no bridge\n traffic. Duck them to 0 in `setState` for any state that isn't\n `'playing'` (the loop early-returns there and won't do it for you).\n- Pitch sweeps (lasers, jumps, slides) are one more line on a one-shot:\n `o.frequency.exponentialRampToValueAtTime(target, t + dur)`.\n\nThe worked example carries `audioInit` + a `blip` oscillator one-shot;\nadd this filtered-noise `thud` (sharing one noise buffer) when the game\nneeds steps, hits or shots:\n\n```\nlet noise;\nfunction thud(dur = 0.08, cutoff = 600, vol = 0.35) {\n if (!noise) {\n noise = ctx.createBuffer(1, ctx.sampleRate, ctx.sampleRate);\n const d = noise.getChannelData(0);\n for (let i = 0; i < d.length; i++) d[i] = Math.random() * 2 - 1;\n }\n const t = ctx.currentTime;\n const src = ctx.createBufferSource();\n src.buffer = noise;\n const f = ctx.createBiquadFilter();\n f.type = 'lowpass';\n f.frequency.value = cutoff;\n const g = ctx.createGain();\n g.gain.setValueAtTime(vol, t);\n g.gain.exponentialRampToValueAtTime(0.001, t + dur);\n src.connect(f).connect(g).connect(master);\n src.start(t);\n src.stop(t + dur);\n}\n```\n\nThe palette:\n- **Car engine**: looping sawtooth → lowpass → gain (the example). Map\n frequency 40–180 Hz and filter cutoff 300–1200 Hz from `|speed| / TOP`\n each frame — the pitch rise IS the acceleration feel. Two slightly\n detuned oscillators into the same filter sound richer.\n- **Footsteps** (walking/running): `thud(0.05, 600, 0.25)` on a cadence\n timer while moving and grounded — every ~0.34s walking, ~0.22s running.\n- **Jump**: a blip with a rising sweep (150→600 Hz over ~0.18s);\n **landing**: a deeper `thud(0.1, 300, 0.5)`.\n- **Weapons**: laser = square blip swept DOWN (900→120 Hz, ~0.12s);\n gunshot = a loud 60ms noise burst (highpass ~1000 Hz instead of the\n lowpass) + a 150 Hz sine thump; explosion = a 0.4–0.6s noise burst with\n the lowpass cutoff sweeping 3000→100 Hz.\n- **Pickup/coin**: two ascending square blips (880 then 1320 Hz, ~70ms\n apart — the example). **Win**: a little arpeggio (523/659/784 Hz\n triangle notes, ~120ms apart); **lose/hit**: one descending saw sweep\n (400→80 Hz, ~0.3s).\n"
}SHA-256 of public snapshot: a18cde65ac0ac2696a2799622f84c449503632a504296e24f9cbefeeab85d412