packages/docs/docs/interpolate.mdx
Allows you to map a range of values to another using a concise syntax.
In this example, we are fading in some content by calculating the opacity for a certain point of time. At frame 0 (the start of the video), we want the opacity to be 0. At frame 20, we want the opacity to be 1.
Using the following snippet, we can calculate the current opacity for any frame:
import {interpolate, useCurrentFrame} from 'remotion';
const frame = useCurrentFrame(); // 10
const opacity = interpolate(frame, [0, 20], [0, 1]); // 0.5
We keep our fade in effect but add a fade out effect at the end. 20 frames before the video ends, the opacity should still be 1. At the end, the opacity should be 0.
We can interpolate over multiple points in one go and use useVideoConfig() to determine the duration of the composition.
import {interpolate, useCurrentFrame, useVideoConfig} from 'remotion';
const frame = useCurrentFrame();
const {durationInFrames} = useVideoConfig();
const opacity = interpolate(
frame,
[0, 20, durationInFrames - 20, durationInFrames],
// v--v---v----------------------v
[0, 1, 1, 0],
);
We don't necessarily have to interpolate over time - we can use any value to drive an animation. Let's assume we want to animate an object on the X axis from 0 to 200 pixels and use a spring animation for it.
Let's create a spring:
import {useCurrentFrame, interpolate, spring, useVideoConfig} from 'remotion';
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const driver = spring({
frame,
fps
});
// - spring
// @include: example-spring
A spring() animation with it's default settings will animate from 0 to 1.
Given that knowledge, we can interpolate the spring value to go from 0 to 200.
// @include: example-spring
// ---cut---
const marginLeft = interpolate(driver, [0, 1], [0, 200]);
We can then apply it to an HTML element.
// @include: example-spring
const marginLeft = interpolate(driver, [0, 1], [0, 200]);
// ---cut---
const Component: React.FC = () => <div style={{marginLeft}}></div>;
Consider the following interpolation which is supposed to animate the scale over 20 frames:
import {interpolate, useCurrentFrame} from 'remotion';
const frame = useCurrentFrame();
// ---cut---
const scale = interpolate(frame, [0, 20], [0, 1]);
This works, but after 20 frames, the value keeps growing. For example, at frame 40, the scale will be 2.
To prevent this, this we can use the extrapolateLeft and extrapolateRight options and set them to 'clamp' to prevent the result going outside the output range.
import {interpolate, useCurrentFrame} from 'remotion';
const frame = useCurrentFrame();
// ---cut---
const scale = interpolate(frame, [0, 20], [0, 1], {
extrapolateRight: 'clamp',
});
outputRange may contain scale, translate, or rotate strings.
Each value may contain up to three components.
import {interpolate, useCurrentFrame} from 'remotion';
export const MyComposition: React.FC = () => {
const frame = useCurrentFrame();
return (
<div
style={{
scale: interpolate(frame, [0, 30], ['1', '2 3']),
translate: interpolate(frame, [0, 30], ['0px 0px', '100px 50px']),
rotate: interpolate(frame, [0, 30], ['0deg', '90deg']),
}}
/>
);
};
Scale values use unitless numbers.
Translate values use length or percentage units.
Rotate values use deg, rad, grad, or turn.
All values in one interpolation must have the same type.
For each component, units must match.
For missing dimensions, CSS defaults are used: scale defaults to 1, translate and rotate default to 0.
outputRange may contain numeric tuples.
Each tuple must contain the same number of numbers.
import {interpolate, useCurrentFrame} from 'remotion';
export const MyComposition: React.FC = () => {
const frame = useCurrentFrame();
const start: readonly [number, number] = interpolate(
frame,
[0, 60],
[
[0, 0.5],
[1, 0.5],
],
);
return <div>{start.join(', ')}</div>;
};
Takes four arguments:
inputRange and outputRange must have the same length and at least one value.
With one value, interpolate() always returns the only output value.
Single-value ranges are supported from <AvailableFrom v="4.0.469" inline />.
Default: extend
What should happen if the input value is outside the left side of the input range:
extend: Interpolate nonetheless, even if outside output range.clamp: Return the closest value inside the range insteadwrap: Loops the value change.identity: Return the input value instead.Default: extend
Same as extrapolateLeft, except for values outside right the input range.
Example:
import {interpolate} from 'remotion';
// ---cut---
interpolate(1.5, [0, 1], [0, 2], {extrapolateRight: 'extend'}); // 3
interpolate(1.5, [0, 1], [0, 2], {extrapolateRight: 'clamp'}); // 2
interpolate(1.5, [0, 1], [0, 2], {extrapolateRight: 'identity'}); // 1.5
interpolate(1.5, [0, 1], [0, 2], {extrapolateRight: 'wrap'}); // 1
Default: (x) => x
Pass a single function to customize the normalized progress within the active segment (between two adjacent keyframes), for example to apply an easing curve. By default, the input is left unmodified, resulting in a pure linear interpolation. Read the documentation for the built-in easing functions.
import {useCurrentFrame} from 'remotion';
const frame = useCurrentFrame();
// ---cut---
import {interpolate, Easing} from 'remotion';
interpolate(frame, [0, 100], [0, 1], {
easing: Easing.bezier(0.8, 0.22, 0.96, 0.65),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
interpolate(frame, [0, 10, 40, 100], [0, 0.2, 0.6, 1], {
easing: Easing.bezier(0.8, 0.22, 0.96, 0.65),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
You can pass an array of easing functions with one entry per segment between consecutive keyframes. Its length must be inputRange.length - 1 (the same as outputRange.length - 1). The first easing applies between the first and second keyframe, the second easing between the second and third, and so on.
For a single keyframe, pass an empty array.
import {useCurrentFrame} from 'remotion';
const frame = useCurrentFrame();
// ---cut---
import {interpolate, Easing} from 'remotion';
interpolate(frame, [0, 100, 200], [0, 1, 2], {
easing: [Easing.out(Easing.cubic), Easing.in(Easing.cubic)],
});
Default: no posterization
Quantizes the input value before interpolation. Use it to sample an animation every n frames instead of updating on every frame.
import {interpolate, useCurrentFrame} from 'remotion';
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 60], [0, 1], {
posterize: 3,
});
With posterize: 3, frames 0, 1, and 2 use the value for frame 0; frames 3, 4, and 5 use the value for frame 3, and so on.
posterize must be a positive finite number.
Since v3.3.77, types for the options are exported from Remotion.
import {ExtrapolateType, InterpolateOptions} from 'remotion';
const extrapolate: ExtrapolateType = 'clamp';
const option: InterpolateOptions = {
extrapolateLeft: extrapolate,
posterize: 3,
};