--- name: remotion description: Create programmatic videos using React with Remotion. Use when building video compositions, animations, or rendering videos programmatically. Triggers include creating video content with React, animating elements frame-by-frame, rendering videos to MP4/WebM/GIF, using spring/interpolate animations, building video editing apps, or deploying video rendering to AWS Lambda. --- # Remotion Remotion is a framework for creating videos programmatically using React. Videos are functions of frames over time. ## Core Concepts **Video Properties:** - `width`, `height`: Dimensions in pixels - `fps`: Frames per second - `durationInFrames`: Total frames (duration = durationInFrames / fps) **First frame is 0, last frame is durationInFrames - 1.** ## Project Setup ```bash npx create-video@latest # Create new project npx remotion studio # Launch preview studio npx remotion render src/index.ts CompositionId out.mp4 # Render video ``` ## Essential Hooks ```tsx import { useCurrentFrame, useVideoConfig } from 'remotion'; const MyComponent = () => { const frame = useCurrentFrame(); // Current frame number (0-indexed) const { fps, durationInFrames, width, height } = useVideoConfig(); return
Frame {frame} of {durationInFrames}
; }; ``` ## Composition Registration Register compositions in `src/Root.tsx`: ```tsx import { Composition } from 'remotion'; export const RemotionRoot = () => ( <> ); ``` ## Animation with interpolate() Map frame values to animation properties: ```tsx import { interpolate, useCurrentFrame } from 'remotion'; const frame = useCurrentFrame(); // Fade in from frame 0-20 const opacity = interpolate(frame, [0, 20], [0, 1], { extrapolateRight: 'clamp', // Prevent values > 1 }); // Fade in and out const { durationInFrames } = useVideoConfig(); const fadeOpacity = interpolate( frame, [0, 20, durationInFrames - 20, durationInFrames], [0, 1, 1, 0] ); ``` **Options:** `extrapolateLeft`, `extrapolateRight`: `'extend'` | `'clamp'` | `'identity'` | `'wrap'` ## Spring Animations Physics-based animations: ```tsx import { spring, useCurrentFrame, useVideoConfig } from 'remotion'; const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const scale = spring({ frame, fps, config: { damping: 10, stiffness: 100, mass: 1 }, durationInFrames: 30, // Optional: constrain duration }); // Combine spring with interpolate for custom ranges const translateX = interpolate(spring({ frame, fps }), [0, 1], [0, 200]); ``` ## Easing Functions ```tsx import { interpolate, Easing } from 'remotion'; const value = interpolate(frame, [0, 30], [0, 100], { easing: Easing.bezier(0.25, 0.1, 0.25, 1), // Or: Easing.ease, Easing.inOut(Easing.quad), Easing.bounce, etc. }); ``` ## Sequencing Content **Sequence** - Time-shift children (useCurrentFrame becomes relative): ```tsx import { Sequence } from 'remotion'; {/* useCurrentFrame() starts at 0 when parent is at frame 30 */} ``` **Series** - Play items one after another: ```tsx import { Series } from 'remotion';
``` **Loop** - Repeat content: ```tsx import { Loop } from 'remotion'; {/* or times={Infinity} */} ``` **Freeze** - Pause at specific frame: ```tsx import { Freeze } from 'remotion'; {/* Always renders as if at frame 10 */} ``` ## Layout & Media Components ```tsx import { AbsoluteFill, Img, Video, Audio, OffthreadVideo, staticFile } from 'remotion'; // Full-screen container {/* Images - waits for load */} {/* Video - synchronized with timeline */} ``` **Video/Audio props:** `volume`, `playbackRate`, `muted`, `loop`, `startFrom`, `endAt` **`playbackRate` limitations:** - Must be a **constant value** (e.g., `playbackRate={2}`) - Dynamic interpolation like `playbackRate={interpolate(frame, [0, 100], [1, 5])}` won't work correctly - For variable speeds, extreme speeds (>4x), or guaranteed audio sync, pre-process with FFmpeg instead (see FFmpeg skill) ## Static Files Place files in `public/` folder: ```tsx import { staticFile } from 'remotion'; const videoSrc = staticFile('videos/intro.mp4'); // -> /public/videos/intro.mp4 ``` ## Input Props Pass dynamic data to compositions: ```tsx // In composition const { title, color } = getInputProps(); // CLI: npx remotion render ... --props='{"title":"Hello","color":"red"}' // Or from file: --props=./data.json ``` ## Async Data Loading ```tsx import { delayRender, continueRender } from 'remotion'; const MyComponent = () => { const [data, setData] = useState(null); const [handle] = useState(() => delayRender()); // Block render useEffect(() => { fetch('/api/data') .then(res => res.json()) .then(d => { setData(d); continueRender(handle); // Unblock render }); }, [handle]); if (!data) return null; return
{data.title}
; }; ``` ## Color Interpolation ```tsx import { interpolateColors, useCurrentFrame } from 'remotion'; const frame = useCurrentFrame(); const color = interpolateColors(frame, [0, 30], ['#ff0000', '#0000ff']); ``` ## CLI Rendering ```bash # Render to MP4 npx remotion render src/index.ts MyComposition out.mp4 # Common flags --codec=h264|h265|vp8|vp9|gif|prores --quality=80 # JPEG quality for frames --scale=2 # 2x resolution --frames=0-59 # Render specific frames --props='{"key":"value"}' --concurrency=4 # Parallel renders ``` ## Programmatic Rendering ```tsx import { bundle } from '@remotion/bundler'; import { renderMedia, selectComposition } from '@remotion/renderer'; const bundleLocation = await bundle({ entryPoint: './src/index.ts' }); const composition = await selectComposition({ serveUrl: bundleLocation, id: 'MyComposition', inputProps: { title: 'Hello' }, }); await renderMedia({ composition, serveUrl: bundleLocation, codec: 'h264', outputLocation: 'out.mp4', inputProps: { title: 'Hello' }, }); ``` ## Lambda Rendering Deploy and render in AWS Lambda for parallel, serverless rendering: ```bash # Setup npx remotion lambda policies user npx remotion lambda functions deploy # Deploy site npx remotion lambda sites create src/index.ts --site-name=mysite # Render npx remotion lambda render MyComposition out.mp4 ``` ```tsx import { renderMediaOnLambda } from '@remotion/lambda'; const { bucketName, renderId } = await renderMediaOnLambda({ region: 'us-east-1', functionName: 'remotion-render', serveUrl: 'https://...', composition: 'MyComposition', codec: 'h264', inputProps: { title: 'Hello' }, }); ``` ## Player Component (Embed in React Apps) ```tsx import { Player } from '@remotion/player'; ``` ## Scene Transitions The toolkit includes a transitions library at `lib/transitions/` for scene-to-scene effects. ### Using TransitionSeries ```tsx import { TransitionSeries, linearTiming } from '@remotion/transitions'; // Import custom transitions from lib (adjust path based on your project location) import { glitch, lightLeak, clockWipe, checkerboard } from '../../../../lib/transitions'; // Or import from @remotion/transitions for official ones import { slide, fade } from '@remotion/transitions/slide'; ``` ### Available Transitions **Custom (lib/transitions/):** | Transition | Options | Best For | |------------|---------|----------| | `glitch()` | `intensity`, `slices`, `rgbShift` | Tech demos, edgy reveals, cyberpunk | | `rgbSplit()` | `direction`, `displacement` | Modern tech, energetic transitions | | `zoomBlur()` | `direction`, `blurAmount` | CTAs, high-energy moments, impact | | `lightLeak()` | `temperature`, `direction` | Celebrations, film aesthetic, warm moments | | `clockWipe()` | `startAngle`, `direction`, `segments` | Time-related content, playful reveals | | `pixelate()` | `maxBlockSize`, `gridSize`, `scanlines`, `glitchArtifacts`, `randomness` | Retro/gaming, digital transformations | | `checkerboard()` | `gridSize`, `pattern`, `stagger`, `squareAnimation` | Playful reveals, structured transitions | **Checkerboard patterns:** `sequential`, `random`, `diagonal`, `alternating`, `spiral`, `rows`, `columns`, `center-out`, `corners-in` **Official Remotion (@remotion/transitions/):** | Transition | Description | |------------|-------------| | `slide()` | Push scene from direction | | `fade()` | Simple crossfade | | `wipe()` | Edge reveal | | `flip()` | 3D card flip | ### Transition Examples ```tsx // Tech/cyberpunk feel glitch({ intensity: 0.8, slices: 8, rgbShift: true }) // Warm celebration lightLeak({ temperature: 'warm', direction: 'right' }) // High energy zoom zoomBlur({ direction: 'in', blurAmount: 20 }) // Chromatic aberration rgbSplit({ direction: 'diagonal', displacement: 30 }) // Clock sweep reveal clockWipe({ direction: 'clockwise', startAngle: 0 }) // Retro pixelation pixelate({ maxBlockSize: 50, glitchArtifacts: true }) // Checkerboard patterns checkerboard({ pattern: 'diagonal', gridSize: 8 }) checkerboard({ pattern: 'spiral', gridSize: 10 }) checkerboard({ pattern: 'center-out', squareAnimation: 'scale' }) ``` ### Timing Functions ```tsx import { linearTiming, springTiming } from '@remotion/transitions'; // Linear: constant speed linearTiming({ durationInFrames: 30 }) // Spring: physics-based with bounce springTiming({ config: { damping: 200 }, durationInFrames: 45 }) ``` ### Duration Guidelines | Type | Frames | Notes | |------|--------|-------| | Quick cut | 15-20 | Fast, punchy | | Standard | 30-45 | Most common | | Dramatic | 50-60 | Slow reveals | | Glitch effects | 20-30 | Should feel sudden | | Light leak | 45-60 | Needs time to sweep | ### Preview Transitions Run the showcase gallery to see all transitions: ```bash cd showcase/transitions && npm run studio ``` ## Best Practices 1. **Frame-based animations only** - Avoid CSS transitions/animations; they cause flickering 2. **Use fps from useVideoConfig()** - Make animations frame-rate independent 3. **Clamp interpolations** - Use `extrapolateRight: 'clamp'` to prevent runaway values 4. **Use OffthreadVideo** - Better performance than `