name: captions description: Dieses Skill wird verwendet, wenn der Nutzer nach Untertiteln oder Bildschirmtext fragt – „brenn die Untertitel ein“, „mach Untertitel“, „Untertitel drauf“, „leg Untertitel drüber“, „brenn die Subs ein“, „mach die Captions“, „Wort für Wort Untertitel“, „Karaoke-Untertitel“, „korrigier den Untertitel-Text“, „burn in the captions“, „add subtitles“, „burn the subs“, „word-by-word captions“, „fix a caption typo“. Es umfasst die ASS-Erzeugung, die Pixelbreiten-Gruppierungsregel für Deutsch, die Schriftartentabelle und das Einbrennen via libass. argument-hint: [Projekt-Kürzel] [Voreinstellung] arguments: [Projekt, Voreinstellung]
captions
Erzeugt eine ASS-Untertiteldatei aus dem Wort-für-Wort-Transkript und brennt sie in das Rendering ein.
Argumente: $project Kürzel, $preset ein Name aus presets/captions/*.json. Vollständige Anfrage in
$ARGUMENTS. Ein leerer $-Platzhalter bedeutet, dass das Skill automatisch ausgelöst wurde, nicht per
Slash-Befehl: Nimm das Projekt aus PIPELINE_STATE im Sitzungskontext und gib an, welches du gewählt hast.
Verbnamen folgen dem Build-Vertrag; python engine/ve.py --help gewinnt.
Zwei deutschspezifische Regeln, die darüber entscheiden, ob dies funktioniert
1. Niemals nach max_chars gruppieren
Deutsche zusammengesetzte Substantive sind einzelne, untrennbare Token, die jede Zeichenbegrenzung sprengen.
Geschwindigkeitsbegrenzung hat 26 Zeichen und belegt bei 90 px ungefähr 60 % eines 1920er Bildes. Eine
max_chars: 22-Regel kann es nicht trennen, also überläuft es entweder den Bildrand oder der Gruppierer
gibt stillschweigend eine Zeile aus, die er versprochen hat, nicht auszugeben.
Gruppiere stattdessen nach einem Pixelbreiten-Budget, mit einer automatischen Schrumpfregel für einzelne
Wörter, die das Budget allein überschreiten. estimate_text_width_px() übernimmt die Messung;
group_words() übernimmt das Budget. Die Details leben in docs/fonts.md und im Modul-Docstring von engine/vedit/captions.py.
Dies ist der häufigste deutsche Untertitelfehler und er ist vollständig vermeidbar.
2. Die Schriftart muss eine statische, einlagige Datei sein, benannt nach ihrer exakten nameID 1
Variable Schriften können in ASS nicht per Schriftstärke ausgewählt werden. InterVariable.ttf rendert
via libass byte-identisch zu Arial – gleiche md5 –, während es protokolliert, dass die Datei geladen wurde.
Exit 0, keine Warnung. Style: D,Inter,...,Bold=-1 ergibt DirectWrite Arial und niemand bemerkt es,
bis der Export auf YouTube ist.
Verwende nur diese, mit der exakten Fontname-Zeichenkette und dem Bold-Wert:
| Datei | ASS Fontname | Bold |
|---|---|---|
Inter-Regular.ttf | Inter | 0 |
Inter-Bold.ttf | Inter | -1 |
Inter-SemiBold.ttf | Inter SemiBold | 0 |
Inter-ExtraBold.ttf | Inter ExtraBold | 0 |
Montserrat-Bold.ttf | Montserrat | -1 |
Montserrat-ExtraBold.ttf | Montserrat ExtraBold | 0 |
assets/fonts/ enthält ausschließlich Schriftarten. libass lädt jede dort gefundene Datei und gibt bei
allem anderen einen Fehler aus – eine versehentliche README.md erzeugt Error opening memory font 'README.md'. Dieses Verzeichnis ist aus genau diesem Grund eine ask-Berechtigung in den Einstellungen; wenn ein Dokument zu den Schriften gehört, kommt es in docs/fonts.md.
Schritt 1 – Wähle eine Voreinstellung
presets/captions/*.json enthält Stil, Gruppierungsbudget, Position und Hervorhebungsverhalten.
Wähle nach output.platform, nicht nach Geschmack:
- Vertikale Plattformen benötigen große, zentrierte, 1–3 Wörter, hoch im sicheren Bereich – das untere Drittel liegt unter der eigenen Benutzeroberfläche der Plattform.
- YouTube-Langformat benötigt zwei Zeilen, unten verankert, so groß, dass ein Smartphone-Zuschauer es lesen kann.
Bestätige die Wahl mit dem Benutzer vor der Erzeugung und nenne, was sich ändert.
Schritt 2 – Erzeuge die ASS-Datei
python engine/ve.py captions $project --preset $preset
Zwei strukturelle Anforderungen, die bei Verletzung beide stillschweigend fehlschlagen:
- Die 23-Felder V4+
Style: Format:-Zeile (Name..Encoding, libass' eigene Feldliste – das 24. Feld,AlphaLevel, ist SSA v4 und nicht ASS V4+) und die 10-Felder EventsFormat:-Zeile müssen kanonisch sein, und die Zeile darunter muss exakt so viele Spalten haben. Ein Zählfehler führt dazu, dass libass mit Exit 0 beendet, ein störendes Komma in den gerenderten Text einfügt und stillschweigend Kontur und Fettschrift fallen lässt. Reproduziert mit einem 5-Felder-Format gegen ein 6-Felder-Dialogue-Ereignis.captions.validate_ass()prüft beide Zählungen vor jedem Brennvorgang; es ist nicht optional undburn_in()verweigert die Ausführung bei einem Fehler. - Die Datei ist UTF-8. Deutsche Sonderzeichen werden durch libass korrekt hin- und zurückverwandelt, wenn sie es ist –
Größe Straße Übermäßig äöüÄÖÜßwurde Ende-zu-Ende verifiziert.
Die Begleitdatei wird nach projects/<slug>/out/captions.ass geschrieben und über captions.sidecar_path referenziert.
Das Timing stammt aus derselben Wortliste, aus der die Schnitte stammen, abgebildet auf die Zeitachsenpositionen
in _computed. Untertitel werden daher durch jede Schnittänderung ungültig – nach einem erneuten Schnitt neu
erzeugen, nicht flicken.
Schritt 3 – Korrigiere den Text, nicht das Transkript
Zahlen sind das vorhersehbare Problem. --suppress_numerals ist bei der Transkription zwingend erforderlich, also
sagt das Transkript zwanzig, wo der Sprecher „20“ gesagt hat. Korrigiere es in
captions.overrides[] als {word_index, text}, niemals durch Bearbeiten des Transkripts – das
Transkript ist der Anker für jeden Wortbereich im Projekt, und eine Umschreibung desynchronisiert die Schnitte.
Gleiches gilt für Eigennamen, Produktnamen und GmbH-artige Abkürzungen. Sammle sie in einem Durchlauf,
indem du nach Wörtern mit niedrigem score suchst: Der Alignment-Score ist als Füllsignal nutzlos, aber er
ist ein gutes „Der Aligner war sich bei diesem Wort nicht sicher“-Signal, was genau wie ein Eigenname aussieht.
Schritt 4 – Einbrennen
python engine/ve.py render $project
Das Einbrennen erfolgt im finalen Mux, einmalig, über das verkettete Video – niemals pro Segment. Ein pro-Segment-Einbrennen rendert denselben Untertitel an jeder Grenze neu und landert eine Teilzeile auf jeder Seite eines Schnitts.
Das Escaping von subtitles= und fontsdir= ist exakt und nicht offensichtlich. Überall Vorwärtsschrägstriche,
und der Wert in Anführungszeichen mit einem einfach maskierten Laufwerksdoppelpunkt:
subtitles='C\:/Users/me/.../out/captions.ass':fontsdir='C\:/Users/me/.../assets/fonts'
escape_filter_path() in vedit/ffmpeg.py ist dafür zuständig und gibt die Zeichenkette einschließlich ihrer
Anführungszeichen zurück – füge keine eigenen hinzu. Die Anführungszeichen, nicht die Verschachtelungstiefe,
sind entscheidend: Die nackte, einfach maskierte Form schlägt mit No option name near '/Users/...' fehl,
und nur die zitierte Form übersteht ein Komma, Semikolon oder eine Klammer im Pfad, die alle unter Windows
erlaubt sind. escape_filter_path_nested() gibt die verdoppelte, nicht zitierte C\\:/...-Variante für
jeden zurück, der sie benötigt, mit dieser Einschränkung dokumentiert.
Alles durchläuft eine argv-Liste von Python aus. Der gleiche Pfad, erstellt in Git Bash, wird zu
C\;C:\Program Files\Git\Users\... – live reproduziert, nicht theoretisch.
Setze captions.enabled und captions.burn_in, und setze stage auf "captions".
Schritt 5 – Beweise, dass die Schriftart tatsächlich geladen wurde
QC-Prüfung (e) ist obligatorisch und dies ist der einzige Weg, um stilles Fallback zu erkennen. Rendere einen
Untertitel-Frame mit dem Projektstil und einen mit einem Arial-Kontrollstil, und stelle sicher, dass die
Hashes unterschiedlich sind. Identische Hashes bedeuten, dass libass zurückgefallen ist und der Export im
falschen Schriftbild ausgeliefert wird.
Überprüfe dann auch: Feldanzahlen in Format:-Zeilen, keine Zeile überschreitet das Pixelbudget und kein
Untertitel überschreitet eine Segmentgrenze so, dass ein Fragment übrig bleibt.
Fehlermodi
| Symptom | Ursache | Behebung |
|---|---|---|
| Untertitel sehen aus wie Arial | Variable Schrift oder falscher Fontname | Statische Datei + exakter nameID 1-String; QC (e) ausführen |
| Störendes Komma im Text, keine Kontur | Fehlerhafte Format:-Zeile | Kanonische 24/10-Felder-Zeilen ausgeben |
Error opening memory font 'README.md' | Nicht-Schriftdatei in assets/fonts/ | Nur Schriftarten in diesem Verzeichnis |
| Ein langes Wort läuft aus dem Bild | Nach max_chars gruppiert | Pixelbreiten-Budget plus automatische Schrumpfung einzelner Wörter |
No option name near '/Users/...' | fontsdir einfach maskiert | Doppelter Backslash vor dem Doppelpunkt |
| Untertitel schreiben Zahlen aus | --suppress_numerals, wie vorgesehen | captions.overrides-Einträge |
| Untertitel nach erneutem Schnitt desynchronisiert | Veraltete ASS | Neu erzeugen; niemals Timings von Hand patchen |