Communitygithub.com

brewed-ops/spatial-film

Spatial Film – o motor cinematográfico por trás do talking-explainer. Cria motion graphics 3D espaciais de produto (45-90 s) com câmera CSS-3D, transições suaves, sem cortes secos, loop da última na primeira cena, interface real do produto, canvases de terceiros fiéis à plataforma (GHL, n8n, Zapier), trilha sonora em tempo nativo e efeitos sonoros, renderizado a 1080p60 via HyperFrames. Construído por 5 workers de cena em paralelo com um único contrato (frame.md + tabela de emendas + harness por cena). Use quando o usuário disser "spatial film" ou "motion graphic 3D", entregar um MOTION-PROMPT.md, ou pedir um vídeo de produto com 6+ cenas / câmera 3D SEM narração. Um explainer narrado (voz do usuário e/ou mascote apresentando) é o explainer-kit, que roda sobre a maquinaria desta skill.

O que é spatial-film?

Spatial Film é uma skill especializada para Agentes de IA (como Claude Code, Cursor, Codex) que automatiza a criação de vídeos de produto em 3D espaciais de 45 a 90 segundos, sem narração, com câmera CSS-3D contínua, transições suaves (push-throughs) e loop perfeito entre a última e a primeira cena. Ela permite que o agente coordene simultaneamente 5 workers independentes (cada um focado em uma cena) a partir de um contrato central (frame.md + tabela de emendas + harness por cena). Suporta a criação de motion graphics com a interface real do produto e réplicas fiéis de canvases de terceiros (GHL, n8n, Zapier), além de trilha sonora e efeitos sonoros gerados ou selecionados automaticamente. A saída é renderizada em 1080p60 com aceleração de hardware via HyperFrames, garantindo fluidez e consistência. Útil para demonstrações de produto, vídeos promocionais e apresentações dinâmicas onde a narrativa visual substitui completamente a narração.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/brewed-ops/talking-explainer/tree/main/skills/spatial-film

Perguntar na sua IA favorita

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

Documentação

Spatial Film

Comprovado do início ao fim em um filme de produto de 60s (7 cenas, 5 workers em uma única onda, todas as emendas exatas no quadro, verificação limpa, 1080p60 em 4m19s). O film.json do template contém as barras de cena e a folha de pauta reais desse filme como exemplo trabalhado.

<skill> = a pasta desta skill (o diretório onde este SKILL.md está). Execute todos os scripts a partir da raiz do projeto de filme. python abaixo = o comando Python salvo pela verificação de configuração do explainer-kit em ~/.talking-explainer/config.json (py -3.12 no Windows, python3 no macOS).

O que você precisa

  • Node 20+, ffmpeg + ffprobe no PATH, Python 3.10+ com numpy e Pillow.
  • As skills HyperFrames: npx hyperframes skills update general-video hyperframes-animation media-use (construtor de pacotes, blueprints + mapa de animação, auxiliar de música). O CLI em si é fixado por projeto e executado via npx.
  • Playwright para pré-renderização de superfícies: npm i -D playwright na pasta do filme (ou defina PLAYWRIGHT_PATH).
  • Opcional, para música com fonte: uma conta HeyGen – execute npx hyperframes auth login uma vez no seu terminal. Sem ela, traga sua própria faixa e comece a fase 4 em music-analyze.py.
  • Uma máquina com GPU para a renderização final (ela ainda renderiza pelo caminho de software, cerca de 15x mais lento).

Como usar esta skill sem desperdiçar contexto

  • Carregue UMA referência de fase por vez, quando a fase começar. Nunca pré-carregue todas.
  • Scripts são o código comprovado. Execute-os; nunca regenere a lógica deles inline.
  • A sessão principal nunca lê um arquivo de cena inteiro (20-60KB). Avalie as cenas pelas folhas de contato; corrija com grep -n e um patch exato.
  • Workers recebem CAMINHOS de arquivo, não conteúdo colado. storyboard.html (60KB+) é vasculhado por ID de célula, nunca lido inteiro.
  • Leia uma folha de contato primeiro; abra PNGs individuais apenas para verificar um detalhe.

Fases (cada uma termina em um portão – não avance até que ele passe)

#FaseCarregarPortão
0Scaffold: node <skill>/scripts/new-film.mjs <dir> --name <slug>-pasta tem film.json, frame.md, kit, docs do template
1Intake, BRIEF, STORYBOARD, folha de esboçoreferences/storyboard.md"vai" explícito do usuário registrado em ## Bloqueado
2frame.md, kit, superfícies pré-renderizadasreferences/surfaces.md (+ platform-canvases.md apenas se GHL/n8n/Zapier aparecerem)sem {{ no frame.md; todos os PNGs de captura verificados
3Teste de harness, pacotes, workers paralelosreferences/workers.mdcada cena: lint 0 erros, folha de contato corresponde ao seu bloco
4Música + SFX (roda enquanto os workers constroem)references/audio.mdbase no BPM nativo, barra 0 no tempo forte; pautas no film.json
5Montar, verificar, emendas, renderizar, enviarreferences/verify-ship.mdverificação passa, seam-check todos PASS, renderização com hardware-gpu verificada

Roteie por /hyperframes -> /general-video para a intenção e as etapas de revisão de esboço (esta skill fornece o formato do projeto, contrato, scripts e portões; general-video fornece o construtor de pacotes e a função de worker).

Arquivos

CaminhoO quê
template/Esqueleto do projeto: film.json (barras de cena, BPM, bgm, SFX, pautas – a ÚNICA fonte de temporização), frame.md (contrato de verdade do design com preenchimentos), BRIEF.md, STORYBOARD.md, assets/kit.css (kit base do filme), assets/fonts/ (Poppins 500/700 + OFL), references/worker-brief.md, references/scene-starter.html (esqueleto de cena limpo de lint), references/snippets.html, package.json (hyperframes 0.8.117 fixado).
surfaces/Reconstruções HTML prontas dos canvases GHL, n8n e Zapier + uma longa página de marketing (dados fictícios da Northwind Dental), platform.css, sprite.svg, jobs.json.
scripts/new-film.mjsScaffold de um projeto a partir do template.
scripts/capture-surfaces.cjsRenderiza src/captures/*.html -> assets/captures/*.png em 2x (jobs.json).
scripts/measure-surface.cjsCaixas 1x de elementos em uma superfície, para alvos exatos de anotação/corte.
scripts/make-harness.py, scripts/test-scene.mjsProjetos de teste isolados por cena; lint + snapshot de uma cena.
scripts/music-search.mjs, sfx-search.mjsCatálogo HeyGen via auxiliar REST do media-use (seguro para Windows).
scripts/music-analyze.py, music-bars.pyTempo apenas com numpy + energia por barra (sem necessidade de librosa).
scripts/bgm-cut.pyCorta a base nas linhas de barra, emenda o próprio final da faixa, fades; --b repete para fazer loop de uma base sob um filme mais longo.
scripts/assemble.pyfilm.json -> index.html (slots de cena na grade de barras, bgm, SFX com durações + pistas).
scripts/seam-check.pyComprova pixel a pixel cada emenda (antes / no / após o corte) e o loop (quadro 0 vs último).
scripts/render-final.mjsRenderização via CLI com --browser-gpu, registrada em arquivo, modo gpu + ffprobe verificados, depois flash-scan.py.
scripts/flash-scan.pyCada quadro de uma renderização: um quadro diferente de ambos os vizinhos (um elemento mostrado por 1/60s) = um bug.
scripts/encode-web.mjsCodificação web (H.264 CRF 21, faststart, AAC ou --silent) + quadro de poster.
scripts/blink-fit.py, scripts/build-presenter.pyFilmes narrados: sobreposições de piscar para poses de folha (--band = faixa dos olhos); a sobreposição do apresentador a partir de sua faixa, com sincronia labial quando o mascote tem mouth-fit.json.
scripts/el-tts.py, el-words.py, el-music.pyFilmes narrados via ElevenLabs (chave na env EL, nunca em disco): candidatos de voz a partir de SCRIPT.md, temporizações de palavras do Scribe, uma base gerada.
scripts/seam-diff.pyDiff de emenda com a caixa do apresentador mascarada (filmes narrados).
scripts/fromto-scan.pyPré-renderização: sinaliza propriedades fromTo ONLY-FROM que workers de renderização (buscas no meio da cena) nunca aplicam. 0 acertos antes de cada renderização.
scripts/patch_exact.pySubstituição exata, segura para CRLF, para correções de cena roteirizadas (afirma uma correspondência cada).
scripts/selftest.mjsProva de ponta a ponta de que a skill funciona nesta máquina. Deve imprimir PASS.

Filmes narrados (voz over + apresentador na tela)

Comprovado em um explainer narrado "API vs Webhook" (83s, vertical e paisagem, voz clonada, mascote apresentador, 10 cenas por 5 workers). As regras de filme musical acima ainda valem, exceto onde estas as substituem:

  • Candidatos de voz primeiro. EL=<key> python <skill>/scripts/el-tts.py . eric=<voice_id> michelle=<voice_id> lê as linhas indentadas de SCRIPT.md e escreve um MP3 por voz em src/audio/voice-candidates/ (chave apenas da env, nunca em disco). Deixe o usuário escolher de ouvido, depois transcreva apenas a escolha.
  • Narração é o relógio. Tempos das palavras: EL=<key> python <skill>/scripts/el-words.py <voice.mp3> src/timing/voice-words.json (ElevenLabs Scribe – sem modelo local, precisa de chave), ou faster-whisper com word_timestamps (idioma definido, VAD ativado; transcribe.py do explainer-kit, gratuito e local). Mantenha o JSON de palavras em src/timing/. Em film.json defina "bpm": 60, "beats_per_bar": 1 para que uma "barra" seja 1s e os comprimentos das cenas sejam segundos simples cortados nas pausas das frases. Os blocos do storyboard fornecem tempos de palavras locais às cenas; as chegadas começam ~0,1s antes e pousam na palavra. Dê a um título pelo menos ~1s na tela antes do próximo corte (verifique o corte em relação à ÚLTIMA palavra da linha que ele mostra).
  • Extras do film.json (assemble.py + make-harness.py os leem): "audio": [{id, src, dur, volume}] para a voz, "overlays": [{id, track, z}] para uma camada de filme inteiro (o apresentador) que fica acima de cada cena, para que nunca apareça em uma emenda e as cenas permaneçam livres de apresentador.
  • Apresentador a partir de PNGs de pose: um PNG transparente por pose (prep-mascot.py do explainer-kit corta, escala e escreve o manifesto), depois scripts/blink-fit.py <mascot_dir> (opcional, precisa de torch; ajusta a faixa BLINK dos olhos em cada pose por NCC; poses abaixo de 0,70 não recebem piscada) e scripts/build-presenter.py (escreve a sobreposição a partir de src/presenter-track.json: poses em palavras de pauta, ancoradas na cabeça para que as trocas nunca saltem, balanço de envelope de voz, respiração, piscadas, fx). Nunca edite manualmente sua saída.
  • Áudio: loudnorm na voz para -16 LUFS / -1,5 dBTP (um ganho simples cortado em +4,6 dBTP), duck do lado da base sob ela offline (~17 dB abaixo da voz), SFX baixo (0,1-0,45). Preencha a chave da voz ou o duck trunca a base para o comprimento da voz (verifique se avisou "bgm 110,25s vs slot 113s"): [1:a]apad=whole_dur=<TOTAL>[k];[0:a][k]sidechaincompress=threshold=0.03:ratio=6:attack=25:release=450,atrim=end=<TOTAL>. Sem base de catálogo (pesquisa HeyGen 500s ou sem login): EL=<key> python <skill>/scripts/el-music.py .media/candidates/bed.mp3 <ms> "<prompt: instrumental, BPM, fica sob um narrador, sem quedas, termina em um acorde resolvido>" - uma faixa que termina sozinha no comprimento do filme não precisa de emenda.
  • Ruído na verificação de emenda: o apresentador se move através de cada emenda, então seam-check.py FALHA apenas por causa dele. Julgue cada par sinalizado com scripts/seam-diff.py a.png b.png out.png x0,y0,x1,y1 (mascara a caixa do apresentador) - 0,00% fora dela é uma aprovação.
  • Lei de tamanho vertical (1080x1920): a faixa superior de cada cena carrega um título real (60-84px), texto do corpo >= 40px, objetos usam a largura total e a altura acima do apresentador. A primeira onda enviou texto de ~33px no topo 45% do quadro – coloque esses números no frame.md antes do despacho, não depois.
  • Não é um loop: um filme narrado termina em um lockup mantido; ignore a linha de loop do seam-check.

Regras rígidas (as que o tornam premium e suave)

  1. Verdade da fonte. A UI do produto é portada do próprio HTML/CSS do produto; os canvases de terceiros são reconstruídos a partir das capturas reais do usuário, nunca da memória. Apenas dados fictícios. Apenas recursos que o produto realmente possui.
  2. Uma câmera. Perspectiva 1866px (35mm) em cada cena; uma camada de deriva sob a camada da câmera para que nada nunca fique parado; paralaxe + desfoque DOF em folhas distantes. Sem opacidade/filtro/overflow/clip-path em um parente 3D (achata).
  3. Nítido em 1080p+. Escale a UI com CSS zoom (.kit-zoom), nunca transform: scale(>1); crie cada peça em seu tamanho de tela mais próximo; capturas são PNGs 2x mostrados em ou abaixo do nativo.
  4. Lei de suavidade de 60fps. Apenas transform/opacity; molas para aterrissagens, expo/power3 para chegadas, inOut para pernas de câmera; sem linear, steps, snap ou arredondamento; pernas de câmera se sobrepõem 0,15-0,3s e duram 0,6s+.
  5. Determinístico. Uma linha do tempo pausada por cena registrada por último em window.__timelines[id], fromTo com inícios explícitos, sem random/clock/CSS transitions.
  6. Emendas são quadros compartilhados. Cada emenda é uma imagem exata que ambos os vizinhos seguram ~0,1s, travada por uma placa 2D fora do rig. Sem corte seco, sem quadro vazio, sem fade para nada. Último quadro = primeiro quadro.
  7. Na grade. As cenas são barras inteiras/meio; cliques, ticks, carimbos e trocas caem nos tempos fortes; música em seu andamento nativo cortada nas linhas de barra.
  8. Correções de contrato, não correções de cena. Caminhos assets/... relativos à raiz, IDs nunca começando com dígito, IDs e classes prefixados com o ID da cena. Uma regra que toda cena quebraria é corrigida uma vez no frame.md / worker-brief.
  9. Proibições. Sem emoji, brilho neon, gradiente roxo-para-azul, cartões com borda esquerda colorida, spinners circulares (shimmer), pessoas de banco de imagens, "João da Silva", ritmo de slideshow ou movimento que não diz nada.
  10. Finais a partir do CLI com GPU de hardware. Nunca a Exportação do Studio (caminho de software, ~15x mais lento).

Quando algo dá errado

SintomaCausaCorreção
Lint: erro de caminho de asset../assets/ em uma sub-composiçãorelativo à raiz assets/... (corrigir no contrato)
Lint: ID de composição inválidoID começa com dígitos01-click, nunca 01-click (film.py recusa)
Construtor de pacotes lança / pacote > 48KBdois IDs de blueprint, ou muitas rules:um id (Adapt); 2-3 regras por bloco
UI parece suaveescalado por transform ou empurrado em direção à câmera além do tamanho de criação.kit-zoom, criar no tamanho mais próximo
3D de repente planoopacidade/filtro/overflow em um ancestral 3Dmover para a folha
Emenda apareceum lado não segurando o quadro compartilhadoseam-check.py, corrigir a placa/pose do lado que deriva
Seam FAIL alguns % mas os quadros parecem idênticosuma cópia do rig sob a placa dobra sua sombraapenas a placa aparece enquanto segura (emendas do frame.md)
UI do produto deriva do aplicativo realreconstruída da memória ou CSS parcialcapturar o aplicativo real em 2x (primeira seção do surfaces.md)
800+ avisos duplicate_audio_trackSFX sem data-durationexecutar assemble.py novamente
music-search diz sem credencialnão logadousuário executa npx hyperframes auth login no terminal deles
Renderização rasteja ~1 quadro/sGPU de software (exportação do Studio)render-final.mjs (CLI, --browser-gpu --workers 6)
Renderização continua rodando após paradaparar o shell não para o nodematar a árvore de processos (verify-ship.md)
Nenhum progresso de renderização visívelsaída pipeada através de `tail`

Autoteste

node <skill>/scripts/selftest.mjs

Cria um filme de 2 cenas em uma pasta temporária, então executa o harness, assemble, check, seam-check, uma renderização com GPU de hardware (1920x1080 a 60 fps) e a codificação web. Deve imprimir PASS – execute-o em uma máquina nova e após qualquer edição.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Habilidades Relacionadas