| name | mira-animator |
| description | Cria slides animados com looping interno obrigatório (D3.js v7+ ou 3D CSS), no padrão dos decks em mira-templates/decks/ e do esqueleto visual do mira-builder (glass-card, icon-hero, attribute-pills, replay-btn). Use SEMPRE que o usuário disser, "criar slide animado", "novo slide com animação", "adicionar card com D3", "/mira-animator", "slide criativo para o deck", "slide com flip cards", "slide com battle arena", "slide com staircase", ou pedir explicitamente "looping na animação", "animação contínua", "movimento contínuo no slide". Também use quando o usuário enviar uma imagem e pedir "transforme isso em um slide animado" ou "anima essa figura". |
Skill: Slides com Animação Criativa e Looping Interno
REGRA ZERO, Loop Interno Obrigatório
Toda animação criada por esta skill DEVE ter um loop interno contínuo. Uma animação que só entra com fade-up e para é proibida: o slide continua respirando depois da entrada, com algo em movimento perpétuo. Exemplos válidos:
- Partícula viajando por uma linha de A para B repetidamente
- Pulso radial em um elemento central (raio expande e contrai)
- Anel orbital com
stroke-dashoffset girando
- Spotlight sequencial percorrendo elementos um por um
- Cards flipados pulsando em cascata
- Climber/orbe percorrendo um caminho e reiniciando
- Música/agente piscando em uníssono aleatório
Se você não consegue descrever o loop em uma frase ("uma esfera laranja sobe a escada e volta ao começo"), a animação está incompleta.
REGRA DE LIBERDADE CRIATIVA
Varie a metáfora visual conforme o conceito do slide; não use sempre o mesmo formato:
- Conceito hierárquico, hub-and-spoke (SPEC no centro, satélites ao redor)
- Conceito evolutivo, staircase com climber
- Conceito comparativo, battle arena com VS badge e duelos
- Conceito de revelação, flip cards 3D
- Conceito de orquestração, pontos pulsando em uníssono
- Conceito de fluxo, partículas viajando entre nós
- Conceito com objeto concreto, o ícone real do objeto como ator (não um círculo que o representa)
Não caia em "8 cards retangulares enfileirados" (o usuário já reclamou). Cada slide é uma micro-narrativa visual.
REGRA DE VOCABULÁRIO VISUAL, ÍCONE REAL EM VEZ DE CÍRCULO
O círculo (dot, partícula, satélite, anel, pulso radial) virou muleta. Ele é legítimo só para conceitos genuinamente abstratos: fluxo, energia, sinal, conexão, pulso, propagação. Para o resto, empobrece a cena.
Quando o conceito tem referente concreto, o ator da animação é um ícone reconhecível, não um círculo. Se dá para nomear o objeto (livro, cérebro, engrenagem, foguete, banco de dados, chave, escudo, moeda, nuvem, robô, funil, alvo, bússola), anime o objeto.
Estilo flat, não outline. "Flat" aqui é o estilo: silhueta cheia (preenchida), cantos suaves, formas sólidas, pouco detalhe, leitura instantânea à distância e na projeção. É o oposto do traço fino vazado do Lucide, que continua só na moldura do card (header, pílulas). Um ícone flat lê como objeto; um outline fininho some no palco.
Como fazer, sem quebrar nada:
- Traga o ícone como
<path> inline no mesmo <svg> da animação. A regra "dentro do SVG, desenhe com path/rect/line" continua valendo; o path agora vem de um ícone real em vez de um círculo desenhado à mão.
- O ícone é o ator do loop interno (Regra Zero intacta): orbita, viaja pela linha, pulsa, se desenha via
stroke-dashoffset, entra em cascata. Ícone parado no centro é proibido igual a qualquer animação estática.
- Cor segue a paleta do deck, o preenchimento flat permanece. No deck card laranja/preto, recolore o ícone para laranja e neutros mantendo-o cheio; no template de animação pura (multicor), a cor cheia do ícone é bem-vinda. Nunca introduza cor fora do tema num deck card. O tamanho segue a composição.
Fonte e licença, mesmo rigor do mira-icon-morph:
- Puxe ícones planos de fontes abertas, só licenças MIT, Apache-2.0, CC0 ou CC-BY. Duas de primeira linha: Google Material Symbols/Icons (fonts.google.com/icons, Apache-2.0, com eixo fill para a versão preenchida, que é a cara do flat) e a API do Iconify (agrega Material, MDI e centenas de sets flat). Prefira ícone de path único, viewBox
0 0 24 24 (anima limpo).
- Embuta inline; o deck continua offline, por
file://. A internet é usada só na geração.
- Se a licença pedir, registre a atribuição no
CREDITS.md do deck. Recuse IP protegida (personagem de franquia) e sugira arte original.
- Slide inteiro feito de morph de ícones já é o
/mira-icon-morph; aqui o ícone entra como mais um elemento da cena.
Círculo continua ótimo para o abstrato. A regra: não desenhe uma bolinha quando existe um objeto óbvio para desenhar.
REGRA DE IDIOMA
Textos visíveis em português brasileiro, acentuação 100% correta, UTF-8 direto:
- "não", "é", "código", "função", "também", "está", "à medida que"
- NUNCA usar Unicode escapes (
é) ou entidades HTML (é) no body
- Charset declarado:
<meta charset="UTF-8">
REGRA DE FORMATAÇÃO
- Proibido travessão (—) em qualquer texto. Substituir por vírgula, dois-pontos ou reescrever.
- Proibido
\destaque{} ou \textcolor{} em LaTeX. Aqui é HTML, mas a regra geral é: títulos limpos, ênfase via <span class="primary-color italic">.
REGRA DE TÍTULO
- Sem ícone no título. Não coloque
icon-hero nem qualquer <i data-lucide> acima ou ao lado do <h2> do slide. O título é só texto (com ênfase via <span class="primary-color italic">). Ícones continuam permitidos dentro do card (header da animação, pílulas de atributo), nunca no título.
- No máximo 6 palavras no título, a não ser que o usuário peça explicitamente mais. Se o título natural passar de 6 palavras, encurte mantendo o sentido.
- Título colado no topo. A
<section> usa px-6 pt-3 pb-6 e o wrapper do card não leva pt-10 md:pt-16. O bloco do título fecha com mb-2.
- Título da CAPA com quebra equilibrada (diretiva). O título do primeiro slide (a capa, o "header" do deck) segue
agents/_shared/titulo-capa.md: o CSS base do deck deve levar text-wrap: balance escopado só à capa (body > section:first-of-type h1, body > section:first-of-type h2), para nunca quebrar com artigo/preposição solto. Vale só para a capa; os slides de conteúdo não precisam.
Quando o Usuário Aciona a Skill
- Usuário aciona com
/mira-animator ou frase equivalente.
- Usuário normalmente envia uma imagem de referência (figura de livro, diagrama do projeto, print), ou descreve o conceito que quer animar.
- Você decide a metáfora visual mais forte para esse conceito.
- Você implementa diretamente (não pede aprovação prévia se o usuário já deu contexto suficiente).
Onde o Slide é Inserido
Como um novo card dentro do deck do tema, em slides/<tema>/index.html. Se o deck ainda não existir, crie a partir de um esqueleto em mira-templates/decks/ (aula-capitulo, pitch-projeto, demo-tecnica, sandeco-just-animation-template ou mira-perfect), respeitando a estrutura do template escolhido.
Variante: sandeco-just-animation-template (animação pura, multi-slide)
Quando o deck usa este template, ele NÃO é feito de cards. As regras de card desta skill (título, subtítulo, pílulas, glass-card, icon-hero, .anim-stage) ficam SUSPENSAS e valem estas:
- Sem texto sobreposto. Nada de título, subtítulo ou pílulas. Cada slide é só a animação de tela cheia sobre fundo preto. Labels mínimos DENTRO do SVG (parte da metáfora) são permitidos; título de slide, não.
- Cada slide é uma
<section class="slide"> filha direta do <body>, com um <svg class="stage"> full-bleed (position: absolute; inset: 0).
- Tamanho e enquadramento fixos:
viewBox="155.15 87.27 969.70 545.45" (nível 5/10) com preserveAspectRatio="xMidYMid slice", e o marcador <!-- @MIRA:SIZE 5/10 --> na linha acima do svg. Componha o conteúdo centrado em (640, 360) ocupando o palco inteiro; não reserve espaço no topo, porque não há título.
- Cor: paleta LIVRE multicor, alto contraste com o preto, NENHUMA cor predominante. NÃO trave em
var(--mira-primary) nem no laranja do tema. Distribua a paleta (#00E5FF, #7CFF6B, #FFD166, #FF5C8A, #B388FF, #FF904D, mais branco para neutros) entre os elementos.
- Mantém o loop interno perpétuo, o anti-vazamento por geração (
window.__slugGen), o trigger por IntersectionObserver e o botão Replay.
- Para adicionar um slide, duplique uma
<section class="slide"> e registre a função em ANIM.sN.
Variante: mira-perfect (animação de tela cheia + título/header)
Design do deck de lançamento do MIRA. As regras de card também ficam SUSPENSAS; vale a estrutura do sandeco-just-animation-template (seção acima: <section class="slide">, <svg class="stage"> full-bleed, viewBox 5/10 com @MIRA:SIZE, loop perpétuo, anti-vazamento por geração, Replay), com estas diferenças:
- Cada slide de conteúdo leva TÍTULO e HEADER sobrepostos num
<div class="slide-head"> (kicker + <h2> com <em> na palavra de ênfase + parágrafo curto), legíveis pelo scrim do topo. Componha a animação levemente abaixo do centro (o template usa CY + 40) para respirar sob o header.
- A capa é a assinatura do deck:
<section class="slide slide-cover"> com <div class="cover-head"> (kicker + <h1> gigante em gradiente + tagline) sobre uma animação ambiente discreta.
- Cor: UMA cor de marca dominante, não paleta livre. A paleta JS (
OR, DEEP, AM, GOLD) deriva de --mira-primary/--mira-primary-deep/--mira-accent-2 do bloco @MIRA:THEME; use COLD/COLD2 (aço) SOMENTE para "material bruto / estático / fonte protegida". Sem arco-íris.
- Camada cinematográfica compartilhada:
play() já envolve todo slide com cineUnder (brasas quentes ao fundo) e cineOver (vinheta + flash de revelação). Não recrie isso por slide; se um slide precisa de campo limpo, adicione a chave em NOEMBERS.
Estrutura Obrigatória do Card
<div class="w-full max-w-6xl" data-aos="fade-up" data-aos-delay="100">
<div class="text-center mb-2">
<h2 class="text-4xl md:text-5xl font-bold mb-2">
Parte fixa <span class="primary-color italic">parte com ênfase</span>
</h2>
<p class="text-white/60 italic text-lg md:text-xl">Subtítulo curto e direto.</p>
</div>
<div class="glass-card rounded-2xl p-1 md:p-2">
<div class="flex items-center justify-between mb-2 px-1">
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-lg bg-[#FFA203]/15 flex items-center justify-center">
<i data-lucide="ICONE" class="w-5 h-5 primary-color"></i>
</div>
<div>
<p class="text-white font-bold text-sm">Subtítulo da animação</p>
<p class="text-white/50 text-xs italic">Frase complementar curta.</p>
</div>
</div>
<button id="replay-SLUG" class="replay-btn" type="button">
<i data-lucide="rotate-cw" class="w-4 h-4"></i>
Replay
</button>
</div>
<div class="anim-stage" id="SLUG-stage">
<svg id="SLUG-svg" viewBox="0 0 1280 720" preserveAspectRatio="xMidYMid meet"></svg>
</div>
<div class="border-t border-white/10 pt-1 mt-1 mb-1">
<p class="text-xs uppercase tracking-[3px] text-white/40 text-center mb-1">Tagline do slide</p>
<div class="grid grid-cols-2 md:grid-cols-N gap-2">
<div class="attribute-pill text-center p-1 rounded-xl">
<i data-lucide="..." class="w-4 h-4 primary-color mx-auto mb-1"></i>
<p class="text-sm font-semibold tracking-wide">Termo</p>
</div>
</div>
</div>
</div>
</div>
CSS específico do stage. O tamanho padrão do canvas já vem do .anim-stage (no base.css): height: clamp(400px, 60vh, 620px). Só adicione um override por slide no <style> se aquele slide precisar de mais ou menos altura:
#SLUG-stage {
height: clamp(400px, 60vh, 620px);
}
#SLUG-stage + .border-t {
padding-top: 0.25rem;
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
Marcador de Tamanho (@MIRA:SIZE)
Toda animação nasce no nível de tamanho 3/10. Na linha imediatamente acima do .anim-stage, estampe sempre o marcador:
<div class="anim-stage" id="SLUG-stage"> ... </div>
Esse comentário é a memória do tamanho da animação: a skill mira-size-animator o lê para reportar e ajustar a percepção de tamanho (escalar a composição para cima ou para baixo) sem adivinhar o nível atual. Gere uma animação por vez já com o marcador 3/10; não invente outro valor.
Trigger System Obrigatório
Toda animação registra-se em setupAnimationTriggers():
const stages = [
{ stage: document.getElementById('SLUG-stage'), fn: animateSlug, replay: 'replay-SLUG' }
].filter(s => s.stage);
O IntersectionObserver já existente dispara animateSlug() quando o stage entra no viewport, e rearma ao sair. O botão Replay invoca a mesma função manualmente.
Padrão Anti-Vazamento de Loops
Toda função de animação que usa setInterval ou setTimeout recursivo DEVE implementar geração:
function animateSlug() {
clearInterval(window.__slugPulse);
clearInterval(window.__slugFlow);
window.__slugGen = (window.__slugGen || 0) + 1;
const myGen = window.__slugGen;
function loop() {
if (myGen !== window.__slugGen) return;
setTimeout(loop, 1000);
}
}
Sem isso, dois climbers correm ao mesmo tempo no Replay, vaza memória, animações ficam fora de sincronia.
Tipos de Animação Suportados
Tipo A: D3 SVG (orchestra, spec-center, climber)
Use quando o conceito tem estrutura geométrica clara (hub-spoke, escada, rede, gráfico).
Stack:
<svg viewBox="0 0 1280 720"> dentro do .anim-stage
- D3 v7+ via CDN (
https://d3js.org/d3.v7.min.js)
- Use
d3.easeBackOut.overshoot(1.1) para entradas com snap
- Use
d3.easeQuadInOut para movimentos de partícula
- Use
attrTween ou stroke-dashoffset para efeitos contínuos
Loops típicos:
- Pulso radial (
circle com r indo e voltando via setInterval)
- Partículas viajando (criar, animar transição, destruir, repetir)
stroke-dashoffset decrementando para "fluxo" em linhas tracejadas
Tipo B: 3D Flip Cards (spec moderna)
Use quando o conceito é revelação ("o que tem dentro de X").
Stack:
- CSS:
perspective, transform-style: preserve-3d, backface-visibility: hidden
- Curva:
cubic-bezier(0.34, 1.4, 0.64, 1) com leve overshoot
- JS adiciona classe
.flipped em cascata
Loop interno após reveal: um card por vez ganha brilho extra com box-shadow em loop.
Tipo C: Battle Arena / Choreographed Reveal (SDD vs Agile)
Use quando o conceito é comparação binária ou transformação A→B.
Stack:
- Grid 3 colunas (A | center | B)
- Estados iniciais escondidos via CSS (
opacity: 0; transform: translateX(±40px))
- JS adiciona
.revealed em cascata
- Cada lado tem sua própria transição (
agile esquerda, sdd direita com bounce)
Loop interno: partícula viajando de A para B em cada linha (com animation-delay por linha gerando onda em cascata).
Hierarquia Tipográfica Padrão
- Título do slide (h2):
text-4xl md:text-5xl font-bold
- Subtítulo italic:
text-lg md:text-xl text-white/60 italic
- Texto de card grande:
text-xl ou text-2xl
- Texto de pílula:
text-sm ou text-base
- Label uppercase tracked:
text-xs uppercase tracking-[3px]
Cores e Tema
- Primária:
#FFA203 (laranja, classe .primary-color, bg .primary-bg)
- Fundo:
#222222
- Backgrounds dos cards:
rgba(255,255,255,0.30) glassmorph ou rgba(255,162,3,0.08) orange
- Glow:
drop-shadow(0 0 N px rgba(255,162,3,0.55)) com N entre 20 e 40
- Linhas/contornos: tracejado
stroke-dasharray="5,5" com opacity 0.5-0.7
- Texto secundário:
text-white/65 ou text-white/70
- Texto terciário:
text-white/40
Ícones
- Lucide via CDN (
https://unpkg.com/lucide@latest), <i data-lucide="ICONE">
- Na moldura do card (header, pílulas), Lucide sempre outline/line (vazado), nunca filled. O ícone-ator DENTRO da animação é o oposto: flat preenchido (ver REGRA DE VOCABULÁRIO VISUAL)
- Tamanhos:
w-4 h-4 (pequeno), w-7 h-7 (médio), w-12 h-12 (grande)
- Dentro do SVG da animação, não use
<i data-lucide>: inline o <path> do ícone. Para um objeto concreto, traga um ícone flat real como ator; <circle>, <rect>, <line> desenhados à mão só para formas abstratas
Workflow de Execução
- Identificar o conceito que o slide vai comunicar (revelação? comparação? hierarquia? evolução?)
- Escolher a metáfora visual mais forte para esse conceito (não copiar uma metáfora já usada no mesmo capítulo se possível)
- Esboçar mentalmente o loop interno ANTES de codar. Se não houver loop, parar e repensar.
- Ler um esqueleto em
mira-templates/decks/ como referência de padrão visual e estrutural do deck.
- Adicionar o CSS específico do novo stage no
<style>.
- Inserir o HTML do card dentro do
<main> em posição lógica.
- Implementar a função JS com:
- Reset (clearInterval de loops anteriores + selectAll('*').remove() do svg)
- Geração anti-vazamento (
window.__slugGen)
- Entrada coreografada com stagger
- Loop interno contínuo
- Registrar o trigger em
setupAnimationTriggers().
- Reportar ao usuário descrevendo o loop interno em uma frase, para confirmar que a regra-mãe foi cumprida.
Anti-padrões (NÃO FAÇA)
- ❌ Fade-up + parou. Sem loop interno.
- ❌ Pulse genérico em todos os elementos ao mesmo tempo (sem hierarquia visual).
- ❌ Desenhar um círculo/dot genérico quando o conceito tem um objeto concreto óbvio. Use um ícone flat real como ator.
- ❌ Animação durando 200ms sem easing customizado (parece bug, não criativo).
- ❌ Cor diferente do tema laranja/preto. Não tem azul, verde, rosa neste livro.
- ❌ Texto com travessão (—).
- ❌ Texto sem acento ou com
é, ç etc.
- ❌
setInterval sem clearInterval correspondente no início da função.
- ❌ 4 cards retangulares idênticos enfileirados (a menos que seja uma grid intencional e única).
- ❌ Animação que precisa ser explicada para ser entendida. A metáfora visual deve ser óbvia.
Checklist Antes de Entregar
Referência de Padrões
Os blueprints de card já prontos vivem em mira-templates/slides/ (capa, comparação, métricas, fluxo, escada, orbital, encerramento), cada um com seu loop interno. Os esqueletos de deck completos vivem em mira-templates/decks/. Ao criar um novo slide, abra o blueprint mais próximo do que você quer fazer e use como base estrutural, variando a metáfora visual conforme o conceito.
Sistema de Passagem de Slides (obrigatório)
Todo deck gerado deve manter o sistema de navegação que já vem nos esqueletos de mira-templates/decks/:
- Barra de progresso no topo (
#mira-progress).
- Botão flutuante "próximo" no canto (
#mira-next).
- Navegação por teclado: setas, PageUp/PageDown, Home/End e F para tela cheia, rolando seção a seção via
scrollIntoView.
Cada slide é uma <section class="min-h-screen"> filha direta do <body>. Nunca remova esse bloco ao editar ou montar um deck.