[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M751TK4M41CRXSNMTMCCBXTK":3,"skill-same:01M751TK4M41CRXSNMTMCCBXTK":49},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":26,"commitSha":27,"skillDirectory":28,"forksCount":29,"repositoryHtmlUrl":30,"repositoryHomepageUrl":31,"ownerHtmlUrl":32,"ownerBlogUrl":31,"ownerDescription":33,"updatedAt":34,"install":35,"resources":48},"01M751TK4M41CRXSNMTMCCBXTK","sound-and-music-sync",null,"Score a video like an editor: beat-match cuts to the music, land SFX on transitions, pace the voiceover so it breathes, source royalty-free tracks safely, and duck the music so the VO sits clearly on top. Use when adding music, sound effects, or voiceover to a video, when asked to \"sync cuts to the beat\", \"the music is drowning out the voice\", \"add whooshes on the transitions\", \"where do I get royalty-free music\", \"mix the audio\", or \"the VO feels rushed\". Do NOT use when wiring audio into the Remotion timeline mechanically (Audio\u002FstaticFile\u002Frender) - that is remotion-compose and remotion-render; do NOT use when choosing the shot order or scene beats - use video-storyboard instead; do NOT use when tuning the visual look (color grade, lighting, contrast) - use motion-color-and-light instead.","SkillMedev\u002Fskills","SkillMedev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F298078254?v=4","01M74ZSGTQ918CB0VXW4EG3RMX","SkillMe","01M74ZSGVBT497NA95CBT8JTY4",25,"MIT","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fsound-and-music-sync\u002FSKILL.md",[],[],"2026-11-11 18:22:23",false,"---\nname: sound-and-music-sync\ndescription: \"Score a video like an editor: beat-match cuts to the music, land SFX on transitions, pace the voiceover so it breathes, source royalty-free tracks safely, and duck the music so the VO sits clearly on top. Use when adding music, sound effects, or voiceover to a video, when asked to \\\"sync cuts to the beat\\\", \\\"the music is drowning out the voice\\\", \\\"add whooshes on the transitions\\\", \\\"where do I get royalty-free music\\\", \\\"mix the audio\\\", or \\\"the VO feels rushed\\\". Do NOT use when wiring audio into the Remotion timeline mechanically (Audio\u002FstaticFile\u002Frender) - that is remotion-compose and remotion-render; do NOT use when choosing the shot order or scene beats - use video-storyboard instead; do NOT use when tuning the visual look (color grade, lighting, contrast) - use motion-color-and-light instead.\"\nmetadata:\n  title: \"Sound and Music Sync\"\n---\n\n# Sound and Music Sync\n\nSound is half the video and the half people forget. A mediocre animation cut to the\nbeat with a clean voiceover reads as professional; a beautiful animation with cuts\nthat float and a VO buried under the music reads as amateur. This is the audio\ntaste layer. You decide where cuts land, where sound effects punctuate, how the\nvoiceover breathes, and how the mix sits - then you hand the concrete numbers\n(beat frames, SFX timestamps, duck levels) to **remotion-compose** to wire onto the\ntimeline and **remotion-render** to export. You do not write the `\u003CAudio>` JSX or\nrun the renderer; you make the creative decisions that feed them.\n\nThis pairs with the rest of the motion-video-direction pack: a **video-storyboard**\nscene list and **motion-design-principles** timing decisions are your input - you\nscore against beats that already exist. If text is animating to the audio, sync it\nwith **kinetic-typography**; if the cut rhythm is carrying a product walkthrough,\ncoordinate with **product-demo-director**; if you are cutting a vertical\u002Fsocial\nversion, re-derive beats per platform with **social-video-formatter**. The audio\nmix is its own layer - leave the visual look (color grade, lighting, contrast) to\n**motion-color-and-light** and score against whatever it grades.\n\n## Workflow\n\nRun these in order. Do not start placing SFX before the cuts are beat-locked, and\ndo not finalize the mix before the VO timing is right - each step depends on the\none before.\n\n1. **Pick the track and lock the tempo.** Choose music that matches the video's\n   energy and length, confirm its license (see references\u002Froyalty-free-sourcing),\n   and get its BPM. Most royalty-free libraries list BPM; if not, tap it out or use\n   a detector. BPM is the spine of everything downstream - one beat lasts\n   `60 \u002F BPM` seconds, and at the project fps that is `fps * 60 \u002F BPM` frames.\n\n2. **Build the beat grid and snap cuts to it.** Convert beats to frame numbers and\n   place every hard cut and major scene change on a beat (run `beat_grid.js`\n   below). Cut on the downbeat - beats 1, 5, 9 in 4\u002F4 - for emphasis; cut on any\n   beat for routine transitions. A cut that lands two or three frames off the beat\n   reads as \"wrong\" even to viewers who cannot name why. Hand the snapped frame\n   list to remotion-compose as the `\u003CSequence from={...}>` boundaries.\n\n3. **Place sound effects on transitions, not over them.** SFX exist to make motion\n   feel physical. The rule: the sound peaks the instant the motion peaks. A whoosh\n   *leads into* a swipe (start it ~3-5 frames before the cut so its tail lands on\n   the cut); an impact\u002Fthud lands *on* the frame a card slams in; a click\u002Fpop lands\n   on the frame a UI element appears; a riser builds *across* the 10-20 frames\n   before a reveal and resolves on it. One SFX per transition - stacking them turns\n   punctuation into noise. See references\u002Fsfx-placement.\n\n4. **Pace the voiceover so it breathes.** VO sets the real pace of the video; the\n   visuals serve it, not the reverse. Target a conversational ~150 words per\n   minute (≈2.5 words\u002Fsecond) - faster reads as rushed, slower as a hostage video.\n   Leave a beat of silence (8-15 frames) before a key line and after the CTA. Write\n   for the ear: short sentences, one idea each, contractions. Never let a scene cut\n   mid-word - align scene boundaries to the gaps *between* sentences. Time the VO\n   first, then stretch or compress scene durations to fit it (this becomes the\n   `durationInFrames` remotion-compose uses).\n\n5. **Mix: duck the music so the VO sits on top.** This is the single most common\n   audio failure. Music and full-volume VO compete in the same frequency range and\n   the words get lost. Duck the music to roughly 25-35% of its level *whenever the\n   VO is speaking*, then bring it back up in the gaps. Run `mix_levels.js` for\n   concrete level and timing numbers. Target the VO around -3 to -6 dB (clear,\n   never clipping), ducked music around -18 to -22 dB. Hand the duck envelope\n   (which frames to duck, the floor level) to remotion-compose, which applies it via\n   per-`\u003CAudio>` `volume` callbacks.\n\n6. **Spot-check the export.** After remotion-render produces the MP4, listen on\n   laptop speakers and on phone speakers, not just good headphones - most viewers\n   are on bad speakers. Confirm: every word of VO is intelligible over the music,\n   no SFX clips or startles, cuts feel locked to the beat, and the loudest moment\n   does not distort. If a word is lost, duck deeper in that span; if SFX startle,\n   pull them down 6 dB.\n\n## Quality bar\n\nThe audio is A+ only when all of these hold:\n\n- Every hard cut lands on a beat frame from the grid - none float between beats.\n- Every transition SFX peaks on the exact frame its motion peaks; risers resolve on\n  the reveal, not before or after.\n- VO runs ~140-160 wpm with deliberate silence before key lines and after the CTA;\n  no scene cuts mid-word.\n- The VO is fully intelligible over the music on phone speakers - verified, not\n  assumed - because the music ducks to ~30% under speech.\n- Exactly one SFX per transition; the track loops or ends cleanly with no abrupt\n  cutoff on the final frame.\n- Every audio asset's license permits the intended use (commercial \u002F paid ads \u002F\n  client work) and attribution requirements are recorded.\n\n## Do NOT\n\n- Do not leave cuts floating off-beat to preserve a scene's \"natural\" length -\n  stretch or trim the scene to the nearest beat instead.\n- Do not run music at full level under the voiceover; un-ducked music is why VO\n  sounds muddy. Duck it every time someone speaks.\n- Do not stack multiple SFX on one transition, or reuse the same whoosh on every\n  cut - vary them or the ear stops hearing them.\n- Do not write the `\u003CAudio>` JSX, set `startFrom`\u002F`volume` callbacks, or invoke the\n  renderer here - produce the numbers and hand them to remotion-compose \u002F\n  remotion-render.\n- Do not pull tracks from YouTube rips, \"free\" sites with no stated license, or a\n  client's Spotify - commercial use needs a real royalty-free or licensed source.\n- Do not normalize the whole mix to be as loud as possible; leave headroom so the\n  loudest impact does not clip.\n- Do not let the VO race to fit a fixed runtime - re-cut the visuals to the VO, not\n  the VO to the visuals.\n\n## Calculator: beat grid\n\nSelf-contained Node script. Save as `beat_grid.js` and run with `node beat_grid.js`.\nIt turns a BPM and an fps into the exact frame numbers your cuts should land on, and\nflags downbeats. No dependencies. Hand the printed frames to remotion-compose as\n`\u003CSequence from={...}>` boundaries.\n\n```javascript\n\u002F\u002F Beat grid. Edit inputs, then: node beat_grid.js\nconst input = {\n  bpm: 120,            \u002F\u002F tempo of the chosen track\n  fps: 30,             \u002F\u002F project frame rate\n  durationSeconds: 12, \u002F\u002F length of the video\n  beatsPerBar: 4,      \u002F\u002F 4\u002F4 time; downbeat is every 4th beat\n}\n\nconst framesPerBeat = (input.fps * 60) \u002F input.bpm\nconst totalFrames = Math.round(input.durationSeconds * input.fps)\nconst beats = []\nfor (let b = 0; ; b++) {\n  const frame = Math.round(b * framesPerBeat)\n  if (frame > totalFrames) break\n  beats.push({ beat: b + 1, frame, downbeat: b % input.beatsPerBar === 0 })\n}\n\nconsole.log('Frames per beat:', framesPerBeat.toFixed(2), '(' + (60 \u002F input.bpm).toFixed(3) + 's each)')\nconsole.log('Cut on these frames (* = downbeat, best for hard cuts):')\nfor (const b of beats) {\n  console.log('  beat ' + String(b.beat).padStart(2), '-> frame', String(b.frame).padStart(4), b.downbeat ? '*' : '')\n}\nconsole.log('Downbeat frames only:', beats.filter((b) => b.downbeat).map((b) => b.frame).join(', '))\n```\n\n### Worked example output\n\nWith the inputs above the script prints:\n\n```\nFrames per beat: 15.00 (0.500s each)\nCut on these frames (* = downbeat, best for hard cuts):\n  beat  1 -> frame    0 *\n  beat  2 -> frame   15 \n  beat  3 -> frame   30 \n  beat  4 -> frame   45 \n  beat  5 -> frame   60 *\n  beat  6 -> frame   75 \n  beat  7 -> frame   90 \n  beat  8 -> frame  105 \n  beat  9 -> frame  120 *\n  ...\nDownbeat frames only: 0, 60, 120, 180, 240, 300, 360\n```\n\nRead it: at 120 BPM and 30 fps a beat is exactly 15 frames. Put routine transitions\non any listed frame and your hardest cuts - the intro-to-content cut, the CTA reveal -\non a downbeat (0, 60, 120…). If a scene wants to run 70 frames, snap it to 75\n(beat 6) rather than letting the cut float at 70. Those snapped numbers are exactly\nwhat remotion-compose drops into `\u003CSequence from={...}>`.\n\n## Calculator: mix levels and duck timing\n\nSelf-contained Node script. Save as `mix_levels.js` and run with `node mix_levels.js`.\nIt computes the ducked music level and the per-VO-line frame spans to duck, so you\nhand remotion-compose a concrete envelope instead of a vibe. No dependencies.\n\n```javascript\n\u002F\u002F Mix and ducking planner. Edit inputs, then: node mix_levels.js\nconst input = {\n  fps: 30,\n  musicVolume: 0.8,       \u002F\u002F music level when no one is speaking (0-1)\n  duckToPercent: 0.30,    \u002F\u002F duck music to this share of its level under VO\n  voVolume: 1.0,          \u002F\u002F voiceover level (keep VO the loudest element)\n  duckFadeFrames: 8,      \u002F\u002F ramp in\u002Fout so the duck is not a hard jump\n  \u002F\u002F VO lines as [startSeconds, endSeconds]; duck music across each, with fade pad\n  voLines: [\n    [0.5, 3.2],\n    [4.0, 7.5],\n    [8.2, 11.0],\n  ],\n}\n\nconst duckedLevel = +(input.musicVolume * input.duckToPercent).toFixed(3)\nconst toFrame = (s) => Math.round(s * input.fps)\n\u002F\u002F rough dB for reference: 20*log10(level)\nconst dB = (v) => (v \u003C= 0 ? '-inf' : (20 * Math.log10(v)).toFixed(1) + ' dB')\n\nconsole.log('VO level:           ', input.voVolume, '(' + dB(input.voVolume) + ')  \u003C- loudest element')\nconsole.log('Music (no speech):  ', input.musicVolume, '(' + dB(input.musicVolume) + ')')\nconsole.log('Music ducked under VO:', duckedLevel, '(' + dB(duckedLevel) + ')')\nconsole.log('Duck fade:          ', input.duckFadeFrames, 'frames in\u002Fout')\nconsole.log('Duck music across these frame spans (pad ' + input.duckFadeFrames + 'f each side for the fade):')\nfor (const [start, end] of input.voLines) {\n  const a = toFrame(start) - input.duckFadeFrames\n  const b = toFrame(end) + input.duckFadeFrames\n  console.log('  VO ' + start + 's-' + end + 's  -> duck frames', Math.max(0, a), 'to', b)\n}\n```\n\n### Worked example output\n\n```\nVO level:            1 (0.0 dB)  \u003C- loudest element\nMusic (no speech):   0.8 (-1.9 dB)\nMusic ducked under VO: 0.24 (-12.4 dB)\nDuck fade:           8 frames in\u002Fout\nDuck music across these frame spans (pad 8f each side for the fade):\n  VO 0.5s-3.2s  -> duck frames 7 to 104\n  VO 4s-7.5s    -> duck frames 112 to 233\n  VO 8.2s-11s   -> duck frames 238 to 338\n```\n\nRead it: the VO stays at full level (the loudest thing in the mix), music rides at\n0.8 in the gaps and ducks to 0.24 - about a third - wherever someone speaks, fading\nover 8 frames so the dip is not a jarring jump. The frame spans are exactly the\nranges remotion-compose feeds to the music `\u003CAudio>` `volume` callback: full level\noutside the spans, `duckedLevel` inside, linear-ramped across the fade pad. That is\nwhy the words stay clear without the music vanishing.\n\n## Template: audio cue sheet\n\nCopy this, fill the FILL fields with your beat-grid and mix-level outputs, and hand\nthe completed sheet to remotion-compose. It is the single source of truth for every\naudio decision in the video.\n\n```\nAUDIO CUE SHEET. [FILL: video name]. fps [FILL] \u002F [FILL] BPM \u002F [FILL]s total\n\nMUSIC\n  Track:                 [FILL: title + source]\n  License:               [FILL: e.g. Epidemic Sound commercial \u002F CC0] - attribution: [FILL: yes\u002Fno, text]\n  Level (no speech):     [FILL: 0-1]    Ducked under VO: [FILL: 0-1] (~30%)\n\nBEAT GRID (from beat_grid.js) - cuts land here\n  Downbeat frames:       [FILL: 0, 60, 120, ...]\n  Hard cuts on:          [FILL: which downbeats carry the big cuts]\n\nSFX (one per transition; peak ON the motion peak)\n  FRAME    SFX            ROLE\n  [FILL]   [FILL whoosh]  leads into swipe (start ~4f early, tail on cut)\n  [FILL]   [FILL impact]  card slam-in, lands ON cut frame\n  [FILL]   [FILL riser]   builds across 10-20f, resolves on reveal\n  [FILL]   [FILL pop]     UI element appears\n\nVOICEOVER (~150 wpm; scenes fit the VO, not the reverse)\n  LINE                                   START   END    SCENE\n  [FILL line]                            [FILL]  [FILL] [FILL]\n  (silence 8-15f before key line \u002F after CTA)\n\nDUCK ENVELOPE (from mix_levels.js) - frame spans to lower music\n  [FILL: 7-104, 112-233, ...]  fade [FILL]f in\u002Fout\n\nHANDOFF: remotion-compose wires \u003CAudio> + volume callbacks; remotion-render exports.\n```\n\n## references\u002Froyalty-free-sourcing\n\nCommercial video needs music you are actually licensed to use - \"I found it on\nYouTube\" is not a license and a client's Spotify is not either. Licensed\u002Froyalty-free\nsources, by use case:\n\n- **Subscription libraries (safest for client\u002Fcommercial\u002Fads):** Epidemic Sound,\n  Artlist, Musicbed, Soundstripe. Flat fee, broad commercial license, large SFX\n  libraries, no per-video attribution. The default for paid work.\n- **Free with terms (check each track):** YouTube Audio Library (free, some tracks\n  need attribution), Pixabay Music and Mixkit (free, commercial OK, no attribution),\n  Free Music Archive and ccMixter (Creative Commons - read the specific CC license,\n  some forbid commercial use or require attribution).\n- **SFX specifically:** Pixabay and Mixkit (free), Epidemic\u002FArtlist (bundled with\n  subscription), freesound.org (Creative Commons - verify each clip's license).\n\nLicense hygiene, always: confirm the license covers your exact use (personal vs.\ncommercial vs. *paid advertising*, which is often a separate tier); record any\nrequired attribution text in the cue sheet; keep proof of license\u002Fdownload. CC0 and\npublic-domain are the only \"use freely anywhere\" cases - everything else has terms.\nWhen in doubt, a paid subscription library is cheaper than a takedown or a claim.\n\n## references\u002Fsfx-placement\n\nSFX make motion physical; placement is everything. The peak of the sound must hit\nthe peak of the motion, or the brain registers a mismatch.\n\n- **Whoosh \u002F swipe** - directional motion (a slide, a swipe transition). Start it\n  ~3-5 frames *before* the cut so its energy *leads into* the motion and the tail\n  resolves on the cut. A whoosh placed after the motion sounds like an echo.\n- **Impact \u002F thud** - something arriving with weight (a card slamming in, a heavy\n  title drop). Land the transient on the exact frame the object stops. Pair with a\n  tiny scale-overshoot in the motion so sound and picture punch together.\n- **Click \u002F pop \u002F tick** - small discrete UI events (a button, a checkmark, a tab).\n  Land on the frame the element appears. Keep them quiet; they punctuate, they do\n  not announce.\n- **Riser \u002F swell** - building to a reveal (the logo, the CTA, the \"after\" state).\n  Build across the 10-20 frames *before* the reveal and resolve its peak on the\n  reveal frame. A riser that peaks early deflates the moment.\n- **Ambience \u002F drone** - a continuous bed under a scene for mood. Low level, sits\n  under everything, no transient - different job from the punctuation SFX above.\n\nDiscipline: one SFX per transition. Vary the whooshes across cuts (pitch or sample)\nso the ear keeps noticing them. Mix SFX a touch under the VO and above the ducked\nmusic - they punctuate, they never compete with the words.\n","# Sound and Music Sync\n\nSound is half the video and the half people forget. A mediocre animation cut to the\nbeat with a clean voiceover reads as professional; a beautiful animation with cuts\nthat float and a VO buried under the music reads as amateur. This is the audio\ntaste layer. You decide where cuts land, where sound effects punctuate, how the\nvoiceover breathes, and how the mix sits - then you hand the concrete numbers\n(beat frames, SFX timestamps, duck levels) to **remotion-compose** to wire onto the\ntimeline and **remotion-render** to export. You do not write the `\u003CAudio>` JSX or\nrun the renderer; you make the creative decisions that feed them.\n\nThis pairs with the rest of the motion-video-direction pack: a **video-storyboard**\nscene list and **motion-design-principles** timing decisions are your input - you\nscore against beats that already exist. If text is animating to the audio, sync it\nwith **kinetic-typography**; if the cut rhythm is carrying a product walkthrough,\ncoordinate with **product-demo-director**; if you are cutting a vertical\u002Fsocial\nversion, re-derive beats per platform with **social-video-formatter**. The audio\nmix is its own layer - leave the visual look (color grade, lighting, contrast) to\n**motion-color-and-light** and score against whatever it grades.\n\n## Workflow\n\nRun these in order. Do not start placing SFX before the cuts are beat-locked, and\ndo not finalize the mix before the VO timing is right - each step depends on the\none before.\n\n1. **Pick the track and lock the tempo.** Choose music that matches the video's\n   energy and length, confirm its license (see references\u002Froyalty-free-sourcing),\n   and get its BPM. Most royalty-free libraries list BPM; if not, tap it out or use\n   a detector. BPM is the spine of everything downstream - one beat lasts\n   `60 \u002F BPM` seconds, and at the project fps that is `fps * 60 \u002F BPM` frames.\n\n2. **Build the beat grid and snap cuts to it.** Convert beats to frame numbers and\n   place every hard cut and major scene change on a beat (run `beat_grid.js`\n   below). Cut on the downbeat - beats 1, 5, 9 in 4\u002F4 - for emphasis; cut on any\n   beat for routine transitions. A cut that lands two or three frames off the beat\n   reads as \"wrong\" even to viewers who cannot name why. Hand the snapped frame\n   list to remotion-compose as the `\u003CSequence from={...}>` boundaries.\n\n3. **Place sound effects on transitions, not over them.** SFX exist to make motion\n   feel physical. The rule: the sound peaks the instant the motion peaks. A whoosh\n   *leads into* a swipe (start it ~3-5 frames before the cut so its tail lands on\n   the cut); an impact\u002Fthud lands *on* the frame a card slams in; a click\u002Fpop lands\n   on the frame a UI element appears; a riser builds *across* the 10-20 frames\n   before a reveal and resolves on it. One SFX per transition - stacking them turns\n   punctuation into noise. See references\u002Fsfx-placement.\n\n4. **Pace the voiceover so it breathes.** VO sets the real pace of the video; the\n   visuals serve it, not the reverse. Target a conversational ~150 words per\n   minute (≈2.5 words\u002Fsecond) - faster reads as rushed, slower as a hostage video.\n   Leave a beat of silence (8-15 frames) before a key line and after the CTA. Write\n   for the ear: short sentences, one idea each, contractions. Never let a scene cut\n   mid-word - align scene boundaries to the gaps *between* sentences. Time the VO\n   first, then stretch or compress scene durations to fit it (this becomes the\n   `durationInFrames` remotion-compose uses).\n\n5. **Mix: duck the music so the VO sits on top.** This is the single most common\n   audio failure. Music and full-volume VO compete in the same frequency range and\n   the words get lost. Duck the music to roughly 25-35% of its level *whenever the\n   VO is speaking*, then bring it back up in the gaps. Run `mix_levels.js` for\n   concrete level and timing numbers. Target the VO around -3 to -6 dB (clear,\n   never clipping), ducked music around -18 to -22 dB. Hand the duck envelope\n   (which frames to duck, the floor level) to remotion-compose, which applies it via\n   per-`\u003CAudio>` `volume` callbacks.\n\n6. **Spot-check the export.** After remotion-render produces the MP4, listen on\n   laptop speakers and on phone speakers, not just good headphones - most viewers\n   are on bad speakers. Confirm: every word of VO is intelligible over the music,\n   no SFX clips or startles, cuts feel locked to the beat, and the loudest moment\n   does not distort. If a word is lost, duck deeper in that span; if SFX startle,\n   pull them down 6 dB.\n\n## Quality bar\n\nThe audio is A+ only when all of these hold:\n\n- Every hard cut lands on a beat frame from the grid - none float between beats.\n- Every transition SFX peaks on the exact frame its motion peaks; risers resolve on\n  the reveal, not before or after.\n- VO runs ~140-160 wpm with deliberate silence before key lines and after the CTA;\n  no scene cuts mid-word.\n- The VO is fully intelligible over the music on phone speakers - verified, not\n  assumed - because the music ducks to ~30% under speech.\n- Exactly one SFX per transition; the track loops or ends cleanly with no abrupt\n  cutoff on the final frame.\n- Every audio asset's license permits the intended use (commercial \u002F paid ads \u002F\n  client work) and attribution requirements are recorded.\n\n## Do NOT\n\n- Do not leave cuts floating off-beat to preserve a scene's \"natural\" length -\n  stretch or trim the scene to the nearest beat instead.\n- Do not run music at full level under the voiceover; un-ducked music is why VO\n  sounds muddy. Duck it every time someone speaks.\n- Do not stack multiple SFX on one transition, or reuse the same whoosh on every\n  cut - vary them or the ear stops hearing them.\n- Do not write the `\u003CAudio>` JSX, set `startFrom`\u002F`volume` callbacks, or invoke the\n  renderer here - produce the numbers and hand them to remotion-compose \u002F\n  remotion-render.\n- Do not pull tracks from YouTube rips, \"free\" sites with no stated license, or a\n  client's Spotify - commercial use needs a real royalty-free or licensed source.\n- Do not normalize the whole mix to be as loud as possible; leave headroom so the\n  loudest impact does not clip.\n- Do not let the VO race to fit a fixed runtime - re-cut the visuals to the VO, not\n  the VO to the visuals.\n\n## Calculator: beat grid\n\nSelf-contained Node script. Save as `beat_grid.js` and run with `node beat_grid.js`.\nIt turns a BPM and an fps into the exact frame numbers your cuts should land on, and\nflags downbeats. No dependencies. Hand the printed frames to remotion-compose as\n`\u003CSequence from={...}>` boundaries.\n\n```javascript\n\u002F\u002F Beat grid. Edit inputs, then: node beat_grid.js\nconst input = {\n  bpm: 120,            \u002F\u002F tempo of the chosen track\n  fps: 30,             \u002F\u002F project frame rate\n  durationSeconds: 12, \u002F\u002F length of the video\n  beatsPerBar: 4,      \u002F\u002F 4\u002F4 time; downbeat is every 4th beat\n}\n\nconst framesPerBeat = (input.fps * 60) \u002F input.bpm\nconst totalFrames = Math.round(input.durationSeconds * input.fps)\nconst beats = []\nfor (let b = 0; ; b++) {\n  const frame = Math.round(b * framesPerBeat)\n  if (frame > totalFrames) break\n  beats.push({ beat: b + 1, frame, downbeat: b % input.beatsPerBar === 0 })\n}\n\nconsole.log('Frames per beat:', framesPerBeat.toFixed(2), '(' + (60 \u002F input.bpm).toFixed(3) + 's each)')\nconsole.log('Cut on these frames (* = downbeat, best for hard cuts):')\nfor (const b of beats) {\n  console.log('  beat ' + String(b.beat).padStart(2), '-> frame', String(b.frame).padStart(4), b.downbeat ? '*' : '')\n}\nconsole.log('Downbeat frames only:', beats.filter((b) => b.downbeat).map((b) => b.frame).join(', '))\n```\n\n### Worked example output\n\nWith the inputs above the script prints:\n\n```\nFrames per beat: 15.00 (0.500s each)\nCut on these frames (* = downbeat, best for hard cuts):\n  beat  1 -> frame    0 *\n  beat  2 -> frame   15 \n  beat  3 -> frame   30 \n  beat  4 -> frame   45 \n  beat  5 -> frame   60 *\n  beat  6 -> frame   75 \n  beat  7 -> frame   90 \n  beat  8 -> frame  105 \n  beat  9 -> frame  120 *\n  ...\nDownbeat frames only: 0, 60, 120, 180, 240, 300, 360\n```\n\nRead it: at 120 BPM and 30 fps a beat is exactly 15 frames. Put routine transitions\non any listed frame and your hardest cuts - the intro-to-content cut, the CTA reveal -\non a downbeat (0, 60, 120…). If a scene wants to run 70 frames, snap it to 75\n(beat 6) rather than letting the cut float at 70. Those snapped numbers are exactly\nwhat remotion-compose drops into `\u003CSequence from={...}>`.\n\n## Calculator: mix levels and duck timing\n\nSelf-contained Node script. Save as `mix_levels.js` and run with `node mix_levels.js`.\nIt computes the ducked music level and the per-VO-line frame spans to duck, so you\nhand remotion-compose a concrete envelope instead of a vibe. No dependencies.\n\n```javascript\n\u002F\u002F Mix and ducking planner. Edit inputs, then: node mix_levels.js\nconst input = {\n  fps: 30,\n  musicVolume: 0.8,       \u002F\u002F music level when no one is speaking (0-1)\n  duckToPercent: 0.30,    \u002F\u002F duck music to this share of its level under VO\n  voVolume: 1.0,          \u002F\u002F voiceover level (keep VO the loudest element)\n  duckFadeFrames: 8,      \u002F\u002F ramp in\u002Fout so the duck is not a hard jump\n  \u002F\u002F VO lines as [startSeconds, endSeconds]; duck music across each, with fade pad\n  voLines: [\n    [0.5, 3.2],\n    [4.0, 7.5],\n    [8.2, 11.0],\n  ],\n}\n\nconst duckedLevel = +(input.musicVolume * input.duckToPercent).toFixed(3)\nconst toFrame = (s) => Math.round(s * input.fps)\n\u002F\u002F rough dB for reference: 20*log10(level)\nconst dB = (v) => (v \u003C= 0 ? '-inf' : (20 * Math.log10(v)).toFixed(1) + ' dB')\n\nconsole.log('VO level:           ', input.voVolume, '(' + dB(input.voVolume) + ')  \u003C- loudest element')\nconsole.log('Music (no speech):  ', input.musicVolume, '(' + dB(input.musicVolume) + ')')\nconsole.log('Music ducked under VO:', duckedLevel, '(' + dB(duckedLevel) + ')')\nconsole.log('Duck fade:          ', input.duckFadeFrames, 'frames in\u002Fout')\nconsole.log('Duck music across these frame spans (pad ' + input.duckFadeFrames + 'f each side for the fade):')\nfor (const [start, end] of input.voLines) {\n  const a = toFrame(start) - input.duckFadeFrames\n  const b = toFrame(end) + input.duckFadeFrames\n  console.log('  VO ' + start + 's-' + end + 's  -> duck frames', Math.max(0, a), 'to', b)\n}\n```\n\n### Worked example output\n\n```\nVO level:            1 (0.0 dB)  \u003C- loudest element\nMusic (no speech):   0.8 (-1.9 dB)\nMusic ducked under VO: 0.24 (-12.4 dB)\nDuck fade:           8 frames in\u002Fout\nDuck music across these frame spans (pad 8f each side for the fade):\n  VO 0.5s-3.2s  -> duck frames 7 to 104\n  VO 4s-7.5s    -> duck frames 112 to 233\n  VO 8.2s-11s   -> duck frames 238 to 338\n```\n\nRead it: the VO stays at full level (the loudest thing in the mix), music rides at\n0.8 in the gaps and ducks to 0.24 - about a third - wherever someone speaks, fading\nover 8 frames so the dip is not a jarring jump. The frame spans are exactly the\nranges remotion-compose feeds to the music `\u003CAudio>` `volume` callback: full level\noutside the spans, `duckedLevel` inside, linear-ramped across the fade pad. That is\nwhy the words stay clear without the music vanishing.\n\n## Template: audio cue sheet\n\nCopy this, fill the FILL fields with your beat-grid and mix-level outputs, and hand\nthe completed sheet to remotion-compose. It is the single source of truth for every\naudio decision in the video.\n\n```\nAUDIO CUE SHEET. [FILL: video name]. fps [FILL] \u002F [FILL] BPM \u002F [FILL]s total\n\nMUSIC\n  Track:                 [FILL: title + source]\n  License:               [FILL: e.g. Epidemic Sound commercial \u002F CC0] - attribution: [FILL: yes\u002Fno, text]\n  Level (no speech):     [FILL: 0-1]    Ducked under VO: [FILL: 0-1] (~30%)\n\nBEAT GRID (from beat_grid.js) - cuts land here\n  Downbeat frames:       [FILL: 0, 60, 120, ...]\n  Hard cuts on:          [FILL: which downbeats carry the big cuts]\n\nSFX (one per transition; peak ON the motion peak)\n  FRAME    SFX            ROLE\n  [FILL]   [FILL whoosh]  leads into swipe (start ~4f early, tail on cut)\n  [FILL]   [FILL impact]  card slam-in, lands ON cut frame\n  [FILL]   [FILL riser]   builds across 10-20f, resolves on reveal\n  [FILL]   [FILL pop]     UI element appears\n\nVOICEOVER (~150 wpm; scenes fit the VO, not the reverse)\n  LINE                                   START   END    SCENE\n  [FILL line]                            [FILL]  [FILL] [FILL]\n  (silence 8-15f before key line \u002F after CTA)\n\nDUCK ENVELOPE (from mix_levels.js) - frame spans to lower music\n  [FILL: 7-104, 112-233, ...]  fade [FILL]f in\u002Fout\n\nHANDOFF: remotion-compose wires \u003CAudio> + volume callbacks; remotion-render exports.\n```\n\n## references\u002Froyalty-free-sourcing\n\nCommercial video needs music you are actually licensed to use - \"I found it on\nYouTube\" is not a license and a client's Spotify is not either. Licensed\u002Froyalty-free\nsources, by use case:\n\n- **Subscription libraries (safest for client\u002Fcommercial\u002Fads):** Epidemic Sound,\n  Artlist, Musicbed, Soundstripe. Flat fee, broad commercial license, large SFX\n  libraries, no per-video attribution. The default for paid work.\n- **Free with terms (check each track):** YouTube Audio Library (free, some tracks\n  need attribution), Pixabay Music and Mixkit (free, commercial OK, no attribution),\n  Free Music Archive and ccMixter (Creative Commons - read the specific CC license,\n  some forbid commercial use or require attribution).\n- **SFX specifically:** Pixabay and Mixkit (free), Epidemic\u002FArtlist (bundled with\n  subscription), freesound.org (Creative Commons - verify each clip's license).\n\nLicense hygiene, always: confirm the license covers your exact use (personal vs.\ncommercial vs. *paid advertising*, which is often a separate tier); record any\nrequired attribution text in the cue sheet; keep proof of license\u002Fdownload. CC0 and\npublic-domain are the only \"use freely anywhere\" cases - everything else has terms.\nWhen in doubt, a paid subscription library is cheaper than a takedown or a claim.\n\n## references\u002Fsfx-placement\n\nSFX make motion physical; placement is everything. The peak of the sound must hit\nthe peak of the motion, or the brain registers a mismatch.\n\n- **Whoosh \u002F swipe** - directional motion (a slide, a swipe transition). Start it\n  ~3-5 frames *before* the cut so its energy *leads into* the motion and the tail\n  resolves on the cut. A whoosh placed after the motion sounds like an echo.\n- **Impact \u002F thud** - something arriving with weight (a card slamming in, a heavy\n  title drop). Land the transient on the exact frame the object stops. Pair with a\n  tiny scale-overshoot in the motion so sound and picture punch together.\n- **Click \u002F pop \u002F tick** - small discrete UI events (a button, a checkmark, a tab).\n  Land on the frame the element appears. Keep them quiet; they punctuate, they do\n  not announce.\n- **Riser \u002F swell** - building to a reveal (the logo, the CTA, the \"after\" state).\n  Build across the 10-20 frames *before* the reveal and resolve its peak on the\n  reveal frame. A riser that peaks early deflates the moment.\n- **Ambience \u002F drone** - a continuous bed under a scene for mood. Low level, sits\n  under everything, no transient - different job from the punctuation SFX above.\n\nDiscipline: one SFX per transition. Vary the whooshes across cuts (pitch or sample)\nso the ear keeps noticing them. Mix SFX a touch under the VO and above the ducked\nmusic - they punctuate, they never compete with the words.\n",{"name":5,"metadata":24,"description":7},{"title":25},"Sound and Music Sync","main","97a13607d669157a4a16d5ba79b77f208319f7b9","skills\u002Fsound-and-music-sync",3,"https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills","https:\u002F\u002Fskillme.dev","https:\u002F\u002Fgithub.com\u002FSkillMedev","MCP-native catalog of Claude Agent Skills. Browse, recommend, install, and auto-apply skills in chat. Open source, every skill free and clonable on GitHub.","2026-10-14 03:19:31",{"source":8,"skillName":5,"commands":36,"prompt":46,"zipAvailable":47},[37,40,43],{"tool":38,"command":39},"npx","npx skills add SkillMedev\u002Fskills --skill sound-and-music-sync",{"tool":41,"command":42},"bunx","bunx skills add SkillMedev\u002Fskills --skill sound-and-music-sync",{"tool":44,"command":45},"pnpm","pnpm dlx skills add SkillMedev\u002Fskills --skill sound-and-music-sync","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fsound-and-music-sync\u002FSKILL.md",true,[],[50,60,67,74,81,88],{"skillNo":51,"name":52,"nameZh":53,"description":54,"descriptionZh":55,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":56,"categories":57,"keywords":58,"publishedAt":59},"01M75271B256DF3FX2VG5VRYEE","zone-2-cardio-plan","有氧运动计划","Use when someone asks to build a steady-state cardio plan, train an aerobic base or Zone 2, structure easy or endurance weekly cardio, train by heart-rate zones, or improve resting heart rate, VO2, or endurance. Builds a heart-rate-zone aerobic training block with session structure, modality choice, and progression. General fitness guidance, not medical advice. Do NOT use to design a strength or lifting program (use Strength Training Plan), high-intensity interval conditioning, HIIT, or circuits (use Conditioning & HIIT Program), or a mobility\u002Fflexibility routine (use Mobility Routine).","当有人要求制定稳态有氧训练计划、进行有氧基础训练或达到第二区间、安排轻松或耐力型的每周有氧训练、按心率区间训练，或提高静息心率、最大摄氧量或耐力时，可以使用此方案。该方案构建了一个包含训练计划结构、训练方式选择和进度安排的心率区间有氧训练模块。本方案仅提供一般健身指导，不构成医疗建议。请勿用于设计力量或举重训练计划（请使用力量训练计划）、高强度间歇训练 (HIIT) 或循环训练（请使用体能训练和 HIIT 计划），或灵活性\u002F柔韧性训练（请使用灵活性训练计划）。","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzone-2-cardio-plan\u002FSKILL.md",[],[],"2026-11-11 18:27:18",{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":59},"01M7526VP1QBBKYBE17S1WR86Y","youtube-script-writer","Writes retention-engineered long-form YouTube scripts on a hook\u002Fbody\u002Fpayoff architecture - a first-30-seconds hook that survives the retention cliff, a beat-sheet body with mini-hooks and bridges, timed pattern interrupts, and a payoff that over-delivers - with B-roll and editing cues marked inline. Use when someone says \"script my next video\", \"my retention graph dies at the start\", \"tighten this draft\", or \"outline a video on X\". Do NOT use for the 3-second opener of TikTok, Reels, or Shorts - use video-hook-writer instead; do NOT use for spoken voiceover synced to on-screen tutorial actions - use narration-script instead; do NOT use for a sales demo built on a buyer's discovery notes - use demo-script instead; do NOT use to design the thumbnail and title - use thumbnail-concept instead.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube-script-writer\u002FSKILL.md",[],[],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":59},"01M7526P2T0WKMHDXS4Q58237T","win-back-campaign","Designs segmented win-back email sequences for dormant users - dormancy tiers, a three-beat sequence with a single proportional incentive, and a suppression rule - and measures success by re-activation, not opens. Use when someone says \"our users went quiet\", \"design a win-back campaign\", \"how do I re-engage lapsed customers\", \"should we email people who haven't logged in for months\", or lifecycle messaging has stopped landing with a lapsed segment. Do NOT use for recovering an unfinished checkout - use abandoned-cart-sequence instead. Do NOT use for diagnosing and fixing why active customers cancel - use churn-reduction instead. Do NOT use for building always-on onboarding or nurture flows - use email-drip-builder instead.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwin-back-campaign\u002FSKILL.md",[],[],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":59},"01M7526HF2RCDJ50P93WRZRHVV","wikipedia-style","Writes neutral, verifiable, encyclopedic prose following Wikipedia's core content policies and manual of style - NPOV, inline citations, notability-backed claims, and a strict ban on promotional language. Use when someone asks \"write this like a Wikipedia article\", \"draft a Wikipedia page for this company or person\", \"make this neutral and encyclopedic\", or \"why does my article draft keep getting rejected\". Do NOT use for persuasive or opinion writing - use op-ed-writer instead; for thesis-driven academic papers, use academic-essay; for verifying claims in existing text, use fact-checker.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwikipedia-style\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":59},"01M7526D43CTGRKGKNQ2GB0KVX","whitepapers","Structures and writes authoritative B2B whitepapers - a standalone executive summary, a data-sized problem statement, methodology, evidence-driven findings, recommendations, and a soft call to action - flagging every claim that needs a real citation. Use when a marketer asks \"write a whitepaper on this topic\", \"turn our research into a lead-gen asset\", \"make this credible enough for executives\", or a draft reads like a product pitch instead of analysis. Do NOT use for customer-story-driven proof - use case-study-builder instead; for policy audiences, use policy-brief.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwhitepapers\u002FSKILL.md",[],[],{"skillNo":89,"name":90,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":59},"01M75268423Y3K50SY5WC2NX2G","white-space-analysis","Finds unmet market gaps by ranking jobs-to-be-done on importance versus satisfaction, overlaying them against current solutions and workarounds, and validating that each gap is real, winnable, and worth winning. Use when someone asks \"where are the gaps in this market\", \"what's underserved here\", \"where should we play next\", or is hunting for product, feature, or market-entry opportunities. Do NOT use for profiling competitors and building battle cards - use competitive-intelligence instead; for putting a dollar figure on an identified opportunity - use market-sizing instead; for extracting jobs-to-be-done from raw customer interviews - use jtbd-extractor instead.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwhite-space-analysis\u002FSKILL.md",[],[]]