Video repurposing skill

Turn long-form video into platform-ready clips - LinkedIn posts, TikTok/Reels, teasers, highlight reels - with word-level captions, using FFmpeg and Remotion.

by naveedharri·MIT license·GitHub ↗

★ 65 Stars on the repo·Checked

npx degit naveedharri/benai-skills/plugins/benai-marketing/skills/video-repurposing#develop ~/.claude/skills/video-repurposing

SKILL.md · 14.2 KB · installs the whole folder to ~/.claude/skills/video-repurposing

Files of Video repurposing

Files 1 file
Show the full text236 lines

Video Repurposing

Turns long-form video into platform-ready clips with captions. FFmpeg for fast CLI operations, Remotion for styled compositions you can preview before rendering. Battle-tested on a real LinkedIn publishing pipeline; the rules below exist because breaking them produced visibly worse clips.


Rules (Always Enforce)

Opening Clip (CRITICAL):

  • The first clip is the hook - it must grab attention immediately
  • Must start at the start of a complete sentence or idea with an explicit subject
  • NEVER start with joining words ("But", "And", "So", "Now", "Then", "However")
  • NEVER start with pronouns without context ("It", "This", "That", "They", "These", "There")
  • NEVER start with filler, hedging, or weak openers ("I think", "You know", "Basically")
  • Review the full transcript and deliberately select the strongest possible opening - a hook, an insight, a bold statement, or a compelling question

Closing Clip (CRITICAL):

  • Must end at the natural conclusion of a thought - never trailing off, never a hard stop mid-idea
  • Should leave the viewer with a takeaway, a call-to-action, or a sense of closure
  • If the last word sounds like it leads into something else, keep going until it resolves
  • Good endings: a summary statement, a strong opinion, a forward-looking insight
  • Bad endings: trailing off, abrupt cuts, filler, unrelated tangents

Clean Cut Points (every cut, no exceptions):

  • Cuts happen at a natural pause in the content - never mid-sentence, never mid-word
  • Respect the idea, not just the words: a cut is clean when the speaker just finished a complete thought and there is a natural breath after the last word
  • Every clip must be a complete, standalone thought with an explicit subject
  • The stitched video must tell a coherent story, not feel like random fragments

Editing modes - pick ONE in intake:

  1. Hard-cut mode (DEFAULT for social clips: LinkedIn, TikTok, Reels). No transitions. Ever. No fades on video or audio, no crossfades, no dissolves. Clip ends on one frame, the next begins on the very next frame. Audio starts and stops at full volume. Clean hard cuts read as confident and native on social feeds; fades read as template-ware. Build with plain <Sequence> blocks + premountFor={60} (see Composition Rules below). Do not use TransitionSeries - it has a null-props bug that crashes Studio in current Remotion versions.
  2. Crossfade mode (optional, for trailers/teasers/montages when the user explicitly wants blended transitions). NEVER allow overlapping audio noise: cosine curves only (audio fade-out 1.5s, fade-in 1.2s, visual crossfade 1s), no fade-in on the first clip, no fade-out on the last. See references/transitions.md for the createVolumeFn pattern and the TransitionSeries bug workaround.

Transcription-first timestamps (CRITICAL - the single source of truth):

  • All clip boundaries come from whisper word-level timestamps, never from scrubbing or guessing
  • startMs/endMs = whisper timestamps of the first and last spoken words → these define the captions
  • Audio/video cut points DERIVE from those: audioEndMs = endMs + audioBufferMs per clip. Whisper timestamps run ~200-700ms ahead of actual speech, so without the buffer the last word gets clipped
  • Punctuation tokens (".", ",") have timestamps but are NOT spoken - never use them as endMs
  • Captions are filtered by the raw transcript boundaries, NOT the buffered audio end, so words from the next sentence never flash on screen during the buffer zone
  • Always verify by ear in Studio: the last word resolves fully, the next sentence doesn't bleed in
  • Full pattern with code in references/transcription.md

Source video prep (before anything else):

  • Check the codec with ffprobe. AV1 is too slow to decode in Remotion Studio (YouTube often serves AV1 by default) - always transcode to H.264
  • -movflags +faststart is mandatory: without it the moov atom sits at the end of the file and Remotion reads the whole file before it can seek, making Studio crawl. Already-H.264 files remux losslessly: ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4
  • Videos go DIRECTLY into public/ with no spaces in filenames

Workflow:

  • ALWAYS complete Phase 2 (Intake) before making any edits - never skip clarification questions
  • ALWAYS propose an edit plan with exact timestamps and get user approval before executing
  • ALWAYS preview in Remotion Studio before rendering
  • ALWAYS run QA checks before showing the preview (see references/qa-testing.md)
  • NEVER render automatically - only when the user explicitly approves

Brand kit (one-time, per user)

All styled output (captions, title cards, graphics) uses the user's brand, captured once in intake and reused forever:

Setting What to ask Default if they have no preference
Colors brand dark, background/light, 1-2 accents dark #0A0A14, light #F5F2EA, accent #B8E0B0
Fonts heading font (Google Fonts name) Inter (via @remotion/google-fonts)
Caption style frosted pill (default) or bold pill frosted
Background rule never pure #000 black - use the brand dark applies to everyone

Store the answers in the Remotion project (a BRAND constant or src/lib/brand.ts) so every composition reads from one place. All code in the references uses example values - swap in the user's kit.


Workflow: 5 Phases

Phase 1: SETUP ──→ Phase 2: INTAKE ──→ Phase 3: EDIT PATH ──→ Phase 4: ITERATE ──→ Phase 5: RENDER
(one-time)         (mandatory)          (copy-first OR          (feedback loop)      (user approves)
                                         video-first)
Phase 1: SETUP (one-time)

If a Remotion project already exists, skip to Phase 2.

  1. Check prerequisites: which ffmpeg || brew install ffmpeg; Node 18+
  2. Create the Remotion project per references/remotion-setup.md (Remotion ^4.0.242, React ^18.x). Complete working code: references/reference-implementation.md
  3. Set up whisper: copy scripts/setup-whisper.ts and scripts/transcribe.ts from THIS SKILL's scripts/ folder into the project's scripts/, then run npx ts-node scripts/setup-whisper.ts (installs whisper.cpp + base.en model into .whisper/, GPU-accelerated)
Phase 2: INTAKE (mandatory - never skip)

Ask before any editing. Do not proceed without clear answers.

Intent & Goal: What's the goal (LinkedIn clip, teaser/trailer, highlight reel, full edit, another platform)? Who is the audience? Video Source: Where is the video (YouTube URL, local file, folder of clips)? Existing copy/script, or discover from the video? Format & Duration: Target duration? Output format (16:9, 9:16, 1:1)? Polish level? Editing mode: Hard cuts (default for social) or crossfades (trailers/montages)? Brand kit: Collect it if this is the first session (table above); otherwise reuse. Content: Specific moments to include or exclude? Reveal the ending or create curiosity?

Then route: has copy → Phase 3A; no copy → Phase 3B.

Phase 3A: COPY-FIRST (user has a script)
  1. Download/copy video into public/ (prep rules above: H.264 + faststart, no spaces)
  2. Analyze with ffprobe (references/video-analysis.md)
  3. Transcribe: npx ts-node scripts/transcribe.ts (references/transcription.md)
  4. Map script sections to transcript timestamps
  5. Propose cuts aligned to the copy - exact timestamps, the spoken words at each boundary, and reasoning
  6. User approves before any editing
Phase 3B: VIDEO-FIRST (no script - discover the story)

1-3. Same prep as 3A 4. Analyze the transcript: hooks, insights, quotable complete thoughts 5. Suggest narrative structure per the goal; create copy/captions from selected segments 6. Propose the edit plan - clips, timestamps, spoken words at boundaries, reasoning 7. User approves before any editing

Phase 4: PROPOSE, PREVIEW & ITERATE (loop)
  1. Present edit plan → get approval
  2. Build/update the Remotion composition (conventions below)
  3. Run QA (references/qa-testing.md)
  4. Preview in Studio (npm run dev) - show the user only after QA passes
  5. Feedback → refine → loop. Users commonly adjust: clip selection, caption style, mode, duration, format

references/intelligent-editing.md has per-task-type questions and quality checks.

Phase 5: RENDER

Only on explicit approval. Social-quality render:

npx remotion render CompositionName out/video.mp4 --video-bitrate 50M --audio-bitrate 320k

Composition Rules

  • One composition per project video, in src/compositions/<platform>/
  • Clip config lives in a clearly marked CONFIG block at the top - the only place to edit. Document every timestamp with the actual spoken words as a comment
  • Export duration as a constant; register every composition in src/Root.tsx

The hard-cut pattern (default):

const CLIPS = [
  {
    label: 'Hook',
    startMs: 148_920,   // "The reason most automations fail..." (whisper timestamp of first word)
    endMs: 238_340,     // "...and that's what makes it work." (whisper timestamp of last spoken word)
    audioBufferMs: 200, // per-clip: small when the next sentence starts fast, up to 700 when there's a gap
  },
] as const;

const clips = CLIPS.map((c) => {
  const audioEndMs = c.endMs + c.audioBufferMs;
  return {...c, audioEndMs, startFrame: msToFrames(c.startMs), endFrame: msToFrames(audioEndMs),
          duration: msToFrames(audioEndMs - c.startMs)};
});

// premountFor={60} is MANDATORY on every Sequence - it preloads the next clip 2s early.
// Without it OffthreadVideo hasn't decoded the next clip's first frame and you get a black flash at the cut.
<Sequence from={0} durationInFrames={clips[0].duration} premountFor={60}>
  <OffthreadVideo src={staticFile('source_h264.mp4')} startFrom={clips[0].startFrame} endAt={clips[0].endFrame} />
</Sequence>

Total duration = sum of clip durations. No overlap, no subtraction.

Captions: never import the captions JSON (bloats the bundle, kills hot reload) - fetch(staticFile(...)) with delayRender/continueRender, pre-filtered to clip ranges. Full pattern + the frosted-pill recipe: references/captions.md.


Platform specs

Platform Resolution FPS Max duration Notes
LinkedIn 1920x1080 (16:9) 30 10 min H.264 MP4; native-feeling hard cuts
TikTok / Reels / Shorts 1080x1920 (9:16) 30 60-90s word-highlight captions carry sound-off viewing
Square feed 1080x1080 (1:1) 30 -

Tool Selection

Task FFmpeg Remotion
Stitching Same codec, no styling Anything styled or previewed
Captions SRT burn-in TikTok-style word highlighting
Teasers Quick cuts Text overlays, branded elements

FFmpeg = fast CLI, batch, format conversion. Remotion = styled content, preview-before-render, React.


Reference Files

Read as needed:

File Contents
references/intelligent-editing.md Editing workflow, questions by task type, quality checks
references/video-analysis.md ffprobe analysis
references/transcription.md Whisper transcription + the timestamp-drift/audioBufferMs pattern
references/qa-testing.md QA tests before user preview
references/stitching.md Combining clips (hard-cut default)
references/transitions.md Crossfade mode + TransitionSeries bug workaround
references/captions.md Word-level captions, frosted pill style, async loading
references/teasers.md 30-second teasers/trailers
references/title-cards.md Chapter headers, bumpers
references/graphics-generation.md Thumbnails, overlays, social graphics
references/ffmpeg-basics.md FFmpeg patterns, faststart/moov, AV1 handling
references/remotion-setup.md Project setup
references/remotion-tips.md Animations, timing, springs
references/reference-implementation.md Complete working project code

Key Lessons (field-tested)

  • Transcription: @remotion/install-whisper-cpp, NOT Python whisper (10x faster, Metal GPU). base.en for speed, medium.en for final quality. whisperCppVersion: '1.5.5' and tokenLevelTimestamps: true are required
  • Whisper drift: timestamps run 200-700ms ahead of audio - per-clip audioBufferMs always, verify by ear
  • Black flash between clips = missing premountFor={60}
  • Studio loading slowly = moov atom at the end of the file - remux with +faststart
  • Studio crash on transitions = TransitionSeries null-props bug - use plain Sequence hard cuts
  • Teasers: 3-4 clips totaling 25-30s; 1.3x playback for energy (1.5x is too fast); first teaser clip must NOT overlap the intro start
  • Captions: pill container behind text beats stroke/shadow for legibility on any footage; same colors on all clips so contrast normalizes
1---
2name: video-repurposing
3description: Turn long-form video into platform-ready clips - LinkedIn posts, TikTok/Reels, teasers, highlight reels - with word-level captions, using FFmpeg and Remotion. USE THIS SKILL WHEN the user wants to repurpose a YouTube video or any long video into social clips, mentions video, clip, footage, mp4, mov, or any video format, wants to cut, stitch, combine, or edit video files, needs captions, subtitles, or TikTok-style word highlighting, wants a teaser, trailer, or highlight reel, asks about video transcription or whisper, mentions FFmpeg, ffprobe, or Remotion errors, or has .mp4/.captions.json files or video folders. Runs a mandatory intake, proposes an edit plan with exact timestamps, previews in Remotion Studio, and renders only on approval.
4disable-model-invocation: true
5---
6 
7# Video Repurposing
8 
9Turns long-form video into platform-ready clips with captions. FFmpeg for fast CLI operations, Remotion for styled compositions you can preview before rendering. Battle-tested on a real LinkedIn publishing pipeline; the rules below exist because breaking them produced visibly worse clips.
10 
11---
12 
13## Rules (Always Enforce)
14 
15**Opening Clip (CRITICAL):**
16- The first clip is the hook - it must grab attention immediately
17- Must start at the start of a complete sentence or idea with an explicit subject
18- NEVER start with joining words ("But", "And", "So", "Now", "Then", "However")
19- NEVER start with pronouns without context ("It", "This", "That", "They", "These", "There")
20- NEVER start with filler, hedging, or weak openers ("I think", "You know", "Basically")
21- Review the full transcript and deliberately select the strongest possible opening - a hook, an insight, a bold statement, or a compelling question
22 
23**Closing Clip (CRITICAL):**
24- Must end at the natural conclusion of a thought - never trailing off, never a hard stop mid-idea
25- Should leave the viewer with a takeaway, a call-to-action, or a sense of closure
26- If the last word sounds like it leads into something else, keep going until it resolves
27- Good endings: a summary statement, a strong opinion, a forward-looking insight
28- Bad endings: trailing off, abrupt cuts, filler, unrelated tangents
29 
30**Clean Cut Points (every cut, no exceptions):**
31- Cuts happen at a natural pause in the content - never mid-sentence, never mid-word
32- Respect the idea, not just the words: a cut is clean when the speaker just finished a complete thought and there is a natural breath after the last word
33- Every clip must be a complete, standalone thought with an explicit subject
34- The stitched video must tell a coherent story, not feel like random fragments
35 
36**Editing modes - pick ONE in intake:**
37 
381. **Hard-cut mode (DEFAULT for social clips: LinkedIn, TikTok, Reels).** No transitions. Ever. No fades on video or audio, no crossfades, no dissolves. Clip ends on one frame, the next begins on the very next frame. Audio starts and stops at full volume. Clean hard cuts read as confident and native on social feeds; fades read as template-ware. Build with plain `<Sequence>` blocks + `premountFor={60}` (see Composition Rules below). **Do not use `TransitionSeries`** - it has a null-props bug that crashes Studio in current Remotion versions.
392. **Crossfade mode (optional, for trailers/teasers/montages when the user explicitly wants blended transitions).** NEVER allow overlapping audio noise: cosine curves only (audio fade-out 1.5s, fade-in 1.2s, visual crossfade 1s), no fade-in on the first clip, no fade-out on the last. See [references/transitions.md](references/transitions.md) for the `createVolumeFn` pattern and the TransitionSeries bug workaround.
40 
41**Transcription-first timestamps (CRITICAL - the single source of truth):**
42- All clip boundaries come from whisper word-level timestamps, never from scrubbing or guessing
43- `startMs`/`endMs` = whisper timestamps of the first and last spoken words → these define the captions
44- Audio/video cut points DERIVE from those: `audioEndMs = endMs + audioBufferMs` per clip. Whisper timestamps run ~200-700ms ahead of actual speech, so without the buffer the last word gets clipped
45- Punctuation tokens (".", ",") have timestamps but are NOT spoken - never use them as `endMs`
46- Captions are filtered by the raw transcript boundaries, NOT the buffered audio end, so words from the next sentence never flash on screen during the buffer zone
47- Always verify by ear in Studio: the last word resolves fully, the next sentence doesn't bleed in
48- Full pattern with code in [references/transcription.md](references/transcription.md)
49 
50**Source video prep (before anything else):**
51- Check the codec with ffprobe. AV1 is too slow to decode in Remotion Studio (YouTube often serves AV1 by default) - always transcode to H.264
52- `-movflags +faststart` is mandatory: without it the moov atom sits at the end of the file and Remotion reads the whole file before it can seek, making Studio crawl. Already-H.264 files remux losslessly: `ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4`
53- Videos go DIRECTLY into `public/` with no spaces in filenames
54 
55**Workflow:**
56- ALWAYS complete Phase 2 (Intake) before making any edits - never skip clarification questions
57- ALWAYS propose an edit plan with exact timestamps and get user approval before executing
58- ALWAYS preview in Remotion Studio before rendering
59- ALWAYS run QA checks before showing the preview (see [references/qa-testing.md](references/qa-testing.md))
60- NEVER render automatically - only when the user explicitly approves
61 
62---
63 
64## Brand kit (one-time, per user)
65 
66All styled output (captions, title cards, graphics) uses the user's brand, captured once in intake and reused forever:
67 
68| Setting | What to ask | Default if they have no preference |
69|---|---|---|
70| Colors | brand dark, background/light, 1-2 accents | dark `#0A0A14`, light `#F5F2EA`, accent `#B8E0B0` |
71| Fonts | heading font (Google Fonts name) | Inter (via `@remotion/google-fonts`) |
72| Caption style | frosted pill (default) or bold pill | frosted |
73| Background rule | never pure `#000` black - use the brand dark | applies to everyone |
74 
75Store the answers in the Remotion project (a `BRAND` constant or `src/lib/brand.ts`) so every composition reads from one place. All code in the references uses example values - swap in the user's kit.
76 
77---
78 
79## Workflow: 5 Phases
80 
81```
82Phase 1: SETUP ──→ Phase 2: INTAKE ──→ Phase 3: EDIT PATH ──→ Phase 4: ITERATE ──→ Phase 5: RENDER
83(one-time) (mandatory) (copy-first OR (feedback loop) (user approves)
84 video-first)
85```
86 
87### Phase 1: SETUP (one-time)
88 
89If a Remotion project already exists, skip to Phase 2.
90 
911. Check prerequisites: `which ffmpeg || brew install ffmpeg`; Node 18+
922. Create the Remotion project per [references/remotion-setup.md](references/remotion-setup.md) (Remotion `^4.0.242`, React `^18.x`). Complete working code: [references/reference-implementation.md](references/reference-implementation.md)
933. Set up whisper: copy `scripts/setup-whisper.ts` and `scripts/transcribe.ts` from THIS SKILL's `scripts/` folder into the project's `scripts/`, then run `npx ts-node scripts/setup-whisper.ts` (installs whisper.cpp + base.en model into `.whisper/`, GPU-accelerated)
94 
95### Phase 2: INTAKE (mandatory - never skip)
96 
97Ask before any editing. Do not proceed without clear answers.
98 
99**Intent & Goal:** What's the goal (LinkedIn clip, teaser/trailer, highlight reel, full edit, another platform)? Who is the audience?
100**Video Source:** Where is the video (YouTube URL, local file, folder of clips)? Existing copy/script, or discover from the video?
101**Format & Duration:** Target duration? Output format (16:9, 9:16, 1:1)? Polish level?
102**Editing mode:** Hard cuts (default for social) or crossfades (trailers/montages)?
103**Brand kit:** Collect it if this is the first session (table above); otherwise reuse.
104**Content:** Specific moments to include or exclude? Reveal the ending or create curiosity?
105 
106Then route: has copy → Phase 3A; no copy → Phase 3B.
107 
108### Phase 3A: COPY-FIRST (user has a script)
109 
1101. Download/copy video into `public/` (prep rules above: H.264 + faststart, no spaces)
1112. Analyze with ffprobe ([references/video-analysis.md](references/video-analysis.md))
1123. Transcribe: `npx ts-node scripts/transcribe.ts` ([references/transcription.md](references/transcription.md))
1134. Map script sections to transcript timestamps
1145. Propose cuts aligned to the copy - exact timestamps, the spoken words at each boundary, and reasoning
1156. User approves before any editing
116 
117### Phase 3B: VIDEO-FIRST (no script - discover the story)
118 
1191-3. Same prep as 3A
1204. Analyze the transcript: hooks, insights, quotable complete thoughts
1215. Suggest narrative structure per the goal; create copy/captions from selected segments
1226. Propose the edit plan - clips, timestamps, spoken words at boundaries, reasoning
1237. User approves before any editing
124 
125### Phase 4: PROPOSE, PREVIEW & ITERATE (loop)
126 
1271. Present edit plan → get approval
1282. Build/update the Remotion composition (conventions below)
1293. Run QA ([references/qa-testing.md](references/qa-testing.md))
1304. Preview in Studio (`npm run dev`) - show the user only after QA passes
1315. Feedback → refine → loop. Users commonly adjust: clip selection, caption style, mode, duration, format
132 
133[references/intelligent-editing.md](references/intelligent-editing.md) has per-task-type questions and quality checks.
134 
135### Phase 5: RENDER
136 
137Only on explicit approval. Social-quality render:
138 
139```bash
140npx remotion render CompositionName out/video.mp4 --video-bitrate 50M --audio-bitrate 320k
141```
142 
143---
144 
145## Composition Rules
146 
147- One composition per project video, in `src/compositions/<platform>/`
148- Clip config lives in a clearly marked `CONFIG` block at the top - the only place to edit. Document every timestamp with the actual spoken words as a comment
149- Export duration as a constant; register every composition in `src/Root.tsx`
150 
151**The hard-cut pattern (default):**
152 
153```tsx
154const CLIPS = [
155 {
156 label: 'Hook',
157 startMs: 148_920, // "The reason most automations fail..." (whisper timestamp of first word)
158 endMs: 238_340, // "...and that's what makes it work." (whisper timestamp of last spoken word)
159 audioBufferMs: 200, // per-clip: small when the next sentence starts fast, up to 700 when there's a gap
160 },
161] as const;
162 
163const clips = CLIPS.map((c) => {
164 const audioEndMs = c.endMs + c.audioBufferMs;
165 return {...c, audioEndMs, startFrame: msToFrames(c.startMs), endFrame: msToFrames(audioEndMs),
166 duration: msToFrames(audioEndMs - c.startMs)};
167});
168 
169// premountFor={60} is MANDATORY on every Sequence - it preloads the next clip 2s early.
170// Without it OffthreadVideo hasn't decoded the next clip's first frame and you get a black flash at the cut.
171<Sequence from={0} durationInFrames={clips[0].duration} premountFor={60}>
172 <OffthreadVideo src={staticFile('source_h264.mp4')} startFrom={clips[0].startFrame} endAt={clips[0].endFrame} />
173</Sequence>
174```
175 
176Total duration = sum of clip durations. No overlap, no subtraction.
177 
178**Captions:** never `import` the captions JSON (bloats the bundle, kills hot reload) - `fetch(staticFile(...))` with `delayRender`/`continueRender`, pre-filtered to clip ranges. Full pattern + the frosted-pill recipe: [references/captions.md](references/captions.md).
179 
180---
181 
182## Platform specs
183 
184| Platform | Resolution | FPS | Max duration | Notes |
185|---|---|---|---|---|
186| LinkedIn | 1920x1080 (16:9) | 30 | 10 min | H.264 MP4; native-feeling hard cuts |
187| TikTok / Reels / Shorts | 1080x1920 (9:16) | 30 | 60-90s | word-highlight captions carry sound-off viewing |
188| Square feed | 1080x1080 (1:1) | 30 | - | |
189 
190---
191 
192## Tool Selection
193 
194| Task | FFmpeg | Remotion |
195|------|--------|----------|
196| Stitching | Same codec, no styling | Anything styled or previewed |
197| Captions | SRT burn-in | TikTok-style word highlighting |
198| Teasers | Quick cuts | Text overlays, branded elements |
199 
200FFmpeg = fast CLI, batch, format conversion. Remotion = styled content, preview-before-render, React.
201 
202---
203 
204## Reference Files
205 
206Read as needed:
207 
208| File | Contents |
209|------|----------|
210| [references/intelligent-editing.md](references/intelligent-editing.md) | Editing workflow, questions by task type, quality checks |
211| [references/video-analysis.md](references/video-analysis.md) | ffprobe analysis |
212| [references/transcription.md](references/transcription.md) | Whisper transcription + the timestamp-drift/audioBufferMs pattern |
213| [references/qa-testing.md](references/qa-testing.md) | QA tests before user preview |
214| [references/stitching.md](references/stitching.md) | Combining clips (hard-cut default) |
215| [references/transitions.md](references/transitions.md) | Crossfade mode + TransitionSeries bug workaround |
216| [references/captions.md](references/captions.md) | Word-level captions, frosted pill style, async loading |
217| [references/teasers.md](references/teasers.md) | 30-second teasers/trailers |
218| [references/title-cards.md](references/title-cards.md) | Chapter headers, bumpers |
219| [references/graphics-generation.md](references/graphics-generation.md) | Thumbnails, overlays, social graphics |
220| [references/ffmpeg-basics.md](references/ffmpeg-basics.md) | FFmpeg patterns, faststart/moov, AV1 handling |
221| [references/remotion-setup.md](references/remotion-setup.md) | Project setup |
222| [references/remotion-tips.md](references/remotion-tips.md) | Animations, timing, springs |
223| [references/reference-implementation.md](references/reference-implementation.md) | Complete working project code |
224 
225---
226 
227## Key Lessons (field-tested)
228 
229- **Transcription:** `@remotion/install-whisper-cpp`, NOT Python whisper (10x faster, Metal GPU). `base.en` for speed, `medium.en` for final quality. `whisperCppVersion: '1.5.5'` and `tokenLevelTimestamps: true` are required
230- **Whisper drift:** timestamps run 200-700ms ahead of audio - per-clip `audioBufferMs` always, verify by ear
231- **Black flash between clips** = missing `premountFor={60}`
232- **Studio loading slowly** = moov atom at the end of the file - remux with `+faststart`
233- **Studio crash on transitions** = `TransitionSeries` null-props bug - use plain `Sequence` hard cuts
234- **Teasers:** 3-4 clips totaling 25-30s; 1.3x playback for energy (1.5x is too fast); first teaser clip must NOT overlap the intro start
235- **Captions:** pill container behind text beats stroke/shadow for legibility on any footage; same colors on all clips so contrast normalizes
236 

Discussion

Alternatives

Also in Captions & subsSee all 325 in Content creator →