Scrollclaw assemble
Assembly stage for UGC videos.
How to use it
Claude Code
- Run the line below. It pulls the whole folder into
~/.claude/skills/assemble, including the files SKILL.md points to. - Describe your job in plain words. Claude Code follows the skill from there.
npx degit TheMattBerman/scrollclaw/assemble#main ~/.claude/skills/assembleFor one project only, change the path to .claude/skills/assemble. This skill also uses -script.md — copying SKILL.md alone won't be enough. See the folder on GitHub.
Claude (web or desktop app)
- On this page open ⋯ → Download .md.
- Save it as SKILL.md in a folder, zip the folder, then Customize → Skills → + → Create skill → Upload a skill.
- Pick the file and Save. Claude shows the name and description and runs a security scan.
- Check the skill is switched on.
- Start a new chat and describe your job in plain words. The AI follows the skill from there.
ChatGPT or another app
- ChatGPT: make a Project and paste it into Instructions.
- Neither? Paste it at the top of a new chat — it works for that chat.
Not working?
- Check which app you pasted it into — the steps above name the right one.
- Some skills need the paid tier of Claude or ChatGPT.
Paste into Claude, ChatGPT or Cursor.
Source of Scrollclaw assemble
Show the full text217 lines
| name | description | metadata |
|---|---|---|
| scrollclaw-assemble | Assembly stage for UGC videos. Handles stitch mode, post mode, captions mode, or full-assemble mode when the user is explicitly working on finalizing an existing campaign video. | openclaw: emoji: "🔧 user-invocable: true triggers: - "assemble video - "full assemble - "stitch clips - "post production - "post produce video - "add captions - "burn captions - "caption overlay - "ugc captions - "ugc audio - "ugc post-production |
Assemble
Three stages: stitch + audio → post-production → captions. Order matters.
Modes
This skill handles four intents. Choose the narrowest one that matches the user's request:
stitch— timeline assembly and voice orchestration onlypost— post-production realism pass onlycaptions— caption rendering and overlay onlyfull-assemble— do all three in order; this is the default when the user says "assemble", "finish the video", or otherwise asks for the final output
If the user asks for one stage explicitly, do not force the full pipeline. If they ask for the final video, run full-assemble.
Prerequisites
- A-roll clips from
/animate - B-roll clips from
/b-roll(if applicable) - Script with timing from
/persona
Stage 1: Stitch + Audio Orchestration
Read references/audio-orchestration.md for the full process.
The critical ordering (tested):
- Stitch A-roll clips ONLY (these drive the timeline)
- Extract audio → run through ElevenLabs S2S → one consistent voice
- Lay S2S voice back on A-roll video
- Cut A-roll at B-roll insertion points
- Insert B-roll clips as VISUAL-ONLY (no audio) at timestamps matching the script
- Lay S2S voice on the final assembled video
Voice never cuts. B-roll swaps visuals only. The wrong approach (stitch all clips then add voice) breaks timing because B-roll adds visual duration that doesn't exist in the voice track.
For single-clip talking head: Sora's built-in audio may be sufficient. For podcast format: always use ElevenLabs S2S.
Multi-Clip Stitching
For longer UGC, either use fal.ai's 20s duration or stitch clips:
Last-frame stitching (tested, works well):
- Extract last frame:
ffmpeg -sseof -0.1 -i clip1.mp4 -frames:v 1 last-frame.png - Use as first frame of clip 2 → seamless visual continuity
- Concatenate with ffmpeg
bash scripts/extend-clip.sh \
--input workspace/campaigns/<slug>/clips/a-roll-01.mp4 \
--prompt-file workspace/campaigns/<slug>/extension-prompt.txt \
--output workspace/campaigns/<slug>/clips/a-roll-01-extended.mp4 \
--log-file workspace/campaigns/<slug>/output-log.md \
--label a-roll-01-extended \
--seconds 10
Use scripts/stitch-video.sh for resolution normalization. Read references/voice-system.md for voice design guidance.
Stage 2: Post-Production (mandatory)
Raw AI output → post-production → final asset. Never skip.
Use scripts/post-production.sh for automated color grade, grain, and frame rate normalization.
Read references/post-production.md for the full realism stack: color grade, grain (the 4K upscale trick), skin texture, frame rate lock, audio realism, lighting consistency.
If mixing Sora + Kling clips, pay special attention to cross-engine color matching — see references/orchestrator.md (in b-roll/references/).
The phone test: watch the final video on a phone screen, in the app, scrolling past it like a user. If anything pings as AI, fix it.
Read references/green-zone.md for platform safe zones.
Stage 3: Captions (ALWAYS LAST)
⚠️ Captions MUST be applied AFTER post-production, not before. Grain and color grade degrade clean caption text. This was the #1 process mistake in session 2.
Caption Overlay System
Use assemble/scripts/caption-overlay.py for all text overlays. It generates transparent PNGs with TikTok-native styling, auto-detects video resolution, and downloads TikTok Sans from Google Fonts if not cached.
# Generate caption overlay (auto-detects resolution from video)
python3 assemble/scripts/caption-overlay.py \
--video workspace/campaigns/<slug>/clips/post-produced.mp4 \
--preset tiktok-wall \
--lines "things i didn't know,would bother me about,my boyfriend..." \
--output workspace/campaigns/<slug>/frames/caption.png
# Overlay onto post-produced video (with compatible encoding)
ffmpeg -i workspace/campaigns/<slug>/clips/post-produced.mp4 \
-i workspace/campaigns/<slug>/frames/caption.png \
-filter_complex "[0:v][1:v]overlay=0:0:enable='between(t,0.2,3.8)'" \
-c:v libx264 -profile:v main -pix_fmt yuv420p -crf 18 \
-movflags +faststart -c:a copy \
workspace/campaigns/<slug>/clips/final-01.mp4
Approved TikTok Text Presets
| Preset | Use For | Font | Size | Color | Stroke |
|---|---|---|---|---|---|
tiktok-wall |
Wall of Text format, dense overlays | TikTok Sans Regular | 38px | #F7F7F2 94% opacity | 2.5px pure black |
tiktok-hook |
Hook captions, opening text | TikTok Sans Bold | 52px | #FFFFFF 100% | 3px pure black |
tiktok-scene |
Scene-by-scene captions | TikTok Sans Regular | 32px | #F7F7F2 94% opacity | 2px pure black |
tiktok-dense |
Dense multi-line overlays | TikTok Sans Regular | 28px | #F7F7F2 94% opacity | 2px pure black |
All presets use centered alignment and safe zone positioning (y=280 at 720x1280 base). Values scale automatically for other resolutions.
Full control via JSON config
For per-scene caption configs, pass a JSON file:
python3 assemble/scripts/caption-overlay.py \
--config workspace/campaigns/<slug>/scripts/captions.json \
--output workspace/campaigns/<slug>/frames/caption-s1.png
Legacy pill-style captions
The older scripts/generate-caption.py still supports pill-style (white rounded rect background) and wall-style captions using Inter font. Use assemble/scripts/caption-overlay.py for all new work — it has the correct TikTok-native styling.
Caption rules
- Caption PNG must match EXACT video resolution. Use
--videoflag to auto-detect. - Use PIL for text overlays — more control than ffmpeg drawtext, no escaping issues.
- Use textfile approach if ffmpeg drawtext is ever needed (avoids apostrophe/escaping bugs).
- Visual Transformation format requires captions on EVERY scene, not just the hook.
- No background pills for TikTok-native text — stroke only.
- Always encode with compatible defaults after caption burn:
-profile:v main -pix_fmt yuv420p -movflags +faststart
Resolution note: Sora outputs 720x1280, Kling outputs 1076x1924. Always normalize to one resolution before stitching.
Requires ffmpeg and python3 with Pillow (auto-installed if missing).
Brand Memory Integration
Reads
| File | Purpose |
|---|---|
workspace/campaigns/<slug>/clips/*.mp4 |
All A-roll and B-roll clips to assemble |
workspace/campaigns/<slug>/scripts/<format>-script.md |
Timing, B-roll insertion points, caption text |
workspace/campaigns/<slug>/creators/creator-<name>.md |
Voice reference for ElevenLabs S2S voice design |
workspace/creators/creator-<name>.md |
Fallback if no campaign-specific profile exists |
Writes
| File | Notes |
|---|---|
workspace/campaigns/<slug>/clips/final-<version>.mp4 |
Assembled video with voice, post-production, captions |
workspace/campaigns/<slug>/output-log.md |
Assembly params, S2S voice used, ffmpeg settings (append-only) |
Context loading
🔧 Assemble context loaded:
✓ Campaign: ridge-q1
✓ A-roll clips: 3 (workspace/campaigns/ridge-q1/clips/a-roll-*.mp4)
✓ B-roll clips: 2 (workspace/campaigns/ridge-q1/clips/b-roll-*.mp4)
✓ Script: talking-head (workspace/campaigns/ridge-q1/scripts/talking-head-script.md)
✓ Creator voice profile: Maya
Contract
Input
- Required: A-roll clips plus a timing-aware script
- Optional: B-roll clips, creator voice profile, ElevenLabs S2S settings
- Format: workspace video files, script markdown, and optional voice metadata
- Source:
/animate,/b-roll,/persona, andreferences/audio-orchestration.md
Output
- Produces: one assembled final video with stitched visuals, audio, post-production, and captions
- Format:
final-<version>.mp4inworkspace/campaigns/<slug>/clips/plus append-only assembly logs - Default behavior: stitch A-roll first, apply voice orchestration, insert B-roll as visual-only cuts, run post-production, then add captions last
- Downstream use:
/score
Validation
- Pre-conditions: source clips exist, script timing is usable, and all inputs are normalized enough to assemble
- Post-conditions: final video is saved locally, voice stays continuous, and captions sit on the post-produced file rather than the raw render
- Failure checks: fix resolution mismatches, broken timing, or synthetic-looking audio here before handing anything to
/score
Stage checkpoints
stitch: assembled timeline exists, cuts land on script beats, voice continuity holds across A-roll and B-rollpost: post-produced file exists, mixed-engine clips look visually coherent, phone test does not immediately ping as AIcaptions: caption overlay matches exact video resolution, readability is mobile-safe, and captions were applied after post-production
Output
- Final assembled video (MP4) in
workspace/campaigns/<slug>/clips/final-<version>.mp4 - All intermediate files preserved in
workspace/campaigns/<slug>/ - Assembly params logged to
workspace/campaigns/<slug>/output-log.md
Next Step
Assembly complete → run /score to verify virality score before publishing.
| 1 | |
| 2 | name scrollclaw-assemble |
| 3 | description "Assembly stage for UGC videos. Handles stitch mode, post mode, captions mode, or full-assemble mode when the user is explicitly working on finalizing an existing campaign video." |
| 4 | metadata |
| 5 | openclaw |
| 6 | emoji "🔧" |
| 7 | user-invocable true |
| 8 | triggers |
| 9 | - "assemble video" |
| 10 | - "full assemble" |
| 11 | - "stitch clips" |
| 12 | - "post production" |
| 13 | - "post produce video" |
| 14 | - "add captions" |
| 15 | - "burn captions" |
| 16 | - "caption overlay" |
| 17 | - "ugc captions" |
| 18 | - "ugc audio" |
| 19 | - "ugc post-production" |
| 20 | |
| 21 | |
| 22 | # Assemble |
| 23 | |
| 24 | Three stages: stitch + audio → post-production → captions. Order matters. |
| 25 | |
| 26 | ## Modes |
| 27 | |
| 28 | This skill handles four intents. Choose the narrowest one that matches the user's request: |
| 29 | |
| 30 | `stitch` — timeline assembly and voice orchestration only |
| 31 | `post` — post-production realism pass only |
| 32 | `captions` — caption rendering and overlay only |
| 33 | `full-assemble` — do all three in order; this is the default when the user says "assemble", "finish the video", or otherwise asks for the final output |
| 34 | |
| 35 | If the user asks for one stage explicitly, do not force the full pipeline. If they ask for the final video, run `full-assemble`. |
| 36 | |
| 37 | ## Prerequisites |
| 38 | |
| 39 | A-roll clips from `/animate` |
| 40 | B-roll clips from `/b-roll` (if applicable) |
| 41 | Script with timing from `/persona` |
| 42 | |
| 43 | ## Stage 1: Stitch + Audio Orchestration |
| 44 | |
| 45 | Read `references/audio-orchestration.md` for the full process. |
| 46 | |
| 47 | **The critical ordering (tested):** |
| 48 | Stitch A-roll clips ONLY (these drive the timeline) |
| 49 | Extract audio → run through ElevenLabs S2S → one consistent voice |
| 50 | Lay S2S voice back on A-roll video |
| 51 | Cut A-roll at B-roll insertion points |
| 52 | Insert B-roll clips as VISUAL-ONLY (no audio) at timestamps matching the script |
| 53 | Lay S2S voice on the final assembled video |
| 54 | |
| 55 | **Voice never cuts. B-roll swaps visuals only.** The wrong approach (stitch all clips then add voice) breaks timing because B-roll adds visual duration that doesn't exist in the voice track. |
| 56 | |
| 57 | For single-clip talking head: Sora's built-in audio may be sufficient. For podcast format: always use ElevenLabs S2S. |
| 58 | |
| 59 | ### Multi-Clip Stitching |
| 60 | |
| 61 | For longer UGC, either use fal.ai's 20s duration or stitch clips: |
| 62 | |
| 63 | **Last-frame stitching (tested, works well):** |
| 64 | Extract last frame: `ffmpeg -sseof -0.1 -i clip1.mp4 -frames:v 1 last-frame.png` |
| 65 | Use as first frame of clip 2 → seamless visual continuity |
| 66 | Concatenate with ffmpeg |
| 67 | |
| 68 | |
| 69 | bash scripts/extend-clip.sh \ |
| 70 | --input workspace/campaigns/<slug>/clips/a-roll-01.mp4 \ |
| 71 | --prompt-file workspace/campaigns/<slug>/extension-prompt.txt \ |
| 72 | --output workspace/campaigns/<slug>/clips/a-roll-01-extended.mp4 \ |
| 73 | --log-file workspace/campaigns/<slug>/output-log.md \ |
| 74 | --label a-roll-01-extended \ |
| 75 | --seconds 10 |
| 76 | |
| 77 | |
| 78 | Use `scripts/stitch-video.sh` for resolution normalization. Read `references/voice-system.md` for voice design guidance. |
| 79 | |
| 80 | ## Stage 2: Post-Production (mandatory) |
| 81 | |
| 82 | Raw AI output → post-production → final asset. Never skip. |
| 83 | |
| 84 | Use `scripts/post-production.sh` for automated color grade, grain, and frame rate normalization. |
| 85 | |
| 86 | Read `references/post-production.md` for the full realism stack: color grade, grain (the 4K upscale trick), skin texture, frame rate lock, audio realism, lighting consistency. |
| 87 | |
| 88 | If mixing Sora + Kling clips, pay special attention to cross-engine color matching — see `references/orchestrator.md` (in `b-roll/references/`). |
| 89 | |
| 90 | **The phone test:** watch the final video on a phone screen, in the app, scrolling past it like a user. If anything pings as AI, fix it. |
| 91 | |
| 92 | Read `references/green-zone.md` for platform safe zones. |
| 93 | |
| 94 | ## Stage 3: Captions (ALWAYS LAST) |
| 95 | |
| 96 | **⚠️ Captions MUST be applied AFTER post-production, not before.** Grain and color grade degrade clean caption text. This was the #1 process mistake in session 2. |
| 97 | |
| 98 | ### Caption Overlay System |
| 99 | |
| 100 | Use `assemble/scripts/caption-overlay.py` for all text overlays. It generates transparent PNGs with TikTok-native styling, auto-detects video resolution, and downloads TikTok Sans from Google Fonts if not cached. |
| 101 | |
| 102 | |
| 103 | # Generate caption overlay (auto-detects resolution from video) |
| 104 | python3 assemble/scripts/caption-overlay.py \ |
| 105 | --video workspace/campaigns/<slug>/clips/post-produced.mp4 \ |
| 106 | --preset tiktok-wall \ |
| 107 | --lines "things i didn't know,would bother me about,my boyfriend..." \ |
| 108 | --output workspace/campaigns/<slug>/frames/caption.png |
| 109 | |
| 110 | # Overlay onto post-produced video (with compatible encoding) |
| 111 | ffmpeg -i workspace/campaigns/<slug>/clips/post-produced.mp4 \ |
| 112 | -i workspace/campaigns/<slug>/frames/caption.png \ |
| 113 | -filter_complex "[0:v][1:v]overlay=0:0:enable='between(t,0.2,3.8)'" \ |
| 114 | -c:v libx264 -profile:v main -pix_fmt yuv420p -crf 18 \ |
| 115 | -movflags +faststart -c:a copy \ |
| 116 | workspace/campaigns/<slug>/clips/final-01.mp4 |
| 117 | |
| 118 | |
| 119 | ### Approved TikTok Text Presets |
| 120 | |
| 121 | | Preset | Use For | Font | Size | Color | Stroke | |
| 122 | |--------|---------|------|------|-------|--------| |
| 123 | | `tiktok-wall` | Wall of Text format, dense overlays | TikTok Sans Regular | 38px | #F7F7F2 94% opacity | 2.5px pure black | |
| 124 | | `tiktok-hook` | Hook captions, opening text | TikTok Sans Bold | 52px | #FFFFFF 100% | 3px pure black | |
| 125 | | `tiktok-scene` | Scene-by-scene captions | TikTok Sans Regular | 32px | #F7F7F2 94% opacity | 2px pure black | |
| 126 | | `tiktok-dense` | Dense multi-line overlays | TikTok Sans Regular | 28px | #F7F7F2 94% opacity | 2px pure black | |
| 127 | |
| 128 | All presets use centered alignment and safe zone positioning (y=280 at 720x1280 base). Values scale automatically for other resolutions. |
| 129 | |
| 130 | ### Full control via JSON config |
| 131 | |
| 132 | For per-scene caption configs, pass a JSON file: |
| 133 | |
| 134 | |
| 135 | python3 assemble/scripts/caption-overlay.py \ |
| 136 | --config workspace/campaigns/<slug>/scripts/captions.json \ |
| 137 | --output workspace/campaigns/<slug>/frames/caption-s1.png |
| 138 | |
| 139 | |
| 140 | ### Legacy pill-style captions |
| 141 | |
| 142 | The older `scripts/generate-caption.py` still supports pill-style (white rounded rect background) and wall-style captions using Inter font. Use `assemble/scripts/caption-overlay.py` for all new work — it has the correct TikTok-native styling. |
| 143 | |
| 144 | ### Caption rules |
| 145 | |
| 146 | **Caption PNG must match EXACT video resolution.** Use `--video` flag to auto-detect. |
| 147 | **Use PIL for text overlays** — more control than ffmpeg drawtext, no escaping issues. |
| 148 | **Use textfile approach** if ffmpeg drawtext is ever needed (avoids apostrophe/escaping bugs). |
| 149 | **Visual Transformation format requires captions on EVERY scene**, not just the hook. |
| 150 | **No background pills** for TikTok-native text — stroke only. |
| 151 | **Always encode with compatible defaults** after caption burn: `-profile:v main -pix_fmt yuv420p -movflags +faststart` |
| 152 | |
| 153 | Resolution note: Sora outputs 720x1280, Kling outputs 1076x1924. Always normalize to one resolution before stitching. |
| 154 | |
| 155 | Requires `ffmpeg` and `python3` with Pillow (auto-installed if missing). |
| 156 | |
| 157 | ## Brand Memory Integration |
| 158 | |
| 159 | ### Reads |
| 160 | | File | Purpose | |
| 161 | |------|---------| |
| 162 | | `workspace/campaigns/<slug>/clips/*.mp4` | All A-roll and B-roll clips to assemble | |
| 163 | | `workspace/campaigns/<slug>/scripts/<format>-script.md` | Timing, B-roll insertion points, caption text | |
| 164 | | `workspace/campaigns/<slug>/creators/creator-<name>.md` | Voice reference for ElevenLabs S2S voice design | |
| 165 | | `workspace/creators/creator-<name>.md` | Fallback if no campaign-specific profile exists | |
| 166 | |
| 167 | ### Writes |
| 168 | | File | Notes | |
| 169 | |------|-------| |
| 170 | | `workspace/campaigns/<slug>/clips/final-<version>.mp4` | Assembled video with voice, post-production, captions | |
| 171 | | `workspace/campaigns/<slug>/output-log.md` | Assembly params, S2S voice used, ffmpeg settings (append-only) | |
| 172 | |
| 173 | ### Context loading |
| 174 | |
| 175 | |
| 176 | 🔧 Assemble context loaded: |
| 177 | ✓ Campaign: ridge-q1 |
| 178 | ✓ A-roll clips: 3 (workspace/campaigns/ridge-q1/clips/a-roll-*.mp4) |
| 179 | ✓ B-roll clips: 2 (workspace/campaigns/ridge-q1/clips/b-roll-*.mp4) |
| 180 | ✓ Script: talking-head (workspace/campaigns/ridge-q1/scripts/talking-head-script.md) |
| 181 | ✓ Creator voice profile: Maya |
| 182 | |
| 183 | |
| 184 | ## Contract |
| 185 | |
| 186 | ### Input |
| 187 | Required: A-roll clips plus a timing-aware script |
| 188 | Optional: B-roll clips, creator voice profile, ElevenLabs S2S settings |
| 189 | Format: workspace video files, script markdown, and optional voice metadata |
| 190 | Source: `/animate`, `/b-roll`, `/persona`, and `references/audio-orchestration.md` |
| 191 | |
| 192 | ### Output |
| 193 | Produces: one assembled final video with stitched visuals, audio, post-production, and captions |
| 194 | Format: `final-<version>.mp4` in `workspace/campaigns/<slug>/clips/` plus append-only assembly logs |
| 195 | Default behavior: stitch A-roll first, apply voice orchestration, insert B-roll as visual-only cuts, run post-production, then add captions last |
| 196 | Downstream use: `/score` |
| 197 | |
| 198 | ### Validation |
| 199 | Pre-conditions: source clips exist, script timing is usable, and all inputs are normalized enough to assemble |
| 200 | Post-conditions: final video is saved locally, voice stays continuous, and captions sit on the post-produced file rather than the raw render |
| 201 | Failure checks: fix resolution mismatches, broken timing, or synthetic-looking audio here before handing anything to `/score` |
| 202 | |
| 203 | ### Stage checkpoints |
| 204 | `stitch`: assembled timeline exists, cuts land on script beats, voice continuity holds across A-roll and B-roll |
| 205 | `post`: post-produced file exists, mixed-engine clips look visually coherent, phone test does not immediately ping as AI |
| 206 | `captions`: caption overlay matches exact video resolution, readability is mobile-safe, and captions were applied after post-production |
| 207 | |
| 208 | ## Output |
| 209 | |
| 210 | Final assembled video (MP4) in `workspace/campaigns/<slug>/clips/final-<version>.mp4` |
| 211 | All intermediate files preserved in `workspace/campaigns/<slug>/` |
| 212 | Assembly params logged to `workspace/campaigns/<slug>/output-log.md` |
| 213 | |
| 214 | ## Next Step |
| 215 | |
| 216 | Assembly complete → run `/score` to verify virality score before publishing. |
| 217 |
Discussion
Browse more free Claude skills.