Communitygithub.com

businessbaum/vedit

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.

Was ist vedit?

Dieses Skill erzeugt ASS-Untertiteldateien aus Wort-für-Wort-Transkripten und brennt sie mittels libass in Videorenderings ein. Es ist speziell für deutsche Untertitel optimiert und löst zwei zentrale Probleme: Erstens werden deutsche Komposita wie „Geschwindigkeitsbegrenzung“ nicht anhand einer maximalen Zeichenanzahl, sondern über ein Budget für die Pixelbreite gruppiert, sodass sie nicht über den Bildrand ragen. Zweitens wird sichergestellt, dass nur statische, einlagige Schriftdateien in der korrekten *Fontname*-Schreibweise verwendet werden, da variable Schriften (z. B. `InterVariable.ttf`) libass dazu zwingen, auf Arial zurückzufallen, ohne eine Warnung auszugeben. Der Workflow durchläuft fünf Schritte: Auswahl eines Voreinstellungsprofils aus `presets/captions/*.json`, Generierung der ASS-Datei mit strikter Einhaltung des 23-Felder-V4+-Formats und UTF-8-Kodierung, Korrektur von Zahlen und Eigennamen über `captions.overrides[]` (ohne das Transkript zu verändern), Einbrennen im finalen Mux (nicht pro Segment) und eine Qualitätskontrolle, die per Hash-Vergleich nachweist, dass die gewünschte Schriftart tatsächlich geladen wurde. Das Skill unterstützt vertikale Plattformen (große, zentrierte, 1–3 Wörter) ebenso wie YouTube-Langformate und erkennt fehlerhafte Formatzeilen, unerwünschte Dateien im Schriftenverzeichnis sowie veraltete ASS-Dateien nach Schnittänderungen. Entwickler erhalten damit eine reproduzierbare, automatisierte Pipeline für professionelle, deutsch-kompatible Untertitel, die stille Fehler wie Schriftausweichungen oder falsche Zeilenumbrüche zuverlässig abfängt.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/businessbaum/vedit/tree/HEAD/.agents/skills/captions

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation


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:

DateiASS FontnameBold
Inter-Regular.ttfInter0
Inter-Bold.ttfInter-1
Inter-SemiBold.ttfInter SemiBold0
Inter-ExtraBold.ttfInter ExtraBold0
Montserrat-Bold.ttfMontserrat-1
Montserrat-ExtraBold.ttfMontserrat ExtraBold0

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 Events Format:-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 und burn_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

SymptomUrsacheBehebung
Untertitel sehen aus wie ArialVariable Schrift oder falscher FontnameStatische Datei + exakter nameID 1-String; QC (e) ausführen
Störendes Komma im Text, keine KonturFehlerhafte Format:-ZeileKanonische 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 BildNach max_chars gruppiertPixelbreiten-Budget plus automatische Schrumpfung einzelner Wörter
No option name near '/Users/...'fontsdir einfach maskiertDoppelter Backslash vor dem Doppelpunkt
Untertitel schreiben Zahlen aus--suppress_numerals, wie vorgesehencaptions.overrides-Einträge
Untertitel nach erneutem Schnitt desynchronisiertVeraltete ASSNeu erzeugen; niemals Timings von Hand patchen

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

businessbaum/vedit

This skill should be used when the user asks for mechanical tightening of material that is already selected - "mach den Rohschnitt", "bau den Rohschnitt", "schneid die Ähms raus", "nimm die Füllwörter raus", "entferne die Pausen", "kürz die Pausen", "schneid die Versprecher raus", "mach den Radioschnitt", "straff das", "build the rough cut", "cut the fillers", "remove the ums", "tighten the pauses", "trim the dead air", "cut the retakes", "radio edit". Turns kept story blocks into enabled segments in project.json. Does not decide what the video is about - that is cut-story.

businessbaum/vedit

This skill should be used when the user asks to decide what the video is actually about before any mechanical cutting - "bau die Story", "was soll ins Video", "was kann raus", "welche Themen bleiben", "kürz das auf 6 Minuten", "mach daraus ein kurzes Video", "wo ist der Hook", "sortier die Themen", "worum geht es hier eigentlich", "build the story", "decide what stays", "structure this", "cut this down to N minutes", "find the hook", "reorder the topics". This is the CONTENT-selection pass that writes the "story" block in project.json; it runs after transcribe and before cut-rough.

businessbaum/vedit

This skill should be used when the user asks for the finished video file - "exportier das", "render das fertig", "mach das final", "renderte das Video", "mach den Endexport", "bau das Video zusammen", "mach es fertig für YouTube", "gib mir die MP4", "export the final", "render the final cut", "make the master", "export for TikTok", "give me the mp4". Covers segment rendering with the cache, guarded concat, the one-pass audio, loudness normalisation and the single mux.

Verwandte Skills