Animation & Timing
In Remotion, animations are not based on real-time intervals or CSS transitions. Instead, they are frame-driven and deterministic. Every visual change must be a pure function of the current frame number to ensure consistent rendering and avoid flickering.
The Foundation: useCurrentFrame
The useCurrentFrame() hook is the primary source of truth for timing. It returns the current frame index (starting at 0) of the composition.
Rule: No CSS Animations
Standard CSS @keyframes, transitions, or Tailwind animation utility classes (e.g., animate-bounce) are forbidden. These rely on the browser's internal clock, which does not synchronize with Remotion's frame-by-frame rendering engine.
Rule: Time-to-Frame Conversion
To make animations intuitive, define durations in seconds and multiply them by the composition's fps (frames per second) obtained from useVideoConfig().
import { useCurrentFrame, useVideoConfig } from "remotion";
const MyAnimation = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Calculate 2 seconds worth of frames
const durationInFrames = 2 * fps;
// ... animation logic
};
Interpolation
The interpolate() function is the standard way to map the current frame to a visual value (such as opacity, scale, or position). It transforms an input value (usually the frame) from an input range to an output range.
Basic Usage
import { interpolate, useCurrentFrame } from "remotion";
const frame = useCurrentFrame();
const opacity = interpolate(
frame,
[0, 30], // Input range (from frame 0 to 30)
[0, 1], // Output range (from 0% to 100% opacity)
{
extrapolateRight: "clamp", // Ensures value doesn't exceed 1 after frame 30
}
);
return <div style={{ opacity }}>Fading In</div>;
Interpolation Options
| Property | Description |
| :--- | :--- |
| extrapolateLeft | Behavior when the frame is below the input range (clamp, extend, identity). |
| extrapolateRight | Behavior when the frame is above the input range. Defaults to extend. |
| easing | A function to change the curve (e.g., Easing.bezier). |
Spring Physics
For natural-looking motion, use the spring() function. Unlike linear interpolation, springs simulate physical properties like stiffness and damping.
Usage
The spring() function returns a value between 0 and 1 by default (though it can overshoot 1 depending on the "bounciness").
import { spring, useCurrentFrame, useVideoConfig } from "remotion";
const MyComponent = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const scale = spring({
frame,
fps,
config: {
stiffness: 100,
damping: 10,
},
});
return (
<div style={{ transform: `scale(${scale})` }}>
Springy Content
</div>
);
};
Key Parameters
frame: The current frame (usuallyuseCurrentFrame()).fps: The composition's frames per second.delay: Number of frames to wait before starting the spring.config:stiffness: Higher values make the spring move faster and feel "tighter".damping: Higher values reduce the oscillation (bounciness).mass: Higher values make the object feel heavier.
Sequencing and Delays
To trigger animations at different times, subtract the start frame from the current frame within your animation functions.
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Starts at 1 second (fps * 1), reaches full height at 2 seconds
const height = spring({
frame: frame - fps,
fps,
config: { damping: 20 }
});
3D Animation (Three.js)
When using @remotion/three, the standard useFrame() hook from React Three Fiber is forbidden because it runs on the browser's requestAnimationFrame clock.
Instead, you must drive 3D attributes directly with useCurrentFrame().
import { useCurrentFrame } from "remotion";
const RotatingBox = () => {
const frame = useCurrentFrame();
// Rotate 0.02 radians per frame
const rotationY = frame * 0.02;
return (
<mesh rotation={[0, rotationY, 0]}>
<boxGeometry />
<meshStandardMaterial color="blue" />
</mesh>
);
};
Summary Checklist
- Always use
useCurrentFrame()to drive property changes. - Never use CSS
transitionoranimationproperties. - Use
interpolate()for linear or eased transitions. - Use
spring()for physics-based, natural motion. - Clamp your interpolations to prevent values from leaking outside your desired range unless intentional.