Morph Edit (motion B-roll)
Você cria clipes de motion graphics para o vídeo de um criador. Cada clipe é uma forma que nunca corta: ela transforma (morph) seu tamanho, cantos e cor de estado a estado enquanto seu conteúdo troca com um breve blur. Um cursor impulsiona as mudanças com cliques e arrastos reais, e cada mudança cai sobre uma palavra falada.
A saída é um conjunto de clipes que o criador insere em seu editor. Você também fornece uma renderização de preview do vídeo com os clipes inseridos, e duas páginas HTML: uma para percorrer os clipes, outra para comparar antes e depois.
Tudo que você precisa está nesta pasta da skill:
engine/: o motor de motion (motion.js), o shell da página (base.css),build.py(clipe → HTML autocontido),render.js(renderização quadro a quadro com motion blur),beats.js(folhas de contato de stills), fontes (Geist, OFL).scripts/:setup.sh,inspect_video.py,words.py,composite.py,make_pages.py.reference/engine-api.md: como escrever um clipe. Leia antes de escrever seu primeiro clipe.examples/opus-aoe2/: seis clipes finalizados para um vídeo real de 54 segundos. Use-os como referência de qualidade e como pontos de partida.
Abaixo, $SKILL significa a pasta desta skill. Trabalhe em uma pasta motion/ dentro do projeto do usuário.
1. Configuração (apenas na primeira execução)
bash $SKILL/scripts/setup.sh ./motion
Isso verifica Node, Python 3 e ffmpeg, e instala Playwright + Chromium em motion/node_modules. Execute cada script do motor com NODE_PATH=./motion/node_modules.
2. Entrevista
Use a ferramenta AskUserQuestion; limite a uma rodada. Você precisa:
- O vídeo. Um caminho. Copie ou referencie como
motion/work/source.*. - A transcrição. Opcional. Se não houver (ou apenas texto simples), transcreva o áudio com
scripts/transcribe.py(veja o passo 3). Isso fornece timestamps reais das palavras, que são mais precisos que estimativas SRT. - Densidade:
- Leve: 2–4 clipes por minuto, apenas nos momentos mais fortes.
- Médio (padrão): 4–7 por minuto.
- Pesado: a maioria das linhas coberta, com pequenos intervalos de rosto.
- Visual:
- A paleta padrão: tela cinza quente, componentes preto e branco, um acento laranja.
- Ou a marca deles: cores e, opcionalmente, uma fonte. Peça para colocarem um logotipo, capturas de tela ou cores da marca em
motion/inputs/, e leia esses arquivos.
- O que evitar ou incluir. Linhas para manter no rosto, números ou nomes reais para mostrar, capturas de tela de produtos para recriar.
Pule qualquer pergunta que o usuário já tenha respondido.
3. Inspecione a filmagem
python3 $SKILL/scripts/inspect_video.py motion/work/source.mp4 motion/work
python3 $SKILL/scripts/words.py transcript.srt > motion/work/words.txt
# sem transcrição (ou você quer timings exatos das palavras): transcreva o áudio
motion/.venv/bin/python $SKILL/scripts/transcribe.py motion/work/source.mp4 motion/work
transcribe.py escreve words.txt e transcript.srt. Mostre a transcrição ao usuário para que ele possa corrigir nomes ou termos ouvidos errados antes do planejamento.
Veja você mesmo motion/work/contact.png. video.json fornece resolução, fps e seções de layout:
- full: o apresentador preenche o quadro.
- pip: o apresentador está em uma caixa e o resto está vazio. Inclui a posição da caixa e um aviso se a caixa mudar de tamanho ou se mover.
Os clipes devem corresponder à resolução e fps do vídeo. Os tempos das palavras de um SRT são estimativas (±0,2s); trate-os como tal.
4. Planeje e obtenha aprovação antes de qualquer código
Mostre uma tabela com uma linha por clipe:
| # | Entrada–Saída | A linha que cobre | O que a forma faz, em quais palavras | Tratamento | Porquê |
Direção criativa: decida quanto do quadro cada clipe ocupa. Esta é a decisão mais importante; tome-a por clipe e dê a razão.
- Corte total para tela cheia. O quadro é todo o apresentador, e a linha descreve algo para ver: um produto, um processo, uma comparação, um número, uma mudança de capítulo.
- Corte pelo tempo da ideia (3–10s), depois devolva o rosto.
- Não corte no primeiro segundo do gancho ou em linhas pessoais, emocionais ou de opinião.
- Deixe pelo menos ~2s de rosto entre os cortes.
- Painel no espaço vazio. A edição já deixa espaço: uma caixa PiP, uma divisão, uma região plana.
- Renderize um clipe transparente (
bg:null) centralizado na área vazia, dimensionado para ficar longe da caixa do apresentador em todos os momentos. - Pode ser longo (15s+) como um morph contínuo, porque o apresentador permanece na tela.
- Se
inspect_video.pyrelatar que a caixa muda, pergunte se isso é intencional, depois dimensione para a maior caixa ou divida o painel na mudança.
- Renderize um clipe transparente (
- Nada. A linha é sobre o apresentador, ou está muito próxima de outro clipe.
Regras de conteúdo:
- Mostre os objetos reais do assunto: a pasta, o terminal, o arquivo, o produto, o resultado. Extraia-os das palavras. Mapeie cada ideia em uma interação do vocabulário em
reference/engine-api.md(pílula + clique, progresso, verificação, ilha de status, cartão com arrasto, controle deslizante, alternância, abas, gráfico + dica de ferramenta, pesquisa/filtro, arrastar e soltar de arquivo, digitação no terminal, comparação lado a lado, cartão de capítulo). - Nunca invente números, citações, preços ou resultados. Use barras relativas, linhas de texto esqueleto ou rótulos retirados da transcrição, e liste o que é ilustrativo. Coloque números reais apenas quando o usuário os fornecer.
- Uma ideia por clipe. Um trecho contínuo (uma seção PiP inteira) pode ser um clipe longo com vários estados.
- Ritmo para a fala, não para a música: uma mudança por batida falada, cerca de 0,4–1,2s de intervalo.
Aguarde o usuário aprovar ou editar o plano.
5. Construa
Escreva um fragmento por clipe em motion/clips/NN-nome.html, seguindo reference/engine-api.md e os exemplos. Depois construa:
python3 $SKILL/engine/build.py motion/dist motion/clips/*.html
Coloque cada mudança de estado em sua palavra: tempo local do clipe = tempo da palavra − ponto de entrada do clipe.
6. Verifique stills nas palavras-chave
NODE_PATH=./motion/node_modules node $SKILL/engine/beats.js motion/dist/NN-nome.html motion/work/NN.png 0.4 1.2 2.1 …
Escolha os tempos em que cada estado se estabilizou e alguns momentos intermediários. Examine cada folha você mesmo. Corrija qualquer coisa apertada, cortada, ilegível ou fora da palavra, ou onde o cursor saia do quadro. Depois verifique mais uma vez. Clipes de painel renderizam em preto na folha para que você possa julgá-los.
7. Renderize
NODE_PATH=./motion/node_modules node $SKILL/engine/render.js motion/dist/NN-nome.html motion/out/NN-nome_0m32s40.mp4 30000/1001
- Use o fps do vídeo.
- Clipes de painel (
bg:null) devem ser escritos como.mov, que fornece ProRes 4444 com alfa. - Nomeie cada arquivo pelo seu ponto de entrada na linha do tempo (
0m32s40= 0:32.40). - A renderização leva 4 subquadros por quadro, portanto é mais lenta que o tempo real. Execute dois clipes em paralelo em uma máquina multi-core.
8. Entregue
Escreva motion/plan.json (esquema em reference/engine-api.md). Para efeitos sonoros de UI, dê a cada clipe uma lista "sfx": [[tempo local do clipe, tipo], …] extraída de suas pistas: click e toggle em cliques do cursor, pickup/drop no início/fim do arrasto, whoosh em morphs de forma, pop na introdução e em badges, rise/fall em barras, type em digitação, tick em itens aparecendo, shutter em capturas de tela e success em verificações. Depois:
python3 $SKILL/scripts/composite.py motion/plan.json motion/out/preview.mp4
python3 $SKILL/scripts/sfx.py motion/plan.json motion/out/preview.mp4 # Efeitos sonoros de UI, se o usuário quiser
python3 $SKILL/scripts/make_pages.py motion/plan.json motion/out/preview.mp4
python3 $SKILL/scripts/make_gallery.py motion/plan.json motion/out/preview.mp4
O usuário recebe, tudo em motion/out/:
- os clipes
TIMING.md: arquivo, entrada, saída, a linha que cobre, o tratamento e o que é ilustrativopreview.mp4: o vídeo deles com os clipes inseridos, cortes secos, áudio original (mais SFX quando usado)sfx/: os efeitos sonoros de cada clipe como um WAV separado, para mixagem no editor delesindex.html: todos os clipes tocando ao mesmo tempo em uma grade, com o preview completo e links para as outras páginas (abra este primeiro)viewer.html: percorra os clipescompare.html: original vs preview, sincronizados, lado a lado, empilhados ou com efeito wipe
Diga claramente que o preview é para revisão: para o corte final, eles colocam os clipes em seu próprio editor, onde podem ajustar o timing, adicionar transições e mixar áudio.
Cartões de inscrição (opcional)
Pergunte ao criador se ele deseja um cartão de inscrição final em sua linha de call-to-action e um ou dois lembretes curtos. Os modelos são fragmentos de clipe em $SKILL/templates/subscribe/ (end-card.html, reminder.html). Copie um para motion/clips/, depois:
- Substitua
__CHANNEL__,__HANDLE__e__AVATAR__(o logotipo ou foto do criador como uma data URI; sem imagem, use uma letra no círculo). Pergunte por estes; nunca adivinhe um nome ou handle. - Reajuste o tempo das constantes no topo do
<script>(IN, os tempos de clique,T) para as próprias palavras do criador. O cartão final clica em Compartilhar, Inscrever-se, Sininho, Curtir e Comentar nas palavras que o criador diz; o lembrete clica em Inscrever-se e Sininho. - Construa, verifique stills, renderize e adicione a
plan.jsoncomo qualquer outro clipe. Renderize o cartão como um.movtransparente para que fique sobre a filmagem.
Legendas (opcional)
Crie um SRT no idioma falado e um SRT em inglês, para upload como legendas ocultas (não queimadas). Trabalhe em motion/work/cap/:
motion/.venv/bin/python $SKILL/scripts/captions/find_gaps.py motion/work/words.txt "<video>": Whisper pode pular trechos inteiros de fala em vídeos longos. Ele imprime as lacunas; retranscreva-as comretx.py "<video>" "<lista de lacunas>" motion/work/gapwords.json [idioma].python3 $SKILL/scripts/captions/make_cues.py motion/work/words.txt motion/work/gapwords.json motion/work/capescreve as pistas e quatro blocos.- Traduza os blocos em paralelo (quatro subagentes, um por bloco) usando
templates/caption_brief.md. Cada um escreveout1..4.jsoncom{"i","orig","en"}para cada pista. - Corrija as pistas sinalizadas, depois
python3 $SKILL/scripts/captions/build_srt.py motion/work/cap motion/out/captionsescrevecaptions_original.srtecaptions_english.srt(duas linhas balanceadas, até 42 caracteres cada). - Diga ao criador para testar o SRT no VLC ou em um upload não listado antes de publicar.
Padrões de estilo
A marca do usuário substitui estes.
- Cor: tela
#E9E7E2, tinta#0B0B0B, componentes brancos, um acento#FF5A1F. Clipes de painel sobre filmagem escura usam formas claras (#F4F2EE). - Tipografia e ícones: Geist para texto de UI, Geist Mono para código, nomes de arquivo e terminais. Um conjunto de ícones com um peso de traço (
M.icon). - Movimento: molas com um pequeno overshoot no máximo. Bordas de entrada e saída usam molas diferentes para que os indicadores estiquem. A câmera amplia para que cada estado preencha o quadro.
- Proibido: easing saltitante, partículas, brilhos, gradientes em cromo de UI, traços de ícones misturados, tempo morto, qualquer coisa que pareça um modelo, dados inventados.
Armadilhas
- Nunca coloque
will-changeem algo que a câmera escala; o texto fica borrado. - A troca de texto dentro de um contêiner em morph precisa de seu próprio tempo de entrada e saída (
M.visdin/lin/lout), ou o texto antigo e o novo se sobrepõem. - Rótulos com
mix-blend-mode: differencedevem estar em uma camada que tenha o próprio modo de mesclagem. Um pai com filtro os isola. - Itens que deslizam sob um destaque precisam de molas
M.FAST, ou a linha de destaque fica vazia por um momento. - Mantenha o cursor dentro do quadro em cada zoom da câmera, inclusive durante morphs.
- Estimativas de palavras de um SRT derivam dentro de uma pista; coloque mudanças importantes na primeira ou última palavra de uma pista quando possível.
- Um clipe termina mantendo seu último estado; o composto mantém o último quadro se seu slot for mais longo.