D0 HyperFrame Videoproduktion
Vollständiger Workflow zur Erstellung von D0-Brandvideos mit HyperFrames HTML + GSAP. Dieses Dokument ist die einzige autoritative Quelle – Schriftarten, Farben, Layouts, Animationen und Übergangsregeln sind hier definiert.
Die Schriftarten-Spezifikation des
d0-brand-Skills ist die endgültige Autorität; dieses Skill überschreibt nur die videospezifischen Ergänzungen.
Auslösewörter
- „Erstelle ein D0-Video“ / „d0 hyperframe“
- „Erstelle Video mit Hyperframes“ / „/d0-hyperframe“
Schritt 0 – Projekt & Assets initialisieren
Empfohlen: Mit dem zum Skill gehörenden Initialisierungsskript
Nach der Installation des Repos führe das Skript innerhalb dieses Skills aus. Es initialisiert das HyperFrames-Projekt und kopiert das D0-Logo, den D0-Avatar und alle erforderlichen Schriftarten:
bash "${CODEX_HOME:-$HOME/.codex}/skills/d0-hyperframe/scripts/bootstrap_project.sh" .
Falls das Projekt bereits initialisiert ist, nur die Brand-Assets synchronisieren:
bash "${CODEX_HOME:-$HOME/.codex}/skills/d0-hyperframe/scripts/bootstrap_project.sh" . --assets-only
Das Skript benötigt Node.js 18+ und npx. Die HyperFrames-CLI wird bei Bedarf über npx hyperframes@latest ausgeführt, es werden keine Drittanbieterpakete im Skill-Repo kopiert.
Optional: D0_AVATAR und Logo aus der Quell-HTML überschreiben
D0_AVATAR und Logo aus der Quell-HTML extrahieren
Das Quell-Poster-HTML enthält normalerweise zwei Arten von Base64-Bildern:
| Asset | Typ | Merkmal | Verwendung |
|---|---|---|---|
| D0-Logo | PNG, ca. 12–16 KB | .brand img oder kürzestes PNG | Linke obere Ecke aller Szenen |
| D0_AVATAR | JPEG, ca. 100 KB | .av oder längstes JPEG | TG-Komponenten-Avatar |
python3 - << 'EOF'
import re, base64, os
with open('SOURCE.html', 'r') as f:
src = f.read()
os.makedirs('assets', exist_ok=True)
# Logo (kürzestes PNG)
pngs = re.findall(r'(data:image/png;base64,[A-Za-z0-9+/=]+)', src)
logo_b64 = min(pngs, key=len)
with open('assets/d0-logo.png', 'wb') as f:
f.write(base64.b64decode(logo_b64.split(',')[1]))
# D0_AVATAR (längstes JPEG)
jpegs = re.findall(r'data:image/jpeg;base64,([A-Za-z0-9+/=]+)', src)
avatar = max(jpegs, key=len)
with open('assets/d0-avatar.jpg', 'wb') as f:
f.write(base64.b64decode(avatar))
print("assets/ ready:", os.listdir('assets'))
EOF
Schriftarten (manuell)
mkdir -p fonts
cp /path/to/d0-hyperframe/assets/fonts/*.woff2 fonts/
# Benötigt: InstrumentSerif-Regular.woff2, InstrumentSerif-Italic.woff2
# OpenSans-400/600/700/800-normal.woff2
Projektinitialisierung (manuell)
npx hyperframes@latest init . --non-interactive --example blank --skill=d0-hyperframe
Schritt 1 – Brand-Tokens (CSS)
:root {
--bg: #06060d;
--pu2: #b3a8f7;
--white: #f2f2f5;
--t2: #8d8d98;
--t3: #5a5a66;
--green: #3ddc84;
--red: #f87171;
--gold: #f7a93a;
--bdr: #23232c;
--bdr2: #2e2e39;
--grad: linear-gradient(120deg, #5468F5 0%, #9B4FD6 34%, #C25C9A 62%, #DD8B57 100%);
}
@font-face { font-family:'Instrument Serif'; src:url('fonts/InstrumentSerif-Regular.woff2') format('woff2'); font-weight:400; font-style:normal; }
@font-face { font-family:'Instrument Serif'; src:url('fonts/InstrumentSerif-Italic.woff2') format('woff2'); font-weight:400; font-style:italic; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-400-normal.woff2') format('woff2'); font-weight:400; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-600-normal.woff2') format('woff2'); font-weight:600; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-700-normal.woff2') format('woff2'); font-weight:700; }
@font-face { font-family:'Open Sans'; src:url('fonts/OpenSans-800-normal.woff2') format('woff2'); font-weight:800; }
Schritt 2 – Bühnenstruktur (persistente Stage + Komponentenschicht)
Kernmodell: Eine feste Hintergrundbühne, Inhalt in Komponenten aufgeteilt. Hintergrund + fixe Elemente (Logo/Footer/obere Schiene) gehören zur persistenten Schicht, bleiben während des gesamten Videos unbewegt; Titel, Daten, TG-Panels, Diagramme usw. sind jeweils eigenständige
.blk-Komponenten, die einzeln ein- und ausgehen. Übergänge finden auf Komponentenebene statt, nicht auf Vollbildebene – das ist die Grundlage, um den „PPT-Hart-Schnitt“ zu vermeiden.
HTML-Grundgerüst
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D0 · [Video-Titel]</title>
<style>/* tokens + scene CSS */</style>
</head>
<body>
<div id="main"
data-composition-id="main"
data-start="0"
data-duration="[Gesamtsekunden]"
data-width="1920"
data-height="1080">
<!-- ── Persistente Schicht: Während des gesamten Videos unbewegt, keine tl-Animation (siehe Schritt 3) ── -->
<div class="bg"></div>
<div class="rail"></div>
<div class="logo"></div>
<div class="foot-tag">Agentic Trading for Every Market.</div>
<div class="foot-url">getdonut.ai</div>
<!-- ── Inhaltsschicht: Nach Beat gruppiert, Komponenten wechseln sich ab (siehe Schritt 6) ── -->
<!-- beat 1 -->
<div class="blk" id="b1-title">...</div>
<div class="blk" id="b1-sub">...</div>
<!-- beat 2 -->
<div class="blk" id="b2-stat">...</div>
<div class="blk" id="b2-tg">...</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>/* GSAP timeline */</script>
</body>
</html>
Bühnen-CSS (persistente Schicht + Inhaltsschicht)
/* Bühnencontainer */
#main {
position: absolute; inset: 0; overflow: hidden;
font-family: 'Open Sans', sans-serif; color: var(--white);
}
/* Persistenter Hintergrund – während des gesamten Videos fix, niemals in tl-Animation einbinden */
.bg {
position: absolute; inset: 0; width: 1920px; height: 1080px; z-index: 0;
background: var(--bg);
background-image:
radial-gradient(ellipse 46% 58% at 76% 50%, rgba(150,128,255,.16) 0%, transparent 60%),
radial-gradient(ellipse 62% 50% at 8% 4%, rgba(110,100,255,.10) 0%, transparent 56%);
}
/* Obere Gradientenschiene – fix, während des gesamten Videos nur eine */
.rail {
position: absolute; top: 0; left: 0; right: 0; height: 5px; z-index: 10;
background: var(--grad);
}
/* Inhaltskomponenten – Minimale Animationseinheit, standardmäßig ausgeblendet, einzeln ein- und ausgehend */
.blk { position: absolute; opacity: 0; z-index: 2; }
Altes Modell: Jeder Vollbild
.scenehatte eigenen Hintergrund, gesamten Block zum Schieben → PPT-Gefühl + Knackpunkte. Neues Modell: Nur eine feste Hintergrundebene, Inhalt in.blk-Komponenten aufgeteilt, Übergänge auf Komponentenebene (siehe Schritt 6).
Schritt 3 – Spezifikation für fixe Elemente (nicht verhandelbar)
Die folgenden drei Elemente bleiben in allen Szenen identisch und erhalten keine Ein- oder Ausgangsanimationen:
| Element | Position | Schriftgröße | Beschreibung |
|---|---|---|---|
| Donut-Logo | Links oben top:40px left:72px | 200×76px | CSS background, kein <img> |
| Agentic Trading for Every Market. | Links unten bottom:48px left:72px | 27px | Instrument Serif italic, --pu2 |
| getdonut.ai | Rechts unten bottom:50px right:72px | 14px | Open Sans, --t3 |
/* Logo – CSS background, kein opacity:0 */
.logo {
position: absolute; top: 40px; left: 72px; z-index: 10;
width: 200px; height: 76px;
background: url('assets/d0-logo.png') left center / contain no-repeat;
}
/* Footer – direkt sichtbar, keine Animation */
.foot-tag {
position: absolute; bottom: 48px; left: 72px; z-index: 10;
font-family: 'Instrument Serif', serif; font-style: italic;
font-size: 27px; color: var(--pu2);
}
.foot-url {
position: absolute; bottom: 50px; right: 72px; z-index: 10;
font-size: 14px; font-weight: 700; letter-spacing: .06em; color: var(--t3); opacity: 0;
}
Feste Elemente gehören zur persistenten Schicht, sind ab Frame 0 sichtbar und erhalten während des gesamten Videos keine tl-Animation.
foot-tagist direkt sichtbar;foot-urlkann ein einmaliges leichtes Einblenden erhalten, ist aber nicht zwingend erforderlich.
Schritt 4 – Layout-Prinzipien
Links-rechts-Ausgleich, zentralen Leerraum vermeiden
- Zweispaltiges Layout bevorzugt: Text/Daten links, TG-Komponenten/Bilder rechts
- Wenn rechts ein Charakter-Hintergrundbild vorhanden ist: Absolut positioniert, füllt die rechte Seite aus, mit einem von links nach rechts verlaufenden Farbverlauf-Maske
.scene-char {
position: absolute; top:0; right:0; bottom:0; width:62%;
background: url('assets/bg-char.png') right center / cover no-repeat;
z-index: 0;
}
.scene-char::after {
content:''; position:absolute; inset:0;
background: linear-gradient(to right,
var(--bg) 0%, rgba(6,6,13,.82) 18%, rgba(6,6,13,.45) 45%, transparent 100%);
}
- Linker Textbereich mit
position: relative; z-index: 2versehen, um sicherzustellen, dass er über dem Hintergrundbild liegt
Mindestschriftgrößen
Basierend auf dem D0 Thorp Engine-Video dürfen folgende Werte nicht unterschritten werden:
| Ebene | Mindestschriftgröße | Schriftart |
|---|---|---|
| Haupttitel | 80px | Instrument Serif |
| Szenen-Untertitel | 56px | Instrument Serif |
| Kick-Label / Eyebrow | 18px | Open Sans 700 uppercase |
| Fließtext / Feature-Bullet | 22px | Open Sans |
| Datenanker (stat-val) | 48px | Instrument Serif |
| Footer-Tag | 27px | Instrument Serif italic |
| TG-Komponententext | 13px (akzeptabler Minimalwert) | Open Sans |
Schritt 5 – TG-Komponenten-Spezifikation
Avatar: Muss D0_AVATAR verwenden
/* Großer Avatar (Header, 40px) */
.av { width:40px; height:40px; border-radius:50%; flex:none;
background: url('assets/d0-avatar.jpg') center/cover no-repeat; }
/* Kleiner Avatar (Nachrichtenzeile, 28px) */
.mav { width:28px; height:28px; border-radius:50%; flex:none; margin-top:2px;
background: url('assets/d0-avatar.jpg') center/cover no-repeat; }
Kein <img>-Tag verwenden, um zu vermeiden, dass HyperFrames doppelte Medienknoten erkennt (Lint-Warnung).
Keinen Farbverlauf als Fallback verwenden, es muss die echte D0_AVATAR-Datei sein.
TG-Panel-Struktur
<div id="tg-panel">
<div class="tg-chrome">
<div class="dot r"></div><div class="dot y"></div><div class="dot g"></div>
<div class="tg-url">t.me / D0_Bot</div>
</div>
<div class="tg-hdr">
<div class="av"></div>
<div>
<div class="tg-nm">D0</div>
<div class="tg-st">bot · online</div>
</div>
</div>
<div class="tg-body">
<div class="msg-user">Benutzer-Prompt</div>
<div class="msg-bot">
<div class="mav"></div>
<div class="bbubble">D0-Antwortinhalt</div>
</div>
</div>
</div>
Schritt 6 – Übergangsregeln (nicht verhandelbar)
Kernprinzip: Hintergrund bleibt unbewegt, Komponenten bewegen sich. "PPT-Gefühl" entsteht, wenn die gesamte
scene(einschließlich Hintergrund) gemeinsam wegschiebt – der Betrachter verliert den stabilen Anker; "Knackpunkte" entstehen, wenn Out-Animation und In-Animation Ende-an-Ende erfolgen – dazwischen gibt es einen Moment totaler Stille. Die Lösung für beides ist derselbe Satz: Fester Hintergrund + Komponenten, die sich überlappend ein- und ausgehen.
Standardübergang: Komponentenübergreifendes Cross-Stagger
Hintergrund + fixe Elemente (Logo/Footer/Rail) bleiben während des gesamten Videos unbewegt. Bei jedem Beat-Wechsel bewegen sich nur die Inhaltskomponenten:
- Alte Beat-Komponenten gehen nacheinander aus (Stagger,
.in-Easing, leichte Verschiebung + Ausblenden) - Neue Beat-Komponenten gehen nacheinander ein (Stagger,
.out-Easing) - Beide überlappen zeitlich ≈ 0,2–0,3s – die alten sind noch nicht vollständig ausgegangen, die neuen beginnen bereits einzugehen. Das ist der Schlüssel zur Beseitigung von Knackpunkten.
// Beat-Wechsel: Alte Komponenten gehen gestaffelt aus, neue gestaffelt ein, zeitliche Überlappung (nicht Ende-an-Ende)
function beat(outEls, inEls, t) {
outEls.forEach((el, i) =>
tl.to(el, { opacity:0, y:-30, duration:0.45, ease:'power2.in' }, t + i*0.06));
inEls.forEach((el, i) =>
tl.fromTo(el, { opacity:0, y:40 },
{ opacity:1, y:0, duration:0.6, ease:'expo.out' }, t + 0.2 + i*0.08)); // +0.2 = Überlappung
}
// Verwendung: beat(['#b1-title','#b1-sub'], ['#b2-stat','#b2-tg'], 4.0);
- Verschiebungen sind klein (20–40px); die Richtung kann einheitlich sein (z. B. alle nach oben), um einen „Seitenlüft-Effekt“ zu erzeugen, aber der Hintergrund nimmt niemals teil.
- Bei vielen Komponenten sorgt das Stagger dafür, dass das Bild ständig in Bewegung bleibt, und vermeidet „gleichzeitiges Einblenden → gemeinsames Einfrieren“.
Wann Vollbild-Übergänge verwendet werden
Nur bei großen Abschnitten (z. B. Brand-Titelkarte → Datenabschnitt) gelegentlich verwenden, und dabei nur die Inhaltsschicht verschieben, nicht den Hintergrund – die Komponenten des Abschnitts in einen #grp-Container packen und verschieben:
// Push-Slide (nur Inhaltscontainer verschieben, Hintergrund .bg unbewegt)
tl.to('#grpA', { x:-1920, duration:0.55, ease:'power3.inOut' }, t);
tl.fromTo('#grpB', { x:1920, opacity:1 }, { x:0, duration:0.55, ease:'power3.inOut' }, t);
// Blur-Crossfade (emotionale Überleitung, normalerweise für den letzten Übergang)
tl.to('#grpC', { filter:'blur(20px)', opacity:0, duration:0.65, ease:'power2.in' }, t);
tl.fromTo('#grpD', { filter:'blur(20px)', opacity:0 },
{ filter:'blur(0px)', opacity:1, duration:0.65, ease:'power2.out' }, t);
❌ Verboten: Gesamte scene (einschließlich Hintergrund) wegschieben, Eck-Zoom, Vollbild-Zoom, Out/In Ende-an-Ende ohne Überlappung.
Schritt 7 – GSAP-Animation-Regeln
Muss beachtet werden
const tl = gsap.timeline({ paused: true });
// ...tweens...
window.__timelines['main'] = tl;
tl.fromTo()verwenden, nichttl.from()(um die HyperFrames-Suchdeterministik sicherzustellen)- Wiederholte Animationen mit
Math.floor(duration / cycle) - 1,repeat: -1verboten - Bei mehreren Animationen desselben Elements
overwrite: 'auto'hinzufügen - Beim Einblenden
.out-Easing, beim Ausblenden.in-Easing verwenden
Layout zuerst, dann Animation
Zunächst den Endzustand der Elemente (CSS-Positionierung) schreiben, dann den Einblendpfad mit fromTo beschreiben:
// ✅ Richtig
tl.fromTo('#title', { opacity:0, y:40 }, { opacity:1, y:0, duration:0.8, ease:'expo.out' }, 0.3);
Keine Animation in der persistenten Schicht
.bg, .rail, .logo, .foot-tag, .foot-url sind während des gesamten Videos fixiert. Animationen finden nur auf .blk-Komponenten statt. Sobald der Hintergrund an einer Bewegung teilnimmt, kehrt sofort das PPT-Gefühl zurück – Übergänge bewegen nur die Inhaltsschicht (siehe Schritt 6 beat()).
Schritt 8 – Lint & Vorschau
npx hyperframes lint # Muss 0 Fehler sein
npx hyperframes preview # http://localhost:300x, Hot Reload
| Häufige Warnung | Behandlung |
|---|---|
overlapping_gsap_tweens | overwrite:'auto' hinzufügen |
duplicate_media_discovery_risk | CSS background:url() anstelle von <img> verwenden |
composition_file_too_large | Bei Einzeldatei <500 Zeilen ignorierbar |
Abhängigkeiten und Asset-Quellen
d0-brand-Skill: Endgültige Autorität für Schriftarten, Schriftgrößen und Brand-Prinzipien; muss zusammen mit diesem Skill installiert werden.- HyperFrames-CLI: Nach Bedarf über
npx hyperframes@latestverfügbar. - GSAP: Beispiel verwendet fest die CDN-Version
3.14.2; bei Upgrade zuerst Lint und Seek-Überprüfung erneut durchführen. assets/fonts/: Instrument Serif und Open Sans; Lizenzdateien befinden sich im entsprechenden Schriftartenverzeichnis.assets/brand/: D0-Logo und D0-Avatar, nur für autorisierte Donut-Teammitglieder zur Erstellung von D0-Brand-Inhalten.