MÓDULO 1.2

📈 interpolate() — frame vira valor

O interpolate() é a ferramenta central do Remotion: você dá um frame e ele devolve um número — opacidade, posição, escala, cor. Uma chamada, infinitas animações.

6
Tópicos
40
Minutos
Básico
Nível
Prático
Tipo
frame 42 interpolate(frame, [0, 30], [0, 1]) inputRange → outputRange opacity 1.4 entrada: frame atual clamp: valor fica entre 0 e 1 saída: qualquer número
1

📝 A assinatura do interpolate()

O interpolate() recebe quatro argumentos: o valor de entrada (quase sempre frame), o inputRange, o outputRange e opções opcionais. Em troca, devolve um número calculado por interpolação linear entre os pontos.

Assinatura 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" }
);

🎯 O que cada argumento faz

  • frame — o número que muda a cada quadro; pode ser qualquer variável numérica.
  • inputRange — a janela de frames onde a animação acontece (pelo menos 2 pontos).
  • outputRange — os valores correspondentes de saída; pode ser pixels, graus, decimais.
  • opcoes — controla o que acontece fora do inputRange (clamp, extend, wrap).
arg 1
Valor de entrada
arg 2
inputRange []
arg 3
outputRange []
arg 4
opções (opcional)
2

🗺️ inputRange e outputRange — domínio e contradomínio

Pense em inputRange como o domínio (quais frames fazem parte da animação) e outputRange como o contradomínio (quais valores saem). O interpolate() encontra o ponto proporcionalmente equivalente dentro do outputRange.

📊 Exemplos de mapeamento

  • [0, 30] → [0, 1]fade-in: opacidade cresce de 0 a 1 em 1 segundo (30fps).
  • [0, 30] → [0, 300]slide: translateX vai de 0 a 300px em 1 segundo.
  • [0, 30] → [0.5, 1]scale: objeto começa na metade do tamanho e cresce para 100%.
  • [0, 30] → [360, 0]rotação inversa: começa girado 360° e vai para 0.
Slide + opacidade 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>
);

💡 Dica: ranges não precisam começar em 0

Você pode usar [45, 60] como inputRange para que a animação comece 1,5s depois do início do vídeo. O que está fora do range é controlado pela opção extrapolate.

Domínio
inputRange de frames
Contradomínio
outputRange de valores
Linear
Proporcional por padrão
Qualquer valor
px, graus, 0–1
3

🔒 extrapolate: clamp vs extend

O que acontece quando frame sai do inputRange? Por padrão, o interpolate() extende a linha além dos pontos definidos — o que pode fazer a opacidade passar de 1 ou ir abaixo de 0. O clamp evita isso.

✓ O que FAZER

  • Usar extrapolateRight: "clamp" em opacidade para nunca passar de 1.
  • Usar extrapolateLeft: "clamp" para segurar o valor antes do início da animação.
  • Deixar extend (padrão) só quando a extrapolação faz sentido (ex.: posição que continua).

✗ O que NÃO fazer

  • Deixar opacidade sem clamp — no frame 60, [0,30]→[0,1] devolve 2 (invisível no CSS).
  • Esquecer o extrapolateLeft quando a animação começa tarde (frame 45+).
  • Usar opções diferentes de clamp/extend/wrap/identity — não existem.
clamp dos dois 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
Segura nos extremos
extend
Continua a reta
wrap
Reinicia em loop
Padrão
extend (cuidado!)
4

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

O inputRange e o outputRange aceitam mais de dois pontos. Isso cria keyframes: a animação passa por cada par [frame → valor] em sequência. É como o timeline de um editor de vídeo, mas em código.

0

frame 0 → opacity 0

Elemento invisível no início.

15

frame 15 → opacity 1

Fade-in completo em 0,5s.

75

frame 75 → opacity 1

Permanece totalmente visível até 2,5s — o "hold".

90

frame 90 → opacity 0

Fade-out de 0,5s antes do 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 pontos no range
Hold
Mesmo valor repetido
Padrão textual
0→1→1→0
Flexível
Qualquer sequência
5

🎨 Easing — movimento natural

Por padrão, o interpolate() faz uma interpolação linear — velocidade constante do começo ao fim. Para movimento natural, use a opção easing com funções do módulo Easing do Remotion (compatível com React Native).

🎯 Easings mais usados

  • Easing.out(Easing.ease) — começa rápido, desacelera no final. Clássico para entradas.
  • Easing.in(Easing.ease) — começa devagar, acelera. Bom para saídas.
  • Easing.inOut(Easing.ease) — suave nos dois extremos. Sólido para transições.
  • Easing.bezier(0.25, 0.1, 0.25, 1) — controle total com curva cúbica.
  • Easing.cubic — alternativa rápida ao bezier com curva cúbica padrão.
Entrada com 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),
});

💡 Linear vs Easing na prática

Uma animação linear parece "mecânica" — objeto se move em velocidade robótica. Com Easing.out, o elemento entra com energia e desacelera naturalmente, como se obedecesse à física. Essa diferença é o que separa protótipos de vídeos profissionais.

linear
Velocidade constante
Easing.out
Desacelera no fim
Easing.in
Acelera até o fim
bezier
Controle total
6

🧩 Padrões: fade, slide e scale

Com interpolate() em mãos, três padrões cobrem 90% das animações de UI de vídeo: fade (opacidade), slide (translateX/Y) e scale. Combinando os três, você constrói qualquer entrada ou saída de elemento.

✓ Os três padrões essenciais

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

✗ Erros comuns

  • Usar CSS transitions ou keyframes — conflita com o modelo de render do Remotion.
  • Combinar scale e translateX sem transform em string única (se apagam).
  • Usar width/height animados em vez de transform: scale (causa 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>
);

💡 Combine sempre no mesmo transform

Quando você usa transform duas vezes no mesmo objeto de estilo, o segundo sobrescreve o primeiro. Sempre concatene tudo numa string só: `translateX(${x}px) scale(${s})`.

opacity
0→1 fade
translateX/Y
slide
scale
cresce/encolhe
Combine
1 string transform

📌 Resumo do módulo

interpolate(frame, inputRange, outputRange, opts) — mapeia qualquer frame em qualquer valor.
inputRange → outputRange — domínio de frames mapeado linearmente para qualquer contradomínio de valores.
extrapolate: "clamp" — impede que opacidade passe de 1 ou fique abaixo de 0.
Múltiplos keyframes — [0,15,75,90]→[0,1,1,0] cria fade-in, hold e fade-out numa linha.
EasingEasing.out(Easing.cubic) torna o movimento natural; combine com os padrões fade/slide/scale.

Próximo módulo:

1.3 — spring() & composição: física de mola, overshoot natural e como empilhar cenas com Sequence e AbsoluteFill.