--- name: remotion description: Remotion programmatic video with motion design principles. Create premium, cinematic videos with React. Audio, 3D, transitions, brand storytelling. last_updated: 2026-03 owner: Frank --- # Remotion Create premium videos with React. Motion design thinking + code = cinematic results. > **See also:** `agents/gsap/SKILL.md`, `agents/motion/SKILL.md`, `workflows/animation-planning/SKILL.md` --- ## What is Remotion? Remotion lets you **write React components that render as video**. But the difference between a basic video and a premium one isn't the code—it's the motion design thinking. **What Remotion enables:** - **Personalized** — Generate 1000 videos with different data - **Data-driven** — Charts that animate from real data - **Programmatic** — API-triggered video generation - **Premium** — When you apply motion design principles --- ## Context Questions Before building a Remotion video: 1. **What's the story?** — What emotional journey should viewers experience? 2. **What's the pacing?** — Fast/energetic or slow/premium? 3. **What assets do you have?** — Video clips, 3D, images, audio? 4. **What's the audio strategy?** — Music sync, voiceover, sound effects? 5. **What's the visual hierarchy?** — What do viewers see first, second, third? --- ## TL;DR | Need | Use Remotion? | |------|---------------| | Personalized video at scale | ✅ Perfect | | Animated data visualization | ✅ Perfect | | Brand storytelling content | ✅ Great with motion design | | Social media templates | ✅ Great | | One-off promo video | ⚠️ Overkill, use editing software | | Live streaming | ❌ Not for this | --- ## Setup ```bash # Create new Remotion project npx create-video@latest my-video cd my-video npm start # Opens Remotion Studio ``` --- ## Project Structure ``` my-video/ ├── src/ │ ├── Root.tsx # Composition entry │ ├── Composition.tsx # Main video component │ └── components/ # Reusable pieces ├── public/ │ ├── sounds/ # Audio files │ └── assets/ # Images, videos └── remotion.config.ts # Render settings ``` --- # Part 1: Motion Design Principles The 12 principles of animation adapted for Remotion. Apply these to make videos that don't look basic. ## 1. Timing & Spacing **Principle:** The number of frames = perceived weight and emotion. | Frames | Feeling | Use For | |--------|---------|---------| | 10-15 (fast) | Snappy, energetic | UI elements, social content | | 20-30 (medium) | Balanced, natural | Most animations | | 45-60 (slow) | Premium, luxurious | Brand reveals, cinematic | ```tsx // FAST: Energetic popup (15 frames = 0.5s at 30fps) const fastScale = interpolate(frame, [0, 15], [0, 1], { easing: Easing.out(Easing.back(1.5)), extrapolateRight: "clamp", }) // SLOW: Premium reveal (60 frames = 2s at 30fps) const slowOpacity = interpolate(frame, [0, 60], [0, 1], { easing: Easing.inOut(Easing.cubic), extrapolateRight: "clamp", }) ``` ## 2. Anticipation **Principle:** Prepare the viewer for what's coming. ```tsx // Pull back before launching forward const anticipation = spring({ frame, fps, config: { damping: 8, stiffness: 100 }, delay: 0, }) // Scale dips to 0.9 BEFORE expanding to 1.1 const scale = interpolate( frame, [0, 8, 20], [1, 0.9, 1.1], { extrapolateRight: "clamp" } ) ``` ## 3. Follow-Through & Overlapping Action **Principle:** Different parts move at different times. ```tsx // Parent moves first, children follow with delays const parentY = spring({ frame, fps, config: { damping: 12 } }) // Child delays slightly and has different physics const childY = spring({ frame: frame - 5, // 5 frame delay fps, config: { damping: 8, stiffness: 80 }, // More bouncy }) ``` ## 4. Staging **Principle:** Direct viewer attention to what matters most. ```tsx // Primary element: Full animation, high contrast const primaryOpacity = interpolate(frame, [0, 20], [0, 1]) const primaryScale = interpolate(frame, [0, 20], [0.9, 1]) // Secondary elements: Subtle, delayed, smaller motion const secondaryOpacity = interpolate(frame, [15, 35], [0, 0.7]) const secondaryScale = interpolate(frame, [15, 35], [0.95, 1]) ``` ## 5. Exaggeration **Principle:** Push motion beyond realistic to create impact. ```tsx // Overshoot for punch const scale = spring({ frame, fps, config: { damping: 6, // Low damping = more overshoot stiffness: 150, // High stiffness = snappy mass: 0.5, // Low mass = responsive }, }) // Extreme position change for drama const y = interpolate(frame, [0, 30], [200, 0], { easing: Easing.out(Easing.expo), }) ``` --- # Part 2: Timing & Easing Mastery ## Easing Reference | Easing | Personality | Use For | |--------|-------------|---------| | `linear` | Robotic, mechanical | Progress bars, loading | | `Easing.cubic` | Natural, default | General purpose | | `Easing.quad` | Gentle, subtle | Fades, opacity | | `Easing.expo` | Dramatic, punchy | Hero reveals, impact | | `Easing.back` | Playful, bouncy | Buttons, UI elements | | `spring()` | Organic, alive | Natural motion | ## Premium Easing Patterns ```tsx import { Easing, interpolate, spring } from "remotion" // CINEMATIC REVEAL: Slow start, dramatic finish const cinematicY = interpolate(frame, [0, 45], [100, 0], { easing: Easing.out(Easing.expo), }) // LUXURY FADE: Ultra-slow, smooth const luxuryOpacity = interpolate(frame, [0, 60], [0, 1], { easing: Easing.inOut(Easing.sine), }) // ENERGETIC POP: Fast in, slight overshoot const energeticScale = spring({ frame, fps, config: { damping: 8, stiffness: 200, mass: 0.5 }, }) // CUSTOM BEZIER: Brand-specific curve const customEasing = Easing.bezier(0.25, 0.1, 0.25, 1.0) const brandMotion = interpolate(frame, [0, 30], [0, 1], { easing: customEasing, }) ``` ## Frame Timing Psychology ```tsx const { fps } = useVideoConfig() // Convert seconds to frames const seconds = (s: number) => Math.round(s * fps) // Timing constants const INSTANT = seconds(0.1) // 3 frames - imperceptible const FAST = seconds(0.3) // 9 frames - snappy const NORMAL = seconds(0.5) // 15 frames - natural const SLOW = seconds(0.8) // 24 frames - deliberate const DRAMATIC = seconds(1.5) // 45 frames - cinematic const LUXURIOUS = seconds(2.5) // 75 frames - premium ``` --- # Part 3: Visual Hierarchy in Motion ## Stagger Patterns ```tsx // STAGGER: Sequential reveal with delay const StaggeredList: React.FC<{ items: string[] }> = ({ items }) => { const frame = useCurrentFrame() return (
{items.map((item, i) => { const staggerDelay = i * 8 // 8 frames between each const opacity = interpolate( frame - staggerDelay, [0, 20], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" } ) const x = interpolate( frame - staggerDelay, [0, 20], [-50, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: Easing.out(Easing.cubic) } ) return (
{item}
) })}
) } ``` ## Text Reveal Hierarchy ```tsx // Headline → Subhead → CTA (proper visual hierarchy) export const TextReveal: React.FC = () => { const frame = useCurrentFrame() // HEADLINE: First, dramatic const headlineOpacity = interpolate(frame, [0, 30], [0, 1]) const headlineY = interpolate(frame, [0, 30], [40, 0], { easing: Easing.out(Easing.expo), }) // SUBHEAD: Second, subtle const subheadOpacity = interpolate(frame, [20, 45], [0, 1]) const subheadY = interpolate(frame, [20, 45], [20, 0], { easing: Easing.out(Easing.cubic), }) // CTA: Last, attention-grabbing const ctaOpacity = interpolate(frame, [40, 55], [0, 1]) const ctaScale = spring({ frame: frame - 40, fps: 30, config: { damping: 10, stiffness: 150 }, }) return (

Bold Headline

Supporting subhead text

) } ``` --- # Part 4: Audio & Sound Design ## Setup Audio ```bash npm install @remotion/media-utils ``` ## Basic Audio ```tsx import { Audio, staticFile } from "remotion" export const VideoWithAudio = () => { return ( {/* Background music */} ) } ``` ## Volume Automation ```tsx import { Audio, interpolate, useCurrentFrame } from "remotion" export const DynamicVolume = () => { const frame = useCurrentFrame() // Fade in music over first 30 frames const musicVolume = interpolate(frame, [0, 30], [0, 0.5], { extrapolateRight: "clamp", }) // Duck music when voiceover plays (frames 60-120) const duckedVolume = interpolate( frame, [55, 60, 115, 120], [0.5, 0.15, 0.15, 0.5], { extrapolateLeft: "clamp", extrapolateRight: "clamp" } ) return ( <>