remotion-best-practices
Build programmatic videos with Remotion (React-based video framework). Covers compositions, animations, media, transitions, 3D, charts, captions, rendering, and Lambda deployment. Uses MCP server for
SKILL.mdskills/remotion-best-practices/SKILL.md
GitHubUse this skill when
- Creating videos programmatically with React and Remotion
- Building Remotion compositions, animations, and transitions
- Embedding media (video, audio, images, GIFs, Lottie) in compositions
- Creating charts, text animations, captions, and subtitles
- Rendering videos locally or on AWS Lambda
- Using Three.js/React Three Fiber inside Remotion
- Any task involving
remotionor@remotion/*packages
Do not use this skill when
- The task involves standard React without Remotion video output
- The user needs video editing of existing footage without programmatic generation
Instructions
Always use mcp__remotion__remotion-documentation for documentation lookups. Query it with specific topics when you need API details, examples, or troubleshooting. Do not rely on memory for Remotion API signatures — always look up.
Capabilities
Project Structure
- Entry file (
src/index.ts): calls registerRoot() with the Root component - Root file (
src/Root.tsx): registers one or more Composition components - Component files: individual video components using Remotion hooks
- Defaults: fps=30, width=1920, height=1080
Animation System
- ALL animations must be driven by
useCurrentFrame()hook — no exceptions interpolate(frame, inputRange, outputRange, options)for linear mapping; always clamp with extrapolateRight/extrapolateLeftspring({ frame, fps, config })for natural physics-based motion- Spring config presets: damping=200 (smooth), damping=20+stiffness=200 (snappy), damping=8 (bouncy), damping=15+stiffness=80+mass=2 (heavy)
Forbidden Patterns
- CSS transitions and CSS animations — will NOT render correctly; Remotion renders frames out of order
- Tailwind
animate-*andtransition-*classes — same reason as CSS animations Math.random()— userandom('seed')from remotion instead; random() is deterministic per seed- Native
<img>— use<Img>from remotion; native img may not wait for load useFrame()from @react-three/fiber inside Remotion — useuseCurrentFrame()from remotion- Third-party animation libraries (GSAP, Framer Motion, CSS keyframes) without disabling their animations
Media Components
- Video and Audio: import from
@remotion/media - Images: import
<Img>andstaticFile()fromremotion - All assets: place in
public/folder, reference withstaticFile('filename') - Video/Audio props: trimBefore, trimAfter (in frames), volume (0-1 or callback), playbackRate, loop, muted, toneFrequency
Sequencing and Layout
<Sequence from={frame} durationInFrames={frames}>: delays appearance; premountFor is important- Always premount Sequences: use
premountFor={1 * fps}to prevent pop-in artifacts <Series>: chains elements back-to-back without overlap<AbsoluteFill>: layers elements filling the full composition<TransitionSeries>: sequences with overlap transitions between scenes
Transitions
- Install:
npx remotion add @remotion/transitions - Available: fade, slide, wipe, flip, clockWipe, iris, and custom presentations
- Timing: linearTiming or springTiming
- Transitions shorten total duration (overlap); use Overlay for non-shortening transitions
<TransitionSeries.Transition presentation={fade()} timing={linearTiming({ durationInFrames: 15 })} />
Fonts
- Google Fonts:
import { loadFont } from '@remotion/google-fonts/FontName'; call loadFont() at module level - Local fonts:
import { loadFont } from '@remotion/fonts'; await loadFont() in calculateMetadata or root
Parameterizable Videos
- Define Zod schema for video props
- Use
zColor()from@remotion/zod-typesfor color inputs - Pass schema to Composition; enables Remotion Studio GUI editing and type-safe renders
Dynamic Metadata
calculateMetadatafunction on Composition for dynamic duration, dimensions, or props- Use for: fetching data from APIs, computing duration from audio/video length, data-driven props
- Returns:
{ durationInFrames, fps, width, height, props }
3D Content
- Install:
npx remotion add @remotion/three <ThreeCanvas width={width} height={height}>: wrapper for React Three Fiber scene- Use
useCurrentFrame()for all 3D animations — not useFrame() from @react-three/fiber <Sequence>inside<ThreeCanvas>must havelayout="none"
Charts and Data Visualization
- Use SVG or HTML/CSS for charts; drive all animations with useCurrentFrame()
- Disable any third-party animation library's built-in animations
- Path drawing animation: use
evolvePath(progress, pathD)from@remotion/paths - Bar charts: interpolate bar heights from 0 to final value using spring or interpolate
Captions and Subtitles
@remotion/captions: parse SRT/VTT, render word-by-word or line-by-line- Sync captions to audio timing using frame-based calculations
Rendering (Local)
npx remotion render CompositionId— renders videonpx remotion still CompositionId— renders single frame as image- Transparent video: ProRes with yuva444p10le pixel format and prores-profile=4444
- Transparent WebM: VP9 codec with yuva420p pixel format
Lambda Rendering
- Setup: deploy function and site with Lambda CLI commands
- Programmatic:
deployFunction(),deploySite(),renderMediaOnLambda(),getRenderProgress() - Always call
getRenderProgress()in a loop until done — Lambda renders are async
Behavioral Traits
- Always queries
mcp__remotion__remotion-documentationbefore writing any Remotion API calls - Uses
useCurrentFrame()for every animation — never CSS transitions or third-party animation libs - Always sets
extrapolateRight: 'clamp'andextrapolateLeft: 'clamp'on interpolate calls - Adds
premountFor={1 * fps}to every Sequence to prevent visual pop-in - Places all assets in public/ and references with staticFile()
- Uses
<Img>from remotion, never native<img> - Chooses spring for natural motion, interpolate for precise linear mapping
Knowledge Base
Frame Math
- Convert seconds to frames:
seconds * fps(e.g., 2 seconds at 30fps = 60 frames) - Convert frames to seconds:
frames / fps - Composition total duration in frames:
durationInSeconds * fps - Audio/video trimming: trimBefore and trimAfter are in frames
Spring vs Interpolate Decision
- Spring: when the motion should feel physical and natural (elements entering/exiting)
- Interpolate: when precise timing and values are required (progress bars, percentage readouts)
- Combine: use spring for entry, interpolate for hold/exit
Common Mistakes
- Forgetting premountFor on Sequence: causes flash/pop-in at sequence start
- Using Math.random(): produces different frames on each render pass; use random('seed') instead
- Native img tag: may not finish loading before frame is captured; always use Img from remotion
- CSS animations: Remotion renders frames out of order; CSS animations assume sequential time
- Missing clamp on interpolate: values extrapolate beyond intended range causing visual artifacts
Render Quality Settings
- Default: H.264 MP4, yuv420p — good for web playback
- High quality: ProRes 4444 with transparency support — good for compositing
- Lossless: PNG image sequence — maximum quality for post-processing
- Lambda: parallelizes rendering across Lambda functions; much faster for long videos
Constraints
- NEVER use Math.random() — always use random('seed') from remotion
- NEVER use CSS transitions, CSS animations, or Tailwind animate-/transition- classes
- NEVER use native
<img>— always use<Img>from remotion - ALWAYS drive animations with useCurrentFrame()
- ALWAYS clamp interpolate extrapolation
- ALWAYS premount Sequences with premountFor
- ALWAYS query mcp__remotion__remotion-documentation for API details before implementing
API Reference
Detailed API documentation: references/REFERENCE.md.
When to read: when you need exact method signatures, configuration options, type definitions, or implementation details not covered above.
How to use: search or read the reference for specific APIs before writing code. Don't read the entire file — look up only what you need.