Demo Video Subtitler
Problem
Bildschirmaufnahmen von Produktdemos verfehlen ihr Publikum aus drei Gründen, die nichts mit dem Produkt zu tun haben: Der UI-Text ist in der falschen Sprache, er ist zu klein zum Lesen, und das Video hat oft gar keine Tonspur (stille Aufnahmen). Der Zuschauer sieht Klicks passieren, kann aber nicht nachvollziehen, warum. Untertitel beheben das – aber nur, wenn sie so gestaltet sind, dass sie über einer unübersichtlichen Benutzeroberfläche lesbar sind, dort platziert werden, wo sie das Demonstrierte nicht verdecken, und zeitlich so abgestimmt sind, dass sie nie durch einen Übergang abgeschnitten werden.
Dieses Skill ist die vollständige Pipeline, einschließlich der nicht offensichtlichen Fehlermodi, die Stunden kosten, wenn man sie auf die harte Tour entdeckt.
Wann verwenden
- „Füge Untertitel zu diesem Demo-Video hinzu“ / „Untertitele diese Aufnahme für unser koreanisches Team“
- Eine stille Bildschirmaufnahme (
.mp4, ohne Audiospur oder mit Audio, das nur Hintergrundmusik ist), bei der die Geschichte allein durch den Untertiteltext erzählt werden muss - Eine englischsprachige Produktdemo, die einem nicht-englischsprachigen Publikum gezeigt wird
- Untertitel existieren bereits, sitzen aber mittig unten und verdecken das Demo-Panel – stattdessen wird eine focus-following-Platzierung benötigt
- Generieren eines Leseskripts für einen Moderator, der über das Video sprechen wird (siehe „Begleitende Verwendung“)
Verwenden Sie dieses Skill nicht für: Synchronisation mit synthetischer Stimme (das ist eine TTS-Pipeline) oder das Extrahieren von bereits auf einer Plattform vorhandenen Untertiteln.
Installation (ein Befehl)
scripts/bootstrap.sh --dry-run # Nur Prüfung: gibt genau aus, was fehlt
scripts/bootstrap.sh # Installiert, was fehlt (fragt einmal nach)
scripts/bootstrap.sh --yes --lang ja # Unbeaufsichtigt; bereitet auch japanische Schriftarten vor
bootstrap.sh ist idempotent – es tut nichts auf einem Rechner, der bereits bereit ist. Es erkennt die Plattform und wählt den richtigen Installer (Homebrew / apt / dnf / pacman / winget / scoop) und fällt darauf zurück, ein statisches ffmpeg in ~/.local/bin abzulegen, wenn kein Paketmanager verfügbar ist. Führen Sie es als erste Aktion einer Sitzung aus, die Untertitel brennen wird; Skills haben keinen Installationszeitpunkt-Hook, daher ist dieses Skript der Installer.
Voraussetzungen
Führen Sie zuerst die integrierte Prüfung aus – sie untersucht den Rechner und sagt Ihnen genau, was fehlt:
scripts/doctor.sh "Hiragino Sans GB" # Übergeben Sie die CJK-Schriftfamilie, die Sie verwenden möchten
Was geprüft wird und der Installationsbefehl, wenn etwas fehlt:
| Anforderung | Warum | Installieren |
|---|---|---|
ffmpeg mit libass erstellt | Brennt die .ass-Untertitel (-vf ass=...) | macOS brew install ffmpeg; Windows: gyan.dev vollständiger Build; Debian apt install ffmpeg |
--enable-fontconfig im ffmpeg-Build | Löst Schriftarten nach Familiennamen auf; ohne erhalten Sie eine stille Fallback-Schriftart | Dieselben Builds wie oben enthalten es |
| Eine CJK-Schriftfamilie, die das System auflösen kann | Der Untertiteltext selbst | macOS: Hiragino Sans GB (vorinstalliert) · Windows: Microsoft YaHei (vorinstalliert) · Linux: apt install fonts-noto-cjk |
python3 (optional) | Nur export_cues.py; Standardbibliothek, keine pip-Installationen | macOS: xcode-select --install; Linux: apt install python3 |
bash, zip (optional) | Skripte und Paketierung für die Verteilung | Überall vorinstalliert |
Kein Node, kein ImageMagick, keine pip-Pakete, keine API-Schlüssel. Ein vision-fähiges Modell (der Agent selbst) liest die Bilder – das ist nichts, was man installiert.
Zwei Umgebungsnotizen, die beißen:
- Setzen Sie
ffmpegaufPATH, oder exportieren Sie seinen Speicherort für die Skripte:FFMPEG=/pfad/zu/ffmpeg scripts/burn.sh .... - Windows: libass löst Schriftarten je nach Build über fontconfig/DirectWrite auf. Wenn Untertitel in der falschen Schriftart gerendert werden, installieren Sie fontconfig (
scoop install fontconfigoder MSYS2) und überprüfen Sie erneut mitfc-match "Microsoft YaHei:bold".
Pipeline
Arbeiten Sie von oben nach unten. Überspringen Sie Phase 2 nicht – jede spätere Phase hängt von der Kenntnis der UI-Geometrie ab.
Phase 1 – Bestandsaufnahme (2 Minuten)
scripts/probe.sh EINGABE.mp4
Notieren Sie: Dauer, Auflösung, Bildrate, Bitrate, ob eine Audiospur vorhanden ist. Führen Sie die Audioprüfung innerhalb des Skripts durch (durchschnittliche Lautstärke + Stillekarte).
Entscheidung aus der Audioprüfung:
| Audio-Befund | Untertiteltyp |
|---|---|
| Keine Audiospur vorhanden | Erzählungs-Untertitel – Sie verfassen die Geschichte („Was passiert / Warum es wichtig ist“) |
| Audio vorhanden, aber keine Sprache (nur Musik) | Wie oben. Bestätigen Sie, indem Sie einen 10-Sekunden-Ausschnitt transkribieren: Ein ASR-Tool, das bei lauten Audiodaten leer oder nahezu leer zurückgibt, bedeutet Musik, nicht Sprache |
| Sprache vorhanden | Dialog-Untertitel – transkribieren Sie zuerst mit Zeitstempeln, dann bereinigen Sie; erfinden Sie keinen Text |
Phase 2 – Visuelle Analyse und Geometrie (die Phase, die Leute überspringen)
Extrahieren Sie Bilder mit 2 fps (ein 60-Sekunden-Clip → ~120 Bilder; überprüfen Sie zuerst jedes 4. Bild für den Bogen, dann zoomen Sie auf den Text):
scripts/split_frames.sh EINGABE.mp4 bilder/ 2
Erstellen Sie drei Artefakte, bevor Sie einen einzigen Untertitel schreiben:
-
Beat-Tabelle –
| Zeit | Was sich auf dem Bildschirm geändert hat | Bildschirmtext (wörtlich) |. Ein „Beat“ ist jede Änderung: eine Benachrichtigung erscheint, ein Panel schiebt sich herein, ein Button wird geklickt, ein Scrollen, ein Seitenwechsel, ein Übergang. Notieren Sie Übergangstypen (weißer Blitz, Schnitt, Schwarz) – Untertitel dürfen sie nicht überschreiten. -
UI-Text, wörtlich, aus der Quellauflösung gelesen. Verkleinerte Vorschaubilder verwischen kleine UI-Texte, und Sie werden sie falsch transkribieren. Zuschneiden aus der Originaldatei:
ffmpeg -i IN.mp4 -ss 12.5 -frames:v 1 -vf "crop=W:H:X:Y,scale=2*iw:-1" out.jpg(-ssnach-ifür bildgenaue Extraktion; siehe Fallstricke.) -
Geometriekarte – die Pixelgrenzen des „live“-Panels (des demonstrierten Objekts) in Quellpixeln. Messen Sie es, schätzen Sie es nicht:
scripts/find_edge.sh EINGABE.mp4 30 2880 300 # t=30s, Streifen von x=2880, 300px breitLesen Sie dann das zurückgegebene Streifenbild und notieren Sie, wo die linke Kante des Panels innerhalb des Streifens liegt; addieren Sie diesen Offset zur x-Koordinate des Streifens, um die absolute Kante zu erhalten. Wiederholen Sie dies für andere Szenen, wenn sich das Layout ändert (z. B. öffnet sich später ein Chat-Panel).
Regel, die aus der Geometriekarte folgt: Der Untertitel lebt in der freien Region neben dem Demo-Panel, niemals darauf. Siehe Phase 5.
Phase 3 – Erstellen des Untertiteltextes
Zwei Regeln bestimmen alles:
- Eine Idee pro Cue. Maximal 2–3 kurze Zeilen. Ein Cue ist ein Satz, kein Absatz.
- Lesegeschwindigkeitsbudget. CJK: 3,5–5,5 Zeichen pro Sekunde ist angenehm; über 6 ist hektisch; unter 3 wirkt tot. Latein: 12–18 Zeichen pro Sekunde. Berechnen Sie es, raten Sie nicht.
scripts/export_cues.pygibt die Dichte pro Cue aus, sobald Sie eine.ass-Datei haben – iterieren Sie anhand dieser Zahl.
Cue-Timing-Regeln:
- Starten Sie den Cue genau, wenn der visuelle Beat eintrifft, nicht vorher. Wenn eine Benachrichtigung bei 1,0s eingeblendet wird, beginnt der Cue bei 1,0s.
- Beenden Sie Cues vor einem Übergang (weißer Blitz / Schnitt), lassen Sie mindestens 0,8s tote Luft dazwischen. Ein Untertitel, der einen Übergang überbrückt, wirkt wie ein Fehler.
- Lassen Sie echte Lücken. Drei bis fünf leere Sekunden pro Minute hält das Video atmend; durchgehende Untertitel ermüden den Zuschauer.
- Für Erzählungs-Untertitel setzen Sie den Grund in den Untertitel, nicht die Mechanik: „Der Agent hat von sich aus Kontakt aufgenommen“ schlägt „Eine Benachrichtigung erschien in der oberen rechten Ecke“.
Halten Sie hier an und lassen Sie den Text abzeichnen. Text genehmigt → Gestaltung. Text nach der Gestaltung abgelehnt, kostet einen zweiten Render ohne Grund.
Phase 3b – Auswahl der Untertitelsprache
Die Pipeline ist sprachunabhängig, aber drei Dinge müssen pro Sprache vor der Gestaltung entschieden werden.
1. Schriftfamilie – wählen Sie eine, die die Plattform auflösen kann (mit scripts/doctor.sh <lang> überprüfen):
| Untertitelsprache | macOS | Windows | Linux |
|---|---|---|---|
| Chinesisch (zh) | Hiragino Sans GB / PingFang SC | Microsoft YaHei | Noto Sans CJK SC |
| Japanisch (ja) | Hiragino Sans | Yu Gothic / Meiryo | Noto Sans CJK JP |
| Koreanisch (ko) | Apple SD Gothic Neo | Malgun Gothic | Noto Sans CJK KR |
| Latein (en/fr/de/es…) | Helvetica Neue | Segoe UI | Inter / DejaVu Sans |
2. Lesegeschwindigkeit – das Budget ist skriptabhängig; scripts/export_cues.py wählt automatisch das richtige aus (--lang überschreibt) und markiert Cues, die es überschreiten:
| Schrift | Angenehm | Als zu schnell markieren |
|---|---|---|
| Han / Kana (zh, ja) | 3,5–5,5 Zeichen/s | > 6,0 |
| Hangul (ko) | 4,0–6,0 Zeichen/s | > 6,5 |
| Latein | 12–18 Zeichen/s | > 19 |
3. Zeilenumbruch – Chinesisch und Japanisch haben keine Wortzwischenräume: brechen Sie an Satzzeichen (U+FF0C, U+3001, U+3002, U+FF1A) und teilen Sie niemals einen Produktnamen. Koreanisch und Latein brechen an Leerzeichen; lassen Sie eine koreanische Partikel an ihrem Nomen haften. Wenn eine Zeile nicht passt, brechen Sie um, bevor Sie die Schrift verkleinern – eine kleinere Schriftart kostet mehr Lesbarkeit als eine zusätzliche Zeile.
4. Zeilenbreite nach Schrift – die Glyphenbreite ist nicht über Skripte hinweg gleich, daher ergibt dieselbe Fontsize unterschiedliche Zeilenlängen. Budgetieren Sie Zeilen als floor(verfügbare_px / (fontsize * k)), wobei k grob 1,0 für Han und 1,05–1,1 für Hangul und Kana (sie setzen breiter) und 0,5 für Latein im Durchschnitt ist (es variiert mit dem Wort).
Gemessen bei 4K mit Fontsize 165: 13 Hangul-Zeichen ≈ 2.150 px (sicher in einem 2.450 px-Slot), während 18 Zeichen ≈ 2.970 px – das läuft über und schiebt die Zeile über die linke Kante des Bildes. Wenn eine Zeile nicht passt, brechen Sie sie um; verkleinern Sie nicht die Schrift, um sie passend zu machen.
Zweisprachige Untertitel (Original + Übersetzung): nur wenn beide Zeilen kurz sind. Zwei Sprachzeilen verdoppeln die Leselast und konkurrieren in einer Demo mit der Benutzeroberfläche. Bevorzugen Sie eine Sprache pro Version der Datei, es sei denn, der Kunde wünscht etwas anderes; wenn Sie müssen, stapeln Sie das Original oben und die Übersetzung darunter, und budgetieren Sie den gesamten Block gegen die Lesegeschwindigkeit der Übersetzung.
Rechts-nach-links-Schriften (Arabisch, Hebräisch): libass unterstützt RTL, aber die Formqualität hängt vom harfbuzz des Builds ab. Rendern Sie ein Vorschaubild, bevor Sie sich festlegen – überprüfen Sie, ob Buchstaben korrekt verbunden sind und der Ausrichtungsanker noch sinnvoll ist.
Die Schriftstärke unterscheidet sich je nach Schrift. Japanische und koreanische Schriftfamilien erscheinen normalerweise bei gleicher Fontsize visuell größer als eine chinesische Familie; überprüfen Sie mit einem Vorschaubild und passen Sie nach Augenmaß an, nicht nach Regel.
Phase 4 – Stil (der zweischichtige Glow)
Ein einzelner ASS-Stil kann „weißen Text mit einem dicken farbigen Umriss und einem weichen farbigen Halo“ nicht erzeugen – Outline zeichnet nur einen Ring. Verwenden Sie zwei Ereignisse pro Cue auf zwei Ebenen:
| Ebene | Füllung | Umriss | Weichzeichner | Zweck |
|---|---|---|---|---|
| 0 | transparent (&HFF000000) | breit, halbtransparentes Lila | \blur 20–30 | der Halo |
| 1 | weiß | schmaler, deckend Lila | keiner / \blur1 | der lesbare Text |
Ausgangspunkt (siehe assets/caption-template.ass). Farben sind &HAABBGGRR – Alpha 00 ist deckend, FF ist vollständig transparent, und die Byte-Reihenfolge ist BGR:
lila RGB(124,46,240) → &H00F02E7C
Halo, 35 % deckend → &H55F02E7C
Skalieren Sie nach PlayRes, nicht nach Geschmack: Ein 4K-Render verwendete „fontsize 180 / outline 16 / halo 28 / blur 24“; derselbe Look bei 1080p ist „80 / 7 / 12 / 12“. Setzen Sie PlayResX/Y auf die Ausgabeauflösung und behalten Sie ScaledBorderAndShadow: yes bei.
Phase 5 – Platzierung, die dem Fokus folgt
Mittig unten ist für Demos falsch: Unten befindet sich normalerweise die Benutzeroberfläche, und das Demo-Panel ist das eine, das sichtbar bleiben muss. Verankern Sie jeden Cue in der freien Region neben dem, was gerade gezeigt wird:
| Fokus dieses Cues | Anker | Warum |
|---|---|---|
| Ein Seiten-/Chat-Panel ist offen | \an6\pos(<panel_links - 40>, <panel_vertikale_mitte>) | Rechte Kante schmiegt sich an das Panel, der Block wächst nach links, Breitenänderungen erfordern keine Neuberechnung |
| Ein Toast/Benachrichtigung oben rechts | \an3\pos(<toast_rechts>, <toast_unten + 80>) | Anker unten rechts setzt den Block direkt unter den Toast |
| Ganzseitige Seite, kein Panel | \an5\pos(<visuelle_mitte_x>, <y zwischen zwei Inhaltsblöcken>) | Zentriert, aber in einer gemessenen Lücke platziert – nicht im geometrischen Zentrum |
| Titelkarte mit großer eingebauter Schrift | \an5\pos(mitte_x, UNTERHALB des Titels) | Das geometrische Zentrum kollidiert mit der eigenen Überschrift des Videos |
Berechnen Sie die maximale Zeilenbreite vor dem Schreiben: max_line_px ≈ fontsize × zeichen. Wenn eine Zeile die freie Region überschreiten würde, brechen Sie sie um (verkleinern Sie niemals die Schrift nur für einen einzelnen Cue) – teilen Sie an Satzzeichen und halten Sie Produktnamen unzerbrochen.
Für rechtsverankerte Blöcke ist ein Überlauf von einigen zehn Pixeln über flachen Hintergrund in Ordnung und sieht beabsichtigt aus; ein Überlauf auf das Demo-Panel ist es nicht.
Halten Sie den Anker vom Bildrand fern. Der Umriss und der Halo erstrecken sich über die Glyphenbox hinaus um etwa outline + blur Pixel (bei 4K mit outline 15 / blur 22 sind das ~40 px, plus Anti-Aliasing). Ein \an3-Anker, der 50 px vom rechten Rand entfernt platziert wird, bekommt daher seinen Halo abgeschnitten und liest sich wie ein kaputtes Wort. Parken Sie Anker mindestens 150 px innerhalb des Bildes und überprüfen Sie das Ergebnis in einem Vorschaubild – Abschneiden ist in der .ass-Datei unsichtbar und auf dem Bildschirm offensichtlich.
Phase 6 – Einbrennen
scripts/burn.sh EINGABE.mp4 subs.ass AUSGABE.mp4 [crf]
Dies ist -i IN -vf "ass=subs.ass" -c:v libx264 -crf 17~18 -pix_fmt yuv420p -movflags +faststart, wobei die originale Audiospur erhalten bleibt. Harte Untertitel sind der richtige Standard für Demos – sie überleben jeden Player, Upload und jede Bildschirmfreigabe; liefern Sie eine .ass/.srt nur auf Anfrage mit.
Phase 7 – Verifizieren
Rendern Sie zuerst günstige Standbilder, dann überprüfen Sie die codierte Datei:
scripts/preview_frame.sh EINGABE.mp4 subs.ass 16.0 /tmp/check1.jpg
Überprüfen Sie jedes Bild auf: Text über dem Demo-Panel, Text außerhalb des Bildes, unerwarteter Zeilenumbruch, ein Cue, der hätte enden sollen, Halo, der über einem hellen Hintergrund zu Matsch geworden ist. Extrahieren Sie dann 3 Bilder aus der fertigen Datei (Untertitel sind eingebrannt, Qualität ist endgültig) und bestätigen Sie erneut.
Fallstricke (jeder hat echte Zeit gekostet, um ihn zu finden)
-ssvor-ischaltet denass-Filter stumm. Die Eingabesuche setzt Zeitstempel auf Null zurück, sodass der Filter den Untertitelzustand bei t≈0 für jedes Bild rendert. Ergebnis: Das Video brennt ohne Untertitel, und ffmpeg gibt keinen Fehler aus. Setzen Sie-ssimmer nach-i(Ausgabesuche) oder fügen Sie-copytshinzu. Die mitgelieferten Skripte machen dies bereits.- Vorschaubild-Koordinaten lügen. Ein auf 1280×720 skaliertes Bild, das Ihnen aber in …
… (truncated) angezeigt wird, ergibt falsche Zuschneidekoordinaten. Extrahieren Sie Zuschnitte immer aus der Originalauflösung mit -ss nach -i und scale=2*iw:-1, nicht aus einem herunterskalierten Vorschaubild.
3. Einzelner ASS-Layer kann keinen Glow rendern. \blur wird auf den gesamten Layer angewendet, nicht auf eine separate Umrisslinie. Sie müssen zwei Ereignisse auf zwei Layern verwenden (siehe Phase 4). \blur auf einen Text mit einer Fill``-Farbe anzuwenden, die Weiß ist, macht den Text unscharf; es erzeugt keinen äußeren Glow. 4. **Untertitel, die Szenenübergänge überbrücken, sehen aus wie ein Fehler.** Der Zuschauer liest den Untertitel, während die Szene wechselt, und der Text „springt“ auf den neuen Hintergrund. Beenden Sie den Cue mindestens 0,8s vor dem Übergang und beginnen Sie den nächsten nach dem Übergang. 5. **Die Lesegeschwindigkeit ist für CJK anders als für Latein.** 15 Zeichen pro Sekunde sind für Latein angenehm, aber für Chinesisch tödlich schnell. Passen Sie Ihr Timing an die Skriptspezifikationen in Phase 3b an. 6. **Die Schriftgröße muss je nach Ausgabeauflösung skaliert werden.** Ein bei 4K perfektes Fontsize 180ist bei 1080p riesig. Verwenden SieScaledBorderAndShadow: yesund passen Sie dieFontsize proportional zur Auflösungsänderung an. 7. **Die Zeilenbreite variiert je nach Skript.** Han-Zeichen sind breiter als lateinische Zeichen bei gleicher Schriftgröße. Budgetieren Sie Zeilen basierend auf Phase 3b, nicht auf einer einzigen Regel. 8. **scripts/preview_frame.sherfordert eine.ass-Datei und ein Quellvideo, kein ausgegebenes Video.** Wenn Sie ein Standbild aus der gebrannten Datei extrahieren möchten, verwenden Sie ffmpeg` direkt.
Mitgelieferte Assets und Skripte
assets/caption-template.ass– Startpunkt für den Stilscripts/bootstrap.sh– Plattformerkenner + Paketmanager-Installer + statischer ffmpeg-Dropscripts/doctor.sh– Überprüft ffmpeg, fontconfig, Schriftarten, Python und Ausführungsrechtescripts/probe.sh– Gibt Dauer, Auflösung, fps, Bitrate, Audiospur aus, erkennt Musik vs. Sprachescripts/split_frames.sh– Extrahiert Bilder mit einer einstellbaren Bildratescripts/find_edge.sh– Schneidet einen vertikalen Streifen aus, um die Grenzen des Panels zu findenscripts/preview_frame.sh– Extrahiert ein Einzelbild mit Untertiteln für die visuelle Überprüfungscripts/export_cues.py– Gibt die Cue-Dichte aus (Zeichen/s) und markiert zu schnelle Cuesscripts/burn.sh– Einbrenn-Wrapper mit Standard-crf 17–18, yuv420p, faststart
Jedes Skript akzeptiert --help. Alle Skripte laufen ohne sudo – sie installieren Pakete nur in den Benutzerbereich, wenn möglich, und geben eine Warnung aus, wenn ein Systempaket benötigt wird.
Begleitende Verwendung
Dieses Skill wird häufig mit einem Geschichtenschreiber-Skill kombiniert: Das Demo-Subtitler-Skill erstellt die .ass-Datei und brennt sie ein; ein Geschichtenschreiber-Skill kann denselben Cue-Text als Skript für einen menschlichen Moderator oder als Eingabe für ein TTS-System aufbereiten. Das Cue-Timing in der .ass-Datei ist die einzige Ground-Truth – leiten Sie daraus das Skript ab, nicht aus einem Transkript des Videos.