PTENES
MÓDULO 1.2

📈 interpolate() — el frame se convierte en valor

O interpolate() es la herramienta central de Remotion: le das un frame y te devuelve un número —opacidad, posición, escala, color—. Una llamada, infinitas animaciones.

6
Temas
40
Minutos
Básico
Nivel
Práctico
Tipo
frame 42 interpolate(frame, [0, 30], [0, 1]) inputRange → outputRange opacity 1.4 entrada: frame actual clamp: el valor queda entre 0 y 1 salida: cualquier número
1

📝 La firma de interpolate()

O interpolate() recibe cuatro argumentos: o valor de entrada (casi siempre frame), o inputRange, o outputRange y opciones opcionales. A cambio, devuelve un número calculado mediante interpolación lineal entre los puntos.

Firma completa interpolate.ts
import { interpolate, useCurrentFrame } from "remotion";

const frame = useCurrentFrame();

// interpolate(valor, inputRange, outputRange, opcoes?)
const opacity = interpolate(
  frame,            // entrada: número atual
  [0, 30],          // inputRange: do frame 0 ao 30
  [0, 1],           // outputRange: de 0 a 1 (opacidade)
  { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);

🎯 Qué hace cada argumento

  • •frame — el número que cambia en cada cuadro; puede ser cualquier variable numérica.
  • •inputRange — la ventana de fotogramas en la que ocurre la animación (al menos 2 puntos).
  • •outputRange — los valores de salida correspondientes; pueden ser píxeles, grados, decimales.
  • •opciones — controla lo que ocurre fuera del inputRange (clamp, extend, wrap).
arg 1
Valor de entrada
arg 2
inputRange []
arg 3
outputRange []
arg 4
opciones (opcional)
2

🗺️ inputRange y outputRange — dominio y codominio

Piensa en inputRange como el dominio (qué frames forman parte de la animación) y outputRange como el contradominio (qué valores se obtienen). El interpolate() encuentra el punto proporcionalmente equivalente dentro del outputRange.

📊 Ejemplos de mapeo

  • [0, 30] → [0, 1] — fade-in: la opacidad crece de 0 a 1 en 1 segundo (30fps).
  • [0, 30] → [0, 300] — deslizar: translateX va de 0 a 300px en 1 segundo.
  • [0, 30] → [0.5, 1] — escala: el objeto comienza a la mitad de su tamaño y crece hasta el 100%.
  • [0, 30] → [360, 0] — rotación inversa: comienza girado 360° y llega a 0.
Deslizamiento + opacidad juntos SlideIn.tsx
const opacity = interpolate(frame, [0, 20], [0, 1], { extrapolateRight: "clamp" });
const translateY = interpolate(frame, [0, 20], [40, 0], { extrapolateRight: "clamp" });

return (
  <div style={{ opacity, transform: `translateY(${translateY}px)` }}>
    Conteúdo que entra de baixo
  </div>
);

💡 Consejo: los rangos no necesitan empezar en 0

Puedes usar [45, 60] como inputRange para que la animación comience 1,5s después del inicio del video. Lo que queda fuera del rango se controla con la opción extrapolate.

Dominio
inputRange de fotogramas
Contradominio
outputRange de valores
Lineal
Proporcional por defecto
Cualquier valor
px, grados, 0–1
3

🔒 extrapolate: clamp vs extend

Qué sucede cuando frame sale de inputRange? Por defecto, el interpolate() extiende la línea más allá de los puntos definidos — lo que puede hacer que la opacidad supere 1 o baje de 0. El clamp evita esto.

✓ Qué HACER

  • ✓Usar extrapolateRight: "clamp" en opacidad para que nunca supere 1.
  • ✓Usar extrapolateLeft: "clamp" para mantener el valor antes de que comience la animación.
  • ✓Dejar extend (predeterminado) solo cuando la extrapolación tenga sentido (p. ej., una posición que continúa).

✗ Qué NO hacer

  • ✗Dejar la opacidad sin clamp — en el frame 60, [0,30]→[0,1] devuelve 2 (invisible en CSS).
  • ✗Olvidar el extrapolateLeft cuando la animación empieza tarde (frame 45+).
  • ✗Usar opciones diferentes de clamp/extend/wrap/identity — no existen.
clamp en ambos lados Fade.tsx
// SEM clamp: frame=60 → opacity=2 (bug visual)
const opacityBug = interpolate(frame, [0, 30], [0, 1]);

// COM clamp: frame=60 → opacity=1 (correto)
const opacity = interpolate(frame, [0, 30], [0, 1], {
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
});
clamp
Se mantiene en los extremos
extend
Continúa la recta
wrap
Se reinicia en bucle
Patrón
extend (¡cuidado!)
4

🔑 Múltiples keyframes — fade-in / hold / fade-out

O inputRange e o outputRange aceptan más de dos puntos. Esto crea keyframes: la animación pasa por cada par [frame → valor] en secuencia. Es como el timeline de un editor de video, pero en código.

0

frame 0 → opacity 0

Elemento invisible al inicio.

15

frame 15 → opacity 1

Fade-in completo en 0,5s.

75

frame 75 → opacity 1

Permanece totalmente visible hasta los 2,5s: el "hold".

90

frame 90 → opacity 0

Fade-out de 0,5s antes del corte.

fade-in / hold / fade-out FadeInOut.tsx
const opacity = interpolate(
  frame,
  [0, 15, 75, 90],   // 4 keyframes
  [0,  1,  1,  0],   // entra, segura, sai
  { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
Keyframes
N puntos en el rango
Hold
El mismo valor repetido
Patrón textual
0→1→1→0
Flexible
Cualquier secuencia
5

🎨 Easing — movimiento natural

Por defecto, el interpolate() hace una interpolación linear — velocidad constante de principio a fin. Para un movimiento natural, usa la opción easing con funciones del módulo Easing de Remotion (compatible con React Native).

🎯 Easings más usados

  • •Easing.out(Easing.ease) — empieza rápido y se desacelera al final. Clásica para entradas.
  • •Easing.in(Easing.ease) — empieza despacio y acelera. Buena para salidas.
  • •Easing.inOut(Easing.ease) — suave en ambos extremos. Sólido para transiciones.
  • •Easing.bezier(0.25, 0.1, 0.25, 1) — control total con curva cúbica.
  • •Easing.cubic — alternativa rápida a bezier con curva cúbica estándar.
Entrada con easing natural EasedSlide.tsx
import { interpolate, Easing, useCurrentFrame } from "remotion";

const frame = useCurrentFrame();

const translateY = interpolate(frame, [0, 25], [60, 0], {
  extrapolateRight: "clamp",
  easing: Easing.out(Easing.cubic),
});

💡 Lineal vs. easing en la práctica

Una animación lineal parece «mecánica» — el objeto se mueve a velocidad robótica. Con Easing.out, el elemento entra con energía y desacelera naturalmente, como si obedeciera a la física. Esa diferencia es lo que separa los prototipos de los videos profesionales.

linear
Velocidad constante
Easing.out
Se desacelera al final
Easing.in
Acelera hasta el final
bezier
Control total
6

🧩 Patrones: fade, slide y scale

Con interpolate() a mano, tres patrones cubren el 90% de las animaciones de UI de video: fade (opacidad), deslizar (translateX/Y) y escala. Al combinar los tres, puedes construir cualquier entrada o salida de un elemento.

✓ Los tres patrones esenciales

  • ✓Fade: opacity = interpolate(frame, [0,20], [0,1], {clamp})
  • ✓Deslizamiento X: transform: translateX(${x}px) con x de −200 a 0.
  • ✓Scale: transform: scale(${s}) con s de 0.8 a 1.

✗ Errores comunes

  • ✗Usar CSS transitions o keyframes: entra en conflicto con el modelo de render de Remotion.
  • ✗Combinar scale e translateX sin transform en una sola string (se borran).
  • ✗Usar width/height animados en lugar de transform: scale (provoca reflow).
Fade + slide + scale combinados Entrance.tsx
const opts = { extrapolateRight: "clamp", easing: Easing.out(Easing.cubic) } as const;

const opacity  = interpolate(frame, [0, 20], [0, 1],    opts);
const x        = interpolate(frame, [0, 20], [-60, 0],  opts);
const scale    = interpolate(frame, [0, 20], [0.9, 1], opts);

return (
  <div style={{
    opacity,
    transform: `translateX(${x}px) scale(${scale})`,
  }}>
    Conteúdo com entrada suave
  </div>
);

💡 Combina siempre en el mismo transform

Cuando usas transform dos veces en el mismo objeto de estilo, el segundo sobrescribe el primero. Siempre concatena todo en una sola cadena: `translateX(${x}px) scale(${s})`.

opacity
0→1 fade
translateX/Y
deslizar
escala
crece/se encoge
Combina
1 transformación de string

📌 Resumen del módulo

✓
interpolate(frame, inputRange, outputRange, opts) — mapea cualquier frame a cualquier valor.
✓
inputRange → outputRange — dominio de frames mapeado linealmente a cualquier contradominio de valores.
✓
extrapolate: "clamp" — impide que la opacidad supere 1 o quede por debajo de 0.
✓
Varios keyframes — [0,15,75,90]→[0,1,1,0] crea un fade-in, hold y fade-out en una línea.
✓
Easing — Easing.out(Easing.cubic) hace que el movimiento sea natural; combínalo con los patrones fade/slide/scale.

Próximo módulo:

1.3 — spring() & composición: física de resorte, overshoot natural y cómo apilar escenas con Sequence y AbsoluteFill.