Edição de motion graphics para Reels
Transforma um vídeo bruto vertical em uma edição final com motion graphics:
setup → analyze → PERGUNTAR: estilo (painel de estilos) + opções de preparação → folha de batida → plan.json
→ verificar + loop de pré-visualização → renderizar sobreposição → compor → verificar → OFERECER: legendas + extras
A sobreposição é HTML/GSAP renderizada quadro a quadro com fundo transparente (assets/engine.html), então a formatação persa, fontes e gradientes são perfeitos em pixels. Você nunca escreve código de animação manualmente: você escreve um plan.json que lista os componentes e seus tempos. O motor os anima no estilo predefinido escolhido, que define a aparência, movimento, transições e paleta de som, e dá a cada componente seus efeitos sonoros padrão.
Fale com o usuário no idioma deles (geralmente persa). Mantenha as atualizações de progresso curtas.
Por que a edição deve parecer "exatamente no lugar" — e não repetitiva
Os espectadores notam quando um gráfico ou som está meio segundo atrasado, ou quando não tem nada a ver com o que está sendo dito. Isso é o que faz uma edição parecer amadora. Edições anteriores foram criticadas exatamente por isso: badges decorativos apareciam sobre o rosto do locutor que não combinavam com o que ele estava dizendo. Depois, o usuário também disse que as edições estavam começando a parecer repetitivas. Quatro ideias resolvem ambos os problemas, e as ferramentas impõem a maioria delas:
- Âncora nas palavras. Qualquer texto que ecoa a fala usa uma âncora de palavra (
"t": "w:رایگان"), para que apareça na sílaba, não perto dela. Segundos digitados manualmente são apenas para eventos puramente visuais. - Âncora na imagem. Cliques, mudanças de página e zooms de layout vêm de eventos
motion.json("t": "m:m12") e das folhas de contato com carimbo de data/hora que você mesmo lê. Um SFX de clique sem um clique visível é ruído. - Proteja o rosto. Declare o retângulo do rosto e do PIP em
plan.avoid.render.js checkentão sinaliza qualquer elemento que os cubra. Corrija todos os avisosCOVERSantes de renderizar. - Deixe o usuário escolher a aparência e varie dentro dela. Pergunte pelo estilo antes de projetar (Passo 2). Depois, não recorra à mesma receita toda vez: varie o formato do gancho, quais componentes carregam as ideias e as transições.
references/styles.mdtem o manual por estilo e uma lista de formatos de gancho.
Passo 0 — configuração (primeira execução em uma máquina)
python <skill>/scripts/setup.py
Instala faster-whisper, puppeteer-core e gsap em ~/.cache/reel-motion-edit/, sintetiza a biblioteca SFX e baixa o modelo Whisper (large-v3-turbo, ~1,6 GB; ele retoma e usa hf-mirror.com como fallback se huggingface.co estiver bloqueado ou cair). Esta é a etapa "baixar o que precisa", então faça sem perguntar. Diga ao usuário em uma linha o que está baixando. Execute em segundo plano: o modelo pode demorar em conexões lentas. Enquanto isso, você pode fazer a análise visual com analyze.py --no-transcript e depois executá-lo novamente para a transcrição. Execute scripts/sfx.py ~/.cache/reel-motion-edit/sfx novamente após atualizar a skill para que os novos sons de estilo existam.
Se você encontrar um ativo útil extra (uma fonte, um conjunto de ícones, um SFX ou faixa de música livre de royalties), baixe-o no diretório de trabalho. Anote sua licença em <workdir>/CREDITS.txt. Prefira fontes OFL/CC0 (Google Fonts, Pixabay/Freesound CC0). Fontes incluídas: Vazirmatn (corpo), Lalezar (display), Changa (tech), Lemonada (divertida), Noto Kufi Arabic (formal). Fontes que o usuário instalou localmente (por exemplo, Morabba, IRANSansX, Yekan Bakh) podem ser adicionadas via plan.fonts e são frequentemente a escolha mais alinhada à marca. Procure em %LOCALAPPDATA%\Microsoft\Windows\Fonts e C:\Windows\Fonts.
Kit de marca. Se ~/.config/reel-motion-edit/brand.json existir, render.js o aplica automaticamente: style, theme (cores da marca), fonts, handle (@username marca d'água), handleCorner, logo. O plano o substitui; "brand": false o ignora para um vídeo. Quando o usuário informar uma preferência duradoura (seu handle, um estilo que sempre deseja, cores da marca), ofereça-se para salvá-lo lá.
Passo 1 — analisar
Crie um diretório de trabalho ao lado do vídeo (<video dir>/<video name>_edit/) e execute:
python <skill>/scripts/analyze.py "<video>" "<workdir>" --lang fa
Em seguida, leia analysis/transcript.txt e cada analysis/sheets/sheet_*.jpg (10 s cada, 0,5 s por célula, com carimbo de data/hora). Os eventos de movimento impressos pelo script (m0 … mN, cut/change) são candidatos. Confirme cada um com as folhas, porque uma rolagem também aparece como "change".
O Whisper às vezes escreve errado nomes de produtos em persa ou inglês. Anote as correções (elas importam para legendas e para âncoras de palavra: ancore em como o Whisper escreveu a palavra).
Passo 2 — pergunte ao usuário: estilo + opções de preparação (antes de projetar qualquer coisa)
Vídeos e públicos diferentes querem aparências diferentes, e o usuário quer escolher. Monte um painel de estilos: um quadro representativo do seu vídeo renderizado em todos os 7 estilos predefinidos, com um título, chip de etapa, adesivo e linha de legenda. Escreva um plano mínimo primeiro (vídeo + um título + uma palavra-chave + etapas se o vídeo tiver etapas), depois execute:
node <skill>/scripts/render.js "<workdir>/plan.json" styleboard <T> # → build/styleboard.jpg
Escolha T onde o quadro seja típico (não uma transição). Envie a imagem para o usuário (SendUserFile, exibir render), depois pergunte com AskUserQuestion. Pule a pergunta de estilo se o kit de marca já tiver um style, a menos que o usuário peça algo diferente.
- P1 — estilo (máximo de 4 opções: recomende o mais adequado para este conteúdo primeiro, com uma justificativa de uma linha, mais três alternativas contrastantes; diga que os outros podem ser digitados via "Outro"). Estilos predefinidos:
gradientgradiente moderno,boldpop/Hormozi,neontech/cyber,minimallimpo como Apple,doodledesenhado à mão,retroVHS,newstelejornal. As descrições estão emassets/styles.json(label,feel). - P2 — opções de preparação (multiSelect), apenas as que se aplicam:
- Cortar pausas (jump cuts):
tighten.pyremove silêncios maiores que ~0,45 s. Melhor para vídeos de fala. Em gravações de tela, avise que trechos silenciosos podem ser onde ocorrem os cliques. Isso altera a linha do tempo, então é executado antes da análise: execute a análise novamente no arquivo apertado. - Limpeza de voz:
"voice": "enhance"(remoção de ruído, corte de graves, presença, compressão suave). Recomende para áudio de telefone ou ambiente. - Marca d'água @handle: pergunte pelo handle se o kit de marca não tiver um.
- Música de fundo: apenas se o usuário tiver uma faixa ou quiser que você encontre uma CC0. Ela é abaixada automaticamente sob a voz.
- Cortar pausas (jump cuts):
Se o usuário só quiser a edição e não se importar, escolha por ele, diga qual estilo você escolheu e por que, e vá em frente.
Passo 3 — folha de batida (pense antes de projetar)
Escreva <workdir>/beats.md>: uma linha por batida com intervalo de tempo, o que é dito, o que é mostrado e o layout (rosto completo / tela + PIP canto inferior esquerdo / tela portátil / …). Marque:
- o gancho (primeiros 1–3 s): escolha um formato de gancho de
references/styles.md, um diferente da última vez se você souber - cada etapa / ideia que o locutor explica
- o momento de recompensa (resultado mostrado: "conectado", "pronto", o número)
- o CTA no final
- mudanças de layout (zoom entre câmera e tela): pontos de transição
- as zonas seguras por layout: onde as sobreposições podem ficar sem esconder o rosto, o cursor ou a coisa que está sendo demonstrada
Leia references/styles.md (o manual do estilo escolhido) e references/creative-direction.md (ritmo, posicionamento, regras SFX). Eles são curtos e são a diferença entre "poluído" e "profissional".
Passo 4 — plan.json
Escreva <workdir>/plan.json. Todos os componentes, suas propriedades e SFX padrão estão em references/components.md. Leia antes de escrever o plano. Forma mínima:
{
"video": "D:/videos/vpn firefox.mp4",
"size": [1080, 1920], "fps": 30,
"style": "neon",
"voice": "enhance",
"handle": {"text": "@seu_handle", "corner": "tl"},
"avoid": [{"name": "face", "from": 0, "to": 14.6, "rect": [200, 420, 680, 900]},
{"name": "pip", "from": 15, "to": 29.1, "rect": [0, 1300, 510, 620]}],
"elements": [
{"type": "title", "t": 0, "d": 3.8, "y": 90, "kicker": "آموزش ۶۰ ثانیهای", "lines": ["`VPN` *رایگان*"], "sub": "با سرورهای فایرفاکس"},
{"type": "transition", "t": "m:m3-0.1"},
{"type": "steps", "items": [{"t": "w:گوگل", "label": "جستجو در گوگل", "sub": "`vpn firefox github`"}], "hide": [[29.0, 34.1]]},
{"type": "keyword", "t": "w:رایگان", "x": 540, "y": 1640, "text": "رایگان", "emoji": "🎁"},
{"type": "success", "t": "w:وصل", "x": 405, "y": 678, "title": "وصل شدی!"},
{"type": "cta", "t": 57.4, "items": [{"text": "سیو کن", "icon": "save"}, {"text": "فالو کن", "icon": "follow"}]}
],
"camera": [{"t": "w:رایگان", "d": 1.2, "type": "punch", "scale": 1.12, "cx": 540, "cy": 700}],
"sfx": [{"t": 16.2, "name": "typing", "db": -8}],
"cover": {"lines": ["`VPN` *رایگان*"], "sub": "آموزش ۶۰ ثانیهای"}
}
Deixe o estilo decidir a aparência. Deixe as propriedades visuais (theme cores, style/rotate/from da palavra-chave, transition kind, anim do título, estilo da legenda) não definidas, a menos que você tenha um motivo semântico (vermelho para um erro, uma cor da marca). O predefinido as preenche, e é isso que faz os estilos parecerem diferentes. Uma transição sem kind percorre as transições do estilo. theme no plano apenas substitui o predefinido (por exemplo, a cor da marca do produto).
Sintaxe de texto: *palavra* ou *duas palavras* = destaque, `latim` = execução LTR isolada (mantém "VPN"/URLs de inverterem dentro do texto RTL).
Passo 5 — verificar, pré-visualizar, corrigir (loop)
node <skill>/scripts/render.js "<workdir>/plan.json" check
node <skill>/scripts/render.js "<workdir>/plan.json" preview 1 5.5 15.8 21.1 27.4 54
check imprime a linha do tempo resolvida e verifica:
COVERS: um elemento sobre uma zona protegidaOFFFRAMECLUTTER: mais de 3 sobreposições ao mesmo tempoSFXPILE: sons empilhados dentro de 0,35 sORDER: uma âncora de palavra atingiu uma ocorrência anterior, então usew:palavra#2
Corrija todos os problemas. Em seguida, olhe para build/preview.jpg: escolha tempos no meio da animação para cada elemento importante e verifique se as chamadas e ondulações estão exatamente sobre seus alvos. Leia as coordenadas dos quadros em resolução total (ffmpeg -ss T -i video -frames:v 1 f.png) em vez de adivinhar a partir de miniaturas. Itere até que esteja correto. Pré-visualizações são baratas, renderizações completas não são.
Passo 6 — renderizar e compor
node <skill>/scripts/render.js "<workdir>/plan.json" full # build/overlay.mov (≈3–6 min / minuto de vídeo)
python <skill>/scripts/compose.py "<workdir>/plan.json" --out "<video dir>/<name> - edit.mp4"
node <skill>/scripts/render.js "<workdir>/plan.json" cover <T> # build/cover.jpg — capa do post (quadro T desfocado + título)
Execute a renderização completa em segundo plano. compose.py faz o seguinte:
- aplica os movimentos de câmera apenas ao vídeo
- sobrepõe os gráficos
- aplica a limpeza de
voicese definido - mixa a base SFX sob a voz, mais música com redução automática se definido:
"music": {"file": "...", "db": -20} - normaliza para −14 LUFS
Nunca sobrescreva o vídeo de origem. Escreva um novo arquivo, com um sufixo de versão (- edit v2) em re-renderizações.
Passo 7 — verificar
Faça uma folha de contato da saída (ffmpeg -i out.mp4 -vf "fps=1/2,scale=216:-1,tile=10x3" sheet.jpg) e olhe para ela. Verifique se a duração corresponde e se o áudio está presente. Relate honestamente o que você verificou (quadros) e o que não pôde (você não pode ouvir; o tempo do SFX é verificado em relação à lista de eventos, não pelo ouvido).
Passo 8 — oferecer legendas e extras (sempre, no final)
Assim que a edição for entregue, pergunte com AskUserQuestion (multiSelect onde couber). Ofereça apenas o que ainda não foi feito:
- Legendas: 3–4 estilos de
references/caption-styles.md, com o padrão do estilo escolhido (captionsem styles.json) recomendado primeiro e a justificativa com base neste vídeo. - Imagem de capa para o post (
render.js cover). - Texto da legenda do Instagram: escreva
<workdir>/post.txta partir da transcrição: uma linha de gancho, 2–4 linhas curtas de valor, o CTA, o link ou palavra-chave de comentário que o locutor mencionou e 8–15 hashtags relevantes em persa + inglês. - Salvar no kit de marca: o estilo, handle e cores escolhidos, para que o próximo vídeo comece a partir daí.
- Outra versão de estilo: re-renderize o mesmo plano com um
stylediferente para teste A/B (apenas a sobreposição muda).
Para legendas:
python <skill>/scripts/captions.py "<workdir>" --style karaoke --zones "0-14.6:1400,29.4-33.8:1400" --default-y 1170 --keywords "رایگان,VPN" --fix "غلط=درست,وی پی این=VPN"
Revise os trechos impressos. Corrija grafias do Whisper com --fix; uma fonte de várias palavras mescla tokens. Adicione "captions": {"file": "captions.json"} ao plano (o estilo assume o padrão do predefinido; defina "style" para substituir), execute check (as legendas também não devem cobrir o rosto ou os adesivos), depois renderize e componha novamente como uma nova versão.
Armadilhas
- Elementos em coordenadas de tela (clique, destaque, setas de chamada) desalinharão se um movimento de câmera ampliar a mesma seção. Use movimentos de câmera apenas em seções de fala.
- Zooms animados estilo Camtasia entre rosto e tela duram ~0,5 s. Coloque o elemento de transição no início do zoom e não coloque texto na tela nessa janela.
steps.hideesconde o chip de etapa durante seções de rosto inteiro e o traz de volta depois.- Os carimbos de data/hora das palavras do Whisper podem estar ~0,1 s atrasados na primeira palavra após uma pausa. Para golpes fortes (título), ajuste com
-0.05. - Fontes que não são 1080×1920 (por exemplo, exportações de telefone 608×1080) são upscaled/cortadas para o tamanho do plano por compose e preview. As coordenadas do plano são sempre em pixels do tamanho do plano, então multiplique as coordenadas lidas dos quadros de origem por
1080 / source_width. - Filmagens portáteis de telefone de um monitor: a tela se move, então elementos fixados na tela (clique, destaque, setas) não permanecerão no alvo. Use estrutura (etapas), adesivos ancorados em palavras nas margens e transições de quadro inteiro.
- Títulos recebem um escurecimento superior escuro por padrão (
"scrim": falsepara removê-lo). Isso os mantém legíveis sobre telas claras. - Mantenha a voz do locutor intocada (sem EQ/compressão além da normalização de volume) a menos que
"voice": "enhance"seja definido. - A renderização completa é cara (3–6 min por minuto de vídeo). Pré-visualize primeiro. Use
render.js previewpara gerar quadros-chave. Você pode também pular para um ponto específico com--time. - O Whisper muitas vezes escreve errado o nome da skill. Não corrija a menos que quebre as âncoras de palavra. Se quebrar, use o alias
skills.py. - Se o usuário disser para "não usar esta skill", interrompa e use uma abordagem diferente.
Ferramentas e dependências
- Python 3.10+:
analyze.py,tighten.py,compose.py,captions.py,setup.py,sfx.py - Node.js 18+:
render.js,cover.js,styleboard.js - ffmpeg (no PATH)
- ffprobe (no PATH)
Estrutura do projeto
<skill>/
├── scripts/
│ ├── setup.py Instala dependências (uma vez)
│ ├── analyze.py Transcrição + detecção de movimento + folhas de contato
│ ├── tighten.py Corte de pausas
│ ├── render.js Motor de renderização de sobreposição
│ ├── compose.py Composição final + mixagem de áudio
│ ├── captions.py Geração de legendas estilizadas
│ ├── sfx.py Síntese de sons
│ └── cover.js Geração de imagem de capa
├── assets/
│ ├── engine.html Motor HTML/GSAP com fundo transparente
│ ├── styles.json Definições de estilo (cores, animações, transições)
│ ├── fonts/ Fontes persas incluídas
│ └── sfx/ Biblioteca de efeitos sonoros
├── references/
│ ├── styles.md Manual de estilo
│ ├── components.md Catálogo de componentes do plano
│ ├── caption-styles.md Estilos de legenda
│ └── creative-direction.md Direção criativa
└── SKILL.md Este arquivo
Licença
Apache 2.0 (veja LICENSE). Os ativos incluídos (fontes, sons) possuem suas próprias licenças listadas em CREDITS.txt.