videolabs: Ein Video erstellen (Terminal-Kurs-Stil)
Alles befindet sich in einem Repository, /opt/opus/videolabs (github.com/bigzaqui/videolabs, öffentlich: niemals Zugangsdaten committen; vor dem Commit scripts/check-secrets.sh ausführen). Die Quelle dieses Skills ist skills/videolabs_create-video/ in diesem Repository, verknüpft in ~/.claude/skills durch scripts/setup.sh. Die Konfigurationswerte (ElevenLabs- und Cloudflare-Schlüssel, der Render-Host) befinden sich in der git-ignorierten .env-Datei im Repository-Stammverzeichnis; siehe .env.example.
Das Repository enthält: eine generische Engine (Remotion + ElevenLabs Tooling, einmal npm ci) und einen Ordner pro Labor unter labs/. Verwendet für "kafka - in a nutshell" (26 Lektionen / 18 Min.), "ceph - first steps" (14 Lektionen / 11,6 Min.) und früher "ceph in a nutshell" (41 Lektionen / 30 Min.; dessen Skript und visuelle Elemente sind in reference/ als Beispiel für Karten, Vergleiche, Messgeräte, Bäume, Vorfälle, Zustände und Standorte erhalten). Beide aktuellen Labore sind praxisorientiert: Jeder Befehl wurde zuerst in einem echten Labor ausgeführt (siehe "Reales Labor").
/opt/opus/videolabs/
engine/ generische Tooling: engine/cli.mjs <lab> <command>, src/ (Remotion), scripts/
labs/<slug>/
lab.config.json Katalogeintrag (Titel, Beschreibung, Tags) + Aussehen (Marke, Logo, Statusleiste, Toolnamen, Beispielausschnitt)
script/script.md Erzählung, eine Szene pro ###-Überschrift
visuals.ts Was jede Szene zeigt + Cue-Überschreibungen
lab/ create-lab.sh, destroy-lab.sh, cap.sh, captures/, lab-meta.json
audio/raw/ ElevenLabs Ausgabe (kostenpflichtig; in git committet)
out/ data/ public/voiceover/ generiert, git-ignoriert
site/ scripts/publish-all.sh state/ die Website und deren Veröffentlichung (Skill videolabs_publish)
script.md ──cli Szenen──▶ data/scenes.json
└─ cli tts (ElevenLabs Wortzeiten) ─▶ audio/raw ──pace──▶ public/voiceover/* + data/{durations,captions}.json
visuals.ts + engine/src/cues.ts (Einblendung = wenn das Wort gesprochen wird) ─▶ Remotion ──cli render──▶ out/<slug>.mp4
cli player ─▶ out/player/{chapters.json,lab.json} ──videolabs_publish──▶ videolabs.pages.dev
Alle Befehle: node engine/cli.mjs <lab> <scenes|tts|pace|cues|stills|typecheck|studio|sample|render|player>, plus list und new <slug> (die README.md des Repos hat die Tabelle). Der Laborordner ist das Einzige, was sich zwischen Kursen unterscheidet; niemals Engine-Code in ein Labor kopieren.
Arbeitsablauf (Stimmen Sie die Gliederung und das Skript mit dem Benutzer ab; alles danach läuft ohne Nachfrage)
Ständige Autorisierung durch den Benutzer: Sobald das Skript vereinbart ist, führen Sie die kostenpflichtigen ElevenLabs tts, die Cue-Überprüfung, das Rendern auf dem Render-Host, den Player/Poster-Schritt und den Laborabbau ohne Erlaubnis für jeden Schritt aus. Melden Sie die Ergebnisse und die neue Länge danach. Halten Sie nur an, um zu fragen, wenn etwas außerhalb dieses Arbeitsablaufs liegt (z. B. eine zerstörende Aktion an Dingen, die das Labor nicht erstellt hat, oder die Veröffentlichung auf der Website, wenn der Benutzer nicht darum gebeten hat).
- Praxisorientiertes Thema? Erstellen und ausführen Sie zuerst ein echtes Labor (siehe "Reales Labor" unten). Schreiben Sie niemals Befehlsausgaben aus dem Gedächtnis: Der erste Entwurf des ceph-first-steps-Skripts war an zehn Stellen falsch, als es auf einem echten Cluster lief. Schreiben Sie dann das Skript basierend auf dem, was wirklich passiert ist.
- Zuerst das Skript, dann das Video. Schlagen Sie eine Gliederung vor (Module → Lektionen, mit dem geplanten Diagramm pro Lektion), holen Sie die Zustimmung ein, dann schreiben Sie
labs/<slug>/script/script.md. Das Ändern von Text ist weitaus billiger als das Neugenerieren von Audio. Markieren Sie mit Geschwindigkeit 1,0 mit Pausen ≈ 160 Wörter pro Minute: 1.500 Wörter ≈ 9,5 Min. inkl. Modulkarten; bei 1,08 ≈ 168 Wörter pro Minute. Überprüfen Sie die tatsächliche Länge mit der Zeile "Paced … total X min" direkt nachttsund passen Sie sie vor dem Rendern an. Für versionsspezifische Befehle überprüfen Sie die aktuelle Version (Dokumente und die Download-/Image-Tags des Projekts) zuerst. Format (geparst vonengine/scripts/build-scenes.mjs):
Beenden Sie die letzte Lektion eines Moduls mit "Modul-Takeaway: …" — das Wort takeaway löst das Takeaway-Fenster aus.## Modul 1 — Kernarchitektur ### S02 · RADOS **Visual:** Notizen für den Designer **Befehle:** `ceph -s` `ceph osd tree` (optional, nur auf dem Bildschirm) **Erzählung:** Ein Absatz, geschrieben zum Sprechen. Befehle buchstabieren wie gesprochen ("ceph dash s"). node engine/cli.mjs new <slug>erstellt das Grundgerüstlabs/<slug>/(Konfiguration, ein Drei-Szenen-Skript, eine visuals.ts); füllen Sielab.config.json(Titel, Beschreibung, Tags für den Katalog;brand,user,logo,statusbar,statusCmd,networkLabels,session,tools,samplefür das Aussehen) aus und führen Sienode engine/cli.mjs <slug> scenesaus.- Visuelle Elemente in
labs/<slug>/visuals.ts(Typen inengine/src/types.ts,colorsvon@engine/theme), ein Eintrag pro Szenen-ID. Diagrammarten (engine/src/components/Diagrams.tsx):topology: Hosts (Name, IP, Daemon-Chips, Festplatten/Replikate) auf einer oder zwei Netzwerkleitungen, eine optionale Statuszeile (statusCmd-Label, Standard aus der Konfiguration) undflows(Blöcke, die sich zwischen Hosts bewegen, voncuebisuntil). Jeder Host/Daemon/Disk/Status kann einencuehaben (erscheint, wenn gesprochen) undchanges: [{cue, state, label}](Festplatteempty|osd|leader|idle|down|destroyed|new, Hostok|spare|down|maint). Elemente ohne Cue sind von Anfang an sichtbar. Bauen Sie den Laborzustand mit Hilfsfunktionen (host(n),built(n)) auf, damit das Diagramm Lektion für Lektion wächst.session: eine realistische Shell; jedercmdtippt sich selbst ein, wenn er gesprochen wird, dann werden seineout-Zeilen gedruckt; behält die neuesten Zeilen.hostsetzt die gesamte Eingabeaufforderung einer Zeile (Standardsession.promptaus der Konfiguration). Optionale kompaktetopologydarüber. Die untere Befehlsleiste ist für Sitzungsszenen ausgeblendet. Andere Arten:title(fastfetch-Karte;user, zusätzlicherows),layers,cards,flow,tree,compare,gauge,terminal(Befehlsausgabe mit Hervorhebungen),incident(Symptom/Prüfung/Aktion),checklist,states,sites; optionaltakeawayundcommandCuespro Szene. Verwenden Sie echte Ausgaben auslab/captures/für jedesoutundsymptom.
- Überprüfen Sie die visuellen Elemente, bevor Sie für Audio bezahlen:
node engine/cli.mjs <slug> stills(ein Frame pro Szene bei 60%;S04,S11 --at=12.5für einen Moment) und zu 2×2 Kontaktabzügen mit ffmpegxstackzusammenstellen, um sie anzusehen. Überprüfen Sie auf Überlauf, Umbruch, leere Layouts. - Sprache: Repository-Stamm
.envmitELEVENLABS_API_KEY/ELEVENLABS_VOICE_ID, dannnode engine/cli.mjs <slug> tts(direkt ausführen, keine Genehmigung erforderlich; überspringt vorhandene;--only=S03,S04 --forcenur um die Szenen zu wiederholen, deren Erzählung sich geändert hat, spart auch Guthaben). Es führtpaceautomatisch aus. Teilen Sie dem Benutzer die neue Länge mit, wenn das Skript gewachsen ist. Committen Sielabs/<slug>/audio/(kostenpflichtige Ausgabe). - Synchronisationsprüfung:
node engine/cli.mjs <slug> cues(nach jeder Änderung an einem Befehl auch seinencommandCues-Eintrag ändern: ein Chip fürdmesg, der immer noch auf "smartctl" gecued ist, ist eine stille Diskrepanz) — listet das Wort, das jedes Element und jede Befehlszeile einblendet (MISS= verteilt zwischen Nachbarn). Korrigieren Sie falsche Treffer mit Cue-Überschreibungen (unten). Wiederholen Sie den Vorgang nach jeder Änderung der Erzählung oder Stimme. - Vorschau:
node engine/cli.mjs <slug> sample(≈1 Min. auf dem Render-Server), stichprobenartige Überprüfung von Frames mitffmpeg -ss <t> -frames:v 1,volumedetectfür Pegel (kein Clipping: max < -1 dB). - Rendern Sie den gesamten Kurs (Remote, unten), dann
node engine/cli.mjs <slug> player, erstellen Sie das Posterlabs/<slug>/out/spot.jpg, zerstören Sie die Labor-VMs und veröffentlichen Sie die gesamte Website mit dem videolabs_publish Skill.
Designregeln, die der Benutzer genehmigt hat
- Aussehen: Omarchy/Hyprland Desktop, Tokyo Night Palette (
src/theme.ts; semantische Namen wierados,mon,cephfssind nur Palettenplätze). Waybar-Leiste mit Modulen als Arbeitsbereiche 0–7, ein Status (HEALTH_WARNim Fehlerbehebungsmodul), Lektionszähler07/41. Ein geteiltes Fenster, 2px quadratischer Rand, keine Eckenrundung/Glanz/Verlauf. Jede Lektion beginnt mit einer getippten robbyrussell-Eingabeaufforderung➜ module-1-core-architecture git:(s03) cat the-daemons.md, dann eine# Überschrift. Notizen werden als// Kommentaredargestellt, Befehle als❯ cmd-Zeilen, Takeaways als schwebendes Fenstercat sre-takeaway.md, Modultrenner alscd module-N-…+ großer Titel, der Opener als fastfetch. Alles in JetBrains Mono; Inter nur für Untertitel. Es ersetzte ein "generisches" dunkles Verlaufs-Aussehen, das der Benutzer nicht mochte. - Einblendungssynchronisation: Niemals nach Zeit staffeln. Jedes Element erscheint, wenn der Sprecher zum ersten Mal seinen Namen nennt (
engine/src/cues.ts: längstes sinnvolles Token, präfixstamm, vorwärts vom vorherigen Cue gesucht). Überschreibungen imvisuals.tsdes Labors:cue: "=managers"exaktes gesprochenes Wort (Bindestriche/Interpunktion ignoriert:"=write-ahead"),cue: null= kein Wort, interpolieren.pointCues(Vergleichsseiten),noteCue(Baum),linkCue(Standorte),cues(Titelabzeichen),commandCues(Befehlszeilen, pro Szene).- Die Label-Reihenfolge in
cueLabels()muss der Index-Reihenfolge entsprechen, die der Renderer inengine/src/components/Visuals.tsxverwendet (Topologie/Sitzung verwenden schlüsselbasierte Traversierung intopologyKeys/sessionKeys). - Ein Vorwärtscursor läuft über alle Labels einer Szene, sodass ein späteres Label, das ein allgemeines Wort wiederverwendet ("three", "recovery", "add"), auf einem späteren Vorkommen landen kann. Bevorzugen Sie ein Wort, das einmal in der Nähe des Moments vorkommt ("=repeat", "=begins"), und lesen Sie immer die
cues-Prüfung.
- Untertitel: einfache Phrasen, getrennt an Satz-/Klauselenden, eine Zeile ≤ 64 Zeichen, keine Karaoke-Hervorhebung pro Wort ("anstrengend").
- Atmung:
engine/scripts/pace.mjsfügt 250 ms nach. ? !und 120 ms nach: ;in das rohe ElevenLabs-Audio ein und verschiebt die Wortzeiten. Schnittpunkte kommen von ffmpegsilencedetect(streng -38 dB/40 ms, dann -30 dB/20 ms), sonst das leiseste 5-ms-Fenster, mit 8 ms Überblendungen — niemals allein von den ElevenLabs-Wortgrenzen (diese landen innerhalb von Wörtern). Passen SieSENTENCE_PAUSE/CLAUSE_PAUSEan, führen Sienode engine/cli.mjs <slug> paceerneut aus (kostenlos; rohes Audio bleibt inaudio/raw/). Die Temposteuerung hängt von der ffmpeg-Version ab (7.1.5 und 8.0.1 ergaben 17,9 und 17,8 Min. für dasselbe Kafka-Audio): Tempo dort steuern, wo Sie rendern, oderdata/undpublic/voiceover/auf den Render-Host kopieren. - Übergänge: 15-Frame-Überblendungen via
@remotion/transitionsTransitionSeries; sie überlappen nur die stille Einleitung (0,4 s) / Ausleitung (0,8 s).engine/src/timeline.tssubtrahiert Überlappungen;engine/scripts/player.mjsundstills.mjsspiegeln diese Konstanten wider — halten Sie sie synchron. - Stimme, die der Benutzer gewählt hat: ElevenLabs "Mark"
v3p1kjzUvro6S76qmYmH(Voice Library; funktioniert für TTS, obwohlGET /v1/voices/{id}404 zurückgibt),eleven_multilingual_v2, Geschwindigkeit 1,08,with-timestamps-Endpunkt,previous_text/next_textfür Kontinuität. Überprüfen Sie immer eine Stimmen-ID mit einem 1-Satz-TTS-Aufruf vor einem vollständigen Durchlauf (eine frühere ID in.envwurde abgeschnitten).
Pro-Kurs-Einstellungen (labs//lab.config.json)
Arbeitsbereiche in der Waybar und die fastfetch-Modul-/Lektionszahlen folgen automatisch den Szenen. Alles andere Kursspezifische sind Daten in der Konfiguration, niemals Code: brand (Waybar-Name), user (Eingabeaufforderung auf der Titelkarte), logo (fünf Zeilen Blockbuchstaben), statusbar (ok/warn-Text, right-Text, warnModule = das Modul, das die Warnung anzeigt), statusCmd und networkLabels (Standardeinstellungen von Topologieszenen), session.prompt/session.title (Terminal-Sitzungen), tools (Befehlswörter, die beim automatischen Cuen einer Befehlszeile übersprungen werden), sample (Szenen-IDs des Beispielausschnitts), plus title, description, tags für den Katalog. Ein neues Labor mit einem anderen Aussehen benötigt keine Engine-Änderung; eine neue Diagrammart oder einen neuen Zustand hingegen schon (engine/src/types.ts, Komponenten, cues.ts) und kommt dann jedem Labor zugute.
Angewandte Remotion-Praktiken (aus den Remotion-*-Skills)
Schriftarten via @remotion/google-fonts (niemals auf Systemschriftarten verlassen); <Audio> von @remotion/media mit from; TransitionSeries; calculateMetadata dimensioniert die Komposition aus Audiodauern; animieren mit interpolate/Easing.bezier und translate (keine CSS-Übergänge). Nicht absichtlich übernommen: Interactive.create/verbundene Kompositionen (nur nützlich für manuelle Bearbeitung im Studio), große Social-Video-Text-Minima, Meme-SFX.
Rendering
VIDEOLABS_RENDER_HOST(SSH-Ziel des Render- und Lab-Servers, Schlüssel bereits eingerichtet) kommt aus der.env-Datei im Repository-Stammverzeichnis: führen Sieset -a; . /opt/opus/videolabs/.env; set +avor den untenstehenden Befehlen aus und schreiben Sie diese Variable, nicht eine wörtliche Adresse, in alles, was Sie committen. Derselbe Host betreibt die Labor-VMs.TMPDIR=/var/tmpwird von der CLI gesetzt:/tmpist ein kleiner RAM-tmpfs auf diesen Hosts und eine lange Audiomischung schlägt am Ende mit "No space left on device" fehl.- Lokale Box (4 vCPU) ≈ 45 Min. pro 30 Min. Video. Remote-Render-Server $VIDEOLABS_RENDER_HOST (Ubuntu 26.04, 24 Threads, 31 GB RAM, RTX 3090 Ti, KVM; Node 22, ffmpeg, rsync und die Chromium-Bibliotheken von apt) rendert den 11,6-minütigen Ceph-Kurs in 3 Min. und den 18-minütigen Kafka-Kurs in 5 Min. bei Gleichzeitigkeit 12–16. Das Repository befindet sich auf beiden Maschinen unter
/opt/opus/videolabs. Ablauf:(Um die gleiche zeitliche Abstimmung wie bei der Überprüfung beizubehalten, synchronisieren Siersync -az --delete --exclude node_modules --exclude out --exclude .env --exclude .git --exclude site --exclude state ./ $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/ # von /opt/opus/videolabs ssh $VIDEOLABS_RENDER_HOST 'cd /opt/opus/videolabs/engine && npm ci && cd .. && node engine/cli.mjs <slug> scenes && node engine/cli.mjs <slug> pace && node engine/cli.mjs <slug> render --concurrency=12 --log=error' rsync -a $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/labs/<slug>/out/<slug>.mp4 labs/<slug>/out/ && node engine/cli.mjs <slug> playerlabs/<slug>/dataundpublic/voiceoverper rsync, anstattscenes/paceauf dem Server auszuführen.) Kopieren Sie niemals.envdorthin. Führen Sie lange Renderings getrennt aus (nohup bash script &gestartet mitssh -f -n) und warten Sie mit einem Monitor auf diereal-Zeile vontime; grep-en Sie nicht das Log nach "error" (die Befehlszeile hat--log=error). Wenn sich der Waybar-/Diagrammcode ändert, überprüfen Sie beide Labore (stills), da sie ihn gemeinsam nutzen. - Überprüfen einer Engine-Änderung: Rendern Sie den Beispielausschnitt mit dem alten und dem neuen Code und vergleichen Sie
ffmpeg -i a.mp4 -i b.mp4 -lavfi ssim -f null -; neu generiertescenes/durations/captions.jsonund diecues-Prüfung müssen …