Scrollclaw assemble

Assembly stage for UGC videos.

How to use it

Claude Code
  1. Run the line below. It pulls the whole folder into ~/.claude/skills/assemble, including the files SKILL.md points to.
  2. Describe your job in plain words. Claude Code follows the skill from there.
Claude Code — installs the whole folder, not just SKILL.md
npx degit TheMattBerman/scrollclaw/assemble#main ~/.claude/skills/assemble

For 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)
  1. On this page open ⋯ → Download .md.
  2. Save it as SKILL.md in a folder, zip the folder, then Customize → Skills → + → Create skill → Upload a skill.
  3. Pick the file and Save. Claude shows the name and description and runs a security scan.
  4. Check the skill is switched on.
  5. Start a new chat and describe your job in plain words. The AI follows the skill from there.
ChatGPT or another app
  1. ChatGPT: make a Project and paste it into Instructions.
  2. 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.
Step-by-step guide with screenshots · Ask in the forum

Paste into Claude, ChatGPT or Cursor.

Source of Scrollclaw assemble

Show the full text217 lines
namedescriptionmetadata
scrollclaw-assembleAssembly 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 only
  • post — post-production realism pass only
  • captions — caption rendering and overlay only
  • 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

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):

  1. Stitch A-roll clips ONLY (these drive the timeline)
  2. Extract audio → run through ElevenLabs S2S → one consistent voice
  3. Lay S2S voice back on A-roll video
  4. Cut A-roll at B-roll insertion points
  5. Insert B-roll clips as VISUAL-ONLY (no audio) at timestamps matching the script
  6. 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):

  1. Extract last frame: ffmpeg -sseof -0.1 -i clip1.mp4 -frames:v 1 last-frame.png
  2. Use as first frame of clip 2 → seamless visual continuity
  3. 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 --video flag 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, and references/audio-orchestration.md
Output
  • Produces: one assembled final video with stitched visuals, audio, post-production, and captions
  • Format: final-<version>.mp4 in workspace/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-roll
  • post: post-produced file exists, mixed-engine clips look visually coherent, phone test does not immediately ping as AI
  • captions: 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---
2name: scrollclaw-assemble
3description: "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."
4metadata:
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 
24Three stages: stitch + audio → post-production → captions. Order matters.
25 
26## Modes
27 
28This 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 
35If 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 
45Read `references/audio-orchestration.md` for the full process.
46 
47**The critical ordering (tested):**
481. Stitch A-roll clips ONLY (these drive the timeline)
492. Extract audio → run through ElevenLabs S2S → one consistent voice
503. Lay S2S voice back on A-roll video
514. Cut A-roll at B-roll insertion points
525. Insert B-roll clips as VISUAL-ONLY (no audio) at timestamps matching the script
536. 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 
57For 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 
61For longer UGC, either use fal.ai's 20s duration or stitch clips:
62 
63**Last-frame stitching (tested, works well):**
641. Extract last frame: `ffmpeg -sseof -0.1 -i clip1.mp4 -frames:v 1 last-frame.png`
652. Use as first frame of clip 2 → seamless visual continuity
663. Concatenate with ffmpeg
67 
68```bash
69bash 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 
78Use `scripts/stitch-video.sh` for resolution normalization. Read `references/voice-system.md` for voice design guidance.
79 
80## Stage 2: Post-Production (mandatory)
81 
82Raw AI output → post-production → final asset. Never skip.
83 
84Use `scripts/post-production.sh` for automated color grade, grain, and frame rate normalization.
85 
86Read `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 
88If 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 
92Read `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 
100Use `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```bash
103# Generate caption overlay (auto-detects resolution from video)
104python3 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)
111ffmpeg -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 
128All 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 
132For per-scene caption configs, pass a JSON file:
133 
134```bash
135python3 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 
142The 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 
153Resolution note: Sora outputs 720x1280, Kling outputs 1076x1924. Always normalize to one resolution before stitching.
154 
155Requires `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 
216Assembly complete → run `/score` to verify virality score before publishing.
217 

Discussion