Communitygithub.com

og-image-animated

Transforma o cartão Open Graph estático de um projeto em uma animação web de alguns segundos — a marca e o título caem do topo, e a janela do aplicativo surge de baixo e se estabiliza no cartão final. Gera uma rota web jogável na stack do projeto e a grava quadro a quadro em MP4, GIF e PNG.

O que é og-image-animated?

Esta skill transforma o cartão de compartilhamento Open Graph (OG image) estático de um projeto em uma animação curta e elegante, criando uma rota web interativa e exportando o resultado em MP4, GIF e PNG. Ela é útil para desenvolvedores que desejam adicionar um vídeo de apresentação animado para posts em redes sociais, README, páginas de lançamento ou usar como `og:video`. A skill funciona com qualquer framework web (React, Next.js, etc.) e é totalmente baseada em animações CSS, sem JavaScript para garantir captura determinística. O processo envolve: (1) detectar o componente de cartão estático existente, (2) adicionar uma prop `animated` ao componente para criar os keyframes de entrada, (3) criar uma rota web que renderiza o cartão animado, (4) gravar a animação usando um script Node.js com Puppeteer e ffmpeg, e (5) revisar o resultado. A animação segue regras rigorosas: apenas opacidade e transformação translateY, uma curva de easing consistente, duração total de 2-2,5s com pausa de 1,5s, e suporte para CSS keyframes. O script de gravação captura cada quadro da animação CSS de forma determinística, garantindo resultados idênticos a cada execução. A skill também garante que o cartão estático permaneça inalterado para uso como `og:image`, já que plataformas sociais não suportam animações.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/paralect/saas-skills/tree/HEAD/skills/og-image-animated

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Animação do cartão Open Graph (OG Image)

Todo arquivo usado por esta skill reside em sua própria pasta, ao lado deste SKILL.md, e os caminhos aqui são relativos a essa pasta. Ela não precisa de nada de outras skills ou pastas, portanto não procure por elas. A menos que o usuário especifique outro local, salve tudo o que ela produzir em out/og-image-animated/ dentro do projeto atual.

O cartão de compartilhamento estático animado como uma revelação curta e calma:

  1. Cartão vazio: apenas fundo e brilho suave.
  2. Marca e título descem do topo (fade + deslizar para baixo).
  3. A janela do aplicativo sobe do fundo (fade + deslizar para cima) e se estabiliza exatamente onde estava no cartão estático.
  4. Pausa no quadro final, que deve corresponder exatamente à imagem OG estática.

Exemplos: references/pulse.gif (o resultado) e references/pulse-frames.png (quatro quadros: início, título entrando, aplicativo subindo, final).

Regras

  • Comece pelo cartão estático. Se o projeto ainda não tiver um componente de cartão OG, construa-o primeiro seguindo references/static-card.md (produto real, mensagens do site atual, dados realistas). A animação adiciona apenas movimento: mesma marcação, mesmo layout final, nenhum conteúdo novo.
  • Um componente, dois modos. Adicione uma prop animated ao componente de cartão existente em vez de copiá-lo, para que o PNG estático e a animação nunca se desalinhem. Sem a prop, nada anima.
  • Movimento, não efeitos. Apenas opacity + transform: translateY, com uma única curva de easing compartilhada (cubic-bezier(0.16, 1, 0.3, 1)). Sem bounce, desfoque, escala, texto digitado ou elementos girando.
  • Curto. Toda a linha do tempo dura cerca de 2–2,5s, depois uma pausa de ~1,5s. O título deve estar totalmente legível por volta de ~1,3s.
  • Apenas animações CSS (keyframes + animation com preenchimento both), sem tweens ou temporizadores acionados por JavaScript dentro do cartão. O gravador busca animações CSS através da Web Animations API; movimentos acionados por JS não seriam capturados deterministicamente.

Linha do tempo

ElementoKeyframesDuraçãoAtraso
Marcade opacity: 0; translateY(-48px)900ms100ms
Títulode opacity: 0; translateY(-48px)1000ms250ms
Janela do appde opacity: 0; translateY(320px)1300ms700ms

Ajuste as distâncias para o cartão: o aplicativo deve começar majoritariamente abaixo da borda inferior (cerca de metade da altura do cartão) e o título cerca de sua própria altura acima de sua posição final. Se houver um painel flutuante, deixe-o chegar por último (+200ms após o início da janela).

Etapas

1. Descobrir

  • Encontre o componente de cartão estático e sua rota de renderização (ex.: og-image.tsx, /og/<page>), e o PNG atual em public/.
  • Anote os wrappers da marca, título e janela do aplicativo. Se a janela usar zoom para ajustar, anime um wrapper interno, não o elemento com zoom, para que os deslocamentos permaneçam corretos.

2. Adicionar o modo animado

No componente do cartão:

const KEYFRAMES = `
@keyframes og-drop { from { opacity: 0; transform: translateY(-48px); } to { opacity: 1; transform: none; } }
@keyframes og-rise { from { opacity: 0; transform: translateY(320px); } to { opacity: 1; transform: none; } }
`;
const EASE = 'cubic-bezier(0.16, 1, 0.3, 1)';
const enter = (name: string, ms: number, delay: number) => ({ animation: `${name} ${ms}ms ${EASE} ${delay}ms both` });

// <div data-og-frame …>{animated && <style>{KEYFRAMES}</style>} …
// marca:  style={animated ? enter('og-drop', 900, 100) : undefined}
// titulo:  style={animated ? enter('og-drop', 1000, 250) : undefined}
// janela: <div style={{ zoom }}><div className="h-full" style={animated ? enter('og-rise', 1300, 700) : undefined}>…

Coloque os keyframes no componente (uma tag <style>) ou no CSS global do projeto; com Tailwind v4, keyframes dentro de @theme só são emitidos quando um token --animate-* correspondente é usado, então prefira o componente ou CSS puro.

3. Adicionar uma rota web que reproduza a animação

Uma rota irmã da estática, ex.: /og/<page>-animated (noindex, sem chrome do aplicativo):

  • Renderiza <Card animated /> dentro do frame 1200×630.
  • Reproduz para visualização: desmonta e remonta o cartão com uma key diferente a cada ~4,5s.
  • ?loop=0 reproduz uma vez (o gravador usa isso). Normalize o parâmetro de busca para string primeiro: roteadores como TanStack interpretam ?loop=0 como o número 0, e uma verificação incorreta continuaria remontando o cartão durante a gravação.

Abra no navegador e assista algumas vezes. Verifique a ordem de entrada, se nada pisca antes do início da animação e se o estado final corresponde ao cartão estático.

4. Gravar MP4 + GIF

Com o servidor de desenvolvimento em execução:

node <pasta desta skill>/scripts/record.mjs \
  --url "http://localhost:<porta>/og/<page>-animated?loop=0" \
  --out out/og-image-animated/og-<page>

Gera og-<page>.mp4 (2400×1260, H.264, 30fps), og-<page>.gif (1200px de largura, paleta otimizada, looping) e og-<page>.png (quadro final). Como funciona: pausa cada animação na página, lê a duração da linha do tempo, então avança todas as animações quadro a quadro e captura uma região fixa de [data-og-frame]. O resultado é idêntico a cada execução, sem quadros perdidos. Opções: --fps, --hold, --lead, --scale, --formats mp4,gif,png, --selector.

Requer ffmpeg no PATH. O Playwright é instalado na pasta scripts/ desta skill na primeira execução, com seu Chromium se nenhum for encontrado.

Armadilhas:

  • A página não deve forçar movimento reduzido. Muitos estilos globais encurtam animações em prefers-reduced-motion; o gravador não emula isso e falha alto se não encontrar animações.
  • Capturas de tela de elementos esperam por "estabilidade", que nunca chega durante uma animação. Por isso o script recorta uma região da página.
  • Certifique-se de que a porta está realmente servindo este aplicativo (outro servidor local pode responder em localhost).

5. Revisar

Extraia uma folha de contato e examine:

ffmpeg -y -loglevel error -i og-<page>.mp4 \
  -vf "select='eq(n\,8)+eq(n\,22)+eq(n\,40)+eq(n\,<último>)',scale=1000:-1,tile=2x2" -frames:v 1 sheet.png
  • Quadro ~0,25s: cartão vazio (apenas brilho), sem salto de layout.
  • ~0,7s: título entrando ou quase entrou, aplicativo ainda não visível.
  • ~1,3s: aplicativo no meio da subida, título totalmente legível.
  • Último quadro: conteúdo idêntico ao PNG estático.

Mantenha o GIF razoavelmente pequeno (abaixo de ~3MB). Se for maior, reduza --fps (20–24) ou encurte --hold.

Saída

Informe ao usuário:

  • a URL da rota de visualização (com loop) e os arquivos gerados (MP4, GIF, PNG)
  • o comando para regenerar
  • a linha do tempo (o que se move, durações)
  • que og:image deve permanecer o PNG estático: plataformas sociais não reproduzem imagens OG animadas. Use o MP4/GIF para posts, README, páginas de lançamento ou og:video onde houver suporte.

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Habilidades Relacionadas