Landing fly-over
Um filme fixo e artisticamente dirigido de uma landing page. Cada quadro é uma função pura do tempo (seek(t) em WebGL2), capturado com Playwright, renderizado na GPU real com motion blur de 16 subquadros e codificado com ffmpeg. Sem editor de vídeo, timeline ou cortes.
Você precisa executar código na máquina do usuário. Se não puder (um ambiente apenas de chat), diga isso imediatamente: você pode descrever o filme, mas o MP4 requer um agente de código com shell (Claude Code, Codex, Cursor…).
0. Peça as entradas
Pergunte uma vez, em uma única mensagem:
- Link da landing page.
- Nome da marca e logotipo (um PNG quadrado ou caminho SVG; procure primeiro no repositório:
logo*,favicon*,brand*). - Uma linha de fechamento em duas partes: uma declaração curta, depois uma cauda itálica curta. Mantenha a linha 1 com menos de ~22 caracteres (ela é definida em 74px em um quadro de 1440px). Ofereça 2–3 opções extraídas do texto da própria página.
- Uma trilha de 15 segundos (opcional). Se não tiver nenhuma, ofereça-se para encontrar uma royalty-free (a licença gratuita do Mixkit permite uso comercial sem atribuição; baixe de
https://assets.mixkit.co/music/<id>/<id>.mp3). Nunca faça commit de uma trilha baixada em um repositório; apenas no MP4 renderizado.
1. Configuração
cp -R <this-skill-dir>/engine ./flyover && cd flyover
npm install && npx playwright install chromium # o Chrome instalado é preferido automaticamente quando presente
cp config.example.json config.json
Requer Node 18+, ffmpeg no PATH e Python 3 com numpy para a pontuação (opencv-python-headless para verificação de fluxo). Coloque o logotipo ao lado de config.json e defina url, brand, logo, title.
2. Inspecione e escolha o que levanta
node inspect.mjs # → dom.txt (árvore de seções com posições da página) + inspect.png
Leia dom.txt e preencha config.json:
hero.section: a seção hero.hero.mockup: o quadro de telefone/produto/vídeo no hero (o filme começa focado nele e o card final corta logo abaixo dele).hero.tileAnchor: o último botão do hero (os quatro tiles de logotipo começam ao lado dele).hero.footerTitle: o último título grande antes do rodapé (fica nítido em 8,0s).layers: peças que levantam, como{ "sel", "role" }, opcionalmente sobrescrevendoz(elevação em repouso),zMax(elevação quando a câmera passa) estand(graus que se levanta em direção à lente). Funções e padrões:
| função | usar para | z → zMax · levantar |
|---|---|---|
button | botões hero / CTA | 6 → 28 · 0° |
chip | badges, pills, abas, pequenos logotipos | 4 → 64 · 30° |
mockup | quadro de telefone/produto/vídeo do hero | 10 → 24 · 0° |
card | cartões de funcionalidades, tabelas, terminais, células de métricas | 6 → 30 · 0° |
photo | imagens dentro de cards, capturas de tela, amostras de código | 8 → 115 · 46° |
flychip | 1–2 chips pequenos que voam pelas bordas do quadro | 4 → 200 · 54° |
testimonial | um cartão de citação/terminal; mostra uma borda branca de 34px | 22 → 112 · 30° |
Mantenha a maioria dos levantamentos pequenos (20–40px). Busque 15–35 peças em toda a página, algumas por seção. Peças aninhadas são aceitáveis: liste a interna (photo) antes de seu card.
waitFor: seletores de números ao vivo fornecidos por uma API (contadores de visitantes, medidores de tokens). A captura espera até que cada um mostre um dígito diferente de zero antes de congelar a página; caso contrário, podem filmar como "0".hide: banners de cookies, widgets de chat, pop-ups.css: qualquer CSS extra para forçar o estado final de efeitos acionados por rolagem (ex.: palavras que acendem ao rolar).routes:[{ "match": "**/broken.jpg*", "file": "/abs/local/copy.jpg" }]para ativos que o site ao vivo falha em servir.
3. Capture e trave a página
node capture.mjs
Isso rola até o fundo uma vez (imagens lazy, contadores, revelações), finaliza animações, congela vídeos em um quadro (ou seu poster), colapsa seções "pista" fixadas por rolagem (espaçadores sticky + 200vh de rolagem seriam filmados como trechos em branco), desfixa barras fixas, então salva a placa base em chunks de 4096px (o Chrome limita uma captura a 16384 px de dispositivo: capturas maiores repetem silenciosamente o topo da página) mais cada peça levantada sozinha em transparência com 28px de preenchimento, e capture/layers.json com cada posição.
Examine a captura antes de ajustar o tempo: abra capture/page_*.png e alguns layer_*.png. Verifique quadros de vídeo em branco, texto parcialmente revelado, regiões duplicadas, pop-ups. Corrija com css/hide/routes e recapture. Trave a página antes de ajustar o tempo: qualquer mudança na altura de uma seção desloca tudo depois dela.
4. Stills para aprovação
node render.mjs stills 0,1.6,2.5,5,6.5,9.3,11 # → stills/contact_sheet.png
Mostre ao usuário a folha de contato e aguarde um sim antes da renderização final. O que cada still deve mostrar:
- 0s: baixo sobre o hero, mockup nítido, quatro tiles de logotipo de 32px ao lado do botão.
- 1,6s: hero caindo para trás, o título da segunda seção cruzando o centro, conteúdo próximo derretendo.
- 2,5s: as fotos daquela seção levantadas e desfocadas perto da lente; um flychip saindo de uma borda.
- 5s / 6,5s: deslize constante; uma seção nítida no centro, suave abaixo; o testimonial erguido com sua borda branca.
- 9,3s: diretamente de cima, a página inteira como uma faixa centralizada.
- 11s: o card final: pill de badge, linha 1 em Geist 500, cauda itálica Instrument Serif cinza, o hero como um card de 1018px, tiles de logotipo em seus cantos, dois desfoques suaves na parte inferior.
5. Verifique o movimento
node render.mjs video preview30.mp4 30 1 && node render.mjs cam
python3 flow.py preview30.mp4 # PASS = o deslize nunca para ou reverte, o voo nunca aproxima
6. Pontuação e renderização
python3 score.py track.mp3 auto # encontra a batida, coloca-a em 9.97s; whooshes em 8.66s e 9.80s → audio/score.wav
node render.mjs video flyover.mp4 60 16 # → flyover.mp4, além de flyover-audio.mp4 quando audio/score.wav existe
Cerca de 0,1–0,2s por quadro em uma GPU Apple M-series (870 quadros). O harness seleciona ANGLE Metal no macOS, D3D11 no Windows, Vulkan no Linux; se relatar SwiftShader/llvmpipe, você está em um rasterizador de software e será lento.
O filme (fixo: não reajuste o tempo por página)
- 14.5s a 60fps, 1440x1152. Voo 0–8,2s · subida 7,75–9,25s · visão aérea 9,25–9,47s · mergulho 9,47–9,97s · card de título 9,97–14,5s.
- Uma câmera, nunca um corte. Distância focal 1880px, inclinação 56°, distância relaxando 1360→1700px, nunca girando. Velocidade ao longo da página é uma curva integrada (fração de cruzeiro): 0 → 0,5 em 0,6s, mantida até 1,25s, 1,0 em 1,6s, mantida até 7,3s, relaxando para 0,12 em 8,3s. O cruzeiro é resolvido para que o título do rodapé fique nítido em 8,0s, então páginas longas deslizam mais rápido.
- Profundidade de campo por pixel: desfoque = 75·(foco−profundidade)/profundidade na frente, 6·(profundidade−foco)/profundidade atrás, limitado a 120px; 40 amostras de ângulo dourado de níveis mip, rotacionadas por subquadro de motion blur; desfoque de campo próximo dilatado para que o primeiro plano desfocado se sobreponha ao fundo nítido.
- Peças levantadas se erguem em torno de seu próprio meio (borda superior em direção à lente) e projetam uma sombra: a mesma imagem em #1a2133 plano, deslocamento (0,10z, 4+0,36z), desfocada 7+0,5z, 26%.
- Subida: zoom em escala logarítmica em uma velocidade trapezoidal, achatamento da inclinação 8,15–8,95s, passando para uma câmera que fixa a borda inferior da página 42px acima do quadro. Mergulho: ease-in-out quadrático em escala logarítmica com a borda superior fixa, depois solta para y 283; uma máscara de retângulo arredondado morphs cantos de 24px → 38px. Conteúdo abaixo do hero desbota na cor de névoa primeiro, depois corta para transparente.
- Título: pill de badge fade in em 10,02s (y 44); linha 1 a partir de 10,12s uma palavra a cada 0,06s; cauda a partir de 10,36s uma palavra a cada 0,05s; cada palavra sobe 16px de um desfoque de 12px em 0,34s. Mantenha com um deslocamento de 2%.
Proibido: cortes, crossfades, paradas ou picos no deslize, a câmera girando ou balançando lateralmente, zoom durante o voo, brilhos, qualquer texto sobre a página antes do card final.
Pegadinhas
- Páginas enormes: a placa base é dividida em chunks, nunca uma captura única. Se você vir o hero repetido no meio da página, uma captura excedeu 16384 px de dispositivo.
- Sites acionados por rolagem: pistas sticky são colapsadas automaticamente; destaques de palavra por palavra na rolagem precisam de uma regra
cssforçando opacidade total. - Vídeos: eles são congelados em
videoTimesegundos. Se o vídeo do site ao vivo der 404, você recebe um card preto; sirva um poster local viaroutes. - Cards que desbotam: mostram o que está atrás deles, então desbote para a cor de névoa primeiro (o mecanismo faz isso para tudo abaixo do hero).
- Linha 1 muito longa: palavras saem do quadro em 74px. Encurte a linha em vez de reduzir o tipo.
- Licenciamento: a música permanece responsabilidade do usuário; prefira faixas cuja licença cubra vídeo comercial.