Communitygithub.com

Landing Flyover: tu landing page como película 3D de 14,5 s

Convierte la URL de cualquier landing page en una película 3D de sobrevuelo de 14,5 segundos (MP4 1440x1152, 60 fps) hecha solo con código: una cámara continua se desliza por la página con profundidad de campo mínima mientras tarjetas y fotos se elevan, sube para mostrarla entera y luego se lanza al hero y lo deja bajo un título de dos líneas, con el drop de la música justo en el título.

¿Qué es Landing Flyover: tu landing page como película 3D de 14,5 s?

Paso 2 de la receta De landing page a película de lanzamiento (filmar la página), de arjunkshah12345-hash/landing-flyover (MIT, con MP4 de ejemplo y fotogramas en el repo). El agente pide primero la URL, la marca y el logo, una frase final en dos partes y una pista opcional de 15 s (puede sugerir una libre de derechos de Mixkit). inspect.mjs vuelca el árbol de secciones para que el agente elija de 15 a 35 piezas que se elevan según su rol (botón, chip, mockup, tarjeta, foto, testimonio); capture.mjs usa Playwright para hacer scroll una vez, terminar animaciones, congelar vídeos, plegar secciones fijadas y guardar la placa de la página; una película WebGL2 donde cada fotograma es seek(t) genera fotogramas y hoja de contactos, una vista previa a 30 fps y el render final a 60 fps con 16 subfotogramas de desenfoque de movimiento. flow.py comprueba con flujo óptico que la cámara nunca se detiene y score.py coloca el drop en 9,97 s con whooshes. Requiere Node 18+, ffmpeg, Python con numpy y una GPU.

Compatible con✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/arjunkshah12345-hash/landing-flyover/tree/HEAD/skills/landing-flyover

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Landing fly-over

Una película fija y artísticamente dirigida de una página de aterrizaje. Cada fotograma es una función pura del tiempo (seek(t) en WebGL2), capturada con Playwright, renderizada en la GPU real con desenfoque de movimiento de 16 subfotogramas y codificada con ffmpeg. Sin editor de vídeo, sin línea de tiempo, sin cortes.

Necesitas ejecutar código en la máquina del usuario. Si no puedes (una superficie solo de chat), dilo de inmediato: puedes describir la película, pero el MP4 necesita un agente de codificación con un shell (Claude Code, Codex, Cursor…).

0. Solicita las entradas

Pregunta una vez, en un solo mensaje:

  1. Enlace a la página de aterrizaje.
  2. Nombre de la marca y logotipo (un PNG cuadrado o una ruta SVG; busca primero en el repositorio: logo*, favicon*, brand*).
  3. Un cierre de dos partes: una declaración corta, luego una cola corta en cursiva. Mantén la línea 1 por debajo de ~22 caracteres (se muestra a 74px en un fotograma de 1440px). Ofrece 2–3 opciones extraídas del texto de la propia página.
  4. Una pista de 15 segundos (opcional). Si no tiene, ofrécete a buscar una libre de regalías (la licencia gratuita de Mixkit permite uso comercial sin atribución; descarga desde https://assets.mixkit.co/music/<id>/<id>.mp3). Nunca subas una pista descargada a un repositorio; solo el MP4 renderizado.

1. Configuración

cp -R <this-skill-dir>/engine ./flyover && cd flyover
npm install && npx playwright install chromium   # se prefiere Chrome instalado automáticamente si está presente
cp config.example.json config.json

Requiere Node 18+, ffmpeg en PATH, y Python 3 con numpy para la partitura (opencv-python-headless para la comprobación de flujo). Coloca el logotipo junto a config.json y define url, brand, logo y title.

2. Inspecciona, luego elige qué se eleva

node inspect.mjs        # → dom.txt (árbol de secciones con posiciones en la página) + inspect.png

Lee dom.txt y completa config.json:

  • hero.section: la sección hero. hero.mockup: el marco del teléfono/producto/vídeo en el hero (la película comienza enfocada en él y la tarjeta final corta justo debajo de él). hero.tileAnchor: el último botón del hero (las cuatro fichas del logotipo comienzan junto a él). hero.footerTitle: el último encabezado grande antes del pie de página (aparece nítido a los 8.0s).
  • layers: piezas que se levantan, como { "sel", "role" }, opcionalmente sobrescribiendo z (elevación en reposo), zMax (elevación cuando pasa la cámara) y stand (grados que se inclina hacia el objetivo). Roles y valores predeterminados:
roluso paraz → zMax · stand
buttonbotones hero / CTA6 → 28 · 0°
chipinsignias, píldoras, pestañas, logotipos pequeños4 → 64 · 30°
mockupel marco del teléfono / producto / vídeo del hero10 → 24 · 0°
cardtarjetas de características, tablas, terminales, celdas de métricas6 → 30 · 0°
photoimágenes dentro de tarjetas, capturas de pantalla, muestras de código8 → 115 · 46°
flychip1–2 chips pequeños que vuelan más allá de los bordes del fotograma4 → 200 · 54°
testimonialuna tarjeta de cita / terminal; muestra un borde blanco de 34px22 → 112 · 30°

Mantén la mayoría de las elevaciones pequeñas (20–40px). Apunta a 15–35 piezas en toda la página, unas pocas por sección. Las piezas anidadas están bien: lista la interna (photo) antes de su tarjeta.

  • waitFor: selectores de números en vivo alimentados por una API (contadores de visitantes, medidores de tokens). La captura espera hasta que cada uno muestre un dígito distinto de cero antes de congelar la página; de lo contrario, pueden filmarse como "0".
  • hide: banners de cookies, widgets de chat, ventanas emergentes. css: cualquier CSS adicional para forzar el estado final de los efectos basados en desplazamiento (por ejemplo, palabras que se iluminan al hacer scroll). routes: [{ "match": "**/broken.jpg*", "file": "/abs/local/copy.jpg" }] para activos que el sitio en vivo no sirve correctamente.

3. Captura y bloquea la página

node capture.mjs

Esto se desplaza hasta el fondo una vez (imágenes perezosas, contadores, revelaciones), finaliza las animaciones, congela los vídeos en un fotograma (o su póster), colapsa las secciones de "pista de aterrizaje" fijadas por desplazamiento (sticky + espaciadores de desplazamiento de 200vh de lo contrario se filmarían como tramos en blanco), desbloquea las barras fijas, luego guarda la placa base en fragmentos de 4096px (Chrome limita una captura a 16384 píxeles de dispositivo: las capturas más grandes repiten silenciosamente la parte superior de la página) más cada pieza elevada individualmente sobre transparencia con 28px de relleno, y capture/layers.json con cada posición.

Mira la captura antes de temporizar cualquier cosa: abre capture/page_*.png y algunas layer_*.png. Verifica si hay fotogramas de vídeo en blanco, texto medio revelado, regiones duplicadas, ventanas emergentes. Corrige con css/hide/routes y vuelve a capturar. Bloquea la página antes de temporizar: cualquier cambio en la altura de una sección desplaza todo lo que está después.

4. Fotogramas fijos para aprobación

node render.mjs stills 0,1.6,2.5,5,6.5,9.3,11      # → stills/contact_sheet.png

Muestra al usuario la hoja de contactos y espera una respuesta afirmativa antes del renderizado final. Lo que debe mostrar cada fotograma fijo:

  • 0s: bajo sobre el hero, maqueta nítida, cuatro fichas de logotipo de 32px junto al botón.
  • 1.6s: hero cayendo detrás, el título de la segunda sección cruzando el centro, el contenido cercano difuminándose.
  • 2.5s: las fotos de esa sección levantadas y desenfocadas cerca del objetivo; un flychip saliendo de un borde.
  • 5s / 6.5s: planeo constante; una sección nítida en el centro, suave debajo; el testimonio elevado con su borde blanco.
  • 9.3s: directamente desde arriba, toda la página como una tira centrada.
  • 11s: la tarjeta final: una píldora de insignia, la línea 1 en Geist 500, cola en cursiva Instrument Serif gris, el héroe como una tarjeta de 1018px, fichas de logotipo en sus esquinas, dos desenfoques suaves en la parte inferior.

5. Verifica el movimiento

node render.mjs video preview30.mp4 30 1 && node render.mjs cam
python3 flow.py preview30.mp4     # PASS = el planeo nunca se detiene ni invierte, el vuelo nunca se acerca

6. Partitura y renderizado

python3 score.py track.mp3 auto     # encuentra el drop, lo aterriza en 9.97s; whooshes en 8.66s y 9.80s → audio/score.wav
node render.mjs video flyover.mp4 60 16   # → flyover.mp4, más flyover-audio.mp4 cuando existe audio/score.wav

Aproximadamente 0.1–0.2s por fotograma en una GPU de la serie M de Apple (870 fotogramas). El harness selecciona ANGLE Metal en macOS, D3D11 en Windows, Vulkan en Linux; si informa SwiftShader/llvmpipe estás en un rasterizador de software y será lento.

La película (fija: no la retemporices por página)

  • 14.5s a 60fps, 1440x1152. Vuelo 0–8.2s · ascenso 7.75–9.25s · vista aérea 9.25–9.47s · inmersión 9.47–9.97s · tarjeta de título 9.97–14.5s.
  • Una cámara, nunca un corte. Distancia focal 1880px, inclinación 56°, distancia con relajación 1360→1700px, sin girar nunca. La velocidad a lo largo de la página es una curva integrada (proporción de crucero): 0 → 0.5 a los 0.6s, mantenida hasta 1.25s, 1.0 a los 1.6s, mantenida hasta 7.3s, relajándose a 0.12 a los 8.3s. El crucero se resuelve para que el título del pie de página esté nítido a los 8.0s, por lo que las páginas largas se deslizan más rápido.
  • Profundidad de campo por píxel: desenfoque = 75·(enfoque−profundidad)/profundidad en el frente, 6·(profundidad−enfoque)/profundidad detrás, limitado a 120px; 40 muestras de ángulo dorado desde niveles mip, rotadas por subfotograma de desenfoque de movimiento; desenfoque de campo cercano dilatado para que el primer plano desenfocado se extienda sobre el fondo nítido.
  • Las piezas levantadas se colocan alrededor de su propio centro (el borde superior hacia el objetivo) y proyectan una sombra: la misma imagen en #1a2133 plano, desplazada (0.10z, 4+0.36z), desenfocada 7+0.5z, 26%.
  • Ascenso: zoom de escala logarítmica en una velocidad trapezoidal, aplanamiento de inclinación 8.15–8.95s, entregando a una cámara que fija el borde inferior de la página 42px sobre el fotograma. Inmersión: easing cuadrático de entrada-salida en escala logarítmica con el borde superior fijado, luego caída a y 283; una máscara de rectángulo redondeado transforma esquinas de 24px → 38px. El contenido debajo del hero se desvanece primero en el color de la neblina, luego se corta a transparente.
  • Título: la píldora de insignia se desvanece a los 10.02s (y 44); línea 1 a partir de 10.12s una palabra cada 0.06s; cola a partir de 10.36s una palabra cada 0.05s; cada palabra se eleva 16px desde un desenfoque de 12px en 0.34s. Se mantiene con un deslizamiento del 2%.

Prohibido: cortes, fundidos cruzados, paradas o aceleraciones en el planeo, la cámara girando o balanceándose lateralmente, zoom durante el vuelo, resplandores, cualquier texto sobre la página antes de la tarjeta final.

Problemas comunes

  • Páginas enormes: la placa base se divide en fragmentos, nunca una sola captura de pantalla. Si ves el héroe repetido a mitad de camino, una captura superó los 16384 píxeles de dispositivo.
  • Sitios con desplazamiento: las pistas adhesivas se colapsan automáticamente; los resaltados de desplazamiento palabra por palabra necesitan una regla css que fuerce la opacidad completa.
  • Vídeos: se congelan en videoTime segundos. Si el vídeo del sitio en vivo da 404, obtienes una tarjeta negra; sirve un póster local mediante routes.
  • Tarjetas que se desvanecen: muestran lo que hay detrás, así que desvanece primero al color de la neblina (el motor hace esto para todo lo que está debajo del hero).
  • Línea 1 demasiado larga: las palabras se salen del fotograma a 74px. Acorta la línea en lugar de reducir el tipo.
  • Licencias: la música sigue siendo responsabilidad del usuario; prefiere pistas cuya licencia cubra el uso comercial.

Skills relacionados