visual-indexer
visual-indexer
course-bundleの全スクリーンショットをカタログ化し、分類・OCR・メタデータ付与を行うスキル。
推奨実行モデル & 並列化
モデル: sonnet 必須(opusはコスト3-5倍。精度差は小さい)
1回の実行で全フレームをReadするためコスト最大。sonnet並列を厳守。
並列化: 章をN分割してN Agent並列起動
| 章数 | 推奨並列度 | 各Agent担当章数 |
|---|---|---|
| ~12章 | 2 Agent | 6章ずつ |
| ~24章 | 4 Agent | 6章ずつ |
| ~36章 | 4-6 Agent | 6-9章ずつ |
| 36章+ | 6 Agent | 6-10章ずつ |
Agent起動テンプレート:
Agent(
model: "sonnet",
mode: "bypassPermissions",
run_in_background: true,
prompt: "Process chapters NN-NN of [bundle_path]..."
)
注意: visual-indexerは画像を全Read するため最もコスト重い。必ずsonnet+並列。opusで全章順次は禁じ手。
WHAT — 何をするか
コースの全チャプターに含まれるスクリーンショット画像を1枚ずつ読み取り、以下を行う:
- フレーム分類 — コア型7種 + 講座固有型(custom_types)で画像を分類
- OCR抽出 — 画像内のテキストをすべて抽出
- ビジュアル要素の特定 — 図形、矢印、ボックス等の視覚要素を記録
- キーワード付与 — ダウンストリームのスキルが検索しやすいようにタグ付け
- インデックス生成 — チャプター別
visual-index.json+ 全体visual-catalog.json
WHY — なぜ必要か
- procedure-extractorが手順画像を紐付けるのにOCR情報とフレーム分類が必要
- concept-extractorがスライド画像を補強材料として使う
- talking_headやtransitionを除外することで後段の処理コストを削減
- コース全体の画像資産を俯瞰できるカタログが必要
HOW — 実行手順
Phase 0: 準備・検証
BLOCKER: manifest.jsonが存在するか確認
→ 存在しない場合は course-ingest を先に実行するよう案内して停止
manifest.jsonを読み込み、チャプター一覧とスクリーンショットディレクトリを取得- 各チャプターのスクリーンショットディレクトリの存在を確認
- 全フレーム数をカウントし、処理計画を立てる
Phase 0.5: 講座固有型の発見
各章の最初の5フレームをサンプル読みし:
- コア型に当てはまるか判定
- 当てはまらない画面が2枚以上ある → 講座固有型を提案
- ユーザーまたはメインセッションに型定義を提示(章の最初だけ)
- 確定したら
visual-index.jsonのcustom_typesに登録 - 以降のフレームはコア型 + 講座固有型から選択
注: 完全自動化する場合は、Phase 0.5でAgent自身が判断して登録する。
Phase 1: チャプター別フレーム処理
各チャプターについて以下を実行:
Step 1.1: フレーム一覧取得
ls chapters/{chapter_id}/screenshots/
Step 1.2: バッチ処理(5-10枚ずつ)
BLOCKER: 各画像は必ずReadツールで読み取ってから分類する
→ ファイル名からの推測は NG
各フレームについて:
- Readツールで画像を読み取る
- フレーム分類 — 以下のタクソノミーで分類:
コア型(全講座共通):
| type | 説明 | ダウンストリームでの使われ方 |
|---|---|---|
title_slide |
章タイトル | マニュアルの見出し画像 |
content_slide |
概念図・スライド | concept-extractorの補強 |
browser_screenshot |
ブラウザ画面 | procedure-extractorの手順画像 |
terminal_screenshot |
コマンドライン | procedure-extractorの手順画像 |
diagram |
フローチャート・図解 | 概念関係の可視化 |
talking_head |
話者の映像のみ | 低価値、スキップ可 |
transition |
空白・遷移フレーム | スキップ |
コア型に当てはまらない繰り返し画面は 講座固有型(custom_types) として登録する(後述)。
講座固有型(custom_types)
コア型に当てはまらないが、講座内で繰り返し出現する画面は講座固有型として動的に作成する。
作成ルール
-
最初の3-5フレームを見て型候補を検討
-
「コア型に当てはまらない」かつ「2枚以上出る」 → 講座固有型として登録
-
命名は snake_case、講座のキーワードを含む
- 例:
tmux_pane,vscode_editor,ae_timeline,figma_canvas
- 例:
-
1講座あたり最大5型まで(無限増殖防止)
-
1枚しか出ない型は作らず、コア型のうち最も近いものに割り当て
-
OCR抽出 — 画像内の全テキストを
text_content配列に格納 -
ビジュアル要素特定 —
visual_elements配列に記録 -
キーワード付与 — 内容を表すキーワードを
keywords配列に格納 -
信頼度判定 —
confidenceをhigh/medium/lowで設定 -
UI操作判定 — ブラウザ/ターミナル画面の場合
is_ui_walkthroughを設定
Step 1.3: visual-index.json 生成
チャプターの全フレーム処理が完了したら visual-index.json を生成:
{
"chapter_id": "03",
"custom_types": {
"tmux_pane": "tmuxで複数paneに分割されたClaude Code画面(タイトルバーにtmux表記、画面分割あり)"
},
"frames": [
{
"filename": "frame_005.jpg",
"type": "content_slide",
"text_content": ["AIマインド", "壁打ち", "アイデア", "専門知識"],
"visual_elements": ["equation_diagram", "four_boxes", "arrow"],
"keywords": ["4原則", "マインド"],
"confidence": "high"
}
]
}
出力先: chapters/{chapter_id}/visual-index.json
スキーマ: schemas/visual-index.schema.json に準拠すること。
Phase 2: visual-catalog.json 生成
全チャプターの処理完了後、コース全体のカタログを生成:
{
"course_name": "YouTube Booster",
"total_frames": 245,
"course_custom_types": {
"tmux_pane": {"definition": "tmuxで複数paneに分割されたClaude Code画面", "frame_count": 18},
"vscode_editor": {"definition": "VS Codeのエディタ画面(ファイルツリー+エディタ+ステータスバー)", "frame_count": 8}
},
"type_distribution": {
"content_slide": 89,
"browser_screenshot": 45,
"talking_head": 67,
"diagram": 23,
"title_slide": 12,
"transition": 9
},
"chapters": [
{
"chapter_id": "03",
"frame_count": 31,
"high_value_frames": ["frame_005.jpg", "frame_012.jpg"],
"visual_index_path": "chapters/03/visual-index.json"
}
]
}
high_value_frames:content_slide,browser_screenshot,diagramのうちconfidence: "high"のものtype_distribution: 全チャプターのフレームタイプを集計
出力先: プロジェクトルートの visual-catalog.json
Phase 3: 自己検証
以下のチェックリストを全て通過すること:
- 全フレームに
typeが設定されているか -
text_contentが空のcontent_slideがないか(スライドには必ずテキストがある) -
talking_headのフレーム数が妥当か(通常20-40%) -
visual-catalog.jsonのtotal_framesが実際のファイル数と一致するか - 各
visual-index.jsonがschemas/visual-index.schema.jsonに準拠しているか -
type_distributionの合計がtotal_framesと一致するか -
custom_typesの数は5以下か - 各
custom_typeに定義文があるか - 各
custom_typeを使ったフレームが2枚以上あるか -
custom_typeの命名が snake_case か
検証失敗時:
→ 不一致があれば該当チャプターを再処理
→ text_contentが空のcontent_slideがあれば画像を再読み取り
BLOCKER ゲート
| Gate | 条件 | 未達時の対応 |
|---|---|---|
| G1 | manifest.jsonが存在する | course-ingestを先に実行するよう案内 |
| G2 | スクリーンショットディレクトリが存在する | video-to-framesを先に実行するよう案内 |
| G3 | 各画像をReadツールで実際に読み取った | ファイル名推測は禁止、必ず読み取る |
| G4 | 全フレームを処理した(サンプルではなく全数) | 未処理フレームがあれば追加処理 |
| G5 | 自己検証チェックリスト全項目パス | 失敗項目を修正して再検証 |
NG / OK 判定表
| NG | OK | 理由 |
|---|---|---|
| ファイル名だけで分類する | 画像をReadツールで読んでから分類 | ファイル名に内容情報がない |
| talking_headを見逃して全部content_slideにする | 人物のみのフレームは明確にtalking_headに分類 | 後段のスキルが不要な画像を処理してしまう |
| text_contentを空で済ませる | 画像内のテキストを全て抽出 | OCR情報がprocedure-extractorの紐付けに必要 |
| 一部のフレームだけサンプル処理する | 全フレームを漏れなく処理する | 抜け落ちたフレームが手順画像だった場合に手順が欠落する |
| content_slideとdiagramを区別しない | スライド形式かフローチャート形式かで明確に分ける | concept-extractorの処理方法が異なる |
| confidenceを全部highにする | 判断に迷う画像はmedium/lowにする | 後段で優先順位をつけるための情報が必要 |
| visual_elementsを省略する | 矢印、ボックス、表、コード等を記録する | ダウンストリームの画像選択精度に影響 |
| 当てはまらない画面を無理にコア型に押し込む | 講座固有型を作成 | 誤分類が後段スキルを破壊する |
| 1枚しか出ない型を作る | 最も近いコア型に割り当て | 型の無限増殖を防ぐ |
| 1講座で5型超の講座固有型を作る | 上位5つに統合 | カタログの肥大化防止 |
講座固有型の命名が汎用語(editor等) |
講座キーワードを含む(vscode_editor等) |
他講座と衝突しない |
フレーム分類の判断基準
詳細は references/frame-types.md を参照。概要:
- title_slide: 大きなテキスト、章番号、背景デザイン。テキスト要素が少ない
- content_slide: 箇条書き、図表、概念説明。テキスト量が多い
- browser_screenshot: ブラウザのUI要素(アドレスバー、タブ等)が見える
- terminal_screenshot: 黒背景にモノスペースフォント、コマンドライン
- diagram: 矢印やフロー、接続線。構造化された図形の配置
- talking_head: 人物の映像が画面の大部分を占める。テキスト要素がない/少ない
- transition: 無地の画面、フェード、ぼかし
エッジケース
- スライド上に小さな話者映像がオーバーレイ →
content_slide(スライドが主体) - ブラウザ画面+解説テキストのオーバーレイ →
browser_screenshot - 半分スライド・半分話者 → テキスト量で判断、テキストが多ければ
content_slide
出力ファイル一覧
| ファイル | 場所 | 内容 |
|---|---|---|
| visual-index.json | chapters/{id}/visual-index.json | チャプター別フレーム情報 |
| visual-catalog.json | プロジェクトルート | コース全体のカタログ |
連携スキル
| スキル | 関係 |
|---|---|
| course-ingest | 前提: manifest.jsonを生成 |
| video-to-frames | 前提: スクリーンショットを生成 |
| procedure-extractor | 後続: フレーム分類とOCRを利用 |
| concept-extractor | 並列実行可能: content_slideを補強に利用 |
バッチ処理の注意
- Readツールで画像を読み取る際、1回のバッチで5-10枚を処理
- 大量のフレーム(100枚超)がある場合でも全数処理する
- 処理の進捗を章ごとに報告する:
Chapter 03: 31/31 frames processed - エラーが発生したフレームは
confidence: "low"で記録し、エラー内容をメモ