📊 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 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.
📊 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.
{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):
Barra 0: anima do frame 0 ao 15
inputRange [0, 15] — primeira a crescer.
Barra 1: anima do frame 3 ao 18
inputRange [3, 18] — começa 3 frames depois.
Barra n: inputRange [n×3, n×3+15]
Padrão universal de stagger para qualquer N barras.
📈 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.
// 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.
🥧 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.
// 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
🔢 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.
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.
⭕ 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.
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.
📚 Biblioteca Completa — Charts & Dados
📌 Resumo do módulo
Próximo módulo:
2.3 — Animação de Conteúdo: listas com stagger, card-flip 3D, countdown, partículas e carrossel rotacionando.