Communitygithub.com

Reframe

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 HyperFrames HTML. Use quando for solicitado a criar qualquer conteúdo de vídeo baseado em HTML.

O que é Reframe?

Reframe é um framework de produção de vídeo baseado em HTML, projetado para desenvolvedores e criadores de conteúdo que desejam gerar composições de vídeo complexas sem a necessidade de ferramentas de edição tradicionais. A habilidade se concentra em HyperFrames, onde o HTML é a fonte de verdade para o vídeo. Ela permite criar desde composições simples, como cartelas de título e sobreposições, até animações avançadas, incluindo legendas sincronizadas com áudio, narrações geradas por texto-para-fala, e visuais reativos ao ritmo da música (beat sync). O processo é altamente estruturado: antes de escrever qualquer código, o desenvolvedor define a identidade visual (em um `DESIGN.md`), a estrutura, o tempo e o layout. A ferramenta impõe regras rigorosas para garantir que as animações sejam previsíveis (sem `Math.random()`), que a construção da timeline seja síncrona, e que as transições entre cenas sigam um padrão específico, evitando animações de saída antes da transição. Ela suporta plataformas como navegadores e ferramentas de linha de comando (CLI) como init, lint, preview e render. O principal benefício do Reframe é que ele elimina suposições de layout: ao construir o estado final do elemento primeiro (CSS estático de sua posição mais visível), o desenvolvedor pode ver e corrigir problemas de layout antes mesmo de adicionar animação. A habilidade também se integra com uma biblioteca de estilos visuais (`visual-styles.md`) e um guia de estilo de casa (`house-style.md`) para fornecer padrões estéticos.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ilya-makarov-dev/Reframe/tree/HEAD/.claude/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

HTML é a fonte de verdade para vídeo. Uma composição é um arquivo HTML com atributos data-* para 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 os batimentos emocionais.
  2. Estrutura — quantas composições, quais são sub-composições vs inline, quais faixas 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 tempo, adicionar um elemento), vá direto para as regras.

Portão de Identidade Visual

Verifique nesta ordem:

  1. Existe um DESIGN.md no projeto? → Leia-o. Use suas cores, fontes, regras de movimento e restrições "O que NÃO fazer" exatas.
  2. Existe um visual-style.md? → Leia-o. Aplique seus style_prompt_full e campos estruturados. (Nota: visual-style.md é um arquivo específico do projeto. visual-styles.md é a biblioteca de estilos com 8 modelos nomeados — são arquivos diferentes.)
  3. O usuário nomeou um estilo (ex.: "Swiss Pulse", "escuro e tecnológico", "marca de luxo")? → Leia visual-styles.md para os 8 modelos nomeados. Gere um DESIGN.md mínimo com: ## Style Prompt (um parágrafo), ## Cores (3-5 valores hexadecimais com funções), ## Tipografia (1-2 famílias de fontes), ## O que NÃO fazer (3-5 anti-padrões).
  4. Nenhum dos casos acima? → Faça 3 perguntas antes de escrever qualquer HTML:
    • Qual é o clima? (explosivo / cinematográfico / fluido / técnico / caótico / acolhedor)
    • Tela clara ou escura?
    • Alguma cor, fonte ou referência visual específica da marca? Em seguida, gere um DESIGN.md mínimo a partir das respostas.

Toda composição deve rastrear sua paleta e tipografia de volta a um DESIGN.md, visual-style.md ou direção explícita do usuário. Se você está usando #333, #3b82f6 ou Roboto — você pulou esta etapa.

Para padrões de movimento, dimensionamento, padrões de entrada e easing — siga house-style.md. O estilo da casa lida com COMO as coisas se movem. O DESIGN.md lida com a APARÊNCIA das coisas.

Layout Antes da Animação

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

Por que isso importa: Se você posicionar elementos em seu estado inicial animado (fora da tela, escalado para 0, opacidade 0) e animá-los até onde você acha que eles devem chegar, você está adivinhando o layout final. Sobreposições são invisíveis até o vídeo renderizar. 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. Este é o layout que você constrói.
  2. Escreva CSS estático para esse quadro. O contêiner .scene-content DEVE preencher a cena inteira 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 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 lidam com 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 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óis. 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 acidentalmente se sobrepõem 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. O objetivo da etapa de layout é detectar sobreposições não intencionais — dois títulos caindo um em cima do outro, uma estatística cobrindo uma legenda, 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 usa a duração da mídia como padrão.
data-track-indexSimInteiro. Clipes na mesma faixa 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 de 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 arquivo HTML externo

Estrutura da 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 o 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 da 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 com escopo */
      }
    </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>

Carregar 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 estar 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["<id-da-composição>"] = 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: Animar apenas propriedades visuais (opacity, x, y, scale, rotation, color, backgroundColor, borderRadius, transformações). NÃO anime visibility, display, ou 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 há necessidade de esperar pelo 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 um div temporizado — use um wrapper não temporizado
  4. Usar data-layer (use data-track-index) ou data-end (use data-duration)
  5. Animar dimensões do elemento de vídeo — anime um div wrapper
  6. Chamar play/pause/seek em 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 momento ou após o data-start do clipe.
  11. Usar <br> em texto de conteúdo — quebras de linha forçadas não levam em conta 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 em vez disso. Exceção: títulos curtos de exibição onde cada palavra está deliberadamente em sua própria linha (ex.: "O JOGO IMORTAL" em 130px).

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

Toda composição com várias cenas DEVE seguir TODAS estas 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 ENTRANDO 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 ser acionada. 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 que a transição possa 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 é acionada 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);
// SEM tweens 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 os eases entre os tweens de entrada — use pelo menos 3 eases 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 radial ou sólido + brilho localizado)
  • Títulos com 60px+, corpo 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 o font-family que você deseja no CSS — o compilador incorpora automaticamente fontes suportadas. Se uma fonte não for suportada, o compilador avisa.
  • Adicione crossorigin="anonymous" em mídia externa

Habilidades Relacionadas