Communitygithub.com

bigzaqui/videolabs

Remotion + ElevenLabs を用いて、ナレーション付きの約30分の技術ビデオコースを構築します。Omarchy / Tokyo Night ターミナルスタイル(Waybar、タイルドウィンドウ、oh-my-zsh プロンプト、Markdown 見出し)で、画面上のすべての要素がナレーターが発話した瞬間に表示され、文のポーズ、プレーンな字幕、高速なリモートレンダリング、チャプター付きウェブプレーヤーを備えています。ハンズオントピックの場合は、最初に実際のラボ(qemu/KVM VM)を構築し、ラボの実際のコマンド出力を画面とナレーションの両方で使用します。公開は videolabs_publish スキルを使用して videolabs サイト(Cloudflare)に行います。ユーザーが技術トピックの解説/コース/トレーニング/ラボビデオを希望する場合、またはこの方法で作成されたビデオの編集、再音声化、再レンダリング、再公開を希望する場合に使用します。

videolabs とは?

`videolabs` スキルは、開発者向け解説ビデオコースを作成するための総合的なツールチェーンです。Remotion(React ベースの動画フレームワーク)と ElevenLabs(AI 音声合成)を基盤としており、Omarchy / Tokyo Night ターミナルスタイル(Waybar、タイルドウィンドウ、oh-my-zsh プロンプト、Markdown 見出し)で統一されたビジュアルを提供します。このスキルの最大の特徴は、ナレーションと画面上の要素の完全な同期です。各要素は、ナレーターがその名前を発話した瞬間に表示されるように、ElevenLabs のワードタイミング機能とカスタムキューシステムを使用して調整されます。また、ハンズオントピックの場合は、実際の KVM 仮想マシンラボを構築し、そのラボで実行した実際のコマンド出力をビデオ内で使用するため、正確で信頼性の高いコンテンツを提供します。スキルは `/opt/opus/videolabs` リポジトリに基づいており、汎用エンジン(Remotion + ElevenLabs ツール)と各ラボ固有の設定(スクリプト、ビジュアル定義、ラボ環境)を分離しています。ワークフローは、ユーザーとのアウトラインとスクリプトの合意から始まり、その後は ElevenLabs での音声生成、レンダリング、プレーヤー生成、ラボの破棄までを自律的に実行します。レンダリングはリモートの GPU サーバーで高速に行われ(例えば、11.6 分のコースが約 3 分で完了)、最終的なビデオと章立てされたウェブプレーヤーが生成されます。このスキルは、特に技術的なチュートリアル、製品デモ、トレーニング教材の作成に適しており、実際のコマンド出力と視覚的に同期したナレーションを提供することで、視聴者の学習効果を高めます。

対応✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/bigzaqui/videolabs/tree/HEAD/skills/videolabs_create-video

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

videolabs: ビデオを作成する(ターミナルコーススタイル)

すべては /opt/opus/videolabs リポジトリ(github.com/bigzaqui/videolabs、公開: 認証情報は絶対にコミットしないでください。コミット前に scripts/check-secrets.sh を実行してください)にあります。このスキルのソースはそのリポジトリ内の skills/videolabs_create-video/ にあり、scripts/setup.sh によって ~/.claude/skills にリンクされます。設定値(ElevenLabs と Cloudflare のキー、レンダリングホスト)は、git で無視されるリポジトリルートの .env にあり、.env.example を参照してください。

リポジトリには、汎用のエンジン(Remotion + ElevenLabs ツール、npm ci 一回)と、labs/ の下にラボごとのフォルダが含まれています。"kafka - in a nutshell"(26 レッスン / 18 分)、"ceph - first steps"(14 レッスン / 11.6 分)、および以前の "ceph in a nutshell"(41 レッスン / 30 分。スクリプトとビジュアルは reference/ にカード、比較、ゲージ、ツリー、インシデント、ステート、サイトの例として保持)に使用されています。現在の両方のラボはハンズオンです。すべてのコマンドは最初に実際のラボで実行されました(「実際のラボ」を参照)。

/opt/opus/videolabs/
  engine/                       汎用ツール: engine/cli.mjs <lab> <command>, src/ (Remotion), scripts/
  labs/<slug>/
    lab.config.json             カタログエントリ(タイトル、説明、タグ)+ ルック(ブランド、ロゴ、ステータスバー、ツール名、サンプルカット)
    script/script.md            ナレーション、### 見出しごとに1シーン
    visuals.ts                  各シーンに表示する内容 + キューオーバーライド
    lab/                        create-lab.sh、destroy-lab.sh、cap.sh、captures/、lab-meta.json
    audio/raw/                  ElevenLabs 出力(有料; git にコミット)
    out/ data/ public/voiceover/  生成物、git で無視
  site/  scripts/publish-all.sh  state/    サイトとその公開(スキル videolabs_publish)

script.md ──cli scenes──▶ data/scenes.json
   └─ cli tts (ElevenLabs ワードタイミング) ─▶ audio/raw ──pace──▶ public/voiceover/* + data/{durations,captions}.json
visuals.ts + engine/src/cues.ts (reveal = 単語が発話された時) ─▶ Remotion ──cli render──▶ out/<slug>.mp4
cli player ─▶ out/player/{chapters.json,lab.json} ──videolabs_publish──▶ videolabs.pages.dev

すべてのコマンド: node engine/cli.mjs <lab> <scenes|tts|pace|cues|stills|typecheck|studio|sample|render|player>、さらに list と new <slug>(リポジトリの README.md にテーブルがあります)。ラボフォルダだけがコース間で異なります。エンジンコードをラボにコピーしないでください。

ワークフロー(ユーザーとアウトラインとスクリプトに合意します。その後はすべて許可なく実行されます)

ユーザーからの事前許可: スクリプトが合意されたら、有料の ElevenLabs tts、キュー監査、レンダリングホストでのレンダリング、プレーヤー/ポスターのステップ、ラボのティアダウンを、各ステップで許可を求めることなく実行します。その後、結果と新しい長さを報告します。このワークフローの外側にある場合(例: ラボが作成しなかったものに対する破壊的なアクション、ユーザーが要求していないサイトへの公開)にのみ、中断して質問します。

  1. ハンズオントピック?最初に実際のラボを構築して実行します(下記の「実際のラボ」を参照)。コマンド出力を記憶から書かないでください: ceph-first-steps スクリプトの最初のドラフトは、実際のクラスターで実行したところ、10 か所間違っていました。次に、実際に起こったことからスクリプトを書きます。
  2. スクリプトが先、ビデオは後。 アウトライン(モジュール → レッスン、各レッスンに計画された図を含む)を提案し、合意を得てから labs/<slug>/script/script.md を書きます。テキストを変更するのは、オーディオを再生成するよりはるかに安価です。速度 1.0、約 160 wpm のポーズで記述: 1,500 ワード ≈ 9.5 分(モジュールカード込み)。1.08 で ≈ 168 wpm。tts の直後の「Paced … total X min」の行で実際の長さを確認し、レンダリング前に調整します。バージョン固有のコマンドについては、現在のリリース(ドキュメントとプロジェクトのダウンロード/イメージタグ)を最初に確認します。フォーマット(engine/scripts/build-scenes.mjs によって解析):
    ## Module 1 — Core Architecture
    ### S02 · RADOS
    **Visual:** デザイナー向けのメモ
    **Commands:** `ceph -s` `ceph osd tree`        (オプション、画面表示のみ)
    **Narration:**
    朗読用に書かれた1つの段落。コマンドは話し言葉として綴る("ceph dash s" のように)。
    
    モジュールの最後のレッスンは「Module takeaway: …」で終わります。単語 takeaway がテイクアウェイウィンドウをトリガーします。
  3. node engine/cli.mjs new <slug> で labs/<slug>/(設定、3シーンのスクリプト、visuals.ts)をスキャフォールディングします。lab.config.json(カタログ用のタイトル、説明、タグ。ルック用の brand、user、logo、statusbar、statusCmd、networkLabels、session、tools、sample)を入力し、node engine/cli.mjs <slug> scenes を実行します。
  4. ビジュアルは labs/<slug>/visuals.ts(型は engine/src/types.ts、colors は @engine/theme から)にあり、シーンIDごとに1エントリです。図の種類(engine/src/components/Diagrams.tsx):
    • topology: 1つまたは2つのネットワークライン上のホスト(名前、IP、デーモンチップ、ディスク/レプリカ)、オプションのステータスライン(statusCmd ラベル、デフォルトは設定から)、およびフロー(ホスト間を移動するブロック、cue から until まで)。すべてのホスト/デーモン/ディスク/ステータスは cue(発話時に表示)と changes: [{cue, state, label}](ディスク empty|osd|leader|idle|down|destroyed|new、ホスト ok|spare|down|maint)を持つことができます。キューのない要素は最初から表示されます。ヘルパー(host(n)、built(n))を使用してラボの状態を構築し、図がレッスンごとに成長するようにします。
    • session: リアルなシェル。各 cmd は発話時に入力され、その out 行が印刷されます。最新の行を保持します。host は行のプロンプト全体を設定します(デフォルトは設定の session.prompt)。その上にオプションのコンパクトな topology。下部のコマンドバーはセッションシーンでは非表示になります。 その他の種類: title(fastfetch カード、user、追加の rows)、layers、cards、flow、tree、compare、gauge、terminal(コールアウト付きのコマンド出力)、incident(症状/確認/アクション)、checklist、states、sites。シーンごとにオプションの takeaway と commandCues。すべての out と symptom には、lab/captures/ からの実際の出力を使用します。
  5. オーディオ代金を支払う前にビジュアルを確認: node engine/cli.mjs <slug> stills(各シーンから60%のフレームを1枚。S04,S11 --at=12.5 で特定の瞬間)。そして、ffmpeg の xstack を使用して2×2のコンタクトシートに並べて確認します。オーバーフロー、折り返し、空のレイアウトをチェックします。
  6. 音声: リポジトリルートの .env に ELEVENLABS_API_KEY / ELEVENLABS_VOICE_ID を設定し、node engine/cli.mjs <slug> tts を実行します(直接実行、承認不要。既存のものはスキップ。--only=S03,S04 --force でナレーションが変更されたシーンのみを再実行し、クレジットも節約)。自動的に pace を実行します。スクリプトが大きくなった場合は、新しい長さをユーザーに伝えます。labs/<slug>/audio/(有料出力)をコミットします。
  7. 同期監査: node engine/cli.mjs <slug> cues(コマンドを変更した場合は常に、その commandCues エントリも変更: dmesg のチップが「smartctl」でキューされているのは、無言の不一致です)。すべての要素とコマンドラインを明らかにする単語をリストします(MISS = 隣接するものの間に広がる)。キューオーバーライドを使用して誤った一致を修正します(以下を参照)。ナレーションまたは音声を変更した後は、再実行します。
  8. プレビュー: node engine/cli.mjs <slug> sample(レンダリングサーバーで約1分)。ffmpeg -ss <t> -frames:v 1 でスポットチェックフレーム、volumedetect でレベルを確認(クリッピングなし: 最大 < -1 dB)。
  9. フルコースをレンダリング(リモート、以下を参照)。次に node engine/cli.mjs <slug> player、ポスター labs/<slug>/out/spot.jpg を作成し、ラボVMを破棄し、videolabs_publish スキルを使用してサイト全体を公開します。

ユーザーが承認したデザインルール

  • ルック: Omarchy/Hyprland デスクトップ、Tokyo Night パレット(src/theme.ts。rados、mon、cephfs などのセマンティック名は単なるパレットスロット)。ワークスペース0~7のモジュール、ステータス(トラブルシューティングモジュールの HEALTH_WARN)、レッスンカウンター 07/41 を備えた Waybar ストリップ。1つのタイルドウィンドウ、2pxの角ばった境界線、半径/グロー/グラデーションなし。各レッスンは、タイプされた robbyrussell プロンプト ➜ module-1-core-architecture git:(s03) cat the-daemons.md で始まり、次に # Heading。ノートは // comments、コマンドは ❯ cmd 行、テイクアウェイはフローティングウィンドウ cat sre-takeaway.md、モジュール区切りは cd module-N-… + 大きなタイトル、オープナーは fastfetch としてレンダリングされます。すべて JetBrains Mono。字幕のみ Inter。これは、ユーザーが好まなかった「汎用的な」ダークグラデーションルックに取って代わりました。
  • 表示同期: 時間でずらさないでください。各要素は、ナレーターがその名前を最初に発したときに表示されます(engine/src/cues.ts: 最長の意味のあるトークン、接頭辞ステミング、前のキューから前方に検索)。ラボの visuals.ts でのオーバーライド:
    • cue: "=managers" は発話された単語と完全一致(ハイフン/句読点は無視: "=write-ahead")。cue: null = 単語なし、補間。
    • pointCues(比較サイド)、noteCue(ツリー)、linkCue(サイト)、cues(タイトルバッジ)、commandCues(コマンドライン、シーンごと)。
    • cueLabels() 内のラベル順序は、engine/src/components/Visuals.tsx(topology/session は topologyKeys/sessionKeys でキー指定されたトラバーサルを使用)でレンダラーが使用するインデックス順序と一致している必要があります。
    • 1つの前方カーソルがシーンのすべてのラベルを実行するため、共通の単語(「three」、「recovery」、「add」)を再利用する後のラベルは、後の出現箇所に着地する可能性があります。瞬間の近くで1回だけ出現する単語を優先し("=repeat"、"=begins")、常に cues 監査を読みます。
  • 字幕: プレーンなフレーズ。文/節の終わりで分割。1行 ≤ 64 文字。単語ごとのカラオケ強調表示なし(「疲れる」)。
  • 呼吸: engine/scripts/pace.mjs は、生の ElevenLabs オーディオに . ? ! の後に 250 ms、: ; の後に 120 ms を挿入し、ワードタイミングをシフトします。カットポイントは ffmpeg の silencedetect(厳密: -38 dB/40 ms、次に -30 dB/20 ms)から取得されます。そうでない場合は、最も静かな 5 ms ウィンドウ(8 ms フェード)。ElevenLabs の単語境界だけから取得することはありません(単語の途中に着地するため)。SENTENCE_PAUSE/CLAUSE_PAUSE を調整し、node engine/cli.mjs <slug> pace を再実行します(無料。生のオーディオは audio/raw/ に保持)。ペーシングは ffmpeg のバージョンに依存します(同じ Kafka オーディオで、7.1.5 と 8.0.1 はそれぞれ 17.9 分と 17.8 分を与えました)。レンダリングする場所でペーシングするか、data/ と public/voiceover/ をレンダリングホストにコピーします。
  • トランジション: @remotion/transitions TransitionSeries による 15 フレームのクロスフェード。サイレントリードイン(0.4 秒)/テール(0.8 秒)のみをオーバーラップします。engine/src/timeline.ts はオーバーラップを差し引きます。engine/scripts/player.mjs と stills.mjs はこれらの定数をミラーリングします。同期を保ってください。
  • ユーザーが選んだ音声: ElevenLabs "Mark" v3p1kjzUvro6S76qmYmH(Voice Library。GET /v1/voices/{id} は 404 を返しますが TTS では動作します)、eleven_multilingual_v2、速度 1.08、with-timestamps エンドポイント、継続性のための previous_text/next_text。フル実行の前に、常に 1 文の TTS 呼び出しで音声 ID を確認してください(以前の .env の ID は切り捨てられていました)。

コースごとの設定(labs//lab.config.json)

Waybar のワークスペースと fastfetch のモジュール/レッスン数は、シーンに自動的に従います。コース固有のその他はすべて、コードではなく設定内のデータです: brand(Waybar 名)、user(タイトルカードのプロンプト)、logo(ブロック文字の5行)、statusbar(ok/warn テキスト、right テキスト、warnModule = 警告を表示するモジュール)、statusCmd と networkLabels(topology シーンのデフォルト)、session.prompt/session.title(ターミナルセッション)、tools(コマンドラインの自動キューイング時にスキップされるコマンドワード)、sample(サンプルカットのシーン ID)、さらにカタログ用の title、description、tags。異なるルックの新しいラボにはエンジンの変更は必要ありません。新しい図の種類や状態には必要であり(engine/src/types.ts、components、cues.ts)、その後すべてのラボに利益をもたらします。

適用される Remotion のプラクティス(remotion-* スキルから)

@remotion/google-fonts によるフォント(システムフォントに依存しない)。@remotion/media からの <Audio> と from。TransitionSeries。calculateMetadata はオーディオ期間からコンポジションのサイズを決定。interpolate/Easing.bezier と translate でアニメーション(CSS トランジションなし)。意図的に採用していないもの: Interactive.create/接続されたコンポジション(Studio での手動編集にのみ有用)、大きなソーシャルビデオテキストの最小値、ミーム SFX。

レンダリング

  • VIDEOLABS_RENDER_HOST(レンダリングとラボサーバーの ssh ターゲット、キーは既に設定済み)はリポジトリルートの .env にあります。以下のコマンドの前に set -a; . /opt/opus/videolabs/.env; set +a を実行し、リテラルアドレスではなくその変数をコミットするものに記述します。同じホストがラボ VM を実行します。
  • TMPDIR=/var/tmp は CLI によって設定されます: /tmp はこれらのホストでは小さな RAM tmpfs であり、長いオーディオミックスは最後に「No space left on device」で失敗します。
  • ローカルボックス(4 vCPU)≈ 30 分のビデオあたり 45 分。リモートレンダリングサーバー $VIDEOLABS_RENDER_HOST(Ubuntu 26.04、24 スレッド、31 GB RAM、RTX 3090 Ti、KVM。Node 22、ffmpeg、rsync、apt からの Chromium ライブラリ)は、11.6 分の ceph コースを 3 分で、18 分の kafka コースを同時実行数 12~16 で 5 分でレンダリングします。リポジトリは両方のマシンの /opt/opus/videolabs にあります。フロー:
    rsync -az --delete --exclude node_modules --exclude out --exclude .env --exclude .git --exclude site --exclude state ./ $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/   # /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> player
    
    (確認したものとタイミングを同一に保つには、サーバーで scenes/pace を実行する代わりに、labs/<slug>/data と public/voiceover を rsync します。)そこに .env をコピーしないでください。長時間のレンダリングはデタッチして実行し(nohup bash script & を ssh -f -n で開始)、time の real 行を Monitor で待機します。ログから「error」を grep しないでください(コマンドラインに --log=error があります)。Waybar/図のコードが変更された場合は、両方のラボを確認します(stills)。共有されているためです。
  • エンジンの変更を検証: 古いコードと新しいコードでサンプルカットをレンダリングし、ffmpeg -i a.mp4 -i b.mp4 -lavfi ssim -f null - で比較します。scenes/durations/captions.json と cues 監査を再生成する必要があります。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル