Mit Code kurze Videos erstellen
Der Bildschirm wird nur durch die Zeit bestimmt: Die Seite legt window.render(t) offen. Gib eine Sekundenzahl an, und sie zeichnet den entsprechenden Frame. Das Rendering-Skript verwendet einen kopflosen Chrome, um jeden Frame aufzurufen und Screenshots zu machen. ffmpeg kombiniert die Screenshots mit dem Voice-Over zu einer MP4-Datei. Die Änderung der Visuals erfolgt durch Code-Änderungen; eine erneute Wiedergabe genügt.
Diese Methode stammt von einem Beitrag von xilo auf X (2026-09-29, https://x.com/xilo2991/status/2104912748794589515). Dieses Skill erweitert diesen Ansatz um Voice-Over-Synchronisation, Cover-Generierung, Standbildprüfung und eine Reihe von Regeln für das Schreiben von Skripten und das Zeichnen von Szenen.
Erste Schritte
Erforderlich: Node 20+, uv, ffmpeg und Google Chrome auf dem lokalen Rechner. Standardschriftarten sind die macOS-eigenen Songti, PingFang und SF Mono; für andere Systeme ersetze die Schriftarten in brand.json unter dem Schlüssel fonts.
- Kopiere das gesamte Verzeichnis
template/dieses Skills in ein neues Projektverzeichnis. - Führe im neuen Verzeichnis
npm installaus (installiert nurplaywright-core). - Bearbeite
brand.json:seriesist der Serienname oben links auf dem Cover,handleist der Name auf dem Cover und am Ende,avatarist der relative Pfad zum Profilbild (kannnullsein),colorsundfontssind Farbschema und Schriftarten. - Führe das Beispiel aus:
uv run tools/voice.py demo # Voice-Over, Musik, Timeline -> episodes/01-demo/build/
node tools/render.mjs demo --stills auto # Ein Standbild am Ende jeder Szene
node tools/render.mjs demo # Komplette Wiedergabe -> episodes/01-demo/out/video.mp4 und cover.png
sh tools/covers.sh demo # 4:3- und 3:4-Cover
sh tools/sheet.sh demo # Cover und letzte Frames aller Szenen zu einem Kontaktblatt in build/sheet.png zusammensetzen
Im Befehl wird nur der Slug verwendet; das Skript findet das Verzeichnis episodes/<Episodennummer>-<slug>/. Die Sprachausgabe sendet den Voice-Over-Text an den Online-TTS-Dienst von Microsoft.
Projektstruktur
brand.json: Marke. Hier ändern, nicht an der Engine.src/lib.js: Zeichenwerkzeuge, verfügbar unterwindow.E.src/run.js: Timeline-Steuerung. Frame 0 ist das Cover, nach 0,3 Sekunden wird nahtlos in die erste Szene eingeblendet; Szenen sind horizontal angeordnet und werden durch Schwenken verbunden; Untertitel und Fortschrittsbalken werden hier ebenfalls gezeichnet.src/stage.html: Rendering-Seite.tools/voice.py: Zeilenweises Synthetisieren des Voice-Overs mit wortgenauen Zeitstempeln zur Bestimmung der Segmentanfänge, Hinzufügen von Hintergrundmusik und Soundeffekten, Lautstärke auf -14 LUFS normalisiert. Bei unvollständiger Synthese wird wiederholt; nach drei Fehlern wird abgebrochen.tools/render.mjs: Vier Seiten parallel für Frames, ffmpeg-Codierung, 30 fps.tools/covers.sh,tools/cover-vertical.mjs: 4:3-Querformat-Cover (16:9-Cover mit Hintergrundfarbe oben/unten) und separat layoutetes 3:4-Hochformat-Cover.tools/sheet.sh: Extrahiert Cover und letzte Frames jeder Szene aus dem fertigen Video und erstellt ein Kontaktblatt.episodes/<Episodennummer>-<slug>/: Ein Verzeichnis pro Episode mitscript.json,shots.jssowie den generierten Verzeichnissenbuild/undout/.
Ablauf einer Episode
In der angegebenen Reihenfolge vorgehen; der nächste Schritt wird nicht ausgeführt, bevor der vorherige abgeschlossen ist.
Inhalt und Fakten bereitest du selbst vor; dieses Skill beginnt mit dem Schreiben des Skripts.
- Skript: Erstelle
episodes/<Episodennummer>-<slug>/und schreibescript.json. Die Episodennummer wird auch incover.noeingetragen. - Visuals: Schreibe
shots.jsim selben Verzeichnis. Die Anzahl der Szenen entspricht der Anzahl der Voice-Over-Zeilen. - Voice-Over:
uv run tools/voice.py <slug>. Bei Änderungen am Voice-Over, an der Stimme oder am Cover-Text muss dies erneut ausgeführt werden. - Standbildprüfung: Siehe Abschnitt "Standbildprüfung".
- Fertiges Video:
node tools/render.mjs <slug>, danncovers.shundsheet.shausführen. Das Kontaktblatt überprüfen. - Abgabe: Siehe letzten Abschnitt dieses Dokuments.
Bei Änderung der Episodennummer: Ändere sowohl das Verzeichnisnamen-Präfix als auch cover.no, dann Voice-Over und Rendering erneut ausführen. Nur Cover-Text ändern erfordert kein erneutes Voice-Over: Ändere cover in script.json, ersetze cover in build/timeline.js durch denselben Inhalt, dann Rendering und covers.sh erneut ausführen.
script.json
{
"title": "Dieses Video ist mit Code gemalt",
"cover": { "no": "01", "lines": ["Dieses Video", "ist mit Code gemalt"], "hot": 1, "tag": "Keine Bearbeitungssoftware und kein Videomodell" },
"voice": "zh-CN-YunxiNeural",
"rate": "+6%",
"lines": [["Jeder Frame, den du siehst,", "ist mit Code gemalt."], ["Die Seite legt nur eine Funktion offen:", "Gib ihr eine Zeit,", "sie zeichnet den Moment."]]
}
- Eine Zeile ist eine Szene. Jeder Satz innerhalb einer Zeile ist ein visueller Beat. Sätze können als
[gesprochener Text, Untertiteltext]geschrieben werden: Sprich "fünfundsiebzig Prozent", zeige "75%"; Englische Begriffe, die schwer auszusprechen sind, können auf diese Weise korrigiert werden. - Cover:
linesmaximal zwei Zeilen,hotist die Zeile, die die Hauptfarbe verwendet,tagist ein Hook mit einer konkreten Zahl oder Schlussfolgerung,noist die zweistellige Episodennummer. Cover-Titel, Plattformtitel und erster Voice-Over-Satz behandeln dasselbe Thema.
Wie schreibt man ein Skript
- Für vertikale Kurzvideos sind 75–90 Sekunden und 8–9 Szenen angemessen. Bei einer Sprechgeschwindigkeit von +6% etwa 4,8 Zeichen pro Sekunde (inkl. Pausen) und Voice-Over von etwa 380–430 Zeichen (chinesische Zeichen plus englische Wörter). Bei Überschreitung zuerst Zeichen streichen, dann Voice-Over.
- In den ersten zwei Sekunden das interessanteste Element dieser Episode zeigen. Bevor das Skript geschrieben wird, beantworte: Was ist der eigentliche Haken dieser Episode? Normalerweise eine kontraintuitive Zahl, ein konkretes Ergebnis oder ein Problem des Publikums. Das Voice-Over beginnt nach 0,5 Sekunden (siehe
HEADintools/voice.py); bis Sekunde 2 sind nur 8–9 Zeichen möglich. Also muss der erste Satz kurz sein und genau diesen Haken enthalten. Die erste Szene zeigt ihn innerhalb von 1,2 Sekunden in großer Schrift; dertagdes Covers wiederholt ihn. Verwende die Formulierung des Publikums und füge Themenschlüsselwörter hinzu (z. B. "Zieh die Inferenzintensität nicht zu hoch", dann erst "von High auf Max, Kosten 2,9x, nur 0,6 Punkte mehr"). Keine Einleitung, keine Selbstvorstellung, kein "Heute sprechen wir über", kein bloßes "Was ist X?", keine leeren Hooks ohne Informationen. Dies ist eine vorläufige Erkenntnis aus wenigen Videos und wird als zu validieren behandelt. - Die folgenden Sequenzen können als Ausgangspunkt dienen, entsprechend dem Inhalt anpassen.
- Tutorial-Typ: Endergebnis → Schritt für Schritt → Häufige Fallen → Ein Satz Abschluss.
- Produktvorstellung: Welches Problem löst es? → 2–3 Hauptfunktionen, eine pro Szene → Wie starten? → Ein Satz Abschluss.
- Konzepterklärung: Schlussfolgerung und Zahlen → Alte Methode oder häufiges Missverständnis → Wo liegt das Problem? → Neue Methode → Konkreter Mechanismus → Messung oder offizielle Daten → Ein Satz Abschluss.
- Forschungsergebnis: Schlussfolgerung und Zahlen → Häufiges Missverständnis → Wie wurde das Experiment durchgeführt? → Ergebnisse → Weitere Forschung → Ursache → Ein Satz Abschluss.
- Abschluss: Zuerst die Schlussfolgerung oder Vorgehensweise in einem Satz, dann eine Frage, die das Publikum aus eigener Erfahrung beantworten kann ("Welche Stufe verwendest du normalerweise?"), um Kommentare anzuregen. Die Frage sollte mit dem angepinnten Kommentar übereinstimmen. Auch dies nach vorläufiger Erkenntnis behandeln, basierend auf der Anzahl der Kommentare. Keine separate Szene für Einschränkungen; Datenbedingungen stehen als Fußnoten in der Datenszene.
- Nicht sagen "In der nächsten Episode" oder "In der letzten Episode erwähnt", da die Veröffentlichungsreihenfolge variieren kann. Bei Bezug auf andere Episoden: "In der Episode über XX".
- Wenn die Quelle eine Fehlertoleranz angibt, werden Unterschiede innerhalb der Toleranz als "fast unverändert" beschrieben. Selbst berechnete Zahlen müssen bei der Abgabe als schwache Beweise gekennzeichnet werden.
- Keine URLs im Voice-Over, kein "Geh auf die Website" oder "Suche nach XX" (die Plattform betrachtet dies als externe Weiterleitung, siehe video-publish Skill).
Wie malt man die Visuals
shots.js ist ein sofort aufgerufener Funktionsausdruck, der am Ende window.SHOTS = [...] schreibt. Jede Szene ist (c, k) => {}:
cist der 2D-Kontext eines 1920×1080 Canvas.k.at(i, delay, dur)gibt den Fortschritt (von 0 bis 1) des i-ten Satzes nachdelaySekunden innerhalb vondurSekunden mit einer Ease-Out-Funktion zurück;k.rawist linearer Fortschritt;k.tist die vergangene Zeit innerhalb der Szene;k.dist die Dauer dieser Voice-Over-Zeile;k.segssind die Sekunden jedes Satzes relativ zum Szenenstart.- Zeichenwerkzeuge unter
window.E:title(Szenentitel mit Markenstrich),txt,measure,rise(Einblenden mit Verschiebung),pop(Einblenden mit Skalierung),rrect,path(Polylinie nach Fortschritt zeichnen),arrow,chip(Tag-Block),code(Schreibmaschinen-Code-Block),stroke(Markenstrich),mark(Profilbild),sign(Abspann),fmt, FarbpaletteC, SchriftartenF. Lies zuerst die Funktionssignaturen insrc/lib.js. Fehlende Werkzeuge werden im eigenenshots.jsder Episode definiert, nicht inlib.jsoderrun.jsfür eine einzelne Szene ändern.
Regeln:
- Jeder Satz entspricht einem neuen visuellen Element. Innerhalb von 2–4 Sekunden muss eine Veränderung stattfinden. Eine Szene behandelt nur eine Sache und verwendet Grafiken: Prozesspfeile, Punktmatrizen, Vergleichsbalken, Code-Blöcke, Tabellen. Keine Vollbild-Text.
- Linksbündig, asymmetrisch. Keine dunklen Hintergründe mit großen zentrierten Schriften, keine gemeinsamen Einblendungen aller Elemente, kein Leuchten.
- Die Hauptakzentfarbe markiert "die Zahl, die man sehen soll" und steht nicht für gut oder schlecht; die Pointierfarbe wird maximal ein- bis zweimal pro Bildschirm verwendet.
- Schriftgrößen basierend auf vertikal gehaltenem Smartphone bei horizontalem Bildschirm:
txterhöht Schriftgrößen unter 56 (aus 24 wird 34px, aus 30 wird 38px). Informationsschriften mindestens 30; Fußnoten können 24 sein. Breitenberechnung basiert auf der erhöhten Größe; monospaced Schriftzeichen etwa 0,6-fache der Schriftgröße. - Layout-Ränder: Untertitel unter y=932; eine Zeile etwa 30 Vollbreitzeichen; Cover-Hook-Satz etwa 14 Vollbreitzeichen bis zum Profilbild; Szenen haben 1,025-faches langsame Zoomen; Randelemente mindestens 20px Abstand; Fußnoten mit Größe 24 etwa 48 Vollbreitzeichen pro Zeile.
- Songti Black hat kein "÷", "×" wird als sehr großes X gezeichnet: Operatoren mit PingFang zeichnen oder als "geteilt durch" / "mal" schreiben. Bei 200px großen Titeln können absteigende englische Buchstaben die nächste Zeile berühren.
- Wenn der erste Satz sehr kurz ist, besteht die Gefahr eines leeren Bildschirms zu Beginn der Szene: Das Gerüst der Grafik (Achsen, Tabellenüberschriften, Umrisse) mit dem ersten Satz einführen, Daten mit den folgenden Sätzen erscheinen lassen.
- Nicht gemessene Daten werden als "schematisch" gekennzeichnet. Aus Originaldiagrammen abgelesene Zahlen: Fußnote "Aus Originaldiagramm abgelesen". Datenquellen am unteren Rand der Datenszene: nur Name ("Quelle: Offizielle Dokumentation von XX"), keine Domain oder URL.
- Jede Szene verwendet
E.titlefür den Titel; die letzte Szene verwendetE.signfür den Abspann.
Standbildprüfung
node tools/render.mjs <slug> --stills auto erstellt ein Standbild am Ende jeder Szene; --stills 0,t1,t2,… erstellt Standbilder zu bestimmten Sekunden (0 ist das Cover). Zwischenframes werden ca. 0,4 Sekunden nach Start jeder Zeile und ca. 1 Sekunde nach jedem Satz aus der build/timeline.js dieser Episode gelesen. Jeder --stills-Befehl löscht die vorherige Charge, also in Batches prüfen oder Zeitpunkte in einem Befehl zusammenfassen. Bei vielen Bildern mit ffmpeg zu einem Kontaktblatt kombinieren; Cover und letzte Frames in Originalgröße prüfen.
Einzeln prüfen:
- Text ragt aus Karten, Code-Blöcken, Tabellenspalten oder wird von Untertiteln/Fortschrittsbalken verdeckt.
- Rechtsbündige Zahlen kollidieren mit linken Labels; Achsenbeschriftungen und Kurvenlabels überlappen sich.
- Ist der letzte Frame jeder Szene der informationsreichste? Fehlen Elemente?
- Sind die beiden Cover-Zeilen zu klein? Ist der Hook-Satz zu breit?
- Gibt es 2–3 Sekunden ohne neue Elemente, insbesondere zu Beginn einer Szene?
Probleme beheben und nicht mit bekannten Überläufen rendern. Bei nur visuellen Änderungen direkt erneut rendern.
Bekannte Einschränkungen
- edge-tts verwendet die inoffizielle Microsoft-Schnittstelle. Version 7.2.8 gab ab 2026-10 einen 403-Fehler zurück (rany2/edge-tts #490);
tools/voice.pyist auf den Fix-Commit für PR #491 festgelegt; nach offiziellem Release aufedge-tts==<neue Version>umstellen. Bei erneutem 403 im Upstream-Repository nachsehen. - Agent kann Voice-Over nicht hören: Aussprache und Geschwindigkeit englischer Begriffe müssen von einer Person gehört werden. Unterbrechungen während der Synthese werden von
voice.pydurch Längenprüfung abgefangen. - Keine Bewegungsunschärfe, kein Schnitt nach Musikbeat.
Bei Abgabe zu erklären
- Voice-Over wurde von keiner Person gehört.
- Ergebnis der Standbildprüfung, einschließlich bekannter verbleibender Probleme.
- Pfade des fertigen Videos, der drei Cover und des Kontaktblatts sowie die Dauer.