# Booth Kiosk Deck

> 何时调：要做展位/评审现场「全自动循环口播演示」——HTML kiosk deck（Edge TTS 口播 + 字幕 + 词级动作点）或配套 HyperFrames MP4。触发词：展位演示、自动循环播放、口播 PPT、booth deck、kiosk demo、演示自动播放、口播文字稿。不调：可交互点击原型（走 mock-devops-platform 那套单文件 HTML）、真人手动翻页的幻灯（frontend-slides）、纯宣传片（ai-video-production / video-use）。确认单通过后目标 15 分钟出全套。

- Skill: `yhyu13/booth-kiosk-deck` (Agent Skill, multi-file: 37 files)
- Install (CLI): `npx get-skill add yhyu13/booth-kiosk-deck`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yhyu13/booth-kiosk-deck/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: yhyu13 (https://skillmd.com/u/yhyu13)
- Updated: 2026-11-12
- Page: https://skillmd.com/skills/yhyu13/booth-kiosk-deck

---


# booth-kiosk-deck · 全自动循环口播演示流水线

替你把「确认单 → 单源生成 → 两级验证 → 出片」跑成 15 分钟流水线。
可跑通的参考实现（整套抄改起点）：`assets/day1025/booth/booth_1/`。

## 零、先记住物理事实（每条都踩过）

- 浏览器默认拦「无手势出声」：只有 `--autoplay-policy=no-user-gesture-required` 的 kiosk 启动才保证开机有声；被拦时 deck 自动降级墙钟静音循环（字幕/动作照常），任意一次点击即从当前页恢复出声
- `new Audio()` 不进 DOM：`querySelector('audio')` 永远查不到——验证必须拦 Audio 构造器（见 fastgate）
- PowerShell 5.1 内联写复杂 patch 必炸（`$` 展开、`\n` 不换行、引号套层）：**一律写 .py 文件执行**，别用 `python -c` 传中文
- npx 版本漂移会改变 check 行为（0.8.195 起 0 错误也 exit 1）：**钉版本**，如 `hyperframes@0.8.193`
- HyperFrames：工程目录只允许一个带 `data-composition-id` 的 HTML（源模板放工程外）；未加作用域的类名（如 `.big`）会命中别的组件；`left:%` 补间被 StaticGuard 拒收（用 `x`，固定像素）；图层切换用 `display` 不用 `opacity`（否则 layout 闸判文字重叠）；deck 永不渲染成 MP4——视频是独立合成，由 build.py 从同一数据生成
- deck 时钟跟 `audio.currentTime`，无声降级墙钟；抽帧验证用 `?t=秒` 直跳，不要实时等

## 一、确认单（动手前一次问全，每个都给★推荐）

**必问 5 问**（少问一个 = 返工 20 分钟级别）：

| # | 问法 | 推荐 |
|---|------|------|
| 1 | 播放方式：全自动循环 kiosk，还是允许访客交互？ | ★ 全自动循环，零交互入口，输入全吞 |
| 2 | 声音：默认有声 + 100% 音量，还是静音循环？ | ★ 默认有声 100%，不放音频控件；拦声时提示「点一下恢复」 |
| 3 | 鼠标：可见不可控，还是隐藏？ | ★ 光标可见、页面不可控 |
| 4 | 客户名：脱敏成 XX客车，还是实名？哪些位置（画面/口播/字幕/文件名/README）？ | ★ 全部脱敏，含 TTS 词表与导出文字稿 |
| 5 | 演示哪几个能力（按 demo 最新侧边栏顺序）？ | ★ 前两个能力 + 封面 + 收尾，共 4 页 |

**grill 清单**（头脑风暴补充，逐条给用户过）：

| # | 问题 | 推荐 |
|---|------|------|
| 6 | 口播稿谁定？ | ★ agent 先出 TXT（每句一行）确认，冻结后再跑 TTS——口播词是一切时长的源头 |
| 7 | 总时长预算？ | ★ 60–120 秒；超了删内容，不加速语速 |
| 8 | 页数结构？ | ★ 封面 + 每能力 1 页 + 收尾（4–5 页）；一个能力不拆两屏 |
| 9 | 数字口径怎么标？ | ★ 演示数字全部标「演示用模拟数据」；事实/编号可引用真实调研来源 |
| 10 | 交付物形态？ | ★ deck HTML + HyperFrames MP4 双交付（kiosk 用前者，大屏/备份用后者）+ 口播 TXT |
| 11 | 展位机怎么启动？ | ★ start.cmd：Edge kiosk + autoplay 豁免 + 独立 user-data-dir |
| 12 | 断网约束？ | ★ 全离线：本地音频、本地 gsap、无 CDN 字体/图标 |
| 13 | 分辨率与缩放？ | ★ 1920×1080 舞台等比缩放任意窗口 |
| 14 | 循环行为细节？ | ★ 页间气口 1.4s；循环回第 1 页时交互状态全部重置 |
| 15 | 验收标准？ | ★ 快闸全绿（见下）+ 关键 cue 抽帧人工过目 + MP4 ffprobe 时长==合成声明 |

## 二、单源生成（消灭双份手工同步）

- `build.py` 是唯一数据源：每页一个块 = 口播词 + cues（动作提示点=正文关键词）+ 面板数据
- 同一份数据渲染两个产物：`slides.html`（kiosk deck）与 `video/index.html`（HyperFrames 合成）
- **永远不手改产物**；改内容只改 build.py 数据块，重跑生成
- 口播动作点用词级时间戳：`edge_tts.Communicate(..., boundary="WordBoundary")`，cue 取关键词开口时刻；时长用 ffprobe 实测，不估算

## 三、两级验证（快闸每次改动都跑，慢闸只跑一次）

**快闸（<30 秒，无截图）**——用本 skill 的 `scripts/fastgate.py`：
1. console/pageerror = 0
2. 口播 `[volume=1, muted=false, playing=true]`（拦 Audio 构造器取真值）
3. 禁词表不在画面文字里（客户名等）
4. 可见面板矩形不溢出舞台
5. （视频）`ffprobe` 时长 == 根 `data-duration`，差 >0.05s 即 FAIL

**慢闸（交付前一次）**：`?t=` 直跳抽 6–8 张关键 cue 帧 → 人工过目 → `render.ps1` 出 MP4 → 抽 2 帧复核。

**纪律：改一行先过快闸；慢闸攒到交付前一次跑。严禁拿慢闸当回归测试。**

## 四、15 分钟预算

| 分钟 | 动作 |
|------|------|
| 0–2 | 确认单 15 问过一遍（用户只答「行/改」） |
| 2–5 | 只改 build.py 数据块 → 生成 deck + video 工程 |
| 5–7 | 快闸全绿 |
| 7–9 | 抽帧过目（有问题回到 2，但只修不重验全量） |
| 9–12 | check + 后台渲染 MP4 |
| 12–15 | 导出口播 TXT / README、ffprobe 复核、收尾 |

## 五、不调的情况

- 要的是**可点击原型**（访客操作驱动）→ 不是本 skill，kiosk 模式会吞掉一切交互
- 真人手动翻页、带演讲者备注的幻灯 → frontend-slides / slideshow skill
- 与口播无关的纯素材剪辑 → video-use
- 一次性 <15 秒概念片，不需要循环 → 纯 HTML/Canvas 即可，别起工程

## 六、红线

- 禁词表（客户全名等）进快闸，任何产物不得出现；文字稿与 TTS 词表一并检查
- 合成内禁随机/定时器/网络请求——画面必须是时间轴的纯函数
- 演示数字必须可见地标「演示用模拟数据」；真实事实必须带编号来源
- 观众侧零可操作入口（除非确认单明确要求）；离开 kiosk 启动脚本跑，必须保留「点击恢复出声」降级路径

