Communitygithub.com

show-n-tell

用于创建带解说、品牌定制的网站演示视频。处理网站探索、故事板草稿(用户用纯文本评审)、OpenAI TTS 配音、Playwright 录制、音视频合成、速度调整、品牌叠加以及(B 阶段)片头/片尾/字幕。最终输出打磨后的 mp4 文件。

show-n-tell 是什么?

show-n-tell 是一项为 AI 代理(如 Claude Code、Cursor、Codex 等)设计的技能,旨在将任何网站、一个 logo 和用户的意图转化为一个约 5 分钟、带有解说和品牌元素的演示视频。它通过一个完整的管道工作,包括用户意图访谈、网站探索(通过 Playwright 或 Chrome)、故事板生成、利用 OpenAI TTS 生成语音、Playwright 录制、音视频合成、画面速度调整,以及为 logo 和品牌颜色添加覆盖层。支持在 Claude Code CLI 和 Cowork 环境下运行,并根据环境自动调整文件路径和执行策略。该技能特别强调用户输入的重要性:如果用户没有提供意图说明或 logo,它会拒绝继续,以确保输出高质量、有故事性的演示视频,而非泛泛的默认内容。

兼容平台✓Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/carveragents/show-n-tell/tree/main/skills/show-n-tell

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

show-n-tell 是做什么的?

你负责编排一个完整的管道,将任何网站 + 一个 logo + 一点意图,转化为一个约 5 分钟、带解说和品牌元素的演示视频。scripts/ 中的脚本只是简单的管道工具;你是指挥员。

本文件夹中的参考文档:docs/SCHEMAS.md(YAML + 动作语法),docs/GOTCHAS.md(已知问题及解决方案),docs/CONTEXT.md(“什么样的输出是好的”),examples/halyard-spme/(规范的完整示例)。根据需要阅读这些文档——不要预加载它们。

何时使用此技能

  • 用户希望制作一个关于某个网站(线上、本地开发或静态站点)的演示视频。
  • 用户至少提供了一些轻量的意图指导(“展示 X、Y、Z” / “演示仪表盘流程”)。
  • 用户可以访问 logo 或文字商标。

如果用户既没有提供意图说明,也没有提供 logo,则拒绝继续。 使用默认品牌元素的通用演示视频质量很差。请向用户寻求指导,而不是默默生成一个低质量的视频。

环境检测(开始前阅读)

在开始任何操作之前,确定 Claude 运行在哪个环境中:

  • Cowork:mcp__cowork__list_artifacts 和 mcp__computer-use__screenshot 在 Claude 的工具列表中可用。
  • Claude Code CLI:这些工具不可用。

这一点很重要,因为多个阶段在不同环境下的行为不同。快速参考:

阶段Claude Code CLICowork
工作目录(阶段 5)~/demo-videos/<slug>/request_cowork_directory 输出路径
网站探索(公开,阶段 2b)Playwright MCP 工具Chrome MCP 工具或头部的 explore_page.py
认证捕获(OAuth,阶段 2a)通过 Bash 运行 capture_auth.py用户在本地运行 capture_auth.py
长命令(阶段 7–9)同步运行nohup + 轮询(45 秒 bash 超时)
交接(阶段 11)报告 mp4 路径mp4 路径 + computer:// 链接

阶段 1 — 访谈(收集输入)

一次只问一两个问题,不要一次问完所有。必备项:

  1. 目标 URL — 确认其可访问。
  2. 演示意图说明 — 要讲述什么故事?哪些功能重要?
  3. 受众和语调 — 内部/外部/投资者;解释性/销售性/技术性/随意性。
  4. 目标时长 — 默认 5 分钟。
  5. Logo — URL 或路径。如果只有纯文本可用,请明确指出限制但接受。
  6. 品牌颜色 — 主色调(墨水色)+ 强调色。如果未指定,使用 PIL 从 logo 推断。
  7. 需要认证? — 网站是否需要登录?
    • 不需要 → 继续。
    • 需要,基于表单(网站有自己的邮箱/密码字段,你可以控制)→ 在 demo_config.yaml 中使用 session.pre_session。收集凭据的环境变量名(不是实际值)和登录 URL/选择器。告知用户在运行前将实际凭据放在 <working_dir>/.env 中,切勿放在聊天中。参见 examples/login-flow/。
    • 需要,OAuth / SSO / 魔法链接 / 通行密钥(Google、Microsoft、Okta 等)→ 使用 session.storage_state。用户不需要运行任何命令。由你在阶段 2a 中为他们启动 helpers/capture_auth.py,他们只需在打开的浏览器窗口中交互式登录。捕获的 auth.json 将同时用于阶段 2b 的探索和阶段 8 的录制。参见 examples/oauth-storage-state/。

阶段 2a — 认证捕获(仅限 OAuth)

如果阶段 1 问题 7 确定为“无需认证”或“基于表单”,则完全跳过此阶段。对于 OAuth / SSO / 魔法链接 / 通行密钥,在网站探索之前立即捕获经过认证的会话——阶段 2b 需要它来查看经过认证的页面。

mkdir -p ~/demo-videos/<demo-slug>/
uv run helpers/capture_auth.py <login_or_start_url> \
  --out ~/demo-videos/<demo-slug>/auth.json \
  --viewport <recording.viewport from demo_config.yaml; default 1440x900>

通过 Bash 工具运行此命令,设置 timeout: 600000(10 分钟——最大值)。脚本会打开一个有头 Chromium 窗口。用通俗的话告诉用户:

“我正在为你打开一个浏览器窗口用于登录。完成登录(Google、Microsoft 等,处理双重认证),导航到你希望录制开始的页面,然后关闭浏览器窗口。我将保存会话并自动继续。”

脚本会将 auth.json 以 0600 权限原子地写入。如果用户耗时超过 10 分钟(罕见,但在另一个房间使用基于手机的双重认证时可能发生),Bash 超时会触发——只需重新运行相同的命令。

--viewport 必须与 demo_config.yaml 中的 recording.viewport 匹配。某些站点会检查视口大小;不匹配可能导致在录制或探索时捕获的会话失效。

如果 Playwright 的 Chromium 尚未安装(技能刚克隆),脚本会显示一个可操作的错误。运行 uv run --with playwright playwright install chromium 一次。

如果在 Claude Code CLI 中运行: 按上述描述通过 Bash 运行 capture_auth.py。

如果在 Cowork 中运行: Claude 直接使用 computer-use 和 Chrome 工具处理——用户只需要在浏览器打开时登录。步骤:

  1. 确保工作目录路径已知。 如果阶段 5 尚未运行,立即调用 mcp__cowork__request_cowork_directory 获取输出路径,并将 <working_dir> 设置为 <outputs_path>/<demo-slug>/。

  2. 在用户桌面上打开 Chrome:

    mcp__computer-use__open_application  →  "Google Chrome"  (或 "Chrome")
    
  3. 导航到登录 URL。 如果已连接,优先使用 Chrome MCP:

    • Chrome 扩展可用:mcp__Claude_in_Chrome__navigate 到 <login_or_start_url>
    • Chrome 扩展未连接:使用 mcp__computer-use__* 工具点击地址栏并输入 URL
  4. 告诉用户登录 —— 用通俗的话说:

    “Chrome 已在登录页面打开。请登录(处理任何双重认证、SSO 等),然后导航到录制应开始的页面。完成后请告诉我。”

  5. 等待并观察。 大约每 15 秒用 mcp__computer-use__screenshot 轮询一次。一旦 URL 不再是登录/认证页面,并且可以看到仪表盘或应用页面,则继续。

  6. 通过 JavaScript 提取会话状态。 使用 mcp__Claude_in_Chrome__javascript_tool 运行此代码片段:

    (() => {
      const cookies = document.cookie.split(';').map(c => {
        const [name, ...rest] = c.trim().split('=');
        return { name: name.trim(), value: rest.join('='), domain: location.hostname,
                 path: '/', expires: -1, httpOnly: false, secure: location.protocol === 'https:',
                 sameSite: 'Lax' };
      }).filter(c => c.name);
      const ls = {};
      for (let i = 0; i < localStorage.length; i++) {
        const k = localStorage.key(i);
        ls[k] = localStorage.getItem(k);
      }
      const ss = {};
      for (let i = 0; i < sessionStorage.length; i++) {
        const k = sessionStorage.key(i);
        ss[k] = sessionStorage.getItem(k);
      }
      return JSON.stringify({
        cookies,
        origins: [{ origin: location.origin,
                    localStorage: Object.entries(ls).map(([n,v]) => ({name:n,value:v})),
                    sessionStorage: Object.entries(ss).map(([n,v]) => ({name:n,value:v})) }]
      }, null, 2);
    })()
    
  7. 使用写入工具将结果写入 <working_dir>/auth.json。 这是有效的 Playwright storage_state 格式——helpers/explore_page.py 和 record_demo.py 都通过 browser.new_context(storage_state=...) 使用它。

  8. HttpOnly cookie 警告。 JavaScript 无法读取 HttpOnly cookie——它们对 document.cookie 有意不可见。如果站点的会话令牌是纯 HttpOnly 的(旧的 Rails/Django 会话 cookie 常见),则提取的状态将缺少它。告诉用户:

    “注意:标记为 HttpOnly 的会话 cookie 无法通过 JavaScript 访问,因此我可能没有捕获所有认证令牌。录制将尝试使用已捕获的内容——如果在阶段 8 遇到登录墙,我们可以回退到在本地使用 capture_auth.py。” 然后继续——许多现代站点(Google、Microsoft、Okta)在非 HttpOnly cookie 或 localStorage 中保留了足够的状态,以便 Playwright 正常工作。

阶段 2b — 网站探索

如果阶段 2a 已运行(auth.json 存在),使用 helpers/explore_page.py 查看经过认证的页面——Playwright MCP 无法加载 storage_state,只会看到登录墙。对于无需认证的演示,Playwright MCP 很好且更具交互性;按照以前的方式使用它。

对于经过认证的页面:

mkdir -p ~/demo-videos/<demo-slug>/_explore/
uv run helpers/explore_page.py https://target.example.com/dashboard \
  --storage-state ~/demo-videos/<demo-slug>/auth.json \
  --out-dir ~/demo-videos/<demo-slug>/_explore/

这会将每个页面的三个文件写入 _explore/:<slug>.png(截图),<slug>.dom.html(用于选择器选取的 DOM),<slug>.meta.json({url_requested, final_url, title, status})。使用读取工具读取 PNG 以查看页面;在 DOM 中搜索选择器。如果 meta.json 中的 final_url 指向登录页面,则会话已过期——重新运行阶段 2a。

对于公开页面(任何演示的登录页、营销页面;无需认证演示中的所有内容)——像以前一样使用 Playwright MCP 工具(mcp__plugin_playwright_playwright__*):

  • 使用 browser_navigate 导航到目标 URL,然后进入用户意图提到的 2–5 个页面。
  • 使用 browser_snapshot 或 browser_take_screenshot 查看每个页面的布局。
  • 使用 browser_evaluate 读取 DOM 以获取稳定的选择器(如有可能,优先使用语义化选择器而非 nth-of-type)。

如果在 Claude Code CLI 中运行: 按上述描述使用 mcp__plugin_playwright_playwright__* 工具。

如果在 Cowork 中运行: 首先确保 Chromium 可用:

uv run --with playwright playwright install chromium

然后选择可用的最佳方法:

  • 如果 mcp__Claude_in_Chrome__navigate 可用(Chrome 扩展已连接),使用 mcp__Claude_in_Chrome__navigate + mcp__Claude_in_Chrome__read_page 交互式地探索站点。
  • 否则回退到无头探索:
    mkdir -p <working_dir>/_explore/
    uv run helpers/explore_page.py <url> --out-dir <working_dir>/_explore/
    
    (对于公开页面不需要 --storage-state——该参数现在是可选的。)

请注意每个重要页面:

  • 值得演示的时刻(滚动到某个功能、点击查看详情、悬停工具提示)。
  • 需要进行的站点调整:粘性标题技巧?PDF 深度链接?模态框阻塞?认证墙?
  • 看起来脆弱且可能需要 wait_for_selector 防御的选择器。

不要穷举爬取。每个页面进行 2–5 个动作就足够了。

阶段 3 — 草拟 storyboard.yaml

生成 15–30 个节拍。每个节拍 = 一个摄像头动作 + 1–3 句解说。有关动作语法的详细信息,请参阅 docs/SCHEMAS.md(A 阶段子集:goto、goto_and_scroll、scroll_into_view、scroll_y、hover、click)。

以 1.2 倍速度加速的 5 分钟视频目标:

  • 加速后总时长:约 5:00
  • 加速前原始总运行时长:约 6:00
  • 每节拍平均时长:约 12 秒,其中约 9–10 秒为解说

起草解说时的硬性规则:

  1. 每个事实性声明必须在该节拍画面中可见。 不要编造数字(“代理标记了 199 处更改”)。如果您在截图中没有看到,就不要说。
  2. 需要逐个字母读出的首字母缩略词必须用连字符书写: S-P-M-E、K-Y-B、A-P-I。TTS 提示强制执行此约定。
  3. 时长与视觉内容匹配: 滚动节拍 8–18 秒,点击节拍 6–12 秒。
  4. 语调与 branding.yaml 的 voice.tone 字段匹配。

在脑海中将节拍分组为段落(概述 / 功能 A / 功能 B / 结束语),但在 YAML 中写成扁平列表——无需段落标记。

阶段 4 — 用纯文本评审

用户不直接编辑 YAML。 您将草稿呈现为编号列表,并接受自然语言反馈。请准确使用此格式:

这是我已经起草的演示流程。预计时长:5:08(1.2 倍加速后)。
请告诉我您想修改的内容。

概述(60 秒)
1. 打开主页(10 秒)—“欢迎来到 Acme Cloud,一个面向小型团队的…无服务器平台”
2. 滚动到功能(15 秒)—“三个核心能力驱动着平台…”
3. 滚动到输出(8 秒)—“这十个政策领域…”

功能 1 — 仪表盘(45 秒)
4. 导航到仪表盘(8 秒)—“点击进入仪表盘…”
5. 悬停活动动态(12 秒)—“每个项目都显示一个实时活动动态…”
...

结束语(20 秒)
27. 返回主页统计数据(12 秒)—“团队选择 Acme 的三个原因…”
28. 片尾(8 秒)

然后:“有要添加、删除或重新排序的内容吗?解说语调需要调整吗?有要跳过的内容吗?”

将自然语言反馈转换为 YAML 编辑:

  • “跳过节拍 7” → 从 YAML 中移除
  • “让节拍 3 更长” → 用更多的屏幕细节扩展解说(如果长很多,则拆分为两个节拍)
  • “在某个地方提到定价” → 确定正确的节拍并添加一句话(确认定价实际上在该节拍画面中可见)
  • “语调太正式” → 用更随意的措辞重写解说
  • “显示团队页面而不是关于页面” → 交换 URL + 调整解说

重新呈现更新后的流程。反复迭代,直到用户明确批准。

TTS 前的运行时漂移检查: 对所有节拍求和 len(beat.narration) / 16(140 wpm 时的字符数/秒)。如果 estimated * (1 / speed_multiplier) 与目标相差超过 30 秒,则指出:"当前加速后时长约为 ~6:20,而您的目标为 5 分钟。需要我进行删减吗?"

阶段 5 — 工作目录设置

mkdir -p ~/demo-videos/<demo-slug>/_assets
cp <logo_path>             ~/demo-videos/<demo-slug>/_assets/<logo>.png
# 根据您的草稿编写 storyboard.yaml、branding.yaml、demo_config.yaml

如果在 Claude Code CLI 中运行: 使用如上所示的 ~/demo-videos/<demo-slug>/。

如果在 Cowork 中运行: 调用 mcp__cowork__request_cowork_directory 获取用户的输出路径。将工作目录设置为 <outputs_path>/<demo-slug>/。在阶段 6–11 中,所有后续文件写入都使用此路径——立即存储它并在整个会话中保持一致。在此路径下创建 _assets/ 子目录,而不是在 ~/demo-videos/ 下。

如果用户磁盘上没有 logo 文件,只有一个 URL,使用 curl 下载并放入 _assets/ 中。

如果用户没有提供品牌颜色,请安装 Pillow 并从 logo 中提取主色:

uv run python3 -c "
from PIL import Image
import colorsys
img = Image.open('~/demo-videos/<slug>/_assets/logo.png').resize((1, 1))
r, g, b = img.getpixel((0, 0))[:3]
# Convert to HSL to find a complement
h, l, s = colorsys.rgb_to_hls(r/255, g/255, b/255)
accent_h = (h + 0.5) % 1.0
ar, ag, ab = colorsys.hls_to_rgb(accent_h, l, s)
print(f'Ink: #{r:02x}{g:02x}{b:02x}')
print(f'Accent: #{int(ar*255):02x}{int(ag*255):02x}{int(ab*255):02x}')
"

现在编写三个配置文件。

branding.yaml

# 使用此精确结构
brand:
  logo_path: ./_assets/<logo>.png
  colors:
    ink: '#1a1a2e'
    accent: '#e94560'
  voice:
    tone: explanatory              # 或 sales / technical / casual
    speaking_rate: 1.0             # OpenAI TTS 速度(默认 1.0)

watermark:
  enabled: true                  # 将 logo 叠加在右下角
  scale: 0.08                    # 相对于帧宽度的 logo 大小
  opacity: 0.85

demo_config.yaml

demo:
  slug: <demo-slug>
  title: "Acme Cloud — Serverless Platform for Small Teams"
  target_url: https://target.example.com
  speed_multiplier: 1.2          # Phase 9 的默认值
  target_duration_s: 300         # 加速后 5 分钟

recording:
  viewport: { width: 1440, height: 900 }
  headless: true                 # 录制期间隐藏浏览器窗口(仅在 Cowork 中相关)
  wait_for_selector_timeout: 8000

session:
  type: none                    # none | form | oauth
  storage_state: null           # 如果 type=oauth 则设置
  pre_session: {}               # 如果 type=form 则设置

storyboard.yaml

作为该阶段的输出,编写您从阶段 3–4 完善的完整故事板列表。

阶段 6 — 生成音频

对于 storyboard.yaml 中的每个节拍,调取 OpenAI TTS 端点。

mkdir -p ~/demo-videos/<demo-slug>/_audio/
# 对于每个节拍 i(从 0 开始):
curl -s https://api.openai.com/v1/audio/speech \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "tts-1",
    "input": "<beat.narration>",
    "voice": "echo",
    "speed": 1.0
  }' \
  --output ~/demo-videos/<demo-slug>/_audio/beat_$(printf '%03d' $i).mp3
  sleep 0.5  # 速率限制:大约 2 个请求/秒

TTS 提示注入: 所有解说文本的编写方式确保 TTS 输出清晰、表现力强。规则:

  • 对于首字母缩略词,使用连字符:S-P-M-E、A-P-I、K-Y-B(输出读作“S-P-M-E”而不是“SPME”)。
  • 在自然停顿处使用逗号。
  • 避免技术上正确但口语尴尬的句子。如果“前端开发说明书”听起来别扭,请重新措辞为“用于前端开发的说明书”。
  • 在 narration 字段中不要包含 SSML 或地道的发音指南——只需在 narration 字符串本身中用连字符分隔首字母缩略词即可。
  • 高度技术性的概念(“异步事务”、“零知识证明”)应该有一个简短的词典式解释,除非已知观众熟悉该术语。

如果在 Claude Code CLI 中运行: 按上述描述运行,同步进行。

如果在 Cowork 中运行: 逐节拍运行 curl 命令。对于超过 15 个节拍的故事板,使用 nohup 模式以避免 45 秒的 bash 超时:

cat > ~/demo-videos/<slug>/_audio/generate_audio.sh << 'EOFSCRIPT'
...  # 包含上述循环的脚本
EOFSCRIPT
chmod +x ~/demo-videos/<slug>/_audio/generate_audio.sh
nohup bash ~/demo-videos/<slug>/_audio/generate_audio.sh &
echo "PID: $!"

轮询 ~/demo-videos//audio/beat*.mp3 的存在以检查进度。所有文件可见后,通过报告总文件数和预期节拍数(并与 storyboard.yaml 中的节拍列表一致)来验证完整性。如果文件数量不匹配,识别缺失的节拍并重新运行其 curl 命令。

阶段 7 — 创建屏幕录制

对于 storyboard.yaml 中的每个节拍,执行指定的操作并捕获/编码帧。

demo_config.yaml 的 session 配置如何处理:

  • session.type: none → 在运行录制工具时省略所有 --storage-state 和 --pre-session 标志。
  • session.type: oauth → 包含 --storage-state ~/demo-videos/<slug>/auth.json。
  • session.type: form → 在运行录制工具之前,通过 demo_config.yaml 的 pre_session 设置提供凭据映射。工具在启动上下文中查找 .env 文件。
mkdir -p ~/demo-videos/<slug>/_frames/
uv run helpers/record_demo.py \
  --config ~/demo-videos/<slug>/demo_config.yaml \
  --audio-dir ~/demo-videos/<slug>/_audio/ \
  --frames-dir ~/demo-videos/<slug>/_frames/ \
  --storage-state ~/demo-videos/<slug>/auth.json  # OAuth 场景;自定义认证场景中设置为 --pre-session

record_demo.py 处理:

  • 节拍动作执行(goto、click、scroll_into_view、scroll_y、hover)。
  • 每个动作后的帧捕获。
  • 播放每个节拍的音频文件并捕获同步的帧序列。
  • 为速度调整(Phase 9 的 speed_multiplier)添加时间戳。

如果在 Claude Code CLI 中运行: 按上述描述运行 record_demo.py。命令通常运行 5–10 分钟——确保 Bash 工具超时设置足够高(例如,timeout: 600000)。

如果在 Cowork 中运行: 使用 nohup 模式:

nohup uv run helpers/record_demo.py --config ... &
echo "PID: $!"

每 30 秒轮询 ~/demo-videos/<slug>/_frames/ 中 .png 文件的存在以检查进度。完成后,验证帧计数是否与节拍数量匹配。

阶段 8 — 合成音频 + 帧

uv run helpers/mux_audio_video.py \
  --frames-dir ~/demo-videos/<slug>/_frames/ \
  --audio-dir ~/demo-videos/<slug>/_audio/ \
  --output ~/demo-videos/<slug>/_raw.mp4 \
  --framerate 30

mux_audio_video.py 从 _frames/ 和 _audio/ 构建最终 mp4。它处理:

  • 将帧序列编码为视频流(H.264)。
  • 从每个节拍的音频文件中读取并交错音频流。
  • 计算总时长以用于后续的速度调整。

此步骤后输出 _raw.mp4。

如果帧/音频文件丢失: mux_audio_video.py 会打印警告并跳过缺失的节拍。查看警告,识别缺失的节拍,并酌情重新运行阶段 6 或 7 来填补空缺。

阶段 9 — 速度调整

uv run helpers/adjust_speed.py \
  --input ~/demo-videos/<slug>/_raw.mp4 \
  --output ~/demo-videos/<slug>/_sped.mp4 \
  --speed 1.2

--speed 值来自 demo_config.yaml 的 speed_multiplier。adjust_speed.py 使用 FFmpeg 的 setpts 和 atempo 过滤器来均匀加速视频。音频音高通过 atempo 过滤器保持不变。

阶段 10 — 叠加品牌元素

uv run helpers/add_brand_overlay.py \
  --input ~/demo-videos/<slug>/_sped.mp4 \
  --output ~/demo-videos/<slug>/_branded.mp4 \
  --branding ~/demo-videos/<slug>/branding.yaml

add_brand_overlay.py 读取 branding.yaml 并应用:

  • 页面角落的纯色/半透明 logo 水印。
  • 品牌颜色用于片头/片尾卡片(B 阶段)。
  • 如果 B 阶段尚未实现,则仅应用水印,并在 <slug>/_branded.mp4 输出——无需错误。

阶段 11 — 交付

向用户报告 mp4 文件路径。明确说明新文件。

如果在 Claude Code CLI 中运行:

Done! Your branded demo video is at:
~/demo-videos/<slug>/_branded.mp4 (14 MB)

如果在 Cowork 中运行:

Done! Your branded demo video is at:
<outputs_path>/<slug>/_branded.mp4

You can open it via computer://<outputs_path>/<slug>/_branded.mp4

如果发生错误,请提供具体的故障排除步骤,而不仅仅是“出了点问题”。


已知陷阱(GOTCHAS)

在启动完整管道之前,请参阅 docs/GOTCHAS.md 以获取全面的列表。重点关注的问题:

  • 帧同步漂移: 如果音频和帧不同步,检查 record_demo.py 是否以正确的 fps 捕获帧,并且 mux_audio_video.py 的视频流时间戳没有偏移。
  • logo 路径丢失: 如果 branding.yaml 引用了一个不存在的 logo 文件,fix 脚本会警告并跳过覆盖层。始终在阶段 5 中确认文件是否存在。
  • OpenAI 速率限制: 阶段 6 中的 sleep 0.5 可能不足以满足 tier-1 账户(1000 RPM)。调整或无限制。
  • Playwright 浏览器安装: 如果 Phase 2a 或 Phase 7 中出现“未找到浏览器”错误,运行 uv run --with playwright playwright install chromium。
  • OAuth 令牌过期: 如果 Phase 8 中遇到登录墙,重新运行 Phase 2a。会话可能已过期。
  • 故事板节拍计数: 确保节拍计数在 Phases 4 到 7 之间保持一致。不匹配会导致 Phase 8 中出现“缺失节拍”警告。

相关技能