Files
SoundGame/HANDOVER.md
T

321 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SoundGame 交接文档(HANDOVER)
> 接收方:即将接手开发、没参与过本项目的同事。读完本文 + 跟随链接即可独立上手。
> 本文是**总入口**:细节一律链接到专项文档,不复制。文中路径除注明外均为仓库相对路径(仓库根 = `/home/ubuntu/SoundGame`)。
## 0. 项目一句话
6 款纯音频 HTML5 游戏:屏幕只有封面图,操作只有 6 种手势(上/下/左/右滑、单击、双击),一切靠音频呈现。纯 vanilla JS ES module,**无构建步骤、无 npm 依赖**,手机浏览器打开即玩。全部对白由本地 Qwen3-TTS 双性别生成,音效由 Stable Audio 3 + 程序合成,BGM 由 Mureka API 生成。**交互层由「向导层」统一承载**(状态签名 earcon/回合标记/静默看门狗/纠错,`web/engine/guide.js`),其设计依据与验证过程见 `research/`(交互研究项目,结论=方法论+4 轮玩家代理闭环)。
## 1. 5 分钟上手
### 1.1 环境依赖清单
| 依赖 | 位置(仓库内) | 说明 |
|---|---|---|
| Node.js | `tools/node/bin/node` | 跑服务器与试玩测试;项目自带,无需装系统 node |
| Python venv(TTS) | `.venv-tts/` | Qwen3-TTS 对白生成(需 GPU,13GB 模型在 `models/hf/`) |
| Python venv(SA3) | `tools/stable-audio-3/.venv/` | Stable Audio 3 音效生成 |
| ffmpeg | `tools/bin/ffmpeg` | 音频转码(ogg/m4a) |
| JDK 17 + Android SDK | `tools/jdk17/`、`tools/android-sdk/` | 仅旧 Android 版用,Web 开发不需要 |
全部工具是用户态安装在 `tools/` 下、不入库(见 §8)。从零复现整机环境的完整手册:[docs/setup.md](docs/setup.md)。
### 1.2 密钥(只在需要重新生成资产时才配)
密钥文件被 .gitignore 排除,**绝不入库**;模板里有获取链接:
```bash
cp env.d/sfx.example.sh env.d/sfx.sh # HF token:https://huggingface.co/settings/tokens
# (需先接受 stable-audio-3-small-sfx 的 gated 许可)
cp env.d/mureka.example.sh env.d/mureka.sh # Mureka key:https://platform.mureka.ai
```
TTS 环境(`env.d/tts.sh`)不含密钥,直接 source 即可。三个 env 脚本的作用:`tts.sh` = HF_HOME/镜像;`sfx.sh` = HF token + uv 路径;`mureka.sh` = Mureka API key。详见 [env.d/tts.md](env.d/tts.md)、[env.d/sfx.md](env.d/sfx.md)。
### 1.3 跑起来
```bash
bash web/serve.sh
# 打印:本机 http://localhost:8000/ 局域网 http://192.168.x.x:8000/
```
- 桌面浏览器开 `http://localhost:8000/` 即游戏大厅;鼠标拖拽/点击可模拟全部手势。
- **手机访问**:手机与电脑连同一 WiFi,开打印出的局域网地址。WSL2 需先在 Windows 做端口转发(命令在 `web/serve.sh:9` 注释里:`netsh interface portproxy add v4tov4 ...`)。
- 服务器 = `web/server/server.js`(Node 零依赖,静态托管 + 用户系统 API 一体),细节见 [web/server/README.md](web/server/README.md)。
### 1.4 跑一遍试玩测试
每款游戏都有无头试玩测试(mock 浏览器 + 虚拟时钟,模拟玩家通关,见 §5):
```bash
for g in storyline escape simon rhythm space rpg; do
tools/node/bin/node web/$g/test/playtest.mjs || echo "FAILED: $g"
done
tools/node/bin/node web/harness/guide.test.mjs # 向导层专项(guide=full 行为断言)
```
退出码 0 = 全绿。当前 6 款 + 向导专项全部通过。**注意:playtest 一律在 setup 里 `settings.set({guide:'off'})` 验证纯玩法逻辑;向导行为断言只住在 guide.test.mjs。**
### 1.4.1 玩家感知转写器(交互研究的测量仪器)
```bash
tools/node/bin/node web/harness/transcribe.mjs <game> # 产物: research/04-playtests/transcripts/<game>.md
```
把一局游戏对玩家的全部输出(每句语音全文/音效/BGM/震动/静默段/缺资产)转成时间轴日志——**无法真听音频的评审(人或 agent)靠它审交互**。会话剧本在 `web/harness/sessions/<game>.mjs`(describe=状态行话术 + session=新手动作剧本)。规矩:剧本必须以完整弧线收尾、driver 要对提示做人类级反应、台词全文映射跑 `tools/extract_voice_text.py` 刷新。
### 1.5 顺手验证:单条语音再生成冒烟
```bash
source env.d/tts.sh
flock .gpu.lock .venv-tts/bin/python tools/tts_smoke_test.py
# 输出 tools/samples/tts_test.wav(约 2s),能出声即 TTS 环境完好
```
### 1.6 常见任务速查
| 我要做什么 | 怎么做 |
|---|---|
| 加/改一句语音 | ① 台词写进对应 `docs/design/*-voice-ids.md`(id+全文+instruct,数字改档位整句)→ ② 条目加进 `tools/gen_voice_dual.py` 台词表 → ③ `flock .gpu.lock .venv-tts/bin/python tools/gen_voice_dual.py --game <g> --only <id>` → ④ 跑 `tools/check_all_assets.py` |
| 加一款新游戏 | 复制模板:`cp -r web/template web/<name>`;接线方式与目录约定见 [docs/web-engine-api.md](docs/web-engine-api.md) §快速开始;手势/震动/菜单遵守 [00-global-ux](docs/design/00-global-ux.md);大厅 `web/index.html` 加卡片;写 `web/<name>/test/playtest.mjs`(mock 层抄现有任一) |
| 修一个爆音/咔哒音 | `tools/scan_clicks.py` 定位 → `tools/fix_clicks.py` 修复(标准:one-shot 真峰值 ≤-3dBFS、首尾 8ms cos² 淡化、去直流;§3.2 的 MDCT 坑必读)→ 终检 |
| 改全局设置项/加设置 | `web/engine/settings.js`(VALID 白名单)+ 大厅 `web/index.html` 设置面板 + 00 文档 §1 语义表,三处同步 |
| 生成一首 BGM | prompt 参考 [10 号文档](docs/design/10-feedback2-state-bgm.md) §8 草稿 → `tools/mureka_gen.py` → `tools/bpm_precise.py` 实测 BPM(节奏类必须)→ 无缝循环处理(90s/强 onset 起点/3s crossfade)→ 记 `tools/mureka_log.md` 台账 |
| 调真机听感参数 | 改完必须真机戴耳机验证(roadmap §4 checklist);模拟器/桌面听不出手感 |
### 1.7 排障速查
| 症状 | 排查 |
|---|---|
| 游戏全程无声 | ① 是否点了启动遮罩(音频必须在真实手势中解锁)② iOS 上 `.ogg` 解码失败——确认资产有 `.m4a` 副本 ③ 开 DevTools 控制台看 `[WebAudioEngine]` 日志(资产缺失只 console.error 不崩) |
| 手机打不开页面 | 同一 WiFi?WSL2 做了端口转发(`web/serve.sh:9` 注释)?防火墙放行 8000? |
| TTS/SA3 脚本抢 GPU 失败或结果损坏 | 所有 GPU 任务必须 `flock .gpu.lock` 串行;模型下载失败看 `env.d/sfx.sh` 注释(gated 模型必须直连官方端点,hf-mirror 会 308) |
| 测试挂了但游戏没改 | 看是不是动了引擎(engine 是 6 游戏共享的);playtest 用虚拟时钟,真实 setTimeout 依赖会失效 |
| 语音变了性别/音色 | voice 缓存键含性别,切换设置后下一句生效;检查资产是否误放进错误的 gender 目录(角色音应平铺,见 §4 核查结论 [12 号文档](docs/design/12-skip-and-longpress-ux.md) §4) |
### 1.8 第一周建议路径
1. 第 1 天:跑通 §1.3 + §1.4;大厅里把 6 款游戏各玩 5 分钟(戴耳机)。
2. 第 2 天:通读 [docs/web-engine-api.md](docs/web-engine-api.md) + [00-global-ux](docs/design/00-global-ux.md),对照 `web/template/` 跑一个 hello-game。
3. 第 3 天:挑一款游戏读 game.js + 对应设计文档 + playtest.mjs,改一个小参数跑测试验证。
4. 第 4-5 天:读 §3 资产管线,跑通 §1.5 冒烟 + 一次 `--only` 单条重录 + 终检。
## 2. 技术架构
### 2.0 顶层目录速览
```
web/ # ★ 全部现役工作在这里:大厅 + 引擎 + 6 游戏 + 服务器
app/ # 旧 Android 版(已停迭代,§2.5)
docs/ # 文档:setup / 引擎手册 / design/(设计规范与审查档案)/ audio/(资产台账与轮次报告)
env.d/ # 环境注入脚本(tts/sfx/mureka/android)+ 密钥模板(*.example.sh)
tools/ # 用户态工具链(node/jdk17/android-sdk/ffmpeg/bin)+ 资产管线脚本(*.py/*.sh)
models/hf/ # HF 模型缓存(13GB,不入库)
.venv-tts/ # TTS venv;tools/stable-audio-3/.venv/ 是 SA3 venv
```
一次手势的完整调用链(以"双击格挡"为例):
```
触摸 → gesture.js(双击识别,内置 confirm 震动)
→ game.onGesture('doubletap')(游戏逻辑:查格挡窗口)
→ audio.play('sfx/parry')(sfx 层即发即弃)+ vibrate()(语义震动)
→ 状态推进(计时器 / voice onComplete 链 / setState)
```
### 2.1 架构图
```
浏览器(手机/桌面)
└── web/index.html 游戏大厅:设置面板(音色/语速/BGM 音量)+ 登录 + 进度卡片
└── web/<game>/ 每游戏一个目录:index.html + game.js + cover.png + audio/
└── 共享引擎 web/engine/
├── gesture.js 手势识别 → 7 种事件(6 手势 + longpress/longpressend)
│ 内置基础震动(滑动→swipe、点按→confirm)
├── audio.js Web Audio 三层(bgm/voice/sfx)+ ducking + 交叉淡入
│ voice 走 SoundTouch 变速不变调管线(engine/vendor/soundtouch.js)
│ 总线挂 DynamicsCompressor 限幅器(-6dB/12:1)防爆音
│ 长按事件 → voice 临时 1.7× 快进(setRateBoostEnabled 可按游戏豁免)
│ isVoicePlaying() 公开查询
├── guide.js ★ 向导层:状态签名 earcon(8 音运行时合成)+ turn cue +
│ 静默看门狗 + 纠错;settings.guide 三档(full/standard/off),
│ off=全静且零定时器;插播一律 queue 不顶对白,error/watchdog
│ 语音空闲才播(过期丢弃)。设计裁定:docs/design/14-guide-layer.md
├── settings.js 四项全局设置(voice/speed/bgm/guide),localStorage 持久化
│ (speed 含 2.2 视障档)
├── haptics.js navigator.vibrate 封装,10 种预定义语义震型
└── game.js Game / StateMachineGame 基类
└── web/server/server.js Node 零依赖:静态文件 + 用户系统 API
└── data/ users.json(PIN 明文!)、sessions.json、<username>.json(进度)
```
**引擎 API 手册(开发新游戏必读)**:[docs/web-engine-api.md](docs/web-engine-api.md)。整体架构与音频时序:[docs/architecture.md](docs/architecture.md)。
### 2.2 服务器 API
`POST /api/register` / `POST /api/login` / `GET /api/progress?game=x` / `PUT /api/progress {game, data}`。进度 `data` 自由格式,但**必须带 `summary` 字符串**(大厅卡片直接显示);`_settings` 是设置同步的保留键。
> ⚠ **玩具级认证**(web/server/README 有显著警告):PIN 明文存储、token 永不过期、HTTP 明文。仅适用同一 WiFi 家庭内网,**勿暴露公网**。
### 2.3 资产目录约定
```
web/<game>/audio/
├── bgm/*.ogg|m4a 背景/状态音乐(循环)
├── voice/male|female/ 旁白/系统音双性别(两目录 id 集合完全一致)
├── voice/<id>.* 角色/NPC 台词平铺(固定单音色,引擎回退命中)
└── sfx/*.ogg|m4a 音效(即发即弃)
```
### 2.4 关键设计决策(为什么)
- **为什么无构建纯 vanilla JS**:游戏逻辑全部是"手势→音频状态机",无 UI 框架需求;无构建 = 任何静态服务器可托管、任何同事改完刷新即验、无依赖腐烂风险。
- **为什么 ogg + m4a 双格式**:iOS Safari 对 Ogg Vorbis 解码支持差,引擎按 `.ogg → .m4a → .mp3 → .wav` 顺序回退;Android/Chrome 用 ogg(体积/音质比好),iOS 自动落到 m4a(AAC)。
- **为什么单击有 ~300ms 延迟**:引擎要等 300ms 双击窗口关闭才能确定单击。这是刻意设计——**即时反馈(格挡、节奏击打)一律绑滑动或双击**,单击只用于非即时操作(确认/检查/菜单)。所有游戏的手势设计都绕开了它。
- **为什么引擎管手势震动、游戏管语义震动**:gesture.js 对"识别成功"内置 swipe/confirm 震动;游戏层只在语义事件(error/success/warning/pickup/hit/beat/danger)调 `vibrate()`。分层防止双重震动,也让 6 款游戏的触觉语言一致(设计规范:[docs/design/00-global-ux.md](docs/design/00-global-ux.md) §2)。
- **为什么 voice 双性别目录而不是运行时变调**:变速变调会毁音色;每句台词用两个 speaker(male=Uncle_Fu / female=见 §3.1 分配表)各生成一遍。角色/NPC 音固定不随设置(只有旁白/系统音跟随)。
### 2.5 Android 旧版状态
`app/` 下 3 款早期 Android flavor(storyline/reflex/escape,Gradle 构建)**已停止迭代**:reflex《声东击西》因质量差已在 Web 版删除,另外两款以 Web 版为准(Web 版 escape 已重设计,逻辑不再一致)。构建命令见 README 与 [docs/engine-api.md](docs/engine-api.md)。新工作全部发生在 `web/`。
## 3. 音频资产制作流水线(接手重点)
总规范:[docs/asset-pipeline.md](docs/asset-pipeline.md);资产总账与音色分配:[docs/audio/asset-manifest.md](docs/audio/asset-manifest.md);各轮生产报告(round1-6):[docs/audio/](docs/audio/)。**设计侧台词表**(id + 全文 + instruct,录什么看这些):`docs/design/*-voice-ids.md`(03/04/05 号系列)。
### 3.1 TTS 对白(Qwen3-TTS CustomVoice,本地 GPU)
```bash
source env.d/tts.sh
# 串行保护 GPU(所有 GPU 任务都要 flock)
flock .gpu.lock .venv-tts/bin/python tools/gen_voice_dual.py # 全量(断点续跑,已有合格 wav 跳过)
flock .gpu.lock .venv-tts/bin/python tools/gen_voice_dual.py --game rpg --gender female --only tut_battle_1 # 单条重录
flock .gpu.lock .venv-tts/bin/python tools/gen_voice_dual.py --check # 校验
```
- **台词表内嵌在 `tools/gen_voice_dual.py`**:加台词 = 在表里加 `(id, speaker组, 全文)` 条目再跑。staging wav 在 `tools/gen_voice_dual_wav/`,脚本自动 ffmpeg 转双格式。
- **音色分配表**(游戏 × 性别 → speaker):storyline m=Uncle_Fu/f=Vivian;escape/simon/space/rpg m=Uncle_Fu/f=Serena;rhythm m=Uncle_Fu/f=Vivian。RPG NPC 单音色(村长 Uncle_Fu·慈和 / 老猎人 Eric / 头目 Dylan / 寨主 Uncle_Fu·阴狠)。完整 instruct 模板见 asset-manifest.md。
- **instruct 规范**(00 文档 §3):同游戏同常量、不含语速词(语速由引擎 SoundTouch 运行时控制)、一句一文件整句生成、**禁止数字碎片拼接**(数字信息按档位预生成整句,如 time_band1..4)。
- **多音字避坑**:"重听"→写"重新听";风险清单见 asset-manifest.md;确认误读后改台词表重跑单条(`--only`)。
- **QC 标准**:时长 >0.3s、峰值 >0.05、峰值归一 0.89(voice 层策略,R6 起不改)、两性时长离群 >3 倍重生成。
### 3.2 音效(Stable Audio 3 + 程序合成)
```bash
source env.d/sfx.sh
cd tools/stable-audio-3 && flock ../../.gpu.lock .venv/bin/python -m stable_audio_tools ... # CLI 用法见 env.d/sfx.md
```
- prompt 一律**英文**;各游戏音效的需求清单与 prompt 草稿:[docs/design/05-rpg-chapter1.md](docs/design/05-rpg-chapter1.md) §7.2 是范本。
- 程序合成兜底:numpy 合成脚本在各游戏 `gen/` 目录(如 `tools/gen_rpg_syn.py`)。
- **⚠ MDCT 编码过冲的坑(踩过的雷,R6 报告 §1)**:SA3 输出的近满幅高密度 one-shot,经 vorbis/aac 等 MDCT 有损编码后**重建峰值会过冲 +4~8dB**;而 `ffmpeg volumedetect` 走 s16 中间格式会把超幅削平显示为 0.0dB——**用 volumedetect 做 QC 完全测不出来**。正确校验法是**"解码回读真峰值"**:编码后再解码成浮点 PCM 读真实峰值。成品标准:**one-shot 真峰值 ≤ -3dBFS** + 去直流 + 首尾 8ms cos² 淡入淡出;loop 类(amb/bgm)只去直流(首尾淡化会破坏无缝循环)。编码管线内置"超 -3dB 则降增益 + 首轮 18kHz 低通 → 重编"(最多 3 次迭代)。
- 排查工具:`tools/scan_clicks.py`(扫描爆音/直流/突变)、`tools/fix_clicks.py`(修复),原件备份在 `tools/asset_fix_backup/`。
### 3.3 BGM(Mureka API)
```bash
source env.d/mureka.sh
.venv-tts/bin/python tools/mureka_gen.py # 调用/选候选/下载,用法见脚本头注释
```
- 全流程与每次调用记录(task id、成本):[tools/mureka_log.md](tools/mureka_log.md)。预算台账:**累计 $0.63 / $2.00**(R6 后)。
- **BPM 实测**:节奏类 BGM 必须用 `tools/bpm_precise.py` 实测(AI 生成曲目 BPM 不精确会毁玩法;rhythm 三曲目 90/105/120 都是归一化过的)。
- **无缝循环处理参数**:90s 时长、强 onset 起点、首尾 3s crossfade 叠化、ogg q3 + m4a 128k。
- 状态 BGM 规范(每游戏状态→曲目映射、切换淡入淡出毫秒数):[docs/design/10-feedback2-state-bgm.md](docs/design/10-feedback2-state-bgm.md)。
### 3.4 资产终检
```bash
.venv-tts/bin/python tools/check_all_assets.py # 全项目 928×2 文件:双格式/0字节/解码/性别集合一致性
```
最近一次全绿报告:[docs/audio/final-asset-check.md](docs/audio/final-asset-check.md)。**改任何资产后必跑。**
## 4. 六款游戏逐个简介
手势全局约定:上滑=帮助/状态、下滑=菜单、单击=确认/继续、双击=重听、左右滑=选择/移动;以滑动为玩法核心的游戏有豁免(00 文档 §5)。
| 游戏 | 玩法一句话 | 手势要点 | 目录 | 设计文档 | 试玩测试覆盖 |
|---|---|---|---|---|---|
| 剑与声 rpg | 纯音频回合制武侠 RPG:节点图探索 + 听前摇双击格挡的回合制战斗 + 升级装备三章剧情 | 左右滑=选选项/招式,单击=确认/出手,双击=格挡/重听,上滑=状态,下滑=菜单/逃跑 | `web/rpg/` | [05-rpg.md](docs/design/05-rpg.md) + chapter1/voice-ids/addendum + [11 战斗重构](docs/design/11-rpg-battle-rebalance.md) | 第一章通关全链(村庄→商店→教学战锁血→支线→连战→Boss 二阶段)、格挡 0.3 减伤、存档继续 |
| 声命线 storyline | 末世互动广播剧:3 幕 8 抉择 4 结局,左右滑做选择 | 单击=继续,双击=重听节点,左右滑=抉择,上滑=帮助+进度,下滑=菜单 | `web/storyline/` | [docs/games/storyline.md](docs/games/storyline.md)(旧)+ 打磨项见 roadmap §2 | 抉择路径到达结局、双击重听、菜单返回不丢节点、剧情标记断言 |
| 暗室 escape | 3x3 黑暗房间密室逃脱:引导式开场 + 三级卡关提示,钥匙→铁柜→保险丝→电箱→大门 | 四向滑=移动,单击=检查/重听环境音,双击=使用物品/背包兜底 | `web/escape/` | [01-escape-redesign.md](docs/design/01-escape-redesign.md) | 引导 8 步、解谜链、撞墙、卡关提示计时、双击兜底 |
| 音序回响 simon | 音频记忆:听手势音序列复现,复活机制(机会重听),全程无 BGM | 六手势全是答题输入;input 阶段双击=重听(期望 doubletap 时=答题,round2 裁决①) | `web/simon/` | [02-simon-redesign.md](docs/design/02-simon-redesign.md) | 教学 6 手势、复活序列不变、双击上下文判定、速度曲线 |
| 节拍行者 rhythm | 跟随领奏:听 1 小节节奏型在下一小节跟打,3 曲目(90/105/120 BPM)解锁制 | 四向滑+单击+双击全是演奏输入;无临近 down 音符时下滑=菜单(折中) | `web/rhythm/` | [03-rhythm-rebuild.md](docs/design/03-rhythm-rebuild.md) + voice-ids | Perfect/Good/Miss 窗口、tap 300ms 补偿、菜单暂停 BGM 断点续播、下滑折中 |
| 盲航 space | 太空盲飞:听方位呼啸**同向**滑闪避陨石,单击加速双击护盾,60s 保护期 | 四向滑=同向闪避;无下方陨石时下滑=菜单(折中) | `web/space/` | [04-space-rebuild.md](docs/design/04-space-rebuild.md) + voice-ids | 演练做错重教、保护期撞不掉血、同向判定、归因语音、里程碑 |
每游戏目录下还有自带 README.md(玩法说明)。**试玩通过标准(测试断言的设计依据)**:[docs/design/13-playtest-criteria.md](docs/design/13-playtest-criteria.md)。
## 5. 测试与质量
### 5.1 无头试玩测试原理
`web/<game>/test/playtest.mjs`(范本注释见 rpg 版头部):用 Node 直接加载**真实**的 `game.js` 和**真实**的引擎模块(`engine/audio.js`、`settings.js`、`haptics.js`、`vendor/soundtouch.js`),只 mock 浏览器底座——`window/document/navigator/localStorage/fetch/AudioContext` 最小接口(fetch 返回带时长的假 buffer,voice 链由引擎真实的结束定时器推进)。**虚拟时钟** patch `setTimeout/setInterval/performance.now/ctx.currentTime`(可快进卡关计时器/保护期,零真实等待)。手势直接注入 `game.onGesture()`(引擎回调路径),随机性用种子 PRNG 保证可重复。退出码 0 = 全绿。
### 5.2 怎么加断言
- 新功能:先查 [13-playtest-criteria.md](docs/design/13-playtest-criteria.md) 对应游戏的章节有没有该行为的检查单条目;没有就按"关键路径 / 边界断言 / 全局通用"三类补一条,再在 playtest.mjs 里实现。
- 新游戏:复制任一现有 playtest.mjs 的 mock 层(虚拟时钟 + 引擎 mock 是通用的),只重写游戏特定的路径断言;断言清单先在 13 号文档登记。
- 重构已知偏差时:13 号文档里有 `known-issue` 标记的预期失败断言,修正落地后翻正。
### 5.3 其他质量手段
- JS 语法校验:`tools/node/bin/node --check web/<game>/game.js`。
- 资产终检:`tools/check_all_assets.py`(§3.4)。
- 真机听测 checklist(听感参数只能真机验):[docs/design/roadmap.md](docs/design/roadmap.md) §4。
## 6. 已知问题与限制
| 问题 | 现状 | 后续处理建议 |
|---|---|---|
| ~~引擎无公开 `isVoicePlaying`~~ | **已解决(R7)**:`audio.isVoicePlaying()` 公开,游戏层全部收编 | — |
| ~~长按快进无 per-game 开关~~ | **已解决(R7)**:`audio.setRateBoostEnabled(false)`,rhythm/space 演奏期已豁免 | — |
| 向导 earcon 为运行时合成音 | 音色是「可用」级不是「精美」级(正弦/三角/方波包络) | 若升级为录制品 earcon:保持 8 音词表与参数边界不变(14 号文档 §2),只换渲染后端 |
| escape「需要帮助吗」问而不等 | P1 终评唯一「擦边当白痴」时刻 | v2 手势宪法专项:真问答 + PLAY 期目标重听入口 |
| space/simon 无「局」与结算仪式;storyline 链尾无轻量 turn 信号、二周目重播开场教学;rhythm 教学首误先震后教 | round4 终评 P0 全部裁定入 v2(research/04-playtests/round4/synthesis.md §2) | L5 会话层专项 + 微 polish 清单 |
| 语速上限 2.2(视障档) | P1 要求 3x+ | 需真机人耳验证 SoundTouch 高 tempo 质量,勿盲上 |
| iOS 无震动 | `haptics.js` 特性检测静默 no-op;**设计裁定:绝不回退提示音**(提示音混淆是用户反馈⑦根因) | RPG 无声敌人 iOS 不可格挡由「防御指令」兜底(05-rpg-addendum §2.2);保持现状 |
| SoundTouch 走 ScriptProcessorNode | 有固定处理延迟;voice 变速不变调用它(`engine/vendor/soundtouch.js`,**LGPL 许可**) | 功能正常不优先动;若换 AudioWorklet 需重测语速档;商业化注意 LGPL 声明义务(§7) |
| 菜单约定 RPG 豁免 | 全球模态菜单=单击循环/双击确认;RPG 探索态菜单刻意保持左右滑+单击(与探索范式同构,round2 裁决②) | 不是缺陷,不要"统一"它;测试断言按豁免写 |
| 服务器玩具级认证 | PIN 明文、token 不过期、HTTP 明文 | 家庭内网可接受;**公网化前必须**重做(PIN 哈希、token 过期、HTTPS),见 roadmap §5 |
## 7. 路线图
完整版:[docs/design/roadmap.md](docs/design/roadmap.md)。摘要:
0. **交互研究 v2 清单**(round4 终评裁定移交,详见 [research/04-playtests/round4/synthesis.md](research/04-playtests/round4/synthesis.md) §5):
- **会话层专项**:space/simon 定义「局」与结算仪式(参照 rhythm 范本);storyline 链尾轻量 turn earcon + 二周目跳过已听教学;rhythm 教学首误免震先教。
- **手势宪法专项**:escape PLAY 期目标重听入口;「需要帮助吗」改真问答;全线重听键统一评估(longpress 候选)。
- **场景参数包 A/B/C/D**([research/03-schemes/schemes.md](research/03-schemes/schemes.md) §3 分期裁定):通勤两遍式播报 / 摸鱼震动语言 / 睡前定时器 / 下班容错档——入口显式选择+记忆,不做自动切换。
- **语速 3x+**:真机人耳验证 SoundTouch 高 tempo 质量后再上。
1. **RPG 第二/三章**(内容灌入,模式已定型):ch2《腐沼泽》(毒状态、蛊师先攻、Boss 召唤二阶段);ch3《无瞳峰》(无声前摇敌人→终 Boss 三阶段全无声,震动格挡是高潮机制)。需策划补发两章台词表 → 音频录制 → 开发灌入。新台词必须同步向导规范(00 文档 §6)。
2. **storyline 打磨**:菜单统一到全球约定;knowTrap 死标记修复(只写不读,需在北区节点接入或删除);ui_confirm/ui_menu 提示音排查替换;结局 X/4 轻量进度。
3. **存量打磨小项**:rhythm 结算末位语音修正(`no_more_song` 补录)、escape PLAY 中回大厅入口、大厅设置试听句。
4. **商业化前置清单**:Stable Audio 3 / Mureka / Qwen3-TTS / NotoSansSC(OFL)四项许可确认与凭证落盘 + **soundtouch.js 的 LGPL 声明义务**(About 页标注库名与许可)+ 隐私政策(用户系统公网化前置)。
## 8. 协作约定
### 8.1 git 规范
- **密钥绝不入库**:`env.d/sfx.sh`、`env.d/mureka.sh`(真实 token/key)已被 .gitignore 排除;只提交 `*.example.sh` 模板。key 泄露去对应平台 Dashboard 吊销换新。
- .gitignore 还排除:`models/`(13GB HF 缓存)、`.venv-tts/`、`tools/stable-audio-3/.venv/`、`tools/bin/`(ffmpeg)、`tools/jdk17/`、`tools/android-sdk/`、`tools/node/`、`tools/bgm_backup/`、`tools/mureka_out/`(原始 flac)、`tools/samples/`、`.gpu.lock`、Android 构建产物。
- **中间产物不入库**:staging wav(`tools/gen_voice_dual_wav/`)、`tools/asset_fix_backup/` 等留本地供断点续跑,不进仓库(已 ignore 或保持 untracked,提交前 `git status` 自查)。
### 8.2 目录红线
- 资产生成脚本放各游戏 `gen/` 或 `tools/`,**可复现是硬要求**——任何入库音频都必须能从脚本重新生成。
- `web/engine/` 是共享引擎,改动要同步更新 [docs/web-engine-api.md](docs/web-engine-api.md) 并跑全部 6 款试玩测试。
- 不改 `docs/design/` 下的裁定记录(round*-review),新结论写新文档。
### 8.3 文档更新义务
- 改玩法/手势/震动语义 → 更新 `docs/design/00-global-ux.md` 与对应游戏设计文档。
- 新增/重录语音 → 台词先进对应 `*-voice-ids.md`(id + 全文 + instruct),再进 `gen_voice_dual.py` 台词表;两表必须一致。
- 音频轮次结束 → 写 `docs/audio/roundN-report.md`(统计、QC、给开发的接线约定),并跑终检更新 `final-asset-check.md`。
- 资产清单变动 → 更新 `docs/audio/asset-manifest.md`。
---
*本文最后更新对应 commit 9a915d6 之后的仓库状态(2026-08-30)。如发现与代码不符,以代码为准并修正本文。*