HyperFrames
HTML ist die Quelle der Wahrheit für Video. Eine Komposition ist eine HTML-Datei mit data-*-Attributen für das Timing, einer GSAP-Timeline für Animationen und CSS für das Aussehen. Das Framework kümmert sich um die Sichtbarkeit der Clips, die Medienwiedergabe und die Synchronisation der Timeline.
Vorgehen
Bevor Sie HTML schreiben, denken Sie auf hoher Ebene:
- Was — was soll der Betrachter erleben? Identifizieren Sie den narrativen Bogen, die Schlüsselmomente und die emotionalen Beats.
- Struktur — wie viele Kompositionen, welche sind Unterkompositionen vs. inline, welche Spuren transportieren was (Video, Audio, Overlays, Untertitel).
- Timing — welche Clips bestimmen die Dauer, wo landen Übergänge, wie ist das Tempo.
- Layout — bauen Sie zuerst den Endzustand. Siehe „Layout vor Animation“ unten.
- Animieren — fügen Sie dann Bewegung mit den folgenden Regeln hinzu.
Für kleine Änderungen (Farbe korrigieren, Timing anpassen, ein Element hinzufügen) gehen Sie direkt zu den Regeln.
Visuelle Identitätstor
Überprüfen Sie in dieser Reihenfolge:
- Gibt es DESIGN.md im Projekt? → Lesen Sie es. Verwenden Sie seine genauen Farben, Schriftarten, Bewegungsregeln und „Was NICHT zu tun ist“-Vorgaben.
- Gibt es visual-style.md? → Lesen Sie es. Wenden Sie seinen
style_prompt_fullund die strukturierten Felder an. (Hinweis:visual-style.mdist eine projektspezifische Datei.visual-styles.mdist die Stilbibliothek mit 8 benannten Presets — unterschiedliche Dateien.) - Hat der Benutzer einen Stil genannt (z. B. „Swiss Pulse“, „dark and techy“, „Luxusmarke“)? → Lesen Sie visual-styles.md für die 8 benannten Presets. Generieren Sie eine minimale DESIGN.md mit:
## Style Prompt(ein Absatz),## Colors(3-5 Hex-Werte mit Rollen),## Typography(1-2 Schriftfamilien),## Was NICHT zu tun ist(3-5 Anti-Patterns). - Nichts davon? → Stellen Sie 3 Fragen, bevor Sie HTML schreiben:
- Was ist die Stimmung? (explosiv / filmisch / fließend / technisch / chaotisch / warm)
- Helle oder dunkle Leinwand?
- Irgendwelche spezifischen Markenfarben, Schriftarten oder visuellen Referenzen? Generieren Sie dann eine minimale DESIGN.md aus den Antworten.
Jede Komposition muss ihre Palette und Typografie auf eine DESIGN.md, visual-style.md oder explizite Benutzeranweisung zurückführen. Wenn Sie nach #333, #3b82f6 oder Roboto greifen — haben Sie diesen Schritt übersprungen.
Für Bewegungsvorgaben, Größen, Eintrittsmuster und Easing — folgen Sie house-style.md. Der Hausstil behandelt WIE sich Dinge bewegen. Die DESIGN.md behandelt WIE Dinge aussehen.
Layout vor Animation
Positionieren Sie jedes Element dort, wo es in seinem sichtbarsten Moment sein soll — dem Frame, in dem es vollständig eingetreten, korrekt platziert und noch nicht austretend ist. Schreiben Sie dies zuerst als statisches HTML+CSS. Noch kein GSAP.
Warum das wichtig ist: Wenn Sie Elemente in ihrem animierten Startzustand (außerhalb des Bildschirms, auf 0 skaliert, Deckkraft 0) positionieren und sie dorthin tweenen, wo sie Ihrer Meinung nach landen sollen, raten Sie das endgültige Layout. Überlappungen sind unsichtbar, bis das Video gerendert wird. Indem Sie den Endzustand zuerst erstellen, können Sie Layoutprobleme sehen und beheben, bevor Sie Bewegung hinzufügen.
Der Prozess
- Identifizieren Sie den Helden-Frame für jede Szene — den Moment, in dem die meisten Elemente gleichzeitig sichtbar sind. Dies ist das Layout, das Sie erstellen.
- Schreiben Sie statisches CSS für diesen Frame. Der
.scene-content-Container MUSS die gesamte Szene ausfüllen, mitwidth: 100%; height: 100%; padding: Npx;unddisplay: flex; flex-direction: column; gap: Npx; box-sizing: border-box. Verwenden Sie Padding, um Inhalt nach innen zu schieben — NIEMALSposition: absolute; top: Npxauf einem Inhaltscontainer. Absolut positionierte Inhaltscontainer laufen über, wenn der Inhalt höher als der verbleibende Platz ist. Reservieren Sieposition: absolutenur für Dekorationen. - Fügen Sie Eintritte mit
gsap.from()hinzu — animieren Sie VON außerhalb des Bildschirms/unsichtbar ZUR CSS-Position. Die CSS-Position ist die Grundwahrheit; der Tween beschreibt die Reise dorthin. - Fügen Sie Austritte mit
gsap.to()hinzu — animieren Sie ZU außerhalb des Bildschirms/unsichtbar VON der CSS-Position.
Beispiel
/* scene-content füllt die Szene, Padding positioniert den Inhalt */
.scene-content {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
height: 100%;
padding: 120px 160px;
gap: 24px;
box-sizing: border-box;
}
.title {
font-size: 120px;
}
.subtitle {
font-size: 42px;
}
/* Container füllt jede Szenengröße (1920x1080, 1080x1920, etc.).
Padding positioniert den Inhalt. Flex + Gap handhabt den Abstand. */
FALSCH — hartcodierte Abmessungen und absolute Positionierung:
.scene-content {
position: absolute;
top: 200px;
left: 160px;
width: 1920px;
height: 1080px;
display: flex; /* ... */
}
// Schritt 3: Animieren IN diese Positionen
TL.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
TL.from(".subtitle", { y: 40, opacity: 0, duration: 0.5, ease: "power3.out" }, 0.2);
TL.from(".logo", { scale: 0.8, opacity: 0, duration: 0.4, ease: "power2.out" }, 0.3);
// Schritt 4: Animieren AUS diesen Positionen
TL.to(".title", { y: -40, opacity: 0, duration: 0.4, ease: "power2.in" }, 3);
TL.to(".subtitle", { y: -30, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.1);
TL.to(".logo", { scale: 0.9, opacity: 0, duration: 0.3, ease: "power2.in" }, 3.2);
Wenn Elemente sich Raum über die Zeit teilen
Wenn Element A austritt, bevor Element B im selben Bereich eintritt, sollten beide korrekte CSS-Positionen für ihre jeweiligen Helden-Frames haben. Die Timeline-Reihenfolge garantiert, dass sie niemals visuell koexistieren — aber wenn Sie den Layout-Schritt überspringen, werden Sie nicht den Fall bemerken, dass sie aufgrund eines Timing-Fehlers versehentlich überlappen.
Was als beabsichtigte Überlappung gilt
Geschichtete Effekte (Glühen hinter Text, Schattenelemente, Hintergrundmuster) und Z-gestapelte Designs (Kartenstapel, Tiefenschichten) sind beabsichtigt. Der Layout-Schritt dient dazu, unbeabsichtigte Überlappungen zu erkennen — zwei Überschriften, die übereinander landen, eine Statistik, die ein Label bedeckt, Inhalt, der aus dem Frame läuft.
Datenattribute
Alle Clips
| Attribut | Erforderlich | Werte |
|---|---|---|
id | Ja | Eindeutige Kennung |
data-start | Ja | Sekunden oder Clip-ID-Referenz ("el-1", "intro + 2") |
data-duration | Erforderlich für img/div/Kompositionen | Sekunden. Video/Audio verwendet standardmäßig die Medienlänge. |
data-track-index | Ja | Ganzzahl. Clips auf derselben Spur können sich nicht überlappen. |
data-media-start | Nein | Trim-Offset in die Quelle (Sekunden) |
data-volume | Nein | 0-1 (Standard 1) |
data-track-index beeinflusst nicht die visuelle Schichtung — verwenden Sie CSS z-index.
Kompositions-Clips
| Attribut | Erforderlich | Werte |
|---|---|---|
data-composition-id | Ja | Eindeutige Kompositions-ID |
data-start | Ja | Startzeit (Root-Komposition: verwenden Sie "0") |
data-duration | Ja | Hat Vorrang vor der GSAP-Timeline-Dauer |
data-width / data-height | Ja | Pixelabmessungen (1920x1080 oder 1080x1920) |
data-composition-src | Nein | Pfad zur externen HTML-Datei |
Kompositionsstruktur
Sub-Kompositionen, die über data-composition-src geladen werden, verwenden einen <template>-Wrapper. Eigenständige Kompositionen (die main index.html) verwenden KEIN <template> — sie setzen das data-composition-id-div direkt in <body>. Die Verwendung von <template> in einer eigenständigen Datei verbirgt den gesamten Inhalt vor dem Browser und bricht das Rendering.
Sub-Kompositionsstruktur:
<template id="my-comp-template">
<div data-composition-id="my-comp" data-width="1920" data-height="1080">
<!-- Inhalt -->
<style>
[data-composition-id="my-comp"] {
/* begrenzte Stile */
}
</style>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// Tweens...
window.__timelines["my-comp"] = tl;
</script>
</div>
</template>
Laden in der Root: <div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="10" data-track-index="1"></div>
Video und Audio
Video muss muted playsinline sein. Audio ist immer ein separates <audio>-Element:
<video
id="el-v"
data-start="0"
data-duration="30"
data-track-index="0"
src="video.mp4"
muted
playsinline
></video>
<audio
id="el-a"
data-start="0"
data-duration="30"
data-track-index="2"
src="video.mp4"
data-volume="1"
></audio>
Timeline-Vertrag
- Alle Timelines starten mit
{ paused: true }— der Player steuert die Wiedergabe - Registrieren Sie jede Timeline:
window.__timelines["<composition-id>"] = tl - Das Framework verschachtelt Unter-Timelines automatisch — fügen Sie sie NICHT manuell hinzu
- Die Dauer stammt von
data-duration, nicht von der GSAP-Timeline-Länge - Erstellen Sie niemals leere Tweens, um die Dauer festzulegen
Regeln (Nicht verhandelbar)
Deterministisch: Kein Math.random(), Date.now() oder zeitbasierte Logik. Verwenden Sie einen gesäten PRNG, wenn Sie pseudo-zufällige Werte benötigen (z. B. mulberry32).
GSAP: Animieren Sie nur visuelle Eigenschaften (opacity, x, y, scale, rotation, color, backgroundColor, borderRadius, Transformationen). Animieren Sie NICHT visibility, display oder rufen Sie video.play()/audio.play() auf.
Animationskonflikte: Animieren Sie niemals dieselbe Eigenschaft desselben Elements aus mehreren Timelines gleichzeitig.
Kein repeat: -1: Endlos-Wiederholungstimelines brechen die Capture-Engine. Berechnen Sie die genaue Wiederholungsanzahl aus der Kompositionsdauer: repeat: Math.ceil(duration / cycleDuration) - 1.
Synchrone Timeline-Konstruktion: Erstellen Sie Timelines niemals innerhalb von async/await, setTimeout oder Promises. Die Capture-Engine liest window.__timelines synchron nach dem Laden der Seite. Schriftarten werden vom Compiler eingebettet, sodass sie sofort verfügbar sind — kein Warten auf das Laden von Schriftarten erforderlich.
Niemals tun:
- Vergessen Sie die
window.__timelines-Registrierung - Verwenden Sie Video für Audio — immer stummgeschaltetes Video + separates
<audio> - Verschachteln Sie Video in einem getimten Div — verwenden Sie einen nicht getimten Wrapper
- Verwenden Sie
data-layer(verwenden Siedata-track-index) oderdata-end(verwenden Siedata-duration) - Animieren Sie die Abmessungen eines Videoelements — animieren Sie ein Wrapper-Div
- Rufen Sie play/pause/seek für Medien auf — das Framework besitzt die Wiedergabe
- Erstellen Sie einen Container der obersten Ebene ohne
data-composition-id - Verwenden Sie
repeat: -1bei einer Timeline oder einem Tween — immer endliche Wiederholungen - Erstellen Sie Timelines asynchron (innerhalb von
async,setTimeout,Promise) - Verwenden Sie
gsap.set()für Clip-Elemente aus späteren Szenen — sie existieren zum Zeitpunkt des Seitenladens nicht im DOM. Verwenden Sie stattdessentl.set(selector, vars, timePosition)innerhalb der Timeline zum oder nach demdata-start-Zeitpunkt des Clips. - Verwenden Sie
<br>im Textinhalt — erzwungene Zeilenumbrüche berücksichtigen nicht die tatsächliche gerenderte Schriftbreite. Text, der natürlich umbricht + ein<br>, erzeugt einen zusätzlichen unerwünschten Umbruch, der zu Überlappung führt. Lassen Sie Text stattdessen übermax-widthumbrechen. Ausnahme: kurze Anzeigetitel, bei denen jedes Wort absichtlich in einer eigenen Zeile steht (z. B. „THE\nIMMORTAL\nGAME" bei 130px).
Szenenübergänge (Nicht verhandelbar)
Jede Multi-Szenen-Komposition MUSS ALLE diese Regeln befolgen. Die Verletzung auch nur einer davon ist eine fehlerhafte Komposition.
- Verwenden Sie IMMER Übergänge zwischen den Szenen. Keine Jump Cuts. Keine Ausnahmen.
- Verwenden Sie IMMER Eintrittsanimationen für jede Szene. Jedes Element animiert via
gsap.from()EIN. Kein Element darf vollständig ausgebildet erscheinen. Wenn eine Szene 5 Elemente hat, benötigt sie 5 Eintritts-Tweens. - Verwenden Sie NIEMALS Austrittsanimationen, außer in der letzten Szene. Das bedeutet: KEIN
gsap.to(), das die Deckkraft auf 0, y aus dem Bildschirm, Skalierung auf 0 oder irgendeine andere „Aus“-Animation vor dem Auslösen eines Übergangs animiert. Der Übergang IST der Austritt. Der Inhalt der ausgehenden Szene MUSS in dem Moment, in dem der Übergang startet, vollständig sichtbar sein. - Nur die letzte Szene: Die letzte Szene darf Elemente ausblenden (z. B. Überblendung nach Schwarz). Dies ist die EINZIGE Szene, in der
gsap.to(..., { opacity: 0 })erlaubt ist.
FALSCH — Austrittsanimation vor dem Übergang:
// VERBOTEN — dies entleert die Szene, bevor der Übergang sie verwenden kann
TL.to("#s1-title", { opacity: 0, y: -40, duration: 0.4 }, 6.5);
TL.to("#s1-subtitle", { opacity: 0, duration: 0.3 }, 6.7);
// Übergang feuert auf leerem Frame
RICHTIG — nur Eintritt, Übergang behandelt Austritt:
// Eintrittsanimationen Szene 1
TL.from("#s1-title", { y: 50, opacity: 0, duration: 0.7, ease: "power3.out" }, 0.3);
TL.from("#s1-subtitle", { y: 30, opacity: 0, duration: 0.5, ease: "power2.out" }, 0.6);
// KEINE Austritts-Tweens — Übergang bei 7,2s behandelt den Szenenwechsel
// Eintrittsanimationen Szene 2
TL.from("#s2-heading", { x: -40, opacity: 0, duration: 0.6, ease: "expo.out" }, 8.0);
Animationsleitplanken
- Versetzen Sie die erste Animation um 0,1-0,3 s (nicht t=0)
- Variieren Sie die Easing-Funktionen über die Eintritts-Tweens hinweg — verwenden Sie mindestens 3 verschiedene Easing-Funktionen pro Szene
- Wiederholen Sie kein Eintrittsmuster innerhalb einer Szene
- Vermeiden Sie Vollbild-lineare Farbverläufe auf dunklen Hintergründen (H.264-Banding — verwenden Sie radial oder einfarbig + lokalisiertes Glühen)
- 60px+ Überschriften, 20px+ Fließtext, 16px+ Datenbeschriftungen für gerendertes Video
font-variant-numeric: tabular-numsbei Zahlenspalten
Wenn keine visual-style.md oder Animationsanweisung gegeben ist, folgen Sie house-style.md für ästhetische Standardeinstellungen.
Typografie und Assets
- Schriftarten: Schreiben Sie einfach die gewünschte
font-familyin CSS — der Compiler bettet unterstützte Schriftarten automatisch ein. Wenn eine Schriftart nicht unterstützt wird, warnt der Compiler. - Fügen Sie
crossorigin="anonymous"zu externen Medien hinzu - Für