Launch video creator skill

Build a 30-60s motion-graphics launch video for a <YOUR_BRAND> product or feature.

by timscheuerai·MIT license·★ 37 Stars on the repo·GitHub ↗

Use now

Inside this skill

SKILL.md · the author's own words
# Launch video creator

Builds a **30-60s motion-graphics launch video** for a <YOUR_BRAND>
product or feature, end-to-end:

- **Remotion 4** React composition rendered to MP4 (1920×1080 + 1080×1080)
- **ElevenLabs** AI narration (Bill voice by default), per-event sound
  effects, and a background music bed
- **Beat-anchored timing**: every visual phase reads its start frame from
  measured audio durations in `script.timings.json`. Edit copy → regen audio
  → all visuals auto-shift. No manual frame nudging.
- If your brand has a motion subsystem (glass/cursor/tool-pill components),
  inherit from there. The reference patterns described below are one valid
  system: a **glassmorphic motion subsystem** (chat shells, cursor, tool
  pills) layered over a **clean white tabular system** (results tables,
  dashboards, traces).

Word-for-word excerpt, not a result. Read the full SKILL.md ↓

Files of Launch video creator

timscheuerai/main1 file shown
SKILL.md
Show the full text463 lines

Launch video creator

Builds a 30-60s motion-graphics launch video for a <YOUR_BRAND> product or feature, end-to-end:

  • Remotion 4 React composition rendered to MP4 (1920×1080 + 1080×1080)
  • ElevenLabs AI narration (Bill voice by default), per-event sound effects, and a background music bed
  • Beat-anchored timing: every visual phase reads its start frame from measured audio durations in script.timings.json. Edit copy → regen audio → all visuals auto-shift. No manual frame nudging.
  • If your brand has a motion subsystem (glass/cursor/tool-pill components), inherit from there. The reference patterns described below are one valid system: a glassmorphic motion subsystem (chat shells, cursor, tool pills) layered over a clean white tabular system (results tables, dashboards, traces).

If your repo has a reference Remotion project, point this skill at it. Otherwise the patterns described below stand alone. Reference implementation path in the source repo: <YOUR_REFERENCE_VIDEO_PATH>.


When to use

Trigger on:

  • "Create a launch video for X"
  • "Make a launch video / product video / feature reveal"
  • "Render a video for the [feature]"
  • User explicitly types /launch-video

Skip for:

  • Static social graphics → /graphics-designer
  • Slide decks / webinars → your decks pipeline
  • Short ad clips < 8s → these can usually be a single Remotion still or a one-scene composition; this skill's full pipeline is overkill.
  • Raw recorded footage (talking heads, webinar recordings, founder videos, customer interviews, screen-capture demos) → use /video-use instead. That skill cuts on word boundaries from a Scribe transcript, removes filler words, color grades, and burns subtitles. This skill is for synthetic motion graphics built from scratch in Remotion. The two compose: a /video-use edit can spawn Remotion overlay slots for branded animation inserts, but the cut comes from /video-use.

Architecture in one diagram

motion/<video-name>/
├── package.json              # remotion 4 + react 19 + tsx + dotenv + mp3-duration
├── remotion.config.ts        # publicDir → ../../brand/motion (single asset source)
├── tsconfig.json
├── SCRIPT.md                 # human-readable narration script (per beat)
├── .env                      # ELEVENLABS_API_KEY (gitignored!)
├── .env.example
├── generate-audio.ts         # ElevenLabs narration runner, hash-cached per beat
├── generate-sfx.ts           # ElevenLabs sound-generation runner, hash-cached
├── generate-music.ts         # ElevenLabs music runner + leading-silence trim
├── script.timings.json       # narration durations (generated)
├── sfx.timings.json          # SFX durations (generated)
├── music.timings.json        # music duration (generated)
└── src/
    ├── Root.tsx              # registerRoot
    ├── Video.tsx             # composition registry + LaunchVideoComposition wrapper
    ├── theme.ts              # fps + duration + colors (mirrors <YOUR_BRAND_TOKENS_PATH>)
    ├── script.ts             # narration beats (id, phase, text)
    ├── timings.ts            # loader for script.timings.json + beatStartFrame()
    ├── sfx.ts                # SFX clip definitions (anchored to frames)
    ├── music.ts              # music prompt + volume
    ├── Narration.tsx         # narration-only Sequence track
    ├── SoundDesign.tsx       # narration + SFX + music combined
    └── scenes/
        ├── HeroBackground.tsx      # looped /video/hero-bg.mp4
        ├── OpeningScene.tsx        # the orchestration scene (anchors all phases)
        ├── GlassCursor.tsx         # multiplayer-style "you" cursor
        ├── CompanyTable.tsx        # populating data table with column reveals
        ├── AgentDashboard.tsx      # Google-Calendar week view
        ├── AgentRunDetail.tsx      # tool-call trace view
        ├── MemoryPanel.tsx         # stats + sparkline dashboard
        ├── Confetti.tsx            # particle burst
        └── ClosingCard.tsx         # closing chat callback (the "Inviting" pattern)

Assets live in brand/motion/:

  • video/hero-bg.mp4 + poster (your brand's hero background loop · e.g. an ambient video at brand/motion/video/hero-bg.mp4)
  • logos/{models,tools,companies,sequencers}/ — third-party brand marks
  • audio/{launch-narration,sfx,music}/ — generated mp3s (committed for reproducible renders)
  • components/HeroChatMockup.tsx — framework-agnostic chat shell

Workflow for a new launch video

1. Brief

Get from the user:

  • Audience: who is this for (GTM teams? Engineers? Investors?)
  • Runtime: target seconds (default 30-45s; 60s+ feels long for hype)
  • Key messages: 4-8 things to communicate, in narrative order
  • Output formats: landscape (web/LinkedIn), square (IG/feed), or both
2. Outline beats

Each beat = one narration sentence that lands during one visual phase. Typically 6-8 beats. Sum of beat audio lengths = total runtime. Beat lengths target 3-7s each.

For each beat capture: id, phase (one-line visual description), text (spoken line, 10-20 words).

3. Write SCRIPT.md

Save the script as a sibling of package.json for human review. Format:

## Beat N — Phase name
**Frames** ~start–end (seconds) · **target ~Nwords**

> "Spoken line here."

**Visual sync:** what happens on screen.
4. Build src/script.ts

Mirrors SCRIPT.md as data. The narration generator and the composition both import SCRIPT. No Remotion imports here so generators can run in plain Node:

export interface Beat { id: string; phase: string; text: string; }
export const SCRIPT: Beat[] = [...];
export const AUDIO_SUBDIR = "audio/launch-narration";
export function audioPath(id: string) { return `${AUDIO_SUBDIR}/${id}.mp3`; }
5. Generate narration
cd motion/<video-name>
cp .env.example .env  # paste ELEVENLABS_API_KEY
npm install
npm run generate-audio

This creates brand/motion/audio/launch-narration/{beat-id}.mp3 and writes durations to script.timings.json. Hashes by beat text so unchanged beats are skipped on subsequent runs (cheap iteration).

6. Build the visual scene

In OpeningScene.tsx:

  1. Compute beat starts at module load:
    const HERO_BEAT     = beatStart("hero", 0);        // → 0
    const DATABASE_BEAT = beatStart("database", 0);    // → 171 (after hero finishes)
    // ... etc
    
  2. Express every animation frame as BEAT_X + offset:
    const BADGE_IN     = HERO_BEAT + 6;
    const TYPE_START   = HERO_BEAT + 38;
    const TOOLS_START  = HERO_BEAT + 115;  // synced to "GTM stack" lyric
    const CURSOR_PRESS = HERO_BEAT + 165;
    
  3. Cross-fade between phase scenes using opacity gates per beat.
7. Generate SFX (optional but high-impact)

Define click/transition moments in src/sfx.ts. Anchor each clip to a specific fromFrame using the same beatStartFrame() helper. Example clips that earn their place:

  • typing texture under prompt animation
  • crisp click on cursor presses
  • celebratory pop on "enroll" / completion moments
  • subtle swell on closing card reveal
npm run generate-sfx
8. Generate music

Define one prompt + duration in src/music.ts. generate-music.ts trims leading silence automatically (ElevenLabs music often opens with a quiet bar that reads as "no music" against narration).

npm run generate-music
9. Iterate with renders
npm run render:landscape

Rendering takes ~30-90s. Always re-encode the output to yuv420p TV range for QuickTime compatibility — the bg video is yuvj420p (JPEG range) and the propagation breaks playback in some players:

ffmpeg -y -i out/launch-landscape.mp4 \
  -c:v libx264 -profile:v high -level:v 4.0 \
  -pix_fmt yuv420p -color_range tv -crf 18 -c:a copy \
  out/launch-landscape-fixed.mp4
mv out/launch-landscape-fixed.mp4 out/launch-landscape.mp4

Use ffmpeg -ss N -i ... -frames:v 1 /tmp/check.jpg to spot-check specific timestamps without watching the whole render.


Design rules

Voice (visual + spoken)
  • Never use em dashes. Periods, commas, colons, parens, middot only.
  • Banned words anywhere: leverage, synergy, robust, world-class, seamless, intuitive, powerful, innovative.
  • Numerals beat adjectives ("8 tools" not "many tools").
  • Terse, concrete. No hedging.
  • Closing: brand-led, not "Congrats." The strongest closing pattern found here: "Inviting" kicker → chat input with a new prompt typed in → URL signature. The chat callback to the opening beats celebration every time.
Color (example tokens · adjust to your brand)

Light, neutral. One accent only, used once per scene where it earns meaning (live dot, highlight, success state).

Token Hex Use
--bg #fafafa page bg
--surface #ffffff cards, dashboards
--ink #0a0a0a primary text + numerals
--muted #71717a secondary text
--line #e4e4e7 borders
--accent #10b981 the one accent
Typography
  • Stack: 'Helvetica Neue', Helvetica, Arial, sans-serif
  • Mono (kickers, code, labels): ui-monospace, 'SFMono-Regular', Menlo
  • Hero typography: weight 450 with tight tracking (-0.05em)
  • Mono kicker style: 11-14px, uppercase, letter-spacing 0.16-0.18em, color #71717a or #a1a1aa
  • Bold/medium parts in muted-grey body text mirror the brand pattern: <span style={{ color: "#0a0a0a", fontWeight: 500 }}>bold</span> vs surrounding #71717a text.
Two visual modes

Pick one per scene; don't mix:

  1. Glassmorphic / in-product — chat shell, cursor, tool pills, over the hero bg video. White glass with backdrop-filter: blur(28px), rgba(255,255,255,0.45).
  2. Clean white / tabular — tables, dashboards, traces, memory panel. bg #ffffff, 1px solid #e4e4e7, subtle drop shadow.

The bg-fade transition between modes is one of the most cinematic moments; budget ~20-30 frames for it and use Easing.bezier(0.4, 0, 0.2, 1) (material standard) for smoothness.


Animation rules

  1. Damping 22-28 on springs. Below 20 you get bounce that reads as amateur. Use 14-18 only when you intentionally want a "pop".
  2. Tighter staggers > slower. First instinct is always to slow down; the second pass usually involves cutting staggers in half. Default stagger between cascading items: 3-6 frames.
  3. Sync visuals to lyrics where it matters. If the narration says "GTM stack", the tool pills should fly in on that word — not 3s before. Use with_timestamps from ElevenLabs for word-level sync, or estimate from beat duration / word count if approximate is fine.
  4. Reserve row heights. When tables/cards animate text in, minHeight on the row prevents layout from jumping as content fills. Looks janky if rows grow during the cascade.
  5. Conditional render rather than 0-opacity if it would create a tall empty rectangle. Cards that haven't started revealing yet should not occupy space.
  6. Crossfade between scene modes, don't hard-cut. Each major scene gets an opacity gate animated via interpolate + ease curves.

ElevenLabs gotchas

  • Default voice + model: generate-audio.ts defaults to Bill (pqHfZKP75CvOlQylNhV4) on eleven_multilingual_v2. Bill is the advertisement use-case voice in ElevenLabs' library: wise, mature, crisp. Reads as a real ad voiceover, not "AI guy on social media". multilingual_v2 is the most stable + lifelike model for production narration. Do not use eleven_turbo_v2_5 for launch videos — it's the fast/cheap model and the difference is audible against a hero bg video. Turbo is fine for previews / SFX timing checks, not the final render.
  • Voice settings baked into the script: stability 0.40, similarity_boost 0.75, style 0.30, use_speaker_boost true. Per ElevenLabs best-practices: stability under 0.30 is unstable, over 0.60 is monotone; similarity 0.75 is the docs sweet spot; style 0.20–0.40 adds expressiveness without drift. Don't push style above 0.4 unless you want noticeable inflection swings.
  • Voice cache key includes voice + model + settings. Swapping any of those (or editing beat text) invalidates the cached MP3 and re-renders the beat. Just edit .env (VOICE_ID=... MODEL_ID=...) or generate-audio.ts and re-run npm run generate-audio.
  • Other narration-grade voices if Bill doesn't fit:
    • Eric cjVigY5qzO86Huf0OWal — smooth, trustworthy, modern SaaS feel
    • Chuck Miller HIGUfNOdjuWQwwapnTRW — pro clone, deep raspy, cinematic
    • George JBFqnCBsd6RMkjVDRZzb — British storyteller, narrative_story
    • Logan jD4PjnscE4XmlzgsuqY0 — pro clone, young storyteller
    • Brian nPczCjzI2devNBz1zQrb — the legacy default; labeled social_media, reads more "AI" than Bill
    • A/B sample these in your reference Remotion project before committing
  • Voices listing requires voices_read permission. Some keys don't have it; if you can't GET /v1/voices, fall back to known IDs.
  • Music API rejects brand names in prompts. "Apple keynote", "Linear launch trailer" etc. trigger a TOS violation. Describe the vibe without naming brands ("cinematic instrumental for a modern technology launch trailer", "pulsing electronic beat with arpeggiated synthesizer melody").
  • Music starts with leading silence (~1-2s) by default. The generator's silenceremove ffmpeg pass strips it so playback hits at frame 0. Keep that filter in place.
  • Sound-effects minimum duration is 0.5s. Anything below that the API errors. Round up.
  • Music volume: 0.10 reads as silent under narration; 0.15-0.18 is the sweet spot — clearly there but doesn't fight the voice.

Pitfalls to avoid

  1. Adding <Audio> without <Sequence>: it'll play continuously from frame 0. Use <Series.Sequence> or <Sequence from={...}> to place audio at specific positions.
  2. Computing absolute frame constants that drift when audio changes. Always express as BEAT_X + offset. Re-derives automatically when you regen audio.
  3. JSON imports in Node generators: script.ts should not import from remotion. Import staticFile lazily where needed.
  4. Mixing too many accents. One accent per scene. If a scene has both a play button and a check icon and a highlight, you've lost the focal point.
  5. Studio scrub showing "blacked-out first 10s": that's a thumbnail cache issue in Remotion Studio — the rendered MP4 has the visuals. Re-extract a frame with ffmpeg -ss N to verify.
  6. API keys in chat/logs: rotate any key the user pastes into a conversation. Always store in .env (gitignored).
  7. Hard-coded prompt text in scenes: the same prompt may appear in the visual chat input, the SCRIPT.md, and the audio narration. Keep the audio version in script.ts as the single source of truth and reference it from visuals where appropriate.
  8. Closing on "Congrats.": the audience remembers the brand, not the celebration. Close with the chat callback + brand stamp.

Reusable scenes (copy & adapt)

The scene library is written to be reusable. For a new launch video, copy what fits and edit data + copy:

Component Use for
HeroBackground The looped hero background video
GlassCursor Multiplayer-style "you" cursor with label pill
CompanyTable Any populating tabular content with cascading columns
AgentDashboard Google-Calendar week-view with event cards
AgentRunDetail Step-by-step tool-call trace with reasoning headers
MemoryPanel Stats + dashboard preview pattern
Confetti Celebration burst (use sparingly, once per video max)
ClosingCard The "Inviting" chat callback closing pattern
HeroChatMockup (in brand/motion) Standalone chat shell for stills/static use

For new components, follow the same pattern:

  • Props for frame anchors (cardInFrame, firstRowFrame, rowStagger)
  • Inline styles in TSX (no separate CSS file — assets resolve via staticFile)
  • All animation values via spring, interpolate, or interpolate with Easing.bezier for smooth curves

Starting a new launch video — concrete steps

# 1. Scaffold the project (or copy a reference Remotion project)
cp -R motion/launch-video motion/<new-video-name>
cd motion/<new-video-name>

# 2. Reset state
rm -rf node_modules out
rm script.timings.json sfx.timings.json music.timings.json
echo "{}" > script.timings.json
echo "{}" > sfx.timings.json
echo "{}" > music.timings.json
rm -rf ../../brand/motion/audio/launch-narration/* \
       ../../brand/motion/audio/sfx/* \
       ../../brand/motion/audio/music/*

# 3. Install + add API key
npm install
cp .env.example .env  # paste ELEVENLABS_API_KEY

# 4. Edit script.ts with the new beats
# 5. Edit OpeningScene.tsx to wire the new beats to scenes
# 6. Edit sfx.ts + music.ts prompts
# 7. Generate audio
npm run generate-all

# 8. Render + spot-check
npm run render:landscape
# repeat: tweak → render → check frames with ffmpeg

What this skill does NOT do

  • Doesn't pick the brief / strategy. The user supplies the messages.
  • Doesn't produce voice-over scripts from scratch — the human writes the beats. The skill structures + animates them.
  • Doesn't produce music compositions — relies on ElevenLabs Music API.
  • Doesn't render in 4K (1080p is the ceiling here; bumping to 4K means re-encoding hero-bg.mp4 and tuning render performance).
  • Doesn't auto-publish to social channels. The MP4 lands in out/; publishing to YouTube / LinkedIn / etc. is on the user.

After the render: upload + log

Once the MP4 renders cleanly:

  1. Upload to Drive via mcp__claude_ai_Google_Drive__create_file into your videos folder (<YOUR_DRIVE_VIDEOS_FOLDER>). Title pattern <feature> · launch · YYYY-MM-DD.mp4.
  2. Log in Notion Content DB (data source <YOUR_NOTION_CONTENT_DB_ID>). Create the row with Title, Format=Video, Channel (LinkedIn / YouTube / X per where it's going), Pillar=Promotional, Status=Scripting (if awaiting review) or Scheduled, and paste the Drive viewUrl into Drive Assets.

See also

  • Reference implementation (in source repo): <YOUR_REFERENCE_VIDEO_PATH>
  • Brand design system: <YOUR_BRAND_DOC>
  • Brand tokens (motion subsystem): <YOUR_BRAND_TOKENS_PATH>
  • ElevenLabs docs: https://elevenlabs.io/docs (text-to-speech, sound-generation, music)
  • Remotion docs: https://www.remotion.dev/docs/
1---
2name: launch-video
3description: Build a 30-60s motion-graphics launch video for a <YOUR_BRAND> product or feature. Remotion 4 React composition + ElevenLabs AI narration + sound effects + background music, beat-anchored timing, brand-aligned design system. Use when asked to "create a launch video", "make a product video", "video for X feature", "launch a new feature", or "/launch-video".
4---
5 
6# Launch video creator
7 
8Builds a **30-60s motion-graphics launch video** for a <YOUR_BRAND>
9product or feature, end-to-end:
10 
11- **Remotion 4** React composition rendered to MP4 (1920×1080 + 1080×1080)
12- **ElevenLabs** AI narration (Bill voice by default), per-event sound
13 effects, and a background music bed
14- **Beat-anchored timing**: every visual phase reads its start frame from
15 measured audio durations in `script.timings.json`. Edit copy → regen audio
16 → all visuals auto-shift. No manual frame nudging.
17- If your brand has a motion subsystem (glass/cursor/tool-pill components),
18 inherit from there. The reference patterns described below are one valid
19 system: a **glassmorphic motion subsystem** (chat shells, cursor, tool
20 pills) layered over a **clean white tabular system** (results tables,
21 dashboards, traces).
22 
23If your repo has a reference Remotion project, point this skill at it.
24Otherwise the patterns described below stand alone. Reference
25implementation path in the source repo: `<YOUR_REFERENCE_VIDEO_PATH>`.
26 
27---
28 
29## When to use
30 
31Trigger on:
32- "Create a launch video for X"
33- "Make a launch video / product video / feature reveal"
34- "Render a video for the [feature]"
35- User explicitly types `/launch-video`
36 
37Skip for:
38- Static social graphics → `/graphics-designer`
39- Slide decks / webinars → your decks pipeline
40- Short ad clips < 8s → these can usually be a single Remotion still or a
41 one-scene composition; this skill's full pipeline is overkill.
42- **Raw recorded footage** (talking heads, webinar recordings, founder
43 videos, customer interviews, screen-capture demos) → use `/video-use`
44 instead. That skill cuts on word boundaries from a Scribe transcript,
45 removes filler words, color grades, and burns subtitles. This skill is
46 for **synthetic motion graphics** built from scratch in Remotion. The
47 two compose: a `/video-use` edit can spawn Remotion overlay slots for
48 branded animation inserts, but the cut comes from `/video-use`.
49 
50---
51 
52## Architecture in one diagram
53 
54```
55motion/<video-name>/
56├── package.json # remotion 4 + react 19 + tsx + dotenv + mp3-duration
57├── remotion.config.ts # publicDir → ../../brand/motion (single asset source)
58├── tsconfig.json
59├── SCRIPT.md # human-readable narration script (per beat)
60├── .env # ELEVENLABS_API_KEY (gitignored!)
61├── .env.example
62├── generate-audio.ts # ElevenLabs narration runner, hash-cached per beat
63├── generate-sfx.ts # ElevenLabs sound-generation runner, hash-cached
64├── generate-music.ts # ElevenLabs music runner + leading-silence trim
65├── script.timings.json # narration durations (generated)
66├── sfx.timings.json # SFX durations (generated)
67├── music.timings.json # music duration (generated)
68└── src/
69 ├── Root.tsx # registerRoot
70 ├── Video.tsx # composition registry + LaunchVideoComposition wrapper
71 ├── theme.ts # fps + duration + colors (mirrors <YOUR_BRAND_TOKENS_PATH>)
72 ├── script.ts # narration beats (id, phase, text)
73 ├── timings.ts # loader for script.timings.json + beatStartFrame()
74 ├── sfx.ts # SFX clip definitions (anchored to frames)
75 ├── music.ts # music prompt + volume
76 ├── Narration.tsx # narration-only Sequence track
77 ├── SoundDesign.tsx # narration + SFX + music combined
78 └── scenes/
79 ├── HeroBackground.tsx # looped /video/hero-bg.mp4
80 ├── OpeningScene.tsx # the orchestration scene (anchors all phases)
81 ├── GlassCursor.tsx # multiplayer-style "you" cursor
82 ├── CompanyTable.tsx # populating data table with column reveals
83 ├── AgentDashboard.tsx # Google-Calendar week view
84 ├── AgentRunDetail.tsx # tool-call trace view
85 ├── MemoryPanel.tsx # stats + sparkline dashboard
86 ├── Confetti.tsx # particle burst
87 └── ClosingCard.tsx # closing chat callback (the "Inviting" pattern)
88```
89 
90Assets live in `brand/motion/`:
91- `video/hero-bg.mp4` + poster (your brand's hero background loop · e.g.
92 an ambient video at `brand/motion/video/hero-bg.mp4`)
93- `logos/{models,tools,companies,sequencers}/` — third-party brand marks
94- `audio/{launch-narration,sfx,music}/` — generated mp3s (committed for
95 reproducible renders)
96- `components/HeroChatMockup.tsx` — framework-agnostic chat shell
97 
98---
99 
100## Workflow for a new launch video
101 
102### 1. Brief
103 
104Get from the user:
105- **Audience**: who is this for (GTM teams? Engineers? Investors?)
106- **Runtime**: target seconds (default 30-45s; 60s+ feels long for hype)
107- **Key messages**: 4-8 things to communicate, in narrative order
108- **Output formats**: landscape (web/LinkedIn), square (IG/feed), or both
109 
110### 2. Outline beats
111 
112Each beat = one narration sentence that lands during one visual phase.
113Typically **6-8 beats**. Sum of beat audio lengths = total runtime.
114Beat lengths target **3-7s** each.
115 
116For each beat capture: `id`, `phase` (one-line visual description), `text`
117(spoken line, 10-20 words).
118 
119### 3. Write SCRIPT.md
120 
121Save the script as a sibling of `package.json` for human review.
122Format:
123 
124```md
125## Beat N — Phase name
126**Frames** ~start–end (seconds) · **target ~Nwords**
127 
128> "Spoken line here."
129 
130**Visual sync:** what happens on screen.
131```
132 
133### 4. Build `src/script.ts`
134 
135Mirrors SCRIPT.md as data. The narration generator and the composition
136both import `SCRIPT`. **No Remotion imports here** so generators can run
137in plain Node:
138 
139```ts
140export interface Beat { id: string; phase: string; text: string; }
141export const SCRIPT: Beat[] = [...];
142export const AUDIO_SUBDIR = "audio/launch-narration";
143export function audioPath(id: string) { return `${AUDIO_SUBDIR}/${id}.mp3`; }
144```
145 
146### 5. Generate narration
147 
148```bash
149cd motion/<video-name>
150cp .env.example .env # paste ELEVENLABS_API_KEY
151npm install
152npm run generate-audio
153```
154 
155This creates `brand/motion/audio/launch-narration/{beat-id}.mp3` and
156writes durations to `script.timings.json`. Hashes by beat text so
157unchanged beats are skipped on subsequent runs (cheap iteration).
158 
159### 6. Build the visual scene
160 
161In `OpeningScene.tsx`:
162 
1631. Compute beat starts at module load:
164 ```ts
165 const HERO_BEAT = beatStart("hero", 0); // → 0
166 const DATABASE_BEAT = beatStart("database", 0); // → 171 (after hero finishes)
167 // ... etc
168 ```
1692. Express every animation frame as `BEAT_X + offset`:
170 ```ts
171 const BADGE_IN = HERO_BEAT + 6;
172 const TYPE_START = HERO_BEAT + 38;
173 const TOOLS_START = HERO_BEAT + 115; // synced to "GTM stack" lyric
174 const CURSOR_PRESS = HERO_BEAT + 165;
175 ```
1763. Cross-fade between phase scenes using opacity gates per beat.
177 
178### 7. Generate SFX (optional but high-impact)
179 
180Define click/transition moments in `src/sfx.ts`. Anchor each clip to a
181specific `fromFrame` using the same `beatStartFrame()` helper. Example
182clips that earn their place:
183- typing texture under prompt animation
184- crisp click on cursor presses
185- celebratory pop on "enroll" / completion moments
186- subtle swell on closing card reveal
187 
188```bash
189npm run generate-sfx
190```
191 
192### 8. Generate music
193 
194Define one prompt + duration in `src/music.ts`. `generate-music.ts`
195trims leading silence automatically (ElevenLabs music often opens with
196a quiet bar that reads as "no music" against narration).
197 
198```bash
199npm run generate-music
200```
201 
202### 9. Iterate with renders
203 
204```bash
205npm run render:landscape
206```
207 
208Rendering takes ~30-90s. **Always re-encode the output to `yuv420p` TV
209range** for QuickTime compatibility — the bg video is `yuvj420p` (JPEG
210range) and the propagation breaks playback in some players:
211 
212```bash
213ffmpeg -y -i out/launch-landscape.mp4 \
214 -c:v libx264 -profile:v high -level:v 4.0 \
215 -pix_fmt yuv420p -color_range tv -crf 18 -c:a copy \
216 out/launch-landscape-fixed.mp4
217mv out/launch-landscape-fixed.mp4 out/launch-landscape.mp4
218```
219 
220Use `ffmpeg -ss N -i ... -frames:v 1 /tmp/check.jpg` to spot-check
221specific timestamps without watching the whole render.
222 
223---
224 
225## Design rules
226 
227### Voice (visual + spoken)
228- **Never** use em dashes. Periods, commas, colons, parens, middot only.
229- Banned words anywhere: `leverage`, `synergy`, `robust`, `world-class`,
230 `seamless`, `intuitive`, `powerful`, `innovative`.
231- Numerals beat adjectives ("8 tools" not "many tools").
232- Terse, concrete. No hedging.
233- Closing: **brand-led, not "Congrats."** The strongest closing pattern
234 found here: *"Inviting" kicker → chat input with a new prompt typed in
235 → URL signature*. The chat callback to the opening beats celebration
236 every time.
237 
238### Color (example tokens · adjust to your brand)
239Light, neutral. One accent only, used once per scene where it earns
240meaning (live dot, highlight, success state).
241 
242| Token | Hex | Use |
243|---|---|---|
244| `--bg` | `#fafafa` | page bg |
245| `--surface` | `#ffffff` | cards, dashboards |
246| `--ink` | `#0a0a0a` | primary text + numerals |
247| `--muted` | `#71717a` | secondary text |
248| `--line` | `#e4e4e7` | borders |
249| `--accent` | `#10b981` | the one accent |
250 
251### Typography
252- Stack: `'Helvetica Neue', Helvetica, Arial, sans-serif`
253- Mono (kickers, code, labels): `ui-monospace, 'SFMono-Regular', Menlo`
254- Hero typography: weight 450 with tight tracking (`-0.05em`)
255- Mono kicker style: 11-14px, uppercase, letter-spacing `0.16-0.18em`,
256 color `#71717a` or `#a1a1aa`
257- Bold/medium parts in muted-grey body text mirror the brand pattern:
258 `<span style={{ color: "#0a0a0a", fontWeight: 500 }}>bold</span>` vs
259 surrounding `#71717a` text.
260 
261### Two visual modes
262Pick one per scene; don't mix:
2631. **Glassmorphic / in-product** — chat shell, cursor, tool pills,
264 over the hero bg video. White glass with `backdrop-filter: blur(28px)`,
265 `rgba(255,255,255,0.45)`.
2662. **Clean white / tabular** — tables, dashboards, traces, memory panel.
267 `bg #ffffff`, `1px solid #e4e4e7`, subtle drop shadow.
268 
269The bg-fade transition between modes is one of the most cinematic moments;
270budget ~20-30 frames for it and use `Easing.bezier(0.4, 0, 0.2, 1)`
271(material standard) for smoothness.
272 
273---
274 
275## Animation rules
276 
2771. **Damping 22-28 on springs.** Below 20 you get bounce that reads as
278 amateur. Use 14-18 only when you intentionally want a "pop".
2792. **Tighter staggers > slower.** First instinct is always to slow down;
280 the second pass usually involves cutting staggers in half. Default
281 stagger between cascading items: 3-6 frames.
2823. **Sync visuals to lyrics where it matters.** If the narration says
283 "GTM stack", the tool pills should fly in *on that word* — not 3s
284 before. Use `with_timestamps` from ElevenLabs for word-level sync,
285 or estimate from beat duration / word count if approximate is fine.
2864. **Reserve row heights.** When tables/cards animate text in,
287 `minHeight` on the row prevents layout from jumping as content fills.
288 Looks janky if rows grow during the cascade.
2895. **Conditional render rather than 0-opacity if it would create a tall
290 empty rectangle.** Cards that haven't started revealing yet should
291 not occupy space.
2926. **Crossfade between scene modes**, don't hard-cut. Each major scene
293 gets an `opacity` gate animated via `interpolate` + ease curves.
294 
295---
296 
297## ElevenLabs gotchas
298 
299- **Default voice + model**: `generate-audio.ts` defaults to **Bill**
300 (`pqHfZKP75CvOlQylNhV4`) on `eleven_multilingual_v2`. Bill is the
301 `advertisement` use-case voice in ElevenLabs' library: wise, mature,
302 crisp. Reads as a real ad voiceover, not "AI guy on social media".
303 `multilingual_v2` is the most stable + lifelike model for production
304 narration. **Do not use `eleven_turbo_v2_5` for launch videos** —
305 it's the fast/cheap model and the difference is audible against a
306 hero bg video. Turbo is fine for previews / SFX timing checks, not
307 the final render.
308- **Voice settings** baked into the script: `stability 0.40`,
309 `similarity_boost 0.75`, `style 0.30`, `use_speaker_boost true`.
310 Per ElevenLabs best-practices: stability under 0.30 is unstable,
311 over 0.60 is monotone; similarity 0.75 is the docs sweet spot;
312 style 0.20–0.40 adds expressiveness without drift. Don't push style
313 above 0.4 unless you want noticeable inflection swings.
314- **Voice cache key includes voice + model + settings.** Swapping any
315 of those (or editing beat text) invalidates the cached MP3 and
316 re-renders the beat. Just edit `.env` (`VOICE_ID=...` `MODEL_ID=...`)
317 or `generate-audio.ts` and re-run `npm run generate-audio`.
318- **Other narration-grade voices** if Bill doesn't fit:
319 - **Eric** `cjVigY5qzO86Huf0OWal` — smooth, trustworthy, modern SaaS feel
320 - **Chuck Miller** `HIGUfNOdjuWQwwapnTRW` — pro clone, deep raspy, cinematic
321 - **George** `JBFqnCBsd6RMkjVDRZzb` — British storyteller, narrative_story
322 - **Logan** `jD4PjnscE4XmlzgsuqY0` — pro clone, young storyteller
323 - **Brian** `nPczCjzI2devNBz1zQrb` — the legacy default; labeled `social_media`, reads more "AI" than Bill
324 - A/B sample these in your reference Remotion project before committing
325- **Voices listing requires `voices_read` permission**. Some keys
326 don't have it; if you can't `GET /v1/voices`, fall back to known IDs.
327- **Music API rejects brand names** in prompts. "Apple keynote",
328 "Linear launch trailer" etc. trigger a TOS violation. Describe the
329 vibe without naming brands ("cinematic instrumental for a modern
330 technology launch trailer", "pulsing electronic beat with arpeggiated
331 synthesizer melody").
332- **Music starts with leading silence** (~1-2s) by default. The
333 generator's `silenceremove` ffmpeg pass strips it so playback hits at
334 frame 0. Keep that filter in place.
335- **Sound-effects minimum duration is 0.5s.** Anything below that the
336 API errors. Round up.
337- **Music volume**: `0.10` reads as silent under narration; `0.15-0.18`
338 is the sweet spot — clearly there but doesn't fight the voice.
339 
340---
341 
342## Pitfalls to avoid
343 
3441. **Adding `<Audio>` without `<Sequence>`**: it'll play continuously
345 from frame 0. Use `<Series.Sequence>` or `<Sequence from={...}>` to
346 place audio at specific positions.
3472. **Computing absolute frame constants** that drift when audio changes.
348 Always express as `BEAT_X + offset`. Re-derives automatically when
349 you regen audio.
3503. **JSON imports in Node generators**: `script.ts` should not import
351 from `remotion`. Import `staticFile` lazily where needed.
3524. **Mixing too many accents.** One accent per scene. If a scene has
353 both a play button and a check icon and a highlight, you've lost
354 the focal point.
3555. **Studio scrub showing "blacked-out first 10s"**: that's a thumbnail
356 cache issue in Remotion Studio — the rendered MP4 has the visuals.
357 Re-extract a frame with `ffmpeg -ss N` to verify.
3586. **API keys in chat/logs**: rotate any key the user pastes into a
359 conversation. Always store in `.env` (gitignored).
3607. **Hard-coded prompt text in scenes**: the same prompt may appear in
361 the visual chat input, the SCRIPT.md, and the audio narration. Keep
362 the audio version in `script.ts` as the single source of truth and
363 reference it from visuals where appropriate.
3648. **Closing on "Congrats."**: the audience remembers the brand, not
365 the celebration. Close with the chat callback + brand stamp.
366 
367---
368 
369## Reusable scenes (copy & adapt)
370 
371The scene library is written to be reusable. For a new launch video,
372copy what fits and edit data + copy:
373 
374| Component | Use for |
375|---|---|
376| `HeroBackground` | The looped hero background video |
377| `GlassCursor` | Multiplayer-style "you" cursor with label pill |
378| `CompanyTable` | Any populating tabular content with cascading columns |
379| `AgentDashboard` | Google-Calendar week-view with event cards |
380| `AgentRunDetail` | Step-by-step tool-call trace with reasoning headers |
381| `MemoryPanel` | Stats + dashboard preview pattern |
382| `Confetti` | Celebration burst (use sparingly, once per video max) |
383| `ClosingCard` | The "Inviting" chat callback closing pattern |
384| `HeroChatMockup` (in brand/motion) | Standalone chat shell for stills/static use |
385 
386For new components, follow the same pattern:
387- Props for frame anchors (`cardInFrame`, `firstRowFrame`, `rowStagger`)
388- Inline styles in TSX (no separate CSS file — assets resolve via `staticFile`)
389- All animation values via `spring`, `interpolate`, or `interpolate` with
390 `Easing.bezier` for smooth curves
391 
392---
393 
394## Starting a new launch video — concrete steps
395 
396```bash
397# 1. Scaffold the project (or copy a reference Remotion project)
398cp -R motion/launch-video motion/<new-video-name>
399cd motion/<new-video-name>
400 
401# 2. Reset state
402rm -rf node_modules out
403rm script.timings.json sfx.timings.json music.timings.json
404echo "{}" > script.timings.json
405echo "{}" > sfx.timings.json
406echo "{}" > music.timings.json
407rm -rf ../../brand/motion/audio/launch-narration/* \
408 ../../brand/motion/audio/sfx/* \
409 ../../brand/motion/audio/music/*
410 
411# 3. Install + add API key
412npm install
413cp .env.example .env # paste ELEVENLABS_API_KEY
414 
415# 4. Edit script.ts with the new beats
416# 5. Edit OpeningScene.tsx to wire the new beats to scenes
417# 6. Edit sfx.ts + music.ts prompts
418# 7. Generate audio
419npm run generate-all
420 
421# 8. Render + spot-check
422npm run render:landscape
423# repeat: tweak → render → check frames with ffmpeg
424```
425 
426---
427 
428## What this skill does NOT do
429 
430- Doesn't pick the brief / strategy. The user supplies the messages.
431- Doesn't produce voice-over scripts from scratch — the human writes
432 the beats. The skill structures + animates them.
433- Doesn't produce music compositions — relies on ElevenLabs Music API.
434- Doesn't render in 4K (1080p is the ceiling here; bumping to 4K means
435 re-encoding hero-bg.mp4 and tuning render performance).
436- Doesn't auto-publish to social channels. The MP4 lands in `out/`;
437 publishing to YouTube / LinkedIn / etc. is on the user.
438 
439---
440 
441## After the render: upload + log
442 
443Once the MP4 renders cleanly:
444 
4451. **Upload to Drive** via `mcp__claude_ai_Google_Drive__create_file`
446 into your videos folder (`<YOUR_DRIVE_VIDEOS_FOLDER>`). Title pattern
447 `<feature> · launch · YYYY-MM-DD.mp4`.
4482. **Log in Notion** Content DB (data source
449 `<YOUR_NOTION_CONTENT_DB_ID>`). Create the row with Title,
450 Format=Video, Channel (LinkedIn / YouTube / X per where it's going),
451 Pillar=Promotional, Status=Scripting (if awaiting review) or
452 Scheduled, and paste the Drive `viewUrl` into `Drive Assets`.
453 
454---
455 
456## See also
457 
458- Reference implementation (in source repo): `<YOUR_REFERENCE_VIDEO_PATH>`
459- Brand design system: `<YOUR_BRAND_DOC>`
460- Brand tokens (motion subsystem): `<YOUR_BRAND_TOKENS_PATH>`
461- ElevenLabs docs: https://elevenlabs.io/docs (text-to-speech, sound-generation, music)
462- Remotion docs: https://www.remotion.dev/docs/
463 

Discussion

Alternatives

/bragTurn the current project website into a short, polished, shareable launch video using Hyperframes. Use when someone says "/brag", "let's brag about this", "make a launch video", "turn this into a video", or wants to share what they built. Reads the project code directly — no live URL or screenshots needed.Business & ops · MIT/brag-slimTurn a project directory or a website URL into a short, shareable launch video with music, motion, and share copy. One file, no bundled assets — built entirely by the model with the tools already on the machine. Use when someone says "/brag-slim", "let's /brag about this", "brag about <url>", "make a launch video", or wants to show off what they built. If the /brag skill is also installed, let /brag handle those phrases; it hands off here on Opus 5.5.Business & ops · MITBusiness motion filmPlan, build and quality-check a premium short commercial for a real business (roofing, property, ecommerce, B2B software) using AI-generated footage, code-built motion (HTML/GSAP), selective Three.js and an independent-critic "Gauntlet" loop. Use when asked to make a launch-style / SaaS-style video, business ad, explainer, sample reel or pitch video, or to review and improve one. Encodes motion principles distilled from 28 professional launch films, a quality bar, audio rules and a business-offer playbook.Business & ops · MITAI Product Launch PlaybookLaunch your AI product to global attention — the playbook behind Manus, Devin, and AFFiNE's breakout launches. Covers AI-specific GTM strategy, hype cycle management, waitlist tactics, and multi-market rollout for maximum day-one impact.Business & ops · MIT