Deft
Ask AI

Search

Search skills, authors and topics

remotion-dev / skills

remotion-markup

Structure Remotion scenes with markup patterns for layout, typography, and reusable video UI.

Install

npx skills add https://github.com/remotion-dev/skills --skill remotion-markup

Drive motion with interpolate() over an explicit frame range. To customize timing, use Easing.bezier or Easing.spring.

A simple linear interpolation is done using the interpolate function.

ts
import { interpolate } from "remotion";
const opacity = interpolate(frame, [0, 0.3 * fps], [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:

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

Studio-editable animation patterns

When an animation should be editable in Remotion Studio, keep the interpolate() call directly in the style prop and prefer individual CSS transform properties:

tsx
// 👍 Inline editable keyframes and transform shorthandsstyle={{  scale: interpolate(frame, [0, 100], [0, 1]),  translate: interpolate(frame, [0, 100], ["0px 0px", "100px 100px"]),  rotate: interpolate(frame, [0, 100], ["20deg", "90deg"]),}}
// 👎 Hidden values and transform strings become computed in Studioconst translateY = interpolate(frame, [0, 100], [0, 120]);const rotation = interpolate(frame, [0, 100], [0, 20]);
style={{  transform: `translateY(${translateY}px) rotate(${rotation}deg)`,}}

Use transform strings only when individual CSS transform properties do not cover the effect, such as skew(), perspective(), or order-sensitive multi-transform chains.

Spring easing

A nice push movement with no bounce:

ts
import { interpolate, Easing } from "remotion";
const opacity = interpolate(frame, [0, 0.3 * fps], [0, 1], {  easing: Easing.spring({damping: 200}),  extrapolateLeft: "clamp",  extrapolateRight: "clamp",});

Bézier easing

Pass values like you would to a CSS cubic-bezier function.

ts
import { interpolate, Easing } from "remotion";
const opacity = interpolate(frame, [0, 0.3 * fps], [0, 1], {  easing: Easing.bezier(0.16, 1, 0.3, 1),  extrapolateLeft: "clamp",  extrapolateRight: "clamp",});

Animating scale

When animating scale, if the output is linear, the perceived scale would be smaller the larger the scale gets.
Use this option to compensate:

ts
const scale = interpolate(frame, [0, 0.3 * fps], [0, 1], {  easing: Easing.bezier(0.16, 1, 0.3, 1),  extrapolateLeft: "clamp",  extrapolateRight: "clamp",  output: 'perceptual-scale' // <- Add this to scale animations});

Multiple keyframes

Add as many keyframes as you want. For multiple easings, pass an array with n - 1 items:

ts
const scale = interpolate(frame, [0, 1 * fps, 9 * fps, 10 * fps], [0, 1, 1, 0], {  easing: [Easing.bezier(0.16, 1, 0.3, 1), Easing.linear, Easing.spring({damping: 200})],  extrapolateLeft: "clamp",  extrapolateRight: "clamp",  output: 'perceptual-scale' // <- Add this to scale animations});

Posterization

You can intentionally reduce the frame rate for artistic reason. Use if it makes sense.

ts
const scale = interpolate(frame, [0, 1 * fps], [0, 1], {  easing: Easing.bezier(0.16, 1, 0.3, 1),  extrapolateLeft: "clamp",  extrapolateRight: "clamp",  posterize: 3 // Only every 3rd frame is sampled});