Nos meus projetos e artigos recentes sobre o ecossistema do Kiro (como os relatos de 1 ano de Kiro na Dimensa e o repositório de KiroCrew Ports), o assistente aparece como ferramenta de terminal e infraestrutura de trabalho. No meio desses experimentos com agentes e skills, resolvi explorar outra face desse universo: transformar o mascote fantasma do Kiro em um avatar SVG animado e interativo para a web.
O resultado é o kiro-ghost, um projeto open-source em Vue e TypeScript que reproduz o personagem em animação fluida a partir dos contornos oficiais.
Do Bloub ao Kiro Ghost
O projeto começou como um fork do Bloub, criado por Jérémy Perret. O Bloub original é uma realização técnica impressionante: ele animava o mascote do x.ai usando modelagem radial. O corpo era tratado como um perfil circular modulado por raios angulares medidos quadro a quadro a partir de um vídeo de referência.
Para um personagem esférico ou circular, a matemática polar funciona muito bem. O mascote do Kiro, no entanto, tem outra estrutura. Ele é vertical, tem dobras na base, assimetrias marcadas em cada expressão e proporções que variam conforme a inclinação. Tentar encaixar o fantasma em um perfil de raios centrados distorcia o desenho e apagava os traços que definem a silhueta.
Em vez de construir tudo do zero, preservei o motor de estados, a interface reativa e os exportadores do Bloub. A mudança essencial foi substituir a modelagem polar por um pipeline de extração e interpolação vetorial direta.
Extração e normalização de contornos
O repositório armazena as oito poses de referência em reference/ghost-poses/. Para que duas curvas SVG possam transitar suavemente entre si, elas precisam ter a mesma quantidade de pontos e uma correspondência direta de vértices. Se um contorno tiver 50 pontos e o outro 80, ou se o ponto inicial de uma pose começar na base e na outra no topo, a interpolação gera um emaranhado de linhas cruzadas.
A solução foi automatizar esse tratamento no script tools/extract-kiro-poses.mjs:
- Varredura dos comandos: o extrator faz o parse dos paths SVG (comandos absolutos
M,L,H,V,CeZ) diretamente pelo arquivo, sem depender do DOM do navegador. - Aproximação de Bézier: curvas cúbicas são fragmentadas em passos densos para reproduzir fielmente o traçado original.
- Alinhamento do topo: o algoritmo calcula a área orientada da curva e localiza o ponto mais alto da cabeça, garantindo o mesmo vértice inicial em todas as poses.
- Reamostragem regular: o contorno do corpo principal é reamostrado em exatamente 128 pontos distribuídos por comprimento de arco.
- Olhos e elementos secundários: cada olho recebe 32 pontos normalizados. Elementos avulsos (os accents, como a bolha flutuante da pose 1) são amostrados com 48 pontos.
O resultado desse processamento gera o arquivo src/bot/kiro-poses.ts. Sempre que um SVG de referência precisa de ajuste, o comando pnpm generate:kiro atualiza as coordenadas de forma previsível.
Motor de animação e interpolação
Com a geometria padronizada, a transição entre poses torna-se uma interpolação direta. No arquivo src/bot/kiro.ts, a função blendPoints interpola linearmente as coordenadas dos 128 pontos do corpo e dos 32 pontos de cada olho:
function blendPoints(a: Point[], b: Point[], t: number): Point[] { return a.map((point, index) => ({ x: lerp(point.x, b[index]!.x, t), y: lerp(point.y, b[index]!.y, t) }))}Quando a pose seguinte possui elementos que não existem na pose atual (ou vice-versa), o motor aplica um crossfade de opacidade no contorno secundário. Isso permite que detalhes como bolhas surjam e desapareçam sem corte brusco.
Na animação de repouso (idle), a timeline foi ajustada para alternar poses mantendo pausas estáveis. O personagem não fica em mutação contínua: ele repousa por alguns segundos e executa a transição em um intervalo curto, preservando o peso visual da ilustração.
Note
Para garantir que a animação seja reproduzível e testável, o módulo src/bot/ não utiliza relógio de sistema nem importa reatividade do Vue. Toda amostragem é uma função pura do tempo decorrido: sample(t).
Componente e exportação
O projeto expõe o componente Vue BloubBot (nome mantido por compatibilidade com a base herdada), aceitando controles de tamanho, estado, ciclos e direção do olhar:
<BloubBot v-model:state="state" v-model:playing="playing" /><BloubBot state="orbit" :size="120" :frozen-at="1.2" />Além da renderização em tela, o projeto preserva a esteira de exportação:
- SVG animado: gera código vetorial com tags SMIL calculadas a partir dos paths interpolados, rodando nativamente no navegador sem depender de scripts.
- Formatos rasterizados: exportação em PNG estático, GIF animado e MP4 (utilizando a biblioteca
mediabunnycarregada sob demanda via import dinâmico).
Stack técnica e atribuição
A base do projeto utiliza:
- Vue 3.5 e Vite 8 com TypeScript strict
- Tailwind CSS 4 com
@tailwindcss/vite - pnpm como gerenciador de pacotes
- Vitest para testes de regressão matemática e geométrica
O código do Kiro Ghost está sob licença MIT. O projeto é um fork que estende o trabalho de Jérémy Perret no Bloub. Os contornos vetoriais e a identidade visual do mascote pertencem aos seus respectivos detentores (Kiro / AWS), sendo esta uma implementação independente para estudo e desenvolvimento open source.
O código completo e as instruções de execução estão no GitHub.