MÓDULO 3.5 · MOTION ENGINE

🎬 animations.jsx em profundidade

Stage props completos, Sprite lifecycle, todas as curvas Easing, composição de cenas complexas (paralelas + stagger), performance e quando cair em Popmotion.

6
Tópicos
45
Minutos
Expert
Nível
Motion
Tipo
1

🎭 Stage — props e features built-in

<Stage> é o container raiz de toda animação. Inclui autoescala (1920×1080 padrão), scrubber timeline, controles play/pause, e props que você pode customizar.

Props completas

PropTipoDefaultPara quê
durationnumber (ms)obrigatórioDuração total da timeline
autoPlaybooleantrueInicia tocando ao montar
loopbooleanfalseRecomeça quando termina
scrubberbooleantrueMostra timeline com scrub manual
controlsbooleantrueMostra play/pause/restart
autoScalebooleantrueEscala 1920×1080 para qualquer viewport
canvasSize{w, h}{1920, 1080}Override resolução interna

Use case: video export-ready

// Para gerar vídeo exportável (sem UI overlays)
<Stage
  duration={5000}
  autoPlay={false}
  scrubber={false}
  controls={false}
  loop={false}
>
  {/* Sprites aqui — nenhum controle visível */}
  {/* Use frame-by-frame screenshot externo para gerar MP4 */}
</Stage>
2

✨ Sprite — lifecycle, props, sub-sprites

Cada <Sprite> tem janela de existência (start..end ms). Antes do start: não montado. Após end: desmontado. Hidden não é "display: none" — é unmount real (children não rodam).

Composição de cenas — 3 padrões

// PADRÃO 1: Sequencial (um após outro)
<Sprite start={0} end={1000}>Hero</Sprite>
<Sprite start={1000} end={2000}>Cards</Sprite>
<Sprite start={2000} end={3000}>CTA</Sprite>

// PADRÃO 2: Paralelo (sobreposição total)
<Sprite start={0} end={2000}>Background pulse</Sprite>
<Sprite start={0} end={2000}>Foreground content</Sprite>
// Os dois rodam simultaneamente

// PADRÃO 3: Stagger (entrada escalonada)
{[0, 200, 400, 600].map(delay => (
  <Sprite key={delay} start={delay} end={delay + 800}>
    <Card index={delay/200} />
  </Sprite>
))}
// 4 cards entram com 200ms de gap entre eles

Sub-sprites (Sprites aninhados)

// Sprite "pai" cria janela de tempo
<Sprite start={1000} end={4000}>
  <HeroSection>
    {/* Sprite "filho" começa relativo ao pai */}
    <Sprite start={500} end={1500}>
      <Headline />  {/* aparece em t=1500ms (pai 1000 + filho 500) */}
    </Sprite>
    <Sprite start={800} end={2000}>
      <Subhead />
    </Sprite>
  </HeroSection>
</Sprite>

Sprites aninhados herdam contexto do pai mas têm timeline própria. Útil para cenas complexas com múltiplos elementos.

3

⏱️ useTime vs useSprite — qual escolher

useTime() — tempo absoluto

const t = useTime();
// t = ms desde o início do Stage
// 0..duration

// Use para:
// - Animações que dependem de tempo absoluto
// - Sincronia com música/áudio
// - Loops contínuos
// - Pulsing/breathing (Math.sin(t/500))

useSprite() — progresso 0-1

const p = useSprite();
// p = progresso do Sprite atual
// 0 no start, 1 no end

// Use para:
// - Animações de entrada/saída
// - Reutilizar componente em Sprites de durações diferentes
// - Casos onde o tempo absoluto não importa

Exemplo combinado: hero com pulse contínuo

function Hero() {
  const t = useTime();          // tempo absoluto (para pulse)
  const p = useSprite();        // progresso da entrada

  const pulse = 1 + Math.sin(t / 400) * 0.05;  // breathing
  const entry = Easing.easeOut(p);             // entrada suave

  return (
    <h1 style={{
      transform: `scale(${entry * pulse})`,
      opacity: entry
    }}>
      Welcome
    </h1>
  );
}

<Sprite start={0} end={1500}>
  <Hero />
</Sprite>
4

📈 Easing — todas as curvas + quando usar cada

Catálogo de easings

EasingComportamentoUse case
linearVelocidade constanteLoops, scrolls automáticos
easeInLento → rápidoSaídas (algo "se afasta")
easeOutRápido → lentoEntradas (default 80% dos casos)
easeInOutLento → rápido → lentoTransições entre estados
easeBackVolta levemente antes de chegarDrama, emphasis (CTA)
easeBounceQuica ao chegarPlayful, casual (não premium)

interpolate — mapeamento avançado

// Forma básica: 0-1 → range customizado
const y = interpolate(p, [0, 1], [40, 0]);
// p=0 → y=40, p=0.5 → y=20, p=1 → y=0

// Multi-stop: anima entre 3 pontos
const opacity = interpolate(
  p,
  [0, 0.5, 1],     // entrada (0..0.5) e saída (0.5..1)
  [0, 1, 0]
);
// p=0 → 0, p=0.25 → 0.5, p=0.5 → 1, p=0.75 → 0.5, p=1 → 0

// Combinado com easing
const x = interpolate(
  Easing.easeOut(p),
  [0, 1],
  [-100, 0]
);
5

⚡ Entry/exit primitives + performance

Helpers prontos (cobrem 80% dos casos)

import { fadeIn, fadeOut, slideInUp, slideOutDown,
         scaleIn, scaleOut, slideInLeft, slideInRight } from 'animations';

// Uso direto:
<Sprite start={0} end={800}>
  <div style={fadeIn()}>
    Conteúdo aparece em fade
  </div>
</Sprite>

// Combinado:
<Sprite start={0} end={800}>
  <div style={{ ...fadeIn(), ...slideInUp({ distance: 40 }) }}>
    Fade + slide combinados
  </div>
</Sprite>

Performance: o que acelera GPU

  • transform (translateX, translateY, scale, rotate) — GPU accelerated
  • opacity — GPU accelerated
  • filter (blur, brightness) — GPU accelerated mas mais caro
  • width, height, top, left, padding — causa reflow, lento
  • background-color animado — repaint constante, evite
6

🎁 Popmotion fallback + consumo de quota

Citação literal — quando cair em Popmotion

"Só use Popmotion (https://unpkg.com/popmotion@11.0.5/dist/popmotion.min.js) se o componente inicial realmente não cobrir o caso de uso."

Casos que justificam Popmotion

  • Spring physics realista (animations.jsx tem easing, mas não simulação de mola completa)
  • Drag/gesture handling com inércia
  • Path animation ao longo de SVG path
  • Color interpolation avançada (HSL, OKLCH path)

CDN exata: https://unpkg.com/popmotion@11.0.5/dist/popmotion.min.js (versão pinned).

⚠️ Animações consomem quota agressivamente

Geração de uma animação complexa pode consumir 5-10x mais tokens que uma landing equivalente. Razões:

  • • Múltiplos Sprites = mais código por geração
  • • Iteração de timing precisa de feedback visual constante
  • • Verificador roda screenshots em múltiplos frames

No plano Pro: 2-3 sessões de animação intensa podem esgotar cota semanal. Para uso rotineiro, Max ($100-200/mês) é necessário.

Hack: itere com prompt simples + Tweaks

"Create initial animation: hero fade-in 0-800ms,
3 cards stagger 600-1800ms, CTA pulse 2000-3000ms.
Total Stage duration 3500ms.

Expose Tweaks for:
- duration multiplier (0.5x, 1x, 1.5x, 2x)
- stagger gap (100ms, 200ms, 300ms)
- CTA easing (easeOut, easeBack, easeBounce)

I want to iterate on timing without re-prompting."

Tweaks > re-prompt para ajustar timing — economiza tokens dramaticamente em animações.

Resumo do Módulo

Stage props — duration (obrigatório), autoPlay, loop, scrubber, controls, autoScale, canvasSize.
Sprite lifecycle — start..end ms, real unmount fora da janela. Sub-sprites herdam pai mas têm timeline própria.
3 padrões composição — sequencial, paralelo, stagger.
useTime vs useSprite — absoluto (loops) vs relativo (entrada/saída).
6 easings — linear, easeIn/Out/InOut, easeBack, easeBounce. interpolate multi-stop.
Performance: GPU vs reflow — transform/opacity/filter sim; width/height/padding/bg-color não.
Popmotion 11.0.5 só fallback — spring physics, gesture, path animation, color HSL avançado.
Quota: 5-10x mais que landing — use Tweaks para iterar timing sem re-prompt.

Próximo Módulo:

3.6 — 🎯 Edge cases + GitHub flow + URLs internas + .napkin