Faça Vídeos Curtos com Código
A cena é determinada apenas pelo tempo: a página expõe window.render(t), que recebe um número de segundos e desenha a cena daquele momento. O script de renderização usa um Chrome headless para chamar essa função quadro a quadro e capturar as imagens, e o ffmpeg combina as imagens com a narração em um mp4. Mudar a cena é mudar o código e re-renderizar.
Esta abordagem é baseada em um artigo de xilo no X (2026-09-29, https://x.com/xilo2991/status/2104912748794589515). Esta skill adiciona sincronização de narração, capas, verificação de quadros estáticos e um conjunto de regras para escrever scripts e desenhar cenas.
Primeiros Passos
Requer Node 20+, uv, ffmpeg e Google Chrome instalado na máquina. A fonte padrão é a Songti, PingFang e SF Mono do macOS; em outros sistemas, altere em brand.json na seção fonts para fontes disponíveis localmente.
- Copie todo o diretório
template/desta skill para um novo diretório de projeto. - Execute
npm installno novo diretório (instala apenasplaywright-core). - Edite
brand.json:seriesé o nome da série no canto superior esquerdo da capa,handleé a assinatura na capa e nos créditos finais,avataré o caminho relativo da imagem do avatar (pode sernull),colorsefontssão as cores e fontes. - Execute o exemplo:
uv run tools/voice.py demo # Narração, música de fundo, linha do tempo -> episodes/01-demo/build/
node tools/render.mjs demo --stills auto # Gera um quadro estático no final de cada cena
node tools/render.mjs demo # Renderiza o vídeo completo -> episodes/01-demo/out/video.mp4 e cover.png
sh tools/covers.sh demo # Capas 4:3 e 3:4
sh tools/sheet.sh demo # Capa com quadros finais de cada cena em uma folha de contato build/sheet.png
Os comandos usam apenas o slug; o script encontra automaticamente o diretório episodes/<número>-<slug>/. A narração envia o texto do roteiro para o serviço de TTS online da Microsoft.
Estrutura do Projeto
brand.json: Marca. Altere aqui, não no mecanismo.src/lib.js: Ferramentas de desenho, disponíveis emwindow.E.src/run.js: Agendamento da linha do tempo. O quadro 0 é a capa, pausa por 0,3 segundos e então desliza para a primeira cena; as cenas são organizadas horizontalmente, conectadas por deslizamento; legendas e barra de progresso também são desenhadas aqui.src/stage.html: Página de renderização.tools/voice.py: Sintetiza a narração linha por linha, usa timestamps de palavra por palavra para determinar o início de cada frase, sintetiza música de fundo e sons de alerta, e normaliza o volume para -14 LUFS. Se a síntese falhar, tenta novamente; após três falhas, gera um erro.tools/render.mjs: Captura quadros de quatro páginas em paralelo, codifica com ffmpeg, 30 quadros por segundo.tools/covers.sh,tools/cover-vertical.mjs: Capa horizontal 4:3 (capa 16:9 com preenchimento de cor nas bordas superior e inferior) e capa vertical 3:4 com layout separado.tools/sheet.sh: Extrai a capa e o quadro final de cada cena do vídeo finalizado e monta uma folha de contato.episodes/<número>-<slug>/: Um diretório por episódio, contendoscript.json,shots.js, e os diretórios geradosbuild/eout/.
Fluxo de um Episódio
Siga a ordem; não avance para a próxima etapa sem concluir a anterior.
O conteúdo e os fatos são de sua responsabilidade; esta skill começa a partir da escrita do roteiro.
- Roteiro: Crie
episodes/<número>-<slug>/, escrevascript.json, e defina o número do episódio emcover.no. - Cenas: Escreva
shots.jsno mesmo diretório. O número de cenas deve ser igual ao número de linhas de narração. - Narração:
uv run tools/voice.py <slug>. Reexecute se alterar a narração, o tom de voz ou o texto da capa. - Verificação de quadros estáticos: Veja "Verificação de Quadros Estáticos" abaixo.
- Vídeo final:
node tools/render.mjs <slug>, depois executecovers.shesheet.sh, e revise a folha de contato. - Entrega: Veja a última seção deste documento.
Ao ajustar o número do episódio, altere o prefixo do diretório e cover.no juntos, e então reexecute a narração e a renderização. Para alterar apenas o texto da capa, não é necessário regravar a narração: altere cover em script.json, substitua cover em build/timeline.js pelo mesmo conteúdo, e então execute a renderização e covers.sh.
script.json
{
"title": "Este vídeo é desenhado com código",
"cover": { "no": "01", "lines": ["Este vídeo", "é desenhado com código"], "hot": 1, "tag": "Sem software de edição, nem modelo de vídeo" },
"voice": "zh-CN-YunxiNeural",
"rate": "+6%",
"lines": [["Cada quadro que você vê, ", "é desenhado com código."], ["A página expõe apenas uma função: ", "dê a ela um tempo, ", "e ela desenha a cena daquele momento."]]
}
- Uma linha é uma cena, e cada frase dentro de uma linha é um batida visual. Frases podem ser escritas como
[texto falado, texto da legenda]: fala "setenta e cinco por cento", mas exibe "75%"; use também para corrigir a pronúncia de termos em inglês. - Capa:
linescom no máximo duas linhas,hoté a linha que usa a cor principal,tagé um gancho com um número ou conclusão específica,noé o número do episódio com dois dígitos. O título da capa, o título da plataforma e a primeira frase da narração devem dizer a mesma coisa.
Como Escrever o Roteiro
- Para vídeos curtos em formato vertical, 75–90 segundos com 8–9 cenas é o ideal. Velocidade de fala
+6%é cerca de 4,8 caracteres por segundo (incluindo pausas), narração de cerca de 380–430 caracteres (incluindo palavras em inglês). Se ultrapassar, remova caracteres antes de gerar a narração. - Nos primeiros dois segundos, mostre a coisa mais atraente deste episódio. Antes de escrever o roteiro, responda: qual é o ponto realmente cativante deste episódio? Geralmente é um número contraintuitivo, um resultado específico ou um problema que o público está enfrentando. No modelo, a narração começa após 0,5 segundos (
HEADemtools/voice.py), e aos 2 segundos, apenas 8–9 caracteres foram falados. Portanto, a primeira frase deve ser curta, começando com esse ponto; a primeira cena deve mostrar isso em letras grandes antes de 1,2 segundos; atagda capa também deve falar sobre isso. Use a linguagem do público, incluindo palavras-chave ("Não maximize a intensidade de raciocínio", depois "De High para Max, custo 2,9x, pontuação apenas 0,6 a mais"), e então vá para o conteúdo principal. Sem introduções, sem "hoje vamos falar sobre", sem usar frases vagas como "O que é X?", nem usar clichês como "o mesmo A, o mesmo B". Isso é baseado em observações de alguns vídeos, tratado como a ser verificado. - As ordens abaixo podem ser usadas como ponto de partida, ajuste conforme o conteúdo.
- Tutoriais: Resultado final → Um passo por cena → Armadilhas comuns → Conclusão em uma frase.
- Apresentação de produto: Problema que resolve → Duas ou três funcionalidades principais, uma por cena → Como começar → Conclusão em uma frase.
- Explicação de conceitos: Conclusão e números → Prática antiga ou equívoco comum → Onde está o problema → Nova abordagem → Mecanismo específico → Dados oficiais ou testes → Conclusão em uma frase.
- Descoberta de pesquisa: Conclusão e números → Equívoco comum → Como o experimento foi feito → Resultados → Pesquisa subsequente → Causa → Conclusão em uma frase.
- Conclusão: Use uma frase para resumir a conclusão ou dar uma ação, depois use uma pergunta que o público possa responder com base na própria experiência ("Qual configuração você usa?"), para incentivar comentários. A pergunta deve ecoar o comentário fixado. Isso também é tratado como a ser verificado, veja se o número de comentários muda. Não faça uma cena separada para limitações; as condições limitantes dos dados devem ser escritas como notas de rodapé na cena dos dados.
- Não diga "no próximo episódio" ou "no episódio anterior", pois a ordem de publicação pode mudar. Para fazer referência a outros episódios, diga "naquele episódio sobre X".
- Quando o原文 fornecer uma margem de erro, diferenças dentro da margem devem ser tratadas como "quase inalterado". Números calculados por você devem ser listados como evidência fraca na entrega.
- Não inclua URLs na narração, nem diga "vá para o site X" ou "pesquise por Y" (a plataforma considera isso como desvio de tráfego, veja a skill video-publish).
Como Desenhar as Cenas
shots.js é uma função de execução imediata que termina com window.SHOTS = [...]. Cada cena é (c, k) => {}:
cé o contexto 2D de um Canvas 1920×1080.k.at(i, delay, dur)retorna o progresso de easing-out de 0 a 1 para a i-ésima frase, começando apósdelaysegundos e durantedursegundos;k.rawé o progresso linear equivalente;k.té o tempo decorrido dentro da cena,k.dé a duração da linha de narração,k.segssão os segundos de cada frase em relação ao início da cena.- Ferramentas de desenho em
window.E:title(título da cena com traço da marca),txt,measure,rise(fade-in com deslocamento),pop(pop-up),rrect,path(desenha linha poligonal com progresso),arrow,chip(bloco de etiqueta),code(bloco de código com efeito de máquina de escrever),stroke(traço da marca),mark(avatar),sign(créditos finais),fmt, cores emC, fontes emF. Leia as assinaturas das funções emsrc/lib.jsantes de usar. Ferramentas ausentes devem ser escritas noshots.jsdo episódio, não modifiquelib.jserun.jspara uma única cena.
Regras:
- Cada frase deve corresponder a um novo elemento visual na cena, com uma mudança a cada 2–4 segundos. Uma cena deve contar apenas uma coisa, usando gráficos: setas de fluxo, matriz de pontos, barras de comparação, blocos de código, tabelas. Evite texto em tela cheia.
- Alinhamento à esquerda, assimétrico. Evite fundo escuro com texto grande centralizado, não faça fade-in de todos os elementos juntos, sem brilho.
- A cor de destaque principal marca "o número a ser observado nesta tela", não representa bom ou ruim; a cor de destaque secundária deve ser usada no máximo uma ou duas vezes por tela.
- Considere a visualização em modo retrato no celular para definir o tamanho da fonte:
txtaumenta tamanhos menores que 56 (24 se torna 34px, 30 se torna 38px). O valor de entrada para informações deve ser no mínimo 30; notas de rodapé podem ser 24. A largura estimada é baseada no tamanho aumentado; fontes monoespaçadas têm cerca de 0,6 vezes o tamanho da fonte por caractere. - Limites de layout: a barra de legendas está abaixo de y 932, uma linha de cerca de 30 caracteres de largura total; a frase de gancho da capa tem cerca de 14 caracteres de largura total antes de tocar no avatar; a cena tem um zoom lento de 1,025x, elementos próximos às bordas devem ter pelo menos 20px de margem; notas de rodapé com fonte 24 cabem cerca de 48 caracteres de largura total por linha.
- A fonte Songti Black não possui "÷", e "×" aparece como um X grande: use PingFang para operadores ou escreva "dividido por" e "vezes". Em títulos grandes de 200px, letras descendentes do inglês podem pressionar a linha seguinte.
- Quando a primeira frase é muito curta, o início da cena pode ficar vazio: coloque a estrutura do gráfico (eixos, cabeçalhos de tabela, contornos) na primeira frase e os dados nas frases seguintes.
- Ícones que não são baseados em dados medidos são chamados de "diagrama ilustrativo". Números lidos de gráficos originais devem ter nota de rodapé "lido do gráfico original". A parte inferior das cenas de dados deve conter a nota de rodapé da fonte, apenas o nome ("Fonte: Documentação oficial da X"), sem domínios ou URLs.
- Cada cena deve usar
E.titlepara o título; a última cena deve usarE.signpara os créditos.
Verificação de Quadros Estáticos
node tools/render.mjs <slug> --stills auto gera o quadro final de cada cena; --stills 0,t1,t2,... gera quadros em segundos específicos (0 é a capa). Quadros intermediários são capturados cerca de 0,4 segundos após o início de cada linha e cerca de 1 segundo após cada frase, os pontos de tempo são lidos de build/timeline.js do episódio. Cada execução de --stills limpa o lote anterior, portanto, verifique em lotes ou combine os pontos de tempo em um único comando. Para muitas imagens, use ffmpeg para montar uma folha de contato; a capa e os quadros finais devem ser verificados no tamanho original.
Verifique quadro a quadro:
- Se o texto está saindo dos cartões, blocos de código, colunas de tabela, ou sendo bloqueado pela barra de legendas e barra de progresso.
- Se números alinhados à direita estão colidindo com os rótulos à esquerda; se os rótulos dos eixos e os rótulos das curvas estão sobrepostos.
- Se o último quadro da cena contém todas as informações, sem elementos que ainda não entraram.
- Se as duas linhas do título da capa estão muito pequenas, se a frase de gancho está muito larga.
- Se há cenas vazias de 2–3 segundos sem novidades, especialmente no início da cena.
Corrija os problemas encontrados. Se apenas as cenas forem alteradas, reexecute a renderização diretamente.
Limitações Conhecidas
- edge-tts usa uma interface não oficial da Microsoft. A versão 7.2.8 retorna 403 desde outubro de 2026 (rany2/edge-tts #490),
tools/voice.pyestá fixado no commit do PR #491; quando uma nova versão oficial for lançada, volte paraedge-tts==<nova versão>. Se ocorrer 403 novamente, verifique as issues no repositório upstream. - O agente não ouve a narração: a pronúncia de termos em inglês e a velocidade devem ser verificadas por um humano. A verificação de duração em
voice.pylida com interrupções de fluxo durante a síntese. - Sem motion blur, sem edição baseada no ritmo da música.
Informações a Incluir na Entrega
- A narração não foi ouvida por um humano.
- Resultados da verificação de quadros estáticos, incluindo problemas conhecidos restantes.
- Caminhos do vídeo finalizado, das três capas e da folha de contato, e a duração do vídeo.