MÓDULO 2.2

📊 Charts & Dados

9 templates que transformam números em visuais animados usando SVG puro e interpolate — sem Chart.js, sem D3. De barras crescendo em stagger até anel de progresso e contador numérico com vírgula.

9
Templates
45
Minutos
Inter
Nível
SVG
Tipo
dados[ ] [45, 72, 58, 90] interpolate() frame → altura Jan Fev Mar Abr stagger: cada barra cresce com delay = i × 3 frames vídeo chart animado
1

📊 Por que SVG puro em vez de Chart.js?

Bibliotecas de chart como Chart.js e D3 são projetadas para o browser — elas dependem de DOM, eventos e estado interno. No Remotion, cada frame é calculado de forma independente e determinística. SVG puro com interpolate é a abordagem correta: o valor de cada elemento visual é uma função direta do frame.

🎯 O modelo mental dos charts no Remotion

Cada elemento visual (barra, ponto, arco) tem uma dimensão que cresce de acordo com o frame. A fórmula é sempre a mesma:

const progress = interpolate(frame, [startFrame, endFrame], [0, 1], {'{'}extrapolateRight: "clamp"{'}'});
const height = targetHeight * progress; // o SVG usa essa altura

✓ SVG puro: vantagens

  • 100% determinístico — mesmo frame, mesmo pixel.
  • Controle total de timing: cada barra com seu próprio stagger.
  • Zero dependência extra — menor bundle do projeto.

✗ Chart.js em Remotion: problemas

  • Animações internas não sincronizam com o frame do Remotion.
  • Canvas pode render diferente em headless Chrome.
  • Difícil de customizar timing e easing.
Paradigma
frame → dimensão
Ferramenta
SVG + interpolate
Stagger
i × delay offset
Sem deps
Zero bibliotecas
2

📊 chart-animation — barras SVG com stagger

O chart-animation.tsx é o template de referência para gráficos de barras. Cada barra cresce da base com um delay proporcional ao seu índice — o stagger dá ritmo visual e separa visualmente as informações.

chart-animation.tsx — barras com stagger templates/chart-animation.tsx
{data.map((point, i) => {
  const barHeight = (point.y / 100) * (chartHeight - padding * 2);

  const barProgress = interpolate(
    frame,
    [i * 3, 15 + i * 3],    // stagger
    [0, 1],
    { extrapolateRight: "clamp" }
  );

  const currentHeight = barHeight * barProgress;

  return (
    <rect
      key={i}
      x={barX}
      y={chartHeight - padding - currentHeight} /* crescer de baixo */
      width={barWidth}
      height={currentHeight}
      fill={colors[i % colors.length]}
      rx={4}
    />
  );
})}

📊 Por que y cresce de baixo para cima no SVG?

No SVG, o eixo Y é invertido: y=0 é o topo, y=altura é a base. Para uma barra crescer da base, você define y = chartHeight - padding - currentHeight e height = currentHeight. Conforme currentHeight aumenta, a barra sobe visualmente.

Timing das barras (delay = i × 3):

B0

Barra 0: anima do frame 0 ao 15

inputRange [0, 15] — primeira a crescer.

B1

Barra 1: anima do frame 3 ao 18

inputRange [3, 18] — começa 3 frames depois.

Bn

Barra n: inputRange [n×3, n×3+15]

Padrão universal de stagger para qualquer N barras.

Stagger
i × 3 frames
SVG Y
Invertido (0=topo)
Extrapolate
clamp obrigatório
Colors
i % colors.length
3

📈 line-chart — strokeDashoffset

O gráfico de linha usa a técnica de stroke-dashoffset para dar a ilusão de uma linha sendo desenhada. O truque: definir stroke-dasharray igual ao comprimento total do path, depois animar dashoffset de comprimento total a zero.

line-chart — técnica dashoffset templates/line-chart.tsx
// 1. Calcular pontos do polyline
const points = data.map((d, i) =>
  `${x0 + i * xStep},${y0 - d.value * scale}`
).join(" ");

// 2. Comprimento total (estimado ou via ref)
const totalLength = 600; // ou getTotalLength() em useRef

// 3. Animar o offset de comprimento a 0
const dashOffset = interpolate(
  frame,
  [0, 60],
  [totalLength, 0],
  { extrapolateRight: "clamp" }
);

return <polyline
  points={points}
  strokeDasharray={totalLength}
  strokeDashoffset={dashOffset}
  stroke="#60a5fa" strokeWidth=3 fill="none"
/>

💡 A técnica funciona em qualquer path SVG

Não só polyline — qualquer <path>, <circle> com stroke-dasharray pode usar essa técnica. É como você anima bordas circulares (circular-progress), assinaturas cursive e qualquer forma desenhada à mão.

Técnica
dashoffset → 0
Funciona em
qualquer SVG stroke
Comprimento
getTotalLength()
Easing
easeInOut recomendado
4

🥧 pie-chart & donut-chart — arcos SVG

Pizza e rosca são os charts mais pedidos em vídeos de negócios. A técnica usa SVG arc commands (A) calculados trigonometricamente a partir das porcentagens de cada fatia. O donut adiciona um círculo branco central para criar o buraco.

cálculo de fatia — função auxiliar pie-chart helper
// converte ângulo → ponto no círculo
const polarToCartesian = (cx, cy, r, angle) => ({
  x: cx + r * Math.cos((angle - 90) * Math.PI / 180),
  y: cy + r * Math.sin((angle - 90) * Math.PI / 180),
});

// gera o "d" de uma fatia
const describeArc = (cx, cy, r, start, end) => {
  const s = polarToCartesian(cx, cy, r, start);
  const e = polarToCartesian(cx, cy, r, end);
  const flag = end - start > 180 ? 1 : 0;
  return `M ${cx} ${cy} L ${s.x} ${s.y} A ${r} ${r} 0 ${flag} 1 ${e.x} ${e.y} Z`;
};

📊 A flag do arco (large-arc-flag)

O quinto parâmetro do comando A é o large-arc-flag: 1 = usa o arco maior (mais de 180°), 0 = usa o menor. Esquecer isso faz fatias maiores que 50% desenharem pelo lado errado.

flag = endAngle - startAngle > 180 ? 1 : 0
Comando SVG
M L A Z
Arc flag
>180° = 1
Donut
circle no topo
Animação
ângulo final × progress
5

🔢 stat-counter — contador com vírgula

O stat-counter.tsx é um dos componentes mais pedidos em vídeos de marketing e resultados: um número grande que conta de 0 até o valor alvo, formatado com separador de milhar. Tudo com interpolate + Math.floor + toLocaleString.

stat-counter — número formatado templates/stat-counter.tsx
const frame = useCurrentFrame();
const targetValue = 1234567;

const currentValue = interpolate(
  frame,
  [0, 60],
  [0, targetValue],
  {
    extrapolateRight: "clamp",
    easing: Easing.out(Easing.quad),
  }
);

// formatar com separador de milhar
const display = Math.floor(currentValue)
  .toLocaleString("pt-BR");

return <div>{display}</div>;

💡 Easing ease-out para contadores

Contadores ficam mais impactantes com Easing.out(Easing.quad) — a contagem começa rápida e desacelera ao chegar no valor final, dando ênfase ao número destino. Linear parece mecânico. ease-in faz o oposto (lento-rápido) e raramente funciona aqui.

Fórmula
interpolate → floor → locale
Easing
ease-out quad
Formato
toLocaleString()
Sufixo
K, M, % opcionais
6

⭕ circular-progress — anel com dashoffset

O circular-progress.tsx usa a mesma técnica do line-chart aplicada a um <circle> SVG. A circunferência total é 2πr, e o dashoffset começa lá e vai até zero conforme o progresso aumenta. No centro, uma métrica numérica animada com stat-counter.

circular-progress — anel animado templates/circular-progress.tsx
const radius = 80;
const circumference = 2 * Math.PI * radius; // ~502px

const progress = interpolate(
  frame, [0, 60], [0, targetPercent / 100],
  { extrapolateRight: "clamp" }
);

const dashOffset = circumference * (1 - progress);

return <circle
  r={radius} cx={100} cy={100}
  fill="none"
  stroke="#3b82f6"
  strokeWidth={12}
  strokeDasharray={circumference}
  strokeDashoffset={dashOffset}
  strokeLinecap="round"
  transform="rotate(-90 100 100)" /* começa no topo */
/>

📊 Por que rotate(-90)?

O SVG começa o desenho de círculos às 3 horas (0°). O transform="rotate(-90 cx cy)" gira o ponto de partida para o topo (12 horas), que é onde esperamos ver um anel de progresso começar. Sem isso, o anel começa pelo lado direito.

Fórmula
2πr = circumference
Offset
circum × (1 - progress)
Início
rotate(-90) → topo
Centro
text sobreposto
7

📚 Biblioteca Completa — Charts & Dados

TemplateDescriçãoTécnica SVG
chart-animation.tsx Barras SVG crescendo com stagger rect height
line-chart.tsx Linha traçada da esquerda dashoffset
pie-chart.tsx Pizza com fatias animadas arc path M L A Z
donut-chart.tsx Rosca com métrica central arc + circle overlay
area-chart.tsx Área preenchida com gradiente path fechado + linearGradient
progress-bars.tsx Barras de progresso horizontal width% interpolado
stat-counter.tsx Contador com separador milhar interpolate + toLocaleString
comparison-chart.tsx Dois grupos lado a lado stagger por grupo
circular-progress.tsx Anel de progresso com % circle dashoffset 2πr

📌 Resumo do módulo

SVG puro com interpolate — sem Chart.js, determinístico e controlável frame a frame.
Stagger = i × delay no inputRange — cada barra/ponto com timing independente.
dashoffset para linhas traçadas — funciona em qualquer stroke SVG.
Arc commands para pizza e rosca — large-arc-flag crítico para fatias >180°.
stat-counter com ease-out — interpolate + floor + toLocaleString + easing quad.

Próximo módulo:

2.3 — Animação de Conteúdo: listas com stagger, card-flip 3D, countdown, partículas e carrossel rotacionando.