name: remotion description: AI video production workflow using Remotion. Use when creating videos, short films, commercials, or motion graphics. Triggers on requests to make promotional videos, product demos, social media videos, animated explainers, or any programmatic video content. Produces polished motion graphics, not slideshows.
Video Generator (Remotion)
Workflow
- Scaffold the project in
output/<project-name>/:cd output && npx --yes create-video@latest <project-name> --template blank cd <project-name> && npm install && npm install lucide-react @remotion/google-fonts - Copy the template library into the project:
This gives the projectcp -r <skill-dir>/templates/src/lib/ src/lib/src/lib/utils.ts,palette.ts,backgrounds.tsx,text.tsx,ui.tsx,effects.tsx,transitions.tsx, andthemes/— all ready to import. - Fix package.json scripts — replace any
bunreferences withnpx remotion:{ "prepare:tts": "node scripts/generate-tts-manifest.mjs", "dev": "npx remotion studio", "build": "npx remotion bundle" } - Choose a theme based on the video's tone (see Theme Guide below), then customize
src/lib/palette.tsto match. - Write the narration script — one sentence per scene, sentence order = scene order.
- Generate TTS — copy
scripts/generate-tts-manifest.mjsfromreferences/inworld-tts.md, update theSENTENCESarray, then:
This producesnpm run prepare:ttspublic/audio/tts/*.mp3andsrc/tts-manifest.jsonwith measured durations. - Build all scenes — each scene imports from
src/lib/andsrc/tts-manifest.json. Never hardcode durations. - Start Remotion Studio:
User openscd output/<project-name> && npm run devhttp://localhost:3000to preview. Hot-reloads on save.
Fast iteration
REUSE_EXISTING_AUDIO=1 npm run prepare:tts # skip re-synthesis
Render (only when user explicitly asks)
npx remotion render CompositionName out/video.mp4
Template Library (src/lib/)
Every project gets these files copied in at scaffold time. Import from them — do not rewrite the code inline.
| File | Exports | When to use |
|---|---|---|
utils.ts | lerp, EASE, SPRING | Every scene. lerp replaces raw interpolate. EASE.out for entrances, EASE.in for exits, EASE.inOut for moves. |
palette.ts | C | Every scene. Never use inline hex colors — always C.accent, C.muted, etc. |
backgrounds.tsx | BokehBackground, WaveBackground, Starfield, FloatingShapes | Persistent layer outside <Sequence> blocks. Choose one per video. |
text.tsx | TextReveal, WordReveal, NeonFlickerText, GlitchText, Typewriter | Headlines use TextReveal. Subtitles use WordReveal. Tech scenes use Typewriter or GlitchText. Bold/edgy scenes use NeonFlickerText. |
ui.tsx | FeatureCard, StatsDisplay, CTAButton, TerminalWindow, StaggeredList | List scenes → StaggeredList. Enumeration → FeatureCard with staggered delay. Stats → StatsDisplay. Endings → CTAButton. Code → TerminalWindow. |
effects.tsx | RadialExplosion, Blob, Scanlines, GridBackground, PerspectiveGrid | Reveal moments → RadialExplosion. Liquid/organic → Blob. Retro/VHS → Scanlines. Tech/HUD → GridBackground or PerspectiveGrid. |
layouts.tsx | FullscreenType, MultiColumn, SplitContrast, GiantNumber, Asymmetric, FrameInFrame | Scene structure. Choose a layout first, then fill with content components. See Layout Guide. |
transitions.tsx | CircleReveal, ColorWipe | Wrap scene content for entrance transitions. |
themes/*.tsx | 12 visual themes (see Theme Guide) | Choose one per video based on tone. Use as scene backgrounds or style reference. |
Theme Guide
Choose one theme per video based on the content's tone. Import from src/lib/themes/. Each theme accepts { startDelay?: number }.
| Theme | Tone | Best for | Key visual |
|---|---|---|---|
ThemeDarkMode | Professional, clean | SaaS, dev tools, product demos | Subtle purple glow, card UI, dark gradient |
ThemeTech | Clean, startup | Pitch videos, app launches, SaaS | Logo, CTA buttons, SVG line chart, light bg |
ThemeCyberpunk | Edgy, tech | Gaming, hacker, sci-fi | Neon cyan/magenta, perspective grid, scanlines, glitch text |
ThemeNeon | Bold, nightlife | Music, events, entertainment | Neon signs on brick wall, multi-glow text, flicker |
ThemeMinimalist | Restrained, elegant | Editorial, architecture, literary | White bg, thin type, single underline, maximum whitespace |
ThemeMonochrome | Dramatic, contrasty | Documentary, photography | Black/white split, animated block reveal |
ThemeGlassmorphism | Modern, polished | App promos, UI showcases | Frosted glass card, purple-pink gradient, blur |
ThemeLuxury | Premium, refined | High-end brands, luxury products | Black + gold, thin frame, extreme letter-spacing |
ThemeNeobrutalism | Bold, energetic | Startups, Gen-Z brands | Thick borders, hard shadows, bright fills, tilted |
ThemeCosmic | Expansive, wonder | Sci-fi, astronomy, futuristic | Stars, gradient planet with ring, shooting star |
ThemeGradient | Vibrant, dynamic | Social media, music, festivals | Rotating multi-stop gradient, large centered text |
ThemeRetro | Warm, nostalgic | Vintage brands, craft, artisan | Sepia, SVG noise texture, vignette, diamond ornament |
Usage: Themes define the visual identity — background, typography treatment, color palette, decorative elements. Use a theme's style to inform scene design, or render the theme component directly as a background/intro layer.
import { ThemeCyberpunk } from "./lib/themes";
// As a background layer in a scene:
<AbsoluteFill>
<ThemeCyberpunk startDelay={0} />
{/* Scene content overlaid on top */}
</AbsoluteFill>
Layout Guide
Every scene needs a layout — the spatial arrangement of elements on screen. Choose a layout before choosing text/UI components.
| Layout | Structure | Best for | Key props |
|---|---|---|---|
FullscreenType | Staggered masked text lines filling the screen | Hook statements, bold claims, chapter titles | lines: {text, color?}[], fontSize, subtitle |
MultiColumn | Header + N equal columns with spring stagger | Process steps, feature lists, pricing, timelines | columns: {number?, title, desc}[], heading, label, lightBg |
SplitContrast | Two-panel clipPath reveal (dark left, light right) | Before/after, problem/solution, old/new | left: {label, heading}, right: {label, heading, accentWord?} |
GiantNumber | Oversized stat number + supporting text | KPIs, data highlights, statistics | number, label, heading, accentWord, body, lightBg |
Asymmetric | 70/30 split — giant text left, metadata right | Hero statements, title cards, bold openers | line1, line2, line2Color, metadata: string[] |
FrameInFrame | Nested animated borders with corner accents | Product reveals, chapter markers, premium intros | heading, label, footnote |
All layouts accept frame, startDelay, and handle their own entrance animations. They render full-screen (AbsoluteFill) and include backgrounds.
Usage: Import a layout, pass content props, and layer additional components (text animations, effects) on top if needed.
import { GiantNumber } from "./lib/layouts";
<GiantNumber
frame={frame}
number="4.2M"
label="MONTHLY ACTIVE USERS"
heading="Growing Fast"
accentWord="Fast"
startDelay={0}
/>
Layout selection rules
- No two adjacent scenes should use the same layout
- Match layout to the sentence archetype (see mapping below)
- Layouts handle backgrounds — don't stack a layout inside another background
| Archetype | Primary layout | Alternative |
|---|---|---|
| Hook / bold claim | FullscreenType | Asymmetric |
| Enumeration / process | MultiColumn | — |
| Contrast / choice | SplitContrast | — |
| Stats / data | GiantNumber | — |
| Product reveal / intro | FrameInFrame | Asymmetric |
| Title card / chapter | Asymmetric | FullscreenType |
For archetypes not listed (list, code, CTA), use a neutral dark background and layer content components from ui.tsx and text.tsx directly.
Scene Architecture
Timing from TTS manifest
import manifest from "./tts-manifest.json";
const sceneDurationFrames = (i: number, fps: number) =>
Math.ceil((manifest[i].durationMs / 1000) * fps);
Set durationInFrames on the Composition from the manifest sum. Never hardcode frame counts.
Video structure
<AbsoluteFill>
<Audio src={staticFile("audio/bg-music.mp3")} volume={0.35} />
<BokehBackground frame={frame} baseHue={220} />
<Series>
<Series.Sequence durationInFrames={d0}>
<Scene00 />
</Series.Sequence>
<Series.Sequence offset={-12} durationInFrames={d1}>
<Scene01 />
</Series.Sequence>
</Series>
</AbsoluteFill>
Use Series with negative offset for overlapping scene transitions.
Scene component pattern
Every scene should:
- Import from
src/lib/— not reimplement animation logic - Accept timing from the manifest — not hardcode durations
- Include its own
<Audio>tag for narration - Use
lerpfor exit fade:lerp(frame, [totalFrames - 15, totalFrames], [1, 0])
Scene Content Design
For each narration sentence, decide before coding:
- What is the single key idea? One concept per scene.
- Which archetype? (see table below)
- Which layout? (see Layout Guide — match archetype to layout)
- Which 2–3 words trigger animation beats? Time component entrances to land on those words.
Scene archetypes → component mapping
| Sentence type | Visual treatment | Components to use |
|---|---|---|
| Hook / bold claim | Full-screen headline, massive type | TextReveal or NeonFlickerText |
| Enumeration | Cards revealing sequentially | FeatureCard with staggered delay |
| List of items | Items appear as spoken | StaggeredList |
| Contrast / choice | Two-column split | Manual layout, lerp for panel entrances |
| Problem statement | Label + visual evidence | Icon cluster with StaggeredList |
| Solution / reveal | Hero element with glow | TextReveal + RadialExplosion |
| Analogy / metaphor | Icon anchors the metaphor | Lucide icon + WordReveal |
| Rhetorical question | Word-by-word reveal | WordReveal |
| Technical / code | Terminal or typewriter | TerminalWindow or Typewriter |
| Stats / numbers | Animated counters | StatsDisplay with staggered delay |
| Ending / CTA | Button with shimmer | CTAButton |
Audio-visual sync rules
- Don't front-load. Spread animation beats across the full duration — not all in the first second.
- Key word = animation beat. Time component entrances to land as key words are spoken.
- Post-entrance motion. After elements enter, they should float/pulse/breathe — never static for >30 frames.
- Exit early. Start fade-out ~15 frames before audio ends.
Content reduction rules
- Show less than the narrator says — the visual is an anchor, not a transcript.
- One headline per scene. If you need two, split into two scenes.
- On-screen text is a 2–5 word distillation, never the full narration sentence.
- Empty space is intentional. Don't fill it.
Motion Graphics Rules
NEVER
- Set
startDelay> 15% of a scene's total frames — layouts have built-in stagger, adding a large scene-level delay creates blank screen while narration plays - Use rotated divs to create non-rectangular zone boundaries — use
clipPath: polygon()containers instead, with content as a child of its zone (rotated div visual boundaries are unpredictable from CSS) - Reference theme objects directly in scenes (
darkTheme.accent,darkTheme.bg) — this bypasses context. Let layouts readt.accentfromuseTheme(). Scene-level<ThemeProvider>overrides put the right tokens in context automatically. - Render
background: t.bgin custom scene code without checkinguseThemeConfig()?.opaqueLayouts— this covers the atmosphere in atmospheric themes - Fade to black between scenes
- Centered text on solid backgrounds with no animation
- Same transition for every scene
- Linear/robotic animations — always use
spring()orEASEcurves - Static screens — every element must move
- Emoji icons — always Lucide React
Math.random()— alwaysrandom()from Remotion (deterministic)- Inline hex colors — always use
Cfrom palette
ALWAYS
- Overlapping transitions via
Serieswith negative offsets - Layered compositions: background → effects → content
- Spring physics for entrances,
EASEcurves for continuous motion - Staggered group entrances (8–15 frames between items)
- Post-entrance float/pulse on every visible element
- Varied scene layouts — no two adjacent scenes should look the same
Visual Style
Typography
- One display font + one body font max
- Minimum 32px for any text — nothing smaller
- Body: 36–48px. Labels: 32px minimum. Headlines: 64px+
Layout
- Safe zone: 160px horizontal padding, 100px vertical padding on every scene root
AbsoluteFillisflex-direction: column— usejustifyContent: "center"for vertical centering- Three valid states: centred, balanced L/R, or intentionally asymmetric → resolves
Critique Checklist
After all scenes are built, audit every scene file:
- Every
fontSize≥ 32 - Root padding ≥ 160px horizontal, ≥ 100px vertical
- Vertical centering uses
justifyContent: "center"not justalignItems: "center" - Animation delays spread across full frame count, not clustered in first 30 frames
- Exit fade starts ≥ 15 frames before end
- No two adjacent scenes use the same layout
- Each scene uses a layout from
layouts.tsxor has a clear reason not to - All colors use
Cfrom palette - All text animations use components from
src/lib/text.tsx - All group entrances are staggered, not simultaneous
- No element is static for >30 frames after entrance
Implementation Steps
- Director's treatment — vibe, emotional arc
- Visual direction — customize
palette.ts, choose theme - Write narration — one sentence per scene
- Generate TTS —
npm run prepare:tts - Scene breakdown — match each sentence to an archetype
- Layout design — assign a layout from
layouts.tsxto each scene (no two adjacent scenes share a layout) - Build persistent layer — background + music outside sequences
- Build scenes — import layouts and components from
src/lib/, wire up timing from manifest - Start Remotion Studio —
npm run dev - Critique — run checklist above, fix all failures
- Iterate — edit source, hot-reload; use
REUSE_EXISTING_AUDIO=1 - Render — only when user says to export
File Structure
my-video/
├── src/
│ ├── Root.tsx # Composition definitions
│ ├── index.ts # Entry point
│ ├── index.css # Global styles
│ ├── MyVideo.tsx # Main video component
│ ├── tts-manifest.json # Generated by prepare:tts
│ ├── lib/ # Copied from templates — DO NOT MODIFY
│ │ ├── utils.ts # lerp, EASE, SPRING
│ │ ├── palette.ts # Centralized colors (customize this one)
│ │ ├── backgrounds.tsx # BokehBackground, WaveBackground, Starfield, FloatingShapes
│ │ ├── text.tsx # TextReveal, WordReveal, NeonFlickerText, GlitchText, Typewriter
│ │ ├── ui.tsx # FeatureCard, StatsDisplay, CTAButton, TerminalWindow, StaggeredList
│ │ ├── layouts.tsx # FullscreenType, MultiColumn, SplitContrast, GiantNumber, Asymmetric, FrameInFrame
│ │ ├── effects.tsx # RadialExplosion, Blob, Scanlines, GridBackground, PerspectiveGrid
│ │ └── transitions.tsx # CircleReveal, ColorWipe
│ └── scenes/ # Scene components (you write these)
├── scripts/
│ └── generate-tts-manifest.mjs
├── public/
│ ├── images/
│ └── audio/
│ ├── bg-music.mp3
│ └── tts/ # Generated TTS clips
├── remotion.config.ts
└── package.json
References
references/inworld-tts.md— TTS API spec, script implementation, manifest schema