From platform-product-video-harness
How the scriptwriter derives burned-in captions from voiceover lines, syncs them to scene frame ranges, and respects per-platform caption constraints. Captions are mandatory for every voiceover line — Reels / Feed / LinkedIn / Shorts all default to muted playback.
How this skill is triggered — by the user, by Claude, or both
Slash command
/platform-product-video-harness:caption-generationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- All major short-form platforms (Instagram Reels + Feed, TikTok, YouTube Shorts, LinkedIn, Twitter/X) default to **muted playback**.
The reviewer (Phase 5 / V4) rejects any output where a voiceover line lacks a matching <CaptionStrip> in the composition.
For each voiceover line in script.md:
brand.captionStrip.maxWordsPerLine (7 words per line) × brand.captionStrip.maxLines (2 lines) = 14 words max per caption.brand.name), product/feature names, persona labels.Example transformations:
| Voiceover (longer) | Caption (shorter) |
|---|---|
| " tracks every transaction, syncs across devices, and gives you live insights." | "Track, sync, see insights — live." |
| "I used to spend hours every Sunday tallying my farm sales." | "Sundays used to mean hours of tallying." |
| "Download on iOS and Android today." | "Get on iOS + Android" |
If the original voiceover already fits in ≤ 14 words, use it verbatim.
In the composition, the <CaptionStrip> lives inside the same <Sequence> as its scene. It automatically appears for the full scene's duration. No per-word timing — captions are scene-level, not karaoke-style.
<Sequence from={90} durationInFrames={240}> {/* Scene 2: 3.0s → 11.0s */}
<FeatureCallout label="Tap to log" />
<CaptionStrip text="Tap to log a transaction" />
</Sequence>
The caption appears at frame 90 and disappears at frame 330 (3.0s → 11.0s) — synced to the voiceover by construction.
When a caption needs 2 lines (12–14 words), the scriptwriter splits at natural break points:
| Single string | Split into 2 lines |
|---|---|
| "Track every transaction in seconds — inventory updates as you sell" | "Track every transaction in seconds —" / "inventory updates as you sell" |
The <CaptionStrip> component handles line-wrapping automatically; the scriptwriter just provides the raw string. But for cleaner line breaks, the scriptwriter can hint with \n:
- **On-screen caption**:
> "Track every transaction in seconds —\ninventory updates as you sell"
The <CaptionStrip> component reads useVideoConfig() and positions itself per-aspect-ratio:
| Aspect | Position from bottom |
|---|---|
| 9:16 | 380px from bottom (above platform UI overlays) |
| 1:1 | 180px from bottom |
| 16:9 | 130px from bottom |
These are tuned to avoid Reels/TikTok/LinkedIn UI overlay zones. No need to override per video.
Inherited from brand.captionStrip:
brand.fonts.body (Inter, weight 600 for legibility on busy backgrounds)brand.colors.ink at 80% opacity (subtle box for contrast)brand.colors.paperThe reviewer:
script.md for voiceover lines (counts them per scene).compositions/<slug>.tsx for <CaptionStrip occurrences (counts them per <Sequence>).<Sequence> containing a voiceover line, verify a matching <CaptionStrip> exists in the same <Sequence>.[V4-CRITICAL] Scene N has voiceover "..." but no <CaptionStrip>.script.md; compositor omits the <CaptionStrip>.<CaptionStrip> with <Sequence> sub-children offset by the line gap (rare; only when lines are >2s apart).Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub ameenaliu/harness-platform --plugin platform-product-video-harness