Vault / wiki/401/remotion-fundamentals.md
updated 2026-07-16Remotion Fundamentals
Remotion's core idea: a video is a React component evaluated once per frame, for frames 0 .. durationInFrames - 1 at a given fps. There is no timeline editor — the timeline is your code, and every visual property is a pure function of the current frame number.
import { useCurrentFrame, useVideoConfig, interpolate } from "remotion";
export const Title: React.FC = () => {
const frame = useCurrentFrame();
const { fps, durationInFrames, width, height } = useVideoConfig();
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateRight: "clamp",
});
return <h1 style={{ opacity }}>Hello at frame {frame}</h1>;
};
The two hooks
useCurrentFrame()— the frame being rendered right now; the single source of truth for all animation.useVideoConfig()—{ fps, durationInFrames, width, height }of the enclosing composition; use it instead of hard-coding so components survive resizes and retimes.
Animation primitives
interpolate(frame, inputRange, outputRange, options) maps frame ranges to value ranges — [0, 30] → [0, 1] fades in over 30 frames. Critical option: without extrapolateRight: 'clamp' the value keeps going past the range (opacity 1.5, x-position off-screen). Clamping is the default mistake generator for newcomers; reach for {extrapolateLeft/Right: 'clamp'} reflexively.
spring() produces physically-based 0→1 motion:
const scale = spring({ frame, fps,
config: { damping: 12, stiffness: 100, mass: 1 } });
damping— how fast oscillation dies (higher = less bounce)stiffness— spring strength (higher = snappier)mass— inertia (higher = slower, heavier feel)
Composition primitives
<Sequence from={60} durationInFrames={40}> time-shifts its children: inside, useCurrentFrame() restarts at 0 when the parent hits frame 60. This local-frame reset is what makes clips composable — a component animates from "its" frame 0 regardless of where it's placed. Sequences are how you build scenes.
<AbsoluteFill> — a position: absolute; inset: 0 container for stacking layers (background / content / overlay), the video equivalent of z-layers.
<Composition> registers a renderable video with its metadata, wired up via registerRoot():
<Composition id="Explainer" component={Explainer}
durationInFrames={300} fps={30} width={1920} height={1080}
defaultProps={{ title: "Prompt Caching" }} />
id is what the studio and render CLI target; defaultProps are overridable at render time with input props (see remotion-player for how the same props flow through interactive playback).
Rendering to a file
Server-side (Node) pipeline:
const bundleLoc = await bundle({ entryPoint }); // webpack bundle
const comp = await selectComposition({ serveUrl: bundleLoc, id: "Explainer" });
await renderMedia({ composition: comp, serveUrl: bundleLoc,
codec: "h264", outputLocation: "out.mp4" });
renderMedia drives Chrome Headless Shell to screenshot every frame and encode. At scale, @remotion/lambda's renderMediaOnLambda() fans the frame range out across many AWS Lambda invocations and stitches the result — the standard approach for per-user video generation.
Licensing
Remotion is free for individuals and companies of up to 3 people; larger companies need a paid company license. Budget this before adopting it in a commercial product.
Key terms
- Composition — a registered video: component + id + durationInFrames + fps + width/height + defaultProps, targeted by the studio and render APIs.
- useCurrentFrame() — hook returning the frame currently being evaluated; all animation derives from it.
- useVideoConfig() — hook returning {fps, durationInFrames, width, height} of the enclosing composition.
- interpolate() — maps a frame range to a value range; without extrapolate clamping, values overshoot past the input range.
- spring() — physics-based 0→1 animation parameterized by damping, stiffness, and mass.
- Sequence — time-shifting container (
from,durationInFrames) inside which the local frame counter restarts at 0. - AbsoluteFill — absolutely-positioned full-size container used for layering.
- registerRoot() — entry-point call that registers your composition list with Remotion tooling.
- renderMedia() — Node API that renders a composition to a video file (e.g. codec 'h264') using Chrome Headless Shell.
- renderMediaOnLambda() — @remotion/lambda API that distributes a render across AWS Lambda for scale.
- Company license — required for companies above 3 people; Remotion is source-available, not fully free for commercial teams.
See also
- remotion-player — real-time playback without rendering files
- how-this-site-works — Remotion explainers in this site