Add resilient presenter mode and speaker notes

This commit is contained in:
郭浩 committed 2026-08-06 21:42:31 +08:00
1 parent 929c2ecb63
commit 006ba0b87a
6 files changed
+704 -23

No files matched your search

+20
View File
@@ -8,6 +8,26 @@
## 🔴 P0 · 一定不能犯的错
### 0-P. 演讲者模式必须可控、可恢复、备注不串页
**现象**:演讲者端已经翻页,观众屏仍停在上一页;观众窗口关闭后没有提示;页面重排后,用户改过的讲稿跑到了另一页;或演讲模式入口变成页面右上角的突兀按钮。
**做法**:
- 演讲入口只放在右下角现有快捷控制区,显示 `P 演讲模式`。
- 演讲者控制顺序固定为 `首页 / 上一页 / 总览 / 下一页 / 尾页`;尾页时最后一个按钮变为“重新开始”。
- 观众屏必须显示软件链路状态:`连接中 / 已同步 / 未同步 / 未连接 / 弹窗被拦截`,并始终提供“重新打开观众屏”。
- 每页必须有稳定、唯一的 `data-slide-id`;`SPEAKER_NOTES` 数量、顺序和 ID 必须逐页一致。
- 备注本地编辑按页面 ID 保存;切页重置滚动位置并显示保存状态。
- 浏览器只能确认观众页面是否同步,不能确认 HDMI/投影线物理连接;现场仍要目视检查外接屏。
**检查**:
```bash
node <SKILL_ROOT>/scripts/validate-presenter-mode.mjs path/to/index.html
```
浏览器里关闭观众窗口,确认状态变化;再点击“重新打开观众屏”,确认它恢复到演讲者当前页。
### 0-S. Swiss locked mode:正文页必须来自原始 22P
**现象**:颜色、字体看起来像 Swiss,但标题跑到中间、图片不在网格上、页面结构和原始 22P 完全不是一套东西。
+93
View File
@@ -0,0 +1,93 @@
# 演讲者模式与演讲备注契约
制作任何需要现场讲述的 deck 时加载本文件。目标不是把页面文案复制到备注区,而是让页面、讲述和转场形成一条可以排练的叙事链。
## 1. 页面计划必须同时规划“看什么”和“说什么”
在写 HTML 前,先做一张表:
| 页码 | `data-slide-id` | 页面目的 | 观众屏可见信息 | 演讲者补充 | 分钟 | 转场 | cue |
|---|---|---|---|---|---:|---|---|
- **观众屏可见信息**:观众此刻必须读到的结论、证据、结构或图像。
- **演讲者补充**:背景、例子、判断依据、语气和细节,不要逐字复述页面。
- **转场**:解释下一页为什么紧接着出现,不要只写“下一页”。
- **cue**:可选的舞台动作,如停顿、提问、播放视频、切 Demo、提醒敏感信息。
默认生成“提词卡”,不是逐字稿。只有用户明确要求逐字稿时,才写完整口播。
## 2. 稳定的页面 ID
每一页都必须有唯一、语义化且稳定的 ID:
```html
<section class="slide ..." data-slide-id="codepilot-capabilities">
```
- 使用小写英文 slug:`cover`、`codepilot-capabilities`、`demo-workflow`、`closing`。
- 页面重排时保留原 ID;只有页面语义彻底改变时才更换。
- 不要用页码作为 ID。演讲者在浏览器里修改的备注按 ID 保存,稳定 ID 可避免重排后串页。
## 3. `SPEAKER_NOTES` 数据结构
在 deck 中保留一条与每页 ID 对应的记录,顺序必须与 slide 完全一致:
```js
const SPEAKER_NOTES = [
{
id: 'codepilot-capabilities',
title: 'CodePilot 能做什么',
minutes: 0.9,
purpose: '先让观众建立完整产品认知,再进入实现过程',
talk: [
'从用户动作讲能力,不先讲底层 Harness',
'用首页、多模型、Skills 和侧边栏四张截图建立产品全貌',
'强调模型、工具和上下文可以在同一工作流里协作'
],
transition: '观众知道产品长什么样后,再回答为什么要这样实现',
cue: '按截图顺序指向四个能力区'
}
];
window.__SPEAKER_NOTES__ = SPEAKER_NOTES;
```
硬规则:
- `id`、`title`、`minutes`、`purpose`、`talk`、`transition` 必填,`cue` 可选。
- `talk` 默认 3–5 条,每条只表达一个意思;封面、章节页和纯过渡页可以更短。
- 不编造原素材没有的数字、事实或经历;信息缺失时标记“待补充”或向用户询问。
- 总建议时长不超过用户时长的 90%,给停顿、现场互动和意外留出约 10% 缓冲。
- 封面只负责建立问题与预期;Demo 页写清操作顺序和失败兜底;尾页回扣开场并给出行动点。
## 4. 演讲者界面行为
- 普通 deck 的右下角控制区显示 `P 演讲模式`,不单独悬浮一个抢眼按钮。
- 点击后当前窗口进入演讲者视图,并打开独立观众屏。
- 控制顺序固定为:`首页 / 上一页 / 总览 / 下一页 / 尾页`;到尾页后“尾页”变为“重新开始”。
- 总览卡片显示页码、标题和当前页高亮,点击缩略图直接跳页;`ESC` 同样切换总览。
- 计时器由用户显式开始,可暂停、继续、重置;不要进入模式就自动计时。
- 备注编辑按 `data-slide-id` 存入 `localStorage`,显示保存状态;切页后备注滚动回顶部,并允许调整字号。
- `Home` / `End`、方向键、PageUp/PageDown 与可见按钮保持一致;光标在备注编辑器中时不得触发翻页。
## 5. 观众屏同步与恢复
模板同时使用窗口 `postMessage`、`BroadcastChannel` 和 `storage` 事件同步。观众页在加载和每次翻页后回传确认,演讲者端显示:
- **连接中**:观众窗口已打开,尚未收到确认。
- **已同步**:观众页确认的页码与演讲者页相同,心跳有效。
- **未同步**:确认超时或两端页码不同。
- **未连接**:观众窗口未打开或已关闭。
- **弹窗被拦截**:浏览器阻止打开观众窗口。
“重新打开观众屏”必须始终可用,并在恢复后立即发送当前页。
浏览器只能确认观众**页面/窗口**的软件同步状态,不能检测 HDMI、转接器或投影仪线缆是否物理断开。现场仍应目视确认外接屏。
## 6. 生成后验证
```bash
node <SKILL_ROOT>/scripts/validate-presenter-mode.mjs path/to/index.html
node <SKILL_ROOT>/scripts/validate-presenter-mode.mjs path/to/index.html --target-minutes 30
```
浏览器实测至少包含:进入演讲模式、弹窗允许/拦截、前后翻页、总览跳页、首页/尾页、尾页重新开始、观众窗口关闭后的状态变化、重新打开后恢复同步、备注保存与重排后不串页。