name: gfx-html description: Este skill deve ser usado quando o usuário solicitar uma sobreposição gráfica, título ou overlay na tela – "bau eine Bauchbinde", "mach ein Lower Third", "blend meinen Namen ein", "mach eine Titelkarte", "setz einen Text drüber", "brauch eine Grafik dazu", "zeig da eine Zahl an", "mach ein Intro-Insert", "build a lower third", "add a title card", "put a graphic over this", "overlay some text", "animate this number". Abrange o contrato de template HTML, renderização de frames via Chrome headless, codificação de vídeo com preservação de alfa e o bloco de overlays no project.json. argument-hint: [project-slug] [what-to-build]
gfx-html
Gráficos são páginas HTML renderizadas um frame por vez pelo Chrome headless e codificadas em um
vídeo com canal alfa. O texto completo da solicitação está em $ARGUMENTS; o primeiro token é geralmente o slug
do projeto. Nomes de verbos seguem o contrato de build; python engine/ve.py --help tem precedência em caso de conflito.
A regra que faz este fluxo funcionar
Cada gráfico é uma função pura de ?t=<segundos>. Sem animações CSS, sem timelines GSAP,
sem requestAnimationFrame, sem transições. A página lê t de location.search,
calcula seu layout e renderiza um frame estático.
Isso não é uma preferência de estilo. chrome --headless --screenshot é acionado "quando a página parece
carregada" – não há relógio virtual neste build, nem Emulation.setVirtualTimePolicy, nem
beginFrame. Uma página com animação CSS amostrada dessa forma retorna um pixel diferente a cada execução. Isso
destrói o cache endereçado por conteúdo (mesma chave, pixels diferentes) e produz vibração visível.
Uma função pura de t amostrada pelo mesmo loop ingênuo é determinística e cacheável, e
essa é toda a diferença.
O orçamento, declarado de antemão
O Chrome renderiza em ~430-470 ms por frame em estado estável, com um arranque a frio de 7,9 s. Um gráfico de 5 segundos a 30 fps são 150 frames, aproximadamente 65 segundos em thread única. O motor paraleliza quatro processos Chrome e armazena em cache PNGs por frame, então um gráfico inalterado re-renderiza de graça – mas uma primeira renderização não é instantânea.
Informe ao usuário a contagem de frames e a estimativa antes de iniciar um gráfico longo. Prefira gráficos curtos: um lower third que segura por 6 segundos não precisa de 6 segundos de movimento, ele precisa de 0,4 s de entrada, uma pausa e 0,4 s de saída.
Passo 1 – escolher ou escrever um template
Os templates ficam em presets/graphics/*.html. Reutilize antes de escrever. Um template é um único
arquivo HTML autocontido que:
- Lê
t(segundos) e suas propriedades delocation.search. - Calcula todas as posições/opacidades a partir de
tcom aritmética simples. Funções de easing são aceitáveis – elsas são puras. - Renderiza em um corpo transparente. Nunca pinte uma cor de fundo.
- Usa fontes de
assets/fonts/via@font-facecom uma URLfile:///. Não dependa de fontes do sistema – o que o Chrome resolve nesta máquina não é o que o controle de renderização QC assume. - É legível em 1920x1080 e dentro da área segura de legendas da plataforma. Verifique
output.platform: um lower third que fica no terço inferior está sob a interface do TikTok.
Detalhes de layout, convenções de easing e o contrato de propriedades estão em docs/graphics.md. Não os
repita aqui.
Passo 2 – renderizar frames
python engine/ve.py gfx <slug>
Por frame, o motor invoca o Chrome como uma lista de argumentos, aproximadamente:
chrome.exe --headless=new --disable-gpu --no-sandbox --hide-scrollbars
--user-data-dir=<win-path>\prof --default-background-color=00000000
--window-size=1920,1080 --screenshot=<win-path>\frame_0007.png
"file:///C:/.../template.html?t=0.233&title=..."
Duas flags carregam todo o fluxo:
--default-background-color=00000000é o que produz alfa genuíno. Verificado: o pixel do canto lê0 0 0 0. Sem ela, você obtém preto opaco e o overlay cobre o vídeo.- A URL
file:///deve ser um caminho real do Windows. Um caminho$PWDdo Git Bash falha silenciosamente – três arquivos HTML diferentes produziram o md5 idêntico de uma página de erro escura e em branco, com saída 0 e tamanho de arquivo plausível. É por isso que a verificação de controle de qualidade (g) compara com o hash da página em branco conhecida.
Os frames são armazenados em cache em .cache/html/ com chave baseada em
sha256(html_content + t + params + renderer + renderer_version). Alterar o template
invalida todos os frames, o que é correto.
Passo 3 – codificar com alfa intacto
Mesmo comando. ve gfx renderiza os frames e os codifica em uma única passagem – não há
um verbo separado de codificação, porque uma sequência de PNGs sem um vídeo ao lado é um
artefato meio acabado que nada downstream pode usar.
Sequência de PNG para QuickTime RLE (qtrle, argb). ProRes 4444 e uma sequência PNG bruta também
preservam o alfa corretamente. VP9 em WebM descarta silenciosamente o alfa neste build, mesmo com
-metadata alpha_mode=1 – não o use, e não aceite de um ativo do usuário sem
verificar.
A saída vai para .cache/ovl/<xx>/<key>.mov com um sidecar <key>.json.
Passo 4 – ancorar o overlay
Escreva a entrada em overlays[]: id, kind: "html", template, props, anchor,
duration_frames, layer, render.
anchor é sempre {segment_id, offset_frames} – nunca uma posição absoluta na linha do tempo.
Posições na linha do tempo são derivadas de uma soma acumulada sobre segmentos habilitados. No momento em que alguém
desabilita um segmento upstream, toda posição absoluta se torna errada e cada gráfico se desloca. Um overlay
ancorado se move com seu segmento automaticamente, que é o comportamento que um editor espera.
layer ordena a composição; quanto maior, mais acima. Legendas são sobrepostas por último e ficam acima dos gráficos.
Passo 5 – verificar antes de declarar concluído
Três verificações, todas baratas:
- Sonda de alfa. Leia um pixel rgba bruto de um frame de canto e afirme
a = 0. Controle de qualidade (d). - Verificação de página em branco. Afirme que os frames não são todos uma cor sólida. Controle de qualidade (g). Isso detecta
uma URL
file:///inválida, uma fonte que não carregou e um erro de JavaScript, todos os quais, de outra forma, saem com 0 com um arquivo plausível. Ela amostra o primeiro frame, o do meio e o de três quartos, e falha apenas se todos forem uniformes – todo template aqui abre com opacidade 0, então o frame 0 de um gráfico funcional é legitimamente vazio e julgar apenas por ele falha uma renderização correta.
ve gfx executa ambas automaticamente sobre o que acabou de produzir e sai com código 2 se alguma falhar.
3. Determinismo. Renderize um frame duas vezes e compare os hashes. Se diferirem, algo no
template não é uma função pura de t – encontre-o. Esta verificação existe porque a falha que ela detecta é invisível até que uma renderização em cache discorde de uma nova.
Em seguida, mostre ao usuário uma imagem estática no ponto médio. Não descreva um gráfico em prosa quando uma captura de tela está a um comando de distância.
Modos de falha
| Sintoma | Causa | Correção |
|---|---|---|
| Overlay cobre o vídeo com preto | --default-background-color ausente, ou o template pinta um fundo | Adicione a flag; torne o corpo transparente |
| Cada frame idêntico, tamanho de arquivo plausível | Página de erro em branco de uma URL file:/// inválida | Use um caminho real do Windows; compare com o hash da página em branco |
| Mesma chave, pixels diferentes entre execuções | Template não é uma função pura de t | Remova toda animação CSS e rAF |
| Texto renderiza na tipografia errada | Fallback de fonte do sistema | @font-face de assets/fonts/ com uma URL file:/// |
| Alfa perdido após codificação | VP9/WebM | Use qtrle argb ou ProRes 4444 |
| Gráfico se desloca após uma edição upstream | Âncora de linha do tempo absoluta | Ancore a {segment_id, offset_frames} |
| Renderização leva minutos | 430 ms/frame é o mínimo | Encurte o gráfico ou aceite; o cache torna a segunda execução gratuita |