Bewegungsgrafik
Erstelle ein Video, indem du eine Webseite schreibst, die der Renderer Bild für Bild durchläuft. Beide Pfade unten führen zum gleichen Ergebnis; der Unterschied liegt darin, was du schreibst.
- HyperFrames — eine HTML-Datei, CSS für das Aussehen, eine pausierte GSAP-Timeline für die Bewegung.
node scripts/hf.mjsführt die gepinnte Version aus und installiert sie einmalig aus einer festgeschriebenen Lockdatei. Apache 2.0. - Remotion — React-Komponenten.
useCurrentFrame()gibt das aktuelle Bild zurück, du machst die Mathematik. Ausgereift, typisiert und lizenziert kostenlos nur für bis zu drei Personen.
Lade die passende Referenz, bevor du den Kompositionscode schreibst. Die Framework-Regeln sind nicht erratbar, und die meisten Fehler sind still: Eine HyperFrames-Datei, die ihre Timeline nie registriert, rendert ein Standbild ohne Fehlermeldung.
Der einfache Weg
Der Benutzer beschreibt in beliebigen Worten, was er möchte. Er schreibt nie ein Briefing, ein Lastenheft oder einen Beat-Plan – Claude erstellt einen.
/motion a punchy 6 second logo sting for Inkwell
Das ist die gesamte Eingabe. Darunter:
- Erstelle die Anfrage in
brief.json— Dauer, Größe, fps, Beats mit Zeitangaben, wörtlicher Text, Easing, Palette und eine Liste vonAnnahmen. Jede Lücke erhält einen Standardwert aus der Tabelle inreferences/brief.md; nichts bleibt undefiniert und nichts wird hinterfragt. - Zeige die kompakte Zusammenfassung (eine Tabelle, ~12 Zeilen) und baue im selben Schritt. Kein Genehmigungs-Gate.
- Baue aus der Vorlage, validiere, rendere, schaue auf die Bilder.
Die Iteration ist dann eine Feldbearbeitung, kein Neubau. "Mach es knackiger" ändert feel.ease und zwei Dauern; der Code bewegt sich nicht, es sei denn, kind oder motion ändern sich.
Das Briefing ist das Artefakt, das dies günstig macht. Es liegt neben der Komposition auf der Festplatte, sodass eine Überarbeitung ein Diff ist und das erneute Rendern ein einziger Befehl.
Routenauswahl
| Signal | Pfad |
|---|---|
| Frischer Neubau, kein Framework genannt | HyperFrames |
| Vorhandenes HTML/CSS/GSAP/Lottie zur Wiederverwendung | HyperFrames |
Kein node_modules, kein Build-Schritt gewünscht | HyperFrames |
| Team größer als drei Personen | HyperFrames (Lizenz) |
| Benutzer nennt Remotion, oder Repository ist React/TS | Remotion |
| Benötigt ein Designsystem, eine Diagrammbibliothek oder komplexe Komponenten | Remotion |
| Portierung eines bestehenden Remotion-Projekts | Remotion (Portierung kostet mehr als sie spart) |
Wenn der Benutzer beide nennt, baue in HyperFrames und sage in einer Zeile, dass die Remotion-Portierung auf Anfrage verfügbar ist. Zwei vollständige Bauversionen desselben Stücks sind verschwendete Arbeit, es sei denn, ein Vergleich wurde angefordert.
Der Kreislauf
1. Erstelle das Briefing
Erstelle die Anfrage in brief.json bevor du Code schreibst. Das Schema, die kind/motion-Grammatik, die Standardwerte-Tabelle und die Iterationshebel befinden sich in references/brief.md.
node scripts/brief.mjs brief.json # validieren + Zusammenfassungstabelle
node scripts/brief.mjs brief.json --json # Maschinenergebnis
Drucke die Zusammenfassung für den Benutzer, behebe jeden ERROR und fahre dann im selben Schritt fort. Warnungen sind Ermessensentscheidungen – eine Warnung, die du akzeptierst, kommt in die Annahmen.
Das Briefing enthält auch die Metrik. Wähle audio.bpm so, dass das Beat-Raster die Schnitte teilt – bei bpm dauert ein Beat 60 / bpm Sekunden, und jeder beats[].start sollte auf einem landen. 120 BPM ergibt einen Beat alle 0,5 s und passt zu den meisten kurzen Stücken. Wenn brief.mjs off_beat_grid meldet, verschiebe den Schnitt oder ändere das Tempo; ignoriere es nicht, denn das ist der Unterschied zwischen einem Stück, das sitzt, und einem, das sich subtil falsch anfühlt.
Erledigt, wenn brief.mjs mit Exit-Code 0 endet, jeder Beat ein Zeitfenster, eine Art, eine Bewegung und den wörtlichen Text hat und kein Schnitt außerhalb des Beat-Rasters liegt.
2. Gerüst erstellen
Beginne mit den Vorlagen in diesem Skill, nicht mit einer leeren Datei – sie sind korrekt bezüglich beider Verträge und sparen die zwei fehleranfälligen Schritte (Timeline-Registrierung, Sequenz-Timing).
# HyperFrames — einfaches HTML. Die gepinnte Engine installiert sich einmal selbst, was Netzwerk benötigt
cp -R assets/hyperframes/. ./my-video/
node scripts/hf.mjs lint ./my-video
# Remotion — React-Projekt, benötigt seine gepinnten Abhängigkeiten einmal
cp -R assets/remotion/. ./my-video/
cd my-video && npm ci
# PowerShell
Copy-Item -Recurse -Force assets\hyperframes\* .\my-video\
Copy-Item -Recurse -Force assets\remotion\* .\my-video\
Erledigt, wenn node scripts/hf.mjs lint bestanden ist oder npx remotion compositions src/index.tsx die Kompositions-ID auflistet.
3. Baue die Beats
Eine Datei pro Beat. Halte die Timeline flach – absolute Zeiten in HyperFrames, <Sequence> Bilder in Remotion. Aktualisiere den Beat-Plan, wenn der Bau das Timing ändert, und überprüfe dann die Gesamtdauer erneut.
Benenne jede Szene nach ihrem Beat, weil die Prüfungen sie so finden: data-brief-beat="<id>" im HyperFrames-Host, <Sequence name="<id>"> in Remotion. Wenn eine Remotion-Sequenz ihr Timing berechnet, setze auch data-brief-beat="<id>" auf ein Element darin, damit das Timing gemessen werden kann.
Erledigt, wenn jeder Beat im Plan im Code existiert, die Kompositionsdauer mit dem Plan übereinstimmt und es keine TODOs, Platzhalter oder Platzhaltertexte gibt.
4. Überprüfe die Bewegung
Standbilder lügen über das Timing. Schaue auf die Bilder, dann auf den Render.
node scripts/check-contract.mjs --dir ./my-video --preflight # statisch, keine Installation
node scripts/check-contract.mjs --dir ./my-video --runtime # prüft auch in einem Browser
node scripts/hf.mjs check ./my-video # Layout, Bewegung, Kontrast
node scripts/hf.mjs snapshot ./my-video --review # Beat- und Nahtbilder als PNGs
node scripts/hf.mjs keyframes ./my-video --selector "#card" --shot motion.png
npx remotion still src/index.tsx LaunchCard out/f.png --frame=45
npx remotion studio src/index.tsx # sieh es dir mit 1x an
check-contract.mjs fängt die stillen Fehler ein, ohne etwas zu installieren: eine nicht registrierte Timeline, einen nicht übereinstimmenden window.__timelines-Schlüssel, eine nicht pausierte Timeline, eine fehlende Dauer, Math.random() in einer Komposition, ein nicht begrenztes interpolate. Es ist ein Vorflugcheck, kein Ersatz für die echten Linters.
Wenn brief.json im Projekt liegt (oder --brief darauf verweist), vergleicht es außerdem den Bau mit dem Briefing. Jede Anforderung endet als verified, failed oder unverified. unverified ist kein Bestehen und blockiert den Render.
| Code | Status | Bedeutung |
|---|---|---|
brief_format_mismatch | fehlgeschlagen | Breite, Höhe, fps oder Länge weichen von format ab |
brief_scene_count, brief_scene_unmapped | fehlgeschlagen | Ein Beat hat keine Szene, die seine ID deklariert, oder eine Szene hat keinen Beat. Position ist nicht Identität |
brief_timing_mismatch | fehlgeschlagen | Eine Szene beginnt oder dauert nicht das, was das Briefing sagt, innerhalb eines Bildes |
brief_copy_missing | fehlgeschlagen | Die Zeile ist nicht in der Szene. Kommentare und ungenutzte Variablen zählen nicht |
brief_copy_wrong_scene | fehlgeschlagen | Die Zeile ist nur in einer anderen Szene |
copy_not_visible | fehlgeschlagen | Laufzeit: Im DOM, aber versteckt, transparent, außerhalb des Bildschirms, beschnitten, unscharf oder bedeckt |
copy_hold_short | fehlgeschlagen | Laufzeit: Weniger als beats[].hold lesbar |
first_frame_empty | fehlgeschlagen | Laufzeit: visibleAtStart ist gesetzt und nichts vom Beat ist gemalt |
first_frame_unverified | unbestätigt | Laufzeit: Nur eine Grafik ist im ersten Bild, oder der Beat hat keinen Text. Schau dir das Bild an |
brief_timing_unverified, brief_format_unverified | unbestätigt | Die Quelle berechnet es. Die Laufzeit kann es klären |
brief_copy_dynamic, brief_copy_unverified | unbestätigt | Ob es angezeigt wird, ist eine Laufzeitfrage. Remotion-Text ist immer dies bis zur Laufzeit |
Der Abgleich ignoriert Groß-/Kleinschreibung und Leerzeichen und faltet geschweifte Anführungszeichen. Andere Satzzeichen sind signifikant, und "12,480" passt zu einem Zähler, der auf 12480 endet. Wenn Anforderungen unbestätigt bleiben, nenne sie und versuche, sie messbar zu machen, bevor du sie akzeptierst. Eine zu akzeptieren bedeutet, sie zu nennen, mit --allow-unverified "beat.lines.copy[0].visible", und dies dem Benutzer zu melden. Akzeptiere niemals ein pauschales Muster, und Fehlschläge können überhaupt nicht akzeptiert werden. Lese references/validation.md für die genauen Regeln und Grenzen.
Behebe Abweichungen im Code oder ändere das Briefing gezielt und führe brief.mjs erneut aus – lass die beiden niemals uneins sein.
Überprüfe die Bilder – alle Prüfungen können bei einem kaputten Film bestanden sein
Ein bestandener Vertrag sagt, dass Timing und Kopie übereinstimmen und der Text lesbar ist. Er sagt nichts über Palette, Easing, Übergänge oder ob der Film funktioniert. Linting-, Layout-, Bewegungs-, Kontrast- und Handwerksprüfungen haben alle bei der eigenen Vorlage dieses Skills bestanden, während sie bei jedem Beat auf Schwarz schnitt und den Zähler genau in dem Moment beendete, als die Zahl erschien. Nur das Anschauen der Bilder hat es erfasst. Nimm sie auf:
# HyperFrames: Beat-Bilder, ein 5-Bild-Streifen um jeden Schnitt und ein Telefonblatt
node scripts/motion-render.mjs --brief ./my-video/brief.json --snapshot --no-render
# Remotion: Für jeden Schnitt c (in Bildern), nimm c-6, c und c+6, plus die Mitte jedes Beats
# (die Vorlage schneidet bei 75, 210 und 270)
node scripts/motion-render.mjs --dir ./my-video --no-render \
--stills 37,69,75,81,142,204,210,216,240,264,270,276,315
Lies dann die Bilder und beantworte jede Frage. Behebe den Code, nimm erneut auf, schaue noch einmal:
- Ist der Schnitt schwarz? Mehr als ein leeres Bild um einen Schnitt herum bedeutet, dass das Ende zu früh beendet ist und der nächste Beat aus dem Nichts einblendet. Verschiebe das Ende so, dass es auf dem Schnitt endet (
start = Beat-Dauer − End-Dauer). - Hält der Höhepunkt an? Die letzte Zahl eines Zählers oder das letzte Wort einer Zeile bleibt mindestens einen Beat (
60 / bpms) still auf dem Bildschirm, bevor es verschwindet. In dem Moment zu enden, in dem es landet, bedeutet, dass es nie gelesen wird. - Ist es auf einem Telefon lesbar? Überprüfe
review-phone.jpgoder stelle dir das Bild bei 360 px Breite vor. Bei 1080p fallen Beschriftungen und Schlagzeilen unter ~40 px normalerweise durch. - Ist es die Schriftart des Briefings? Ein Fallback wie Segoe UI oder Arial bedeutet, dass die Schriftart nie geladen wurde und eine andere Maschine einen anderen Film rendert.
--runtimewarnt vorfont_fallback, und der Bericht zeichnet die tatsächlich gezeichneten Schriftarten auf. Remotion benötigt@fontsource/*(die Wahl der Vorlage) oder@remotion/fontsfür eine lokale Datei. - Ist es der Übergang des Briefings?
feel.transitionist in den Bildern um jeden Schnitt herum, nicht ein Einblenden auf Schwarz.
Erledigt, wenn du die Beat-Bilder und jeden Nahtstreifen gelesen, jede der obigen Fragen beantwortet hast und jeder Punkt auf der Checkliste unter "Versandcheckliste" zutrifft.
5. Rendern
node scripts/motion-render.mjs --brief ./my-video/brief.json
node scripts/motion-render.mjs --brief ./my-video/brief.json --batch rows.json --no-audio
Der Wrapper liest Pfad, Format, fps und Slug aus dem Briefing und stoppt, bevor Renderzeit aufgewendet wird, wenn das Briefing, die statischen Prüfungen, die Werkzeuge, die Assets oder die Laufzeitprüfung dies sagen. Er beendet sich mit Exit-Code 1 bei einem Fehler und 3 bei nicht bestätigten Anforderungen. --no-checks überspringt die Validierung und zeichnet dies im Bericht auf. Dann lintet, rendert, misst er die Datei mit ffprobe und schreibt <out>.report.json.
Wenn audio.policy generated ist, synthetisiert er auf beiden Pfaden den Hintergrund mit music.mjs, rendert das Bild nur als Video und mischt die beiden mit einem einzigen ffmpeg-Aufruf – sodass die Komposition nie von der Audio-Mischung einer Engine abhängt. Er misst dann, dass die Datei einen Audiostream hat und dieser nicht still ist.
Für Transparenz: --format webm oder --format mov – H.264 kann kein Alpha transportieren. --no-audio überspringt den Hintergrund und liefert eine Datei ohne Audiostream. GIF kann kein Audio transportieren, daher wird ein Briefing mit Hintergrund für GIF abgelehnt, es sei denn, du übergibst --no-audio.
Mit --batch wird ein Briefing plus eine Zeilendatei zu N Videos: HyperFrames rendert Zeilen nativ, Remotion erhält eine Props-Datei pro Zeile. Batch ist nur Video, und ein Briefing mit Hintergrund wird abgelehnt, es sei denn, du übergibst --no-audio.
Erledigt, wenn die Datei existiert, der Bericht rendered sagt, seine notVerified-Liste leer ist oder du dem Benutzer mitgeteilt hast, was darauf ist, und seine ersten und letzten Bilder beabsichtigt sind.
Der Vertrag, der stillschweigend bricht
HyperFrames – vier Dinge, alle obligatorisch:
- Wurzelelement trägt
data-composition-id,data-width,data-height,data-duration,data-start="0". - Jedes zeitgesteuerte Element trägt
id+data-start+data-duration. - Die GSAP-Timeline wird mit
{ paused: true }erstellt. window.__timelines[<data-composition-id>] = tl– gleicher Schlüssel. Nachdem die Tweening-Schritte hinzugefügt wurden. Vergiss dies und du erhältst ein Standbild, keinen Fehler.
Remotion – drei:
registerRoot()in der Einstiegsdatei,<Composition>in der Root-Komponente.interpolate(..., { extrapolateLeft: "clamp", extrapolateRight: "clamp" })– beide Enden clampsen, jedes Mal.- Kein
Math.random(), keinDate.now()in einer Komposition. Verwenderandom(seed).
Die vier Regeln, die entscheiden, ob es günstig liest
Dies sind diejenigen, die am häufigsten schiefgehen. Vollständiger Satz mit Code in references/motion-craft.md.
- Bewege nur das, was lebendig ist. Abgeschlossene Dinge bleiben still. Idle "atmender" Skalierungsfaktor liest sich wie maschinengeneriert.
- Überlappen, nicht in die Warteschlange stellen. Staffelung ≈ 15–30 % der eigenen Dauer des Elements. Das nächste Ding beginnt, während das letzte noch zur Ruhe kommt.
- Kein Überschwingen bei Typ. Überschwingen ist für Objekte mit Masse – Karten, Klappen, Figuren. Text, Zahlen und UI-Beschriftungen verwenden
power3.out/expo.outund überschwingen nie. - Eine Idee pro Bewegung.
y + opacityist "ankommen". Füge Drehung und Skalierung hinzu und das Wort ist während des Flugs unlesbar.
Außerdem: Ein Übergang ist das Ende, nicht ein Ausblenden gefolgt von einem Einblenden. Das erscheint als Jump Cut mit einem Einbruch in der Mitte.
Versandcheckliste
-
brief.jsonvalidiert: Timing-Fliesen, erstes Bild beabsichtigt, End-Haltepunkt ≥ 2 s. -
check-contract.mjs --runtimesagtverified, oder die nicht bestätigten IDs sind namentlich akzeptiert und dem Benutzer gemeldet. - Text, Zahlen, Handles und URLs sind wie geschrieben – kein Lorem, kein Platzhalter.
- Timeline unter der Kompositions-ID registriert (HyperFrames) oder Komposition gelistet von
npx remotion compositions(Remotion). - Linting/Prüfung sauber.
-
<out>.report.jsonsagtrendered, mit der erwarteten Größe, fps, Länge und Audio. - Bilder inspiziert: jeder Beat, jede Naht, Telefonbreite – kein Schwarz an einem Schnitt,
…
[abgeschnitten für Übersetzung]