claude-motion-sound-design
Skill9 starsChanged 24 days agoMITView on GitHub
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.
In this repository17 other files it gives its agents.
- 3d-productSkill
- anatomySkill
- claude-motion-motion-designSkill
- claude-motion-review-loopSkill
- claude-motion-web-simsSkill
- hyperframes-motion-reelSkill
- img2threejsSkill
- kinetic-reelSkill
- lemo-opuscarSkill
- lower-thirdsSkill
- motion-designerSkill
- motion-design-principlesSkill
- motion-graphics-music-videoSkill
- opus-visual-motion-engineSkill
- painted-animationSkill
- talking-head-b-rollSkill
- video-shotcraftSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 48
Add an "sfx" script in package.json pointing at the new cue sheet, or run it directly.
- Very specific: line 76
Write a function in sfx/synth.py that returns a list of floats at SR.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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 WAVWriting 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 postIn 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}>.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

