Um filhote, um clipe de 10 segundos e um cursor para seguir.
Do vídeo aos 240 frames em grade: como o personagem passou a olhar para o mouse sem nenhuma pose inventada, e por que a primeira versão mostrava frames sobrepostos.
Pipoca & Cia é uma marca fictícia criada para este estudo. Não há produtos, vendas ou cadastro.
CAPTURA DO SITE REAL · PRÉVIA MUDA
Um prompt curto, um vídeo e a pergunta: como fazer o olhar acompanhar?
O Jorge enviou um clipe de 10 segundos e pediu uma hero interativa em JavaScript puro. O resultado usa o vídeo original em loop no fundo; ao mover o mouse, uma sprite com todos os frames assume no mesmo instante e o filhote vira a cabeça para onde o cursor está, a partir de um mapa de olhar montado pela análise dos frames. Quando o mouse para, o vídeo retoma da pose. A página Raio-X do próprio site ensina a reproduzir tudo, do FFmpeg ao código.
240frames do clipe na sprite, nenhum geradoREADME.md · grade 60×4, 384×216
1,07 spara assentar de uma ponta à outrasimulação a 60 fps do motor · sem overshoot
Olhar que segue o mouseMapa cursor → instante do clipe com keypoints em ordem cronológica; o easing atravessa poses reais do vídeo.
Handoff no frame exatoVídeo e sprite compartilham a linha do tempo: pausa, quantiza a 1/24 s, canvas assume; parado 900 ms, o vídeo volta do mesmo ponto.
Raio-X reproduzívelNove etapas com comandos FFmpeg, decisões, erros, o prompt ajustado e o código-fonte completo, dentro do próprio site.
Os dois prompts, na ordem em que foram usados.
Primeiro o vídeo nasce de uma imagem no Google Flow; depois o Claude transforma esse vídeo na hero interativa. Os textos abaixo são os que geraram este projeto, sem edição.
1. Gerar o vídeo no Google FlowAbra o Google Flow, adicione a imagem do personagem como imagem inicial e cole:
Trate a imagem enviada como uma referência rígida. Mantenha o personagem, a expressão, as proporções, a iluminação, o ângulo da câmera, o enquadramento e o fundo exatamente como mostrado. A câmera deve permanecer totalmente travada: sem zoom, pan, rotação, reenquadramento ou qualquer mudança de cena em nenhum momento.
Anime apenas o personagem. Nunca adicione cursor, ponteiro, ponto, inseto, brinquedo, mão, sombra, partícula ou qualquer outro elemento novo no quadro.
O personagem deve reagir como se algo estivesse flutuando ao seu redor, percorrendo 360 graus completos da sua atenção. Os olhos iniciam o movimento, e a cabeça acompanha um instante depois. As orelhas giram sutilmente, o pescoço se move de forma natural, e os bigodes apresentam um leve movimento secundário.
Faça com que ele olhe para a extrema esquerda, depois para a parte inferior esquerda, depois para a parte superior esquerda, retornando suavemente pelo centro; em seguida para a extrema direita, parte inferior direita, parte superior direita, e por fim volte exatamente para a pose inicial e coma um pedaço do biscoito (isso deve parecer real). Inclua pequenas pausas antes de cada mudança de direção, um leve excesso natural de movimento (overshoot) e transições suaves com desaceleração/aceleração fluida (easing) em todos os movimentos.
O corpo, os ombros, o peito, as patas e a postura sentada devem permanecer quase totalmente imóveis. Não faça alongamento, deformação facial, giros, rotações exageradas, respiração visível ou movimento de bombeamento do tronco. O primeiro e o último frame devem ser idênticos, para que o clipe possa ser reproduzido em loop de forma limpa, quadro a quadro.
2. Criar a hero com o ClaudeEnvie o vídeo gerado junto com:
Crie uma hero section interativa a partir da animação enviada.
Use FFmpeg para extrair todos os frames do clipe e reuni-los em uma única sprite sheet em grade (todos os frames, na taxa original do vídeo, distribuídos em várias linhas para respeitar o limite de largura dos navegadores). Depois, crie um sistema de animação baseado em frames usando JavaScript puro (vanilla JavaScript), desenhando em canvas com cross-fade entre frames vizinhos.
Coloque o vídeo original em loop no fundo. Quando o mouse se mover, pause o vídeo e faça a sprite assumir exatamente no mesmo frame, sem sobreposição; quando o mouse parar ou sair da área, o vídeo retoma a partir da pose em que o personagem ficou. Carregue o vídeo como Blob para o seek ser preciso.
Faça o personagem olhar para o cursor de verdade: antes de programar, analise os frames e identifique em que instantes ele olha para a esquerda, direita, frente, cima e para o objeto que segura. Monte um mapa cursor → instante do clipe com esses pontos, e percorra a sprite com interpolação com easing (amortecimento dependente de dt, velocidade máxima limitada).
Mantenha a composição original, preserve o personagem centralizado em paisagem e em retrato, e faça toda a interação transmitir uma sensação premium, fluida e responsiva. Teste no navegador antes de entregar.
Sobre o Blob: carregar o vídeo como Blob resolve o seek em servidores de desenvolvimento sem HTTP Range. Atrás de uma CSP com media-src self, como neste programa, usa-se src direto e confere-se que o servidor devolve 206.
NÃO É UM BOTÃO MÁGICO.
É UMA SEQUÊNCIA DE DECISÕES.
O raio-X mostra inclusive o que foi reprovado. Porque saber o que corrigir também é construir.
01
Pesquisar a marca
Referências, linguagem e fidelidade do produto antes da ferramenta.
02
Escrever a experiência
Um roteiro de cenas, transições e intenção de cada momento.
03
Dirigir a arte
Gerar, compor, comparar e corrigir as imagens no contexto.
04
Dar movimento às imagens
Frames aprovados, prompts de UGC e seleção das saídas do Flow.
05
Construir com código
Astro, 3D, movimento de scroll e alternativas por capacidade do dispositivo.
06
Revisar de verdade
Rótulo, recortes, teclado, contraste, carga e comportamento.
07
Preparar a publicação
SEO, segurança, artefatos estáticos e entrega para integração.
RAIO-X
O resultado tem bastidores.
8 recortes de um único projeto: o clipe, a análise dos frames, a sprite em grade, o mapa de olhar, o handoff, a correção da dupla exposição, o retrato e a página Raio-X. Artefatos reais e instruções documentadas.
RAIO-X / Pipoca & Cia · hero
Um clipe de 10 segundos virou o hero.
O Jorge enviou um clipe gerado por IA (1280×720, 24 fps, 240 frames) e uma imagem de referência. Nenhuma pose foi gerada: o filhote que olha para o cursor é sempre um frame real do vídeo. Em repouso quem aparece é o vídeo original, mudo e em loop, na resolução completa; a sprite só entra quando o ponteiro se move.
Frame de repouso do clipe (t = 4,0 s)Hero em produção, cursor à esquerda
Ferramenta / modelo · conforme registro
Google Flow gerou o clipe a partir da imagem (prompt abaixo); FFmpeg 7.1 (binário do pacote imageio-ffmpeg) para frames e sprite; Claude Fable 5.1 escreveu o motor em JavaScript puro (canvas, sem bibliotecas).
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · 1. Gerar o vídeo no Google Flow
Trate a imagem enviada como uma referência rígida. Mantenha o personagem, a expressão, as proporções, a iluminação, o ângulo da câmera, o enquadramento e o fundo exatamente como mostrado. A câmera deve permanecer totalmente travada: sem zoom, pan, rotação, reenquadramento ou qualquer mudança de cena em nenhum momento.
Anime apenas o personagem. Nunca adicione cursor, ponteiro, ponto, inseto, brinquedo, mão, sombra, partícula ou qualquer outro elemento novo no quadro.
O personagem deve reagir como se algo estivesse flutuando ao seu redor, percorrendo 360 graus completos da sua atenção. Os olhos iniciam o movimento, e a cabeça acompanha um instante depois. As orelhas giram sutilmente, o pescoço se move de forma natural, e os bigodes apresentam um leve movimento secundário.
Faça com que ele olhe para a extrema esquerda, depois para a parte inferior esquerda, depois para a parte superior esquerda, retornando suavemente pelo centro; em seguida para a extrema direita, parte inferior direita, parte superior direita, e por fim volte exatamente para a pose inicial e coma um pedaço do biscoito (isso deve parecer real). Inclua pequenas pausas antes de cada mudança de direção, um leve excesso natural de movimento (overshoot) e transições suaves com desaceleração/aceleração fluida (easing) em todos os movimentos.
O corpo, os ombros, o peito, as patas e a postura sentada devem permanecer quase totalmente imóveis. Não faça alongamento, deformação facial, giros, rotações exageradas, respiração visível ou movimento de bombeamento do tronco. O primeiro e o último frame devem ser idênticos, para que o clipe possa ser reproduzido em loop de forma limpa, quadro a quadro.
Documento de origem: E:\Dogs\PROMPT.md · 1. Gerar o vídeo no Google Flow
Um mapeamento linear do mouse para a linha do tempo faria o personagem passar por todas as poses em qualquer ordem. Antes de programar, grades de contato (1 miniatura a cada 0,6 s e a cada 0,33 s) e recortes de frames-chave registraram os instantes: esquerda em 1,0–2,3 s, frente em 4,0 s, direita em 5,0–5,7 s, olhar para cima em 6,0–6,7 s, mordida em 8,0–8,6 s.
Grade de contato: 16 miniaturas, uma a cada 0,6 sFrames-chave com o instante anotado
Ferramenta / modelo · conforme registro
FFmpeg (filtros fps + tile) e Pillow para os recortes anotados; leitura visual pelo Claude.
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · Etapa 3 — Analisar os frames antes de programar
ffmpeg -i clipe.mp4 -vf "fps=3,scale=400:-1,tile=6x5" -frames:v 1 grade-densa.jpg — depois recortar os frames 1, 25, 41, 57, 73, 97, 121, 137, 145, 161, 201 e 217 com o instante anotado.
Documento de origem: E:\Dogs\src\data\raio-x.js · Etapa 3 — Analisar os frames antes de programar
Navegadores não decodificam imagens com mais de cerca de 32.767 px de largura. Os 240 frames numa linha só caberiam com 136 px cada. A sprite final é uma grade de 60 colunas por 4 linhas (23.040×864 px, ~20 MP, 2,8 MB em JPEG), gerada com o filtro tile do FFmpeg. O frame i fica na coluna i mod 60 e na linha ⌊i / 60⌋.
Versão anterior: 60 frames a 6 fps, com dupla exposiçãoRecorte das 6 primeiras colunas da grade final
O eixo horizontal do cursor é convertido em tempo do clipe por keypoints interpolados com smoothstep: 1,05 s na borda esquerda, 4,0 s no centro, 5,7 s na borda direita. Como a sequência está em ordem cronológica no vídeo, quando o alvo muda de uma ponta à outra o motor atravessa poses intermediárias reais e a transição parece movimento, não corte. Faixa superior da tela leva ao olhar para cima; a região do biscoito, à mordida.
Cursor na borda esquerda (t ≈ 1,1 s)Cursor na borda direita (t ≈ 5,7 s)
Ferramenta / modelo · conforme registro
JavaScript puro: gazeTime(x, y), amortecimento exponencial dependente de dt (rate 9/s) e velocidade máxima de 6 s de clipe por segundo.
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · 2. Criar a hero com o Claude
Crie uma hero section interativa a partir da animação enviada.
Use FFmpeg para extrair todos os frames do clipe e reuni-los em uma única sprite sheet em grade (todos os frames, na taxa original do vídeo, distribuídos em várias linhas para respeitar o limite de largura dos navegadores). Depois, crie um sistema de animação baseado em frames usando JavaScript puro (vanilla JavaScript), desenhando em canvas com cross-fade entre frames vizinhos.
Coloque o vídeo original em loop no fundo. Quando o mouse se mover, pause o vídeo e faça a sprite assumir exatamente no mesmo frame, sem sobreposição; quando o mouse parar ou sair da área, o vídeo retoma a partir da pose em que o personagem ficou. Carregue o vídeo como Blob para o seek ser preciso.
Faça o personagem olhar para o cursor de verdade: antes de programar, analise os frames e identifique em que instantes ele olha para a esquerda, direita, frente, cima e para o objeto que segura. Monte um mapa cursor → instante do clipe com esses pontos, e percorra a sprite com interpolação com easing (amortecimento dependente de dt, velocidade máxima limitada).
Mantenha a composição original, preserve o personagem centralizado em paisagem e em retrato, e faça toda a interação transmitir uma sensação premium, fluida e responsiva. Teste no navegador antes de entregar.
Documento de origem: E:\Dogs\PROMPT.md · 2. Criar a hero com o Claude
Sprite e vídeo compartilham os mesmos 10 segundos. Ao mover o mouse, o vídeo pausa, o tempo é quantizado ao frame (round(t × 24) / 24), o canvas desenha esse frame e aparece em 70 ms já mostrando a mesma imagem. Parado 900 ms ou fora da área, o vídeo recebe currentTime igual ao tempo da sprite, espera o seeked e volta a tocar; o canvas some em 220 ms. Em desenvolvimento o seek caía em 0 porque o servidor Python não responde a HTTP Range; em produção o nginx devolve 206.
Repouso: o vídeo em loopCursor sobre o biscoito: a sprite na mordida
Ferramenta / modelo · conforme registro
Máquina de estados video → follow → resume → video em JavaScript puro; simulação em Node confirmou assentamento em 1,07 s de ponta a ponta sem overshoot.
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · Etapa 5 — Vídeo em loop e a troca sem emenda
Quando o ponteiro se move: pause o vídeo, quantize o currentTime ao frame exato, desenhe esse frame no canvas e mostre o canvas em ~70 ms; só então o alvo passa a seguir o cursor. Parado por ~900 ms: currentTime = tempo da sprite, seeked, play(), fade do canvas.
Documento de origem: E:\Dogs\src\data\raio-x.js · Etapa 5 — Vídeo em loop e a troca sem emenda
A primeira sprite tinha 1 frame a cada 4 (60 frames, tira única de 30.720 px). O cross-fade entre vizinhos a 167 ms de distância virava dupla exposição nas viradas de cabeça, e no início do handoff a sprite já se movia enquanto o canvas aparecia sobre o vídeo parado. A correção: todos os 240 frames em grade (vizinhos a 42 ms) e alvo travado no frame exato do vídeo durante a entrada do canvas.
Cross-fade a 6 fps: frames 121 + 125 a 50%Cross-fade a 24 fps: frames 121 + 122 a 50%
Ferramenta / modelo · conforme registro
Reconstrução do defeito com Pillow: mistura a 50% dos frames 121 e 125 (6 fps) contra 121 e 122 (24 fps).
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · "deixa a transição sprite/vídeo mais suave"
Deixa a transição sprite/vídeo mais suave: quando eu movo o mouse eu vejo ainda frames sobrepostos.
Documento de origem: Conversa de produção, 16/09/2026 · "deixa a transição sprite/vídeo mais suave"
O corte cover em retrato deixava o filhote gigante e cortado. A composição ficou ancorada no topo com 66% da altura e o texto desceu para o fundo escuro. Como só o centro do quadro 16:9 aparece, as poses laterais ficavam inalcançáveis: o eixo x do cursor passou a cobrir a largura visível, e não a largura da composição.
Quadro 16:9 originalRetrato em produção (720×1300), cabeça virada à direita
Ferramenta / modelo · conforme registro
layout() e toComposition() em src/sprite-hero.js; o <video> é posicionado por JavaScript no mesmo retângulo do canvas.
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · Etapa 6 — Composição, retrato e o que fica em volta
const x = portrait ? px / w : (px - dest.x) / dest.w;
Documento de origem: E:\Dogs\src\data\raio-x.js · Etapa 6 — Composição, retrato e o que fica em volta
O pedido do Jorge foi que quem acessar o raio-X consiga reproduzir o mesmo resultado. A página /pipoca-cia/raio-x/ tem nove etapas: entrada, FFmpeg, análise, motor, handoff, layout, QA, o prompt ajustado e o arquivo sprite-hero.js inteiro. Todo o texto vive em src/data/ e é renderizado em HTML estático no build, sem script inline.
Abertura da página Raio-XEtapa 2: a grade de olhares e a tabela de instantes
Ferramenta / modelo · conforme registro
Vite + plugin de conteúdo próprio (scripts/content-plugin.mjs); botões "Copiar" progressivos.
Tempo de produção
Não documentado. Não estimado.
Prompt ou instrução real · raioX.steps
Detalhe passo a passo para quem acessar o raio-X do projeto consiga reproduzir o mesmo resultado.
Documento de origem: E:\Dogs\src\data\raio-x.js · raioX.steps