Communitygithub.com

geoqiao/short-video-skills

Crie vídeos curtos com narração usando código, sem modelos de geração de vídeo. Ideal para vídeos baseados em gráficos, texto, código e dados, como tutoriais, análises de dados e listas.

O que é short-video-skills?

Esta skill permite criar vídeos curtos com narração gerada por código, sem depender de modelos de geração de vídeo tradicionais. É ideal para conteúdos como tutoriais, análises de dados, demonstrações de produtos e listas, onde gráficos, texto e código são os elementos principais. O fluxo de trabalho consiste em desenhar cada quadro em um Canvas controlado pelo tempo, sincronizar a narração com marcações de palavra por palavra usando edge-tts, capturar quadros com Playwright e um Chrome headless, e finalmente compor o vídeo com ffmpeg. A skill também gera capas nos formatos 16:9, 4:3 e 3:4, além de uma folha de contato. Ela é compatível com Node.js, Python (com uv), ffmpeg e Google Chrome, e é projetada para facilitar a criação de novos projetos de vídeo, adição de episódios, alteração de narração ou cenas, e verificação de quadros estáticos para evitar overflow.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/geoqiao/short-video-skills/tree/HEAD/skills/code-video

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

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.

  1. Copie todo o diretório template/ desta skill para um novo diretório de projeto.
  2. Execute npm install no novo diretório (instala apenas playwright-core).
  3. 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 ser null), colors e fonts são as cores e fontes.
  4. 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 em window.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, contendo script.json, shots.js, e os diretórios gerados build/ e out/.

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.

  1. Roteiro: Crie episodes/<número>-<slug>/, escreva script.json, e defina o número do episódio em cover.no.
  2. Cenas: Escreva shots.js no mesmo diretório. O número de cenas deve ser igual ao número de linhas de narração.
  3. Narração: uv run tools/voice.py <slug>. Reexecute se alterar a narração, o tom de voz ou o texto da capa.
  4. Verificação de quadros estáticos: Veja "Verificação de Quadros Estáticos" abaixo.
  5. Vídeo final: node tools/render.mjs <slug>, depois execute covers.sh e sheet.sh, e revise a folha de contato.
  6. 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: lines com 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 (HEAD em tools/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; a tag da 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ós delay segundos e durante dur segundos; 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.segs sã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 em C, fontes em F. Leia as assinaturas das funções em src/lib.js antes de usar. Ferramentas ausentes devem ser escritas no shots.js do episódio, não modifique lib.js e run.js para 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: txt aumenta 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.title para o título; a última cena deve usar E.sign para 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.py está fixado no commit do PR #491; quando uma nova versão oficial for lançada, volte para edge-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.py lida 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.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Habilidades Relacionadas