Loading...
Loading...
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.
npx skill4agent add digitalsamba/claude-code-video-toolkit remotionwidthheightfpsdurationInFramesnpx create-video@latest # Create new project
npx remotion studio # Launch preview studio
npx remotion render src/index.ts CompositionId out.mp4 # Render videoimport { useCurrentFrame, useVideoConfig } from 'remotion';
const MyComponent = () => {
const frame = useCurrentFrame(); // Current frame number (0-indexed)
const { fps, durationInFrames, width, height } = useVideoConfig();
return <div>Frame {frame} of {durationInFrames}</div>;
};src/Root.tsximport { Composition } from 'remotion';
export const RemotionRoot = () => (
<>
<Composition
id="MyVideo"
component={MyComponent}
durationInFrames={150}
fps={30}
width={1920}
height={1080}
defaultProps={{ title: 'Hello' }}
/>
<Composition id="AnotherVideo" ... />
</>
);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]
);extrapolateLeftextrapolateRight'extend''clamp''identity''wrap'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]);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.
});import { Sequence } from 'remotion';
<Sequence from={30} durationInFrames={60}>
<MyComponent /> {/* useCurrentFrame() starts at 0 when parent is at frame 30 */}
</Sequence>import { Series } from 'remotion';
<Series>
<Series.Sequence durationInFrames={30}><Intro /></Series.Sequence>
<Series.Sequence durationInFrames={60}><Main /></Series.Sequence>
<Series.Sequence durationInFrames={30}><Outro /></Series.Sequence>
</Series>import { Loop } from 'remotion';
<Loop durationInFrames={30} times={3}> {/* or times={Infinity} */}
<Animation />
</Loop>import { Freeze } from 'remotion';
<Freeze frame={10}>
<MyComponent /> {/* Always renders as if at frame 10 */}
</Freeze>import { AbsoluteFill, Img, Video, Audio, OffthreadVideo, staticFile } from 'remotion';
// Full-screen container
<AbsoluteFill style={{ backgroundColor: 'white' }}>
{/* Images - waits for load */}
<Img src={staticFile('image.png')} />
{/* Video - synchronized with timeline */}
<Video src={staticFile('clip.mp4')} volume={0.5} />
{/* OffthreadVideo - better performance for heavy videos */}
<OffthreadVideo src={staticFile('large.mp4')} />
{/* Audio */}
<Audio src={staticFile('music.mp3')} volume={0.8} />
</AbsoluteFill>volumeplaybackRatemutedloopstartFromendAtplaybackRateplaybackRate={2}playbackRate={interpolate(frame, [0, 100], [1, 5])}public/import { staticFile } from 'remotion';
const videoSrc = staticFile('videos/intro.mp4'); // -> /public/videos/intro.mp4// In composition
const { title, color } = getInputProps();
// CLI: npx remotion render ... --props='{"title":"Hello","color":"red"}'
// Or from file: --props=./data.jsonimport { 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 <div>{data.title}</div>;
};import { interpolateColors, useCurrentFrame } from 'remotion';
const frame = useCurrentFrame();
const color = interpolateColors(frame, [0, 30], ['#ff0000', '#0000ff']);# 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 rendersimport { 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' },
});# 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 <serve-url> MyComposition out.mp4import { 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' },
});import { Player } from '@remotion/player';
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{ width: '100%' }}
controls
loop
autoPlay
inputProps={{ title: 'Hello' }}
/>lib/transitions/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';
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={90}>
<TitleSlide />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={glitch({ intensity: 0.8 })}
timing={linearTiming({ durationInFrames: 30 })}
/>
<TransitionSeries.Sequence durationInFrames={120}>
<ContentSlide />
</TransitionSeries.Sequence>
</TransitionSeries>| Transition | Options | Best For |
|---|---|---|
| | Tech demos, edgy reveals, cyberpunk |
| | Modern tech, energetic transitions |
| | CTAs, high-energy moments, impact |
| | Celebrations, film aesthetic, warm moments |
| | Time-related content, playful reveals |
| | Retro/gaming, digital transformations |
| | Playful reveals, structured transitions |
sequentialrandomdiagonalalternatingspiralrowscolumnscenter-outcorners-in| Transition | Description |
|---|---|
| Push scene from direction |
| Simple crossfade |
| Edge reveal |
| 3D card flip |
// 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' })import { linearTiming, springTiming } from '@remotion/transitions';
// Linear: constant speed
linearTiming({ durationInFrames: 30 })
// Spring: physics-based with bounce
springTiming({ config: { damping: 200 }, durationInFrames: 45 })| 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 |
cd showcase/transitions && npm run studioextrapolateRight: 'clamp'<Video>.claude/skills/remotion/SKILL.md