
Web Video Presentation
- 3.3k installs
- 10.1k repo stars
- Updated July 12, 2026
- conardli/garden-skills
web-video-presentation is an agent skill that converts articles or scripts into click-driven 16:9 Vite React presentations with optional TTS audio for screencast recording.
About
web-video-presentation is an agent skill for turning articles or narration scripts into click-driven 16:9 web presentations that look like video, with optional TTS audio synthesis. The workflow moves from raw content through a single script.md plus outline.md pass, a mandatory Checkpoint Plan aligning script, outline, theme, assets, and development mode, chapter-based Vite React TypeScript development, and optional provider-agnostic audio via narrations.ts as the sole step-count truth source. outline.md plans chapter pacing and information density but not animation types because chapter agents design motion at implementation time using CHAPTER-CRAFT.md principles. Chapter one is always a main-thread anchor requiring user approval before later chapters run sequentially, in order, or in parallel subagents. Audio paths support built-in MiniMax mmx-cli and OpenAI TTS with swappable providers in scripts/tts-providers. Hard self-check protocols require Agent Teams or subagent review of script.md, outline.md, and each completed chapter against checklists before reporting done. Developers reach for it when recording Bilibili, YouTube, or screencast tutorials, product demos, or keynote-sty.
- Single pass produces script.md and outline.md before a mandatory five-item Checkpoint Plan.
- narrations.ts is the sole truth source for step counts linking script, outline, chapters, and audio.
- outline plans pacing and screen content but deliberately avoids prescribing animation types.
- Chapter one anchor requires user approval before sequential, ordered, or parallel chapter modes.
- Provider-agnostic TTS supports MiniMax mmx-cli, OpenAI, and custom scripts/tts-providers adapters.
Web Video Presentation by the numbers
- 3,331 all-time installs (skills.sh)
- +118 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #131 of 1,335 Generative Media skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
web-video-presentation capabilities & compatibility
- Capabilities
- script and outline co generation · checkpoint plan theme and asset alignment · chapter based vite react implementation · narrations.ts step truth source · provider agnostic audio synthesis pipeline
- Use cases
- presentations · video generation · copywriting
What web-video-presentation says it does
outline 只规划节奏与信息密度,不规划动画
`narrations.ts` 是 step 数和音频合成的**唯一真相源**。
第 1 章无论哪种模式都必须主线程做完 + 用户验收
npx skills add https://github.com/conardli/garden-skills --skill web-video-presentationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3.3k |
|---|---|
| repo stars | ★ 10.1k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 12, 2026 |
| Repository | conardli/garden-skills ↗ |
How do I turn an article or narration script into a full-screen click-advanced web presentation ready for screen recording?
Turn articles or narration scripts into click-driven 16:9 web presentations with optional TTS audio for screencast recording.
Who is it for?
Creators making screencast tutorials, product demos, or keynote-style explainers from articles or voiceover scripts.
Skip if: Skip when the user has no source material and wants the agent to invent the entire topic from scratch without an article or script.
When should I use this skill?
User wants a web video presentation, dynamic slide-like tutorial, or article-to-screencast workflow with optional audio.
What you get
A Vite React TypeScript presentation with aligned script, outline, chapter implementations, and optional synthesized narration audio.
- Vite presentation project
- script.md and outline.md
- Optional MP3 narration files
By the numbers
- Skill version 1.2.1 with Vite + React + TypeScript scaffold
- Lists 6 compatible agents including claude-code, cursor, and codex-cli
- Ships 2 built-in TTS providers: MiniMax and OpenAI
Files
Web Video Presentation
把一篇文章或口播稿,一步步做成可录屏的"伪装成视频的网页",可选合成 口播音频。产出物 = Vite + React + TS 项目 + 按章节切分的音频。
适用场景
- "我有口播稿 / 一篇文章,帮我做成视频" —— 口播驱动的内容
- 想做 "动态 PPT"
- 16:9 横屏录屏,大字、留白、每屏都要有动效
- 教学 / 产品演示 / keynote 想要电影感
- B 站 / YouTube /抖音视频内容
本 Skill 以方法论 + 协作流程为核心。脚手架模板提供 token 和原语, 但每个美学决策(配色、字型、动效气质)都应该针对你的主题重新设计 —— 不要照搬。
---
工作流总览
Phase 1 内容编写
1.1 识别用户输入
1.2 一次产出 script.md + outline.md
(口播稿 + 开发计划)
▼
[Checkpoint Plan] ← 必须停。一次对齐 5 件事:
稿子 / outline / 主题 / 素材 / 开发模式
▼
Phase 2 网页开发
2.1 脚手架(按选定主题)
2.2 第 1 章 = 主线程 + 完整版本(强制 anchor)
▼
[硬节点] 用户验收第 1 章 ← 不可跳过
▼
2.3 第 2~N 章(按选定模式:A 逐章 / B 顺序 / C 并行)
▼
[Checkpoint Audio] ← 必须停。是否合成音频
▼
Phase 3 音频合成(可选)
▼
Phase 4 录屏 + 后期工作目录约定(agent 在用户当前目录下创建 / 编辑):
my-video/
├── article.md # 用户给原文时必有 —— 不删!开发阶段画面信息源
├── script.md # 必有:保持原文语言的平台化口播稿(决定节拍)
├── outline.md # 必有:开发计划(章节切分 + 每步内容 + 信息池)
└── presentation/ # 脚手架产出的 Vite + React + TS 项目
├── src/chapters/<NN>-<id>/
│ ├── <Chapter>.tsx # 视觉实现
│ ├── <Chapter>.css
│ └── narrations.ts # ★ step 数 + 口播文本的唯一真相源
├── scripts/
│ ├── extract-narrations.ts # 扫所有 narrations.ts → audio-segments.json
│ ├── synthesize-audio.sh # provider-agnostic runner(循环 segments)
│ └── tts-providers/ # 每 provider 一个 .sh(内置 2 个)
│ ├── README.md # 三函数契约 + 5 段现成代码片段(11labs / edge-tts / say / azure / gcloud)
│ ├── minimax.sh # 默认 provider,用 mmx-cli
│ └── openai.sh # 内置 OpenAI TTS(curl + OPENAI_API_KEY)
├── audio-segments.json # extract 产出(合成前 review)
└── public/audio/<id>/<N>.mp3 # 可选:合成的音频关键:narrations.ts 是 step 数和音频合成的唯一真相源。章节.tsx里的if (step === N)出现的最大 N + 1 必须等于
narrations.length。这保证 5 处地方(script / outline / 章节代码 /chapters.ts / 音频文件)永远不会漂。
---
硬性自检协议(贯穿整个 Skill)
下面三个产出,每一个完成后必须走自检 → 修复 → 再汇报 / 推进:
| 产出 | 自检清单出处 |
|---|---|
script.md | `SCRIPT-STYLE.md` 三层自检(形式 / 风骨 / 念出来) |
outline.md | `OUTLINE-FORMAT.md` 自检 |
| 单章实现完成 | `CHAPTER-CRAFT.md` 完工自检 |
执行方式(按能力降级,优先用更隔离的方式):
1. Agent Teams(最优):开一个独立的 reviewer agent,给它"产出文件 路径 + 对应清单 + 关键上下文",让它逐项核查并严格汇报结论 (哪几条 pass / 哪几条 fail + 证据 + 改写建议)。 2. subAgent(次优):没有 Teams 能力但能开 subagent 就用 subagent 走同样流程。 3. 自检(兜底):当前 agent 都没有上述能力,就自己严格逐项 核查 —— 不允许目测一遍就放行。
铁律:拿到结论后先按 fail 项把产出改完,再向用户汇报"做完了 + 自检结论 + 改了什么"。直接拿原始结论汇报但不修复 = 违规。
---
各阶段文件读取指南
不同阶段读不同的文件。长会话里 agent 容易遗忘原则,特别是 Phase 2.4 的"实现单章"会重复 N 次 —— 每次都要回看核心约束。
| 阶段 | 必读(每次都看) | 一次性看完 / 按需查 |
|---|---|---|
| Phase 1.1-1.2 内容编写 | references/SCRIPT-STYLE.md + references/OUTLINE-FORMAT.md + article.md(用户原文,如有) | —— |
| Checkpoint Plan 选主题 | —— | themes/*/theme.json(动态读全部,列清单 + bestFor 推荐 + descriptionZh);references/THEMES.md(用户想了解主题系统时) |
| Phase 2.1 脚手架 | —— | SKILL.md 本节看一次 |
| Phase 2.4 实现单章(×N 次,被 2.2 / 2.3 调用) | `references/CHAPTER-CRAFT.md` 单一入口 —— Part 0 十条原则 / Part 1 开工 5 问 / Part 2 关系→动作决策树 / Part 3 视觉工具箱 / Part 4 时长参考 / Part 5 反 AI 味反模式 / Part 6 代码硬规则(含 narrations.ts 强制约束)/ Part 7 完工自检 / Part 8 反馈速查 + 当前主题的 themes/<id>/theme.json + 当前章节的 outline.md 段落 + `article.md` 本章对应段落 + 素材清单 | references/EXAMPLES/(结构示意,不是抄袭模板);references/THEMES.md 完整 token 契约 |
| Phase 3 音频合成 | references/AUDIO.md(含 narrations.ts → segments.json → 任意 provider 流程,内置 minimax + openai) | templates/scripts/tts-providers/README.md(换 provider / 自带 TTS 时) |
| Phase 4 录屏 + 后期 | references/RECORDING.md(含 ?auto=1 自动录屏) | —— |
| 选 / 造 / 切主题 | —— | references/THEMES.md |
写章节时只读一份 `CHAPTER-CRAFT.md`。十条原则 / 开工 self-prompting /
决策树 / 反 AI 味反模式 / 完工自检全部并入这一份单一入口。EXAMPLES/不是必读 —— 先按内容自由设计,卡壳才翻(按 anchor 翻"形",不要照搬)。
---
Phase 1 —— 内容编写(一次产出)
1.1 识别用户输入
| 用户给的东西 | 该做的 |
|---|---|
| 原始文章(书面语 / 公众号 / 论文 / 博客) | 一次产出 script.md + outline.md(1.2),过 Checkpoint Plan |
| 直接的口播稿 / 视频脚本 | 落盘成 script.md,一次产出 outline.md(1.2 简化版),过 Checkpoint Plan |
| 啥都没有,只说"帮我做个 X 主题的视频" | 反问:先给一段素材或大纲。Skill 不替用户构思内容 |
1.2 一次产出 script.md + outline.md
两份产出物在一次思考中完成:
1. 生成 `script.md`:按 `references/SCRIPT-STYLE.md` 的规则把 article 转成保持原文语言的平台化口播稿。保留 `article.md` 不删——它是 outline 写信息池和章节实现画面时的细节源(双源原则)。 2. 生成 `outline.md`:按 `references/OUTLINE-FORMAT.md` 规则切章节 + 切 step + 每章首段抽信息池。
outline 的边界(关键):
| outline 必须写 | outline 不要写 |
|---|---|
| 章节切分 / 每章 step 数 / 估时 | 具体动画类型(blur clear / wipe / 弹簧) |
| 每步屏幕内容(hero / 数据 / 标语 / 列表项) | CSS 实现手段(filter / SVG / clip-path) |
| 章节级信息池:从 article 抽的数字 / 引用 / 案例 / 标签 | 时长数值(不写 ~2.5s / 80~120ms) |
| 步级关系名前缀("反差对照" / "递进列表" / "金句" 等可选 hint) | 持续微动 / 错峰量等微观节奏 |
outline 不写动画的理由:写死动画 = chapter agent 退化为翻译机;
留白让 chapter agent 在每步开工时按 `CHAPTER-CRAFT.md`
的"内容驱动决策树"自由设计,才有真正的视频感。详见
`CHAPTER-CRAFT.md` Part 0 原则 7。
落盘后必须先走自检再进 Checkpoint Plan:按上文「硬性自检协议」分别 对 script.md / outline.md 执行(优先 Agent Teams → subAgent → 自检), 按结论修复完成后再进入 Checkpoint Plan。
---
Checkpoint Plan —— 5 件事一次对齐(硬节点)
script.md + outline.md 写完后必须停下来。用户在这一个节点同时确认 5 件事。
agent 此时要做的预备工作
1. 读所有 themes/*/theme.json 拿 nameZh / descriptionZh / bestFor / mood —— 不要硬编码清单 2. 根据 script.md 的内容类型 / 关键词 / 语气,主动从主题里挑 2~3 套最匹配的推荐(匹配 bestFor 字段) 3. 扫一遍 outline.md 末尾"素材清单"部分
总结模板(骨架,agent 按情况填充)
内容计划写完,产出文件:
📄 article.md {若用户给原文则保留}
📄 script.md {X} 字 / ~{T} 分钟
📄 outline.md {N} 章 / {M} 步 + 每章信息池 + 末尾素材清单
章节速览:
1. <id> <章节标题> <S> 步 ~<T>s
2. ...
接下来一次对齐 5 件事:
1. 稿子 (script.md) 要不要改?
可以直接编辑文件,或口头告诉我修改方向。
2. 开发计划 (outline.md) 要不要改?重点看:
- 章节切分 / step 数 / 估时是否合理(合理判断:每章 30~60s)
- 每步屏幕内容是否清晰
- 每章首段「信息池」是否有足够的 article 细节供画面挂
- 末尾素材清单是否完整
3. 选哪个主题?我的推荐:
★ <推荐 1:nameZh (id)> — 因为 <bestFor 命中>;<descriptionZh 摘要>
★ <推荐 2 / 推荐 3>
其它可选:<剩余主题,nameZh + 一句话>
也可以让我帮你做新主题(详见 references/THEMES.md)。
4. 真素材怎么准备?粗看本视频要的图:<列粗略清单>
a) 我从 <现有素材路径> 帮你挑 b) 你自己提供 c) 全部 placeholder
5. 开发模式选哪个?
**第 1 章无论哪种模式都必须主线程做完 + 用户验收**(强制 anchor)。
差异在第 2 章及之后:
A) 默认 · 逐章确认(推荐)
每章做完都暂停验收 → 风险可控 / 节奏最稳
B) 第 1 章后顺序开发(不并行)
第 2~N 章主线程顺序做完后统一验收 → 速度中 / 适合 agent 不支持并行
C) 第 1 章后并行开发(subagent)
第 2~N 章用 subagent 并行 → 最快 / 用户控并行数(一次几章)
⚠️ 风格各章会有差异(这是预期,主题禁区兜底)收到反馈后:
- 稿子 / outline 要改:直接编辑文件,编辑完 ping 一次(或口头描述 agent 改)
- 主题必须明确才进入 Phase 2。用户说"主题你帮我选" → 取你推荐的第 1 个,
告诉用户你选了什么、为什么,给反悔机会
- 模式选定 → 进 Phase 2
---
Phase 2 —— 网页开发
2.1 脚手架
bash <path-to-web-video-presentation>/scripts/scaffold.sh \
./presentation \
--theme=<用户选的主题 id>
bash <path-to-web-video-presentation>/scripts/scaffold.sh --list-themes自定义主题 → 先按 `references/THEMES.md`
"创作新主题"流程做一个themes/<my-theme>/,再--theme=<my-theme>。
脚手架带一个 01-example demo。在写第一章真实内容前删掉:
rm -rf presentation/src/chapters/01-example并把 presentation/src/registry/chapters.ts 里 EXAMPLE_CHAPTER 的 import 和数组项移除。
2.2 第 1 章 —— 主线程 + 强制验收
核心:第 1 章 = 完整版本一次到位(节奏 + 视觉 + 真素材齐全)。 没有"骨架版"概念 —— 第一章就要做出用户能直接验收的样板。
为什么第 1 章必须主线程:
- 它是 `CHAPTER-CRAFT.md` 这套指引在**当前
主题 + 当前题材**下的第一次落地
- 如果指引有盲区 / 主题颜色 / 字体 token 不够用,第 1 章一定会暴露 ——
这时候有人类反馈就能修指引 / 调主题,早改成本最低
- 后续章节(无论顺序 / 并行)都要参考第 1 章的代码模式,所以第 1 章 =
当次项目的"风格锚点(不强求章节间一致,但单章自身得有完整说服力)"
做完第 1 章后必须停下来等用户验收:
第 1 章 <id> 做完了,dev server 在 localhost:5173 运行。
验收重点:
□ 视觉气质对不对?符合 <theme nameZh> 的预期吗?
□ 节奏对不对?某些步太快 / 太慢 / 信息太薄?
□ 内容驱动动画是否到位?还是有几步是无脑入场动画?
□ 双源原则:屏幕画面有没有"口播没念但 article 能挂"的细节?
□ 反 AI 味检查:紫粉渐变 / 圆角彩色边框 / 假插画 / emoji 是否有?
问题告诉我,我针对性改。OK 了告诉我"继续",我按选定模式做第 2 章及之后。2.3 第 2~N 章 —— 按选定模式
所有模式下的共同规则:每章独立按 `CHAPTER-CRAFT.md` 开发。风格不强求章节间完全一致 —— 主题颜色 / 字体 token 兜底视觉 统一,动画 / 节奏 / 视觉演示由章节自由发挥是设计预期。
模式 A · 默认 · 逐章确认
第 2 章做完 → 暂停验收 → OK → 第 3 章 → 暂停 → ... → 第 N 章。每章 独立验收,问题随时改,风险最低,节奏最稳。用户不明确选模式时 默认走这个。
模式 B · 第 1 章后顺序开发
第 2 章 → 第 3 章 → ... → 第 N 章 主线程顺序做完,最后统一验收。 速度中等,适合 agent 不支持并行任务的环境。
模式 C · 第 1 章后并行开发(subagent)
用 subagent 把第 2~N 章并行做完,最大并行数由用户控制("一次 4 章" / "一次 2 章")。最快,但风格各章会有差异 —— 这是预期,因为:
1. 每个 subagent 看不到别的 subagent 产出,无法机械对齐 2. 章节代码物理分离(每章一个文件夹 / 自己的 CSS 前缀),不会互相 破坏 3. 主题 token 兜底视觉统一(颜色 / 字体 / hero 数字 / 卡片 / 分割线 性格 / 装饰),气质不会跑偏 4. 风格不一致 = 人手写视频的呼吸感(多 voice / 多视角)
并行 subagent 的 prompt 必须包含:
- 当前章节 outline 段落(含信息池)
references/CHAPTER-CRAFT.md的路径(单一必读 —— 视觉演示要求 +
逐步揭示 + 双源原则 + 反 AI 味 + 代码红线 + 完工自检全部在这一份里)
- 当前主题
theme.json的descriptionZh/mood/bestFor(参考气质
即可,动画 / 时长 / 字号 / emoji 由 chapter agent 自由决定)
- 第 1 章代码作为"代码风格"参考(不是"视觉抄袭对象")
- 硬规则:每章独立 CSS 前缀(
.cd-/.mg-/.pm-/ ...);
不修改 chapters.ts;完工跑 npx tsc --noEmit
重要:无论选哪种模式,用户随时可以中途切换模式。第 2 章 OK 后用户说"剩下的并行" / "剩下的逐章" 都行。
2.4 实现单章(每章必走)
详细指引见 `references/CHAPTER-CRAFT.md` —— 单一必读入口,覆盖:视觉演示要求 / 逐步揭示 / 内容取舍 / 双源原则 / 视频演示基本审美 / 反 AI 味 / 代码红线 / 完工自检。
核心要点(CHAPTER-CRAFT.md 详述):
- 每章必须有 CSS / SVG / Canvas / JS 视觉演示,禁纯文字章节
- 逐步揭示:清单 / 列表必须 1 项 = 1 step,禁一次全展示
- 双源原则:节奏跟口播稿(顺序不能乱),细节回原文章抽(信息池 +
本章 article 段落)
- 完工自检逐项过,不达标回去改 —— 按上文「硬性自检协议」执行
(优先 Agent Teams → subAgent → 自检),改完再向用户汇报本章交付
2.5 大改后 bump STORAGE_KEY
改动 chapters.ts(增加 / 删除 / 重排章节,或某章 narrations.ts 长度变化)后,bump presentation/src/hooks/useStepper.ts 的 STORAGE_KEY(如 v4 → v5),避免持久化游标落到不存在的 step 上。
---
Checkpoint Audio —— 是否合成音频(硬节点)
Phase 2 结束后必须停下来,问用户:
网页做完,{N} 章 {M} 步,dev server 在 localhost:5173 跑着。
要不要合成音频做"自动播放录屏"?
✓ 合成 → 扫所有章节的 narrations.ts 出 audio-segments.json,
调 TTS provider 合成每步一个 mp3 到 public/audio/。
合成完后用 ?auto=1 模式可以一镜到底录屏(音视频天然同步)。
内置两个 provider:
• minimax (mmx-cli) —— 默认,中文音色稳
• openai (OPENAI_API_KEY) —— curl-based,多数已有 key
其它后端 (ElevenLabs / edge-tts 免费 / macOS say 离线 /
Azure / Google) 见 scripts/tts-providers/README.md 的现成片段。
✗ 不合成 → 跳过 Phase 3,直接 Phase 4 用手动录屏 + 后期配音。要合成 → Phase 3。不合成 → 直接 Phase 4。
---
Phase 3 —— 音频合成(可选)
详细流程见 `references/AUDIO.md`。简版:
cd presentation
npm run extract-narrations # 扫所有 narrations.ts → audio-segments.json
# 让用户扫一眼 audio-segments.json 确认文本对
npm run synthesize-audio # 默认 minimax provider,增量
# 或用内置 openai (要 OPENAI_API_KEY):
PRESENTATION_TTS=openai npm run synthesize-audio
# 或自定义:写一个 scripts/tts-providers/<name>.sh,见该目录的 README.md合成完告诉用户:输出位置 / 总段数 / 哪些段时长异常(太长 = 该 step 拆 分;太短 = 文案太薄)—— 给最后一次校准节奏的机会。然后进入 Phase 4。
---
Phase 4 —— 录屏 + 后期
详见 `references/RECORDING.md`。两种路径:
| 场景 | 推荐路径 |
|---|---|
| Phase 3 已合成音频 | Auto 模式一镜到底:浏览器开 localhost:5173/?auto=1 → 按 SPACE → 整片自动播完 → 停录 → 裁头尾即成片,无需后期对音轨 |
| Phase 3 跳过 | 默认 Manual 模式手动点击推进 → 后期任意剪辑工具配音 |
agent 在 Phase 3 / Checkpoint Audio 后主动告诉用户适合的录屏路径。
---
十条原则(一句话清单)
完整展开见 `references/CHAPTER-CRAFT.md` Part 0 —— 写章节时回那里查,下面只是索引。
| # | 原则 | 一句话 |
|---|---|---|
| 1 | 16:9 固定舞台 | 内容 1920×1080 + transform scale,没有响应式 |
| 2 | 全局 step 计数器 | 章节是 step 的纯函数,无定时器 |
| 3 | 每步独占整屏 | if (step === N) return <FullScene /> |
| 4 | 口播节拍 = step | 一节拍 = 一 step = 一聚焦想法 |
| 5 | 隐藏的边角控件 | 进度条 / 翻页器默认 opacity 0 |
| 6 | 舞台无 chrome | 没有 header / footer / 页码 / 品牌条 |
| 7 | 内容驱动动画 | 先找内在动作,找不到才入场动画兜底;持续微动慎用 |
| 8 | 多点逐个揭示 | 1 项 = 1 step,禁同步 stagger 上 N 项 |
| 9 | 整片同一主题 | 章节间不翻表面色;颜色 / 字体走 token,其它尺度章节自由 |
| 10 | 双源原则 | script 定节拍,article 定画面密度(落到信息池) |
---
常见用户反馈速查
简化表见 `references/CHAPTER-CRAFT.md` Part 8「常见反馈速查」。关键:先定位是哪一层(节奏 / 视觉 / 内容 / 代码),再改最小切片,不要重做整章。
---
相关资源
按"何时读"标注,避免一次性全读:
| 文件 | 何时读 | 内容 |
|---|---|---|
| `references/SCRIPT-STYLE.md` | Phase 1.2 必读 | 文章 → 口播稿规则、平台变体 |
| `references/OUTLINE-FORMAT.md` | Phase 1.2 必读 | outline.md 字段 spec、命名约定、章节切分、信息池 |
| `references/CHAPTER-CRAFT.md` | Phase 2.4 每章单一必读入口 | Part 0 十条原则 / Part 1 开工 5 问 / Part 2 关系→动作决策树 / Part 3 视觉工具箱 / Part 4 时长 / Part 5 反 AI 味反模式 / Part 6 代码硬规则 / Part 7 完工自检 / Part 8 反馈速查 |
| `references/EXAMPLES/` | 可选 —— 看结构 | 章节结构示意(hook / list-reveal / case-tech-review);不是抄袭模板 |
| `references/THEMES.md` | 选 / 造 / 切主题时 | 完整 token 契约 + 内置主题清单 + 创作流程 |
| `references/AUDIO.md` | Phase 3 才读 | provider-agnostic 音频合成流程、内置 minimax 用法、换 provider 路径、故障排查 |
| `templates/scripts/tts-providers/README.md` | 换 / 加 TTS provider 时 | 三函数契约 + 内置 2 个 (minimax / openai) + 5 种现成代码片段(ElevenLabs / edge-tts / macOS say / Azure / Google) |
| `references/RECORDING.md` | Phase 4 才读 | 录屏工具 + 后期合成 |
| `themes/` | Checkpoint Plan / Phase 1.2 时翻 | 内置主题(每个含 theme.json + tokens.css) |
| `scripts/scaffold.sh` | Phase 2.1 跑一次 | 一键项目脚手架 |
{
"name": "web-video-presentation",
"version": "1.2.2",
"category": "Web Video / Presentation",
"description": "Turn scripts, articles, lessons, product demos, and talks into click-driven 16:9 web presentations that can be screen-recorded as cinematic videos. Ships a Vite + React + TypeScript scaffold, a (chapter, step) cursor model, hard collaboration checkpoints, and a theme-token architecture.",
"homepage": "https://github.com/ConardLi/garden-skills/tree/main/skills/web-video-presentation",
"compat": [
"claude-code",
"claude-ai",
"cursor",
"codex-cli",
"gemini-cli",
"opencode"
]
}
Web Video Presentation Skill
A method-driven agent skill for turning scripts and articles into click-driven 16:9 web presentations that can be screen-recorded as cinematic videos.
中文文档 · Back to collection root

---
What Is This?
web-video-presentation helps an agent build a Vite + React + TypeScript presentation that behaves like a video production surface rather than a slide deck. Each click advances one narration beat, each step owns the whole 1920×1080 stage, and the progress UI stays hidden unless hovered so the output is clean for screen recording.
It is designed for:
- Turning a written article into a Bilibili / YouTube / video-channel narration script
- Turning an existing voiceover script into a cinematic web presentation
- Building product demos, tutorials, keynote-style explainers, and visual talks
- Creating “dynamic PPT, but not PPT” experiences with strong motion and pacing
- Optionally synthesizing narration audio after the visual outline is approved
The skill is primarily a methodology and collaboration workflow. The scaffold supplies reusable tokens, stage primitives, themes, and examples, but each project should still choose a visual language that fits the topic.
---
Core Ideas
- Fixed 16:9 stage — content is authored in a stable 1920×1080 coordinate system and scaled to the viewport.
- One global step cursor — click or keyboard advances
(chapter, step), with the cursor persisted locally. - One step, one idea — every beat gets a focused full-screen scene instead of accumulating slide bullets.
- Script beats drive structure — narration rhythm maps directly to visual steps.
- Hidden chrome — progress controls are hover-only, keeping recordings clean.
- Motion first — each scene needs a moving visual anchor; static paragraphs are treated as a smell.
- Theme tokens — visual decisions flow through semantic tokens so themes can change the whole feel.
- Pluggable TTS — provider-agnostic audio runner ships two built-in providers (MiniMax
mmx-cliand OpenAI TTS via curl); swap to ElevenLabs / edge-tts / Azure / Google Cloud / macOSsay/ any self-hosted TTS by dropping a single shell file intotts-providers/. - Hard checkpoints — the agent pauses after script/theme alignment, after outline approval, and before optional audio synthesis.
---
Workflow
Phase 1.1 Identify input
Phase 1.2 Article -> narration script
|
Checkpoint A1 Script, theme, and rough asset plan
|
Phase 1.3 Script + article -> outline.md
|
Checkpoint A2 Outline approval + development mode
|
Phase 2 Build the Vite / React / TS presentation
|
Checkpoint B Ask whether to synthesize audio
|
Phase 3 Optional audio synthesis
Phase 4 Recording and post-productionThe checkpoints are part of the skill contract: the agent should not silently rush from raw article to finished code. Theme choice influences motion design, and outline approval keeps chapter pacing from drifting.
---
What It Ships
skills/web-video-presentation/
├── SKILL.md
├── README.md / README.zh-CN.md
├── references/
│ ├── PRINCIPLES.md
│ ├── CHAPTER-CRAFT.md
│ ├── OUTLINE-FORMAT.md
│ ├── SCRIPT-STYLE.md
│ ├── THEMES.md
│ ├── AUDIO.md
│ └── RECORDING.md
├── scripts/
│ └── scaffold.sh
├── templates/
│ ├── index.html
│ ├── vite.config.ts
│ ├── scripts/
│ │ ├── extract-narrations.ts
│ │ ├── synthesize-audio.sh # provider-agnostic runner
│ │ └── tts-providers/ # 1 file = 1 TTS backend
│ │ ├── README.md # contract + ready-to-paste ElevenLabs / edge-tts / Azure / Google / say snippets
│ │ ├── minimax.sh # default — uses mmx-cli
│ │ └── openai.sh # built-in — uses OPENAI_API_KEY via curl
│ └── src/
└── themes/ # 23 themes, each with its own signature
├── midnight-press/
├── warm-keynote/
├── newsroom/
├── bauhaus-bold/
└── ... # full list in references/THEMES.md---
Quick Start
Copy the skill into the directory your agent scans, then ask it to turn a script or article into a web-video presentation.
To scaffold manually from inside a project:
bash skills/web-video-presentation/scripts/scaffold.sh ./presentation --theme=paper-pressList available themes:
bash skills/web-video-presentation/scripts/scaffold.sh --list-themesThe generated presentation/ project is a normal Vite + React + TypeScript app. Run it like any other Vite project, then record the 16:9 stage with your screen recorder.
---
Theme Gallery
The skill ships 23 themes, each with its own design DNA — not a simple color swap. Browse the gallery below by canvas tone, pick one that fits the topic, or use any tile as a starting point for a derived theme. Click any preview to open the full-size 1920×1080 frame.
Frames are real 16:9 stages rendered by the live demo gallery at `demo/web-video-presentation-demo`.
Dark · 8 themes
Cinematic dark canvases — for focus, drama, and high-contrast storytelling.
<table> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/midnight-press.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/midnight-press.webp" alt="midnight-press preview" /></a> <br /><strong><code>midnight-press</code></strong> <br /><sub>Cinematic editorial dark · warm espresso + hot orange</sub> <br /><sub><b>Best for</b> · developer tutorials · AI & tool reviews · technical deep dives</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dark-botanical.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dark-botanical.webp" alt="dark-botanical preview" /></a> <br /><strong><code>dark-botanical</code></strong> <br /><sub>Premium editorial dark · terracotta / blush / gold glow</sub> <br /><sub><b>Best for</b> · brand films · fashion & beauty · premium product launches</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/chalk-garden.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/chalk-garden.webp" alt="chalk-garden preview" /></a> <br /><strong><code>chalk-garden</code></strong> <br /><sub>Slate chalkboard · handwritten Patrick Hand + chalk-yellow</sub> <br /><sub><b>Best for</b> · explainers · classroom teaching · beginner-friendly walk-throughs</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/blueprint.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/blueprint.webp" alt="blueprint preview" /></a> <br /><strong><code>blueprint</code></strong> <br /><sub>Drafting board · deep navy + cyan + 60 px grid</sub> <br /><sub><b>Best for</b> · tech architecture · system breakdowns · API / SDK intros</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/terminal-green.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/terminal-green.webp" alt="terminal-green preview" /></a> <br /><strong><code>terminal-green</code></strong> <br /><sub>80s phosphor CRT · mono-only + scanlines</sub> <br /><sub><b>Best for</b> · CLI tutorials · hacker / security topics · retro-tech homages</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/neon-cyber.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/neon-cyber.webp" alt="neon-cyber preview" /></a> <br /><strong><code>neon-cyber</code></strong> <br /><sub>Cyberpunk future · cyan + magenta double-neon</sub> <br /><sub><b>Best for</b> · AI / LLM reviews · web3 & security · futuristic / cyberpunk topics</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bold-signal.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bold-signal.webp" alt="bold-signal preview" /></a> <br /><strong><code>bold-signal</code></strong> <br /><sub>Hero pitch deck · dark gradient + orange focal card</sub> <br /><sub><b>Best for</b> · pitch decks · product launches · brand keynote opens</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/creative-voltage.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/creative-voltage.webp" alt="creative-voltage preview" /></a> <br /><strong><code>creative-voltage</code></strong> <br /><sub>Saturated electric blue + neon yellow halftone</sub> <br /><sub><b>Best for</b> · design week · studio showcases · type / visual-culture talks</sub> </td> </tr> </table>
Light · 15 themes
Bright editorial canvases — for clarity, restraint, and the warmth of printed paper.
<table> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/paper-press.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/paper-press.webp" alt="paper-press preview" /></a> <br /><strong><code>paper-press</code></strong> <br /><sub>Editorial paper · warm cream + hot orange</sub> <br /><sub><b>Best for</b> · magazine pieces · lifestyle · everyday tool reviews</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/newsroom.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/newsroom.webp" alt="newsroom preview" /></a> <br /><strong><code>newsroom</code></strong> <br /><sub>NYT broadsheet · newsprint cream + banner red</sub> <br /><sub><b>Best for</b> · documentary reporting · deep reviews · current-affairs commentary</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/monochrome-print.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/monochrome-print.webp" alt="monochrome-print preview" /></a> <br /><strong><code>monochrome-print</code></strong> <br /><sub>Refined Monocle / Wallpaper print restraint</sub> <br /><sub><b>Best for</b> · long-read adaptations · academic / opinion · arts criticism</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/vintage-editorial.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/vintage-editorial.webp" alt="vintage-editorial preview" /></a> <br /><strong><code>vintage-editorial</code></strong> <br /><sub>Witty Fraunces + geometric overlay (circle / line / dot)</sub> <br /><sub><b>Best for</b> · personal essays · culture columns · type / design talks</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/sunset-zine.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/sunset-zine.webp" alt="sunset-zine preview" /></a> <br /><strong><code>sunset-zine</code></strong> <br /><sub>Risograph zine · peach + magenta + dashed cut lines</sub> <br /><sub><b>Best for</b> · lifestyle vlogs · creative shares · short-video / zine-style</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/pastel-dream.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/pastel-dream.webp" alt="pastel-dream preview" /></a> <br /><strong><code>pastel-dream</code></strong> <br /><sub>Soft pastel + sage + right-edge pill ribbon</sub> <br /><sub><b>Best for</b> · product onboarding · friendly tutorials · wellness & parenting</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/warm-keynote.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/warm-keynote.webp" alt="warm-keynote preview" /></a> <br /><strong><code>warm-keynote</code></strong> <br /><sub>Modern SaaS keynote · glass slab + teal + warm grid</sub> <br /><sub><b>Best for</b> · SaaS keynotes · B2B launches · team-facing roll-ups</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/electric-studio.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/electric-studio.webp" alt="electric-studio preview" /></a> <br /><strong><code>electric-studio</code></strong> <br /><sub>Corporate clarity · crisp white + electric-blue base bar</sub> <br /><sub><b>Best for</b> · B2B product talks · investor decks · quarterly updates</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bauhaus-bold.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bauhaus-bold.webp" alt="bauhaus-bold preview" /></a> <br /><strong><code>bauhaus-bold</code></strong> <br /><sub>Manifesto modernist · 0 radius + 4 px thick frame</sub> <br /><sub><b>Best for</b> · product launches · manifestos · brand statements</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/swiss-ikb.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/swiss-ikb.webp" alt="swiss-ikb preview" /></a> <br /><strong><code>swiss-ikb</code></strong> <br /><sub>Extra-light 200 Helvetica + IKB + 1 px hairline grid</sub> <br /><sub><b>Best for</b> · AI / tech launches · year-in-review data · info-graphics</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dune.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dune.webp" alt="dune preview" /></a> <br /><strong><code>dune</code></strong> <br /><sub>Charcoal + sand · near-zero accent (architecture brochure)</sub> <br /><sub><b>Best for</b> · architecture & interior · art exhibitions · premium brand books</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/indigo-porcelain.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/indigo-porcelain.webp" alt="indigo-porcelain preview" /></a> <br /><strong><code>indigo-porcelain</code></strong> <br /><sub>Indigo <em>is</em> the ink (not an accent) + porcelain white</sub> <br /><sub><b>Best for</b> · academic research · AI / data deep dives · serious tech briefings</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/forest-ink.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/forest-ink.webp" alt="forest-ink preview" /></a> <br /><strong><code>forest-ink</code></strong> <br /><sub>Forest green <em>is</em> the ink + ivory (vintage National Geographic)</sub> <br /><sub><b>Best for</b> · nature & sustainability · documentary non-fiction · slow living</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/kraft-paper.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/kraft-paper.webp" alt="kraft-paper preview" /></a> <br /><strong><code>kraft-paper</code></strong> <br /><sub>Deep brown <em>is</em> the ink + kraft beige + copper accent</sub> <br /><sub><b>Best for</b> · book reviews · history & nostalgia · craft & food storytelling</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/split-canvas.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/split-canvas.webp" alt="split-canvas preview" /></a> <br /><strong><code>split-canvas</code></strong> <br /><sub>Dual-tone · peach left + lavender right</sub> <br /><sub><b>Best for</b> · A/B comparisons · dialogue stories · concept-contrast explainers</sub> </td> <td align="center" width="50%" valign="middle"> <br /> <strong>+ derive your own</strong> <br /><sub>See <a href="./references/THEMES.md">THEMES.md</a> for the token contract,<br />theme signatures, and Swiss yellow / green / orange variants.</sub> <br /><br /> </td> </tr> </table>
---
Reference Map
- PRINCIPLES.md — core rules for video-like web presentations
- CHAPTER-CRAFT.md — chapter implementation rules and visual checklist
- OUTLINE-FORMAT.md — required outline structure
- SCRIPT-STYLE.md — article-to-narration rewrite guidance
- PATTERNS.md — optional visual primitive recipes
- AUDIO.md — optional narration synthesis workflow (provider-agnostic)
- tts-providers/README.md — TTS provider contract + 2 built-ins (minimax / openai) + ready-to-paste snippets for ElevenLabs / edge-tts / Azure / Google Cloud / macOS say
- RECORDING.md — screen recording and post-production notes
Web Video Presentation Skill
把文章或口播稿做成点击驱动的 16:9 网页演示,并通过录屏产出有电影感视频的 Agent Skill。
English · 返回集合首页

---
这是什么?
web-video-presentation 帮 Agent 构建一种 Vite + React + TypeScript 演示:它看起来不是传统幻灯片,而更像为录屏设计的视频舞台。每次点击推进一个口播节拍,每一步独占 1920×1080 舞台,进度 UI 平时隐藏,只有悬浮时出现,方便录出干净画面。
它适合:
- 把文章改写成 B 站 / YouTube / 视频号风格口播稿
- 把已有口播稿做成有节奏的网页演示
- 做产品演示、教程、keynote 式讲解、视觉 talk
- 做“动态 PPT,但不要像 PPT”的演示体验
- 在视觉 outline 对齐后,可选合成口播音频
这个 Skill 的核心是方法论 + 协作流程。脚手架提供 token、舞台原语、主题和示例,但每个项目仍然应该根据主题重新选择视觉语言。
---
核心理念
- 固定 16:9 舞台:内容写在稳定的 1920×1080 坐标系里,再按视口缩放。
- 一个全局 step 游标:点击或键盘推进
(chapter, step),游标本地持久化。 - 一步一个想法:每个节拍独占整屏,不堆叠项目符号。
- 口播节拍驱动结构:讲述节奏直接映射为视觉 step。
- 隐藏 chrome:进度控制悬浮才出现,录屏画面保持干净。
- 动效优先:每一步都需要一个移动的视觉锚点,静态正文是坏味道。
- 主题 token:视觉属性通过语义 token 驱动,换主题不只是换颜色。
- 可插拔 TTS:provider-agnostic 音频 runner,内置 2 个 provider(MiniMax
mmx-cli+ OpenAI TTS via curl);往tts-providers/丢一个.sh就能换成 ElevenLabs / edge-tts / Azure / Google Cloud / macOSsay/ 任何自部署 TTS。 - 硬 checkpoint:稿子/主题、outline、音频合成前都必须停下来与用户确认。
---
工作流
Phase 1.1 识别用户输入
Phase 1.2 文章 -> 口播稿
|
Checkpoint A1 稿子、主题、粗略素材计划
|
Phase 1.3 口播稿 + 原文 -> outline.md
|
Checkpoint A2 outline 确认 + 开发模式选择
|
Phase 2 构建 Vite / React / TS 演示
|
Checkpoint B 询问是否合成音频
|
Phase 3 可选音频合成
Phase 4 录屏与后期这些 checkpoint 是 Skill 契约的一部分:Agent 不应该从原文一路闷头做到成品。主题选择会影响动效气质,outline 确认能避免章节节奏跑偏。
---
内含内容
skills/web-video-presentation/
├── SKILL.md
├── README.md / README.zh-CN.md
├── references/
│ ├── PRINCIPLES.md
│ ├── CHAPTER-CRAFT.md
│ ├── OUTLINE-FORMAT.md
│ ├── SCRIPT-STYLE.md
│ ├── THEMES.md
│ ├── AUDIO.md
│ └── RECORDING.md
├── scripts/
│ └── scaffold.sh
├── templates/
│ ├── index.html
│ ├── vite.config.ts
│ ├── scripts/
│ │ ├── extract-narrations.ts
│ │ ├── synthesize-audio.sh # provider-agnostic runner
│ │ └── tts-providers/ # 一个文件 = 一个 TTS 后端
│ │ ├── README.md # 三函数契约 + ElevenLabs / edge-tts / Azure / Google / say 的现成片段
│ │ ├── minimax.sh # 默认 provider(mmx-cli)
│ │ └── openai.sh # 内置:OpenAI TTS(curl + OPENAI_API_KEY)
│ └── src/
└── themes/ # 23 套主题,每套独立设计签名
├── midnight-press/
├── warm-keynote/
├── newsroom/
├── bauhaus-bold/
└── ... # 完整列表见 references/THEMES.md---
快速上手
把这个 Skill 复制到你的 Agent 会扫描的目录,然后让 Agent 把一篇文章或口播稿做成网页视频演示。
如果要手动脚手架:
bash skills/web-video-presentation/scripts/scaffold.sh ./presentation --theme=paper-press查看可用主题:
bash skills/web-video-presentation/scripts/scaffold.sh --list-themes生成的 presentation/ 是普通 Vite + React + TypeScript 项目。启动后用录屏工具录制 16:9 舞台即可。
---
主题画廊
Skill 内置 23 套主题,每套都有独立的设计 DNA —— 不是简单换色版。下面按底色分两组浏览,挑一套接近目标气质的,或者把任意一格当作派生新主题的起点。点击任意预览图可放大查看 1920×1080 原帧。
所有截图都是真实的 16:9 舞台,来自 `demo/web-video-presentation-demo` 现场画廊。
深色 · 8 套
电影感深色画布 —— 适合需要聚焦、戏剧张力、强对比的叙事。
<table> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/midnight-press.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/midnight-press.webp" alt="midnight-press 预览" /></a> <br /><strong><code>midnight-press</code> · 暗色印刷</strong> <br /><sub>电影感编辑暗底 · 暖暗底 + 火热橙</sub> <br /><sub><b>适合</b> · 开发者教程 · AI / 工具评测 · 技术 deep dive</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dark-botanical.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dark-botanical.webp" alt="dark-botanical 预览" /></a> <br /><strong><code>dark-botanical</code> · 暗夜植物</strong> <br /><sub>高级时尚刊物 · 暖陶 / 玫粉 / 鎏金叠层</sub> <br /><sub><b>适合</b> · 品牌故事 · 时尚 / 美妆 · 高端产品发布</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/chalk-garden.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/chalk-garden.webp" alt="chalk-garden 预览" /></a> <br /><strong><code>chalk-garden</code> · 粉笔花园</strong> <br /><sub>深石板黑板 · 手写 Patrick Hand + 粉笔黄</sub> <br /><sub><b>适合</b> · 科普讲解 · 教学课堂 · 面向初学者的亲切口吻</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/blueprint.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/blueprint.webp" alt="blueprint 预览" /></a> <br /><strong><code>blueprint</code> · 工程蓝图</strong> <br /><sub>制图工作台 · 深海军 + 制图青 + 60 px 网格</sub> <br /><sub><b>适合</b> · 技术架构 · 系统拆解 · API / SDK 介绍</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/terminal-green.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/terminal-green.webp" alt="terminal-green 预览" /></a> <br /><strong><code>terminal-green</code> · 终端绿</strong> <br /><sub>80 年代磷光 CRT · 纯等宽 + 扫描线</sub> <br /><sub><b>适合</b> · CLI 工具教程 · 黑客 / 安全话题 · 复古技术致敬</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/neon-cyber.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/neon-cyber.webp" alt="neon-cyber 预览" /></a> <br /><strong><code>neon-cyber</code> · 霓虹赛博</strong> <br /><sub>赛博朋克未来 · 电光青 + 玫红双霓虹</sub> <br /><sub><b>适合</b> · AI / 大模型评测 · web3 / 安全 · 未来主义与赛博朋克</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bold-signal.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bold-signal.webp" alt="bold-signal 预览" /></a> <br /><strong><code>bold-signal</code> · 焦点信号</strong> <br /><sub>Pitch Deck 主舞台 · 暗渐变 + 大橙焦点卡</sub> <br /><sub><b>适合</b> · pitch deck / 路演 · 产品发布 · 大字宣言 / brand keynote</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/creative-voltage.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/creative-voltage.webp" alt="creative-voltage 预览" /></a> <br /><strong><code>creative-voltage</code> · 电压创意</strong> <br /><sub>饱和电光蓝 + 霓虹黄 + halftone 网点</sub> <br /><sub><b>适合</b> · 设计周 / 创意分享 · 工作室作品集 · 字体 / 视觉文化</sub> </td> </tr> </table>
浅色 · 15 套
明亮编辑画布 —— 适合清晰、克制、带纸感温度的内容。
<table> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/paper-press.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/paper-press.webp" alt="paper-press 预览" /></a> <br /><strong><code>paper-press</code> · 亮色印刷</strong> <br /><sub>编辑纸张 · 暖奶油 + 火热橙</sub> <br /><sub><b>适合</b> · 杂志型内容 · 生活方式 · 日常工具评测</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/newsroom.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/newsroom.webp" alt="newsroom 预览" /></a> <br /><strong><code>newsroom</code> · 报社</strong> <br /><sub>NYT 大报 · 新闻纸奶油 + 旗红</sub> <br /><sub><b>适合</b> · 纪录片 / 报道 · 深度评测 · 时事 / 热点解读</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/monochrome-print.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/monochrome-print.webp" alt="monochrome-print 预览" /></a> <br /><strong><code>monochrome-print</code> · 黑白印刷</strong> <br /><sub>精炼克制 · Monocle / Wallpaper 气质</sub> <br /><sub><b>适合</b> · 深度阅读改编 · 学术 / 思想型内容 · 文化艺术评论</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/vintage-editorial.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/vintage-editorial.webp" alt="vintage-editorial 预览" /></a> <br /><strong><code>vintage-editorial</code> · 复古编辑</strong> <br /><sub>俏皮 Fraunces + 几何叠层(圆 / 线 / 点)</sub> <br /><sub><b>适合</b> · 个人见解 / 评论 · 文化随笔 · 设计 / 字体话题</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/sunset-zine.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/sunset-zine.webp" alt="sunset-zine 预览" /></a> <br /><strong><code>sunset-zine</code> · 日落 Zine</strong> <br /><sub>Risograph 拼贴 · 暖桃 + 玫红 + 虚线剪贴</sub> <br /><sub><b>适合</b> · 生活向 vlog · 创意分享 · 小红书 / 抖音风</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/pastel-dream.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/pastel-dream.webp" alt="pastel-dream 预览" /></a> <br /><strong><code>pastel-dream</code> · 柔光梦</strong> <br /><sub>柔粉 + 鼠尾草绿 + 右侧 pill 色条</sub> <br /><sub><b>适合</b> · 产品 onboarding · 友好教学 · 心理 / 健康 / 母婴</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/warm-keynote.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/warm-keynote.webp" alt="warm-keynote 预览" /></a> <br /><strong><code>warm-keynote</code> · 暖色 Keynote</strong> <br /><sub>现代 SaaS Keynote · glass slab + 青绿 + 暖色网格</sub> <br /><sub><b>适合</b> · SaaS keynote · B 端产品发布 · 团队对外汇报</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/electric-studio.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/electric-studio.webp" alt="electric-studio 预览" /></a> <br /><strong><code>electric-studio</code> · 电光企业</strong> <br /><sub>企业级清晰 · 净白 + 贴底电光蓝色条</sub> <br /><sub><b>适合</b> · B2B 产品演讲 · 投资人路演 · 企业财报 / 季度更新</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bauhaus-bold.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/bauhaus-bold.webp" alt="bauhaus-bold 预览" /></a> <br /><strong><code>bauhaus-bold</code> · 包豪斯</strong> <br /><sub>宣言式现代主义 · 0 圆角 + 4 px 厚边</sub> <br /><sub><b>适合</b> · 产品发布 · 观点宣言 · 品牌主张</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/swiss-ikb.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/swiss-ikb.webp" alt="swiss-ikb 预览" /></a> <br /><strong><code>swiss-ikb</code> · 瑞士克莱因蓝</strong> <br /><sub>极细 200 Helvetica + IKB + 1 px 发丝网格</sub> <br /><sub><b>适合</b> · AI / 科技产品发布 · 年度数据汇报 · 信息图</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dune.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/dune.webp" alt="dune 预览" /></a> <br /><strong><code>dune</code> · 沙丘</strong> <br /><sub>炭褐 + 沙底 · 近乎零 accent,建筑画廊感</sub> <br /><sub><b>适合</b> · 建筑 / 室内 / 空间 · 艺术展览 · 高端品牌画册</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/indigo-porcelain.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/indigo-porcelain.webp" alt="indigo-porcelain 预览" /></a> <br /><strong><code>indigo-porcelain</code> · 靛蓝瓷</strong> <br /><sub>靛蓝<em>本身即墨</em>(不是 accent)+ 瓷白</sub> <br /><sub><b>适合</b> · 学术 / 论文解读 · AI / 数据深度 · 严肃技术汇报</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/forest-ink.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/forest-ink.webp" alt="forest-ink 预览" /></a> <br /><strong><code>forest-ink</code> · 森林墨</strong> <br /><sub>森林绿<em>本身即墨</em> + 象牙 · 旧版国家地理</sub> <br /><sub><b>适合</b> · 自然 / 可持续 · 纪录 / 非虚构 · 慢生活</sub> </td> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/kraft-paper.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/kraft-paper.webp" alt="kraft-paper 预览" /></a> <br /><strong><code>kraft-paper</code> · 牛皮纸</strong> <br /><sub>深棕<em>本身即墨</em> + 牛皮米 + 紫铜 accent</sub> <br /><sub><b>适合</b> · 书评 / 文学随笔 · 历史 / 怀旧 · 手工艺 / 食物</sub> </td> </tr> <tr> <td align="center" width="50%"> <a href="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/split-canvas.webp"><img src="https://cdn.jsdelivr.net/gh/ConardLi/assets@main/imgs/web-video/split-canvas.webp" alt="split-canvas 预览" /></a> <br /><strong><code>split-canvas</code> · 双拼画布</strong> <br /><sub>50/50 双底色 · 蜜桃左 + 薰衣草右</sub> <br /><sub><b>适合</b> · 双主题对比 / 辩论 · 故事讲述 · 概念对照科普</sub> </td> <td align="center" width="50%" valign="middle"> <br /> <strong>+ 派生你自己的</strong> <br /><sub>完整 token 契约、每套设计签名、<br />以及怎么派生新主题(Swiss 黄 / 绿 / 橙变体等),<br />见 <a href="./references/THEMES.md">THEMES.md</a>。</sub> <br /><br /> </td> </tr> </table>
---
Reference Map
- PRINCIPLES.md:视频感网页演示的核心原则
- CHAPTER-CRAFT.md:章节实现规则与视觉 checklist
- OUTLINE-FORMAT.md:outline 必须遵循的结构
- SCRIPT-STYLE.md:文章转口播稿规则
- PATTERNS.md:可选视觉 primitive 配方
- AUDIO.md:可选口播音频合成流程(provider-agnostic)
- tts-providers/README.md:TTS provider 三函数契约 + 内置 2 个 (minimax / openai) + ElevenLabs / edge-tts / Azure / Google / macOS say 的现成代码片段
- RECORDING.md:录屏与后期注意事项
音频合成
把每个章节 narrations.ts 里的口播文字按 step 颗粒度合成 mp3, 落到 presentation/public/audio/<chapter-id>/<step-N>.mp3。运行时 Auto 模式会自动按 step 播放并自动推进——录屏可以一镜到底。
真相源:每个章节的 src/chapters/<NN>-<id>/narrations.ts 是 step数 + 口播文本的唯一来源。outline.md 不再参与音频合成,章节代码也不再手写 totalSteps。这一改根除了"网页 step 和音频文件数对不上"这个老问题。
合成器是 provider-agnostic 的:runner 本身不绑定任何 TTS 后端,每个 后端是 scripts/tts-providers/<name>.sh 一个文件。内置 2 个 provider:
| Provider | 默认 | 何时用 |
|---|---|---|
minimax | ✓ | 中文口播首选(用 mmx-cli,要 MiniMax API key) |
openai | —— | 多数 agent 已有 OPENAI_API_KEY;curl-based、响应快 |
换 / 加 provider 见 `scripts/tts-providers/README.md` (脚手架跑完后路径是 presentation/scripts/tts-providers/README.md)。 README 里还附了 5 套可粘贴的现成片段(ElevenLabs / edge-tts / macOS say / Azure / Google Cloud)和写自定义 provider 的三函数契约。
---
文件命名约定
presentation/public/audio/
├── coldopen/
│ ├── 1.mp3
│ ├── 2.mp3
│ └── ...
├── hook/
│ └── ...
└── ...- 章节子目录名 =
chapters.ts里的id - 文件名 =
<step-N>.mp3(1-indexed,对齐 narrations 数组的 index + 1) - 格式默认 mp3。如果你写的 provider 只能出 wav,在函数里加一步
ffmpeg
转 mp3(参见 tts-providers/README.md 的 say.sh 示例)
---
标准流程
1. 抽取 segments
cd presentation
npm run extract-narrations这会扫所有章节的 narrations.ts,按 chapters.ts 注册顺序生成 audio-segments.json:
[
{ "chapter": "coldopen", "step": 1, "text": "...", "audio": "coldopen/1.mp3" },
{ "chapter": "coldopen", "step": 2, "text": "...", "audio": "coldopen/2.mp3" },
...
]让用户先扫一眼这个 json,确认文本和切分都对,再开始烧 token 合成。
空字符串的 narration 会被自动跳过(不烧 TTS token)——运行时 Auto 模式
按字数估时撑过这种"无声过场"step。
2. 选 provider
ls scripts/tts-providers/ # 看本项目带了哪些2.A 用内置 minimax 合成
npm run synthesize-audio # 增量:跳过已存在的 mp3
npm run synthesize-audio -- --force # 全部重合成
npm run synthesize-audio -- --voice=<voice-id> # 指定音色启动时 runner 会先调 provider 的 tts_check:
- mmx 未安装 → 报
mmx CLI not found in PATH,并打印安装说明 - mmx 未登录 → 报
mmx is not authenticated,并提示登录命令
修完再跑。每条段打印进度:
[ 3/24] coldopen/3.mp3 ✓ 4s
[ 4/24] coldopen/4.mp3 skip (exists)合成串行(避免 rate limit),自动跳过已存在文件(断点续合,不烧 重复 token)。
2.B 用内置 openai 合成
export OPENAI_API_KEY=sk-... # 在 platform.openai.com 拿
PRESENTATION_TTS=openai npm run synthesize-audio
# 换音色 + HD 模型
OPENAI_TTS_MODEL=tts-1-hd PRESENTATION_TTS=openai \
npm run synthesize-audio -- --voice=nova可选 env:
| 变量 | 默认 | 作用 |
|---|---|---|
OPENAI_API_KEY | —— 必须 | API key |
OPENAI_BASE_URL | https://api.openai.com/v1 | 切代理 / Azure-OpenAI |
OPENAI_TTS_MODEL | tts-1 | tts-1 快 / tts-1-hd 高质量约 2× 价 |
--voice= / PRESENTATION_TTS_VOICE | alloy | 可选 alloy / echo / fable / onyx / nova / shimmer |
tts_check 会检查 curl / jq / OPENAI_API_KEY 三件套,缺哪个报哪个。
2.C 换 provider / 加自定义 provider
内置之外的常见后端在 scripts/tts-providers/README.md 里有 5 段 可粘贴代码片段(ElevenLabs / edge-tts / macOS say / Azure / Google Cloud)。
挑一个 → 复制 README 里的代码块 → 保存为 scripts/tts-providers/<name>.sh → 设好环境变量 → 切换 provider 跑:
PRESENTATION_TTS=elevenlabs npm run synthesize-audio
# 或
npm run synthesize-audio -- --provider=edge-tts如果用户的 TTS 完全自研,按三函数契约写一个 <name>.sh 即可:
| 函数 | 必需 | 作用 |
|---|---|---|
tts_synthesize <text> <out_path> [<voice>] | ✓ | 把一段文字写成 mp3 到指定路径 |
tts_check | 可选 | 启动时校验环境(CLI / key / auth),未就绪 return 非零 |
tts_install_help | 可选 | tts_check 失败时打印怎么修 |
抄 openai.sh(HTTP-based)或 minimax.sh(CLI-based)起手最快。 详细规范在 scripts/tts-providers/README.md。
2.D 退化路径
如果两个内置 provider 都没就绪(没装 mmx 也没有 OpenAI key)告诉用户:
我可以:
1. 用内置 openai provider(如果你已有 OpenAI key)
export OPENAI_API_KEY=sk-...
PRESENTATION_TTS=openai npm run synthesize-audio
2. 帮你装 MiniMax CLI(默认 provider,中文音色更稳)
npm install -g mmx-cli && mmx auth login --api-key sk-xxxxx
API key 在 https://platform.minimaxi.com 获取
3. 换其它 provider
scripts/tts-providers/README.md 里有 5 种现成代码片段:
• ElevenLabs (要 ELEVENLABS_API_KEY,英文音色最佳)
• edge-tts (免费 / 无 key / pip install edge-tts)
• macOS say (零依赖离线,质量一般,适合预览)
• Azure (要 AZURE_SPEECH_KEY)
• Google (要 gcloud auth)
复制一段保存成 tts-providers/<name>.sh,
再 PRESENTATION_TTS=<name> npm run synthesize-audio
4. 暂时跳过
稿子和 narrations 都在,你自己用任意 TTS 录制即可——文件
按 audio-segments.json 的 audio 字段命名就行。不要假装合成成功。
---
校验时长
合成完后跑:
for f in public/audio/*/*.mp3; do
d=$(ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 "$f")
echo "$f ${d}s"
done把每条的实际秒数汇总告诉用户。重点关注 ≥ 15s 的条目——口播太长意味 着该 step 的 narration 写得过密,或者 step 没拆够。让用户决定改稿子 重合还是回章节代码拆 step。
---
运行时如何使用合成的音频
合成完成后,不需要任何额外配置——脚手架的 App.tsx 已经接好:
| 模式 | 触发方式 | 行为 |
|---|---|---|
| Manual(默认) | 直接打开页面 | 不播音频,点击 / 方向键推进 |
| Audio(半自动) | URL ?audio=1 或按 M 键 | 进入 step 自动播音频,但你手动推进(点鼠标) |
| Auto(全自动) | URL ?auto=1 或按两次 M 键 | 进入 step 播音频 → 播完自动 next() → 进下个 step → ... |
Auto 模式首次需要按一次 Space 启动(绕过浏览器自动播放限制),之后 全自动跑。录屏时打开屏幕录制 → 按 Space → 整片自动跑完 → stop。
Auto 模式的推进规则就一句话:每段音频播完 + 200ms 缓冲 → 自动 next。
没有"等动画跑完"的兜底——如果你写的视觉动画比口播长,会被当场切。
解决办法:写更长口播 / 拆 step / 调动画速度(详见
`CHAPTER-CRAFT.md` 「代码层最小约束」)。
>
音频文件缺失(还没合成 / 404)或 narration 是空串 → 退化到字数估时
(max(1500ms, 字数 × 250ms)),保证预览也能整片跑通。---
故障排查
通用:
| 现象 | 原因 / 修法 |
|---|---|
chapter id "X" registered but no matching folder found | 章节文件夹应命名为 NN-<id>;id 必须等于 chapters.ts 里注册的 |
narrations.ts in X must export an array named "narrations" | 该章节的 narrations.ts 没 export 名为 narrations 的数组 |
TTS provider 'X' not found | scripts/tts-providers/X.sh 不存在;列出来看哪些可用,或抄 README 加一个 |
provider 'X' does not define tts_synthesize | 你的 <X>.sh 没定义必需的函数。看 README 的契约部分 |
| 中间断了几条没合成 | npm run synthesize-audio 重跑 —— 已存在文件会跳过 |
| 浏览器没播音频 | Auto / Audio 模式下首次需要用户手势——确认你按了 SPACE 启动 Auto,或者点过页面 |
| 音频 404 但 Auto 模式还能跑 | 找不到 mp3 时 useAudioPlayer 退化到字数估时(4 字/秒),保证预览不中断 |
minimax 专属:
| 现象 | 原因 / 修法 |
|---|---|
mmx: command not found | npm install -g mmx-cli;npm 全局 bin 不在 PATH 时 npm config get prefix 看一下 |
mmx is not authenticated | mmx auth login --api-key sk-xxxxx 重新登录 |
| 中文音色不自然 | mmx 默认音色未必最佳;查 mmx speech --help 看 --voice 可选项,传 --voice=<id> |
| 整段合成被截断 | 单段过长(mmx 默认上限约 5000 字符)。在 narrations.ts 里把这条拆成两条(也意味着该 step 应该拆成两个 step) |
openai 专属:
| 现象 | 原因 / 修法 |
|---|---|
OPENAI_API_KEY is not set | export OPENAI_API_KEY=sk-...,或者把它加到 shell rc / .env |
| 全部段 FAILED + key 是对的 | 多半 model / voice 名字错。--voice=alloy 试默认值;OPENAI_TTS_MODEL=tts-1 试默认模型;用 bash -x scripts/synthesize-audio.sh 看请求体 |
| 走代理 / 走 Azure-OpenAI | export OPENAI_BASE_URL=https://your-proxy/v1 |
| HD 太慢 | 改成 OPENAI_TTS_MODEL=tts-1(默认);HD 大约慢 2 倍 |
| 中文音色不像真人 | OpenAI 6 种音色都是英语偏向;中文角色用 minimax 更合适 |
换其它(自定义)provider 之后:
| 现象 | 原因 / 修法 |
|---|---|
<X>_API_KEY not set | 你的 provider 需要 API key,但 env 里没设。export <X>_API_KEY=... 或写到 .env 再 set -a; source .env; set +a |
| 合成的 mp3 浏览器播不了 | 检查 provider 是否真的出了 mp3(不是 wav / opus / aac)。file public/audio/*/*.mp3 看 magic header |
| 一切看起来都对,但全部 FAILED | bash -x scripts/synthesize-audio.sh 看每段实际调了什么 |
---
相关链接
- Provider 契约 + 现成片段:`scripts/tts-providers/README.md`
- mmx-cli 仓库:<https://github.com/MiniMax-AI/cli>
- mmx 官方文档:<https://platform.minimaxi.com/docs/token-plan/minimax-cli>
- mmx 参数 / 音色查询:
mmx speech --help
章节开发指引(每章开发必读)
---
这是视频,不是 PPT
正在做的是视频网页 —— 讲者点击 + 口播 + 录屏发出去给观众看。 判断每一步做对没有,标准非常朴素:
- 不像 PPT —— 观众感觉是在看视频,不是在看翻页幻灯(页面中不得包含页眉页脚,突出主视觉元素)
- 看起来舒服 —— 配色、字体、节奏都让人放松,不得出现大量的纯文字、不得出现字体太小的文字
- 有视觉冲击 —— 画面在演事情,不只是文字堆砌,不得一次性全部罗列所有元素,关键元素随进度逐步推进展现
---
必须用 CSS / SVG / Canvas / JS 大胆绘制视觉演示
这是底线。
>
每一章都至少要有 1~2 处"动起来的图 / 演示元素"。
整章只有纯文字 = 验收不过 = 回去重做。
视频感最强的来源 —— 用户看见了被讲解的东西在屏幕上演给他看:
- 数字在递增 / 横条在生长 / 排名在交换
- 流程节点依次点亮 / 连线自绘
- 对比被一刀切开 / 聚光灯扫过 / 形状在变形
- 粒子聚拢成形 / 噪声背景流动 / 字符雨下落
- 模拟终端交互
- 模拟 AI 对话窗口
- 模拟文件目录树
怎么组合发挥都行 —— 但每章必须用,不允许整章纯文字。
---
逐步揭示,禁止一次全展示
整页内容由全局 `step` 计数器驱动 —— 点击空白处或按 → 键推进 一步。设计每一步时心里要默念:这一步演什么,下一步演什么。
最重要的一条:
当口播在说"第一是 X、第二是 Y、第三是 Z"这种清单 / 列表时,
严禁一个 step 把 X / Y / Z 全部 stagger 上来。
正确做法:
- 一项 = 一个 step
- X 只在它自己的 step 里独自亮起
- 讲到 Y 时,X 灰化保留作上下文 + Y 亮起
- 讲到 Z 时,X / Y 都灰化 + Z 亮起
判断标准:讲者会一个一个念出来吗?会 → 必须逐个揭示。
---
内容取舍:抓重点,不要原文搬运
视频是音 + 画:
- 口播负责把信息线性讲清楚
- 画面负责把节拍重点放大、节奏感拉出来
每个 step 屏幕上只挂这个节拍最值得放大的 1~3 个东西 —— 一个 hero 标语 / 一个数字 / 一组对比 + 必要的视觉演示。
不要试图把原文每个字都搬上去。那是论文阅读,不是视频。
---
双源:节奏跟口播稿,细节回原文章
节奏 / 顺序 / 节拍切分 跟 `script.md` 口播稿 —— 关键顺序不能乱。
画面细节 / 数据 / 引用 / 案例 回 `article.md` 原文章抽。
outline.md 已经在每章首段抽了「信息池」做参考。但实现章节时 也必须回去翻 `article.md` 本章对应段落 —— 那里有比口播稿多得多的 细节(具体数字、引用原话、案例维度、出处时间)。把这些挂到画面上, 让画面信息密度 > 口播信息密度。
如果你只用了口播稿的内容做章节 —— 屏幕等于把口播打字打了一遍
—— 那就是 PPT,不是视频。
>
章节实现一定要回原始文章抽细节,不要嫌麻烦。
---
字体 / 配色 / 动画 / 留白 —— 视频演示基本审美
视频观众离屏幕远、注意力浮动,所以:
- 字号要大 —— hero 文字至少 80px 起,远观也能看清
- 留白要多 —— 舞台四边都要让出大留白,画面不要塞满
- 配色要舒服 —— 颜色和字体家族必须用主题 token(保证换主题不破);
字号 / 间距 / 时长这些章节按内容自由发挥(详见下方「代码层最小约束」)
- 动画要舒服 + 炫酷 —— 出现得干净利落,停下来不抢戏;炫酷靠
设计巧思(内容驱动的演示动画),不靠速度暴力或密集闪烁
---
避免 AI 味
AI 生成的网页有几种共有的"视觉指纹",全部不要:
- 紫粉 / 蓝紫对角渐变背景
- 圆角卡片 + 彩色左边框装饰
- 渐变按钮 + 大圆角药丸
- emoji 当图标用
- 假数据 / 假 logo / 假"X 万用户"
- 整章 N 步用同一种入场动画(全场 fade / 全场 blur)
- 每步都挂 ken burns / 光晕呼吸 / 持续闪烁
- 每屏右下角都挂 mono 角标 / 序号
缺的东西承认缺 —— 用 placeholder 占位卡(一张写着"image · 16:9 描述"的卡片,按真实比例留位)。不要用 emoji 凑、不要找无关图凑、 不要编数字。没有就承认没有,比 fake 强一百倍。
---
框架已经搭好的部分(理解就好,不需重写)
- 16:9 固定舞台:内容设计在 1920×1080 上,外层 transform scale
缩到任何视口,外围 letterbox 留黑 —— 没有响应式断点
- 舞台居中 + 大留白:上下左右四边都让出至少 80px 的安全区
- 隐形进度条:屏幕底部默认完全透明,鼠标悬到底部边缘才出现,
支持点击跳转章节(录屏时摄像头看不到任何 chrome 控件)
- 全局 step 驱动:点击舞台空白处 / 键盘 ←/→ 推进;章节是
step
的纯函数,没有定时器、没有命令式状态
---
代码层最小约束
不能踩的红线,其它怎么写都行:
必须用 token(换主题不破的底线)
- 颜色:
--shell/--surface/--surface-2/--surface-3/
--text / --text-2 / --text-mute / --text-faint / --rule / --accent / --accent-soft / --accent-glow —— 禁硬编码 hex / rgb / 颜色名
- 字体家族:
--font-display-cn/--font-display-en/--font-body
/ --font-mono —— 禁硬编码字体名
- 主题性格签名通过 primitive class 自动接入,**不要在章节 CSS 里
重定义它们**:
.hero-num(hero 数字风格 —— 主题决定衬线 / 等宽 / 粗黑).rule(分割线 —— 主题决定 1px 实线 / 4px 实线 / 2px 虚线).card(卡片 —— 主题决定圆角 + 阴影性格).stage-frame(舞台底色 / 圆角 / 阴影 / 装饰图案 / vignette
全自动,章节什么都不用做)
可硬编码 / 可 token,按内容自由(解锁章节自由设计)
- 字号:想要 80px 就写 80px,想用
var(--t-h1)也行 - 间距 / padding / margin:按画面节奏写具体值
- 动画时长 / 缓动 / keyframe:按动画意图写具体值
(节奏气质参考 theme.json 的 mood —— 慢主题别写 200ms 的快动画)
- 边框宽度 / 非性格圆角 / 字距:随手写
- gap / grid 布局尺寸:按画面构图写
其它工程红线
- 不用
setTimeout/setInterval驱动动画 —— 用 CSS keyframes - 章节内的可交互元素(按钮 / 自定义控件)加
data-no-advance,
否则点了会被舞台误推进 step
- 章节代码物理隔离:每章独立文件夹、独立 CSS 类前缀,不跨章 import
- 每章必须有 `narrations.ts`(与
<Chapter>.tsx同目录): - 数组长度 = 章节代码里
if (step === N)出现的最大 N + 1 - 每个元素 = 一个 string,该 step 要播的口播文本(来自
script.md
对应段,语义一致——可微调标点 / 断句以适配 TTS,但不能漏关键短语)
- 完全无音频的过场 step 用空串
"",Auto 模式会按字数估时撑过 - 这是音频合成 + Auto 模式自动推进的唯一真相源,写错或漏写
会让录屏对不上嘴
- 动画时长必须 ≤ 该 step 的口播时长——Auto 模式严格按音频结束推进,
没有"等动画跑完"的兜底。动画太长 → 三选一:写更长口播 / 拆 step / 调动画速度。详细机制见 `AUDIO.md`
---
完工自检(写完每章强制执行,不可跳过)
⚠️ 硬性流程:章节实现完成后必须走完下面的自检 → 修复 → 汇报
三步。禁止"实现完成 → 直接汇报给用户"。
>
执行方式(按能力降级):
>
1. 优先 Agent Teams:开一个独立的 reviewer agent,传入本章代码路径
+ 本文件 Part「完工自检」清单,让它逐项核查 + 出结论(哪几条
pass / 哪几条 fail + 证据)。
2. 其次 subAgent:当前 agent 没有 Teams 能力但能开 subagent,用 subagent
走同样的流程。
3. 都没有:当前 agent 自己严格逐项核查,不允许目测一遍就放行。
>
拿到自检结论后:先按 fail 项改完代码,然后再向用户汇报"做完
了 + 自检结论 + 改了什么"。直接拿原始结论汇报但不修复 = 违规。
写完一章 + 在浏览器点完一遍后逐项过:
- [ ] 每章至少 1~2 处 CSS / SVG / Canvas / JS 视觉演示 —— 没有 = 回去补
- [ ] 不同 step 的主导动作不一样 —— 全章一种动画 = 回去重做
- [ ] 字号大、留白舒服、配色舒服
- [ ] 清单 / 列表逐个揭示,1 项 = 1 step
- [ ] 画面信息比口播稿多(回了原文章抽细节挂上来)
- [ ] 没有紫粉渐变 / 圆角彩色边框 / emoji / 假数据 / 假 logo
- [ ] 缺的素材用 placeholder,不是 fake
- [ ] 颜色和字体家族全部走 token(无硬编码 hex / 字体名);hero 数字
/ 卡片 / 分割线 / 舞台用 primitive class 接入主题性格 —— 这两条不 达标 = 换主题就破
- [ ] 章节交付时主动告诉用户:"本章还缺这些素材"
- [ ] 禁止出现小号字体,大量纯文字(出现后必须回去改)
- [ ] 禁止出现任何形式的页眉页脚,仅展示关键内容(出现后必须回去改)
- [ ] `npx tsc --noEmit` 通过 —— 不通过禁止汇报"做完了"
- [ ] 章节代码物理隔离:独立 CSS 类前缀(
.cd-/.mg-/ ...),
未跨章 import,未修改 chapters.ts 之外的共享文件
- [ ] `narrations.ts` 存在且
narrations.length=== 章节代码里
if (step === N) 用到的最大 N + 1(不一致 = Auto 模式录屏会错位)
- [ ] 每条 narration 文本与 `script.md` 对应段落语义一致(关键短语 /
数字 / 引用全部保留,可为 TTS 微调标点断句)—— 录屏画外音应当能被 观众听成同一段稿子
- [ ] 每个 step 的视觉动画时长 ≤ 口播时长(口播
字数 ÷ 4≈ 秒数)——
超出会被 Auto 模式当场切断,动画演到一半就跳下一步
任一未过 → 回去改。不要"先放着以后修"。
Outline 节选 · 科技测评类 case
节选:前 2 章(10 step),用来展示 outline 在科技测评题材里的
形状。完整版 7 章 36 步在调用此 Skill 的具体项目里,不进 spec。
主题:midnight-press(电影感慢镜、blur clear、暖橙 accent、scanline;克制有重量。禁砸下 shake / 弹簧 / emoji)
>
总时长:约 6 分 30 秒
---
1. coldopen — 登顶悬念(5 steps · ~30s)
- step 1 (~5s) — 暗场远景粒子云 + 钩子字幕"我刷到一张图,愣了三秒"
· 动画:屏幕从纯黑慢速 fade 到暗暖底(1.5s ease-out)→ 远景光尘粒子云慢漂浮入(1.0s 错峰)→ 字幕 mono 打字机逐字打出(每字 100ms);持续微动:粒子云永不停 brownian 漂移 + 暖橙暗角光晕 6s 周期慢呼吸 + ken burns 缓推 · 手段:CSS background 慢 fade + Canvas 粒子云慢漂 + JS typewriter + filter: drop-shadow 暖橙呼吸 + transform: scale 永动 ken burns
- step 2 (~7s) — 排行榜慢镜景深聚焦 + 主分数 hero 数字 blur clear 浮出
· 动画:截图从 blur(12px) + scale(1.05) 慢速景深聚焦(1.5s ease-out)→ 主分数从 blur(20px) 慢慢锐化(1.2s 错峰 400ms)→ 王冠 SVG 沿数字外圈慢速 mask reveal(1.5s);持续微动:主分数暖橙光晕 5s 呼吸 + ken burns 缓推 · 手段:filter: blur 反向 + transform scale 慢推 + clip-path 沿 path mask reveal + filter: drop-shadow 呼吸 · article 补:主分数(来自 article §1,具体数字)+ 测评窗口("X 月 N 日 ~ Y 日")+ 投票数(mono cue 角标)—— 口播只说"换榜首",画面把"领先多少 / 多少票投出来的"全挂上
- step 3 (~6s) — 第 2 名对比横条 + "+差距分"慢浮锐化
· 动画:第一条从左向右慢速 mask reveal 拉到 100%(1.2s ease-out)→ 第二条同向 mask reveal 但只到 ~70%(错峰 600ms)→ 中间空缺区差距分从 blur(15px) 慢慢锐化进场(错峰);持续微动:差距区暖橙光晕慢呼吸 + accent 横线 8s 缓延展永动 + scanline 极淡 overlay 慢移 · 手段:clip-path inset 慢 reveal + filter: blur 反向 + linear-gradient 暖光晕 + linear-gradient scanline 永动 · article 补:第 2 名具体名字(article §1)+ 差距分(具体数字 vs 模糊"低很多")+ 趋势注释("过去 N 周首次反超")
- step 4 (~6s) — 官方原话 pull-quote 慢镜入场(电影感引文)
· 动画:左右两枚巨大引号 SVG 从 opacity 0 + blur(15px) 慢速锐化进场(1.0s 错峰 200ms,无砸下)→ 引文文字 mono 打字机逐字打出(每字 80ms)→ 落款慢速 blur clear 浮出(0.8s);持续微动:引号暖橙慢光晕呼吸 + 镜头 ken burns 缓推 · 手段:filter: blur 反向锐化 + JS typewriter + transform translateY 慢推 + filter: drop-shadow 呼吸 · article 补:原话直引(来自 article §1,1~2 句)+ 落款来源("— 出处.AI")—— 引文是 article 里口播完全省略的"权威背书"
- step 5 (~5s) — 主持人介绍 + 4 件事预告速览
· 动画:第一行自我介绍 blur clear 慢入场(1.2s ease-out)→ 4 张占位卡分别从 blur(15px) 慢速景深聚焦 stagger 出现(每张 250ms 错峰,每张 1.0s 慢镜),卡内 mono 数字 01/02/03/04 + 关键词;持续微动:每张卡暖橙边线慢光晕呼吸(错峰 400ms)+ 远景粒子永漂 · 手段:filter: blur 反向 + opacity 慢 fade + transform scale 慢推 + filter: drop-shadow 多 instance 错峰呼吸 · article 补:4 件事的关键词(来自 article 章节标题,简化)
口播节选:
我刷到一张图,愣了三秒……今天讲清楚四件事。
---
2. why-strong — 强在哪(5 steps · ~80s)
- step 1 (~6s) — hero"强在哪 · 四个方向" + 4 个 ghost 占位卡
· 动画:hero 字符整体从 blur(20px) + opacity 0 慢速景深聚焦(1.5s ease-out)→ 下方暖橙长横线从中心向两侧慢延展(0.8s)→ 4 张 ghost 卡片同步从 blur 慢镜出现(保持 opacity 0.3 占位状态);持续微动:暖橙下划线 8s 周期慢光晕脉冲 + ghost 卡片暖暗边线慢闪 · 手段:filter: blur 反向 + transform scaleX 慢延展 + opacity 阶梯填充 + filter: drop-shadow 永动呼吸 · article 补:4 个方向各自的关键词(mono cue 标签,"01 X / 02 Y / 03 Z / 04 W")
- step 2 (~16s) — 第 1/4 项填实 + 大图慢镜 takeover
· 动画:卡片 1 从 ghost 状态慢速 mask 填实(0.8s 暖暗底色 + 边线慢光晕亮起)→ 中央 hero 大图从 blur(15px) 慢速景深聚焦(1.5s ease-out)→ mono cue 标签从暗角慢速 blur clear 入场(0.8s)→ 副标打字机逐字打出(每字 80ms);持续微动:暖橙 accent 高亮条永动呼吸 + 大图 ken burns 缓推(0.5% scale 12s 周期)+ scanline 慢移 · 手段:filter: blur 反向 + clip-path 慢 reveal + JS typewriter + transform scale 永动 ken burns + linear-gradient scanline 永动 · article 补:本项的具体表现(article §2 抽 1~2 个数据点 / 案例标签)—— 口播只说"它强在 X",画面挂"具体强到 N% / 跑赢 M / 测评分数 K"
- step 3 (~16s) — 第 2/4 项填实 + 列表/演示
· 动画:卡片 2 慢速 mask 填实(0.8s)→ mono cue 标签 blur clear 慢入场(0.8s)→ 4 行具体细则 typewriter 逐行打出(每行 0.8s 错峰 350ms)→ 每行末尾 mono 光标闪烁后追加暖橙对勾 SVG path stroke 慢绘制;持续微动:mono 光标永闪烁(800ms blink)+ scanline 慢移 · 手段:JS typewriter + opacity blink 光标 + SVG path stroke-dashoffset 慢绘 + linear-gradient scanline overlay 永动 · article 补:4 行细则的具体内容(来自 article §2 第 N 段子列表)—— 口播只说"指令遵循好",画面把 article 列出来的 4 个具体维度"主体放哪 / 背景怎么搭 / ..."逐行打出来
- step 4 (~16s) — 第 3/4 项填实 + before/after 慢镜对照 + 永动 cross-fade
- step 5 (~16s) — 第 4/4 项填实 + 多参数预览 + redacted 注释
口播节选:
实测下来强在四个方向 ……
---
观察:每个 step 的画面都做到"口播说一件事,画面挂多件事"。比如
step 2 口播只是"第一项很强",画面同时呈现:本项关键词 / 大图实例 /
具体数据点 / 副标补充 —— 这是双源原则的具象落地。
Case: 科技测评类(tech review)
一篇 AI / 工具 / 产品实测对比类文章 → 7 章 36 步、6 分 30 秒视频 的真实案例。
## ⚠️ 这是结构示意 / 历史案例,不是抄袭模板
>
这个目录的角色是让 agent 看:"**测评类视频章节怎么切、信息池怎么
抽、章长怎么定"。它包含的具体动画描述(如"慢速 blur clear
1.5s ease-out / 打字机每字 80~100ms")属于历史版本** —— 新版
outline 已经不写动画 / 不写时长(见 `../../OUTLINE-FORMAT.md`)。
新写 outline 时只写"屏幕内容 + 关系名前缀 + 章节级信息池",动画
选型留给章节实现阶段按 `../../CHAPTER-CRAFT.md`
Part 0 五问决定。
>
看这个 case 学的应该是:
1. 测评类怎么切 7 章(钩子 → 优点 → 场景 → 进阶 → 收束)
2. 章长怎么定(每章 4~6 step 防疲劳)
3. 双源原则怎么落地(hero 来自 script / 数据角标来自 article)
>
不应该学:动画选型、CSS 实现、时长数值(这些已下放到 chapter
阶段)。
适用场景
- AI 模型 / 产品 / 工具的实测体验文
- 多家产品对比(A vs B vs C)
- 跑分 / benchmark / 用户投票数据驱动的内容
- "强在哪 / 怎么用 / 怎么用得好"型结构
关键决策
| 维度 | 这个案例的选择 | 通用启发 |
|---|---|---|
| 主题 | midnight-press(电影感慢镜、blur clear、暖橙 accent、scanline) | 科技测评类适合"克制、有重量"的暗色调;避开俏皮 / 糖果色 |
| 章节切分 | 7 章:开场悬念 / 强在哪 / 哪能用 / 怎么用好 / Skill 介绍 / Skill 模式 / 收尾 | 测评类的标准结构:钩子 → 优点 → 场景 → 进阶 → 收束 |
| 章长 | 每章 4~6 step | 测评类信息密度高,每章不超过 6 step 防止观众疲劳 |
| 双源应用 | hero 标语来自 script、画面密度(具体分数 / 投票数 / 时间戳)来自 article | 测评类 article 数据极多 —— 用 mono cue / 角标 / 数据浮层挂出来 |
| 动画风格 | 慢速 blur clear / 打字机 / ken burns 缓推 | midnight-press 暗色印刷气质,章节实现时按主题氛围自由发挥 |
文件
- `outline-snippet.md` —— 前 2 章完整节选(5 + 5 step),
展示双源原则在 outline 里怎么落地
完整 7 章 outline 在调用此 Skill 的具体项目里(gpt-image2-video/outline.md),不放进 Skill 仓库 —— 避免 Skill spec 被某一个项目内容污染。
不在这个 case 出现的情形
测评类通常不需要:
- 慢节奏长镜头(电影感片头 / 旅行 vlog 才需要)
- 手写温暖感(教育 / 亲子 / 食谱才需要)
- 大量插画(设计稿 / 工艺品类才需要)
→ 选别的 case anchor 或自由发挥。
/* ─────────────────────────────────────────────────────────────────
* hook-chapter · 完整章节示例样式
* 默认绑 newsroom 主题。所有视觉属性走语义 token,零硬编码。
* ───────────────────────────────────────────────────────────────── */
.hk-scene {
color: var(--text);
display: flex;
flex-direction: column;
justify-content: center;
}
/* ── kicker ── */
.hk-kicker {
display: flex;
align-items: center;
gap: var(--space-3);
margin-bottom: var(--space-6);
font-family: var(--font-mono);
font-size: var(--t-cue);
color: var(--accent);
letter-spacing: 0.12em;
text-transform: uppercase;
}
.hk-kicker-line {
width: 64px;
height: 2px;
background: var(--accent);
}
/* ── step 1 三 ghost ── */
.hk-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-5);
align-items: center;
}
.hk-ghost {
aspect-ratio: 16 / 9;
border: var(--rule-w) dashed var(--rule);
border-radius: var(--r-card);
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
padding: var(--space-4);
background: var(--surface);
}
.hk-ghost-num {
font-family: var(--font-mono);
font-size: var(--t-h2);
color: var(--text-mute);
letter-spacing: 0.08em;
}
.hk-ghost-label {
font-family: var(--font-mono);
font-size: var(--t-cue);
color: var(--text-faint);
text-transform: uppercase;
letter-spacing: 0.2em;
align-self: end;
}
/* ── step 2-4 单图独占 ── */
.hk-solo-frame {
width: 78%;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.hk-solo-img-wrap {
position: relative;
aspect-ratio: 16 / 9;
border-radius: var(--r-card);
overflow: hidden;
box-shadow: var(--shadow-card);
background: var(--surface-2);
}
.hk-solo-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.hk-stamp {
position: absolute;
top: var(--space-4);
right: var(--space-4);
padding: var(--space-2) var(--space-3);
border: 3px solid var(--accent);
color: var(--accent);
font-family: var(--font-display-en);
font-size: var(--t-h3);
font-weight: 900;
letter-spacing: 0.1em;
transform: rotate(-8deg);
background: color-mix(in oklch, var(--surface) 60%, transparent);
animation: hk-stamp-drop var(--dur-base) var(--ease-quart) backwards;
animation-delay: 600ms;
}
@keyframes hk-stamp-drop {
0% { transform: rotate(-8deg) scale(2.4); opacity: 0; }
60% { transform: rotate(-8deg) scale(0.92); opacity: 1; }
100% { transform: rotate(-8deg) scale(1); }
}
.hk-solo-meta {
display: flex;
justify-content: space-between;
align-items: baseline;
font-family: var(--font-mono);
font-size: var(--t-cue);
color: var(--text-2);
letter-spacing: 0.08em;
text-transform: uppercase;
}
.hk-solo-label { color: var(--accent); }
.hk-solo-caption {
font-family: var(--font-display-cn);
font-size: var(--t-body);
text-transform: none;
letter-spacing: 0;
color: var(--text);
}
/* ── step 5 takeover ── */
.hk-takeover {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-6);
justify-content: center;
}
.hk-mini-row {
display: flex;
gap: var(--space-3);
}
.hk-mini {
width: 140px;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: calc(var(--r-card) * 0.5);
box-shadow: var(--shadow-card);
animation: hk-mini-shrink var(--dur-base) var(--ease-quart) backwards;
}
@keyframes hk-mini-shrink {
from { transform: scale(2.4); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.hk-accent-bar {
width: 60%;
height: 4px;
background: var(--accent);
animation: hk-bar-grow 700ms var(--ease-quart) 250ms backwards;
}
@keyframes hk-bar-grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
.hk-hero {
margin: 0;
font-family: var(--font-display-en);
font-size: var(--t-display-1);
letter-spacing: -0.025em;
color: var(--text);
line-height: 0.95;
}
/* ── step 6 close + brush ── */
.hk-close {
display: grid;
place-items: center;
}
.hk-quote-wrap {
position: relative;
display: inline-block;
}
.hk-quote {
margin: 0;
font-family: var(--font-display-cn);
font-size: var(--t-display-2);
color: var(--text);
}
.hk-brush {
position: absolute;
left: -4%;
right: -4%;
top: 50%;
height: 0.18em;
background: var(--accent);
transform-origin: left center;
transform: scaleX(0) translateY(-50%);
animation: hk-brush-strike 700ms var(--ease-expo) 500ms forwards;
}
@keyframes hk-brush-strike {
to { transform: scaleX(1) translateY(-50%); }
}
// ⚠️ 这是 anchor 参考代码,不会被任何项目编译。
// 抄到真实项目时(presentation/src/chapters/NN-hook/),
// 把下面两个 import 改成:
// import { MaskReveal } from "../../components/MaskReveal";
// import type { ChapterStepProps } from "../../registry/types";
import { MaskReveal } from "../../../templates/src/components/MaskReveal";
import type { ChapterStepProps } from "../../../templates/src/registry/types";
import "./chapter.css";
/**
* hook-chapter · 完整章节示例
* ─────────────────────────────────────────
* 默认绑 newsroom 主题(serif + 报头红 + 印刷盖章 motion)。
*
* 关键手段:
* - 真素材:<img src="/hook/{name}.png" /> 而不是 placeholder
* - 字号狠对比:hero 用 --t-display-1(≥ 144px)+ 微微负字距
* - 主导动作:mask reveal + 印章砸下(贴 newsroom 印刷气质)
* - takeover:三张图缩入 + 巨字爆出 + accent 红条贯穿
* - 收束:brush 划掉旧概念
*
* 切其它主题时按那个主题的气质自由换"印章砸下 / brush"等效动作,
* 结构和字号节奏保持。
*/
export default function HookChapter({ step }: ChapterStepProps) {
// step 1 — 三张 ghost(精修:加 kicker 引子 + accent 红条)
if (step === 0) {
return (
<div className="hk-scene scene-pad">
<div className="hk-kicker">
<span className="hk-kicker-line" />
<span className="hk-kicker-text">这几天</span>
</div>
<div className="hk-grid" key={step}>
{["01", "02", "03"].map((i, idx) => (
<MaskReveal show key={i} delay={idx * 200} duration={900}>
<div className="hk-ghost">
<span className="hk-ghost-num">{i}</span>
<span className="hk-ghost-label">image</span>
</div>
</MaskReveal>
))}
</div>
</div>
);
}
// step 2-4 — 每张图独占(真素材 + 角章 + 旁白)
// ⚠️ 这是结构示例。具体反例 caption / src 应该来自 outline.md 本章
// article 补字段(双源原则)—— 别照抄下面这些占位字符串。
const reveals: Array<{ src: string; label: string; caption: string }> = [
{
src: "/hook/<asset-1>.png",
label: "01 / 03",
caption: "<反例 1 caption,来自 article §X>",
},
{
src: "/hook/<asset-2>.png",
label: "02 / 03",
caption: "<反例 2 caption>",
},
{
src: "/hook/<asset-3>.png",
label: "03 / 03",
caption: "<反例 3 caption>",
},
];
if (step >= 1 && step <= 3) {
const r = reveals[step - 1];
return (
<div className="hk-scene scene-pad" key={step}>
<div className="hk-solo-frame">
<MaskReveal show duration={1100}>
<div className="hk-solo-img-wrap">
<img className="hk-solo-img" src={r.src} alt={r.caption} />
<div className="hk-stamp">FAKE?</div>
</div>
</MaskReveal>
<MaskReveal show delay={400} duration={900}>
<div className="hk-solo-meta">
<span className="hk-solo-label">{r.label}</span>
<span className="hk-solo-caption">{r.caption}</span>
</div>
</MaskReveal>
</div>
</div>
);
}
// step 5 — takeover:三张缩入 + 巨字爆出 + accent 红条
if (step === 4) {
return (
<div className="hk-scene scene-pad hk-takeover" key={step}>
<div className="hk-mini-row">
{reveals.map((r, idx) => (
<img
key={r.src}
className="hk-mini"
src={r.src}
alt={r.caption}
style={{ animationDelay: `${idx * 80}ms` }}
/>
))}
</div>
<span className="hk-accent-bar" />
<h1 className="hk-hero">
<MaskReveal show duration={1100}>
{/* hero 文案来自 outline 本章 step 5;这里只是占位 */}
<主题大字 takeover>
</MaskReveal>
</h1>
</div>
);
}
// step 6 — 钩子收束:brush 划掉
return (
<div className="hk-scene scene-pad hk-close" key={step}>
<div className="hk-quote-wrap">
<h2 className="hk-quote"><下一句钩子></h2>
<span className="hk-brush" aria-hidden />
</div>
</div>
);
}
Anchor: hook-chapter(钩子型开场)
⚠️ 这是结构示意,不是抄袭模板。先走 `../../CHAPTER-CRAFT.md`
Part 0 五问。本 anchor 给的是"钩子型开场的结构骨架"——你要保留它的
step 切分逻辑、字号关系、布局原则,**按本项目的主题 + 内容换动作
选型**。倒过来照抄 = `../../CHAPTER-CRAFT.md`
Part 5 第 8 条「整章只用一种入场动画」同质化反模式。
定位
视频开头最常用的章节类型:抛 N 张可疑图 / 反例 / 截图 → 引出主题 → 切大字 hero takeover。
适用场景
- 悬念型开头:先甩 3~4 张让人怀疑 / 困惑的图,再揭示原因
- "今天聊聊 X 的几个翻车现场":先看翻车,再切主题
- 产品发布的"问题感"开场:先看痛点截图,再揭示新功能
假设的 outline.md 章节段(抽象)
## 2. hook — <章节标题>(6 steps)
- **step 1** (~4s) — N 张可疑图片占位(虚线 ghost 卡片)
- **step 2** (~5s) — 第 1 张露出:<反例 1 描述>(独占视觉)
- **step 3** (~5s) — 第 2 张露出:<反例 2 描述>(独占视觉)
- **step 4** (~5s) — 第 3 张露出:<反例 3 描述>(独占视觉)
- **step 5** (~4s) — 三张图同时缩入侧栏,中间出 <主题大字> takeover
- **step 6** (~3s) — 切到下一句钩子(被 brush 划掉)关键节奏决策
| step | 节奏意图 | 视觉 |
|---|---|---|
| 1 | 抛悬念 —— N 张未知 | 虚线 ghost 卡片,1/3 屏一张 |
| 2-N | 每张图独占视觉 —— 重点不是"凑数",是让观众盯着每张图想"这是真的吗" | 大图占据 ~70% 屏幕,旁边小字标注图源 |
| N+1 | takeover —— 揭示主题 | 三张缩成左侧迷你卡,中间巨字 |
| 末 | 钩子收束 | brush 划掉旧概念,引下一章 |
为什么 2-N 不能 stagger 同时上
口播会逐个念出来 —— 必须 1 项 = 1 step(CHAPTER-CRAFT.md Part 0 原则 8)。 同时 stagger 上 = 观众扫一眼看完,讲者还在念第一张 = PPT 直觉。
文件结构
hook-chapter/
├── README.md ← 本文件
├── chapter.tsx ← 完整章节示例 —— 默认绑 newsroom 主题
└── chapter.css关键手段(地板线)
| 维度 | 这个 anchor 怎么实现 |
|---|---|
| 素材 | <img src="/hook/<asset>.png" /> 真截图 |
| 字号 | hero = 144px serif (var(--t-display-1)) |
| 主导动作 | brush-stroke + 印章砸下(newsroom 气质) |
| 伴随动作 | accent 红条 scaleX + 副标 stagger 200ms |
| 持续微动 | accent 红条光晕 infinite 呼吸;图片 ken burns 缓推 |
| 卡片样式 | drop-shadow + 微旋转 1deg |
| takeover | 三张图缩入 + hero 巨字爆出 + accent 红条贯穿 |
新写章节时:抄结构和字号关系,按本章内容 + 本主题气质自由
设计动画形式。持续微动按需挂,不强求 —— 详见
`../../CHAPTER-CRAFT.md`「避免 AI 味」一节
关于「每步都挂 ken burns / 持续闪烁」的反模式。
切到其它主题时
bauhaus-bold→ brush 划掉换 hard-cut 大色块;hero 字体换 Archivo Blackterminal-green→ 三张图换"FILE_001/002/003"占位框;hero 用打字机chalk-garden→ 粉笔感虚线 + 慢速 wiggle 入场midnight-press→ blur clear 慢镜入场 + ken burns + scanline;
takeover 改"主标 blur 锐化 + 暖橙光晕呼吸"
结构(N+2 步、独占节奏、takeover、收束)保持不变。
想看具象题材应用
- 科技测评 / 实测对比类视频用这个 anchor 开场长什么样 →
`../case-tech-review/`
/* ─────────────────────────────────────────────────────────────────
* list-reveal · 完整章节示例样式
* 默认绑 newsroom 主题。零硬编码视觉属性。
* ───────────────────────────────────────────────────────────────── */
.lr-scene {
color: var(--text);
display: flex;
flex-direction: column;
gap: var(--space-6);
}
/* ── masthead ── */
.lr-masthead {
display: flex;
align-items: center;
gap: var(--space-3);
}
.lr-rule {
flex: 1;
height: 1px;
background: var(--rule);
}
.lr-kicker {
font-family: var(--font-mono);
font-size: var(--t-cue);
letter-spacing: 0.18em;
color: var(--accent);
text-transform: uppercase;
white-space: nowrap;
}
/* ── intro step ── */
.lr-intro {
justify-content: center;
align-items: stretch;
gap: var(--space-5);
}
.lr-intro-h {
margin: 0;
font-family: var(--font-display-cn);
font-size: var(--t-display-2);
text-align: center;
letter-spacing: -0.01em;
}
.lr-em { color: var(--accent); }
.lr-intro-sub {
font-family: var(--font-body);
font-size: var(--t-h3);
color: var(--text-2);
text-align: center;
margin-bottom: var(--space-5);
}
/* ── grid (3 slots, fixed layout) ── */
.lr-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-5);
}
/* ── slot base ── */
.lr-slot {
border-radius: var(--r-card);
padding: var(--space-5);
display: flex;
flex-direction: column;
gap: var(--space-3);
min-height: 360px;
transition: opacity var(--dur-base) var(--ease-quart),
filter var(--dur-base) var(--ease-quart),
border-color var(--dur-base) var(--ease-quart);
}
/* ghost: 虚线边 + 大灰序号 */
.lr-slot-ghost {
border: var(--rule-w) dashed var(--rule);
background: transparent;
opacity: 0.55;
}
.lr-slot-ghost .lr-slot-num {
color: var(--text-faint);
}
/* active: 红框 + 实心面板 + 巨号砸下 */
.lr-slot-active {
border: var(--rule-w) solid var(--accent);
background: var(--surface);
box-shadow: var(--shadow-card);
}
.lr-slot-active .lr-slot-num {
color: var(--accent);
animation: lr-num-drop var(--dur-base) var(--ease-quart) backwards;
}
@keyframes lr-num-drop {
0% { transform: translateY(-40%) scale(1.6); opacity: 0; }
60% { transform: translateY(0) scale(0.94); opacity: 1; }
100% { transform: translateY(0) scale(1); }
}
/* past: 灰化 */
.lr-slot-past {
border: var(--rule-w) solid var(--rule);
background: transparent;
opacity: 0.7;
filter: grayscale(0.4);
}
.lr-slot-past .lr-slot-num {
color: var(--text-mute);
}
/* ── slot internals ── */
.lr-slot-num {
font-family: var(--hero-num-font, var(--font-display-en));
font-style: var(--hero-num-style, normal);
font-weight: var(--hero-num-weight, 700);
font-size: calc(var(--t-display-2) * 0.85);
letter-spacing: var(--hero-num-track, -0.02em);
line-height: 1;
}
.lr-slot-content {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.lr-slot-title {
font-family: var(--font-display-cn);
font-size: var(--t-h2);
letter-spacing: -0.005em;
}
.lr-slot-body {
font-family: var(--font-body);
font-size: var(--t-body);
color: var(--text-2);
line-height: 1.6;
max-width: 22ch;
}
// ⚠️ 这是 anchor 参考代码,不会被任何项目编译。
// 抄到真实项目时(presentation/src/chapters/NN-list/),
// 把下面两个 import 改成:
// import { MaskReveal } from "../../components/MaskReveal";
// import type { ChapterStepProps } from "../../registry/types";
import { MaskReveal } from "../../../templates/src/components/MaskReveal";
import type { ChapterStepProps } from "../../../templates/src/registry/types";
import "./chapter.css";
/**
* list-reveal · 完整章节示例
* ─────────────────────────────────────────
* 默认绑 newsroom 主题。
*
* 关键手段:
* - 槽位用 hero-num(serif 巨号)替代普通文字编号
* - 引子用 masthead 双线规则 + serif 大字
* - 槽位状态切换有专属动画:
* ghost → active:mask reveal 标题 + 数字砸下(accent 红)
* active → past :accent 灰化(filter)
* - 关键:所有槽位的 React 节点位置不重排,只切换 className
*/
const ITEMS = [
{ num: "01", title: "文字渲染", body: "图里的文字也能正确写出来" },
{ num: "02", title: "指令遵循", body: "可以给到非常具体的要求" },
{ num: "03", title: "照片真实感", body: "光影 / 材质 / 人物接近真实" },
];
export default function ListRevealChapter({ step }: ChapterStepProps) {
// step 1 — 引子
if (step === 0) {
return (
<div className="lr-scene scene-pad lr-intro">
<header className="lr-masthead">
<span className="lr-rule" />
<span className="lr-kicker">第一部分</span>
<span className="lr-rule" />
</header>
<MaskReveal show duration={1100}>
<h1 className="lr-intro-h">
强在<span className="lr-em">哪</span>
</h1>
</MaskReveal>
<MaskReveal show delay={400} duration={900}>
<div className="lr-intro-sub">三件事 —— 一个个看</div>
</MaskReveal>
<div className="lr-grid">
{ITEMS.map((it) => (
<Slot key={it.num} state="ghost" item={it} />
))}
</div>
</div>
);
}
const activeIdx = step - 1;
return (
<div className="lr-scene scene-pad">
<header className="lr-masthead">
<span className="lr-rule" />
<span className="lr-kicker">第一部分 · 强在哪</span>
<span className="lr-rule" />
</header>
<div className="lr-grid">
{ITEMS.map((it, i) => {
const state =
i < activeIdx ? "past" : i === activeIdx ? "active" : "ghost";
return <Slot key={it.num} state={state} item={it} />;
})}
</div>
</div>
);
}
function Slot({
state,
item,
}: {
state: "ghost" | "active" | "past";
item: { num: string; title: string; body: string };
}) {
return (
<div className={`lr-slot lr-slot-${state}`}>
<div className="lr-slot-num">{item.num}</div>
<div className="lr-slot-content">
{state !== "ghost" && (
<>
<MaskReveal show duration={900} key={`${item.num}-title`}>
<div className="lr-slot-title">{item.title}</div>
</MaskReveal>
{state === "active" && (
<MaskReveal show delay={350} duration={900}>
<div className="lr-slot-body">{item.body}</div>
</MaskReveal>
)}
</>
)}
</div>
</div>
);
}
Anchor: list-reveal(列举型逐个揭示)
⚠️ 这是结构示意,不是抄袭模板。先走 `../../CHAPTER-CRAFT.md`
Part 0 五问。本 anchor 给的是"列举型章节的结构骨架"(单网格 N 槽位 +
每 step 只填一个槽位 + 位置不重排)——保留这个结构,**按本项目的
主题 + 内容换动作选型**。倒过来照抄 = `../../CHAPTER-CRAFT.md`
Part 5 第 8 条「整章只用一种入场动画」同质化反模式。
定位
口播说"三件事 / 四个原因 / N 个特性"时,每项 1 step 逐个揭示。 视频中段最常用的章节类型,最容易翻车成 PPT —— 这是为什么需要 anchor。
适用场景
- "<主体> 强在哪 → 三件事"
- "选购 <X> → 四个角度"
- "为什么我喜欢 <X> → 五个理由"
- 任何"主题 + N 个并列子项"的结构
假设的 outline.md 章节段(抽象)
## 4. <chapter-id> — <主题 N 件事>(N+1 steps)
- **step 1** (~3s) — masthead 引子"<N 件事>"
- **step 2** (~6s) — 第 1 件:<标题> + <article 抽来的细节>
- **step 3** (~6s) — 第 2 件:<标题>
- ...
- **step N+1** (~6s) — 第 N 件:<标题>关键节奏决策
| step | 视觉布局 |
|---|---|
| 1 | 中心引子大字 + 序号 01/02/.../N 占位(不显示内容,纯占位) |
| 2 | "01" 槽位填充:标题 + 简短说明 + accent 编号;其余仍是 ghost |
| 3 | "02" 填充;01 已激活变次级;其余仍 ghost |
| ... | 当前槽位填充;之前的激活降级;之后的 ghost |
CHAPTER-CRAFT.md Part 0 原则 8 的核心实现
"布局不重排,只是单元格内容变化"
整个章节只有一个网格布局,N 个槽位的 React 节点位置完全不变。 变的只是每个槽位的内容状态(ghost / active / past)。这样:
- 单元格不会重排 → 视觉稳
- 每点一次只有"一个槽位变化" → 观众视线明确锁定新揭示的项
反模式:每点一次重新渲染整个布局 → 已揭示的项也跟着抖动 / 重新 入场 → 观众不知道该看哪。
文件结构
list-reveal/
├── README.md
├── chapter.tsx ← 完整章节示例 —— 默认绑 newsroom 主题
└── chapter.css关键手段(地板线)
| 维度 | 这个 anchor 怎么实现 |
|---|---|
| 字号 | 标题 64px / 巨号 144px serif |
| 槽位状态 | dashed → 巨号红色高亮 → 灰化数字(位置不重排) |
| 序号 | hero-num 字体(衬线大数字) |
| 主导动作 | mask reveal(标题)+ 数字砸下(accent 红) |
| 伴随动作 | 副标 stagger 200ms + accent 横线 scaleX |
| 持续微动 | active 槽位的数字 accent 光晕 infinite 呼吸 |
| 引子 | masthead 双线规则 + serif 大字 |
新写章节时:抄结构(单网格 N 槽位、每 step 只填一个槽位、位置
不重排),按本章内容 + 本主题气质自由设计主导动作的形式。
切到其它主题时
bauhaus-bold→ 序号换 Archivo Black + 大色块;用 hard-cut 砸下terminal-green→ 序号[01][02][03]风格;打字机入场chalk-garden→ 粉笔下划线手绘 + wiggle 入场midnight-press→ 数字 blur clear 慢锐化 + 暖橙光晕慢呼吸
结构不变:N+1 step、单网格 N 槽位、每 step 只填一个槽位。
想看具象题材应用
- 科技测评 / 实测对比类视频用这个 anchor 长什么样 →
`../case-tech-review/outline-snippet.md` 里 ## 2. why-strong 章节
EXAMPLES —— 完整章节 / 题材 anchor
## ⚠️ 这是结构示意,不是抄袭模板
>
这些 example 不是给你照抄的。它们的角色是"看一个完整章节大概
什么形状、动画怎么分层、CSS 用了哪些 token、outline 长什么样"。
>
正确使用流程:
>
1. 走完 `../CHAPTER-CRAFT.md` Part 0 五问
2. 实在卡壳"我这一章的整体结构应该是什么"才翻 EXAMPLES
3. 保留它的"形"(step 切分逻辑、字号关系、布局原则),**按本
项目的主题 + 内容换动作选型**
>
倒过来——先翻 EXAMPLES 选一个照搬到底 = `../CHAPTER-CRAFT.md`
Part 5 第 8 条「整章只用一种入场动画」同质化反模式(每个用户的视频
看起来像同一个模板的 N 个变奏)。
两类参考资源,让 agent 在写章节时有具体形状可参考,不用从零设计。
不是必须按这个写。卡壳时翻一翻;用力发挥时大胆偏离。
目录
A. 章节结构 anchor(与题材无关)
| 例子 | 适用场景 | 文件 |
|---|---|---|
| `hook-chapter/` | 钩子型开场 —— 多张图片逐张揭示后 hero takeover | chapter.tsx + chapter.css |
| `list-reveal/` | 列举型 —— 口播说"三件事 / N 个特性",每项 1 step | chapter.tsx + chapter.css |
每个 example 都是完整章节:内容驱动主导动作 + 必要的伴随动作 (不强求挂持续微动,按 `../CHAPTER-CRAFT.md` Part 0 原则 7 节制使用)、真素材(不是占位卡)、字号狠对比、绑了 newsroom 主题作为示范。
B. 题材 case anchor(与题材相关)
| 例子 | 题材 | 文件 |
|---|---|---|
| `case-tech-review/` | 科技测评 / 实测对比 / 跑分类视频 | README + outline 节选 |
题材 case 展示真实 outline 的样子(含 article 补字段如何填、
章节切分如何决策)。拿到与某个 case 题材相似的需求时,先翻它再
写自己的 outline。
怎么用
写章节卡壳时
1. 看哪个 anchor 跟你这一章结构最像(钩子型 vs 列举型 vs 其它) 2. 翻 README.md 看这个例子的设计思路 + 节奏 3. 翻 chapter.tsx 看实现:JSX 结构、step 切分、用了哪些组件 / 类名 4. 翻 chapter.css 看动画用了哪些 keyframes、token、infinite 持续 微动写在哪 5. 写自己这一章时保留 anchor 的"形",按本章内容 + 本主题气质换动画选型
切换主题时
每个 example 的 README 末尾有"切到其它主题怎么换"的提示 —— 通常只需要 换主导动作的形式(newsroom 印章砸下 → terminal 打字机 → chalk 粉笔自绘),结构、step 切分、字号关系不动。
---
⚠️ 这两个 anchor 是"地板",不是"天花板"
这两个例子已经引入印章砸下、stagger、accent 红条 —— 但仍然是相对克 制的版本。鼓励你做得更狂、更"视频感":
进阶玩法(任选搭配)
| 维度 | 这俩 anchor 给的(地板) | 可以升级到(无上限) |
|---|---|---|
| 背景层 | 纯色 surface | + SVG turbulence filter 纸纹永不停斜向漂移 |
| 主导动作 | mask reveal + 印章砸下 | + Canvas 粒子从屏幕外汇聚成 hero 字 |
| 伴随动作 | accent 红条 scaleX | + SVG path stroke-dashoffset 自绘下划线 / 装饰花纹 |
| 持续微动 | accent 光晕呼吸 | + 多层粒子漂移 / scanline / ken burns 缓推 |
| 数字 hero | 直接显示 | + JS 数字滚动(requestAnimationFrame + easeOutQuart) |
| 流程 / 架构 | 仅文字列 | + SVG path 自绘流程图(每条线 stroke-dashoffset 错峰) |
| 对比图 | 两段文字 | + SVG 双柱图自绘 + 差值数字滚动 |
| 转场 | 章节边界硬切 | + clip-path inset 横向擦除转场 |
→ 详细工具箱见 `../CHAPTER-CRAFT.md` Part 2 "视觉手段全栈工具箱"(CSS / SVG / Canvas / JS 四层)。
实测原则
写章节时,先实现 anchor 同等的地板版本(按 `../CHAPTER-CRAFT.md` Part 0 五问选好主导动作),跑起来确认气质对,再决定要不要加伴随 动作 / 持续微动。
判断标准:
- 如果不同 step 的主导动作够多样(PPT 警报通过 `../CHAPTER-CRAFT.md`
Part 0 原则 7 自检)= 不需要再加持续微动
- 如果整章主导动作太单一 = 不要靠"加持续微动"补救,**回 `../CHAPTER-CRAFT.md`
Part 1 五问换主导动作**才是正解(参 Part 5 第 8 条「整章只用一种入场动画」)
不在 EXAMPLES 里出现的章节类型
- 数字型 hero("+47%" → "几乎快了一倍")
- 对比型(前后对照 / 双柱图)
- 链接卡片收尾
这些场景的视觉原语已经在 `../CHAPTER-CRAFT.md` Part 3 视觉工具箱(CSS / SVG / Canvas / JS 全栈)里覆盖了;按 anchor 的"形"组合即可。
outline.md 格式 spec
视频章节规划的产出文件。用户可以直接编辑,所以格式必须人类友好 (用 markdown 不用 JSON / YAML)。
!重要:阅读此文件后必须继续阅读 `CHAPTER-CRAFT.md` 的全部内容,了解对网页效果的真实需求,然后再开始编写 outline
## ⚠️ outline 是开发计划,不是视觉规划
>
outline 只规划节奏 + 内容 + 信息密度:
>
- 章节切分 / 每章 step 数 / 每步估时
- 每步屏幕内容(hero / 标语 / 数据 / 列表项)
- 章节级信息池(从 article 抽的数字 / 引用 / 案例 / 标签)
>
outline 里的 step 数是初始预估。最终 step 数以章节实现时的
narrations.ts 为准——后者既是 step 数源,也是音频合成源(详见 `CHAPTER-CRAFT.md` 「代码层最小约束」+
`AUDIO.md`)。如果实现时章节 step 数和 outline 不一致,
回过来同步 outline 即可,不需要纠结"对得严丝合缝"。
写 outline 前必读(双源原则,CHAPTER-CRAFT.md Part 0 原则 10):
>
- `script.md` —— 决定节拍:按 --- 切节拍,每节拍 1~2 step、估时- `article.md`(如有)—— 决定画面信息密度:每章首段抽信息池
---
抽象示例(看格式)
````markdown
Video Outline
主题:<theme-id>(Checkpoint Plan 已选定)—— <一句话风格描述>总时长:约 <T> 分 <S> 秒(口播 ~<X> 字 ÷ 4 字/秒)
章节数:<N> 章 / <M> 步
---
1. <chapter-id> — <章节标题>(<S> steps · ~<T>s)
信息池(chapter agent 按需挂角标 / 副标 / pull-quote / mono cue):
- <类型:数字 / 引用 / 出处 / 案例 / 词义 / 时间 / 对比 / ...>:<内容> —— <来源 article §X / Lxx>
- ...
开发计划:
- step 1 (~Ts) — <屏幕内容>
- ...
口播节选:
<1~3 句节选,对应到 script.md 完整文本>
---
2. <chapter-id> — ...
````
关于时长:outline 里只写 step 的 (~Ts) 口播估时(音画对齐用),绝对不写动画时长 / 错峰量 / keyframe 数值。这些都在章节开发
阶段决定(`CHAPTER-CRAFT.md` Part 3 时长参考)。
想看具象示例:
- 钩子型开场结构 → `EXAMPLES/hook-chapter/`
- 列举型章节结构 → `EXAMPLES/list-reveal/`
- 科技测评类(实测 / 对比 / 跑分) → `EXAMPLES/case-tech-review/`
---
字段约定
顶部 metadata block
用引用块(>)形式,方便扫一眼整体规模:
| 字段 | 必填 | 说明 |
|---|---|---|
| 主题 | ✓ | Checkpoint Plan 必须已选定。chapter agent 实现时按主题颜色 / 字体 token 走,动画 / 节奏 / 视觉演示由章节自由发挥 |
| 总时长 | ✓ | 估算口播时长(中文 ~ 250 字 / 分钟) |
| 章节数 | ✓ | N 章 / M 步 |
章节标题:## N. <id> — <title>(<S> steps · ~<T>s)
| 部分 | 规则 |
|---|---|
N | 1-indexed 顺序,对齐 chapters.ts 的注册顺序 |
<id> | 小写 + 连字符。会成为 React key / 文件夹名 (src/chapters/0N-<id>/) / 音频子目录 (public/audio/<id>/) |
<title> | 给人看的中文标题。不会进 React 代码 |
<S> steps | 该章 step 总数 |
~<T>s | 该章口播总估时(中文 ~ 4 字/秒) |
合法 id:coldopen、hook、why-good、why-good-text-render。 不合法:why_good(用连字符)、Hook(小写)、第一章(拉丁字符)。
章节首段「信息池」(双源原则核心落地)
每章独立列出从 article.md 抽的细节集合,让 chapter agent 实现每步 画面时按需取用——可能挂成右下角 mono 角标 / 副标小字 / pull-quote 引用 / 数据浮层。
信息池条目格式
- <类型>:<具体内容> —— <来源 article §X / Lxx 或简注>没 article(用户直接给 script):信息池退化为"主动设计画面信息
密度"——靠数字 / 对比 / 元数据等让画面比口播信息密。可以列"画面
装饰元素池"而非"article 抽取池"。
Step 列表:每步 1 行
- step N (~Ts) — <屏幕内容>| 规则 | 原因 |
|---|---|
step N 1-indexed | agent 实现时 if (step === N - 1) ...(注意零基偏移) |
| `(~Ts)` 必填 | 按 script.md 本步对应口播段字数 ÷ 4 估算(中文 ~ 4 字/秒)。范围 3~10s |
| 屏幕内容 | 一句话讲清楚这一步舞台上有什么:hero / 标语 / 数据 / 装饰元素。≤ 1 行,再多就该拆 step |
| 不写动画 | 写死 = 翻译机化(详见本文件顶部框) |
| 不写时长数值 / 错峰量 | 这些在章节开发阶段决定 |
| 不写实现手段 | filter / SVG / Canvas 选型留给 chapter agent |
口播节选(每章末尾,可选但推荐)
精炼 1~3 句,不是完整稿子,仅供章节规划阶段对照"这章在讲什么"。 完整文本回 script.md。outline.md 章节 = script.md 中两个明显 主题切换之间的段落。
音频合成(`AUDIO.md`)会回到 `script.md` 切分完整
文本,不用 outline 节选。
---
命名规则速查
| 对象 | 规则 | 示例 |
|---|---|---|
| 章节 id | 小写 + 连字符 | coldopen, why-good |
| 章节文件夹 | 0N-<id> | src/chapters/01-coldopen/ |
| 章节组件 | PascalCase | Coldopen.tsx, WhyGood.tsx |
| 章节 CSS 类前缀 | 章节缩写(避免跨章冲突) | .cd- / .wg- / .mg- |
| 音频子目录 | <id>/ | public/audio/coldopen/ |
| 音频文件 | <step-N>.mp3 (1-indexed) | public/audio/coldopen/1.mp3 |
---
章节切分的经验法则
- 每章 3~8 步。少于 3 步太薄;多于 8 步观众会忘记这章在讲啥
- 总时长 ÷ 30 秒 ≈ 章节数(一章约 30~60 秒讲完)
- 每章 = 一个聚焦主题。"为什么强 + 怎么用" 是两章,不是一章
- 章节边界 = 口播稿里讲者会换语气 / 换主题的位置。读
script.md
时哪里你下意识想"咳一声接下一段",那里就是章节边界
- 慢节奏 / 长镜头风主题(midnight-press / 电影感片头)每章可少到
2~3 step;信息密集型(科技测评 / 对比表)每章可放宽到 8~10 step
---
素材清单(outline.md 末尾)
## 素材清单
### 1. coldopen
- ✓ <资源 1 描述> (<已就位路径>)
- ⚠️ <资源 2 描述>(待提供)
- ⚠️ <资源 3 描述>(待提供)
---
## 自检(写完 outline **强制**执行,不可跳过)
> ⚠️ **硬性流程**:outline 写完后**必须**走自检 → 修改 → 提交 三步。
> **禁止**写完直接进入 Checkpoint Plan 让用户对齐。
>
> **执行方式**(按能力降级):
>
> 1. **优先 Agent Teams**:开一个独立 reviewer agent,传入 `outline.md`
> + 本节自检清单 + `script.md` / `article.md` 路径,让它**逐项核查 +
> 出结论**(哪几条 fail + 证据)。
> 2. **其次 subAgent**:当前 agent 没 Teams 但能开 subagent,用 subagent
> 走同样流程。
> 3. **都没有**:自己**严格逐项**核查。
>
> 拿到结论后**先按 fail 项改 outline,再进入 Checkpoint Plan**。
- [ ] 每个 step 都是**单一句屏幕内容描述**,没有"动画"行 / "手段"行
- [ ] 没有任何 step 写了具体毫秒 / 秒数(除 `(~Ts)` 口播估时)
- [ ] 每章首段都有「信息池」block,至少 3 条 article 抽取项,**每条
必带来源标注**(`—— 来源 article §X / Lxx`)—— 没标注 chapter agent
回不到原文
- [ ] **所有 step `(~Ts)` 累加 ≈ 顶部声明的总时长**(误差 < 10%)—— 不
一致说明节奏规划失真
- [ ] 章节切分符合"每章 3~8 步 / 30~60s 一聚焦主题"经验
- [ ] 末尾「素材清单」分章节列出,✓ / ⚠️ 标注清楚
- [ ] 脚本不得包含标题、序号等非口播内容,仅包含人类正常可读的内容
写完看一眼:**outline 是不是干净到 chapter agent 看了能立刻开工 + 还有
设计空间**?是 = 合格。如果你看了都觉得"太空,agent 不知道动画选什么"
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Presentation</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
# ────────────────────────────────────────────────────────────────────
# MiniMax provider — uses the official mmx-cli.
#
# Docs: https://platform.minimaxi.com/docs/token-plan/minimax-cli
# Repo: https://github.com/MiniMax-AI/cli
#
# Strengths: Chinese narration quality is consistently good; lots of
# voice options; one-line CLI call.
# ────────────────────────────────────────────────────────────────────
tts_check() {
if ! command -v mmx >/dev/null; then
echo "✗ mmx CLI not found in PATH." >&2
return 1
fi
if ! mmx auth status >/dev/null 2>&1; then
echo "✗ mmx is not authenticated." >&2
return 1
fi
}
tts_install_help() {
cat <<'EOF' >&2
To use the MiniMax provider:
Install: npm install -g mmx-cli
Login: mmx auth login --api-key sk-xxxxx
(get a key at https://platform.minimaxi.com)
Or pick another provider: PRESENTATION_TTS=<name> npm run synthesize-audio
See tts-providers/README.md for the list and how to add your own.
EOF
}
tts_synthesize() {
local text="$1"
local out="$2"
local voice="${3:-}"
# Branch instead of using an empty array — runner uses `set -u`, and
# macOS-default bash 3.2 fires "unbound variable" on "${arr[@]}" when
# arr is empty. The two-branch form is portable to old bash.
if [[ -n "$voice" ]]; then
mmx speech synthesize --voice "$voice" --text "$text" --out "$out" \
>/dev/null 2>&1
else
mmx speech synthesize --text "$text" --out "$out" \
>/dev/null 2>&1
fi
}
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: {
port: 5174,
fs: { allow: [".."] },
},
});
Related skills
Forks & variants (1)
Web Video Presentation has 1 known copy in the catalog totaling 49 installs. They canonicalize to this original listing.
- conardli - 49 installs
How it compares
Pick web-video-presentation over generic frontend-design skills when you need a click-driven, screen-recordable 16:9 deck with narration sync—not a static landing page.
FAQ
Why does outline.md avoid specifying animations?
Animation is designed per chapter at implementation time using CHAPTER-CRAFT.md so agents do not merely translate preset motion notes.
What file controls step count and audio segments?
Each chapter narrations.ts is the sole truth source; max step index plus one must equal narrations.length.
Is Web Video Presentation safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.