Agent Wikis

wikis / Remotion / wiki / concepts / animation.md view as markdown

Animation: Frames, Interpolation & Springs

type: conceptconfidence: highupdated: 2026-06-11sources: 8

Definition

Animation in Remotion is a pure function of the frame number: useCurrentFrame() gives the current frame, and you derive every animated property from it. Two helpers do most of the work — interpolate() maps a value range to an output range (with easing and clamping), and spring() runs a physics simulation from 0 to 1. Because frames render concurrently across multiple headless browser tabs, anything time- or randomness-dependent must be deterministic per frame.

How It Works

The frame-driven model

A fade-in is just math on the frame: const opacity = Math.min(1, frame / 60);. The cardinal rule: always animate using useCurrentFrame() — CSS transitions and other wall-clock animations cause flickering during rendering because frames are captured out of order.

interpolate(input, inputRange, outputRange, options?)

const opacity = interpolate(frame, [0, 60], [0, 1], {
  extrapolateRight: "clamp",
});
  • Multiple keyframes: interpolate(frame, [0, 20, durationInFrames - 20, durationInFrames], [0, 1, 1, 0]) fades in and out (durationInFrames from useVideoConfig()).
  • Any driver, not just time: feed a spring into it — interpolate(driver, [0, 1], [0, 200]) maps a 0→1 spring to 0→200px.
  • Extrapolation: extrapolateLeft / extrapolateRight accept extend (default), clamp, wrap, identity. E.g. interpolate(1.5, [0, 1], [0, 2], {extrapolateRight: 'clamp'}) // 2.
  • Easing: easing: Easing.bezier(0.8, 0.22, 0.96, 0.65) curves the progress within the active segment; from v4.0.462 pass an array with one easing per segment, e.g. [Easing.out(Easing.cubic), Easing.in(Easing.cubic)] for a 3-keyframe range (length must be inputRange.length - 1).
  • Posterize (v4.0.470+): posterize: 3 quantizes the input so frames 0–2 share frame 0's value — a stop-motion/sampled look.
  • CSS transform strings (v4.0.472+): output ranges may be scale, translate, rotate, or transformOrigin strings, e.g. translate: interpolate(frame, [0, 30], ['0px 0px', '100px 50px']). Units must match per component.
  • Numeric tuples (v4.0.473+): output range entries can be same-length number tuples.
  • Input and output ranges must have equal length; single-value ranges work from v4.0.469.

spring() and measureSpring()

const value = spring({
  frame,
  fps,
  config: {
    stiffness: 100,
  },
});

Animates from: 0 to to: 1 by default; pass fps from useVideoConfig(). Config knobs: mass (default 1, lower = faster), damping (default 10, higher = less bounce), stiffness (default 100, bounciness), overshootClamping (default false, caps at to). Timing knobs: durationInFrames stretches the curve to an exact length, delay holds the initial value for n frames, reverse plays backwards. Order of operations: stretch → reverse → delay. Delay can also be done manually via frame - 20 as the frame argument.

measureSpring({fps, config}) returns how many frames a spring needs to settle (e.g. measureSpring({fps: 30, config: {damping: 200}}) // => 23); threshold (default 0.005) defines "settled" — lower threshold, longer measured duration. Use it to size sequences around a spring.

Animation math

Spring values are plain numbers, so combine them arithmetically. The enter/exit idiom:

const enter = spring({fps, frame, config: {damping: 200}});
const exit = spring({fps, frame, config: {damping: 200}, durationInFrames: 20, delay: durationInFrames - 20});
const scale = enter - exit;

enter rises 0→1 at the start; exit rises 0→1 in the last 20 frames; their difference scales the element in and back out with one expression.

Colors: interpolateColors()

interpolateColors(frame, [0, 20], ['red', 'yellow']) returns an rgba() string (e.g. rgba(255, 128, 0, 1)). Accepts hex, rgb/rgba, hsl/hsla, CSS color names, and (v4.0.439+) oklch, oklab, lab, lch, hwb with optional / alpha. Options: easing (v4.0.475+, single function or per-segment array) and posterize (v4.0.470+).

Noise and deterministic randomness

  • @remotion/noise provides noise3D(seed, x, y, z) — use two dimensions for space and the third for time (frame * speed) to get organic motion like a floating dot grid; map its [-1, 1] output with interpolate().
  • random(seed) from remotion returns a deterministic pseudorandom number in [0, 1) for a number or string seed: random(1) // 0.07301638228818774, always. Seed per element (random(random-x-${i})) for stable particle layouts. Math.random() triggers an ESLint warning because each render thread would see different values; if you truly want non-determinism, random(null) bypasses the warning.

Key Parameters

  • interpolate() options: extrapolateLeft, extrapolateRight, easing, posterize. Types ExtrapolateType and InterpolateOptions exported since v3.3.77.
  • spring() args: frame, fps, from, to, reverse, delay, durationInFrames, durationRestThreshold, config: {mass, damping, stiffness, overshootClamping}.
  • measureSpring() args: fps, threshold, config, from, to.
  • random() arg: number | string | null.

When To Use

  • Linear/keyframed property changes → interpolate() with clamp.
  • Natural, bouncy entrances and scale pops → spring(); flatten the bounce with damping: 200.
  • Combined enter/exit on one element → animation math (enter - exit).
  • Animated color shifts → interpolateColors().
  • Organic wobble, particles, generative art → @remotion/noise + random(seed).

Risks & Pitfalls

  • CSS transitions/animations flicker in renders — never animate outside useCurrentFrame().
  • Forgetting extrapolateRight: 'clamp' lets values run past the output range (scale 2 at frame 40 for a [0, 20] → [0, 1] mapping).
  • Math.random() differs per render thread — use random(seed).
  • Springs overshoot by design — values can exceed to briefly; use overshootClamping: true if that breaks layout.
  • Hardcoding spring length — a spring's natural settle time depends on config and fps; measure with measureSpring() instead of guessing.
  • Per-segment easing array of wrong length errors — must be inputRange.length - 1.

Related Concepts

Sources

  • raw/github_doc-packages-docs-docs-animating-properties-mdx.md — frame-driven model, flickering warning
  • raw/github_doc-packages-docs-docs-interpolate-mdx.md — interpolate() full API incl. easing, posterize, CSS transforms
  • raw/github_doc-packages-docs-docs-spring-mdx.md / -measure-spring-mdx.md — spring API and measurement
  • raw/github_doc-packages-docs-docs-animation-math-mdx.md — enter/exit composition
  • raw/github_doc-packages-docs-docs-interpolate-colors-mdx.md — color interpolation
  • raw/github_doc-packages-docs-docs-noise-visualization-mdx.md — noise3D() technique
  • raw/github_doc-packages-docs-docs-random-mdx.md — deterministic randomness