关于 video-docs-builder
video-docs-builder 是用于网页应用交互式文档视频的 Agent 技能,面向需要录制产品操作说明的团队。它串联 Playwright 录屏、TTS 旁白、FFmpeg 合成和 React 文档站点生成,并支持多语言流程。
主要功能
- 01Playwright 浏览器录制与应用分析
- 02通过 TTS 生成旁白
- 03FFmpeg 合成视频
- 04生成 React 文档站点
- 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 步检查清单
- Flow 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。
旁白语言
旁白语言绝不硬编码——始终根据上下文推断:
- 用户的语言——如果用户用西班牙语书写,就用西班牙语配旁白;如果用英语,就用英语;如果用俄语,就用俄语。
- 应用界面语言——如果应用界面语言与用户所用语言不同,请询问应使用哪种语言:
应用界面似乎是英语,但您用西班牙语与我交流。 旁白应使用哪种语言? A) 西班牙语(与我们的对话语言相同) B) 英语(与应用界面语言相同) - 不确定时——编写任何 flow JSON 前先询问。
TTS 提供商兼容性:
- ElevenLabs / OpenAI TTS——支持多语言,可自动用于任何语言。
- Piper——需要指定语言的语音模型。查看 TTS-PROVIDERS.md 了解可用语音。如果目标语言没有对应语音,请建议切换到 ElevenLabs 或 OpenAI TTS。
多语言视频
要以多种语言制作相同的流程,请将 flow 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/
多语言工作流——优先处理主要语言
始终先完成主要语言,再开始处理其他语言。
首次运行时会发现流程中的错误(选择器错误、时序问题、旁白调整)。先在一种语言中修复,再复制到其他语言,远比并行处理多种语言时逐一修复相同问题省时。
用户要求使用多种语言时的流程:
- 确定主要语言(通常是用户使用的语言或应用的主要区域设置)。
- 完成该语言的整个流程:流程 → 音频 → 视频 → 组装。
- 展示结果并请求确认:
✅ 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)
步骤 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)
步骤 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>" }
}
步骤 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。
步骤 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)
步骤 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/ 中的截图以了解界面。
流程 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 指南:
navigateSPA:2000ms +wait_for: "<selector confirming render>"fill:600–800ms(无需旁白——静音输入会显得自然)- 简单的
click:800ms - 会触发导航的
click:500ms +wait_for_url - 用于显示内容的
wait:2000–3000ms
use_setup_login:
false→ 视频会展示登录过程(流程内容就是登录)true→ 在开始录制前,登录过程会在镜头外完成
步骤 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 输入框是否存在且能接受输入,不会测试实际邮件投递。
步骤 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 格式
两阶段执行模型
每个 flow 都有两个阶段。最终视频中只会出现第 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
当视频需要从工作流中途开始时,请使用 setup[]——例如,已登录、已打开特定页面、购物车已填充、已输入 OTP 等。
观众不会看到这些步骤。
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(或省略)→ 视频会显示登录过程——当 flow 本身就是关于登录时使用true→ 录制前使用config.setup_login在镜头外静默登录
show_cursor(默认值为 true)
true→ 显示红点光标叠加层——大多数 flow 推荐使用false→ 隐藏光标——适用于红点会分散注意力的表单较多的 flow,或不需要展示指针移动的 flow
setup[] — 在录制前运行,不会出现在视频中。支持:
| action | fields | description |
|---|---|---|
navigate | value:URL | 跳转到某个 URL |
fill | selector、value | 填写字段 |
click | selector | 点击元素 |
wait_ms | value:毫秒字符串 | 等待 N 毫秒 |
步骤字段(steps[])
| field | type | description |
|---|---|---|
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 | 逐字符输入(200ms/字符)— 当 fill 无法触发验证或处理掩码字段时使用 |
click | — | CSS | 点击元素 |
blur | — | CSS | 移除焦点(按 Tab)— 在 type 后触发失焦验证时很有用 |
paste | 文本或 ${var} | CSS | 派发 ClipboardEvent — 适用于监听 onPaste 且忽略 fill 的 React 输入框 |
otp_fill | 验证码或 ${var} | CSS(可选) | 逐位填写多输入框 OTP 组件(默认选择器: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/