sound-design
Procedural sound design with the sfx engine — writing a cue sheet against a video's timeline, which sound goes with which visual event, gain hierarchy, panning, musical key, automatic mastering to -14 LUFS, adding new generators, and verifying sync. Use when adding, changing or checking audio, SFX, music beds or loudness for any video in this repo.
How do I install this agent skill?
npx skills add https://github.com/whaleyxbt/claude-motion --skill sound-designIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill provides a framework and instructions for procedural sound design using a local Python-based synthesis engine. It outlines workflows for creating audio cues, mastering loudness, and synchronizing sound with video timelines. No malicious behaviors, data exfiltration patterns, or obfuscation were detected.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Sound design
Most AI-made motion graphics are silent. Sound is what makes a piece feel produced.
The sfx/ engine synthesizes every sound in pure Python stdlib: no samples, no licenses, no installs, same output on every run. It reads the same timeline JSON as the picture, so sound can't drift out of sync.
How it fits together
| File | Role |
|---|---|
sfx/synth.py | generators: each returns mono samples at 48 kHz |
sfx/mix.py | Mix: place sounds in time, master to a loudness target, write WAV |
sfx/loudness.py | BS.1770 integrated loudness (matches ffmpeg's ebur128) |
sfx/cues/<video>.py | a cue sheet: one video's sound design |
python3 -m sfx --list # generators with what each is for
python3 -m sfx sfx/cues/<video>.py # render → mastered WAV
Writing a cue sheet for a new video
Create sfx/cues/<video>.py:
from sfx.synth import click, pop, whoosh, chime, riser, impact
TIMELINE = "timeline.json" # the same file the composition reads
OUT = "public/sfx.wav"
TARGET_LUFS = -14.0 # optional, this is the default
def score(mix, tl):
s1 = tl["s1"]
mix.put(s1["title"], whoosh(0.4, 500, 2400, peak=0.45), 0.12)
for i, t in enumerate(s1["items"]):
mix.put(t, pop(900 + i * 150, 400), 0.3, pan=-0.4 + i * 0.3)
mix.put(t, samples, gain, pan):talways comes fromtl, never a typed number. Offsets from a beat (s1["exit"] + 0.05) are fine.mix.typing(start, end, chars): one humanized keystroke per character.mix.put_stereo(t, left, right, gain): for stereo sources likepad().- Mastering is automatic: the engine soft-clips and sets gain to hit
TARGET_LUFS, raising drive only as far as needed to keep the true peak ≤ −2 dBFS (room for AAC overshoot, so the MP4 stays under −1 dBTP). A mix that's mostly short hits with silence between can't reach −14 without crushing; the engine then comes out quieter and says so. Fix it with sustained sound (a pad, longer tails), not by forcing it. - Add an
"sfx"script inpackage.jsonpointing at the new cue sheet, or run it directly.
sfx/cues/effort.py is a complete, real example: 128 sounds plus a pad bed.
Visual event → sound
| On screen | Generator | Notes |
|---|---|---|
| Typing | mix.typing() | jitter ±4–6 ms, random gain |
| Word / line reveal | whoosh() + blip() on the landing | short, airy |
| Badge, chip, callout pops in | pop() | raise pitch across a sequence |
| Control snaps to a step | click() + blip() in key | |
| Sketch / draw-on | scratch() | |
| Build-up | riser() | end exactly on the hit; one big riser per video |
| Success / arrival | chime() | chord in key |
| Hero transition | whoosh() in, impact() on the hit | one impact per video |
| Under everything | pad() with an envelope() | duck it under the hero transition |
Accent, don't narrate: not every motion needs a sound. Continuous motion (drift, grain, rotation) stays silent.
Levels and space
- Hero hits: gain 0.25–0.35. Supporting sounds: 0.08–0.2. Pad: ~0.03, ducked ~65% under the hero transition.
- Pan follows on-screen position (−1 left … +1 right). Sequences sweep across the stereo field.
- Pick one key and keep every tonal sound in it; pitch rises with progress and resolves on the payoff. (In the effort example the pad and slider notes are D major, but the scene 3 pops and chime are still in C major. Don't copy that.)
Adding a generator
Write a function in sfx/synth.py that returns a list of floats at SR. Put what it's for in the first docstring line; --list shows it. Use the module-level random for noise so renders stay reproducible. Build on bandnoise() for anything airy.
Verify
npm run sfx # or python3 -m sfx sfx/cues/<video>.py
npm run wave # out/wave.png + loudness of the WAV
npm run build
node scripts/wave.mjs out/effort.mp4 # loudness of what you'll actually post
In out/wave.png every coral line is a timeline beat. Each transient should sit on a line or a hair after it. A hit between lines means a hardcoded time or a stale WAV. Pass --timeline for a video with its own timeline file.
Optional: generated audio
For voiceover or sounds you can't synthesize, the ElevenLabs MCP (see .mcp.json.example) can generate files into public/. Place them with <Audio src={staticFile(...)} /> inside a <Sequence from={beat * FPS}>.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/whaleyxbt/claude-motion/sound-design">View sound-design on skillZs</a>