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 Erscheinungsbild. Das Framework kümmert sich um Clip-Sichtbarkeit, Medienwiedergabe und Timeline-Synchronisation.
Open Design Integration (tragend für diese Oberfläche)
Wenn dieses Skill innerhalb von Open Design ausgeführt wird (d.h. $OD_PROJECT_DIR ist gesetzt), ist der Ausgabefluss festgelegt: Nur die gerenderte .mp4-Datei soll im Projektstamm landen. Die Quellcodedateien der Komposition (hyperframes.json, meta.json, index.html, Assets) gehören in ein verstecktes Cache-Verzeichnis, damit sie die Dateiansicht des Benutzers oder die "erzeugten Dateien"-Chips im Chat nicht überladen.
Render-Workflow innerhalb von OD – schneller Pfad:
Für die meisten OD-Anfragen ("Testvideo", "5s Produktvorstellung", "Demo-Clip") NICHT die Komposition HTML von Grund auf neu schreiben. Verwenden Sie das integrierte Gerüst von HyperFrames und bearbeiten Sie nur das, was die Eingabeaufforderung tatsächlich ändert. Der Pfad "von Grund auf neu schreiben" kostet Minuten an Modellausgabe und stille Chat-Tool-Zeit; der Gerüstpfad kostet Sekunden.
# 1. Wähle einen versteckten Cache-Slot. Das Punkt-Präfix sorgt dafür, dass ODs
# Projektdateiliste es überspringt, sodass die Quelldateien den Chat nie überladen.
COMP_REL=".hyperframes-cache/$(date +%s)-$(openssl rand -hex 2)"
COMP="$OD_PROJECT_DIR/$COMP_REL"
# 2. Hol dir ein sofort renderbares Gerüst (hyperframes.json,
# meta.json, index.html mit GSAP CDN + bereits registrierter
# window.__timelines.main). Dies wird in deiner Shell ausgeführt – reine
# Dateikopie, kein Chrome, kein Netzwerk außer dem npx-Cache.
npx hyperframes init "$COMP" --example blank --skip-skills --non-interactive
# 3. Bearbeite NUR $COMP/index.html – ändere `data-duration` im Root-Element,
# wenn du eine nicht standardmäßige Länge benötigst, tausche die Platzhalter-Palette
# in <style>, füge 1–3 Clip-<div>s für Text/Bilder hinzu und hänge die passenden
# GSAP-Tweens an den bestehenden
# `window.__timelines["main"] = gsap.timeline({paused:true})`-Block an.
# Halte die Bearbeitungen minimal; das Gerüst ist bereits gültiges HF.
# 4. Sende den Render-Auftrag über den OD-Daemon. Führe NICHT `npx hyperframes
# render` von dieser Shell aus – der Daemon führt es für dich in einem
# unsandboxed-Prozess aus. (Viele Agent-CLIs, insbesondere Claude Code,
# wrappen Bash in macOS sandbox-exec, unter dem puppeteers Chrome-Subprozess
# während der Frame-Erfassung teilweise hängt. Der Daemon-Prozess ist
# unsandboxed, daher werden Renderings zuverlässig abgeschlossen.)
#
# Der Dispatcher kehrt innerhalb von ~1s mit einem {taskId} zurück; treibe das
# Rendering durch wiederholte Aufrufe von `"$OD_NODE_BIN" "$OD_BIN" media wait <taskId>`.
# Jeder Aufruf long-pollt bis zu 25s (weit unter dem standardmäßigen 30s-Limit
# deines Shell-Tools) und beendet sich mit 0/2/5 für fertig/laufend/fehlgeschlagen.
out=$("$OD_NODE_BIN" "$OD_BIN" media generate \
--project "$OD_PROJECT_ID" \
--surface video \
--model hyperframes-html \
--output "<descriptive-name>.mp4" \
--composition-dir "$COMP_REL")
ec=$?
task_id=$(printf '%s\n' "$out" | tail -1 | jq -r '.taskId // empty')
since=$(printf '%s\n' "$out" | tail -1 | jq -r '.nextSince // 0')
while [ "$ec" -eq 2 ] && [ -n "$task_id" ]; do
out=$("$OD_NODE_BIN" "$OD_BIN" media wait "$task_id" --since "$since")
ec=$?
since=$(printf '%s\n' "$out" | tail -1 | jq -r '.nextSince // '"$since")
done
["$ec" -ne 0 ] && { echo "$out" >&2; exit "$ec"; }
Jeder generate- und jeder wait-Aufruf dauert maximal ~25s, sodass das standardmäßige ~30s-Limit des Agent-Shell-Tools niemals greift. Fortschrittszeilen von HF (Capturing frame N/M) werden live während der Schleife auf stderr gestreamt. Wenn das Rendern abgeschlossen ist, ist die letzte stdout-Zeile {"file": { "name": "<output>", "size": …, "kind": "video", … }} – zitiere file.name in deiner Antwort, damit der Benutzer weiß, was erzeugt wurde.
Überspringe das Visual Identity Gate innerhalb von OD. Der HARD-GATE-Abschnitt unten (unter "Ansatz") sagt dir, dass du DESIGN.md / visual-style.md lesen oder anhalten und 3 Stimmungsfragen stellen sollst, bevor du eine Komposition schreibst. Dieses Gate gilt für eigenständige HF-Projekte. OD-Projekte haben bereits ihre eigene Design-System-Schicht – der Benutzer hat seine visuelle Richtung bei der Projekterstellung gewählt. Für einen OD-Test-Render verwende standardmäßig: dunkle Leinwand (#0b0b0f), einen warmen Akzent (#ffb76b), einen kühlen Akzent (#7da4ff), zurückhaltende Bewegung. Frage nur nach stilistischen Angaben, wenn die Eingabe des Benutzers zu vage ist, um überhaupt ein Thema auszuwählen (sehr selten).
Wann das Gerüst übersprungen und von Grund auf geschrieben werden soll: nur wenn der Benutzer explizit etwas verlangt, das die leere Vorlage offensichtlich nicht beherbergen kann (z. B. Multi-Kompositions-Timelines, audio-reaktive Overlays, mit einer bereits generierten TTS-Spur synchronisierte Untertitel). Für alles andere ist init + edit der Standardpfad.
Die leichteren HF-Unterbefehle, die du weiterhin von deiner eigenen Shell aus ausführen KANNST (sie benötigen kein Chrome):
npx hyperframes lint "$COMP"– Komposition vor dem Dispatch validierennpx hyperframes transcribe <audio>– Untertitel generierennpx hyperframes tts <text>– Erzählung generieren
Reserviere den Daemon-Dispatch für render/inspect/preview (alles, was Chrome benötigt).
Rufe NICHT "$OD_NODE_BIN" "$OD_BIN" media generate --model hyperframes-html auf – dieser Dispatcher-Pfad gibt absichtlich eine 400 (AGENT_RENDERED) zurück. HyperFrames wird von dir direkt über npx gerendert.
Lege NICHT hyperframes.json / meta.json / index.html im Projektstamm ab; ODs Dateiliste scannt rekursiv und der Benutzer würde drei nicht verwandte Dateien im Chat sehen.
Rufe für CLI-Optionen außerhalb von render (lint, preview, transcribe, tts, inspect, benchmark) diese direkt von deinem Shell-Tool aus, wenn die Aufgabe es rechtfertigt (z. B. TTS-Audio in den Cache generieren, bevor du in der Komposition darauf verweist).
Ansatz
Bevor du HTML schreibst, denke auf hohem Niveau:
- Was – was soll der Betrachter erleben? Identifiziere den narrativen Bogen, Schlüsselmomente und emotionale Schwerpunkte.
- Struktur – wie viele Kompositionen, welche sind Unterkompositionen vs. inline, welche Spuren tragen was (Video, Audio, Overlays, Untertitel).
- Timing – welche Clips bestimmen die Dauer, wo liegen die Übergänge, wie ist die Taktung.
- Layout – baue zuerst den Endzustand. Siehe "Layout vor Animation" unten.
- Animieren – füge dann Bewegung mit den untenstehenden Regeln hinzu.
Für kleine Änderungen (Farbe korrigieren, Timing anpassen, ein Element hinzufügen), gehe direkt zu den Regeln.
Gate der Visuellen Identität
Überprüfe in dieser Reihenfolge:
- Existiert DESIGN.md im Projekt? → Lies es. Verwende seine exakten Farben, Schriftarten, Bewegungsregeln und die "Was NICHT zu tun ist"-Einschränkungen.
- Existiert visual-style.md? → Lies es. Wende sein
style_prompt_fullund die strukturierten Felder an. (Hinweis:visual-style.mdist eine projektspezifische Datei.visual-styles.mdist die Stilbibliothek mit 8 benannten Voreinstellungen – verschiedene Dateien.) - Hat der Benutzer einen Stil genannt (z.B. "Swiss Pulse", "dunkel und technisch", "Luxusmarke")? → Lese visual-styles.md für die 8 benannten Voreinstellungen. Generiere ein minimales DESIGN.md mit:
## Style Prompt(ein Absatz),## Colors(3-5 Hex-Werte mit Rollen),## Typography(1-2 Schriftfamilien),## What NOT to Do(3-5 Anti-Patterns). - Nichts davon? → Stelle 3 Fragen, bevor du HTML schreibst:
- Was ist die Stimmung? (explosiv / filmisch / fließend / technisch / chaotisch / warm)
- Helle oder dunkle Leinwand?
- Irgendwelche spezifischen Markenfarben, Schriftarten oder visuellen Referenzen? Generiere dann aus den Antworten ein minimales DESIGN.md.
Jede Komposition muss ihre Palette und Typografie auf eine DESIGN.md, visual-style.md oder explizite Benutzeranweisung zurückführen. Wenn du nach #333, #3b82f6 oder Roboto greifst – hast du diesen Schritt übersprungen.
Für Bewegungsstandards, Größen, Eintrittsmuster und Easing – folge house-style.md. Der Haus-Stil kümmert sich darum, WIE sich Dinge bewegen. Die DESIGN.md kümmert sich darum, WIE die Dinge aussehen.
Layout vor Animation
Positioniere jedes Element dort, wo es in seinem sichtbarsten Moment sein soll – der Frame, in dem es vollständig eingetreten, korrekt platziert und noch nicht am Verlassen ist. Schreibe dies zuerst als statisches HTML+CSS. Noch kein GSAP.
Warum das wichtig ist: Wenn du Elemente in ihrem animierten Startzustand positionierst (außerhalb des Bildschirms, auf 0 skaliert, Deckkraft 0) und sie dorthin tweenst, wo sie deiner Meinung nach landen sollen, rätst du das endgültige Layout. Überlappungen sind unsichtbar, bis das Video gerendert wird. Indem du zuerst den Endzustand baust, kannst du Layoutprobleme sehen und beheben, bevor du Bewegung hinzufügst.
Der Prozess
- Identifiziere den Helden-Frame für jede Szene – den Moment, in dem die meisten Elemente gleichzeitig sichtbar sind. Dies ist das Layout, das du baust.
- Schreibe statisches CSS für diesen Frame. Der
.scene-content-Container MUSS die gesamte Szene mitwidth: 100%; height: 100%; padding: Npx;füllen, mitdisplay: flex; flex-direction: column; gap: Npx; box-sizing: border-box. Verwende Padding, um Inhalt nach innen zu drücken – NIEMALSposition: absolute; top: Npxauf einem Inhaltscontainer. Absolut positionierte Inhaltscontainer laufen über, wenn der Inhalt höher ist als der verbleibende Platz. Reserviereposition: absolutenur für dekorative Elemente. - Füge Eintritte mit
gsap.from()hinzu – animiere VON außerhalb des Bildschirms/unsichtbar ZUR CSS-Position. Die CSS-Position ist die Grundwahrheit; der Tween beschreibt die Reise dorthin. - Füge Austritte mit
gsap.to()hinzu – animiere 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: In diese Positionen hinein animieren
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: Aus diesen Positionen heraus animieren
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 den 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 nie visuell koexistieren – aber wenn du den Layout-Schritt überspringst, wirst du den Fall nicht bemerken, in dem sie aufgrund eines Timing-Fehlers versehentlich überlappen.
Was als beabsichtigte Überlappung gilt
Geschichtete Effekte (Glanz hinter Text, Schattenelemente, Hintergrundmuster) und Z-Stack-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 Rahmen 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 standardmäßig auf Mediendauer. |
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 – verwende CSS z-index.
Kompositions-Clips
| Attribut | Erforderlich | Werte |
|---|---|---|
data-composition-id | Ja | Eindeutige Kompositions-ID |
data-start | Ja | Startzeit (Root-Komposition: verwende "0") |
data-duration | Ja | Überschreibt die GSAP-Timeline-Dauer |
data-width / data-height | Ja | Pixelabmessungen (1920x1080 oder 1080x1920) |
data-composition-src | Nein | Pfad zur externen HTML-Datei |
Kompositionsstruktur
Unterkompositionen, die über data-composition-src geladen werden, verwenden einen <template>-Wrapper. Eigenständige Kompositionen (die main index.html) verwenden KEINEN <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 unterbricht das Rendering.
Unterkompositionsstruktur:
<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 im Root: <div id="el-1" data-composition-id="my-comp" data-composition-src="compositions/my-comp.html" data-start="0" data-duration="5"></div>
Standardregeln für Animationen
Eigenschaften
| Eigenschaft | Standardwert | Alternative Optionen im Haus-Stil |
|---|---|---|
ease | "power2.out" | power1, power3, power4, back, elastic, custom |
duration | 0.5s | 0.2–2.0s |
scale | 1.0 | 1.2, 0 (bei Exit), auto |
opacity | 1 | 0 (bei Exit) |
Standard-GSAP-Entrance-Patterns
| Pattern | Beschreibung |
|---|---|
".from" | Von außerhalb des Bildschirms hinein animieren |
".fromTo" | Bestimmte Start- und Endwerte festlegen |
".set" | Sofortige Positionierung ohne Animation |
".to" | Aus aktueller Position heraus animieren |
Beispiel einer Standardbewegung
// Element fliegt von unten herein und wird in Position eingeblendet
tl.from(".title", { y: 60, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
Nächste Schritte
- Siehe house-style.md für vollständige Bewegungsrichtlinien.
- Siehe visual-styles.md für benannte visuelle Voreinstellungen.
- Verwende
npx hyperframes init --helpfür die CLI-Startoptionen.