Communitygithub.com

thativanng/reels-maker

Crie e renderize filmes, reels ou animações como código. Uma página HTML desenha qualquer quadro sob demanda com window.seek(t) e um navegador headless renderiza cada quadro em 2x em um MP4 com som.

O que é reels-maker?

O reels-maker transforma uma única página HTML em um mecanismo determinístico de produção de vídeo. A página deve expor uma função window.seek(t) que, para qualquer instante t, desenha exatamente o quadro correspondente — sem depender de relógios reais. Um renderizador headless percorre t a 30 FPS, captura cada quadro em 2x e o envia ao ffmpeg para montagem do MP4 final. O processo é dividido em etapas bem definidas: storyboard, construção de faixa-teste, construção completa, auditoria (collision check + sondas de pixel), renderização, geração de áudio (com normalização −14 LUFS) e mixagem final. O sistema é independente de estilo, suporta formatos 9:16, 4:5, 1:1 e 16:9, e é voltado para desenvolvedores que desejam criar vídeos com código em vez de geradores baseados em IA. A skill também fornece ferramentas CLI (render.mjs, cover.mjs, stills.mjs, sheet.py, mux.sh) e um template starter que pode ser estendido por pacotes de estilo como voxel-walk. É indicado sempre que alguém pedir "faça um filme/reel/animação explicativa/vídeo de carreira", "renderize isso em MP4", "transforme esta página em vídeo", ou precisar das etapas finais (sinais de áudio, loudness, codificação segura de cores, pré-visualização para celular).

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/thativanng/reels-maker/tree/HEAD/skills/film-engine

Perguntar na sua IA favorita

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

Documentação

film-engine: filmes desenhados a partir de código, um quadro de cada vez

Onde o kit vive: execute cada comando desta skill a partir da pasta reels-maker (o clone de github.com/thativanng/reels-maker que contém template/ e tools/). Se o projeto não tiver nenhuma, configure-o primeiro seguindo o SETUP.md desse repositório.

A ideia em um parágrafo

Um filme aqui é uma única página HTML com uma regra: window.seek(t) deve desenhar exatamente o quadro para o instante t, sempre, a partir apenas de t. Nada na imagem pode ler um relógio real. Um renderizador então avança t a 30 FPS, captura cada quadro em 2x e o envia para o ffmpeg. Como a página é determinística, uma re-renderização corresponde (em média, dentro de uma fração de nível; ruído de GPU pode mover pixels individuais em até cerca de 60 níveis), um still em 17,3 s é o quadro que o vídeo mostrará, e cada verificação (film-audit) pode examinar qualquer momento sem reproduzir o filme.

A rota (não pule uma estação)

  1. Brief e look primeiro. reel-intake termina em um brief assinado e storyboard (formato, duração, som, o que nunca aparece); reel-style termina em um look escolhido. Não abra as etapas de construção desta skill sem ambos.
  2. Storyboard. reel-intake o escreve (tempo · palavras na tela · som e legenda · porquê; references/brief.md), e a pessoa o assina antes de você construir. Um estilo com banner adiciona uma coluna de banner.
  3. Test strip. Construa cerca dos primeiros 10 s no look escolhido (um filme em estilo walk pode precisar de 15–30 s para mostrar um capítulo), tire stills, obtenha um sim. Uma construção completa em um look não assinado é trabalho desperdiçado.
  4. Construa o filme completo (o pacote de estilo diz como construir cenas).
  5. Gates (film-audit): a verificação de colisão a 40 FPS, as sondas de pixel, depois um auditor independente. Nada vai para a pessoa antes disso.
  6. Renderize: node tools/render.mjs --page reels/<name>/page.html --out reels/<name>/out/film-silent.mp4 (quadros 2x, redimensionados com lanczos, sem tags de cor).
  7. Áudio: python3 template/audio.py out/film.wav (uma lista de cues no mesmo relógio do filme).
  8. Finalize: zsh tools/mux.sh out/film-silent.mp4 out/film.wav out/film.mp4. Isso resulta em −14 LUFS, um limitador, um arquivo H.264 sem tags e uma pré-visualização para celular no mesmo formato do filme (lado curto 720 px).
  9. Capa: node tools/cover.mjs --page reels/<name>/page.html --out reels/<name>/out/cover.jpg. Uma página com modo de capa (o ?cover do starter, a partir da config cover) desenha o still projetado; qualquer outra página fornece o quadro em T=. É salvo no formato do próprio filme e mantido abaixo de 2 MB, mais o recorte central 3:4 para um filme 9:16 (a grade do Instagram, relatada). O LinkedIn aceita uma capa apenas no momento da publicação: depois disso, apenas o texto de uma postagem pode ser editado (LinkedIn Help, "Edit a shared post", https://www.linkedin.com/help/linkedin/answer/a522811). Sua especificação de miniatura, JPG ou PNG no formato do vídeo e no máximo 2 MB, vem da ajuda do LinkedIn conforme citado por um resumo de busca; a página em si não carregaria, então trate como não verificado.
  10. Envie a pré-visualização para celular primeiro, depois o arquivo completo e a capa.

O contrato da página

  • window.seek(T): desenha o quadro T. É o único lugar que anima qualquer coisa.
  • window.ready: uma promise que resolve após fontes, texturas e o primeiro quadro.
  • window.DUR: a duração do filme em segundos.
  • window.FILM = { w, h, format, safe }: o tamanho do quadro e a zona de segurança em pixels. Todas as ferramentas dimensionam sua janela a partir disso, então a página possui seu próprio formato.
  • Opcional: window.cover() desenha a capa em vez de um quadro, e FILM.coverAt nomeia o momento em que ela se encontra (tools/cover.mjs usa ambos; sem eles, pega o quadro em T=).
  • window.collide(T) e window._dbg: hooks para film-audit (veja essa skill).
  • As ferramentas servem a pasta do kit via http por conta própria (módulos ES não carregam de file://). Para assistir a uma página ao vivo em um navegador, npm run serve e abra http://127.0.0.1:8765/template/starter.html.

Formatos, o starter e outros idiomas

  • template/formats.json contém os quatro tamanhos (9:16 1080×1920 · 4:5 1080×1350 · 1:1 1080×1080 · 16:9 1920×1080), o mapeamento plataforma → formato e a zona de segurança de cada plataforma com sua fonte. A linha de formato do brief escolhe a partir dele.
  • Cada reel vive em sua própria pasta, reels/<name>/ (gitignorada): seu brief, storyboard, page.html (uma cópia do starter ou de film.html), seu reel.json ou career.json e seu out/. As páginas carregam fontes e formats.json da raiz do kit, então uma cópia funciona a partir dali. Aponte as ferramentas para ela: PAGE=reels/<name>/page.html.
  • template/starter.html + template/reel.json é o esqueleto para todo look, exceto o voxel walk. Suas palavras e tempos vivem na config, ele se dimensiona a partir de ?fmt= ou da config e mantém cada palavra dentro do núcleo de segurança da plataforma. ?guides mostra as zonas cobertas em vermelho, apenas para verificação; nunca renderize com isso ligado. É um esqueleto, não um look: reel-style reescreve seus tokens e layout.
  • template/film.html (o template voxel) é apenas 4:5, e opta por não usar zonas de segurança (safe é 0): seu banner e legendas ficam perto das bordas por design, então a sonda safe sempre passa lá e o olho do auditor é a verificação. Suas câmeras são configuradas para 4:5; outra proporção significa reconfigurá-las e reexecutar cada gate.
  • Chinês, Japonês, Coreano: o starter carrega Noto Sans TC do Google Fonts no momento da renderização (apenas os caracteres que a config usa) e executa tipo CJK em aproximadamente 0,72× o tamanho latino (seus caracteres têm largura total de em). Escreva \n onde uma linha deve quebrar: o chinês quebra entre quaisquer dois caracteres, então uma linha longa precisa de uma quebra escolhida por você. template/reel.zh.json é um exemplo prático. Qualquer outro script precisa de sua própria fonte na pilha.

Relógios e temporização

  • Um relógio de filme dirige as cenas, a câmera, o banner, as legendas e o som. Quando você insere um beat mais tarde sem re-temporizar tudo, use um remapeamento: o relógio da cena pausa no ponto de inserção enquanto as sobreposições mantêm o relógio real:
    const INS = [[24.0, 5.0, 'detail']];   // no tempo da cena 24.0, toque um beat inserido de 5 s
    function remap(T) { let sh = 0; for (const [a, len, id] of INS) { if (T < a + sh) return { t: T - sh, ins: null }; if (T < a + sh + len) return { t: a, ins: id, u: T - sh - a, len }; sh += len; } return { t: T - sh, ins: null }; }
    
    O script de áudio precisa da mesma tabela: escreva um RT(t) que adiciona as durações inseridas a um tempo de cena e coloque cada cue em RT(t), ou cada cue após a inserção deriva. (O template não tem inserções, então seu audio.py não precisa de uma.)
  • Easing: eio para movimentos de câmera, eo para coisas chegando, trap (velocidade trapezoidal) para caminhar e dirigir, para que um movente não "estraga" nas extremidades.
  • Chaves de câmera são absolutas A(pos, target) ou seguem F(offset, targetOffset) a partir do ponto de solo do herói. Misture entre chaves com eio. Segure em um beat que importa; um plano que se move o tempo todo soa como nervoso.

As sobreposições (no DOM, acima do canvas)

  • Banner: ano, depois empresa, depois a pílula de cargo, mais uma linha do tempo cujo ponto respira no ano atual. O banner muda quando a nova cena ESTÁ NA TELA (seu conjunto subiu, a roupa mudou, o herói chegou), nunca quando o código começa a construí-la. Verifique isso em uma folha de quadros a ±1 s em torno de cada mudança.
  • Legendas: uma linha de história por beat, com a frase-chave em negrito e acento. Use text-wrap: balance. Dê a um leitor cerca de 3 palavras por segundo e esmaeça uma legenda antes de um movimento rápido de câmera descobrir o assunto atrás dela.
  • Um balão de fala que segue um personagem: projete o ponto da cabeça e prenda o balão ≥24 px dentro do quadro.
  • Cartão final: nome, uma tagline, no que são bons, uma citação. A cena desfoca atrás dele.

Áudio

  • As cues são escritas no relógio do filme, próximas ao momento a que pertencem (passos por perna de caminhada, um sino quando algo aparece, um baque quando pousa).
  • Sem sons de whoosh em transições; soam como baratos. Use sinos, tiques e impactos suaves.
  • A base padrão em template/audio.py é gerada a partir de ondas senoidais, então é gratuita para uso em qualquer lugar. Se alguém trouxer uma faixa gerada por IA, verifique sua licença: alguns pesos de modelos só permitem uso não comercial.
  • Loudness: two-pass loudnorm para −14 LUFS (meça, depois aplique linearmente), depois um limitador. Uma passagem ultrapassa.

Fatos de renderização que nos custaram dias (mais em references/gotchas.md)

  • Renderize em 2x e reduza a escala. EffectComposer remove o anti-aliasing do canvas, então uma renderização 1x tem bordas irregulares em todos os lugares.
  • Sem tags de cor no MP4. Um pipe JPEG o marca como full-range, e alguns players então deslocam as cores. setparams=...=unknown no filtro.
  • Dois rostos no mesmo plano piscam (z-fighting). Dê ao da frente um deslocamento de profundidade.
  • Fontes devem ser carregadas (document.fonts.load) antes que qualquer texto do canvas seja desenhado, ou ele cai silenciosamente no fallback.
  • GPU ligada no Chromium headless (--use-angle=metal no macOS). Sem ela, uma renderização é cerca de 10x mais lenta.

Trabalhando sem um prompt a cada passo

A pessoa disse sim às regras de permissão do kit uma vez (SETUP.md passo 4); fique dentro delas, ou elas serão perguntadas repetidamente:

  • Escreva e altere arquivos com as ferramentas Write e Edit: páginas, reel.json, brief, storyboard, AUDIT.md. Não os gere com um script Python ou shell, um heredoc ou sed -i; cada um desses é um prompt de aprovação.
  • Meça com as ferramentas do kit (stills, probe, sheet, collide, render, cover), não com trechos avulsos de python3 -c.
  • Sem necessidade de mkdir, loops ou cadeias: toda ferramenta cria sua própria pasta de saída e aceita uma lista de tempos em uma única chamada (stills.mjs … 1.5,6,12).
  • Os scripts próprios de um reel (seu script de som, um helper) vivem em reels/<name>/ e executam como python3 reels/<name>/audio.py ou node reels/<name>/x.mjs, o que as regras cobrem.

Comandos

Execute cada ferramenta como um único comando simples (flags, sem VAR=… inicial, sem loops, sem cadeias &&). Assim, as regras de permissão da pessoa (node tools/*) o cobrem e eles não são solicitados a aprovar cada etapa. As variáveis de ambiente ainda funcionam para scripts.

npm run doctor                                  # verifica esta máquina primeiro
npm run demo                                    # a prova de 12 segundos: out/demo/
node tools/stills.mjs "2,8.5,15"                # stills 2x → out/stills (o template voxel)
node tools/stills.mjs --page template/starter.html --format 16:9 1.6        # o starter em outra proporção
node tools/stills.mjs --page template/starter.html --cfg reel.zh.json 1.6   # outra config (aqui: chinês)
node tools/stills.mjs --dsf 1 --out out/chk 2,8.5                           # quadros 1x rápidos para uma folha
python3 tools/sheet.py out/chk/sheet.jpg 6 300 out/chk/t*.jpg
node tools/render.mjs --page reels/<name>/page.html --out reels/<name>/out/film-silent.mp4
python3 template/audio.py out/film.wav
zsh tools/mux.sh out/film-silent.mp4 out/film.wav out/film.mp4

Individual skills in this repo

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

thativanng/reels-maker

The gates every code-rendered film passes before anyone sees it. A 40 fps collision pass (no mover touches a solid or another mover), pixel probes (nothing sits over or behind a face, a head, a subtitle or the frame edge), then an independent auditor (a fresh agent) who reads frame sheets at ≥2 fps and signs off. The builder never signs off their own film. Use it before sending ANY render, after every fix round, and whenever someone says "check the film", "audit this", "is it ready", or "why does this frame look wrong".

thativanng/reels-maker

The interview before any video is built. It reads what the person already gave (source text, CV, links, brand files), then asks the rest in a few short rounds of numbered questions with a recommended answer marked, always including the format (platform, reel or video, ratio, layout, length, sound). It ends in a one-screen brief that splits "you said" from "I assumed", plus a storyboard, and builds nothing until the person says yes. Use it whenever someone asks for a reel, a video, an explainer, a career film, an animation or a "make a video about X", before film-engine or any style pack, and again when a request changes its purpose, platform or audience mid-way.

thativanng/reels-maker

Picks the look of a reel or film before it is built. It shows three genuinely different looks as stills of the same opening frame with the same words, so the person judges the look and not the content. It keeps a log of every look ever shown, so no look comes back unless asked for, and it locks one look on purpose for a series. Use it after reel-intake's brief is signed and before any test strip, whenever someone says "what should it look like", "give me options", "make it look different from last time", "it looks cheap", or starts a new reel or a new series.

thativanng/reels-maker

The voxel career-film style. A blocky 3D version of the person walks, without ever vanishing, through one scene per role. Their outfit changes as they walk, each scene rises out of the floor ahead of them, and a dark banner tracks year, company and role. Use it when someone wants their career, a journey or a "how I got here" told as a short 3D film for LinkedIn or a portfolio, says "make my career film", "turn my CV into a video", "voxel film", or wants a new chapter added to an existing one. It runs on film-engine (render, audio, finish) and must pass film-audit before anything is sent.

Habilidades Relacionadas