Communitygithub.com

Parcha-ai/build

Crie composições de vídeo, animações, cartelas de título, sobreposições, legendas, narrações, visuais reativos a áudio e transições de cena em HTML HyperFrames.

O que é build?

Esta skill capacita agentes de IA a produzirem conteúdo de vídeo completo usando HTML como a única fonte da verdade, por meio do framework HyperFrames. Ela cria composições, anima elementos com GSAP, sincroniza legendas com áudio, gera narrações por texto-para-fala, produz visuais que reagem a batidas musicais (pulsos, brilhos sincronizados) e adiciona transições entre cenas (como crossfades e wipe). A skill utiliza atributos data-* para controle de tempo e trilhas, garantindo que o layout final seja construído antes da animação para evitar sobreposições acidentais. É compatível com plataformas como Claude Code e Cursor, e deve ser usada sempre que o usuário solicitar a criação de qualquer conteúdo de vídeo baseado em HTML, incluindo legendas, narrações, animações reativas a áudio e transições entre cenas.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Parcha-ai/build/tree/HEAD/.agents/skills/hyperframes

Perguntar na sua IA favorita

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

Prévia

Do README da skill

Documentação

HyperFrames

O HTML é a fonte da verdade para o vídeo. Uma composição é um arquivo HTML com atributos data-* para controle de tempo, uma timeline GSAP para animação e CSS para aparência. O framework gerencia a visibilidade dos clipes, a reprodução de mídia e a sincronização da timeline.

Abordagem

Antes de escrever HTML, pense em alto nível:

  1. O quê — o que o espectador deve experimentar? Identifique o arco narrativo, os momentos-chave e as batidas emocionais.
  2. Estrutura — quantas composições, quais são sub-composições versus inline, quais trilhas carregam o quê (vídeo, áudio, sobreposições, legendas).
  3. Tempo — quais clipes determinam a duração, onde as transições ocorrem, qual é o ritmo.
  4. Layout — construa o estado final primeiro. Veja "Layout Antes da Animação" abaixo.
  5. Animar — depois adicione movimento usando as regras abaixo.

Para pequenas edições (corrigir uma cor, ajustar o tempo, adicionar um elemento), vá direto para as regras.

Quando nenhum visual-style.md ou direção de animação for fornecido, siga house-style.md para padrões de movimento, dimensões e paletas de cores.

Layout Antes da Animação

Posicione cada elemento onde ele deve estar no seu momento mais visível — o quadro em que ele entrou completamente, está corretamente posicionado e ainda não está saindo. Escreva isso como HTML+CSS estático primeiro. Nenhum GSAP ainda.

Por que isso importa: Se você posicionar elementos no estado inicial animado (fora da tela, escalados para 0, opacidade 0) e animá-los para onde você acha que devem parar, você está adivinhando o layout final. Sobreposições ficam invisíveis até o vídeo ser renderizado. Ao construir o estado final primeiro, você pode ver e corrigir problemas de layout antes de adicionar qualquer movimento.

O processo

  1. Identifique o quadro herói para cada cena — o momento em que o maior número de elementos está simultaneamente visível. Esse é o layout que você constrói.
  2. Escreva CSS estático para esse quadro. O contêiner .scene-content DEVE preencher toda a cena usando width: 100%; height: 100%; padding: Npx; com display: flex; flex-direction: column; gap: Npx; box-sizing: border-box. Use padding para empurrar o conteúdo para dentro — NUNCA use position: absolute; top: Npx em um contêiner de conteúdo. Contêineres de conteúdo com posicionamento absoluto transbordam quando o conteúdo é mais alto que o espaço restante. Reserve position: absolute apenas para elementos decorativos.
  3. Adicione entradas com gsap.from() — anime DE fora da tela/invisível PARA a posição CSS. A posição CSS é a verdade absoluta; o tween descreve a jornada para chegar lá.
  4. Adicione saídas com gsap.to() — anime PARA fora da tela/invisível A PARTIR da posição CSS.

Exemplo

/* scene-content preenche a cena, padding posiciona o conteúdo */
.scene-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 120px 160px;
  gap: 24px;
  box-sizing: border-box;
}
.title {
  font-size: 120px;
}
.subtitle {
  font-size: 42px;
}
/* Contêiner preenche qualquer tamanho de cena (1920x1080, 1080x1920, etc.).
   Padding posiciona o conteúdo. Flex + gap lida com o espaçamento. */

ERRADO — dimensões fixas e posicionamento absoluto:

.scene-content {
  position: absolute;
  top: 200px;
  left: 160px;
  width: 1920px;
  height: 1080px;
  display: flex; /* ... */
}
// Passo 3: Anime PARA essas posições
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
tl.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
tl.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);

// Passo 4: Anime PARA FORA dessas posições
tl.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
tl.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
tl.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);

Quando os elementos compartilham espaço ao longo do tempo

Se o elemento A sai antes do elemento B entrar na mesma área, ambos devem ter posições CSS corretas para seus respectivos quadros herói. A ordenação da timeline garante que eles nunca coexistam visualmente — mas se você pular a etapa de layout, não perceberá o caso em que eles se sobrepõem acidentalmente devido a um erro de tempo.

O que conta como sobreposição intencional

Efeitos em camadas (brilho atrás do texto, elementos de sombra, padrões de fundo) e designs empilhados em z (pilhas de cartões, camadas de profundidade) são intencionais. A etapa de layout serve para detectar sobreposições não intencionais — dois títulos caindo um em cima do outro, uma estatística cobrindo um rótulo, conteúdo vazando para fora do quadro.

Atributos de Dados

Todos os Clipes

AtributoObrigatórioValores
idSimIdentificador único
data-startSimSegundos ou referência de ID do clipe ("el-1", "intro + 2")
data-durationObrigatório para img/div/composiçõesSegundos. Vídeo/áudio assume a duração da mídia.
data-track-indexSimInteiro. Clipes da mesma trilha não podem se sobrepor.
data-media-startNãoDeslocamento de corte na fonte (segundos)
data-volumeNão0-1 (padrão 1)

data-track-index não afeta a camada visual — use CSS z-index.

Clipes de Composição

AtributoObrigatórioValores
data-composition-idSimID único da composição
data-startSimTempo de início (composição raiz: use "0")
data-durationSimTem precedência sobre a duração da timeline GSAP
data-width / data-heightSimDimensões em pixels (1920x1080 ou 1080x1920)
data-composition-srcNãoCaminho para o arquivo HTML externo

Estrutura de Composição

Sub-composições carregadas via data-composition-src usam um wrapper <template>. Composições independentes (o index.html principal) NÃO usam <template> — elas colocam a div data-composition-id diretamente no <body>. Usar <template> em um arquivo independente esconde todo o conteúdo do navegador e quebra a renderização.

Estrutura de sub-composição:

<template id="my-comp-template">
  <div data-composition-id="my-comp" data-width="1920" data-height="1080">
    <!-- conteúdo -->
    <style>
      [data-composition-id="my-comp"] {
        /* estilos escopados */
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
    <script>
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });
      // tweens...
      window.__timelines["my-comp"] = tl;
    </script>
  </div>
</template>

Carregue na raiz: <div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>

Vídeo e Áudio

O vídeo deve ser muted playsinline. O áudio é sempre um elemento <audio> separado:

<video
  id="el-v"
  data-start="0"
  data-duration="30"
  data-track-index="0"
  src="video.mp4"
  muted
  playsinline
></video>
<audio
  id="el-a"
  data-start="0"
  data-duration="30"
  data-track-index="2"
  src="video.mp4"
  data-volume="1"
></audio>

Contrato da Timeline

  • Todas as timelines começam { paused: true } — o player controla a reprodução
  • Registre cada timeline: window.__timelines["<composition-id>"] = tl
  • O framework aninha automaticamente sub-timelines — NÃO as adicione manualmente
  • A duração vem de data-duration, não do comprimento da timeline GSAP
  • Nunca crie tweens vazios para definir a duração

Regras (Não Negociáveis)

Determinístico: Sem Math.random(), Date.now() ou lógica baseada em tempo. Use um PRNG com semente se precisar de valores pseudo-aleatórios (ex.: mulberry32).

GSAP: Anime apenas propriedades visuais (opacity, x, y, scale, rotation, color, backgroundColor, borderRadius, transformações). NÃO anime visibility, display nem chame video.play()/audio.play().

Conflitos de animação: Nunca anime a mesma propriedade no mesmo elemento de múltiplas timelines simultaneamente.

Sem repeat: -1: Timelines com repetição infinita quebram o mecanismo de captura. Calcule a contagem exata de repetições a partir da duração da composição: repeat: Math.ceil(duration / cycleDuration) - 1.

Construção síncrona da timeline: Nunca construa timelines dentro de async/await, setTimeout ou Promises. O mecanismo de captura lê window.__timelines de forma síncrona após o carregamento da página. As fontes são incorporadas pelo compilador, então estão disponíveis imediatamente — não é necessário esperar o carregamento de fontes.

Nunca faça:

  1. Esquecer o registro de window.__timelines
  2. Usar vídeo para áudio — sempre vídeo mudo + <audio> separado
  3. Aninhar vídeo dentro de uma div com tempo — use um wrapper sem tempo
  4. Usar data-layer (use data-track-index) ou data-end (use data-duration)
  5. Animar dimensões do elemento de vídeo — anime uma div wrapper
  6. Chamar play/pause/seek na mídia — o framework controla a reprodução
  7. Criar um contêiner de nível superior sem data-composition-id
  8. Usar repeat: -1 em qualquer timeline ou tween — sempre repetições finitas
  9. Construir timelines de forma assíncrona (dentro de async, setTimeout, Promise)
  10. Usar gsap.set() em elementos de clipe de cenas posteriores — eles não existem no DOM no carregamento da página. Use tl.set(selector, vars, timePosition) dentro da timeline no horário ou após o data-start do clipe.
  11. Usar <br> em texto de conteúdo — quebras de linha forçadas não consideram a largura real da fonte renderizada. Texto que quebra naturalmente + um <br> produz uma quebra extra indesejada, causando sobreposição. Deixe o texto quebrar via max-width. Exceção: títulos curtos de exibição onde cada palavra está deliberadamente em sua própria linha (ex.: "O\nJOGO\nIMORTAL" a 130px).

Transições de Cena (Não Negociáveis)

Toda composição com várias cenas DEVE seguir TODAS essas regras. Violar qualquer uma delas resulta em uma composição quebrada.

  1. SEMPRE use transições entre cenas. Sem cortes secos. Sem exceções.
  2. SEMPRE use animações de entrada em cada cena. Cada elemento anima PARA DENTRO via gsap.from(). Nenhum elemento pode aparecer totalmente formado. Se uma cena tem 5 elementos, ela precisa de 5 tweens de entrada.
  3. NUNCA use animações de saída exceto na cena final. Isso significa: NENHUM gsap.to() que anime opacidade para 0, y para fora da tela, escala para 0, ou qualquer outra animação de "saída" antes de uma transição disparar. A transição É a saída. O conteúdo da cena de saída DEVE estar totalmente visível no momento em que a transição começa.
  4. Apenas na cena final: A última cena pode esmaecer elementos (ex.: fade para preto). Esta é a ÚNICA cena onde gsap.to(..., { opacity: 0 }) é permitido.

ERRADO — animação de saída antes da transição:

// PROIBIDO — isso esvazia a cena antes da transição poder usá-la
tl.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
tl.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// transição dispara em um quadro vazio

CERTO — apenas entrada, transição lida com a saída:

// Animações de entrada da Cena 1
tl.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
tl.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// NENHUM tween de saída — a transição em 7.2s lida com a mudança de cena
// Animações de entrada da Cena 2
tl.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);

Diretrizes de Animação

  • Desloque a primeira animação em 0.1-0.3s (não t=0)
  • Varie as curvas de easing nos tweens de entrada — use pelo menos 3 curvas diferentes por cena
  • Não repita um padrão de entrada dentro de uma cena
  • Evite gradientes lineares em tela cheia em fundos escuros (bandeamento H.264 — use gradientes radiais ou sólidos + brilho localizado)
  • Títulos com 60px+, corpo de texto com 20px+, rótulos de dados com 16px+ para vídeo renderizado
  • font-variant-numeric: tabular-nums em colunas de números

Quando nenhum visual-style.md ou direção de animação for fornecida, siga house-style.md para padrões estéticos.

Tipografia e Ativos

  • Fontes: Basta escrever a font-family desejada no CSS — o compilador incorpora automaticamente as fontes suportadas. Se uma fonte não for suportada, o compilador avisa.
  • Adicione crossorigin="anonymous" a mídia externa
  • Para estouro de texto dinâmico, use window.__hyperframes.fitTextFontSize(text, { maxWidth, fontFamily, fontWeight })
  • Todos os arquivos ficam na raiz do projeto junto com index.html; sub-composições usam ../

Editando Composições Existentes

  • Leia a composição completa primeiro — corresponda às fontes, cores e padrões de animação existentes
  • Altere apenas o que foi solicitado
  • Preserve o tempo de clipes não relacionados

Lista de Verificação de Saída

  • npx hyperframes lint e npx hyperframes validate passam
  • Avisos de contraste resolvidos (veja Verificações de Qualidade abaixo)
  • Coreografia de animação verificada (veja Verificações de Qualidade abaixo)

Verificações de Qualidade

Contraste

hyperframes validate executa uma auditoria de contraste WCAG por padrão. Ela busca 5 timestamps, captura a tela, amostra os pixels de fundo atrás de cada elemento de texto e calcula as taxas de contraste. Falhas aparecem como avisos:

⚠ Avisos de contraste WCAG AA (3):
  · .subtitle "texto secundário" — 2.67:1 (necessário 4.5:1, t=5.3s)

Se aparecerem avisos:

  • Em fundos escuros: clareie a cor com falha até que ultrapasse 4.5:1 (texto normal) ou 3:1 (texto grande, 24px+ ou 19px+ negrito)
  • Em fundos claros: escureça-a
  • Mantenha-se dentro da família da paleta — não invente uma nova cor, ajuste a existente
  • Reexecute hyperframes validate até ficar limpo

Use --no-contrast para pular se estiver iterando rapidamente e verificará depois.

Mapa de Animação

Após criar as animações, execute o mapa de animação para verificar a coreografia:

`

...

Habilidades Relacionadas