Motion Graphics
Produce silent MP4 motion-graphic clips from a markdown video script using Remotion. The clips are overlay B-roll the user drops onto a 4K 30fps voiceover timeline in their video editor.
When to Use
Run this from a video folder — the folder holding source material for one YouTube video, e.g. C:\videos\rls\. Use when the user:
- says "build motion graphics for this video"
- pastes or points at a script and wants overlay clips made from it
- mid-edit, says "I want this part to be a motion graphic" — re-invoke and add one clip
Do not use this for full standalone explainer videos. The output is overlay content for an existing voice track.
Output Spec
Every clip the skill produces is:
- 3840 x 2160 (4K), 30 fps, H.264
- silent — no audio track. The user has their own voice recording.
- duration matches the natural read time of the script section it covers (see Phase 5). Most clips end up 2-15 seconds; longer is allowed but consider splitting (see "Long clips" below).
- rendered to
motion-graphics/out/<clip-id>-{A,B,C}.mp4
3 variants are rendered per clip. The user picks one. The other two MP4s move to out/_rejected/ (do not delete — keep for recovery). All three .tsx files stay in src/clips/.
Workflow
Phase 1 — Locate the script (pre-flight gate)
Before scaffolding or any other work, confirm a script exists in the video folder.
List .md files in the video folder (top level only, not in subfolders).
If exactly one .md file is found, silently use it as the script. Do not ask the user to confirm — they already pointed you at this folder.
If multiple .md files are found, ask the user which one is the script (genuine ambiguity, can't guess).
If none is found, stop immediately. Tell the user verbatim:
I couldn't find a .md script in <folder>. Either drop the script there as a .md file, or paste the script content in chat now and I'll save it to <folder>/script.md.
Then wait. If the user pastes the content, save it to <folder>/script.md first. Do not proceed past this phase until a script is on disk in the video folder.
Once located, never modify the source file — it's the source of truth. The skill will work against a copy inside the Remotion project (see Phase 2).
Phase 2 — Set up the project (once per video)
Run from the video folder so the subfolder is created in place.
- Create
motion-graphics/ subfolder.
- Scaffold a blank Remotion project inside it:
npx create-video@latest --yes --blank --no-tailwind motion-graphics
- Copy the located script into the project as the canonical working copy. Use the right command for the shell:
# bash / git-bash
cp <located-script>.md motion-graphics/script.md
# PowerShell
Copy-Item <located-script>.md motion-graphics/script.md
The original file in the video folder remains untouched.
- Install the official Remotion AI skill into the new project so its rules are available next time an agent works here:
cd motion-graphics && npx skills add remotion-dev/skills
- Install supporting Remotion packages:
npm install @remotion/shapes @remotion/transitions @remotion/google-fonts @remotion/paths @remotion/animation-utils @remotion/layout-utils
- Copy the skill's bundled assets into the new project:
skills/motion-graphics/theme.ts -> motion-graphics/src/theme.ts
skills/motion-graphics/STYLE.md -> motion-graphics/STYLE.md
- Read
STYLE.md and src/theme.ts before writing any clip code. Read the official Remotion skill's SKILL.md and any rules/*.md that match the clips you're about to build (e.g. rules/text-animations.md, rules/transitions.md, rules/spring-physics.md).
Phase 3 — Gather external context
The script often references URLs (docs, blog posts, tldraw boards, GitHub repos, diagrams). Before proposing clips, try to fetch what's relevant so clip ideas can build on real reference material.
- Scan
script.md for URLs (markdown links, bare URLs, "see X" references). Ignore URLs inside <aside> blocks — those belong to the user's editor-side B-roll, not the clips this skill generates. Exception: if you've decided to propose a clip immediately adjacent to an aside and the URL inside the aside genuinely supports that clip's visual, treat it as load-bearing and fetch it.
- For each URL that's plausibly visual or referential context (not just a citation), attempt
WebFetch.
- If fetch returns meaningful content (article text, README, diagram description), keep it as context for clip design.
- If fetch fails or returns nothing useful (auth-walled, client-rendered SPA like tldraw/Figma/Excalidraw, 404), log the URL to
motion-graphics/refs/blocked-urls.md with a one-line note of why it failed, then continue. Do not pause to ask. If the user later notices a clip is missing visual context that URL would have provided, they'll bring it up in revision.
- Save any fetched text context to
motion-graphics/refs/<slug>.md. Reference these in clip notes files.
If no URLs are present or none need fetching, skip this phase and move on.
Phase 4 — Propose clips
Parse script.md and produce a candidate clip list. The bar is illustrative value: every clip you propose must answer "yes" to "does a visual genuinely help the viewer understand what the voice is saying here?". If the answer is "not really, it would just be filler", do not propose a clip there.
Selection rules in priority order:
- Intro hook — propose 1 clip for the opening 2-3 sentences. The intro is a special case: even if there's no concrete concept to illustrate, a punchy typographic title-card works because the goal is attention, not comprehension.
- Code blocks — propose 1 clip per meaningful code block (3+ lines). Code reveals are pure illustration.
- Enumerated/sequential content — lists of steps, recipes, ordered procedures. The "update schema -> migrate -> tighten schema" pattern is a perfect candidate.
- Concept comparisons — "User A vs User B", before/after, "Firebase does X, Convex does Y", architecture diagrams.
- Concrete hypotheticals — "imagine if...", "let's say we've got...", anything that sets up a scenario you can show.
- Outro/takeaway — only if there's a concrete idea to visualise. "We have zero downtime" is sentiment, not concept — skip. "Three rules to remember" is concept — propose.
Things to skip — do not propose clips for:
<aside> blocks. These are the user's editing notes to themselves about B-roll they will overlay manually in their editor (e.g. "show sweaty balmer gif", "point to the hat"). They are not briefs for the motion-graphics skill. Treat them as comments — read them for context, do not generate clips from them.
- Pure sentiment / opinion — "this is really powerful", "I love this", "trust me".
- Conversational filler — "anyways", "let me explain", "okay so".
- Sections where the spoken words are the whole point — a personal story, a joke, a meta-comment about the video. Audio-only is correct here.
Announce the proposed list to the user as a table, then proceed straight to Phase 5. Do not pause for approval — the user picks variants after the renders are done, not before, because they need to see the clips to react usefully. Each entry:
- clip id (
clip-01, clip-02, ...) — these are also the Remotion composition IDs (see Phase 5 for naming rules).
- 1-2 lines of the script section it covers (quoted)
- one-line visual concept
- estimated duration in seconds (based on natural read time — see Phase 5 step 4)
If the user wants to redirect mid-flight (e.g. "drop clip-04, add one for the X paragraph"), they'll say so when they see the list. Otherwise, keep moving.
Phase 5 — Generate 3 variants per approved clip
For each approved clip:
Write a notes file at motion-graphics/src/clips/notes/clip-NN.notes.md:
# Clip NN - <short slug>
## Script section
<verbatim paste>
## Visual brief
<one paragraph plain-English description of what the clip shows>
## Duration
<word_count> words / 2.5 wps + 0.7s buffer = <N> seconds = <N*30> frames
## Variants
- A: <one-line distinguisher>
- B: <one-line distinguisher>
- C: <one-line distinguisher>
## Chosen variant
<filled in by user later>
## Revisions
<appended over iterations>
Write 3 component files. Filenames can use underscores (e.g. src/clips/Clip01_IntroA.tsx) but Remotion composition IDs can only contain [a-zA-Z0-9-] — use dashes for variant suffixes. Each variant must be meaningfully different (see Variant Strategy).
Each clip file imports tokens from ../theme:
import { colors, fonts, motion } from '../theme';
Never hardcode colors, fonts, or timing. Use different motion.springs.* presets across variants (snappy / gentle / dramatic) so they feel different in motion language, not just composition.
Set durationInFrames to match natural read time. The clip should fully animate within the time the user would naturally read the script section out loud. Default formula:
read_seconds = word_count / 2.5
buffer_seconds = 0.7 # lets the final state breathe
durationInFrames = ceil((read_seconds + buffer_seconds) * 30)
The user can hold the final frame longer in their editor, but the clip shouldn't run longer than the spoken section.
Long clips (>15s): if the formula yields more than ~15 seconds, generate as one long clip with phased animation (e.g. multiple staggered reveals). Do not pause to ask. Flag the duration in the clip notes file so it's visible. If the user wants to split it, they'll say so in revision after seeing the rendered result — a 20s+ motion graphic is sometimes two ideas wearing a trenchcoat, but that's a judgement easier to make from the rendered output than from the script.
Register all 3 variants in src/Root.tsx as <Composition> entries with width={3840} height={2160} fps={30}. Composition id props must use dashes only:
<Composition id="clip-01-a" component={Clip01IntroA} durationInFrames={120} ... />
<Composition id="clip-01-b" component={Clip01IntroB} durationInFrames={120} ... />
<Composition id="clip-01-c" component={Clip01IntroC} durationInFrames={120} ... />
Type-check before rendering. 4K renders take minutes; surfacing TypeScript errors first costs seconds:
# from inside motion-graphics/
npx tsc --noEmit
Fix everything it reports (including unused imports) before moving on.
Render each. Run from inside motion-graphics/ — the render command uses the current working directory's Remotion config:
# from inside motion-graphics/
npx remotion render clip-01-a --codec=h264 out/clip-01-A.mp4
npx remotion render clip-01-b --codec=h264 out/clip-01-B.mp4
npx remotion render clip-01-c --codec=h264 out/clip-01-C.mp4
Report the 3 MP4 paths to the user and ask them to pick one.
Phase 6 — User picks; losers archived
When the user picks A/B/C:
- Move the two unpicked MP4s to
out/_rejected/. Do not delete.
- Update
clip-NN.notes.md "Chosen variant" line.
- Leave all three
.tsx files in src/clips/ — they're cheap to keep and useful if the user reverses the decision.
Phase 7 — Revisions
When the user asks for changes to a chosen clip:
- Read
clip-NN.notes.md first — it has the brief and prior revisions.
- Edit the chosen variant file only. Don't touch the rejected siblings.
- Re-render with the same output name (overwrites).
- Append the revision to the notes file with what changed and why.
Phase 8 — Mid-edit additions
When the user re-invokes the skill and says "add a clip for this paragraph":
- Append a new entry to the clip list with the next id.
- Run Phase 5 for just that clip.
Variant Strategy
When generating 3 variants per clip, each variant must differ along at least one of:
- Composition — centered vs split-screen vs grid vs sequential timeline
- Reveal language — typewriter, scale-spring, slide-from-edge, mask-wipe, stagger-in
- Visual metaphor — diagram, code reveal, abstract shape, side-by-side comparison, "screen frame" mock
- Motion preset — pair each variant with a different
motion.springs.* (snappy / gentle / dramatic) so the cadence feels different, not just the layout
Do not generate 3 variants that differ only in colour or timing. If you can't think of 3 distinct directions, say so and propose 2 — better fewer good variants than 3 near-identical ones.
Style Rules
STYLE.md (copied into the project at scaffold time) is the source of truth. Re-read it at the start of each session.
Headline rules to keep in mind while coding:
- No headers, footers, logos, tickers, or clip numbers on screen. Overlay content only.
- Not text-heavy. If a single moment shows more than ~15 words, redesign. The viewer is listening; the clip reinforces, it doesn't restate.
- One idea per clip. If two ideas fight, split into two clips.
- Spring motion by default. Pure fades are weak — combine opacity with scale or position.
Constraints
- Never render with audio. Strip any audio component before rendering.
- Always render 3 variants on first generation unless the user explicitly asks for fewer.
- Never modify
script.md.
- Never delete a rejected variant — TSX stays in
src/clips/, MP4 moves to out/_rejected/.
- Never skip the per-clip notes file. It carries context across sessions.
- If a script section is narrative-only and a visual would just be filler, say so and skip it instead of generating noise.
File Layout
<video folder>/
motion-graphics/
script.md
package.json
remotion.config.ts
STYLE.md
src/
Root.tsx
theme.ts
clips/
Clip01_IntroA.tsx
Clip01_IntroB.tsx
Clip01_IntroC.tsx
Clip03_DiagramA.tsx
...
notes/
clip-01.notes.md
clip-03.notes.md
out/
clip-01-A.mp4
clip-03-A.mp4
_rejected/
clip-01-B.mp4
clip-01-C.mp4
Bad vs Good
Bad: "Here are 3 variants of the diagram clip" — all three use the same centered layout with different accent colors.
Good: "Variant A: split-screen User A | User B with typewriter code reveal underneath. Variant B: centered Firebase-style hierarchy diagram with the insecure path highlighted in red. Variant C: sequential timeline showing request -> DB query -> policy check arrows."
Bad: A clip that repeats the entire spoken sentence as on-screen text.
Good: A clip that shows one keyword or visual cue that reinforces the sentence. The viewer is listening, not reading.
// Bad: hardcoded values, fade-only, multiple competing ideas
export const ClipBad = () => {
const frame = useCurrentFrame();
return (
<AbsoluteFill style={{ background: '#000', color: '#fff' }}>
<h1 style={{ opacity: frame / 30 }}>First idea</h1>
<h2 style={{ opacity: frame / 60 }}>Second idea fighting for attention</h2>
</AbsoluteFill>
);
};
// Good: theme tokens, named spring preset, deliberate accent pick
import { spring, useCurrentFrame, useVideoConfig, AbsoluteFill } from 'remotion';
import { colors, fonts, motion } from '../theme';
export const ClipGood = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const t = spring({ frame, fps, config: motion.springs.snappy });
return (
<AbsoluteFill style={{
background: `linear-gradient(180deg, ${colors.bg}, ${colors.bgGradientEnd})`,
fontFamily: fonts.display,
color: colors.text,
}}>
<h1 style={{
fontSize: fonts.sizes.headline,
transform: `scale(${t})`,
color: colors.accents.teal,
}}>
One Big Idea
</h1>
</AbsoluteFill>
);
};
Checklist
1---2name: motion-graphics3description: Generate silent motion-graphic MP4 clips for a tech-explainer YouTube video using Remotion. The clips are overlay B-roll the user drops onto a voiceover timeline. Use when the user is working from a video folder and says "build motion graphics for this video", "make motion graphics", "add a motion graphic for this section", "render this part as a clip", or wants to scaffold a Remotion project from a markdown script.4---56# Motion Graphics78Produce silent MP4 motion-graphic clips from a markdown video script using Remotion. The clips are overlay B-roll the user drops onto a 4K 30fps voiceover timeline in their video editor.910## When to Use1112Run this from a video folder — the folder holding source material for one YouTube video, e.g. `C:\videos\rls\`. Use when the user:1314- says "build motion graphics for this video"15- pastes or points at a script and wants overlay clips made from it16- mid-edit, says "I want this part to be a motion graphic" — re-invoke and add one clip1718Do not use this for full standalone explainer videos. The output is overlay content for an existing voice track.1920## Output Spec2122Every clip the skill produces is:2324- 3840 x 2160 (4K), 30 fps, H.26425- silent — no audio track. The user has their own voice recording.26- duration matches the natural read time of the script section it covers (see Phase 5). Most clips end up 2-15 seconds; longer is allowed but consider splitting (see "Long clips" below).27- rendered to `motion-graphics/out/<clip-id>-{A,B,C}.mp4`28293 variants are rendered per clip. The user picks one. The other two MP4s move to `out/_rejected/` (do not delete — keep for recovery). All three `.tsx` files stay in `src/clips/`.3031## Workflow3233### Phase 1 — Locate the script (pre-flight gate)3435Before scaffolding or any other work, confirm a script exists in the video folder.36371. List `.md` files in the video folder (top level only, not in subfolders).382. If exactly one `.md` file is found, **silently use it** as the script. Do not ask the user to confirm — they already pointed you at this folder.393. If multiple `.md` files are found, ask the user which one is the script (genuine ambiguity, can't guess).404. If **none** is found, **stop immediately**. Tell the user verbatim:41 > I couldn't find a `.md` script in `<folder>`. Either drop the script there as a `.md` file, or paste the script content in chat now and I'll save it to `<folder>/script.md`.4243 Then wait. If the user pastes the content, save it to `<folder>/script.md` first. Do not proceed past this phase until a script is on disk in the video folder.445. Once located, never modify the source file — it's the source of truth. The skill will work against a copy inside the Remotion project (see Phase 2).4546### Phase 2 — Set up the project (once per video)4748Run from the video folder so the subfolder is created in place.49501. Create `motion-graphics/` subfolder.512. Scaffold a blank Remotion project inside it:52 ```bash53 npx create-video@latest --yes --blank --no-tailwind motion-graphics54 ```553. Copy the located script into the project as the canonical working copy. Use the right command for the shell:56 ```bash57 # bash / git-bash58 cp <located-script>.md motion-graphics/script.md59 ```60 ```powershell61 # PowerShell62 Copy-Item <located-script>.md motion-graphics/script.md63 ```64 The original file in the video folder remains untouched.654. Install the official Remotion AI skill into the new project so its rules are available next time an agent works here:66 ```bash67 cd motion-graphics && npx skills add remotion-dev/skills68 ```695. Install supporting Remotion packages:70 ```bash71 npm install @remotion/shapes @remotion/transitions @remotion/google-fonts @remotion/paths @remotion/animation-utils @remotion/layout-utils72 ```736. Copy the skill's bundled assets into the new project:74 - `skills/motion-graphics/theme.ts` -> `motion-graphics/src/theme.ts`75 - `skills/motion-graphics/STYLE.md` -> `motion-graphics/STYLE.md`767. Read `STYLE.md` and `src/theme.ts` before writing any clip code. Read the official Remotion skill's `SKILL.md` and any `rules/*.md` that match the clips you're about to build (e.g. `rules/text-animations.md`, `rules/transitions.md`, `rules/spring-physics.md`).7778### Phase 3 — Gather external context7980The script often references URLs (docs, blog posts, tldraw boards, GitHub repos, diagrams). Before proposing clips, try to fetch what's relevant so clip ideas can build on real reference material.81821. Scan `script.md` for URLs (markdown links, bare URLs, "see X" references). **Ignore URLs inside `<aside>` blocks** — those belong to the user's editor-side B-roll, not the clips this skill generates. Exception: if you've decided to propose a clip immediately adjacent to an aside and the URL inside the aside genuinely supports that clip's visual, treat it as load-bearing and fetch it.832. For each URL that's plausibly visual or referential context (not just a citation), attempt `WebFetch`.843. **If fetch returns meaningful content** (article text, README, diagram description), keep it as context for clip design.854. **If fetch fails or returns nothing useful** (auth-walled, client-rendered SPA like tldraw/Figma/Excalidraw, 404), **log the URL to `motion-graphics/refs/blocked-urls.md`** with a one-line note of why it failed, then continue. Do not pause to ask. If the user later notices a clip is missing visual context that URL would have provided, they'll bring it up in revision.865. Save any fetched text context to `motion-graphics/refs/<slug>.md`. Reference these in clip notes files.8788If no URLs are present or none need fetching, skip this phase and move on.8990### Phase 4 — Propose clips9192Parse `script.md` and produce a candidate clip list. **The bar is illustrative value**: every clip you propose must answer "yes" to *"does a visual genuinely help the viewer understand what the voice is saying here?"*. If the answer is "not really, it would just be filler", do not propose a clip there.9394**Selection rules** in priority order:95961. **Intro hook** — propose 1 clip for the opening 2-3 sentences. The intro is a special case: even if there's no concrete concept to illustrate, a punchy typographic title-card works because the goal is attention, not comprehension.972. **Code blocks** — propose 1 clip per meaningful code block (3+ lines). Code reveals are pure illustration.983. **Enumerated/sequential content** — lists of steps, recipes, ordered procedures. The "update schema -> migrate -> tighten schema" pattern is a perfect candidate.994. **Concept comparisons** — "User A vs User B", before/after, "Firebase does X, Convex does Y", architecture diagrams.1005. **Concrete hypotheticals** — "imagine if...", "let's say we've got...", anything that sets up a scenario you can show.1016. **Outro/takeaway** — only if there's a concrete idea to visualise. *"We have zero downtime"* is sentiment, not concept — skip. *"Three rules to remember"* is concept — propose.102103**Things to skip — do not propose clips for**:104105- **`<aside>` blocks**. These are the user's editing notes to themselves about B-roll they will overlay manually in their editor (e.g. *"show sweaty balmer gif"*, *"point to the hat"*). They are **not** briefs for the motion-graphics skill. Treat them as comments — read them for context, do not generate clips from them.106- **Pure sentiment / opinion** — "this is really powerful", "I love this", "trust me".107- **Conversational filler** — "anyways", "let me explain", "okay so".108- **Sections where the spoken words are the whole point** — a personal story, a joke, a meta-comment about the video. Audio-only is correct here.109110**Announce the proposed list** to the user as a table, then proceed straight to Phase 5. Do not pause for approval — the user picks variants after the renders are done, not before, because they need to see the clips to react usefully. Each entry:111112- clip id (`clip-01`, `clip-02`, ...) — these are also the Remotion composition IDs (see Phase 5 for naming rules).113- 1-2 lines of the script section it covers (quoted)114- one-line visual concept115- estimated duration in seconds (based on natural read time — see Phase 5 step 4)116117If the user wants to redirect mid-flight (e.g. "drop clip-04, add one for the X paragraph"), they'll say so when they see the list. Otherwise, keep moving.118119### Phase 5 — Generate 3 variants per approved clip120121For each approved clip:1221231. Write a notes file at `motion-graphics/src/clips/notes/clip-NN.notes.md`:124 ```125 # Clip NN - <short slug>126127 ## Script section128 <verbatim paste>129130 ## Visual brief131 <one paragraph plain-English description of what the clip shows>132133 ## Duration134 <word_count> words / 2.5 wps + 0.7s buffer = <N> seconds = <N*30> frames135136 ## Variants137 - A: <one-line distinguisher>138 - B: <one-line distinguisher>139 - C: <one-line distinguisher>140141 ## Chosen variant142 <filled in by user later>143144 ## Revisions145 <appended over iterations>146 ```1472. Write 3 component files. **Filenames** can use underscores (e.g. `src/clips/Clip01_IntroA.tsx`) but **Remotion composition IDs** can only contain `[a-zA-Z0-9-]` — use dashes for variant suffixes. Each variant must be **meaningfully different** (see Variant Strategy).1483. Each clip file imports tokens from `../theme`:149 ```tsx150 import { colors, fonts, motion } from '../theme';151 ```152 Never hardcode colors, fonts, or timing. **Use different `motion.springs.*` presets across variants** (`snappy` / `gentle` / `dramatic`) so they feel different in motion language, not just composition.1534. **Set `durationInFrames` to match natural read time.** The clip should fully animate within the time the user would naturally read the script section out loud. Default formula:154 ```155 read_seconds = word_count / 2.5156 buffer_seconds = 0.7 # lets the final state breathe157 durationInFrames = ceil((read_seconds + buffer_seconds) * 30)158 ```159 The user can hold the final frame longer in their editor, but the clip shouldn't run longer than the spoken section.160161 **Long clips (>15s):** if the formula yields more than ~15 seconds, generate as one long clip with phased animation (e.g. multiple staggered reveals). Do not pause to ask. Flag the duration in the clip notes file so it's visible. If the user wants to split it, they'll say so in revision after seeing the rendered result — a 20s+ motion graphic is sometimes two ideas wearing a trenchcoat, but that's a judgement easier to make from the rendered output than from the script.1625. Register all 3 variants in `src/Root.tsx` as `<Composition>` entries with `width={3840} height={2160} fps={30}`. Composition `id` props must use dashes only:163 ```tsx164 <Composition id="clip-01-a" component={Clip01IntroA} durationInFrames={120} ... />165 <Composition id="clip-01-b" component={Clip01IntroB} durationInFrames={120} ... />166 <Composition id="clip-01-c" component={Clip01IntroC} durationInFrames={120} ... />167 ```1686. **Type-check before rendering.** 4K renders take minutes; surfacing TypeScript errors first costs seconds:169 ```bash170 # from inside motion-graphics/171 npx tsc --noEmit172 ```173 Fix everything it reports (including unused imports) before moving on.1747. Render each. **Run from inside `motion-graphics/`** — the render command uses the current working directory's Remotion config:175 ```bash176 # from inside motion-graphics/177 npx remotion render clip-01-a --codec=h264 out/clip-01-A.mp4178 npx remotion render clip-01-b --codec=h264 out/clip-01-B.mp4179 npx remotion render clip-01-c --codec=h264 out/clip-01-C.mp4180 ```1818. Report the 3 MP4 paths to the user and ask them to pick one.182183### Phase 6 — User picks; losers archived184185When the user picks A/B/C:1861871. Move the two unpicked MP4s to `out/_rejected/`. Do not delete.1882. Update `clip-NN.notes.md` "Chosen variant" line.1893. Leave all three `.tsx` files in `src/clips/` — they're cheap to keep and useful if the user reverses the decision.190191### Phase 7 — Revisions192193When the user asks for changes to a chosen clip:1941951. Read `clip-NN.notes.md` first — it has the brief and prior revisions.1962. Edit the chosen variant file only. Don't touch the rejected siblings.1973. Re-render with the same output name (overwrites).1984. Append the revision to the notes file with what changed and why.199200### Phase 8 — Mid-edit additions201202When the user re-invokes the skill and says "add a clip for this paragraph":2032041. Append a new entry to the clip list with the next id.2052. Run Phase 5 for just that clip.206207## Variant Strategy208209When generating 3 variants per clip, each variant must differ along at least one of:210211- **Composition** — centered vs split-screen vs grid vs sequential timeline212- **Reveal language** — typewriter, scale-spring, slide-from-edge, mask-wipe, stagger-in213- **Visual metaphor** — diagram, code reveal, abstract shape, side-by-side comparison, "screen frame" mock214- **Motion preset** — pair each variant with a different `motion.springs.*` (`snappy` / `gentle` / `dramatic`) so the cadence feels different, not just the layout215216Do not generate 3 variants that differ only in colour or timing. If you can't think of 3 distinct directions, say so and propose 2 — better fewer good variants than 3 near-identical ones.217218## Style Rules219220`STYLE.md` (copied into the project at scaffold time) is the source of truth. Re-read it at the start of each session.221222Headline rules to keep in mind while coding:223224- **No headers, footers, logos, tickers, or clip numbers on screen.** Overlay content only.225- **Not text-heavy.** If a single moment shows more than ~15 words, redesign. The viewer is listening; the clip reinforces, it doesn't restate.226- **One idea per clip.** If two ideas fight, split into two clips.227- **Spring motion by default.** Pure fades are weak — combine opacity with scale or position.228229## Constraints230231- Never render with audio. Strip any audio component before rendering.232- Always render 3 variants on first generation unless the user explicitly asks for fewer.233- Never modify `script.md`.234- Never delete a rejected variant — TSX stays in `src/clips/`, MP4 moves to `out/_rejected/`.235- Never skip the per-clip notes file. It carries context across sessions.236- If a script section is narrative-only and a visual would just be filler, say so and skip it instead of generating noise.237238## File Layout239240```241<video folder>/242 motion-graphics/243 script.md244 package.json245 remotion.config.ts246 STYLE.md247 src/248 Root.tsx249 theme.ts250 clips/251 Clip01_IntroA.tsx252 Clip01_IntroB.tsx253 Clip01_IntroC.tsx254 Clip03_DiagramA.tsx255 ...256 notes/257 clip-01.notes.md258 clip-03.notes.md259 out/260 clip-01-A.mp4261 clip-03-A.mp4262 _rejected/263 clip-01-B.mp4264 clip-01-C.mp4265```266267## Bad vs Good268269```text270Bad: "Here are 3 variants of the diagram clip" — all three use the same centered layout with different accent colors.271272Good: "Variant A: split-screen User A | User B with typewriter code reveal underneath. Variant B: centered Firebase-style hierarchy diagram with the insecure path highlighted in red. Variant C: sequential timeline showing request -> DB query -> policy check arrows."273```274275```text276Bad: A clip that repeats the entire spoken sentence as on-screen text.277278Good: A clip that shows one keyword or visual cue that reinforces the sentence. The viewer is listening, not reading.279```280281```tsx282// Bad: hardcoded values, fade-only, multiple competing ideas283export const ClipBad = () => {284 const frame = useCurrentFrame();285 return (286 <AbsoluteFill style={{ background: '#000', color: '#fff' }}>287 <h1 style={{ opacity: frame / 30 }}>First idea</h1>288 <h2 style={{ opacity: frame / 60 }}>Second idea fighting for attention</h2>289 </AbsoluteFill>290 );291};292293// Good: theme tokens, named spring preset, deliberate accent pick294import { spring, useCurrentFrame, useVideoConfig, AbsoluteFill } from 'remotion';295import { colors, fonts, motion } from '../theme';296297export const ClipGood = () => {298 const frame = useCurrentFrame();299 const { fps } = useVideoConfig();300 const t = spring({ frame, fps, config: motion.springs.snappy });301302 return (303 <AbsoluteFill style={{304 background: `linear-gradient(180deg, ${colors.bg}, ${colors.bgGradientEnd})`,305 fontFamily: fonts.display,306 color: colors.text,307 }}>308 <h1 style={{309 fontSize: fonts.sizes.headline,310 transform: `scale(${t})`,311 color: colors.accents.teal,312 }}>313 One Big Idea314 </h1>315 </AbsoluteFill>316 );317};318```319320## Checklist321322- [ ] script saved to `motion-graphics/script.md`323- [ ] Remotion project scaffolded under `motion-graphics/`324- [ ] official Remotion skill installed in the project325- [ ] theme.ts + STYLE.md copied from this skill into the project326- [ ] URLs in the script were fetched; blockers logged to `refs/blocked-urls.md` and the workflow continued327- [ ] `<aside>` blocks were treated as editor notes and *not* turned into clips328- [ ] every proposed clip passes the "does a visual actually help here?" test329- [ ] clip list was announced to the user but the workflow proceeded without pausing for approval330- [ ] composition IDs in `Root.tsx` use dashes only (no underscores)331- [ ] `durationInFrames` per clip matches natural read time of the script section332- [ ] every clip has 3 meaningfully distinct variants (or a clear note saying fewer made sense)333- [ ] variants use *different* `motion.springs.*` presets, not just different layouts334- [ ] every clip has a notes file at `src/clips/notes/`335- [ ] rejected variants moved to `out/_rejected/`, TSX files kept in place336- [ ] every render is silent, 3840x2160, 30fps, H.264