Skill: animar um SVG que o usuário fornece
Dá vida a um SVG que o usuário já tem: a borboleta bate asas, a roda gira, o contorno se desenha, o objeto desliza. A forma ganha movimento próprio, não vira outra (isso é morph).
Fonte da verdade: padrão validado em
decks/apresentacao-mira-gsap/borboleta-bate-asas.html(sessão de 2026-06-19): asas batendo viascaleXem torno do eixo do corpo, fundo branco removido, antenas mantidas estáticas. Spec completa em_reversa_sdd/GSAP/mira-svg-animator-spec.md. Em dúvida, copie desse exemplo.
Animar uma PARTE exige que a parte seja separada
GSAP só move o elemento que você entrega. Para mover uma parte (uma asa, uma roda, um braço), ela tem que ser um elemento separado no SVG (um <g>/<path> próprio). A maioria dos SVGs vem como path único fundido, e aí o GSAP só move o desenho inteiro. Antes de animar uma parte, separe-a:
- Corte por eixo com clipPath (recomendado para simetria). Renderize a silhueta duas (ou mais) vezes, cada cópia recortada por um
clipPathnuma região (ex.: metade esquerda / direita no eixo do corpo). Cada cópia vira um grupo animável — foi assim que a borboleta ganhou asa esquerda e direita. - Edite o path para isolar ou remover um trecho. Se uma parte do path não deve se mover (ex.: antenas dentro do path da asa), localize o trecho contínuo e substitua por uma reta curta que fecha a forma sem ele (ex.: trocar as antenas por
L x yatravessando o topo do corpo). Assim o corte por eixo não duplica nem mexe nessa parte.
Se a parte não isolar de jeito limpo, avise e ofereça animar o SVG inteiro (rotação/pulso global).
Remova o fundo
Se o SVG tiver fundo opaco (ex.: <rect fill="#ffffff"> cobrindo tudo, ou fundo de cor), remova/oculte esse elemento antes de animar, senão ele tampa o card escuro do Mira. Se for ambíguo (gradiente, imagem), pergunte qual elemento é o fundo.
A origem do movimento (svgOrigin)
Rotação e escala giram em torno do ponto certo, não do canto do SVG. Defina a origem em coordenadas do SVG com svgOrigin: 'X Y' (ex.: o eixo da dobradiça das asas, ou o centro de uma roda). Se a dobradiça não for óbvia, use o centro geométrico da parte e diga qual ponto usou.
Vendorar o GSAP (offline é inegociável)
Baixe para assets/gsap/ do deck só o que a técnica usar (uma vez por deck; se já existir, pule):
curl -s https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/gsap.min.js -o assets/gsap/gsap.min.js
curl -s https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/DrawSVGPlugin.min.js -o assets/gsap/DrawSVGPlugin.min.js # só se for "o traço se desenha"
curl -s https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/MotionPathPlugin.min.js -o assets/gsap/MotionPathPlugin.min.js # só se for "percorre uma curva"
GSAP e plugins são gratuitos e redistribuíveis desde abril de 2025. Referencie por caminho relativo no <head> e registre os plugins (gsap.registerPlugin(DrawSVGPlugin, MotionPathPlugin)) quando usá-los.
A técnica conforme o movimento
- Bater, girar, deslizar, pulsar, balançar →
transform(rotation,scale/scaleX/scaleY,x/y,skewX) comrepeat: -1eyoyoquando for vai e volta. - O traço se desenha →
DrawSVGPluginno contorno (a forma precisa destroke; se só tiver preenchimento, adicione um stroke). - Percorre uma curva →
MotionPathPluginnum path-guia.
REGRA ZERO (herdada) + acessibilidade
Movimento perpétuo em loop (repeat: -1). Descreva o loop em uma frase ("as asas batem sem parar em torno do corpo"). Respeite prefers-reduced-motion: quando ativo, mostre o SVG no estado final estático, sem loop.
Composição do card (padrão do mira-animator: limpo, SVG maximizado)
Título no topo, sem ícone, no máximo 6 palavras. O SVG ocupa boa parte da altura útil. Identidade laranja #FF904D quando fizer sentido recolorir (não altere a arte sem pedido). Insira como <section> no padrão do deck, preserve a navegação e estampe @MIRA:SIZE 3/10 acima do palco.
Scaffold canônico (bater asas, validado na borboleta)
Silhueta de path único cortada no eixo do corpo em duas cópias (asa esquerda/direita), cada uma flapando por scaleX em torno da dobradiça. O corpo fica estático por cima cobrindo a emenda.
<svg id="SLUG-svg" viewBox="... ..." preserveAspectRatio="xMidYMid meet">
<defs>
<clipPath id="SLUG-clip-l"><rect x="0" y="0" width="EIXO" height="H"/></clipPath>
<clipPath id="SLUG-clip-r"><rect x="EIXO" y="0" width="RESTO" height="H"/></clipPath>
</defs>
<g clip-path="url(#SLUG-clip-l)"><g id="SLUG-lwing"><path d="SILHUETA_SEM_PARTES_FIXAS" fill="..."/></g></g>
<g clip-path="url(#SLUG-clip-r)"><g id="SLUG-rwing"><path d="SILHUETA_SEM_PARTES_FIXAS" fill="..."/></g></g>
<path id="SLUG-corpo" d="CORPO_E_PARTES_FIXAS" fill="..."/> <!-- estático, por cima da emenda -->
</svg>
const REDUCE = matchMedia('(prefers-reduced-motion: reduce)').matches;
const MIRA_SIZE = 3, SPEED = 0.7 + MIRA_SIZE * 0.1; // ponto único de ritmo/amplitude
if (!REDUCE) {
const flap = { scaleX: 0.34, svgOrigin: 'EIXO_X EIXO_Y', duration: 0.55, ease: 'sine.inOut', repeat: -1, yoyo: true };
const tl = gsap.timeline();
tl.to('#SLUG-lwing', { ...flap }, 0).to('#SLUG-rwing', { ...flap }, 0);
tl.timeScale(SPEED);
}
Outras técnicas (mesma ideia de loop + svgOrigin + reduced-motion):
// girar uma roda em torno do próprio centro
gsap.to('#SLUG-roda', { rotation: 360, svgOrigin: 'CX CY', duration: 1.4, ease: 'none', repeat: -1 });
// o contorno se desenha (precisa de DrawSVGPlugin e stroke na forma)
gsap.fromTo('#SLUG-traco', { drawSVG: '0%' }, { drawSVG: '100%', duration: 2.2, ease: 'power1.inOut', repeat: -1, yoyo: true });
Passos
- Receber destino + SVG + movimento. Slide novo ou slide N do deck X, o
.svge a descrição do movimento. Se faltar arquivo ou descrição, pergunte. - Copiar o SVG para
assets/, remover o fundo opaco e inspecionar a estrutura (partes separadas ou path único). - Separar a parte a animar se for path único (corte por eixo com clipPath ou edição do path para isolar/remover trechos fixos). Definir a origem do movimento.
- Escolher a técnica (transform / DrawSVG / MotionPath) e vendorar só os arquivos GSAP necessários em
assets/gsap/. - Montar o card no padrão do deck (título sem ícone máx. 6 palavras, marcador @MIRA:SIZE), implementar a timeline em loop com
prefers-reduced-motione registrar no trigger do deck. - Reportar. Caminho do arquivo, o movimento em uma frase, técnica e origem usadas, se separou parte e como, e que abre por
file://.
Checklist
- GSAP (e só os plugins usados) vendorados em
assets/gsap/; caminho relativo; nenhum CDN em runtime. - Slide abre por
file://sem nada externo. - Fundo opaco removido (ex.:
<rect>branco). - Parte a animar é um elemento separado; em path único, separada por clipPath ou edição do path, sem arrastar o resto.
- Nada que deve ficar parado se move em cópia (ex.: antenas removidas do path da asa).
- Origem do movimento no ponto certo (
svgOrigin), não no canto. - Técnica coerente com o pedido (transform / DrawSVG / MotionPath).
- Loop contínuo (
repeat: -1),yoyoquando for vai e volta. -
prefers-reduced-motionmostra o estado final estático, sem loop. - Card limpo: título sem ícone, no máximo 6 palavras; marcador
@MIRA:SIZE 3/10; timeline registrada no trigger do deck. - Nenhum travessão (—); acentuação UTF-8 correta (segue
agents/_shared/idioma.md).