# SoundGame 交接文档(HANDOVER) > 接收方:即将接手开发、没参与过本项目的同事。读完本文 + 跟随链接即可独立上手。 > 本文是**总入口**:细节一律链接到专项文档,不复制。文中路径除注明外均为仓库相对路径(仓库根 = `/home/ubuntu/SoundGame`)。 ## 0. 项目一句话 11 款纯音频 HTML5 游戏:屏幕只有封面图,操作只有 6 种手势(上/下/左/右滑、单击、双击),一切靠音频呈现。纯 vanilla JS ES module,**无构建步骤、无 npm 依赖**,手机浏览器打开即玩。全部对白由本地 Qwen3-TTS 双性别生成,音效由 Stable Audio 3 + 程序合成,BGM 由 Mureka API 生成。游戏阵容:6 款首发(rpg/storyline/escape/simon/rhythm/space)+《围猎》联机协作(纯音频 MMORPG 路线第一阶段切片)+ new8 四批 8 款 RPG(radio/dungeon/abyss/detective/cipher/teahouse/keeper/bridge,全部经多轮玩家代理迭代裁定可交付)。**交互层按 26 号交互手册由引擎六模块统一承载**(发言权/回执/三档提示/迷茫接管/手势阶梯/输入管道,`web/engine/{floor,receipts,hints,confusion,novice,pipeline}.js`;2026-10 全部 15 款完成深度落地,施工单见 `docs/design/26-apply-*.md`)。旧「向导层」guide.js 仍服务未迁移场景,其设计依据与验证过程见 `research/`。 ## 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 radio dungeon; 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 行为断言) tools/node/bin/node web/harness/engine-voice.test.mjs # 引擎 voice 句尾保真专项(见 §6) ``` 退出码 0 = 全绿。当前 6 款 + 向导专项全部通过。**注意:playtest 一律在 setup 里 `settings.set({guide:'off'})` 验证纯玩法逻辑;向导行为断言只住在 guide.test.mjs。** ### 1.4.1 玩家感知转写器(交互研究的测量仪器) ```bash tools/node/bin/node web/harness/transcribe.mjs # 产物: research/04-playtests/transcripts/.md ``` 把一局游戏对玩家的全部输出(每句语音全文/音效/BGM/震动/静默段/缺资产)转成时间轴日志——**无法真听音频的评审(人或 agent)靠它审交互**。会话剧本在 `web/harness/sessions/.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 --only ` → ④ 跑 `tools/check_all_assets.py` | | 加一款新游戏 | 复制模板:`cp -r web/template web/`;接线方式与目录约定见 [docs/web-engine-api.md](docs/web-engine-api.md) §快速开始;手势/震动/菜单遵守 [00-global-ux](docs/design/00-global-ux.md);大厅 `web/index.html` 加卡片;写 `web//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(滑动识别,内置 swipe 震动) → pipeline.js 输入管道(26 号:新手门→迷茫信号→防连点→发言权→等待点限制) → game.onGesture('left')(游戏逻辑:查移动) → audio.play('sfx/parry')(sfx 层即发即弃)+ vibrate()(语义震动) → 状态推进(计时器 / voice onComplete 链 / setState) ``` ### 2.1 架构图 ``` 浏览器(手机/桌面) └── web/index.html 游戏大厅:设置面板(音色/语速/BGM 音量)+ 登录 + 进度卡片 └── web// 每游戏一个目录: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、.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//audio/ ├── bgm/*.ogg|m4a 背景/状态音乐(循环) ├── voice/male|female/ 旁白/系统音双性别(两目录 id 集合完全一致) ├── voice/.* 角色/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 双击窗口关闭才能确定单击。**26 号落地后,叙事/探索类游戏一律 `doubleTapWindow: 0`(单击零延迟、无双击)**;双击是核心玩法的游戏(space 护盾、hunt 旋风斩)在手势阶梯阶段 ≥3 后才恢复双击窗口(`pipeline` 的 `doubletapCore`),此时单击延迟是该玩法的既定代价。 - **为什么引擎管手势震动、游戏管语义震动**: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. 六款游戏逐个简介 手势全局约定(26 号宪法):单击=继续/确定、左右滑=选择/移动、上滑=我在哪(阶段 1 解锁)、下滑=菜单(阶段 2)、双击=重听(阶段 3;未解锁按单击处理);四向滑动是玩法的游戏帮助换到长按(00 文档 §5 / 26 号 §4.3)。 | 游戏 | 玩法一句话 | 手势要点 | 目录 | 设计文档 | 试玩测试覆盖 | |---|---|---|---|---|---| | 剑与声 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//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.js`。 - 引擎 voice 句尾保真:`tools/node/bin/node web/harness/engine-voice.test.mjs` (I1 源未耗尽不得结算 / I2 耗尽后排空窗才断开 / I3 mock 零消耗走旧路径; 2026-09 真机人耳反馈固化,改动 `audio.js _finishVoice` 必跑)。 - voice 资产尾部静默审计:`.venv-tts/bin/python tools/audit_voice_tails.py` (量化尾部裁剪松紧;注意判读口径——尾静默紧≠剪字,句尾完整性验收在引擎层)。 - 资产终检:`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 演奏期已豁免 | — | | ~~voice 句尾剪字(每句末尾音节缺失)~~ | **已根治(2026-09 真机人耳反馈,三修)**:一修固定排空窗(手机端未交付量浮动,不够);二修 onEnd 完成信号(仍不解决交付缺失);三修定位真根因——**SoundTouch Stretch 源结束不冲刷最后一个小节,句尾 0.1-0.25s 任何平台都不会播出**,根治 = 源尾垫 0.25s 静音推出真实句尾 + onEnd 驱动完成 + 1.5s 兜底。回归 `web/harness/engine-voice.test.mjs`(PAD+I1-I3);live 验证 span 8.57s→9.04s(≥文件时长 8.80s);全 8 游戏 live 巡检 225 句对账:自然结束句 210/210 完整,15 条短跨度逐条分诊=输入抢占(space 教学错手重教×12/simon 单击跳句×2,零手势静听复测完整)或探针对齐容差(rpg×1 差 0.06s),引擎零截断 | 引擎层已固化,新游戏零改动继承;live 探针同步适配(清扫器守卫);合成侧经 ASR 抽查排除剪字(尾静默紧是裁剪工艺,判读口径见 `tools/audit_voice_tails.py` 头注) | | 向导 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)。如发现与代码不符,以代码为准并修正本文。*