Generate sound effects and ambience for tabletop RPGs — entirely locally, on Apple Silicon. No cloud, no API keys, no per-generation cost, no rate limits.
A 2-minute stereo ambience bed takes under a second to generate. The whole 34-sound library rebuilds in ~80 seconds.
Comes with a browser soundboard: layer a storm under a tavern, then drop a fireball over the top.
git clone git@github.com:biozal/ttrpg-sfx.git
cd ttrpg-sfx
./setup.sh # ~10 min, mostly downloading weights
./generate-library.sh --web # 14 ambience beds (~65s)
./generate-spells.sh # 20 spell one-shots (~15s)
./generate-music.sh # 30 bard/tavern tunes (~1:45)
./serve.sh # → http://127.0.0.1:8777Apple Silicon only — the stack is Metal/MLX-backed. See docs/setup.md.
14 ambience beds — tavern (busy/quiet), storm (heavy/distant), crowd (market/angry), cave, dungeon, forest (night/day), battle, ship at sea, campfire, temple. 117 s each, seamlessly looping, stereo, loudness-matched.
20 spell one-shots — fireball, lightning bolt, magic missile, eldritch blast, thunderwave, fire bolt, scorching ray, chain lightning, shatter, cone of cold, ray of frost, guiding bolt, sacred flame, healing word, cure wounds, revivify, counterspell, dispel magic, shield, misty step. 3–6 s, peak-matched.
30 instrumental bard tunes — lute, harp, lyre, mandolin, piano, harpsichord, fiddle, cello, recorder, flute, hurdy-gurdy, accordion, tin whistle, and small ensembles. ~45 s, half lively/half ballad, no singing. Each ships as both a seamless loop and a clean-ending version — the soundboard's ∞/1× toggle picks.
A soundboard that layers them, with per-track volume, fade, and loop/one-shot.
All of it is a starting point — the lists are yours to edit.
One at a time:
./new-sound.sh --type ambience --name mine_deep \
--prompt "deep mine shaft, dripping water echoing, distant pickaxe strikes, low rumbling"
./new-sound.sh --type spell --name wall_of_fire \
--prompt "a wall of flame erupting from the ground, sustained roaring fire, deep whoosh"It runs the right pipeline for the type and prints the line to paste into
web/index.html.
The prompt is the whole job. Describe physical sources, spaces, and materials — never mood. The model has no idea what "ominous" sounds like, but it knows exactly what a stone hall does to a voice.
| Weak | Strong |
|---|---|
crowd noise |
busy medieval tavern, crowd talking and laughing, mugs clinking, crackling fireplace, wooden room |
fireball |
a huge explosion, roaring fireball igniting, deep booming blast and crackling flames |
Full guide: docs/prompting.md.
Two skills ship in .claude/skills/ — ask Claude in natural language and it'll
handle the pipeline and the soundboard wiring:
| Skill | For |
|---|---|
generate-ambience |
looping beds — crowd noise, weather, room tone, locations |
generate-spell-sfx |
one-shots — spells, impacts, traps, roars |
generate-music |
instrumental — tavern dances, ballads, bard tunes |
"I need ambience for a rainy moor at night" "make me a sound for when the portcullis slams shut"
| docs/setup.md | install, requirements, disk, troubleshooting |
| docs/prompting.md | how to get good sounds — the highest-leverage read |
| docs/pipeline.md | every stage and the measurement justifying it |
| docs/architecture.md | how it fits together, why these models |
| docs/soundboard.md | the web player, and how it works |
| docs/formats.md | why Opus 96k, with the numbers |
| docs/moss-apple-silicon.md | the optional second engine, and its patches |
| Script | Does |
|---|---|
setup.sh [--with-moss] |
rebuild the toolchain from scratch |
new-sound.sh --type <t> --name <n> --prompt <p> |
one sound, end to end |
generate-library.sh [--loop|--web] |
batch-build every scene in SCENES |
generate-spells.sh [--wav] |
batch-build every spell in SPELLS |
generate-music.sh [--wav] |
batch-build every tune in SONGS (loop + clean-end) |
make-loop.sh in.wav out.wav [xfade] |
one clip → seamless loop |
normalize.sh <in> <out> [LUFS] |
match loudness across a folder |
web-encode.sh <in> <out> [fmt] [rate] |
compress for the browser |
serve.sh [port] |
serve the soundboard |
moss-sfx "<prompt>" out.wav [s] [steps] |
the optional MOSS engine, on MPS |
Stable Audio 3 Small SFX
(433M params, 44.1 kHz stereo, up to 120 s) via Stability's pure-MLX backend —
Apple Metal natively, no PyTorch. The entire dependency list is mlx, numpy,
sentencepiece, huggingface_hub.
Measured on an M5 Max: 60 s of audio in 0.75 s (~80× realtime), 2.4 GB peak RAM.
Raw generations aren't table-ready, so each pipeline stage fixes a measured problem:
- Looping — ambience starts/stops arbitrarily and clicks when repeated; the tail is crossfaded over the head.
- Loudness — raw beds spanned 41 dB (−13.5 to −55). Normalizing to −20 LUFS tightened that to ~6 dB while keeping natural dynamics.
- Spells use peak normalization instead — loudness-normalizing a 6 s explosion squashes the transient that makes it land.
- Opus 96k — 883 KB vs 20 MB WAV, no encoder padding. Measured: it keeps the top end intact even at 64k.
- Web Audio, not
<audio loop>— the element gaps between repeats and would undo the crossfade work.
docs/architecture.md has the reasoning; docs/pipeline.md has the numbers.
The toolkit — scripts, docs, skills, the soundboard, the MOSS patches. A few hundred KB.
Not the ~13 GB around it: model weights, upstream clones, and generated audio.
All of it is downloadable by setup.sh or regenerable in ~80 seconds, and binary
churn in git is miserable. See .gitignore.
| This toolkit | MIT |
| Stable Audio 3 | Stability AI Community License — you own your outputs; commercial terms above $1M annual revenue |
| MOSS-SoundEffect v2 | Apache 2.0 |
Both models are trained on licensed/CC data — Stable Audio 3 on AudioSparx plus CC-0/CC-BY Freesound. For a home game you're clear; read the Stability license if you're publishing commercially at scale.
Not affiliated with Wizards of the Coast. D&D spell names are used descriptively.