Opus Visual Motion Engine
Eine disziplinierte Pipeline für visuelle Liefergegenstände: planen → aus der Vorlage bauen → rendern → QA → korrigieren → exportieren. Qualität entsteht durch Kontrollen vor und nach dem Rendern, nicht durch Geschmack. Folge den Schritten in der angegebenen Reihenfolge. Überspringe keinen Schritt, weil die Aufgabe „einfach aussieht“.
Die folgenden Pfade sind relativ zum Verzeichnis dieses Skills (der skill_resources-Basis, die dir gegeben wurde). Nenne es $SKILL.
0. Zuerst lesen (unbedingt)
Bevor du Code schreibst, lies die Referenzen, die zum Liefergegenstand passen. Sie sind maßgeblich für ihr Thema:
| Liefergegenstand | Lesen |
|---|---|
| Video, Motion Graphic, Erklärvideo, Produktvideo | references/video-generation.md, references/motion-design.md, references/javascript-animation.md |
| Kinetische Typografie / Typografie-geführtes Stück | das Video-Set oben + references/typography.md |
| Landing Page, Dashboard, Mockup, UI | references/visual-design.md, references/typography.md |
| Diagramm, Schema, Datenvisualisierung | references/visual-design.md §4 |
| Bildausschnitt / Kamerentscheidungen | references/cinematography.md |
| Dauern und Easing-Funktionen | references/animation-primitives.md |
| Musik oder Sprache zum Synchronisieren | SKILL.md §10 + references/video-generation.md §6 |
Ausgearbeitete Beispiele befinden sich in examples/*.md. Lies das, das dem Brief am nächsten kommt.
1. Vor dem Codieren planen (ausschreiben)
Schreibe den Plan in deine Antwort (oder in eine PLAN.md neben der Ausgabe), bevor du das HTML erstellst. Ein Plan, der nur in deinem Kopf existiert, zählt nicht.
UI / Seite
- Primäre Botschaft: ein Satz. Was muss der Betrachter in 3 Sekunden verstehen?
- Benannte Richtung: ein Name, 4–6 benannte Hex-Token mit zugewiesenen Bedeutungen, Schriftarten mit Rollen, Formbehandlung. Leite sie aus der Branche, den Materialien und der Ausdrucksweise des Themas ab. Ein Spielwarenladen und ein Fintech-Dashboard teilen nie eine Richtung.
- Hierarchie: Markiere jeden Block als PRIMARY / SECONDARY / TERTIARY. Nur PRIMARY erhält die eine kühne Geste.
- Abschnittsabfolge: eine Zeile pro Abschnitt, die seine Aufgabe beschreibt und wie er zum nächsten überleitet.
- Vor-Render-Mathematik: Textbreite ≈
chars × 0.55 × font-size(serifenlos) oder× 0.5(Serife); Kastenbreite =max(title_chars × 8, subtitle_chars × 7) + 24bei 14px; Zeilenpassung = ΣBreiten + Lücken ≤ Container. Verfolge jeden Verbinder gegen jede Box. Wenn er eine kreuzt, zeichne einen L-förmigen Pfad.
Video / Motion Graphic
- Kernbotschaft: ein Satz. Wenn es zwei braucht, gibt es zwei Videos.
- Beats: 3–7. Jeder Beat beantwortet die Frage „Was weiß der Betrachter jetzt?“.
- Szenenkarte pro Beat: Start/Ende (s), Komposition, Kamera, Schriftgrößen, Primitiven (2–4), Ausgang. Verwende die Vorlage in
references/motion-design.md§2. - Signature-Moment: Nenne den EINEN Frame, in dem der Mechanismus gezeigt wird, nicht beschriftet (z. B. Rauschen in Signal gefiltert). Wenn die Geschichte nur mit ihren Untertiteln funktioniert, gestalte den Beat neu.
- Globale Zeitleiste: absolute Zeitstempel. Der AUSGANG einer Szene ist abgeschlossen, bevor die nächste Szene den Platz beansprucht. Setze
DURATIONauf das wahre Ende (Standard 10–20s; 30–45s nur mit Erzählung).
Eine Szene ohne Karte gehört nicht in das Video.
2. Aus der Vorlage bauen (Video)
Kopiere assets/composition-template.html neben den Liefergegenstand und fülle die EDIT-Blöcke. Schreibe die ENGINE-Blöcke nicht um. Sie bieten bereits:
- eine 1920×1080
#stage(ändereSTAGE_W/Hfür 1080×1920 oder 1080×1080), an jedes Fenster angepasst; window.DURATION,window.seek(t),window.render(t),window.SCENES: den Capture/Export-Vertrag (QA erfasst jede Szene ausSCENES);at(),ease.*,lerp,mulberry32(gesäter PRNG) undlayer()für Szenensichtbarkeit plus AUSGANG;- Audio-Helfer
audioAt(t, "rms"|"low"),since(t, list),hit(t, list, dur), diewindow.AUDIO(§10) lesen und 0 ohne es zurückgeben; - einen Vorschau-Player (Leertaste, ←/→, Pos1/Ende), der unter Capture und reduzierter Bewegung automatisch deaktiviert wird;
- Farb-Token in den erforderlichen 3 Ebenen (hell,
prefers-color-schemegeschützt,[data-theme]).
Für Seiten schreibe ein normales Single-File-HTML gemäß §6.
3. Deterministische Zeit (Video)
render(t)ist der einzige Zustandstreiber. Jede Position, Deckkraft, Größe, Zahl und jeder Dashoffset wird austin Sekunden berechnet.seek(x)rendert den identischen Frame, unabhängig davon, was vorher gerendert wurde.tist in Sekunden. Begrenzetauf[0, DURATION], niemals auf[0, 1]: Wenn Sekunden auf 0..1 begrenzt werden, friert dies die gesamte Zeitleiste stillschweigend ein.- Verboten:
setTimeout,setInterval, CSS-Animationen/Übergänge als Zeitleiste, ungesäterMath.random(),Date.now()in Zuständen.requestAnimationFramedarf nur die Wiedergabeuhr vorrücken undrender(clock)aufrufen. Die Vorlage macht dies bereits. - Zufälligkeit: zur Bauzeit aus
mulberry32(seed)generieren, niemals innerhalb vonrender. - SVG-Zeichnen benötigt alle drei:
pathLength="1",stroke-dasharray="1"undstroke-dashoffsetvon 1 bis 0. Ohne ein Dasharray erscheint die Linie ab Frame 0 vollständig gezeichnet. inline-block-Wortspannen verschlucken nachfolgende Leerzeichen. Setze den Abstand inmargin-right.
4. Bewegungsgrammatik
Fünf Bewegungen, jede mit einer Aufgabe. Wenn eine Bewegung keine davon ist, lösche sie.
- EINGANG: eine orchestrierte Sequenz pro Seite oder Szene, in Lesereihenfolge, Geschwister mit 60–120ms Versatz. Fade-up in jedem Abschnitt ist das KI-Verratmerkmal.
- BETONUNG: ein Element nach dem anderen: eine Maßvergrößerung (≤1.2), ein Leuchten oder eine Farbänderung, die Bedeutung trägt.
- ÜBERGANG: eine Zustandsänderung. Das geänderte Teil bewegt sich; alles andere bleibt still. 0.2–0.6s.
- KAMERA: eine Maßstabs-/Verschiebung auf Bühnenebene, höchstens einmal pro Szene, 0.8–1.2s, niemals während des Lesens von Text.
- AUSGANG: 0.3–0.5s, vollständig abgeschlossen. Kein Element überlebt einen Zwischenzustand über eine Szenengrenze hinweg, außer einem bewussten Kontinuitätsanker, der identisch bleibt oder morphiert (dasselbe Objekt ändert seinen Zustand, der stärkste verfügbare Übergang).
Übergänge tragen Bedeutung: harter Schnitt = Kategorienwechsel, Morph = dasselbe ändert sich, Schwenk = Überquerung. Niemals einen überall gleichen Standard-Crossfade. Dauern und Easing-Funktionen sind in references/animation-primitives.md. Nachbarn, die sich zusammen bewegen, erhalten unterschiedliche Dauern oder einen Versatz.
5. Stack-Entscheidung
| Situation | Stack |
|---|---|
| Seiten-Mikrobewegung | CSS-Übergänge auf transform/opacity, 0.2–0.6s; Schleifen ≤2s innerhalb @media (prefers-reduced-motion: no-preference) |
| Video / Motion Graphic / Kinetische Typografie | Vorlage + Vanilla render(t) (Standard) |
| >6 versetzte Spuren oder SVG-Morph-Orchestrierung | GSAP UMD, eine pausierte Master-Zeitleiste, seek(t) → tl.seek(t) |
| Diagramme | Inline SVG (Standard) oder Chart.js UMD mit animation:false, Hex-Farben (Canvas kann keine CSS-Variablen lesen) |
| Generative Kunst | p5.js mit randomSeed/noiseSeed |
| 3D, nur wenn 3D die Botschaft ist | Three.js UMD; Kamera in render(t) skripten |
Verwende den einfachsten Stack, der zum Ergebnis führt. Externe Skripte müssen exakte, festgepinnte Versionen von cdnjs.cloudflare.com oder cdn.jsdelivr.net sein. Alles andere inline. Jede Schriftart erhält einen echten Fallback-Stack.
6. Technische Basis (nicht verhandelbar)
- Einzelne
.html-Datei mit CSS und JS inline, unter 16 MB, Bilder/Daten alsdata:-URIs. - Farben als
:root-Token; dunkle Ebene unter@media (prefers-color-scheme: dark)geschützt durch:root:not([data-theme="light"])und wiederholt unter:root[data-theme="dark"]; expliziterbody-Hintergrund. meta viewportmitviewport-fit=cover;env(safe-area-inset-*)-Padding;height:100%auf html/body, niemals100vh; breite Blöcke scrollen innerhalb ihres eigenenoverflow-x:auto; Raster verwendenminmax(0,1fr).- Angezeigte berechnete Zahlen gehen durch
Math.round,toFixedoderIntl.NumberFormat. Count-ups landen exakt auf dem Endwert. - Barrierefreiheit: Kontrast ≥4.5:1 (≥3:1 für ≥24px Text), sichtbarer Fokus,
prefers-reduced-motionrespektiert (die Vorlage zeigt den eingeschwungenen Endframe). - Lesbare Schrift: in einem 1080p-Videoframe kein Text unter 20px (H/54). Auf mobilen Seiten kein Fließtext unter 14px.
- Browserspeicher hält niemals Zeitleistenzustände. Wo Speicher überhaupt verwendet wird, in try/catch verpacken.
7. Vermeide generisches KI-Design
Wo der Brief Freiheit lässt, gib sie niemals für diese Standardeinstellungen aus (qa.mjs markiert mehrere automatisch):
| Verratsmerkmal | Korrektur |
|---|---|
Cremefarben #F4F1EA-ähnlich + Serifen-Display + Terrakotta #D97757-ähnlicher Akzent | eine Palette, die aus den eigenen Materialien des Themas stammt |
| Beinahe-Schwarz + ein saurer Akzent, unabhängig vom Thema verwendet | nur erlaubt, wenn die Richtung es schriftlich rechtfertigt |
| Identische abgerundete Karten, ein Radius überall, derselbe weiche Schatten | Radius-Token nach Hierarchie; Karten nur für begrenzte Objekte |
| Verläufe als Dekoration, lila Verläufe, Glas-Morphismus | flache Füllungen; maximal ein Verlauf, nur für eine kontinuierliche physikalische Eigenschaft |
| GROSSBUCHSTABEN-Augenbrauen mit Tracking, Mittelpunkt-Meta-Strings, "→" auf Links | Satzfall; lösche Labels, die den Inhalt wiederholen |
| Inter / System-Schriftart als Standard | Schriftarten, die für dieses Thema ausgewählt wurden, mit einem Fallback-Stack |
| Ein einzelnes Wort in einer Überschrift hervorgehoben | NUR erlaubt, wenn die Akzentfarbe ein semantischer Token ist, der für dieselbe Bedeutung an anderer Stelle im Stück verwendet wird (z. B. Koralle = Rauschen) |
| Generischer Hero: Überschrift + Untertitel + CTA + Screenshot | Eröffne mit dem charakteristischsten Ding in der Welt des Themas |
| Alles zentriert, gleicher Rasterrhythmus in jedem Abschnitt | ein Ausrichtungssystem pro Abschnitt; variiere den Rhythmus |
| Alles gleichzeitig animiert, 300ms überall | die Dauer-Karte + Stagger (§4) |
Setze Kühnheit an einer Stelle ein, dann entferne ein Accessoire.
8. Rendern + QA (vor der Auslieferung obligatorisch)
Führe die automatisierte QA aus. Sie rendert die Datei headless und schreibt Nachweise plus ein Urteil. Sie benötigt Node ≥18. Der erste Lauf in einer frischen Kopie des Skills benötigt npm install in $SKILL/scripts (überspringe es, wenn scripts/node_modules existiert).
node "$SKILL/scripts/qa.mjs" path/to/deliverable.html
In DSH unter Windows führe es mit dem pwsh-Tool mit demselben Befehl aus. Optionen: --step 0.25 (ein feineres Raster für schnelle Szenen), --out <dir>, --mode page|video.
Video-Modus (automatisch, wenn DURATION + seek existieren) erfasst einen Frame pro Schritt und prüft: verbotene APIs, Deterministisch bei Wiederholungen in falscher Reihenfolge, eine eingefrorene Zeitleiste, tote Luft, nahezu leere Spannweiten, einen nicht eingeschwungenen Endframe, Textkollisionen, Text über anderen Grafiken, Clipping, Kontrast, minimale Schriftgröße, Dash-Offset-Linien, die nie zeichnen, reduziert-motion-Schleifen, Konsolen-/Seitenfehler und Vorlagen-Verratsmerkmale.
Seiten-Modus rendert Desktop 1440, Mobil 390 und dunkles Schema und prüft dieselben Layout-Regeln plus mobilen horizontalen Überlauf.
Die Ausgaben landen in qa-<name>/: report.md (Urteil und Ergebnisse), report.json (Tintendeckung und Änderung pro Frame), contact-sheet.png (jeder Frame in einem Bild), moments.png (jeweils Anfang, Mitte und Ende jeder Szene, aus window.SCENES), key_000..100.png und frames/.
- Übergib den Signature-Moment und jeden Sync-Punkt explizit:
--at 5.4,9.1. - Bewusste Überlagerung (kinetische Typografie absichtlich gestapelt, ein Titel über Filmmaterial) wird in ein Element mit
data-qa-allow-overlapgesetzt. Das überspringt die Kollisions- und Text-über-Grafiken-Prüfung nur für diesen Teilbaum. Verwende es niemals, um eine versehentliche Kollision zu unterdrücken. - Eine
font-WARNUNG bedeutet, dass die erste Wahl der Familie nicht geladen wurde und der Text in einem Fallback angezeigt wird. Behebe dies, bevor du das Layout beurteilst, weil jede Breite falsch ist.
Exit-Code 0 = kein FEHLER. FEHLER ist blockierend. Jede WARNUNG wird entweder behoben oder in einer Zeile in deiner Kritik begründet.
9. Kritik-Loop
- Wenn dein Modell Bilder lesen kann: öffne
contact-sheet.png, dann allekey_*.png, die falsch aussehen. Beurteile die Pixel, nicht deine Absichten. - Wenn dein Modell text-only ist: verwende
report.mdplus die Pro-Frame-Tabelle inreport.json.coverage< 0.015 bedeutet, dass der Frame leer gelesen wird. Eindiffvon 0 über eine Szene hinweg bedeutet, dass sich nichts bewegt. Ein Anstieg indiffmarkiert einen Schnitt. Überprüfe jede Szenenkarten-Zeitstempel gegen diese Zahlen. - Beantworte jede Frage mit einer konkreten Beobachtung, nicht mit „✓“:
- Komposition: Auf jedem Schlüssel-Frame, wo landet das Auge zuerst? Ist das die Botschaft?
- Hierarchie: Ist PRIMARY unverkennbar? Gibt es genau eine bewegte Sache, die pro Frame zählt?
- Mechanismus: Zeigt der Signature-Moment die Idee ohne die Untertitel?
- Kontinuität: Sind alle Übergaben sauber, nichts im Zwischenzustand an einer Grenze und Anker identisch oder morphing?
- Timing: Sind Versätze vorhanden, keine Standarddauern und Lesezeit ≥1.2s pro 8 Wörter?
- Typografie / Kontrast / Dichte: Größen gemäß Plan, ≤5 konkurrierende Elemente pro Frame, im dunklen Modus lesbar?
- Erzählung: Könnte ein Betrachter die Kernbotschaft nach einem Ansehen wiederholen?
- Korrigieren →
qa.mjserneut ausführen → erneut kritisieren. Wiederholen, bis die QA bestanden wird und die Kritik keinen offenen Punkt mehr hat. - Abschließende Frage, ehrlich beantwortet: „Sieht dies absichtlich gestaltet oder lediglich generiert aus?“ Wenn „generiert“: nenne, was generisch ist, überarbeite den Plan (§1) und baue neu auf. Ein erster Render ist fast nie der Liefergegenstand. Erwarte 2–3 Generationen.
10. Audio-Sync (wenn es Musik oder Sprache gibt)
Errate das Timing niemals nach Gehör. Wandle das Audio in Daten um und lass render(t) sie lesen:
node "$SKILL/scripts/audio-data.mjs" music.mp3 --inject composition.html # schreibt window.AUDIO in das HTML
AUDIO.beats(ein gleichmäßig verteiltes Raster im geschätzten Tempo),AUDIO.onsets(Schläge, Noten, Silben) und Pro-FrameAUDIO.rms/AUDIO.low(0..1;lowist das <150 Hz Kick/Bass-Band).- Treibe Bewegung mit den Vorlagen-Helfern an:
hit(t, AUDIO.beats, 0.2)für einen Beat-Puls (EMPHASIS),audioAt(t, "low")für kick-reaktive Skalierung,since(t, AUDIO.onsets)für Enthüllungen pro Treffer. Setze Szenenschnitte auf Beats: wähle Szenenanfänge ausAUDIO.beats. - Sync ist durch Konstruktion frame-exakt: Ein Puls landet auf dem ersten Frame bei oder nach seinem Beat (≤1 Frame, ≤33 ms bei 30 fps). Wenn das Audio später als t=0 beginnt, übergib
--offset <s>. - Pegel werden überprüft, bevor jemand zuhört. Beschnittene Samples beenden mit Exit-Code 1. Ein Sample-Peak über −1 dBFS warnt, weil AAC-Codierung es beschneiden wird. Lautstärke außerhalb −18..−12 LUFS wird gemeldet (Plattformen normalisieren auf etwa −14).
--bpmüberschreibt das geschätzte Tempo. Nützlich, wenn das Audio ein gleichmäßiges, aber nicht offensichtliches Tempo hat.- Verwende
--skip-inject, wenn du nur die JSON-Daten sehen und die Audio-Datei manuell einfügen willst.