motion-video · Animationen mit Code, die maschinell prüfbar sind
Dieses Skill löst ein spezifisches Problem: Kleine Modelle (Flash/mini/turbo) können CSS und Canvas schreiben, aber die resultierenden Animationen sind oft nur „scheinbar“ vorhanden – Zwischenzustände werden übersprungen, Easing ist falsch, Schlüsselelemente erscheinen zu anderen Zeiten, und das Ende bleibt auf halbem Weg stecken. Das Modell selbst merkt es nicht, weil es keine Augen hat.
Der Ansatz ist daher nicht „schreibe es hübscher“, sondern die Animation als maschinell prüfbares Artefakt zu definieren:
- Spezifikation vor Code – übersetze ästhetische Urteile in tabellarische Werte.
- Das Bild muss eine reine Funktion von
tsein – zwinge Zwischenzustände strukturell ein. - Zahlen gehören zu Skripten – Bézier, Feder, Staffelung, Kontrast – alles über Tools, nicht im Kopf.
- Verwende einen deterministischen Renderer (Frame für Frame) – derselbe Code, derselbe Frame.
- Maschinelle Prüfung: zuerst numerisch, dann auf Pixelebene.
- Erst wenn die Maschine sagt „Struktur in Ordnung“, kommt der Mensch zur Komposition.
Lücken werden nicht durch einen Zauberspruch geschlossen, sondern durch diese sechs Schritte – sie machen „falsch“ zu „erkennbar und reparierbar“. Wo die Lücken herkommen, welche geschlossen werden können und welche nicht, siehe references/delta-vs-opus.md.
Qualität zuerst: Nur unnötige Kosten sparen, nicht die Validierung
Diese Regel steht über den eisernen Regeln. Das Ziel dieses Skills ist Opus-Level-Videos, nicht die billigsten Videos. Der Maßstab ist daher nicht, ob es schnell ist, sondern ob es besser wird.
Nur eine Art von Kosten darf gespart werden: wiederholte, ineffektive, sich gegenseitig um Ressourcen streitende. Validierungsdichte, Renderingqualität, Bildrate, Bewegungsunschärfe – diese werden nicht gespart.
Erlaubt zu sparen (Verschwendung, Sparen bringt keinen Mehrwert)
| Verschwendung | Sparmethode |
|---|---|
| 4 Chrome-Prozesse starten, die sich um CPU streiten | Serielle Ausführung (schneller als parallel), render.mjs hat bereits eine Sperre eingebaut |
| Ein 20KB-Spezifikationsdokument pro Kapitel | Ein vollständiges storyboard.md erstellen |
Wiederholtes render --still für jeweils nur einen Frame | Einmal 6–8 Zeitpunkte aufnehmen |
| Wiederholte Analyse desselben Materials | Einmal analysieren, Ergebnis ins Storyboard schreiben |
| Frame-für-Frame-PNGs auf Platte speichern und wieder einlesen | optimizeForSpeed ist bereits aktiviert; bei großen Projekten auf image2pipe umstellen (cinema-grade.md §9) |
| „Aus Sicherheit“ dieselbe Sache dreimal validieren | Zweimal validieren (numerisch + Pixel) reicht, eine dritte Prüfung bringt keine neuen Informationen |
Verboten zu sparen (Sparen bedeutet Qualitätsverlust)
| Nicht sparen | Begründung |
|---|---|
Vollständiges audit, inklusive jump/flat-Bearbeitung | Letzte Prüfung vor der Auslieferung – Überspringen = keine Abnahme |
verify --idempotent | Wenn die Idempotenz zerstört ist, sind alle nachfolgenden Prüfungen unglaubwürdig |
rigcheck (jedes Mal, wenn ein Charakter oder eine Pose geändert wird) | Skelettfehlstellungen können nur numerisch erkannt werden, nicht mit dem Auge |
| Bewegungsunschärfe in der finalen Ausgabe | Der Unterschied zwischen „mit und ohne Verschluss“ ist eine ganze Qualitätsstufe, kein schmückendes Beiwerk |
| 60fps bei schnellen Bewegungen | Bei 30fps ruckeln schnelle Gliedmaßen – das ist ein Defekt, keine Entscheidung |
| Frame-Prüfung (mehrere Zeitpunkte + lokale Vergrößerung) | Ein Bild zeigt keine Probleme in der Mitte; mindestens 6 Frames + 2–3× Vergrößerung der Schlüsselbereiche |
| Nach der Reparatur erneut ausführen (nicht „sollte behoben sein“) | Ohne erneute Ausführung ist nichts repariert |
Entscheidungshilfe in einem Satz
Gesparte Wartezeit kann gespart werden; gesparte „Gelegenheit, Fehler zu entdecken“, nicht.
Dass ein Rendern 70 Minuten dauert, ist inakzeptabel, nicht weil „70 Minuten zu lang sind“, sondern weil 85% dieser 70 Minuten darauf entfallen, dass 4 Prozesse sich um CPU kloppen – die Wartezeit hat keine Qualität gebracht. Aber für eine 180°-Verschlusszeit die 4-fache Renderzeit zu investieren, bringt eine spürbare Verbesserung der Bildwirkung – das muss investiert werden.
Die richtige Reihenfolge der Beschleunigung
- Verschwendung zuerst eliminieren: Parallelaufrufe seriell machen, doppelte Starts vermeiden, redundante Dokumente löschen, Frames bündeln.
- Dann Implementierung optimieren: Screenshot-Parameter, mehrere Tabs in einem Chrome-Prozess, direkter Zugriff auf den Encoder ohne Zwischenablage.
- Erst zuletzt die Validierung reduzieren – und das sollte eigentlich nicht passieren; wenn doch, wurden die ersten beiden Schritte nicht gemacht.
Eiserne Regeln
Verstöße gegen eine dieser Regeln machen das Produkt unannehmbar; neu machen.
- Kein Code ohne Spezifikation. Zuerst die Shot- und Zeitachsen-Tabellen erstellen (STEP 1). Jedes Element in der Tabelle muss
enter/active/exitals drei Zeitintervalle haben. Fehlt eines, hast du noch nicht durchdacht, wann es existiert. Aber wenn der Benutzer nur einen Satz sagt („Mach was Beeindruckendes“, „Zeig deine Fähigkeiten“, „Gib Vollgas“), darfst du nicht nachfragen – fülle die vier Slots (Motiv, Meta-Erzählung, Form, Niveau) selbst aus, schreibe sie insstoryboard.mdund leg los. Siehe references/wish-mode.md. - Alle Bildzustände sind reine Funktionen von
seek(t).requestAnimationFrame,Date.now(),performance.now(),Math.random(), selbstinkrementierende Zähler und selbstlaufende CSS@keyframes/transitionsind verboten. Derselbe Code, derselbet, muss immer denselben Pixel erzeugen. - Zahlen gehören zu Skripten, nicht ins Hirn. Bézier-Kontrollpunkte, Federparameter, Staffelung, Koordinatenberechnung, Kontrastverhältnisse,
linear()-Serie – alles vonease.mjs. Solche Zahlen dürfen in deiner Antwort erst erscheinen, nachdem das Tool gelaufen ist. Siehe unten „Zahlen gehören zu Tools, Entscheidungen zu dir“. - Nach jeder Änderung
verifyundrender + auditausführen.FAILbedeutet nicht auslieferbar.WARNmuss einzeln begründet werden („geändert“ oder „designintern, weil...“). Nichtverifyüberspringen und das ganze Video rendern – das kostet nur 8 Sekunden mehr, bringt aber eine dumme „Bild bewegt sich nicht“-Diagnose. - Dreiteilige Abgabe: Endvideo (mp4/webm/gif) + Kontaktabzug (-sheet.png) + audit-Ergebnis.
- Bei ästhetischen Unsicherheiten: Optionen anbieten, nicht raten. Zwei Farbschemata, zwei Rhythmen – lass den Benutzer wählen. Das ist besser, als eine mittelmäßige Version zu liefern.
- Keine Materialien abwarten, selbst zeichnen. Keine Platzhalter wie „Bild hier einfügen“, „Grafik empfohlen“, „warten auf Material“. Die Renderpipeline besteht nur aus HTML/CSS/SVG/Canvas – alle visuellen Elemente müssen aus Code generiert werden. Für Effekte/Texturen/Grafiken/Icon-Sets zuerst references/asset-recipes.md öffnen (20 vorgefertigte Code-Fragmente: Lichtflecken, Sweep-Lights, Partikel, Glas, Neon, Grids, abstrakte Illustrationen, Wireframe-Kugeln, Diagramme, Stadt-Silhouetten, Glitch-Effekt, Scanlines, Icons-Set, Lichtstrahlen, Tiefenschärfe, Stoffmuster, Bokeh, Pseudo-3D). Wenn nichts Passendes dabei ist, selbst SVG-Pfade schreiben. Keine Emojis oder Unicode-Symbole als Grafiken verwenden. Jedes Bild muss mindestens drei Ebenen haben (Hintergrundverlauf/Grid → Hauptmotiv → Atmosphäre/Partikel/Bokeh), mindestens 2 selbst erstellte visuelle Elemente, 1 Tiefenhinweis (Schatten/Verlauf/Farbschichtung/Partikel). Nur eine Ebene mit Text und Farbflächen = nicht bestanden.
- Bestehende Assets haben Vorrang, nicht neu bauen. Wenn im Workspace bereits fertige Skelette/Spezifikationen/Komponenten/Designs vorhanden sind, müssen sie komplett übernommen werden, kein einziger Wert neu geschätzt.
rigcheck.mjs --refbeweist, dass du die Originalwerte verwendest. Unfallbericht: Einmal wurdehead.posvon[-6.8,-182.5]auf[0,-248]geändert (Abweichung 65.9px),torso.pvvon[160,160]auf[160,291](Abweichung 131px). Ergebnis: Der Kopf schwebte links vom Körper, aber „Bildkontrolle“ hat es nicht erkannt – weil das menschliche Auge es als „eine Figur“ interpretiert. Solche Fehler müssen numerisch erkannt werden. - Material-Whitelist. Nur die im
storyboard.mdexplizit gelisteten Materialien verwenden. Andere Dateien im Workspace (ältere Versionen, Bilder von anderen Charakteren, Konfigurationen anderer Projekte) dürfen nicht angerührt werden, selbst wenn sie nutzbar erscheinen. Neue Materialien: eine Zeile im Storyboard + Verwendungszweck angeben, dann suchen. - Abnahme ohne Nachsicht, keine parallelen Renderings.
auditmeldetWARN≠ „kann geliefert werden“: Harte Übergänge (jump) und einfarbige Frames (flat) müssen auf Null zurückgesetzt oder einzeln erklärt werden, sonst neu machen.verify/rigcheckmitFAIL– keine weitere Arbeit. Nur einrender.mjs-Prozess gleichzeitig – das Skript hat eine Sperre; parallel laufende Prozesse streiten sich nur um CPU. Für Parallelisierung innerhalb eines Chrome mehrere Tabs öffnen (siehe cinema-grade.md §9), nicht mehrere Prozesse starten.
Zahlen gehören zu Tools, Entscheidungen zu dir
Diese Modellklasse (Flash/mini/turbo) hat eine Tendenz: Lieber selbst schätzen, als Tools zu verwenden. Es hält Kopfrechnen für kostenlos, Tools für umständlich. Diese Kostenrechnung ist falsch. Rechnen wir es klar:
| Kopfrechnen | ease.mjs aufrufen | |
|---|---|---|
| Direkte Zeit | 0 Sekunden | ca. 0.3–0.5 Sekunden |
| Wahrscheinlichkeit, richtig zu liegen | 30–40% (ein falscher Bézier-Kontrollpunkt ändert die ganze Kurve) | 100% |
| Kosten eines Fehlers | 90 Frames rendern ≈ 8 Sek. + Bildprüfung, und man sieht den Fehler wahrscheinlich nicht, nur „es ist nicht ganz geschmeidig“ | 0 |
| Erwartete Kosten | 0 + 0.5 × (8 + 30) ≈ 19 Sekunden, plus stiller Qualitätsverlust | 0.5 Sekunden |
Die 0.5 Sekunden, die du durch Kopfrechnen sparst, sind die teuerste Art zu sparen. Daher: harte Anforderung, kein Vorschlag.
Die folgenden Zahlen stammen ausschließlich von Tools. In deiner Antwort sind handgeschriebene Schätzwerte verboten:
| Was brauchst du? | Was läufst du? |
|---|---|
| Eigenschaften eines Bézier (Überschwingen, Plateau, Sample-Tabelle) | node scripts/ease.mjs cubic 0.22 1 0.36 1 |
| Federparameter (wie viel Überschwingen, wie lange, stoppt es mittendrin) | node scripts/ease.mjs spring 120 14 1 1.2 |
Kurve als CSS linear() ausgeben | node scripts/ease.mjs css-linear --preset silkIn |
| Staffelung einer Gruppe von Elementen, Gesamtzeit, ob sie überschreitet | node scripts/ease.mjs stagger 7 2.4 0.5 |
| Textkontrast prüfen | node scripts/ease.mjs contrast "#0b0e14" "#6d8bbd" |
| Lesbare Graustufen aus einer Hintergrundfarbe erzeugen | node scripts/ease.mjs ramp "#0b0e14" 5 |
Drei Selbstchecks (vor der Abgabe fragen; kein „kann ich nicht beantworten“ erlaubt):
- Kann jeder Kurvenparameter in meiner Antwort auf einen vorherigen Befehl zurückgeführt werden?
- Habe ich irgendwo eine Zahl wie „wahrscheinlich um 0.3“ geschätzt? Ja → löschen, Befehl ausführen.
- Sage ich „diese Kurve ist geschmeidig“, weil ich die ASCII-Grafik und den Überschwing-Prozentsatz von
ease.mjsgesehen habe, oder weil ich es rate?
Auch das Modell will sich selbst prüfen. Lass es den Verifikator nutzen: verify.mjs liest die echten berechneten Styles, nicht Schätzungen. Wenn es „nur bestätigen“ will, ist der korrekte Schritt verify auszuführen, nicht im Kopf zu simulieren.
Umgebung
Keine npm-Abhängigkeiten. Benötigt Chrome oder Edge (bereits auf dem System) + ffmpeg + ffprobe.
ffprobe wird nur für audit zur Überprüfung von Auflösung/Dauer verwendet. Fehlt, wird nicht stillschweigend ignoriert: Wenn --width/--height/--duration deklariert ist, FAIL; wenn nicht deklariert, WARN mit Nachricht „Auflösung unbekannt (nicht geprüft)“.
node scripts/render.mjs --check # Zeige chrome / ffmpeg / node / WebSocket-Fähigkeit
Wenn chrome als NOT FOUND ausgegeben wird, mit --chrome <pfad> angeben oder zuerst einen Browser installieren.
Was tun, wenn kein Bildverständnis vorhanden ist?
Manche Modelle (z. B. reine Text-Inferenz-Versionen) können read_image nicht verwenden. Diese Pipeline basiert vollständig auf Zahlen, nicht auf Bildern, also kann sie trotzdem durchlaufen: ease (Parameter) → verify (numerische Trajektorie + Idempotenz) → audit (Pixelstatistik, Ergebnis ist Zahl) → rigcheck (geometrische Zusicherungen).
- Möglich: Struktur, Bewegung, Geometrie, Lesbarkeit
- Nicht möglich: Kompositionsqualität, Farbharmonie, Stil-Konsistenz, visuelle Clipping-Fehler
Letztere müssen von einem Menschen (oder einem visuellen Modell) beurteilt werden. Aber das kann aufgeschoben werden: Zuerst mit Zahlen alle erkennbaren Fehler abfangen, dann dem Menschen 6–8 Frames zeigen (--still Batch + --guides Sicherheitszonen).
Dokumentenverzeichnis (Nach Bedarf lesen, nicht alles auf einmal lesen)
| Datei | Wann lesen? |
|---|---|
| references/wish-mode.md | Wenn der Benutzer nur einen Satz sagt, zuerst lesen: Vier Slots, Kapitelableitung, Standardwerte, kein Interview im Wunschmodus |
| references/spec-and-prompt.md | Beim Schreiben der Spezifikationstabelle (STEP 1); wenn reproduzierbare Prompt-Vorlagen benötigt werden; gegen Modelle, die keine Tools verwenden wollen |
| references/code-patterns.md | Beim Schreiben von Code (STEP 2): seek(t)-Paradigma, Easing-Bibliothek, keys()-Keyframe-Tabelle, spring(f,z), SVG/Canvas, 20 moderne CSS-Effekte |
| references/asset-recipes.md | Wenn das Bild etwas braucht, sofort öffnen: Lichtflecken, Sweep, Partikel, Glas, Neon, Grids, Illustration, Partikel, Wireframe-Kugel, Diagramm, Icon-Set, Bokeh, Pseudo-3D |
| references/rig-characters.md | Wenn eine Figur im Bild sich bewegt: Teile + Parent-Child-Transformationskette + Pose-Tabelle + 12 Prinzipien auf Felder umsetzen |
| references/cinema-grade.md | Vor der Finalisierung: Bewegungsunschärfe, Encoding-Parameter (gegen Banding), Vignette, HUD-System, Wisch-Effekte, Bildratenwahl, Lange-Filme-Organisation, Parallelbeschleunigung |
| references/review-checklist.md | STEP 5: Menschliche Stichprobe + alle Prüfpunkte vor der Abgabe |
| references/failure-modes.md | Bei Fehlern von audit/verify nachschlagen |
| references/delta-vs-opus.md | Wenn du wissen willst, „wie weit dieses System kommt“, und entscheiden musst, ob du das Modell wechseln sollst |
Zuerst aufteilen: Wunsch- oder Spezifikationsmodus
| Eingabeform | Weg |
|---|---|
| Liefert die meisten Informationen (Größe/Dauer/Inhalt/Stil) oder antwortet auf Rückfragen | Spezifikationsmodus: STEP 0 nachfragen → STEP 1 Spezifikationstabelle → … |
| Ein Satz + autorisierender Ton („Mach was Beeindruckendes“, „Zeig deine Fähigkeiten“, „Wie ein bestimmter Film“, „Gib Vollgas“) | Wunschmodus: STEP 0 überspringen, nicht nachfragen. Zuerst Workspace scannen, Motiv finden, vier Slots füllen, dann ab STEP 1 arbeiten. Siehe wish-mode.md |
Die Entscheidung ist einfach: Hat er nicht alles gesagt, ist es „warte auf meine Frage“ oder „entscheide du“? Ein Ton wie „mach was du kannst/Vollgas/zeig es mir“ ist Letzteres. Im Wunschmodus muss ebenfalls ein storyboard.md erstellt werden – nur dass die Tabelle von dir gefüllt wird, nicht durch Fragen.
Arbeitsablauf
STEP 0 · Kläre drei Dinge (nur im Spezifikationsmodus; Wunschmodus überspringen)
- Anwendungszweck: Vorspann / Social-Media-Kurzvideo / Web-Hero-Animation / Erklär-Schnipsel / Datenwachstumsanimation / GIF
- Größe und Dauer: Siehe Standardwerte unten, es sei denn, der Benutzer gibt explizite Angaben.
- Stimmung: Ruhig (Business/Finanzen), Schnell (Tech/Launch), Sanft (Leben/Marke), Hart (Spiele/Sport)
| Anwendungszweck | Größe | Dauer | Bildrate | Format |
|---|---|---|---|---|
| Vorspann / Launch | 1920x1080 | 3–6s | 30 | mp4 |
| Social-Media-Hochformat | 1080x1920 | 5–15s | 30 | mp4 |
| Web-Hero / Banner | 1920x800 oder 1440x600 | 2–4s, endlos wiederholbar | 30 | webp / apng (mit Transparenz); webm nur nach Alpha-Überprüfung |
| Datenanimation / Diagramm | 1920x1080 | 3–8s | 30 | mp4 |
| Endlos-GIF | 800x800 / 1080x1080 | 1–3s, nahtlos wiederholbar | 15–20 | gif / webp |
| Erklär-Schnipsel | 1920x1080 | 2–5s pro Einstellung, dann ganzer Film zusammensetzen | 30 | mp4 |
Länger als 10 Sekunden oder mehr als 3 Einstellungen: In mehrere Szenendateien aufteilen, jede einzeln rendern und prüfen, dann mit ffmpeg zusammensetzen. Kein einziges seek() über 30 Sekunden – das kann niemand selbst überprüfen.
STEP 1 · Spezifikation schreiben (einziger Schritt für kreative Freiheit)
Erstelle storyboard.md. Beides ist notwendig:
① Aufnahmetabelle
| # | Zeit | Was passiert im Bild | Hauptbewegung | Endzustand |
|---|---|---|---|---|
| 1 | 0.00–1.10s | Titel schwebt Zeichen für Zeichen ein | y: +96→0, je Zeichen 75ms Versatz | Titel ist sichtbar |
| 2 | 1.10–2.40s | Fortschrittsbalken füllt sich + drei Punkte erscheinen | scaleX: 0→1 (ease in out) | Linie am Rand, Punkte fertig |
② Element-Zeitachsen-Tabelle (eine Zeile pro Element, das ist die alleinige Grundlage für den Code)
| Element | enter | active | exit | Attribute | Kurve |
|---|---|---|---|---|---|
| #title span | 0.15 + i*0.075 | bis Ende | — | translateY 96→0, opacity 0→1 | easeOutCubic |
| #bar b | 0.30 | 0.30–2.40 | — | scaleX 0→1 | easeInOutCubic |
| .dots i | 1.50 + i*0.15 | bis Ende | — | scale 0→1 | easeOutBack |
Wenn du diese Tabelle nicht schreiben kannst, hast du es noch nicht durchdacht. Überspringe sie nicht und schreibe Code – der wird nur „erster und letzter Frame“ enthalten.
Die Spalte „Kurve“ bedeutet nicht, dass du nur einen Namen hinschreibst. Wenn der Name feststeht, sofort das Tool ausführen, um „wie diese Kurve bei deiner Dauer wirkt“ festzustellen, und die Zeile mit einem Zahlenwert ergänzen:
node scripts/ease.mjs cubic 0.33 1 0.68 1 # easeOutCubic → Plateau-/Overshoot-Prüfung
node scripts/ease.mjs stagger 6 2.4 0.7 # 6 Titelbuchstaben in 2.4s, jeder 0.7s → Staffelung und Überschreitung
Die Tabelle sieht dann so aus:
| Element | enter | active | exit | Attribute | Kurve (Tool-bestätigt) |
|---|---|---|---|---|---|
| #title span | 0.15 + i*0.075 | bis Ende | — | translateY 96→0, opacity 0→1 | cubic-bezier(0.33,1,0.68,1), overshoot 0%, nach 0.75 Plateau-Abschnitt → Dauer auf <0.7s begrenzen |
| .dots i | 1.50 + i*0.15 | bis Ende | — | scale 0→1 | spring(120,14) overshoot 7.1%, stabil nach 0.67s → Abschnittslänge 0.75s |
Kriterien für eine gute Kurve (das Tool sagt es dir direkt): Overshoot ≤ 15%, kein mittleres Plateau, Stabilisierungszeit der Feder ≤ Abschnittslänge. Wenn eine Bedingung nicht erfüllt ist, Parameter ändern und erneut ausführen, nicht „erstmal so schreiben und rendern“. Nichts mit dem Auge prüfen.
Vorlage und weitere Paradigmen: references/spec-and-prompt.md
STEP 2 · Implementierung
Beginne mit einem Grundgerüst, schreibe nicht die ganze Szene auf einmal. Grundgerüst = Hintergrund + ein animiertes Element + seek-Vertrag erfüllt.
window.scene = {
duration: 3.0, fps: 30, width: 1920, height: 1080, ready: true,
seek(t) {
// Jedes Element: Die Zeile aus der Zeitachsen-Tabelle in 3 Codezeilen übersetzen
// k = kurve(seg(t, enter, enter + dauer)) → k zur Interpolation des Attributs verwenden
},
};
CSS und JS müssen inline sein. Keine externen CDNs (Rendering wird dann wie ein Netzwerkausfall fehlschlagen). Systemschriftarten verwenden ("Segoe UI", "Microsoft YaHei", Arial).
Mögliche Paradigmen (DOM/CSS/SVG/Canvas/GSAP/Web Animations, Easing-Bibliothek, Mehrfach-Orchestrierung, Buchstabe-für-Buchstabe, Path-Stroke, Scroll-Number, Mask-Transition, CSS linear(), filter/blend-mode/mask): references/code-patterns.md
Wenn etwas gezeichnet werden muss (Lichteffekte, Texturen, Grafiken, Icons, Diagramme, Illustrationen, Pseudo-3D): Zuerst references/asset-recipes.md öffnen. Dort gibt es 20 abhängigkeitsfreie Code-Fragmente, die alle in eine einzelne HTML-Datei eingefügt und von seek(t) gesteuert werden können. Nicht von Grund auf neu erfinden und nicht auf Materialien warten.
STEP 3 · Numerische Prüfung (zuerst Zahlen prüfen, nicht gleich rendern)
Dies ist der erste Schritt in der „mehr Prüfungen“-Kette: dauert Sekunden, kein Encoding, und kann Elemente direkt benennen.
# Sieh die tatsächliche Trajektorie jedes Elements: wer sich bewegt, wohin, wo es hängt
node scripts/verify.mjs --html scene.html --select "#bar b,#title span" --props transform,opacity --steps 31
# Prüfen, dass das Bild nur von t bestimmt wird (zweimal derselbe t muss identische Pixel ergeben)
node scripts/verify.mjs --html scene.html --select ".item" --idempotent
Es gibt dir direkt die Antworten:
⚠ #b[0] · sx — Pause auf halbem Weg 0–2s, dann weiter verändert→ Interpolation wurde unterbrochen oder fehltℹ #card[0] · (alle) — Dieses Element hat sich während des gesamten Abschnitts nicht verändert→ Selektor trifft nicht / Style nicht im DOM✖ seek nicht idempotent: 13 Stellen mit unterschiedlichen Ergebnissen bei gleichem t→ seek verwendet Akkumulationsstatus
Wenn der numerische Layer bestanden ist, weiter. Nicht das ganze Video rendern, wenn die Zahlen falsch sind – das bringt nur eine vage „Bild scheint sich nicht zu bewegen“-Diagnose und du musst von Pixeln zurückverfolgen. Lass zuerst die Zahlen sprechen.
STEP 4 · Rendern + Pixel-Abnahme
Zuerst nur Keyframes ausgeben, schnell, um die Komposition zu prüfen:
node scripts/render.mjs --html scene.html --still 0.2,1.0,2.2 --out out/stills
Diese Bilder ansehen (mit read_image selbst, nicht überspringen). Wenn die Komposition passt, das ganze Video:
node scripts/render.mjs --html scene.html --out out/v.mp4 --fps 30 --sheet
node scripts/audit.mjs --video out/v.mp4 --fps 30 --duration 3 --width 1920 --height 1080
audit gibt dir: Änderungspixel-Kurve, Rhythmusbalken, und eine bewertende Schlussfolgerung. Nach der Schlussfolgerung ändern, jedes Mal nur eine benannte Stelle, dann sofort audit erneut ausführen. Maximal 5 Runden; wenn die 5. Runde immer noch FAIL ist, zurück zu STEP 1 und die Spezifikation ändern (das heißt, die Spezifikation selbst war falsch).
Häufige Fehler finden: references/failure-modes.md
STEP 5 · Menschliche Stichprobe
Die Maschine prüft nur „Struktur korrekt“. Diese Punkte musst du selbst ansehen:
- Läuft Text über den Bildrand / wird abgeschnitten / kollidiert mit dem Hintergrund?
- Ist der visuelle Schwerpunkt an der erwarteten Position (Drittelung / Zentrum / Schwerpunkt der Elementgruppe)?
- Ist der Kontrast ausreichend (grauer Text mit 40% Deckkraft auf dunklem Hintergrund ist unsichtbar)?
- Sind Ein- und Ausgänge sauber (beginnt ein Element außerhalb des Bildes? verschwindet es plötzlich innerhalb des Bildes)?
Checkliste: references/review-checklist.md
STEP 6 · Abgabe
# Für jedes benötigte Format einen weiteren Befehl
node scripts/render.mjs --html scene.html --out out/v.webm --format webm
node scripts/render.mjs --html scene.html --out out/v.gif --format gif --fps 15
Abgabe: Pfad des Videos, Kontaktabzug, audit-Veridikt (die paar Zeilen), storyboard.md. Wenn audit WARN hat, du es aber als designintern betrachtest, benenne die Zeile und gib den Grund an.
Die endgültige Version muss mit Bewegungsunschärfe neu gerendert werden.
node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 30 --motion-blur 180
Das ist die Grenze zwischen „sieht geschmeidig aus“ und „sieht aus wie ein Screenshot“. In der Iterationsphase kann Bewegungsunschärfe vorübergehend ausgeschaltet werden, um Zeit zu sparen, aber die Abgabeverion darf keinen Verschluss vermissen lassen – das zu sparen, bedeutet Qualitätsverlust. Nach dem Einschalten audit erneut ausführen, um sicherzustellen, dass Dauer und Bildrate nicht geändert wurden. Bei schnellen Bewegungen (Charakter-Aktionen, Wisch-Effekte, Partikel) gleichzeitig --fps 60 verwenden.
Befehls-Schnellreferenz
# System-Check
node scripts/render.mjs --check
# Berechnungen (Kurven / Feder / Staffelung / Kontrast) — diese niemals im Kopf rechnen
node scripts/ease.mjs cubic 0.22 1 0.36 1
node scripts/ease.mjs spring 120 14 1 1.2
node scripts/ease.mjs css-linear --preset silkIn
node scripts/ease.mjs stagger 7 2.4 0.5
node scripts/ease.mjs contrast "#0b0e14" "#6d8bbd"
node scripts/ease.mjs ramp "#0b0e14" 5
node scripts/ease.mjs presets
# Skelett-Geometrie-Check (bei Charakteren immer; bei vorhandenem Rig muss --ref für Alignment)
node scripts/rigcheck.mjs --rig rig/ander.rig.json
node scripts/rigcheck.mjs --rig lib/rig.json --ref rig/ander.rig.json
node scripts/rigcheck.mjs --rig rig.json --pose '{"head":{"rot":0.2}}' --assert
# SKILL.md-Frontmatter-Check (nach jeder Änderung am Skill ausführen, um zu verhindern, dass „das ganze Skill nicht geladen wird“)
node scripts/lint-skill.mjs
# Numerische Prüfung (Sekundenbruchteile, benennt Elemente)
node scripts/verify.mjs --html scene.html --select "#bar b" --props transform,opacity --steps 31
node scripts/verify.mjs --html scene.html --select ".item" --idempotent
node scripts/verify.mjs --html scene.html --all --json
# Keyframes (für die Bildprüfung, am schnellsten)
node scripts/render.mjs --html scene.html --still 0,0.5,1.5,2.9 --out out/stills
# Keyframes + Kompositionshilfslinien (100px Raster / 80px Sicherheitszone / Drittelungslinien / zentrales Kreuz)
node scripts/render.mjs --html scene.html --still 1.6 --guides --out out/guides
# Gesamtes Video + Kontaktabzug
node scripts/render.mjs --html scene.html --out out/v.mp4 --fps 30 --sheet
# Finale Abgabe mit Bewegungsunschärfe (180° Verschluss = Kinostandard; Rendering ×4, nur zur Finalisierung)
node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 30 --motion-blur 180
# Nur bei schnellen Bewegungen (Charakter-Aktionen, Wisch-Effekte, Partikel) 60fps
node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 60 --motion-blur 180
# 2x Supersampling (schärfer, 3–4× langsamer)
node scripts/render.mjs --html scene.html --out out/v.mp4 --scale 2
# Transparenter Hintergrund: webp / apng / png zuverlässig
node scripts/render.mjs --html scene.html --out out/v.webp --format webp --alpha
node scripts/render.mjs --html scene.html --out out/v.apng --format apng --alpha
# webm-Alpha hängt vom ffmpeg-Build ab. Lokal getestet: VP8/VP9 stufen auf kein Alpha zurück.
# Skript liest nach dem Encoding den ersten Frame zurück und prüft auf Alpha-Pixel – wenn keine vorhanden, Fehler mit Hinweis auf Alternative.
node scripts/render.mjs --html scene.html --out out/v.webm --format webm --alpha
# Endlos-GIF
node scripts/render.mjs --html scene.html --out out/v.gif --format gif --fps 15
# Pixel-Abnahme
node scripts/audit.mjs --video out/v.mp4 --fps 30 --duration 3 --width 1920 --height 1080
node scripts/audit.mjs --video out/v.gif --loop # Nahtlosigkeitsprüfung
node scripts/audit.mjs --video out/v.mp4 --json out/audit.json
render.mjs Parameter: --html --out --fps --duration --width --height --scale --format(mp4|webm|gif|webp|apng|png) --still --sheet --alpha --file --keep-frames --chrome --check --quiet
verify.mjs Parameter: --html --select --props --steps --all --idempotent --json --rig --ref --pose --assert --video --duration --width --height --quiet
audit.mjs Parameter: --video --fps --duration --width --height --changelog --json --loop --quiet
scripts/ease.mjs Parameter: Siehe node scripts/ease.mjs --help.
Häufige Fehler & Reparaturen
| Symptom | Ursache | Reparatur |
|---|---|---|
"WARN — flat frame(s) detected" | Ein oder mehrere Frames haben weniger als 5% sich ändernde Pixel | 1. --still auf die flat-Frames prüfen 2. In der Zeitachsen-Tabelle: Kann ein Element zu früh wieder verschwinden? Ist ein exit-Intervall zu kurz? 3. ease-Tool prüfen: Overshoot zu niedrig zwischen den Frames? 4. Am Ende keine Bewegung → Verlängerung des active-Abschnitts prüfen |
"FAIL — jump detected" | Ein Pixel-Kanal springt zwischen zwei Frames um mehr als 25/255 | 1. Bezier-Overshoot zu groß? ease.mjs prüfen 2. Fast Movement ohne 60fps + motion-blur? → --fps 60 und motion-blur aktivieren 3. — Ein Element wird zu spät eingeblendet / zu früh ausgeblendet → enter/active/exit prüfen |
"WARN — 30% clamped value range" | Die Animationseigenschaft wird nur teilweise ausgenutzt (z.B. opacity läuft nur von 0,8–1,0) | Prüfen, ob der Start-/Endwert in der Tabelle korrekt ist; ggf. Bereich ausweiten |
"WARN — static tail" | Die letzten 20% der Dauer haben keine Pixeländerung | Ende der Animation auffüllen: Nachklang-Effekt, End-Element still stehen lassen, oder kürzen |
"FAIL — seek not idempotent" | seek(t) verwendet Akkumulationsstatus (z.B. +=), Date.now() oder performance.now() | Alle Zustände als Funktion von t umschreiben; sicherstellen, dass t von 0 bis duration wiederholt aufgerufen werden kann |
verify sagt „Element nicht gefunden“ und überspringt die Prüfung | CSS-Selektor passt nicht / Element im DOM nicht vorhanden / Style nicht inline | --select korrigieren oder prüfen, ob das Element sichtbar ist |
audit meldet „Auflösung unbekannt“ | Kein --width/--height angegeben | --width 1920 --height 1080 anfügen |
rigcheck meldet „Schulter aus der Pose“ | Posenparameter nicht mit --ref abgeglichen | --ref mit der Original-Rig-Datei angeben; dann die abweichenden Werte korrigieren |
Weitere Modi: references/failure-modes.md
Kurzes Beispiel: Ein Titel schwebt ein
storyboard.md
Aufnahmetabelle
| # | Zeit | Bild | Hauptbewegung | Endzustand |
|---|---|---|---|---|
| 1 | 0.00–2.00s | Titel „Hello World“ schwebt Buchstabe für Buchstabe von unten ein | y: 120→0, je Buchstabe 80ms, opacity 0→1 | Titel vollständig sichtbar |
Element-Zeitachsen-Tabelle
| Element | enter | active | exit | Attribut | Kurve (Tool bestätigt) |
|---|---|---|---|---|---|
.char i | 0.10 + i*0.08 | bis 2.00 | — | translateY 120→0, opacity 0→1 | easeOutCubic → cubic-bezier(0.33,1,0.68,1), overshoot 0%, 0.75s nach Einblendung stabil |
Implementierung
<!DOCTYPE html>
<html>
<head>
<style>
body { margin:0; background: #0b0e14; display:flex; justify-content:center; align-items:center; height:100vh; font-family:"Segoe UI",sans-serif; }
.char { display:inline-block; will-change:transform,opacity; font-size:4rem; color:#e0e6f0; }
</style>
</head>
<body>
<div id="scene">
<div id="title">
<span class="char">H</span><span class="char">e</span><span class="char">l</span><span class="char">l</span><span class="char">o</span><span class="char"> </span><span class="char">W</span><span class="char">o</span><span class="char">r</span><span class="char">l</span><span class="char">d</span>
</div>
</div>
<script>
window.scene = {
duration: 2.0, fps: 30, width: 1920, height: 1080, ready: true,
seek(t) {
const chars = document.querySelectorAll('.char');
chars.forEach((el, i) => {
const enter = 0.10 + i * 0.08;
const dur = 0.75;
const progress = (t - enter) / dur;
if (progress <= 0) {
el.style.transform = 'translateY(120px)';
el.style.opacity = 0;
} else if (progress >= 1) {
el.style.transform = 'translateY(0)';
el.style.opacity = 1;
} else {
const k = 1 - Math.pow(1 - progress, 3); // easeOutCubic: 1 - (1 - t)^3
el.style.transform = `translateY(${120 * (1 - k)}px)`;
el.style.opacity = k;
}
});
}
};
</script>
</body>
</html>
Ausführen & Prüfen
# 1. Numerische Prüfung
node scripts/verify.mjs --html scene.html --select ".char" --props transform,opacity --steps 21
# 2. Keyframes zur Ansicht
node scripts/render.mjs --html scene.html --still 0,0.3,0.8,1.5,2.0 --out out/stills
# 3. Komplett rendern + audit
node scripts/render.mjs --html scene.html --out out/v.mp4 --fps 30 --sheet
node scripts/audit.mjs --video out/v.mp4 --fps 30 --duration 2 --width 1920 --height 1080
# 4. Finale Version mit Bewegungsunschärfe
node scripts/render.mjs --html scene.html --out out/final.mp4 --fps 60 --motion-blur 180