Animações Front-End
Você é responsável por projetar, implementar, revisar e otimizar animações front-end. Por padrão, assuma que o projeto é React + TypeScript; para JS puro ou outros frameworks, siga o estado atual do projeto — não imponha soluções React a projetos Vue ou nativos.
Animações são um aprimoramento, não uma decoração: primeiro garanta que a versão estática seja bonita e funcional, depois adicione animações.
Sem confirmação do usuário, não adicione nenhuma nova dependência.
§0 Antes de Codificar: Detecção de Dependências e Design System
Antes de codificar, complete as cinco etapas na ordem; se alguma estiver faltando, primeiro detecte e depois codifique.
- Leia
package.jsone tambémpnpm-lock.yaml/package-lock.json/yarn.lockpara verificar as versões reais das bibliotecas de animação instaladas e suas versões principais. - Leia
tailwind.config.*, estilos globais (globals.css/index.css/app.css), arquivos de tema para encontrar tokens existentes, durações, easings e nomes. - Se motion já estiver presente, não use GSAP; se GSAP já estiver presente, não adicione motion. O mesmo requisito não deve ter duas bibliotecas coexistentes.
- Não adicione novas dependências por conta própria. Se realmente necessário, informe o nome do pacote, tamanho min+gzip, alternativas, e por que a biblioteca existente não atende. Aguarde a confirmação do usuário antes de instalar.
- Mantenha a nomenclatura, organização de arquivos, estilo de código e nomes de tokens já existentes no projeto. Não introduza um segundo sistema de animação.
| O que foi detectado | Como proceder por padrão |
|---|---|
| Motion já presente | Animações de interação, entrada/saída e layout usam motion; não introduza GSAP |
| framer-motion (versão antiga) | Use o nome e API existentes do pacote; não migre para motion por conta própria. Atualizações devem ser propostas e executadas separadamente |
| GSAP já presente | Linha do tempo e animações vinculadas a scroll usam GSAP + ScrollTrigger; hovers simples ainda usam CSS transition; não adicione motion |
| Apenas Tailwind | Use classes atômicas transition / duration / ease combinadas com variáveis CSS globais; não instale bibliotecas |
| Projeto CSS puro | Use apenas CSS transition/animation + WAAPI; não instale bibliotecas JS de animação |
| Next.js App Router | Componentes de animação devem ter "use client"; View Transitions e motion tratados como componentes cliente; sem hacks para estado compartilhado entre rotas |
| Vue | Use CSS nativo ou soluções de motion do ecossistema Vue; não force bibliotecas específicas do React |
§1 Lista de Antipadrões (Não Violável)
Verifique cada item; se qualquer um for violado, reescreva — sem concessões do tipo "por enquanto está ok".
| Proibido | Substituição |
|---|---|
transition: all .3s | Liste explicitamente transform, opacity e, se necessário, color |
ease-in-out uniforme em todo o site | Escolha a curva com base no contexto de entrada/saída/bidirecional (veja §3) |
Elemento aparecendo com opacity: 0 + scale(.8) | Use opacity: .9→1 + translateY(8px)→0 |
linear sem pensar | Apenas para barras de progresso e decorações com loop infinito |
| Mais de 3 elementos animados simultaneamente na mesma tela | Mantenha apenas 1 foco visual; os outros devem estar parados ou com movimento muito sutil |
Hover com transform: translateY(-4px) sem espaço reservado no contêiner pai | Use scale ou adicione padding ao pai como espaço reservado |
| Animar apenas a entrada, sem a saída | Devem ser projetados em pares, e a saída deve ser mais rápida que a entrada |
Animações com filter: blur() / drop-shadow em área grande | Use camadas de desfoque pré-renderizadas ou reduza o escopo da animação |
| Camada de animação cobrindo CTA / formulário | Camada de animação deve ter pointer-events: none ou ser posicionada fora da área de interação |
| Animação de loading na tela inicial com mais de 1,5s | Se exceder, mostre primeiro um skeleton |
| Cursor personalizado + rastro (a menos que o usuário peça explicitamente) | Não faça |
| Animações complexas letra a letra / quadro a quadro para cada item de lista | Use um stagger geral de 30–50ms com deslocamento simples |
Usar setTimeout para encadear animações | Use eventos transition/animation, onAnimationComplete, timeline |
el.style.left = x quadro a quadro | WAAPI / rAF / timeline da biblioteca |
Justificativa para os limites: a espera na tela inicial acima de 1,5s faz o usuário suspeitar que a página travou; portanto, mostre primeiro o skeleton. Mais de 3 movimentos independentes simultâneos na mesma tela quebram o foco visual — o usuário não sabe para onde olhar.
§2 Árvore de Decisão (Versão Resumida)
Primeiro consulte a tabela para definir a abordagem, depois vá para §3 para definir os valores, e só então escreva o código.
| Cenário | Escolha preferida | O que NÃO usar |
|---|---|---|
| Feedback de hover / press / toggle | CSS transition | GSAP (muito pesado) |
| Entrada/saída de componentes, adição/remoção de itens em lista, mudanças de layout | motion (AnimatePresence + layout) | Animação manual de height |
| Transições de rota/página | View Transitions API, ou motion layoutId | Máscara de tela cheia com atraso |
| Linha do tempo complexa, sequência coreografada, animação vinculada a scroll | GSAP + ScrollTrigger | Acúmulo de CSS keyframes |
| 3D / partículas / física / shader | three.js + React Three Fiber + drei | Fingir 3D com CSS |
| Animações vetoriais do designer | dotLottie / Lottie | Converter para GIF |
| Ícones simples ou animações de caminho | SVG + CSS | Introduzir o runtime do Lottie |
| Animações de gráficos de dados | Animação nativa da biblioteca (ex.: transição do Recharts/visx) | Animar o caminho manualmente |
| Decorações de fundo (grade/ondas/brilho) | CSS ou canvas + requestAnimationFrame, com suporte a pausa | three.js (a menos que precise de 3D real) |
| Mudanças de número/valor | tabular-nums + tween simples | Refluxo de layout quadro a quadro |
A lógica completa de seleção, ordem de perguntas e a escada de "CSS → biblioteca leve → biblioteca pesada" estão em references/decision-tree.md.
§3 Especificações de Valores (Não Confie na Intuição)
Todas as durações, curvas e amplitudes devem ser retiradas da tabela abaixo; se um valor não estiver na tabela, justifique antes de adicionar.
Duração
| Item | Valor |
|---|---|
| hover / press | 120–180ms |
| toggle / abrir/fechar | 200–300ms |
| Entrada | 240–400ms |
| Saída | Duração de entrada × 0,6–0,7 |
| Transição de página | 300–500ms |
| Refluxo de layout (animação layout) | 300–500ms |
| Intervalo de stagger | 30–50ms, duração total do grupo ≤ 500ms |
| Acima de 600ms | Deve ser justificado; caso contrário, removido |
Easing
| Easing | Curva |
|---|---|
| Entrada | cubic-bezier(0.16, 1, 0.3, 1) |
| Saída | cubic-bezier(0.4, 0, 1, 1) |
| Bidirecional / mudança de estado | cubic-bezier(0.4, 0, 0.2, 1) |
| Deslocamento / arrasto / gestos | spring: stiffness 300–500, damping 30–40 |
| linear | Apenas barras de progresso, decorações de loop infinito |
Amplitude
| Amplitude | Valor |
|---|---|
| Deslocamento | Micro 4–8px / Médio 12–24px / Grande 32–64px / >80px apenas para transições de tela cheia |
| Opacidade | Micro-interação .9→1; Entrada .6→1; 0→1 apenas para máscaras de tela cheia e modais |
| Escala | Apenas no intervalo 0.96–1.04 |
Spring
| Parâmetro | Valor | Justificativa |
|---|---|---|
| stiffness | 300–500 | Abaixo de 300 é lento; acima de 500 vibra como se estivesse com defeito |
| damping | 30–40 | Abaixo de 30, o efeito de retorno é exagerado; acima de 40, não há sensação de retorno |
| mass | 0.8–1 | Menor alteração perceptível na inércia |
Justificativa resumida para cada intervalo:
- hover / press 120–180ms: Abaixo de 120ms não dá tempo de perceber a mudança de estado; acima de 180ms o feedback é lento, o usuário acha que não clicou.
- Entrada 240–400ms: Abaixo de 240ms a direção do deslocamento não é percebida; acima de 400ms o usuário começa a esperar.
- Saída × 0,65: A saída não precisa ser vista claramente; lenta é arrastada.
- stagger 30–50ms: Abaixo de 30ms parece que tudo aparece ao mesmo tempo; acima de 50ms o grupo ultrapassa o limite de paciência de 500ms.
Esses valores já estão definidos como variáveis CSS e constantes TypeScript em references/tokens.md; todo código deve referenciar os tokens, sem números mágicos.
§4 Linhas Vermelhas de Desempenho e Acessibilidade
- Animar apenas
transform/opacity; para animar dimensões, use FLIP ou a capacidadelayoutda biblioteca. - Camadas com animação contínua devem ter
will-change: transform, que deve ser removido após a animação terminar. - Listas longas devem ser virtualizadas; elementos fora da tela devem ter animação pausada via IntersectionObserver.
prefers-reduced-motion: reduceé um requisito obrigatório, não um recurso opcional. A versão degradada ainda deve ter uma mudança de estado clara: geralmente, regride para uma transição de opacidade de ≤120ms (120ms é suficiente para perceber a mudança de estado sem ser uma animação que precisa ser compreendida), ou uma troca direta.- Não use piscadas com frequência superior a 3 vezes por segundo (o limite de fotossensibilidade da WCAG 2.3.1 é de 3 vezes por segundo).
- Durante a animação, não roube o foco, não desorganize a ordem de tabulação; o anel de foco do teclado não deve participar da animação.
- Ao projetar, conceba a composição de forma que a "versão estática também seja bonita"; a animação é apenas um aprimoramento.
Consulte as cláusulas WCAG, aria-live e métodos de teste em references/accessibility.md.
§5 Regras de Implementação
- Entrada e saída devem ser projetadas em pares, e a saída deve ser mais rápida.
- Uma tela deve ter apenas um foco visual.
- Stagger com 30–50ms, grupo total não excedendo 500ms.
- Camadas de animação decorativa devem ter
pointer-events: none. - Use eventos transition/animation,
onAnimationCompleteou timeline para encadear; proibidosetTimeout. - Se for possível com CSS ou Framer, não use GSAP.
- Se for possível com
transform, não animewidth/height. - A duração da animação deve ser revisada no design; não ajuste "de ouvido" com "um pouco mais devagar".
- Primeiro remova, depois adicione: remova animações que podem ser removidas; otimize apenas as que não podem.
§6 Modo de Revisão
Ao revisar animações existentes, cada item deve ser relatado em quatro seções fixas:
Problema / Base (citando cláusulas de §1–§4) / Código sugerido / Impacto (duração, desempenho, acessibilidade)
Regras:
- Relate apenas problemas reais. Não reescreva implementações razoáveis apenas para preencher uma lista.
- No máximo 8 itens, ordenados por gravidade: acessibilidade > desempenho > duração/curva > estilo.
- No final, escreva uma seção "Estes pontos estão corretos", listando 1–3 itens, para evitar que o usuário modifique implementações corretas por engano.
Comando de varredura (apenas leitura, não forneça --fix; qualquer modificação automática de animação quebraria a intenção do design):
node ~/.claude/skills/frontend-animation/scripts/audit-animation.mjs <diretório-do-projeto> --json
O script apenas relata problemas e suas localizações; a correção é decidida pelo humano.
§7 O que Ler Quando Precisar de X
| Sintoma/Necessidade | Arquivo |
|---|---|
| Não sabe se usa CSS ou biblioteca, precisa escolher entre frameworks, precisa da ordem de perguntas | references/decision-tree.md |
| Precisa aplicar tokens, conectar com Tailwind, escrever variáveis CSS ou constantes TS | references/tokens.md |
| Consultar instalação, API e armadilhas de versão de motion / GSAP / three.js+R3F / Lottie / View Transitions | references/libraries.md |
| Precisa de modelos prontos (entrada de lista / transição de rota / arrasto / mouse follower / número rolante / flip 3D / fundo de loop / skeleton / botão magnético / Lottie) | references/patterns.md |
| Escolher curvas de easing, obter aproximação linear() do spring, explicar por que uma curva específica | references/easing.md |
| Degradação reduced-motion, WCAG, piscadas e foco, métodos de teste | references/accessibility.md |
| Precisa de um componente de referência completo com branch reduced-motion | assets/template-component.tsx |
| Precisa escanear problemas de animação no código existente | scripts/audit-animation.mjs |
§8 Auto-Checklist Pré-commit (8 Perguntas, Responda uma a uma)
- Esta animação é necessária? A versão estática ainda é bonita sem ela?
- Estou animando apenas transform / opacity?
- Duração, curva e amplitude estão dentro de §3?
- Entrada e saída estão emparelhadas? A saída é mais rápida?
- Há um branch para reduced-motion? O estado degradado ainda é distinguível?
- Adicionei alguma dependência? Se não foi confirmado, é violação.
- Há piscadas >3 vezes/segundo? Roubei o foco durante a animação?
- A tela tem apenas um foco visual?
Se alguma pergunta não puder ser respondida, pare e corrija; não envie.