video-docs-builder について
video-docs-builderは、Webアプリの操作を説明する動画を作るためのエージェントスキルです。Playwrightの録画、TTSナレーション、FFmpegによる編集、Reactサイト生成を組み合わせ、多言語フローにも対応します。
主な機能
- 01Playwrightによる録画とアプリ分析
- 02TTSによるナレーション生成
- 03FFmpegによる動画編集
- 04Reactドキュメントサイトの生成
- 05言語別のフローと出力管理
活用シーン
- 01ログインやダッシュボードの操作録画
- 02選択した画面の説明動画作成
- 03複数言語のナレーション動画制作
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tecnomanu/ video-docs-builder --skill video-docs-builderインストール後、Claude Code で/video-docs-builderを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.gitignore.env.exampleTTS-PROVIDERS.mdTROUBLESHOOTING.mdREADME.mdLICENSEpackage.jsonpackage-lock.jsonevaluations/eval-03-docs-site.jsoneval-01-document-login.jsoneval-02-existing-project.jsonscripts/gen-all-flows.shadjust-timing.tsgenerate-audio.tsanalyze-app.tsassemble.tsgenerate-docs-site.tspaths.tsrun-all.shgenerate-video.tsrehearse.tsinit-project.tssetup.shtypes.tstools/piper-tts/.env.example.gitignoreREADME.mdpackage.jsontools/piper-tts/src/generate.tstools/piper-tts/voices/.gitkeep詳細
動画ドキュメントビルダー
Web アプリの操作ドキュメント動画を録画します。
パイプライン:Playwright(ブラウザー録画)→ TTS ナレーション → FFmpeg による編集 → React ドキュメントサイト
スキルのルート:この SKILL.md ファイルを含むディレクトリです。すべてのコマンドはここから実行します。
目次
- スキルの構成
- 初回セットアップ
- TTS プロバイダー
- ナレーションの言語
- 操作プロトコル — 8 ステップのチェックリスト
- フロー JSON の形式
- タイミングの最重要ルール
- クイックコマンドリファレンス
- 出力の構成
- TTS プロバイダーの詳細 → TTS-PROVIDERS.md
- トラブルシューティング → TROUBLESHOOTING.md
スキルの構成
video-docs-builder/
├── SKILL.md ← Agent instructions (this file)
├── TTS-PROVIDERS.md ← TTS provider setup and voice options
├── TROUBLESHOOTING.md ← Common errors and fixes
├── evaluations/ ← Test scenarios
├── package.json
├── scripts/
│ ├── setup.sh ← Runs first time to install deps + configure TTS
│ ├── run-all.sh ← Full pipeline for one flow
│ ├── gen-all-flows.sh ← Batch pipeline for a flows directory
│ ├── analyze-app.ts ← Playwright: discovers sections, screenshots
│ ├── generate-audio.ts ← TTS: generates MP3 per step
│ ├── generate-video.ts ← Playwright: records video with cursor
│ ├── assemble.ts ← FFmpeg: assembles final MP4
│ ├── adjust-timing.ts ← Adjust audio timing without re-recording
│ ├── generate-docs-site.ts ← Generates React docs site from videos
│ └── types.ts ← Shared TypeScript types
├── tools/
│ └── piper-tts/ ← Free local TTS (language-specific voice models)
└── projects/ ← gitignored — legacy location (still supported)
初回セットアップ
開始前に、スキルの準備ができていることを必ず確認してください。
# 1. Check .env exists and TTS is configured
ls .env 2>/dev/null && grep '^TTS_PROVIDER' .env || echo "NO .env — run scripts/setup.sh"
.env がない場合、または TTS_PROVIDER が設定されていない場合は、停止してセットアップを実行してください。
bash scripts/setup.sh
セットアップウィザードは npm の依存関係と Playwright Chromium をインストールし、FFmpeg を確認して、設定する TTS プロバイダーを尋ねます。
Which TTS provider?
A) Piper (free, local — included in tools/piper-tts/)
B) ElevenLabs (best quality — API key required)
C) OpenAI TTS (very good — API key required)
D) Google Gemini TTS (very natural — GEMINI_API_KEY required)
この手順を省略しないでください。 .env がないと、音声を生成できません。
スキルを最新の状態に保つ
このスキルは git clone としてインストールされます。セッションを開始する前に、最新バージョンを取得してください。
git pull
TTS プロバイダー
| プロバイダー | 品質 | 費用 | 対応言語 |
|---|---|---|---|
| Piper | 良好 | 無料 | 言語別の音声モデル(TTS-PROVIDERS.md を参照) |
| ElevenLabs | 優秀 | 無料プラン/有料 | 多言語対応 — 追加設定なしで任意の言語に対応 |
| OpenAI TTS | 非常に良好 | 有料 API | 多言語対応 — 追加設定なしで任意の言語に対応 |
| Google Gemini | 優秀 | 無料プラン(AI Studio) | 多言語対応 — スペイン語には Kore の音声を推奨 |
詳しいセットアップ手順、言語別の音声モデル、環境変数については、TTS-PROVIDERS.md を参照してください。
ナレーションの言語
ナレーションの言語は決してハードコードしません。必ず文脈から判断してください。
- ユーザーの言語 — ユーザーがスペイン語で書いている場合は、スペイン語でナレーションします。英語なら英語、ロシア語ならロシア語でナレーションします。
- アプリの UI 言語 — アプリのインターフェースがユーザーの言語と異なる場合は、どちらの言語を使うか尋ねてください。
アプリは英語のようですが、あなたはスペイン語で話しかけています。 ナレーションにはどちらの言語を使いますか? A) スペイン語(会話と同じ言語) B) 英語(アプリの UI と同じ言語) - 判断に迷う場合 — フロー JSON を書く前に尋ねてください。
TTS プロバイダーの対応状況:
- ElevenLabs/OpenAI TTS — 多言語対応で、任意の言語を自動的に使用できます。
- Piper — 対象言語の音声モデルが必要です。利用可能な音声については TTS-PROVIDERS.md を確認してください。対象言語の音声がない場合は、ElevenLabs または OpenAI TTS への切り替えを推奨してください。
多言語動画
同じフローを複数の言語で作成するには、フロー JSON を言語別のサブフォルダーに配置してください。
flows/
├── es/01-login.json ← Spanish narration
├── en/01-login.json ← English narration
└── pt/01-login.json ← Portuguese narration
言語は自動的に検出されます。パイプラインはフォルダー名から言語コードを読み取り、.env から対応する音声を使用します。出力は output/<lang>/ 以下に言語ごとに分けて保存されます。
.env での言語別音声の設定
# ── Default voice (used when no language-specific voice is set) ───────────────
ELEVENLABS_VOICE_ID=EXAVITQu4vr4xnSDxMaL
OPENAI_VOICE=nova
PIPER_VOICE=es_AR-daniela-high
# ── Per-language overrides (optional — fall back to default if not set) ───────
ELEVENLABS_VOICE_ES_ID=<elevenlabs-id-for-spanish>
ELEVENLABS_VOICE_EN_ID=<elevenlabs-id-for-english>
ELEVENLABS_VOICE_PT_ID=<elevenlabs-id-for-portuguese>
OPENAI_VOICE_ES=nova
OPENAI_VOICE_EN=alloy
OPENAI_VOICE_PT=shimmer
PIPER_VOICE_ES=es_AR-daniela-high
PIPER_VOICE_EN=en_US-lessac-medium
解決の優先順位:ELEVENLABS_VOICE_{LANG}_ID → ELEVENLABS_VOICE_ID(OpenAI と Piper も同じ形式です)。
多言語フローの実行
# Run Spanish flow
bash scripts/run-all.sh /abs/path/client/.video-docs/flows/es/01-login.json
# → output goes to .video-docs/output/es/01-login/final/
# Run English flow
bash scripts/run-all.sh /abs/path/client/.video-docs/flows/en/01-login.json
# → output goes to .video-docs/output/en/01-login/final/
多言語ワークフロー — まず主要言語から
ほかの言語に着手する前に、必ず主要言語を完成させてください。
フローのエラー(セレクターの誤り、タイミングの問題、ナレーションの調整)は、最初の実行で見つかります。1つの言語で修正してからほかの言語に反映するほうが、複数の言語で並行して同じ問題を修正するより、はるかに効率的です。
ユーザーが複数の言語をリクエストした場合の手順:
- 主要言語を特定します(通常はユーザーの言語、またはアプリの主要なロケールです)。
- その言語のパイプライン全体を完了します:フロー → 音声 → 動画 → 組み立て。
- 結果を提示し、確認を求めます:
✅ Primary language (ES) done — 3 videos generated.
Before I continue with EN and PT, please review:
• .video-docs/output/es/01-login/final/01-login.mp4
• .video-docs/output/es/02-dashboard/final/02-dashboard.mp4
• .video-docs/output/es/03-settings/final/03-settings.mp4
Does everything look good? (narration, timing, UI interactions)
A) Yes, continue with EN and PT
B) Fix [describe issue] first, then continue
- クライアントが確認してから、残りの言語に進みます。
これにより、ナレーションの微調整やセレクターの修正が必要になるたびに、N 個の言語すべてで音声と動画を再生成せずに済みます。
プロジェクトの保存場所 — ファイルの保存先
プロジェクトはスキル内ではなく、クライアント自身のリポジトリ内に保存されます:
client-project/ ← client's Git repository
├── .gitignore ← skill adds: .video-docs/output/
└── .video-docs/ ← all video-docs files live here
├── README.md ← regeneration instructions (commit this)
├── config.json ← app URL + credentials (add to .gitignore if sensitive)
├── flows/ ← flow JSONs — commit these, they're small and useful
│ ├── 01-login.json ← no language (default)
│ ├── es/ ← Spanish flows (optional)
│ │ └── 01-login.json
│ └── en/ ← English flows (optional)
│ └── 01-login.json
├── output/ ← gitignored — heavy generated files
│ ├── .gitignore
│ ├── 01-login/ ← output for default (no language) flows
│ │ ├── audio/
│ │ ├── raw/
│ │ └── final/ ← 01-login.mp4
│ ├── es/ ← output for Spanish flows
│ │ └── 01-login/
│ │ └── final/ ← 01-login.mp4
│ └── en/
│ └── 01-login/
│ └── final/ ← 01-login.mp4
└── docs/ ← React docs site — commit or ignore (your choice)
言語は自動検出されます — フローが flows/es/ の下にあれば、出力先は output/es/ になります。追加のフラグは不要です。
この構成にする理由:
flows/はバージョン管理可能です — 各言語に固有のナレーションスクリプトがありますoutput/は gitignore の対象です — フローからいつでも任意の言語を再生成できます- 後方互換性があります —
flows/直下にあるフロー(言語サブフォルダーなし)も、これまでどおり動作します
新しいプロジェクトを初期化する
npm run init-project /absolute/path/to/client-project
# Creates .video-docs/ structure and adds .video-docs/output/ to .gitignore
すべてのコマンドで絶対パスを使用する
# From the skill directory:
bash scripts/run-all.sh /absolute/path/client/.video-docs/flows/01-login.json
bash scripts/run-all.sh /absolute/path/client/.video-docs/flows/es/01-login.json
npx tsx scripts/generate-docs-site.ts /absolute/path/client/.video-docs --dev
npx tsx scripts/analyze-app.ts /absolute/path/client/.video-docs
インタラクションの手順
以下の手順に沿って進めてください。以下のチェックリストをコピーし、進捗を記録します。
Documentation Progress:
- [ ] Step 0: Verify setup (.env exists, TTS configured, git pull)
- [ ] Step 1: Get app info (URL, client project path, credentials)
- [ ] Step 2: Initialize .video-docs/ in client project (npm run init-project)
- [ ] Step 3: Analyze the app (npx tsx scripts/analyze-app.ts <path>)
- [ ] Step 4: Choose sections to document
- [ ] Step 5: Create or update flow JSONs
- [ ] Step 5b: Rehearse the flow (npx tsx scripts/rehearse.ts <flow.json>)
- [ ] Step 6: Confirm TTS provider
- [ ] Step 7: Run the pipeline (absolute path to flow)
- [ ] Step 8: Generate docs site (optional)
STEP 1 — アプリ情報を取得する
ユーザーに尋ねます:
Which app do you want to document?
• Base URL (e.g. http://localhost:8100)
• Absolute path to the client project (e.g. /home/user/projects/my-app)
• Access credentials: email and password
(or let me know if .video-docs/config.json already exists in that project)
STEP 2 — クライアントのプロジェクトに .video-docs/ を初期化する
.video-docs/ がすでに存在するか確認します:
ls /absolute/path/client/.video-docs/config.json 2>/dev/null && echo "exists" || echo "missing"
存在しない場合 → 初期化します:
npm run init-project /absolute/path/to/client-project
次に、実際のアプリ情報を使って .video-docs/config.json を編集します:
{
"app_name": "<visible app name>",
"base_url": "<URL>",
"credentials": {
"demo": { "email": "<email>", "password": "<password>" }
},
"setup_login": { "email": "<email>", "password": "<password>" }
}
STEP 3 — アプリを分析する
npx tsx scripts/analyze-app.ts /absolute/path/client/.video-docs
アプリを操作し、ナビゲーションの各セクションのスクリーンショットを撮影して、CSS セレクターを抽出し、以下に保存します:
.video-docs/analysis/sections.json.video-docs/analysis/screenshots/
自動ログインに失敗する場合:コマンドに -- --no-login を追加します。
SPA に関する注意:アプリが Vite/Webpack 開発サーバーを使用している場合は、本番ビルドが有効になっていることを確認してください(public/hot ファイルが存在しない状態)。TROUBLESHOOTING.md を参照してください。
STEP 4 — ドキュメント化するセクションを選ぶ
見つかったセクションをアルファベット付きのリストで提示します:
Found these sections in [App Name]:
A) Login — /login
B) Dashboard — /dashboard [existing flow: 01-dashboard.json]
C) Bot Management — /bots
D) All sections
Which sections to document? (e.g. A, C or D for all)
STEP 5 — フロー JSON を作成または再利用する
フローがすでに存在する場合:
"[Section]" already has a flow: /absolute/path/client/.video-docs/flows/<name>.json
A) Use existing flow as-is
B) Update flow based on current screenshots
C) Create from scratch
フローが存在しない場合 → 直接作成します。.video-docs/analysis/screenshots/ のスクリーンショットを見て、UI を把握してください。
フロー JSON のテンプレート:
{
"project": "<name>",
"title": "<descriptive title>",
"category": "<docs site sidebar group, e.g. Getting Started>",
"description": "<one-line summary shown in docs site cards>",
"steps_summary": ["Step 1 text", "Step 2 text"],
"output_name": "<NN-slug>",
"viewport": { "width": 1280, "height": 800 },
"use_setup_login": true,
"steps": [
{
"id": "navigate_section",
"action": "navigate",
"value": "<URL>",
"narration": "<What this screen is and what the user can do here>",
"action_ms": 2000,
"wait_for": "<CSS selector confirming the page has rendered>"
},
{
"id": "pre_action",
"action": "wait",
"narration": "<Narrate WHAT WE ARE ABOUT TO DO — plays BEFORE the action>",
"action_ms": 600
},
{
"id": "do_action",
"action": "click",
"selector": "<CSS selector>",
"action_ms": 500
}
]
}
action_ms のガイドライン:
- SPA の
navigate:2000ms +wait_for: "<レンダリングを確認するセレクター>" fill:600~800ms(ナレーションなし — 無音で入力するほうが自然に感じられます)- 単純な
click:800ms - 画面遷移を伴う
click:500ms +wait_for_url - コンテンツを表示するための
wait:2000~3000ms
use_setup_login:
false→ 動画にログイン操作が表示されます(フローはログイン操作を扱います)true→ 録画開始前に、カメラに映らないところでログインします
STEP 5b — フローをリハーサルする
パイプライン全体を実行する前に、必ずリハーサルしてください。
リハーサルでは、Playwright を使ってすべてのステップを実行します(実際のブラウザー、実際のセレクター、実際の画面遷移)。ただし、動画の録画、音声の生成、ナレーションのための一時停止は省略します。数秒で完了し、TTS の処理に数分かかったあとでパイプラインの途中で失敗するのではなく、問題のあるステップをすべて一度に報告します。
npx tsx scripts/rehearse.ts /abs/path/client/.video-docs/flows/<flow>.json
出力例:
🎭 Rehearsing: "Checkout flow"
8 steps + 4 setup
🔐 Setup login ([email protected])... ✅ → /dashboard
📋 Setup steps:
setup[0] navigate → https://app/plans... ✅
setup[1] click .plan-card button... ✅
📹 Recording steps:
[navigate_checkout] navigate → https://app/checkout... ✅ 312ms → /checkout
[fill_email] fill #email → [email protected]... ✅ 98ms
[fill_card] fill #card-number → 4242... ❌ Timeout: waiting for #card-number
[submit] click button[type=submit]... ❌ Timeout: waiting for button[type=submit]
─────────────────────────────────────────────────
🎭 Rehearsal complete: 6/8 steps passed (2.4s)
❌ Failed steps (2):
• [fill_card] Timeout: waiting for #card-number
• [submit] Timeout: waiting for button[type=submit]
⚠️ Fix these steps before running the full pipeline.
報告されたセレクターを修正し、すべてのステップが成功するまで再度リハーサルしてから run-all.sh を実行します。
リハーサル時の mailpit_code — 偽のコード "123456" を挿入するため、${variable} を使う後続の fill ステップが、コードの不足によって失敗しません。これは OTP 入力フィールドが存在し、入力を受け付けることだけを検証します。実際のメール配信はテストしません。
STEP 6 — TTS プロバイダーを確認する
grep '^TTS_PROVIDER' .env
設定されていない場合 → 尋ねます:
Which TTS provider should I use?
A) Piper (free, local — included in tools/piper-tts/)
B) ElevenLabs (best quality — API key required)
C) OpenAI TTS (very good — API key required)
D) Google Gemini TTS (very natural — GEMINI_API_KEY required)
セットアップの詳細は TTS-PROVIDERS.md を参照してください。
STEP 7 — パイプラインを実行する
フローファイルには、必ず絶対パスを使用してください。
bash scripts/run-all.sh /absolute/path/client/.video-docs/flows/<flow>.json
フラグ:
--skip-audio→ 動画のみを再録画します(UI が変更された場合に、音声はそのままにします)--skip-video→ 再構成のみを行います(タイミングを調整します)
エラーが発生した場合は、TROUBLESHOOTING.md を参照してください。
STEP 8 — ドキュメントサイトを生成する(任意)
Videos are ready! 🎉
Would you like a React docs site with all videos embedded?
A) No, just the videos
B) Yes, generate site — opens browser automatically
C) Yes, add videos to an existing docs site (tell me the path)
オプション B:
npx tsx scripts/generate-docs-site.ts /absolute/path/client/.video-docs
# Generates .video-docs/docs/, installs deps, opens browser automatically
# Add --no-open to skip auto-launch
オプション C:
npx tsx scripts/generate-docs-site.ts /absolute/path/client/.video-docs --existing <path>
Flow JSON 形式
2 フェーズ実行モデル
すべてのフローには 2 つのフェーズがあります。最終的な動画に表示されるのはフェーズ 2 のみです。
Phase 1 — Setup (off-camera, trimmed away)
use_setup_login: true → automatic login from config.json credentials
setup: [...] → any custom Playwright steps (navigate, click, fill, wait_ms)
Phase 2 — Recording (what the viewer sees)
steps: [...] → narrated, timed tutorial steps
動画をフローの途中から開始する必要がある場合(すでにログイン済み、特定のページを表示中、カートに商品が入っている、OTP を入力済みなど)は、setup[] を使用してください。
これらの手順は視聴者には表示されません。
Flow JSON — 完全リファレンス
{
"project": "<name>",
"title": "<descriptive title>",
"category": "<docs site sidebar group, e.g. Getting Started>",
"description": "<one-line summary shown in docs site cards>",
"steps_summary": ["Step 1 text", "Step 2 text"],
"output_name": "<NN-slug>",
"viewport": { "width": 1280, "height": 800 },
"use_setup_login": true,
"show_cursor": true,
"setup": [
{ "action": "navigate", "value": "https://app.example.com/plans" },
{ "action": "click", "selector": ".plan-card:first-child button" },
{ "action": "wait_ms", "value": "1500" },
{ "action": "fill", "selector": "#email", "value": "[email protected]" }
],
"steps": [
{
"id": "navigate_checkout",
"action": "navigate",
"value": "https://app.example.com/checkout",
"narration": "We are now at the checkout screen.",
"action_ms": 2000,
"wait_for": ".checkout-form"
},
{
"id": "pre_click",
"action": "wait",
"narration": "We fill in the card number and confirm.",
"action_ms": 600
},
{
"id": "fill_card",
"action": "fill",
"selector": "#card-number",
"value": "4242 4242 4242 4242",
"action_ms": 800
},
{
"id": "submit",
"action": "click",
"selector": "button[type=submit]",
"action_ms": 500,
"wait_for_url": "/confirmation"
}
]
}
use_setup_login
false(または省略)→ 動画にログインが表示されます。フローがログインについてのものである場合に使用しますtrue→ 録画前にconfig.setup_loginを使用して、カメラに映らない状態でログインします
show_cursor(デフォルトは true)
true→ 赤い点のカーソルオーバーレイを表示します。ほとんどのフローで推奨されますfalse→ カーソルを非表示にします。点が邪魔になるフォーム中心のフローや、ポインターの動きを表示する必要がないフローで使用します
setup[] — 録画前に実行され、動画には表示されません。次のアクションに対応しています。
| アクション | フィールド | 説明 |
|---|---|---|
navigate | value: URL | URL に移動する |
fill | selector, value | フィールドに入力する |
click | selector | 要素をクリックする |
wait_ms | value: ms 文字列 | N ミリ秒待機する |
ステップのフィールド(steps[])
| フィールド | 型 | 説明 |
|---|---|---|
id | string | 一意の識別子(音声ファイル名に使用) |
action | string | 下記のアクション表を参照 |
value | string | URL/テキスト/変数名 — ${varName} による置換に対応 |
selector | CSS | 対象の要素 |
nth | number | セレクターが複数の要素に一致する場合の 0 始まりのインデックス |
narration | string | TTS で読み上げるテキスト — 無音のステップでは省略 |
action_ms | number | アクションの後、次のステップを開始するまでの待機時間 |
wait_for | CSS | アクション後、このセレクターが表示されるまで待機 |
wait_for_url | string | アクション後、URL にこの文字列が含まれるまで待機 |
email | string | mailpit_code 用 — 検索するメールアドレス(デフォルトを上書き) |
利用可能なアクション(steps[])
action | value | selector | 説明 |
|---|---|---|---|
navigate | URL | — | URL に移動する |
fill | テキストまたは${var} | CSS | 入力欄に入力する — 即時に反映され、キーボードイベントは発生しません |
type | テキストまたは${var} | CSS | 1 文字ずつ入力する(200ms/文字) — fillで検証がトリガーされない場合や、マスクされたフィールドで使用します |
click | — | CSS | 要素をクリックする |
blur | — | CSS | フォーカスを外す(Tab キーを押す) — typeの後にぼかし時の検証をトリガーするのに便利です |
paste | テキストまたは${var} | CSS | ClipboardEvent をディスパッチする — onPasteをリッスンし、fillを無視する React の入力欄で使用します |
otp_fill | コードまたは${var} | CSS(任意) | 複数入力欄の OTP コンポーネントに、数字を 1 桁ずつ入力する(デフォルトのセレクター:input[inputmode="numeric"]) |
hover | — | CSS | 要素にカーソルを合わせる(ツールチップやドロップダウン用) |
scroll | "down" | "up" | px | CSS(任意) | ページまたは要素をスクロールして表示する |
wait | — | — | action_msミリ秒間待機する — ナレーションの表示時間に使用します |
mailpit_code | 変数名 | — | Mailpit 専用 — 6 桁の OTP を抽出して変数に保存する |
変数の置換
valueフィールド内の任意の場所で${varName}を使うと、保存済みの変数を挿入できます。
{ "id": "get_otp", "action": "mailpit_code", "value": "otp", "email": "[email protected]", "action_ms": 1000 },
{ "id": "fill_otp", "action": "fill", "selector": "#otp-input", "value": "${otp}", "action_ms": 600 }
録画前によく使うパターン
最初に複数の画面を遷移する必要があるページから動画を開始する場合:
"use_setup_login": true,
"setup": [
{ "action": "navigate", "value": "https://app/products" },
{ "action": "click", "selector": ".product-card:first-child a" },
{ "action": "wait_ms", "value": "1200" },
{ "action": "click", "selector": "button.add-to-cart" },
{ "action": "navigate", "value": "https://app/checkout" },
{ "action": "wait_ms", "value": "1000" }
]
カメラに映らないところで新しいユーザーを登録する場合(アカウント作成後に動画を開始):
"use_setup_login": false,
"setup": [
{ "action": "navigate", "value": "https://app/register" },
{ "action": "fill", "selector": "#email", "value": "[email protected]" },
{ "action": "fill", "selector": "#password", "value": "Demo1234!" },
{ "action": "click", "selector": "button[type=submit]" },
{ "action": "wait_ms", "value": "2000" }
]
メール/OTP 認証フロー
OTP フローを作成する前に、必ずクライアントに確認してください:
Does the flow involve an email verification code or OTP?
If yes — how does your test environment handle email?
A) Mailpit (local inbox at localhost:8025 or similar)
B) Mailtrap or another SMTP testing service
C) The code arrives to a real inbox I can read manually
D) No email verification involved
各オプションでは、異なる方法が必要です。
A) Mailpit — 組み込みのmailpit_codeアクションを使用します。config.jsonでmailpit_urlが設定されていることを確認してください。
// config.json
{ "mailpit_url": "http://localhost:8025" }
// flow setup[] + steps[]
"setup": [
{ "action": "click", "selector": "#send-otp-button" },
{ "action": "wait_ms", "value": "2000" }
],
"steps": [
{ "id": "get_code", "action": "mailpit_code", "value": "otp", "email": "[email protected]", "action_ms": 500 },
{ "id": "fill_code", "action": "fill", "selector": "#otp-input", "value": "${otp}", "action_ms": 600 },
{ "id": "submit", "action": "click", "selector": "button[type=submit]", "action_ms": 500, "wait_for_url": "/dashboard" }
]
B) Mailtrap/外部サービス — mailpit_codeは動作しません。テストアカウントで常に同じコードが使われる場合は固定のデモコードを使用するか、setup[]で認証済みアカウントを使ってデモ中の OTP を省略します。
"setup": [
{ "action": "navigate", "value": "https://app/register" },
{ "action": "fill", "selector": "#email", "value": "[email protected]" },
{ "action": "fill", "selector": "#password", "value": "Demo1234!" },
{ "action": "click", "selector": "button[type=submit]" },
{ "action": "wait_ms", "value": "2000" }
]
C) 手動コード — クライアントに最初にフローを手動で実行してもらい、コードを控えてから、fillの値としてハードコードします。または、OTP を完全に回避できる認証済みテストアカウントを使用します。
mailpit_codeはsteps[]でのみ利用でき、setup[]では利用できません。OTP を見えないように処理するには、setup[]で送信をトリガーし、最初の録画ステップでコードを抽出します。抽出はすぐに完了するため、視聴者に見えるのは短い待ち時間だけです。
タイミングの鉄則
ナレーションでは、すでに起きたことではなく、これから起きることを説明します。
❌ Wrong — dashboard appears 4s before narration
{ "id": "click_login", "action": "click", ..., "narration": "We click Login", "action_ms": 4000 }
✅ Right — narration plays on the form, THEN click happens
{ "id": "pre_login", "action": "wait", "narration": "We click Login to authenticate.", "action_ms": 600 },
{ "id": "click_login","action": "click", ..., "action_ms": 500, "wait_for_url": "/dashboard" }
コマンド早見表
# Analyze app and discover sections
npx tsx scripts/analyze-app.ts /absolute/path/client/.video-docs
npx tsx scripts/analyze-app.ts /absolute/path/client/.video-docs --no-login
# Rehearse a flow (validate selectors without recording)
npx tsx scripts/rehearse.ts /absolute/path/client/.video-docs/flows/<flow>.json
# Full pipeline for one flow
bash scripts/run-all.sh /absolute/path/client/.video-docs/flows/<flow>.json
# Individual steps
npx tsx scripts/generate-audio.ts /absolute/path/client/.video-docs/flows/<flow>.json
npx tsx scripts/generate-video.ts /absolute/path/client/.video-docs/flows/<flow>.json
npx tsx scripts/assemble.ts /absolute/path/client/.video-docs/flows/<flow>.enriched.json
# Re-record without regenerating audio
bash scripts/run-all.sh /absolute/path/client/.video-docs/flows/<flow>.json --skip-audio
# Adjust audio timing without re-recording
npx tsx scripts/adjust-timing.ts /absolute/path/client/.video-docs/flows/<flow>.enriched.json --show
npx tsx scripts/adjust-timing.ts ... --step <id>:<ms> --reassemble
# Batch all flows in a directory
bash scripts/gen-all-flows.sh /absolute/path/client/.video-docs/flows/
# Generate docs site (with auto browser open)
npx tsx scripts/generate-docs-site.ts /absolute/path/client/.video-docs --dev
npx tsx scripts/generate-docs-site.ts /absolute/path/client/.video-docs --out /custom/path
npx tsx scripts/generate-docs-site.ts /absolute/path/client/.video-docs --existing /path/to/existing/docs
出力構成
/absolute/path/client/.video-docs/
├── output/
│ └── <flow-name>/
│ ├── audio/ ← MP3 per step
│ ├── raw/ ← .webm recording
│ └── final/
│ ├── <flow>.mp4 ← FINAL VIDEO
│ └── <flow>-thumb.jpg
└── docs/ ← React site (if generated)
├── package.json
├── src/App.tsx
└── public/videos/