When this skill is activated, always start your first response with the :clapper: emoji.
Remotion Video
Remotion is a framework for creating videos programmatically using React. Instead of timeline-based editors, you write compositions as React components where every frame is a function of the current frame number. This gives you the full power of TypeScript, npm packages, and component-based architecture for building videos - from animated explainers and social media clips to data-driven visualizations and personalized video at scale.
This skill covers project setup, composition structure, frame-based animations with interpolate and spring, scene sequencing, asset management, audio integration, parametrized videos with Zod schemas, and rendering to MP4/WebM via CLI or programmatic APIs.
When to use this skill
Trigger this skill when the user:
- Wants to create a video programmatically using React/TypeScript
- Asks about Remotion compositions, useCurrentFrame, or useVideoConfig
- Needs to animate text, elements, or transitions between scenes
- Wants to render a video to MP4, WebM, or GIF from code
- Asks about spring animations, interpolate, or frame-based timing
- Needs to set up a new Remotion project from scratch
- Wants to add audio, images, or fonts to a Remotion video
- Asks about parametrized/data-driven video generation
- Needs to configure Remotion Studio for previewing compositions
Do NOT trigger this skill for:
- General React questions unrelated to video creation - use React skills
- Video editing with traditional timeline tools (Premiere, DaVinci, FFmpeg CLI)
- CSS animations for web pages - use absolute-ui skill
- Video playback or streaming in web apps - use media player skills
Key principles
- Every frame is a pure function - A Remotion component receives the current
frame via useCurrentFrame() and must render deterministically for that frame. No side effects, no randomness without seeds, no reliance on wall-clock time. The same frame number must always produce the same visual output.
- Compositions are the unit of video - Each
<Composition>defines a video
with explicit dimensions (width, height), frame rate (fps), and duration (durationInFrames). Think of compositions as "pages" in your project - one per video variant or scene that can be rendered independently.
- Interpolate for everything - The
interpolate()function maps frame
numbers to any numeric value (opacity, position, scale, color channels). Combined with extrapolateRight: 'clamp', it is the workhorse for all animations. Use spring() when you need physics-based easing.
- Sequence for time offsets - Use
<Sequence from={frame}>to delay when
children start appearing, and <Series> to play children one after another. Never use setTimeout or manual frame math for sequencing - the declarative primitives handle it correctly across preview and render.
- Assets are static, data is dynamic - Put images, fonts, and audio files
in the public/ folder and reference them with staticFile(). For dynamic data (API responses, database records), use delayRender() / continueRender() to pause rendering until the data is loaded.
Core concepts
Composition structure
Every Remotion project has a root file that registers compositions:
import { Composition } from 'remotion';
import { MyVideo } from './MyVideo';
export const RemotionRoot: React.FC = () => {
return (
<Composition
id="MyVideo"
component={MyVideo}
durationInFrames={150}
fps={30}
width={1920}
height={1080}
/>
);
};
Frame-based timing
All timing in Remotion is expressed in frames, not seconds. To convert:
- Seconds to frames:
seconds * fps - Frames to seconds:
frame / fps
At 30 fps, a 5-second video is 150 frames. Frame 0 is the first frame.
Animation model
Remotion provides two core animation primitives:
| Primitive | Use case | Example | |-----------|----------|---------| | interpolate() | Linear/clamped mapping from frame to value | Fade, slide, scale | | spring() | Physics-based animation with damping/mass | Bouncy entrances, natural motion |
Both return a number you apply to styles (opacity, transform, etc.).
Common tasks
1. Set up a new Remotion project
npx create-video@latest
This scaffolds a project with TypeScript, a sample composition, and Remotion Studio configured. The project structure will be:
my-video/
src/
Root.tsx # Registers all compositions
MyComp.tsx # Your first composition component
public/ # Static assets (images, fonts, audio)
remotion.config.ts # Remotion configuration
package.json
Start the preview studio with:
npx remotion studio
2. Create a basic composition with useCurrentFrame
import { AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
export const FadeInText: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateRight: 'clamp',
});
const translateY = interpolate(frame, [0, 30], [20, 0], {
extrapolateRight: 'clamp',
});
return (
<AbsoluteFill
style={{
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#0f0f0f',
}}
>
<h1
style={{
fontSize: 80,
color: 'white',
opacity,
transform: `translateY(${translateY}px)`,
}}
>
Hello Remotion
</h1>
</AbsoluteFill>
);
};
3. Animate text word by word
Split text into words and stagger each word's appearance using <Sequence>:
import { AbsoluteFill, Sequence, useCurrentFrame, interpolate } from 'remotion';
const AnimatedWord: React.FC<{ children: string }> = ({ children }) => {
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 15], [0, 1], {
extrapolateRight: 'clamp',
});
const translateY = interpolate(frame, [0, 15], [10, 0], {
extrapolateRight: 'clamp',
});
return (
<span
style={{
display: 'inline-block',
opacity,
transform: `translateY(${translateY}px)`,
marginRight: 12,
}}
>
{children}
</span>
);
};
export const WordByWord: React.FC<{ text: string }> = ({ text }) => {
const words = text.split(' ');
return (
<AbsoluteFill
style={{
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1a1a2e',
flexWrap: 'wrap',
padding: 100,
}}
>
{words.map((word, i) => (
<Sequence key={i} from={i * 8}>
<AnimatedWord>{word}</AnimatedWord>
</Sequence>
))}
</AbsoluteFill>
);
};
4. Element animations with spring
Use spring() for physics-based animations that feel natural:
import { AbsoluteFill, useCurrentFrame, useVideoConfig, spring } from 'remotion';
export const SpringCard: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const scale = spring({
frame,
fps,
config: { damping: 200, stiffness: 100, mass: 0.5 },
});
const slideUp = spring({
frame: frame - 10,
fps,
config: { damping: 12, stiffness: 100 },
});
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center', backgroundColor: '#0d1117' }}>
<div
style={{
width: 400,
height: 250,
backgroundColor: '#161b22',
borderRadius: 16,
transform: `scale(${scale}) translateY(${(1 - slideUp) * 50}px)`,
}}
>
<p style={{ color: 'white', fontSize: 32 }}>Spring Animation</p>
</div>
</AbsoluteFill>
);
};
5. Scene transitions with Sequence and Series
Use <Sequence> for