Files
calesthioandHanzo Dev 7ffb943132 Initial release — OpenMontage: the first open-source agentic video production system
11 production pipelines, 47 tools, 124 agent skills.
Supports cloud APIs (fal.ai, OpenAI, ElevenLabs, Suno, HeyGen, Runway) and
free local providers (diffusers, Piper TTS, WAN 2.1, Hunyuan, CogVideo).

Co-authored-by: Hanzo Dev <[email protected]>
2026-03-29 08:25:17 -07:00

3.9 KiB

name, description, metadata
name description metadata
timing Interpolation curves in Remotion - linear, easing, spring animations
tags
spring, bounce, easing, interpolation

A simple linear interpolation is done using the interpolate function.

import { interpolate } from "remotion";

const opacity = interpolate(frame, [0, 100], [0, 1]);

By default, the values are not clamped, so the value can go outside the range [0, 1].
Here is how they can be clamped:

const opacity = interpolate(frame, [0, 100], [0, 1], {
  extrapolateRight: "clamp",
  extrapolateLeft: "clamp",
});

Spring animations

Spring animations have a more natural motion.
They go from 0 to 1 over time.

import { spring, useCurrentFrame, useVideoConfig } from "remotion";

const frame = useCurrentFrame();
const { fps } = useVideoConfig();

const scale = spring({
  frame,
  fps,
});

Physical properties

The default configuration is: mass: 1, damping: 10, stiffness: 100.
This leads to the animation having a bit of bounce before it settles.

The config can be overwritten like this:

const scale = spring({
  frame,
  fps,
  config: { damping: 200 },
});

The recommended configuration for a natural motion without a bounce is: { damping: 200 }.

Here are some common configurations:

const smooth = { damping: 200 }; // Smooth, no bounce (subtle reveals)
const snappy = { damping: 20, stiffness: 200 }; // Snappy, minimal bounce (UI elements)
const bouncy = { damping: 8 }; // Bouncy entrance (playful animations)
const heavy = { damping: 15, stiffness: 80, mass: 2 }; // Heavy, slow, small bounce

Delay

The animation starts immediately by default.
Use the delay parameter to delay the animation by a number of frames.

const entrance = spring({
  frame: frame - ENTRANCE_DELAY,
  fps,
  delay: 20,
});

Duration

A spring() has a natural duration based on the physical properties.
To stretch the animation to a specific duration, use the durationInFrames parameter.

const spring = spring({
  frame,
  fps,
  durationInFrames: 40,
});

Combining spring() with interpolate()

Map spring output (0-1) to custom ranges:

const springProgress = spring({
  frame,
  fps,
});

// Map to rotation
const rotation = interpolate(springProgress, [0, 1], [0, 360]);

<div style={{ rotate: rotation + "deg" }} />;

Adding springs

Springs return just numbers, so math can be performed:

const frame = useCurrentFrame();
const { fps, durationInFrames } = useVideoConfig();

const inAnimation = spring({
  frame,
  fps,
});
const outAnimation = spring({
  frame,
  fps,
  durationInFrames: 1 * fps,
  delay: durationInFrames - 1 * fps,
});

const scale = inAnimation - outAnimation;

Easing

Easing can be added to the interpolate function:

import { interpolate, Easing } from "remotion";

const value1 = interpolate(frame, [0, 100], [0, 1], {
  easing: Easing.inOut(Easing.quad),
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
});

The default easing is Easing.linear.
There are various other convexities:

  • Easing.in for starting slow and accelerating
  • Easing.out for starting fast and slowing down
  • Easing.inOut

and curves (sorted from most linear to most curved):

  • Easing.quad
  • Easing.sin
  • Easing.exp
  • Easing.circle

Convexities and curves need be combined for an easing function:

const value1 = interpolate(frame, [0, 100], [0, 1], {
  easing: Easing.inOut(Easing.quad),
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
});

Cubic bezier curves are also supported:

const value1 = interpolate(frame, [0, 100], [0, 1], {
  easing: Easing.bezier(0.8, 0.22, 0.96, 0.65),
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
});