Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply best practices for creating programmatic videos with Remotion and React
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/timing.md
1---2name: timing3description: Interpolation and timing in Remotion—prefer interpolate with Bézier easing; springs as a specialized option4metadata:5tags: easing, bezier, interpolation, spring, timing6---78Drive motion with `interpolate()` over an explicit frame range. Prefer `interpolate()` over `spring()` unless the user explicitly asks for physics-based motion. To customize timing, use **`Easing.bezier`**. The four parameters are the same as CSS `cubic-bezier(x1, y1, x2, y2)`.910A simple linear interpolation is done using the `interpolate` function.1112```ts title="Going from 0 to 1 over 100 frames"13import { interpolate } from "remotion";1415const opacity = interpolate(frame, [0, 100], [0, 1]);16```1718By default, the values are not clamped, so the value can go outside the range [0, 1].19Here is how they can be clamped:2021```ts title="Going from 0 to 1 over 100 frames with extrapolation"22const opacity = interpolate(frame, [0, 100], [0, 1], {23extrapolateRight: "clamp",24extrapolateLeft: "clamp",25});26```2728## Studio-editable animation patterns2930When an animation should be editable in Remotion Studio, keep the `interpolate()` call directly in the `style` prop and prefer individual CSS transform properties:3132```tsx33style={{34scale: interpolate(frame, [0, 100], [0, 1]),35translate: interpolate(frame, [0, 100], ["0px 0px", "100px 100px"]),36rotate: interpolate(frame, [0, 100], ["20deg", "90deg"]),37}}38```3940Avoid extracting the value and composing a `transform` string:4142```tsx43const scale = interpolate(frame, [0, 100], [0, 1]);4445style={{46transform: `scale(${scale})`,47}}48```4950Use `transform` strings only when individual CSS transform properties do not cover the effect, such as `skew()`, `perspective()`, or order-sensitive multi-transform chains.5152## Bézier easing5354Use `Easing.bezier(x1, y1, x2, y2)` inside the `interpolate` options object. The curve is identical in spirit to CSS animations and transitions, which helps when you are stealing timing from the web or from a designer’s spec.5556```ts57import { interpolate, Easing } from "remotion";5859const opacity = interpolate(frame, [0, 60], [0, 1], {60easing: Easing.bezier(0.16, 1, 0.3, 1),61extrapolateLeft: "clamp",62extrapolateRight: "clamp",63});64```6566### Examples (copy-paste curves)6768**1. Crisp UI entrance (strong ease-out, no overshoot)** — slows nicely into the rest value; similar to many system “deceleration” curves.6970```tsx71const enter = interpolate(frame, [0, 45], [0, 1], {72easing: Easing.bezier(0.16, 1, 0.3, 1),73extrapolateLeft: "clamp",74extrapolateRight: "clamp",75});76```7778**2. Editorial / slow fade (balanced ease-in-out)** — symmetric acceleration and deceleration over a hold-friendly move.7980```tsx81const progress = interpolate(frame, [0, 90], [0, 1], {82easing: Easing.bezier(0.45, 0, 0.55, 1),83extrapolateLeft: "clamp",84extrapolateRight: "clamp",85});86```8788**3. Playful overshoot (control point y > 1)** — a little past the target then settles; use sparingly for emphasis.8990```tsx91const pop = interpolate(frame, [0, 30], [0, 1], {92easing: Easing.bezier(0.34, 1.56, 0.64, 1),93extrapolateLeft: "clamp",94extrapolateRight: "clamp",95});96```9798## Preset easings (`Easing.in` / `Easing.out` / named curves)99100Easing can be added to the `interpolate` function without a custom cubic:101102```ts103import { interpolate, Easing } from "remotion";104105const value1 = interpolate(frame, [0, 100], [0, 1], {106easing: Easing.inOut(Easing.cubic),107extrapolateLeft: "clamp",108extrapolateRight: "clamp",109});110```111112The default easing is `Easing.linear`.113Convexities:114115- `Easing.in` — starting slow and accelerating116- `Easing.out` — starting fast and slowing down117- `Easing.inOut`118119Named curves (from most linear to most curved):120121- `Easing.quad`122- `Easing.cubic` (good default when you do not need a custom cubic)123- `Easing.sin`124- `Easing.exp`125- `Easing.circle`126127### Easing direction for enter/exit animations128129Use `Easing.out` for enter animations (starts fast, decelerates into place) and `Easing.in` for exit animations (starts slow, accelerates away). This feels natural because elements arrive with momentum and leave with gravity. When you need a specific curve from design, prefer a single `Easing.bezier(...)` instead of stacking presets.130131## Composing interpolations132133When multiple properties share the same timing and do not need Studio keyframe editing (e.g. a slide-in panel and a video shift), avoid duplicating the full interpolation for each property. Instead, create a single normalized progress value (0 to 1) and derive each property from it:134135```tsx136const slideIn = interpolate(137frame,138[slideInStart, slideInStart + slideInDuration],139[0, 1],140{141easing: Easing.bezier(0.22, 1, 0.36, 1),142extrapolateLeft: "clamp",143extrapolateRight: "clamp",144},145);146const slideOut = interpolate(147frame,148[slideOutStart, slideOutStart + slideOutDuration],149[0, 1],150{ easing: Easing.in(Easing.cubic), extrapolateLeft: "clamp", extrapolateRight: "clamp" },151);152const progress = slideIn - slideOut;153154// Derive multiple properties from the same progress155const overlayX = interpolate(progress, [0, 1], [100, 0]);156const videoX = interpolate(progress, [0, 1], [0, -20]);157const opacity = interpolate(progress, [0, 1], [0, 1]);158```159160The key idea: separate **timing** (when and how fast) from **mapping** (what values to animate between).161162If the values should be visually keyframed in Studio, prefer inline `interpolate()` calls in the relevant style props, even if it duplicates the timing.163