297 lines
24 KiB
Markdown
297 lines
24 KiB
Markdown
# SoundGame 交接文档(HANDOVER)
|
||
|
||
> 接收方:即将接手开发、没参与过本项目的同事。读完本文 + 跟随链接即可独立上手。
|
||
> 本文是**总入口**:细节一律链接到专项文档,不复制。文中路径除注明外均为仓库相对路径(仓库根 = `/home/ubuntu/SoundGame`)。
|
||
|
||
## 0. 项目一句话
|
||
|
||
6 款纯音频 HTML5 游戏:屏幕只有封面图,操作只有 6 种手势(上/下/左/右滑、单击、双击),一切靠音频呈现。纯 vanilla JS ES module,**无构建步骤、无 npm 依赖**,手机浏览器打开即玩。全部对白由本地 Qwen3-TTS 双性别生成,音效由 Stable Audio 3 + 程序合成,BGM 由 Mureka API 生成。
|
||
|
||
## 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
|
||
```
|
||
|
||
退出码 0 = 全绿。当前 6 款全部通过。
|
||
|
||
### 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× 快进
|
||
├── settings.js 三项全局设置(voice/speed/bgm),localStorage 持久化
|
||
├── 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. 已知问题与限制
|
||
|
||
| 问题 | 现状 | 后续处理建议 |
|
||
|---|---|---|
|
||
| iOS 无震动 | `haptics.js` 特性检测静默 no-op;**设计裁定:绝不回退提示音**(提示音混淆是用户反馈⑦根因) | RPG 无声敌人 iOS 不可格挡由"防御指令"兜底(05-rpg-addendum §2.2);保持现状 |
|
||
| SoundTouch 走 ScriptProcessorNode | 有固定处理延迟;voice 变速不变调用它(`engine/vendor/soundtouch.js`,**LGPL 许可**) | 功能正常不优先动;若换 AudioWorklet 需重测语速档;商业化注意 LGPL 声明义务(§7) |
|
||
| 引擎无公开 `isVoicePlaying` | 游戏层读私有字段 `audio._voice` 判断语音是否在播 | 下轮引擎迭代加公开 getter,游戏层替换;勿在更多地方扩散私有字段引用 |
|
||
| 长按快进无 per-game 开关 | 长按=voice 临时 1.7× 是引擎全局行为;12 号文档 §2.2 裁定的 rhythm 演奏期/space 对局豁免**尚未实现** | 引擎加 `setRateBoostEnabled(false)` 类开关,rhythm/space 注册豁免;落地后跑 13 号文档全局断言 |
|
||
| 菜单约定 RPG 豁免 | 全球模态菜单=单击循环/双击确认;RPG 探索态菜单刻意保持左右滑+单击(与探索范式同构,round2 裁决②) | 不是缺陷,不要"统一"它;测试断言按豁免写 |
|
||
| 服务器玩具级认证 | PIN 明文、token 不过期、HTTP 明文 | 家庭内网可接受;**公网化前必须**重做(PIN 哈希、token 过期、HTTPS),见 roadmap §5 |
|
||
|
||
## 7. 路线图
|
||
|
||
完整版:[docs/design/roadmap.md](docs/design/roadmap.md)。摘要:
|
||
|
||
1. **RPG 第二/三章**(内容灌入,模式已定型):ch2《腐沼泽》(毒状态、蛊师先攻、Boss 召唤二阶段);ch3《无瞳峰》(无声前摇敌人→终 Boss 三阶段全无声,震动格挡是高潮机制)。需策划补发两章台词表 → 音频录制 → 开发灌入。
|
||
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)。如发现与代码不符,以代码为准并修正本文。*
|