Communitygithub.com

Landing Flyover: jede Landingpage als 14,5-s-3D-Film

Macht aus jeder Landingpage-URL einen 14,5-sekündigen 3D-Flyover-Film (1440x1152, 60 fps MP4), komplett per Code: Eine durchgehende Kamera gleitet mit hauchdünner Schärfentiefe über die Seite, Karten und Fotos heben ab, die Kamera steigt auf, taucht dann in den Hero und landet ihn unter einem zweizeiligen Titel, wobei der Drop des Tracks genau auf dem Titel sitzt.

Was ist Landing Flyover: jede Landingpage als 14,5-s-3D-Film?

Schritt 2 des Rezepts Von der Landingpage zum Launch-Film (die Seite filmen), aus arjunkshah12345-hash/landing-flyover (MIT, mit Beispiel-MP4 und Standbildern). Der Agent fragt zuerst URL, Marke und Logo, eine zweiteilige Schlusszeile und einen optionalen 15-Sekunden-Track ab (oder schlägt einen lizenzfreien Mixkit-Track vor). inspect.mjs gibt den Sektionsbaum aus, damit der Agent 15–35 Elemente nach Rolle (Button, Chip, Mockup, Karte, Foto, Testimonial) zum Anheben wählt; capture.mjs scrollt mit Playwright einmal durch, beendet Animationen, friert Videos ein, klappt scroll-gepinnte Sektionen zusammen und speichert die Seitenplatte; ein WebGL2-Film, in dem jedes Frame seek(t) ist, rendert Standbilder und Kontaktbogen, eine 30-fps-Vorschau und das finale 60-fps-Render mit 16 Motion-Blur-Subframes. flow.py prüft per optischem Fluss, dass die Kamera nie stockt, score.py legt den Drop auf 9,97 s und ergänzt Whooshes. Braucht Node 18+, ffmpeg, Python mit numpy und eine GPU.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Landing Fly-Over

Ein fest inszenierter, künstlerisch gestalteter Film einer Landingpage. Jeder Frame ist eine reine Funktion der Zeit (seek(t) in WebGL2), wird mit Playwright erfasst, auf der echten GPU mit 16-Unterframe-Bewegungsunschärfe gerendert und mit ffmpeg kodiert. Kein Videobearbeitungsprogramm, keine Timeline, keine Schnitte.

Du musst Code auf dem Rechner des Benutzers ausführen. Falls du das nicht kannst (reine Chat-Oberfläche), sag es sofort: Du kannst den Film zwar beschreiben, aber die MP4 benötigt einen Coding-Agenten mit einer Shell (Claude Code, Codex, Cursor …).

0. Die Eingaben abfragen

Einmal in einer Nachricht erfragen:

  1. Link zur Landingpage.
  2. Markenname und Logomarke (ein quadratisches PNG/SVG; zuerst im Repo suchen: logo*, favicon*, brand*).
  3. Eine zweiteilige Schlusszeile: eine kurze Aussage, dann ein kurzer kursiver Nachsatz. Zeile 1 unter ~22 Zeichen halten (wird in 74pt über einen 1440px breiten Frame gesetzt). 2–3 Optionen aus dem Text der Seite vorschlagen.
  4. Einen 15-Sekunden-Track (optional). Falls der Benutzer keinen hat, einen lizenzfreien von Mixkit anbieten (Mixe freie Lizenz erlaubt kommerzielle Nutzung ohne Namensnennung; herunterladen von https://assets.mixkit.co/music/<id>/<id>.mp3). Nie einen heruntergeladenen Track in ein Repository committen; nur die gerenderte MP4.

1. Einrichtung

cp -R <skill-verzeichnis>/engine ./flyover && cd flyover
npm install && npx playwright install chromium   # installiertes Chrome wird automatisch bevorzugt, falls vorhanden
cp config.example.json config.json

Benötigt Node 18+, ffmpeg im PATH und Python 3 mit numpy für die Partitur (opencv-python-headless für die Bewegungsprüfung). Lege das Logo neben config.json und setze url, brand, logo, title.

2. Inspizieren, dann auswählen, was sich hebt

node inspect.mjs        # → dom.txt (Abschnittsbaum mit Seitepositionen) + inspect.png

Lies dom.txt und fülle config.json aus:

  • hero.section: der Hero-Abschnitt. hero.mockup: das Telefon/Produkt/Video-Frame im Hero (der Film startet fokussiert darauf und die Endkarte beschneidet direkt darunter). hero.tileAnchor: der letzte Button im Hero (die vier Logokacheln beginnen daneben). hero.footerTitle: die letzte große Überschrift vor dem Footer (ist bei 8,0s scharf).
  • layers: Stücke, die sich heben, als { "sel", "role" }, optional mit Überschreibung von z (Hebehöhe in Ruhe), zMax (Hebehöhe, wenn die Kamera vorbeifährt) und stand (Grad, um die sie sich zur Linse aufrichten). Rollen und Standardwerte:
RolleVerwendungz → zMax · Stand
buttonHero-/CTA-Buttons6 → 28 · 0°
chipBadges, Pillen, Tabs, kleine Logos4 → 64 · 30°
mockupDas Hero-Telefon/Produkt/Video-Frame10 → 24 · 0°
cardFeature-Karten, Tabellen, Terminals, Metrik-Zellen6 → 30 · 0°
photoBilder in Karten, Screenshots, Code-Beispiele8 → 115 · 46°
flychip1–2 kleine Chips, die an den Bildrändern vorbeifliegen4 → 200 · 54°
testimonialEin Zitat-/Terminal-Karte; zeigt einen 34px weißen Rand22 → 112 · 30°

Halte die meisten Hubhöhen klein (20–40px). Ziel: 15–35 Stücke über die gesamte Seite, ein paar pro Abschnitt. Verschachtelte Stücke sind in Ordnung: das innere (photo) vor seiner Karte auflisten.

  • waitFor: Selektoren von Live-Zahlen, die von einer API gespeist werden (Besucherzähler, Token-Meter). Der Capture wartet, bis jede eine Ziffer ungleich Null anzeigt, bevor die Seite eingefroren wird; sonst könnten sie als „0“ gefilmt werden.
  • hide: Cookie-Banner, Chat-Widgets, Popups. css: zusätzliches CSS, um den Endzustand von scrollgesteuerten Effekten zu erzwingen (z. B. Wörter, die beim Scrollen aufleuchten). routes: [{ "match": "**/broken.jpg*", "file": "/abs/local/copy.jpg" }] für Assets, die die Live-Seite nicht ausliefern kann.

3. Seite erfassen und einfrieren

node capture.mjs

Dies scrollt einmal nach unten (Lazy-Images, Zähler, Revalings), beendet Animationen, friert Videos auf einem Frame ein (oder deren Poster), faltet scroll-pinierte „Runway“-Abschnitte zusammen (Sticky + 200vh Scroll-Abstandshalter würden sonst als leere Streifen gefilmt), entfernt fixierte Leisten, speichert dann die Basisplatte in 4096px großen Stücken (Chrome begrenzt einen Capture auf 16384 Geräte-Pixel: größere Captures wiederholen stillschweigend den oberen Teil der Seite) plus jedes gehobene Stück einzeln auf Transparenz mit 28px Rand, sowie capture/layers.json mit allen Positionen.

Sieh dir den Capture an, bevor du irgendetwas timest: öffne capture/page_*.png und ein paar layer_*.png. Prüfe auf leere Videoframes, halb aufgedeckten Text, duplizierte Regionen, Popups. Behebe mit css/hide/routes und nimm den Capture erneut vor. Seite vor dem Timing einfrieren: jede Änderung der Höhe eines Abschnitts verschiebt alles dahinter.

4. Standbilder zur Freigabe

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

Zeig dem Benutzer das Kontaktblatt und warte auf ein Ja, bevor der finale Render erfolgt. Was jedes Standbild zeigen sollte:

  • 0s: Tief über dem Hero, Mockup scharf, vier 32px Logokacheln neben dem Button.
  • 1.6s: Hero fällt zurück, die Überschrift des zweiten Abschnitts kreuzt die Mitte, nahe Inhalte verschwimmen.
  • 2.5s: Die Fotos dieses Abschnitts stehen aufgerichtet und unscharf nahe der Linse; ein Flychip verlässt einen Rand.
  • 5s / 6.5s: Stetiger Gleitflug; ein Abschnitt scharf in der Mitte, weich darunter; das Testimonial angehoben mit seinem weißen Rand.
  • 9.3s: Senkrecht von oben, die gesamte Seite als ein zentrierter Streifen.
  • 11s: Die Endkarte: Badge-Pille, Zeile 1 in Geist 500, grauer kursiver Instrument Serif Nachsatz, der Hero als 1018px Karte, Logokacheln an den Ecken, zwei weiche Unschärfen unten.

5. Bewegung prüfen

node render.mjs video preview30.mp4 30 1 && node render.mjs cam
python3 flow.py preview30.mp4     # PASS = der Gleitflug stockt oder kehrt nie um, der Flug zoomt nie hinein

6. Partitur und Render

python3 score.py track.mp3 auto     # findet den Drop, landet ihn bei 9,97s; Whooshes bei 8,66s und 9,80s → audio/score.wav
node render.mjs video flyover.mp4 60 16   # → flyover.mp4, plus flyover-audio.mp4 falls audio/score.wav existiert

Etwa 0,1–0,2s pro Frame auf einem Apple M-Serie GPU (870 Frames). Das Harness wählt ANGLE Metal auf macOS, D3D11 auf Windows, Vulkan auf Linux; falls es SwiftShader/llvmpipe meldet, läuft ein Software-Rasterizer und es wird langsam.

Der Film (festgelegt: nicht pro Seite neu timen)

  • 14,5s bei 60fps, 1440×1152. Flug 0–8,2s · Aufstieg 7,75–9,25s · Überkopf 9,25–9,47s · Tauchgang 9,47–9,97s · Titelcard 9,97–14,5s.
  • Eine Kamera, nie ein Schnitt. Brennweite 1880px, 56° Neigung, Abstand mit Ease-Out 1360→1700px, niemals drehend. Geschwindigkeit entlang der Seite ist eine integrierte Kurve (Anteil an Reisegeschwindigkeit): 0 → 0,5 bis 0,6s, gehalten bis 1,25s, 1,0 bis 1,6s, gehalten bis 7,3s, Ease-Out auf 0,12 bis 8,3s. Die Reisegeschwindigkeit wird so gelöst, dass die Footer-Überschrift bei 8,0s scharf ist; lange Seiten gleiten daher schneller.
  • Tiefenschärfe pro Pixel: Unschärfe = 75·(Fokus−Tiefe)/Tiefe vorne, 6·(Tiefe−Fokus)/Tiefe hinten, gedeckelt bei 120px; 40 Golden-Angle-Taps aus Mip-Ebenen, rotiert pro Bewegungsunschärfe-Unterframe; Nahfeld-Unschärfe aufgeweitet, sodass unscharfer Vordergrund über scharfen Hintergrund läuft.
  • Gehobene Stücke richten sich um ihre eigene Mitte auf (obere Kante zur Linse) und werfen einen Schatten: das gleiche Bild in flachem #1a2133, versetzt um (0.10z, 4+0.36z), unscharf 7+0.5z, 26%.
  • Aufstieg: logarithmisch skalierter Zoom auf einer trapezförmigen Geschwindigkeit, Neigungsabflachung 8,15–8,95s, Übergabe an eine Kamera, die die untere Kante der Seite 42px über dem Frame festhält. Tauchgang: quadratischer Ease-In-Out im logarithmischen Maßstab mit fixierter oberer Kante, dann abgesenkt auf y 283; eine abgerundete Rechteck-Maske wandelt 24px → 38px Ecken. Inhalt unter dem Hero verblasst zuerst in die Dunstfarbe, dann auf transparent.
  • Titel: Badge-Pille blendet bei 10,02s ein (y 44); Zeile 1 ab 10,12s ein Wort alle 0,06s; Nachsatz ab 10,36s ein Wort alle 0,05s; jedes Wort steigt 16px aus einer 12px Unschärfe in 0,34s empor. Halten mit einem 2% Kriechen.

Verboten: Schnitte, Überblendungen, Stopps oder Beschleunigungen im Gleitflug, die Kamera drehen oder seitlich schwenken, während des Flugs hineinzoomen, Glüheffekte, jeglicher Text über der Seite vor der Endkarte.

Fallstricke

  • Riesige Seiten: Die Basisplatte wird stückweise erfasst, nie ein einzelner Screenshot. Wenn der Hero auf halber Höhe wiederholt erscheint, hat ein Capture 16384 Geräte-Pixel überschritten.
  • Scrollgesteuerte Seiten: Sticky-Runways werden automatisch zusammengefaltet; Wort-für-Wort-Scroll-Hervorhebungen benötigen eine css-Regel, die volle Deckkraft erzwingt.
  • Videos: Sie werden bei videoTime Sekunden eingefroren. Falls das Video der Live-Seite mit 404 antwortet, erhältst du eine schwarze Karte; lege ein lokales Poster über routes aus.
  • Ausblendende Karten zeigen, was dahinter liegt. Blende daher zuerst zur Dunstfarbe aus (die Engine macht das für alles unterhalb des Hero).
  • Zeile 1 zu lang: Wörter laufen bei 74pt aus dem Frame. Verkürze die Zeile, anstatt die Schrift zu verkleinern.
  • Lizenzierung: Die Musik bleibt in der Verantwortung des Benutzers; bevorzuge Tracks, deren Lizenz kommerzielle Videos abdeckt.

Verwandte Skills