Skip to main content

Animating properties

Animation works by changing properties over time.
Let's create a simple fade in animation.

If we want to fade the text in over 60 frames, we need to gradually change the opacity over time so that it goes from 0 to 1.

FadeIn.tsx
tsx
export const FadeIn = () => {
const frame = useCurrentFrame();
 
const opacity = Math.min(1, frame / 60);
 
return (
<AbsoluteFill
style={{
justifyContent: "center",
alignItems: "center",
backgroundColor: "white",
fontSize: 80,
}}
>
<div style={{ opacity: opacity }}>Hello World!</div>
</AbsoluteFill>
);
};
FadeIn.tsx
tsx
export const FadeIn = () => {
const frame = useCurrentFrame();
 
const opacity = Math.min(1, frame / 60);
 
return (
<AbsoluteFill
style={{
justifyContent: "center",
alignItems: "center",
backgroundColor: "white",
fontSize: 80,
}}
>
<div style={{ opacity: opacity }}>Hello World!</div>
</AbsoluteFill>
);
};

Using the interpolate helper function

Using the interpolate() function can make animations more readable. The above animation can also be written as:

tsx
import { interpolate } from "remotion";
 
const opacity = interpolate(frame, [0, 60], [0, 1], {
/* ^^^^^ ^^^^^ ^^^^
Variable to interpolate ----| | |
Input range ------------------------| |
Output range -------------------------------| */
extrapolateRight: "clamp",
});
tsx
import { interpolate } from "remotion";
 
const opacity = interpolate(frame, [0, 60], [0, 1], {
/* ^^^^^ ^^^^^ ^^^^
Variable to interpolate ----| | |
Input range ------------------------| |
Output range -------------------------------| */
extrapolateRight: "clamp",
});

In this example, we map the frames 0 to 60 to their opacity values (0, 0.0166, 0.033, 0.05 ...) and use the extrapolateRight setting to clamp the output so that it never becomes bigger than 1.

Using spring animations

Spring animations are a natural animation primitive. By default, they animate from 0 to 1 over time. This time, let's animate the scale of the text.

tsx
import { spring, useCurrentFrame, useVideoConfig } from "remotion";
 
export const MyVideo = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
 
const scale = spring({
fps,
frame,
});
 
return (
<div
style={{
flex: 1,
textAlign: "center",
fontSize: "7em",
}}
>
<div style={{ transform: `scale(${scale})` }}>Hello World!</div>
</div>
);
};
tsx
import { spring, useCurrentFrame, useVideoConfig } from "remotion";
 
export const MyVideo = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
 
const scale = spring({
fps,
frame,
});
 
return (
<div
style={{
flex: 1,
textAlign: "center",
fontSize: "7em",
}}
>
<div style={{ transform: `scale(${scale})` }}>Hello World!</div>
</div>
);
};

You should see the text jump in.


The default spring configuration leads to a little bit of overshoot, meaning the text will bounce a little bit. See the documentation page for spring() to learn how to customize it.

Always animate using useCurrentFrame()

Watch out for flickering issues during rendering that arise if you write animations that are not driven by useCurrentFrame() – for example CSS transitions.

Read more about how Remotion's rendering works - understanding it will help you avoid issues down the road.