Video Assembler
Mix narration audio over video, adjust levels, and add subtitles.
Installation
- Make sure Claude is on your device and in your terminal.
Skills load from
~/.claude/skills/when Claude Code starts up — so you need it on your machine first. If you don't have it yet, install it once with the command below, then runclaudein any terminal to verify.One-time setupnpm i -g @anthropic-ai/claude-codeAlready have it? Skip ahead.
- Paste into Claude Code or into your terminal.
This copies the whole skill folder into
~/.claude/skills/video-assemble-worldwonderer/— the SKILL.md plus any scripts, reference docs, or templates the skill ships with. Safe default: works for every skill.Faster alternative (instruction-only skills)
Skips the clone and grabs only the SKILL.md file. Don't use this if the skill ships Python scripts, reference markdowns, or asset templates — they won't be downloaded and the skill will fail when it tries to load them.
Quick install (SKILL.md only)Sign up to copy - Restart Claude Code.
Quit and reopen Claude Code (or any other agent that loads from
~/.claude/skills/). New skills are picked up on startup. - Just ask Claude.
Skills auto-activate when your request matches the skill's description — no slash command needed. Trigger phrases live in the skill's own frontmatter; you can read them in the “What this skill does” section above.
Prefer to read the source first? Open on GitHub.
When Claude uses it
Use as the last stage of the video-recap pipeline — muxes the narration audio over the source video, ducks the original audio underneath, renders subtitles (SRT/ASS, optionally burned in), and loudness-normalizes the final cut.
What this skill does
What this does
- Mixes the narration audio segments onto the source video at their placed times.
- Ducks the original audio under narration (fixed / sidechain / zone modes).
- Renders subtitles from the narration placement →
subtitles.srt(+subtitles.asswhen burning, which is on by default;--no-burn-subtitlesto disable). - Optional final loudness normalization to a target LUFS.
Input contract
<video>— the source video (the original, oredited_source.mp4in cut mode).work_dir/tts_meta.json—{segments: [...]}from video-voiceover (each segment carriesaudio_path, timing,pause_after_ms, andoverlaps_speech/placement used for ducking + subtitles).
Running the scripts below — the
scripts/…paths are relative to this skill's own directory (the folder containing thisSKILL.md). Claude Code runs commands from there, so they work as written. If your harness runs commands from the project root instead (opencode / Codex / OpenClaw commonly do), prefix this skill's absolute directory — e.g.<skill-dir>/scripts/…, using the directory your harness reports when it loads the skill. The scripts self-locate from their own path, so once started by the correct path they resolve their sibling skills and assets regardless of the working directory.
Run
python3 scripts/assemble.py <video> --work-dir <work_dir> \
[--recap-stem <name>] [--output-dir <dir>] [--no-burn-subtitles]
[--subtitle-y-top <inclusive-y> --subtitle-y-bot <exclusive-y>]
[--source-video <orig.mp4>] [--export-jianying [--jianying-out <dir>]]
Output contract
recap_<stem>.mp4— the final recap video (written to--output-dirorwork_dir's parent). It is the stable output alias, overwritten in place on every run so iterating on the narration refreshes the same file.work_dir/output.mp4— the in-place render.subtitles.srt— narration subtitles;subtitles.asswhen burning subtitles (on by default).timeline.json— backend-neutral multi-track model (video / original-audio / narration / BGM / subtitle tracks with ducking automation). Always written.assembly_manifest.json— a slim render record: the input/source paths, the cut-mode source fingerprint (proving a stale ambientSOURCE_VIDEOdid not leak into a full-mode export), the render settings, and the final output path.- draft folder (
recap_<stem>/draft_content.json+draft_info.json+draft_meta_info.json) — only with--export-jianying.
Notes
- Audio is mixed as tracks (like a cut-software timeline): the original audio, an optional BGM bed, and the narration.
- Optional /JianYing export:
--export-jianying(orEXPORT_JIANYING=1) turnstimeline.jsoninto an editable draft with original clips, separate narration/BGM tracks, subtitle materials, native volume keyframes, and optional local photo overlays. It is fully decoupled and lazy-imported: the ffmpeg render never depends on it, and need not be installed. In cut mode pass--source-video <orig>so the draft references real source ranges. Bundling is on by default and copies video/audio/photo toResources/local/{video,audio,image}, writes placeholder paths plusdraft_meta_info.jsonindexes, and keeps a cloned/moved draft self-contained;--jianying-no-bundle-mediais only for reachable original paths. Overlapping overlays split onto numbered lanes, and a non-empty draft folder gets a numbered sibling instead of being overwritten. Constant speed, reverse, transforms, rich text, transition/mask/LUT, green-screen compound drafts, and explicit sound/sticker/text-template/video-effect/face-effect tracks are available through the documented timeline v2 authoring extensions. Resource-backed features require legal caller-supplied offline packages; no official catalog, demo credential, text-template adapter, or AutoJY desktop automation is bundled. The draft references the un-burned source, so its hardcoded subtitles remain visible (mask them in if needed). - Subtitle look:
SUBTITLE_FONT_SIZE,SUBTITLE_MARGIN_V,SUBTITLE_MAX_CHARS, etc. - Source-pinned subtitle look:
SUBTITLE_Y_TOP/BOTplaces the ASS baseline on a measured source band using half-open display-pixel coordinates[top, bot). With an explicit mask policy, the band defaults toSUBTITLE_MASK_OPACITY=0.6andSOURCE_SUBTITLE_MASK_TIMING=narration;SUBTITLE_MASK_PADDINGcontrols pixel padding. - Ducking / loudness: the original swells to
IDLE_ORIG_VOLUMEin the gaps and ducks toSPEECH_DUCKING_VOLUMEunder narration (DUCK_FADE_SECONDSsmooths the transition); alsoDUCKING_MODE,ZONE_DUCKING_VOLUME,FINAL_LOUDNORM,TARGET_LUFS. - BGM (optional): set
BGM_PATHto any audio file; it loops to length and ducks under narration (BGM_VOLUME/BGM_DUCKING_VOLUME). - Burning subtitles requires an ffmpeg with
subtitles/libass support; assemble (and the recap orchestrator) preflight this and fail fast with a clear message if it is missing. - During original-audio blocks (the narration gaps), original dialogue is burned only when the
source mask actually covers those gaps, or when a user-supplied subtitle file explicitly asks
for replacement text. Narration-only masking otherwise leaves the source hard subtitles visible.
Replacement dialogue is wrapped in `` to set it apart from narration
(
SUBTITLE_ORIGINAL_IN_GAPS, default on). Preferred source is the agent-calibratedoriginal_subtitles.json(OUTPUT-time[{start,end,text}]); without it, a conservative auto-ASR mapping is used (cut mode remaps ASR source→output via the clip plan, assigns each line to the one gap it lands in, and skips lines too dense to read).
What this skill does NOT do
- Does NOT generate narration or synthesize TTS.
- Does NOT re-transcribe or alter timing decisions — it consumes placement from tts_meta.json.
- Burning subtitles is on by default (
--no-burn-subtitlesto turn it off); when on, it re-encodes the video to draw the subtitle band.
Related skills
Skill Builder & Optimizer
anthropics
Create, edit, and optimize Claude skills with performance testing and benchmarking.
Org Change Management
alirezarezvani
Guide teams through organizational changes using the ADKAR model and communication strategies.
Audio/Video Transcription
daymade
Transcribe audio and video files to text with fast local or remote processing.
Claude Export Conversation Fixer
daymade
Repair broken line wrapping in Claude Code exported conversation files.