remotion-video
This skill should be used when the user asks to "make a video with Remotion", "create a programmatic/data-driven video in React", "render an MP4/GIF from code", "animate with useCurrentFrame/interpolate/spring", "sync video to audio/beats", or "render a templated video per record headlessly". Covers building React compositions and rendering them via CLI or @remotion/renderer.
How do I install this agent skill?
npx skills add https://github.com/iart-ai/motion-design-skills --skill remotion-videoIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill provides a comprehensive guide for using Remotion to create programmatic videos using React. It includes standard CLI commands for rendering and single-frame inspection, as well as code examples for motion graphics, audio syncing, and data-driven compositions. No security issues or malicious patterns were detected.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Remotion (Programmatic Video)
Build real MP4/GIF/WebM videos in React. Every frame is a pure function of useCurrentFrame(), so output is deterministic, scrubbable, diffable, and renderable in CI. The code-first alternative to After Effects for templated and data-driven motion graphics.
When to use
- Render MP4/GIF/WebM from code (social clips, title cards, explainers).
- Templated/data-driven videos: one composition, many outputs from props (per-user, per-record, per-row of a CSV/DB).
- Motion graphics that must be versioned, code-reviewed, and rendered in CI without a GUI.
- Programmatic audio sync, charts that animate from data, or embedding shaders/Three.js into video.
Core techniques
Frame-driven animation
Animation is derived from the current frame, never from setState or requestAnimationFrame. interpolate maps an input range to an output range; spring produces physically natural motion.
import {useCurrentFrame, useVideoConfig, interpolate, spring} from 'remotion';
export const Title = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
// Fade in over frames 0-30, then stay (clamp prevents over/undershoot).
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
// Spring entrance; divide by spring duration is unnecessary — drive transforms directly.
const scale = spring({frame, fps, config: {damping: 200, mass: 1, stiffness: 100}});
return <h1 style={{opacity, transform: `scale(${scale})`}}>Hello</h1>;
};
Always clamp interpolate unless an intentional overshoot is desired — by default it extrapolates linearly past the range, which produces opacity > 1 or negative values.
Scheduling: Sequence and Series
<Sequence> shifts time: children see frame reset to 0 at the sequence's from. Use it to place clips on a timeline. <Series> lays out back-to-back segments without manual offset math.
import {Sequence, Series, AbsoluteFill} from 'remotion';
export const Timeline = () => (
<AbsoluteFill style={{backgroundColor: 'black'}}>
<Sequence from={0} durationInFrames={60}><Intro /></Sequence>
<Sequence from={60} durationInFrames={90}><Body /></Sequence>
{/* Series auto-sequences; offset overlaps the previous segment for crossfades */}
<Series>
<Series.Sequence durationInFrames={60}><ShotA /></Series.Sequence>
<Series.Sequence durationInFrames={60} offset={-15}><ShotB /></Series.Sequence>
</Series>
</AbsoluteFill>
);
Composition registration + parametric props
The <Composition> declares id, size, fps, duration, and defaultProps. A zod schema makes props type-safe and editable in the Studio sidebar.
import {Composition} from 'remotion';
import {z} from 'zod';
export const schema = z.object({
title: z.string(),
accent: z.string(),
fps: z.number().default(30),
});
export const Root = () => (
<Composition
id="Promo"
component={Promo}
durationInFrames={150}
fps={30}
width={1080}
height={1920}
schema={schema}
defaultProps={{title: 'Launch', accent: '#5b8cff', fps: 30}}
/>
);
To make duration data-dependent, use calculateMetadata on the Composition to compute durationInFrames from props (e.g. number of rows × frames per row) before render.
Audio and beat sync
import {Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const BEATS_SEC = [0.5, 1.0, 1.5, 2.0]; // detected offline
export const Music = ({children}) => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const t = frame / fps;
const onBeat = BEATS_SEC.some((b) => Math.abs(t - b) < 1 / fps);
return (
<>
<Audio src={staticFile('track.mp3')} />
<div style={{transform: `scale(${onBeat ? 1.06 : 1})`}}>{children}</div>
</>
);
};
Detect beats offline (e.g. with web-audio-beat-detector or aubio) and bake the timestamps into props — never analyze audio at render time, since headless rendering has no realtime audio clock.
Rendering
Preview in the browser-based Studio; render headlessly via CLI or the programmatic API.
npx remotion studio # interactive preview
npx remotion render Promo out/promo.mp4 \
--props='{"title":"Launch","accent":"#f43"}' # pass parametric props
npx remotion render Promo out.gif --codec=gif # GIF output
For batch/data-driven pipelines, render in Node with @remotion/renderer (bundle once, render many) — see the reference file.
Deliver & verify (rendered stills → MP4)
Packaged helper (
scripts/): tile your stills withscripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png, then assert the encode withscripts/probe-mp4.sh out.mp4 [WxH] [fps]. Seescripts/README.md.
Remotion is frame-deterministic by construction — every frame is a pure function of useCurrentFrame(), so you can render any exact frame headlessly with no seek harness (this is the heavy-tier counterpart to a web scene's ?t=N). Use this tier when the output must be an MP4/GIF, must carry exact numbers/text, or batches from data; for a lightweight web animation, deliver standalone HTML instead.
Output contract:
- A Remotion project with the composition registered (
<Composition>+ zodschema+defaultProps), all motion frame-driven (no timers /Date.now()/Math.random()). - Deliverable = the rendered
out/*.mp4(plus the project, so the user can re-render with new props/data). - Duration data-dependent? compute it in
calculateMetadata, not by hand.
Verify loop — render stills → inspect → encode. Render single frames first (cheap, no video encode), inspect them, and encode the full video only once the frames are right.
# 1. Frame-exact stills at start / mid / end (PNG, headless, fast)
npx remotion still Promo out/f-start.png --frame=0
npx remotion still Promo out/f-mid.png --frame=75
npx remotion still Promo out/f-end.png --frame=149 # last frame = durationInFrames - 1
# render with the SAME props you'll ship, not just defaultProps:
# npx remotion still Promo out/f-mid.png --frame=75 --props='{"title":"Launch"}'
# 2. Inspect each PNG — fidelity (matches brief; numbers/text correct) AND
# artifacts (text overflow, off-canvas, clipped safe-area, missing font, wrong data binding).
# 3. Only after the stills check out, encode the video:
npx remotion render Promo out/promo.mp4 --props='{"title":"Launch"}'
- Use
npx remotion compositionsto read each composition'sdurationInFrames/fpsand pick the end frame. - Data-driven / batch: verify ONE representative props set via stills before batch-rendering all rows — catch a layout bug once instead of N times.
- README demo GIF for free:
npx remotion render Promo out/demo.gif --codec=gifproduces the first-screen proof clip (Direction D).
Before you finish:
npx remotion stillrenders cleanly at frame 0, mid, and last — no errors, no missing assets/fonts.- Numbers/text are exact and inside safe areas at every checked frame.
- Frame-driven only — no
Date.now()/Math.random()/ timers (determinism holds in CI). - Props are zod-typed; the shipped props render correctly (not just
defaultProps). - Full MP4 encoded and plays; (optional) GIF rendered for the README.
Quick reference
| Need | Use |
|---|---|
| Map time → value | interpolate(frame, [a,b], [x,y], {extrapolateRight:'clamp'}) |
| Natural easing | spring({frame, fps, config}) |
| Place a clip at t | <Sequence from durationInFrames> |
| Back-to-back shots | <Series> |
| Audio | <Audio src={staticFile(...)} /> |
| Frame ↔ seconds | frame / fps |
| Loop a value | frame % period then interpolate |
| Editable props | zod schema on <Composition> |
| CI render | npx remotion render or @remotion/renderer |
Gotchas
- Never use
Math.random(),Date.now(), or animation timers — they break determinism. Userandom(seed)from Remotion for stable per-frame randomness. - Load fonts and assets via
staticFile()and wait withdelayRender/continueRender, or fonts pop in mid-render. - Default
interpolateextrapolates — clamp it. useCurrentFrameinside a<Sequence>is local (starts at 0); useuseVideoConfig().durationInFramesfor absolute timing.
Reference files
references/api-and-patterns.md—interpolateoptions andEasing, spring config recipes, Sequence/Series scheduling,<Audio>+ beat-sync, parametricdefaultPropswith zod +calculateMetadata, CLI flags, programmatic@remotion/rendererbatch rendering, and embedding GLSL shaders / Three.js (@remotion/three).
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/iart-ai/motion-design-skills/remotion-video">View remotion-video on skillZs</a>