Motion design (versão HyperFrames)
Os documentos da HyperFrames ensinam a API; este arquivo cuida do bom gosto. Os números abaixo vêm de um trabalho real que foi ao ar. Use-os como padrões: você pode se desviar deles, mas deve ser intencionalmente, não por descuido.
Adaptado da skill
motion-designde whaleyxbt/claude-motion (MIT, veja o arquivoLICENSEna mesma pasta). A versão original era para Remotion; esta versão foi reescrita para HyperFrames (HTML + GSAP) e inclui regras de tipografia para chinês tradicional. Parágrafos marcados como "(novo nesta versão)" não fazem parte do conteúdo original.
Divisão de trabalho com as skills oficiais da HyperFrames (novo nesta versão)
Esta máquina também tem as skills oficiais da HyperFrames da HeyGen (hyperframes, hyperframes-core, hyperframes-animation). A divisão é a seguinte:
- As skills oficiais cuidam do "como fazer": estrutura do projeto, atributos
data-*, escrita de API, roteamento de fluxo, componentes prontos do registry. Em caso de conflito com este arquivo, prevalece a documentação oficial. - Este arquivo cuida do "bom gosto": easing, ritmo, tempo de espera, fontes, paleta de cores, tipografia em chinês. Ao usar as regras/blueprints da
hyperframes-animationoficial, os números de tempo e easing ainda seguem este arquivo como padrão. - Revisão: sempre use o
review-loop, que já inclui a verificação oficialhyperframes check.
0. Regras rígidas da HyperFrames (novo nesta versão)
Violar estas regras fará com que a tela pisque, desalinhe ou produza resultados diferentes a cada execução:
-
O tempo é definido pelo HTML: cada cena é um elemento com
class="clip", usandodata-startedata-durationna linha do tempo. O elemento raiz deve terdata-composition-ide umdata-durationexplícito. -
A animação é responsabilidade do GSAP:
gsap.timeline({ paused: true }), registrado emwindow.__timelines["<composition-id>"], com a chave igual adata-composition-id. -
Cada tween importante recebe uma posição explícita (terceiro parâmetro); quando ambas as extremidades são importantes, use
fromTo(), pois a saída buscará posições. -
Anime apenas
transformeopacity; não mexa emtop/left/width/heightrepetidamente. -
Proibido: CSS
transition/@keyframes,Date.now(),requestAnimationFrame,setTimeout,Math.random()sem semente, recursos buscados durante a renderização. -
Não use scripts para tocar, pausar ou buscar áudio/vídeo, nem para mostrar ou ocultar clips baseado no tempo. Isso é feito pelos atributos
data. Para mover vídeos, mova o elemento wrapper externo. -
Randomização sempre usa uma função com semente:
function rand(seed) { let t = (seed += 0x6D2B79F5); t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }
1. Tempo centralizado em um só lugar
-
Cada batida é um ponto nomeado no tempo (em segundos), agrupado por cena (
s1,s2…), escrito emtimeline.jsna raiz do projeto:window.TL = { s1: { start: 0, title: 0.3, items: [1.2, 1.45, 1.7], exit: 3.6 }, s2: { start: 3.4, drawOn: 3.5, hook: 5.2, end: 8 }, };Em
index.html, carreguetimeline.jscom<script src="timeline.js"></script>antes de qualquer script de composição. -
Os parâmetros de posição do GSAP devem sempre vir de
TL(comoTL.s1.title,TL.s1.exit + 0.05); não use segundos fixos nas cenas. -
data-start/data-durationna moldura da cena devem corresponder aos limites de cena emTL. Ao recronometrar, primeiro alteretimeline.jse depois sincronize esses dois atributos. -
Efeitos sonoros e narração usam
<audio data-start="…">nas mesmas batidas. O tempo de captura de tela doreview-looptambém vem deTL, portanto, imagem, som e revisão se movem juntos. -
Toda a imagem deve ser determinada apenas pelo tempo, conforme a Seção 0.
2. Easing
As quatro curvas originais são recriadas precisamente no GSAP usando CustomEase. Carregue gsap@3/dist/CustomEase.min.js e registre com gsap.registerPlugin(CustomEase):
CustomEase.create("enter", "0.16,1,0.3,1"); // easeOut
CustomEase.create("exit", "0.6,0,0.9,0.35"); // easeIn
CustomEase.create("move", "0.65,0,0.35,1"); // easeInOut
CustomEase.create("land", "0.55,0,0.2,1.12"); // overshoot
| Curva | Uso | Nome interno mais próximo |
|---|---|---|
enter = bezier(0.16, 1, 0.3, 1) | Entrada, revelação, qualquer "chegada" | expo.out (quase idêntico) |
exit = bezier(0.6, 0, 0.9, 0.35) | Saída: rápida e limpa | Aprox. power3.in |
move = bezier(0.65, 0, 0.35, 1) | Movimento entre dois estados (virar, parar, transformar) | power2.inOut (idêntico) |
land = bezier(0.55, 0, 0.2, 1.12) | Valores que "se fixam" (controle deslizante parando em uma posição) | Não há substituto interno bom; use CustomEase |
ease: "none" (linear) deve ser usado apenas para movimento contínuo: rotação, deriva, partículas, ponteiro de segundos.
Para fazer uma animação seguir outro valor (ex.: legenda acompanhando posição de controle), use um mesmo tween para dirigir um objeto proxy e derive no onUpdate; não lhe dê outro relógio independente.
3. Elasticidade
O original usava molas físicas do Remotion; GSAP não tem física de mola. A tabela abaixo são valores aproximados escolhidos para esta versão (novo, não do original). Após a saída, verifique a sensação com o review-loop:
| Sensação | Configuração GSAP | Uso |
|---|---|---|
| Parada padrão | back.out(1.2), 0.6 s | Entrada de UI geral |
| Pesada, sólida | power3.out, 0.8–1.0 s | Painéis grandes, reversão |
| Botão encaixando | back.out(1.7), 0.35 s | Controles pulando para uma posição |
| Estalo | back.out(2.2), 0.45 s | Rótulos, badges, pontos de sucesso |
| Acento elástico | elastic.out(1, 0.4), 0.9 s | Momento culminante, usado apenas uma vez por vídeo |
Use elasticidade para coisas com sensação física (UI, objetos); para texto e movimentos de câmera, use curvas Bezier.
4. Ritmo
- Escalonamento: palavras em inglês ~0,09 s; caracteres individuais em chinês ~0,04–0,05 s, por palavra em chinês ~0,09 s (parte chinesa é nova nesta versão); itens de lista e rótulos ~0,2–0,25 s; anéis e pontos ~0,06 s.
- Revelação de texto: ~0,8 s, usando máscara: externo
overflow: hidden, internoyPercent: 100 → 0com uma leve rotação (rotation: 3 → 0). - Saída é aproximadamente metade da entrada (0,35–0,55 s vs 0,7–1,25 s), use a curva
exit. - Cenas devem se sobrepor: a próxima cena começa a desenhar antes da anterior sair completamente (ex.:
s2.drawOn4,02 s antes des1.flipEnd4,4 s). Um corte abrupto para espaço vazio parece "carregando". - Digitação: ~0,035 s por caractere; cursor pisca a ~2,4 Hz quando ocioso (use
stepsousetna linha do tempo, não um timer). - Pausa para leitura: cada estado que precisa ser lido deve parar depois de se fixar. Frases curtas: pelo menos 1 s; mais de 3 palavras, adicione ~0,25 s por palavra extra; em chinês, adicione ~0,25 s a cada 4 caracteres extras (novo nesta versão). A frase final: pelo menos 2 s. A versão de 22 segundos do original existe porque os caracteres na versão de 15 segundos passavam rápido demais: quando em dúvida, pause mais e mova menos.
5. Tipografia
- Máximo de três famílias de fontes: serifa para exibição, sans-serif para interface, monoespaçada (para rótulos, prompts, números).
- Inglês (original): Instrument Serif / Inter / JetBrains Mono.
- Chinês tradicional (novo nesta versão): Noto Serif TC / Noto Sans TC, números e rótulos com JetBrains Mono. Coloque os arquivos de fonte em
assets/fonts/do projeto, carregue com@font-face, não dependa de fontes do sistema (diferentes em cada computador).
- Fonte de exibição em inglês: grande (aproximadamente 138 px em uma tela de 1080 px de largura), espaçamento entre letras apertado (
-0.02em),line-height: 1. - Fonte de exibição em chinês (novo nesta versão): aproximadamente 96–120 px para largura 1080 px, máximo de cerca de 12 caracteres por linha, espaçamento entre caracteres
0a0.02em(sem espaçamento negativo para chinês),line-height: 1.15–1.25. - Uma ênfase por linha: em inglês, use uma palavra em itálico com cor de destaque; em chinês, sem itálico verdadeiro, use a cor de destaque e peso forte (novo nesta versão).
- Rótulos monoespaçados: maiúsculos,
letter-spacing: 0.2–0.24em, cor esmaecida. São apenas decoração; informações cruciais para o espectador devem ser grandes. - Teste em celular: em 360 px de largura (tamanho real visto em feeds de redes sociais), a mensagem chave ainda deve ser legível. Verifique com uma contact sheet.
6. Paleta de cores
- (Novo nesta versão) Toda a peça é definida por três cores, como um modelo de slide, determinadas pelo usuário: cor de fundo
bg, cor principalfg(texto e traços), cor de destaqueaccent, escritas emtheme.jsonno projeto, aplicadas pela skillmotion-explainer(ou versão com imagensmotion-explainer-images) usandotheme.py. A cor de destaque é reservada para "resposta, conclusão, números-chave, cartões de capítulo". - Defina a paleta como variáveis CSS no
:root(--bg,--ink,--muted,--accent…); não introduza novos códigos de cor nas cenas. - Apenas uma cor de destaque, e ela tem significado: o item que mudou, a resposta, o vencedor. Se tudo for destaque, nada é destaque.
- Brilho deve ser orientado pelo estado em vez do tempo (
glow = effort); a luz deve contar a história.
7. Textura: nada é completamente estático
- Grão de filme: sobreponha um filtro SVG
feTurbulence, opacidade ~0,09, troque aseeda cada dois quadros (definido comsetna linha do tempo, semente calculada pelo número do quadro). - Vinheta + grade de pontos, derivando alguns px por segundo: vinheta com gradiente radial, grade com um tween linear que atravessa toda a peça.
- "Tremulação de linha" desenhada à mão (
feTurbulence+feDisplacementMap, também trocando semente a cada dois quadros): use para estados de esboço, baixa finalização, desaparece quando a qualidade aumenta. - Elementos ociosos devem respirar: relógio correndo, cursor piscando, rotação lenta.
8. Continuidade e transições
- Prefira a continuidade de objetos a cortes secos. A barra de prompt, faíscas e controles deslizantes do original atravessam cenas e mudam de função: essa é a diferença entre "bem projetado" e "montado". No HyperFrames, objetos que cruzam cenas devem estar na composição raiz, não dentro de uma cena específica.
- Cada transição deve ser conduzida por um objeto na tela (cinco pontos de resultado se fundem em um, que se transforma em um anel de luz). Não use transições de wipe padronizadas.
- Use velocidade: rastro de movimento, compressão derivada da diferença entre o quadro atual e o anterior; não force algo falso.
- Cada vídeo tem um momento culminante (anel de luz + impacto). Construa até ele; não o use cedo demais.
9. Anti-padrões
- Tudo desaparecendo ao mesmo tempo, ou tudo com a mesma duração.
- Usar easing linear para movimentos que começam e param.
- Texto ainda se movendo enquanto deveria estar sendo lido.
- Mais de um foco em um único quadro.
- Conteúdo a menos de aproximadamente 60 px da borda da tela (zona de segurança), a menos que intencionalmente cortado.
- Primeiro quadro em branco ou preto: em redes sociais com reprodução automática sem som, o primeiro quadro é a miniatura.
- (Novo nesta versão) Controlar reprodução de áudio/vídeo ou exibição de clip em scripts, usar animações CSS, usar randomização sem semente; veja a Seção 0.
Fluxo de trabalho
- Primeiro, escreva as batidas em
timeline.js(storyboard com números), confirme o ritmo com o usuário antes de prosseguir. - Use o
hyperframes_initdo kinocut para criar o projeto; cada cena é uma composição emcompositions/, componentes compartilhados e objetos entre cenas vão emindex.html. - Após cada alteração significativa, execute a skill
review-loop. - Depois que o tempo visual estiver travado, processe o áudio: efeitos sonoros e trilha sonora usam
<audio data-start>para alinhar com as batidas deTL. A entonação e emoção da narração em chinês devem ser avaliadas pelo usuário com os ouvidos; não use ASR ou pontuações de similaridade (novo nesta versão).