name: remotion
description: Build, debug, and render videos programmatically with Remotion (React-based video framework). Use when the user wants to create a video with code, asks about Remotion specifically, mentions React video, programmatic video, MP4 from React, animated explainer with code, talking head with captions, data-driven video, or pastes a Remotion error. Covers composition setup, useCurrentFrame animation patterns (interpolate, spring), Sequence/AbsoluteFill layout, audio/video/image components, the Studio, and rendering via CLI / @remotion/renderer / Lambda. SKIP for non-Remotion video tasks — use the video skill for AI video generation (Veo, Sora, Runway, HeyGen).
metadata:
version: 1.0.0
Remotion
Remotion turns React components into videos. You write JSX, Remotion calls your component once per frame at a fixed fps, and the resulting frames are stitched into an MP4 (or other format).
Core mental model
Remotion gives you a frame number and a blank canvas. Your React component decides what to render at that frame.
There is no animation timeline in the imperative sense. Time is a number (frame), and your component is a pure function of that number plus props. This is why animations must be driven by useCurrentFrame() — CSS transitions and setTimeout are non-deterministic during rendering and will flicker or desync.
When to use this skill
- User has a Remotion project (
remotion.config.tsor@remotion/*in package.json) and wants to build, change, or debug a composition - User says "let's make a video with Remotion / with code / programmatically"
- User pastes a Remotion error or asks about
interpolate,spring,Sequence,useCurrentFrame,Composition, etc. - User wants to render an existing Remotion project or set up Lambda rendering
When NOT to use
- Generating video with AI models (Veo, Sora, Runway, Kling, HeyGen) → use the video skill
- Editing existing video files (cut/trim/concat) → ffmpeg, not Remotion
- Live streaming → Remotion is offline rendering only
Workflow
Detect or scaffold the project.
- New project:
npx create-video@latest(interactive — picks a template like Hello World, Blank, JavaScript, TikTok, etc.) - Existing: check for
remotion.config.ts,src/Root.tsx, and@remotion/cliinpackage.json. Note the Remotion major version — APIs evolve, and the right docs URL ishttps://www.remotion.dev/docs(latest) or version-pinned pages.
- New project:
Locate or create the composition. Compositions are registered in
src/Root.tsxvia<Composition id="..." component={...} durationInFrames={...} fps={30} width={1920} height={1080} defaultProps={{...}} />. Theidis what the CLI renders by name.Build the component using
useCurrentFrame+useVideoConfigfor time and metadata. Compose layout with<AbsoluteFill>, time-slice with<Sequence>.Preview in the Studio:
npx remotion studio(auto-reloads). Don't try to "test" frames in isolation — open the Studio.Render:
npx remotion render <CompositionId> [output.mp4]. Default codec is H.264 / MP4. See references/rendering.md for flags and programmatic API.
Quick API reference
See the linked files for depth — load these only when a task needs them.
| Topic | File |
|---|---|
| Composition, hooks, Sequence, AbsoluteFill, layout | references/core-concepts.md |
interpolate, spring, Easing, staggering, common animation patterns |
references/animation.md |
Rendering: CLI flags, @remotion/renderer, Lambda, codecs, props |
references/rendering.md |
Audio/video/images: <Audio>, <Video>, <Img>, <OffthreadVideo>, captions |
references/media.md |
Project setup, file conventions, remotion.config.ts |
references/project-setup.md |
| Common patterns: typing animations, lower-thirds, data-driven, parallax | references/patterns.md |
Hard rules
- Animate via
useCurrentFrame(). NeversetTimeout,requestAnimationFrame, or CSStransition. They flicker during render because each frame is rendered independently in a headless browser. durationInFramesis required and must be an integer. Total seconds =durationInFrames / fps.- Keep components pure. No top-level side effects, no
Math.random()without a deterministic seed — the same frame must always produce the same pixels. - Don't fetch in render. Use
delayRender()/continueRender()to block frame readiness while data loads, or pre-fetch and pass via props. - Use
<OffthreadVideo>instead of<Video>when possible for non-blocking video reads during render (faster, less memory). - Pass dynamic data via
--props(CLI) orinputProps(Studio/programmatic), not by editing files.
Common errors
| Error / symptom | Cause | Fix |
|---|---|---|
| Flickering / mismatched motion in MP4 vs Studio preview | Used CSS transitions or non-frame-driven animation | Replace with interpolate(frame, ...) or spring({ frame, fps }) |
| "Composition not found" | ID typo or missing <Composition> registration |
Check src/Root.tsx |
| Render hangs | Pending delayRender() never called continueRender() |
Find the unresolved promise; add try/finally |
| Out-of-memory on long videos | <Video> keeping frames in memory |
Switch to <OffthreadVideo> |
| Audio out of sync | Audio file fps mismatch or starting at wrong frame | Wrap <Audio> in <Sequence from={...}> |
Verification
After making changes, always:
- Run
npx remotion studioand scrub the timeline to confirm the change looks right at multiple frames (start, middle, end) - For programmatic changes, render a short test segment:
npx remotion render <id> out.mp4 --frames=0-60 - Type-check:
npx tsc --noEmitif the project is TypeScript
Don't claim success without one of these. Code that compiles isn't the same as a video that looks right.