- 真根因(live span 8.57s < 文件 8.80s 铁证):SoundTouch Stretch 源结束时不冲刷 内部最后一个小节(~1 sequence),句尾 0.1-0.25s 从未交付音频图——任何平台皆然, ASR 因容错转写仍 sim=1(转写评审盲区的又一实证)。一修固定 300ms 排空窗只是 把这段不存在的交付空等成静音;二修 onEnd 保证「已交付必播完」但交付不了这段 - 三修:源尾垫 VOICE_TAIL_PAD_SEC(0.25s) 静音把真实句尾推出管线;完成 = onEnd (平台无关,disconnect 已交付帧仍播);1.5s 兜底;顶掉复核移至新句数据访问前 (垫长拷贝的 getChannelData 先于杀旧句会打乱探针时序) - live 探针适配:尾部垫使 SoundTouch 读未注册 buffer、gcd 抽读信号消失—— 清扫器加「仍有连接中语音 SPN 则不关段」守卫,断开即移出追踪集合 - engine-voice.test:PAD+I1/I2/I2b/I3 五组 19 断言(含垫长存在性、onEnd 结算、 兜底不早于 1.5s);10 套件全绿 - live 复验(男声 p1):span 8.57→9.04s(≥文件 8.80s),ASR sim=1 verdict=OK
29 KiB
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。
1.2 密钥(只在需要重新生成资产时才配)
密钥文件被 .gitignore 排除,绝不入库;模板里有获取链接:
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/sfx.md。
1.3 跑起来
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。
1.4 跑一遍试玩测试
每款游戏都有无头试玩测试(mock 浏览器 + 虚拟时钟,模拟玩家通关,见 §5):
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 玩家感知转写器(交互研究的测量仪器)
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 顺手验证:单条语音再生成冒烟
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 §快速开始;手势/震动/菜单遵守 00-global-ux;大厅 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 号文档 §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 号文档 §4) |
1.8 第一周建议路径
- 第 1 天:跑通 §1.3 + §1.4;大厅里把 6 款游戏各玩 5 分钟(戴耳机)。
- 第 2 天:通读 docs/web-engine-api.md + 00-global-ux,对照
web/template/跑一个 hello-game。 - 第 3 天:挑一款游戏读 game.js + 对应设计文档 + playtest.mjs,改一个小参数跑测试验证。
- 第 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/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 §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。新工作全部发生在 web/。
3. 音频资产制作流水线(接手重点)
总规范:docs/asset-pipeline.md;资产总账与音色分配:docs/audio/asset-manifest.md;各轮生产报告(round1-6):docs/audio/。设计侧台词表(id + 全文 + instruct,录什么看这些):docs/design/*-voice-ids.md(03/04/05 号系列)。
3.1 TTS 对白(Qwen3-TTS CustomVoice,本地 GPU)
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 + 程序合成)
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 §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)
source env.d/mureka.sh
.venv-tts/bin/python tools/mureka_gen.py # 调用/选候选/下载,用法见脚本头注释
- 全流程与每次调用记录(task id、成本):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。
3.4 资产终检
.venv-tts/bin/python tools/check_all_assets.py # 全项目 928×2 文件:双格式/0字节/解码/性别集合一致性
最近一次全绿报告:docs/audio/final-asset-check.md。改任何资产后必跑。
4. 六款游戏逐个简介
手势全局约定:上滑=帮助/状态、下滑=菜单、单击=确认/继续、双击=重听、左右滑=选择/移动;以滑动为玩法核心的游戏有豁免(00 文档 §5)。
| 游戏 | 玩法一句话 | 手势要点 | 目录 | 设计文档 | 试玩测试覆盖 |
|---|---|---|---|---|---|
| 剑与声 rpg | 纯音频回合制武侠 RPG:节点图探索 + 听前摇双击格挡的回合制战斗 + 升级装备三章剧情 | 左右滑=选选项/招式,单击=确认/出手,双击=格挡/重听,上滑=状态,下滑=菜单/逃跑 | web/rpg/ |
05-rpg.md + chapter1/voice-ids/addendum + 11 战斗重构 | 第一章通关全链(村庄→商店→教学战锁血→支线→连战→Boss 二阶段)、格挡 0.3 减伤、存档继续 |
| 声命线 storyline | 末世互动广播剧:3 幕 8 抉择 4 结局,左右滑做选择 | 单击=继续,双击=重听节点,左右滑=抉择,上滑=帮助+进度,下滑=菜单 | web/storyline/ |
docs/games/storyline.md(旧)+ 打磨项见 roadmap §2 | 抉择路径到达结局、双击重听、菜单返回不丢节点、剧情标记断言 |
| 暗室 escape | 3x3 黑暗房间密室逃脱:引导式开场 + 三级卡关提示,钥匙→铁柜→保险丝→电箱→大门 | 四向滑=移动,单击=检查/重听环境音,双击=使用物品/背包兜底 | web/escape/ |
01-escape-redesign.md | 引导 8 步、解谜链、撞墙、卡关提示计时、双击兜底 |
| 音序回响 simon | 音频记忆:听手势音序列复现,复活机制(机会重听),全程无 BGM | 六手势全是答题输入;input 阶段双击=重听(期望 doubletap 时=答题,round2 裁决①) | web/simon/ |
02-simon-redesign.md | 教学 6 手势、复活序列不变、双击上下文判定、速度曲线 |
| 节拍行者 rhythm | 跟随领奏:听 1 小节节奏型在下一小节跟打,3 曲目(90/105/120 BPM)解锁制 | 四向滑+单击+双击全是演奏输入;无临近 down 音符时下滑=菜单(折中) | web/rhythm/ |
03-rhythm-rebuild.md + voice-ids | Perfect/Good/Miss 窗口、tap 300ms 补偿、菜单暂停 BGM 断点续播、下滑折中 |
| 盲航 space | 太空盲飞:听方位呼啸同向滑闪避陨石,单击加速双击护盾,60s 保护期 | 四向滑=同向闪避;无下方陨石时下滑=菜单(折中) | web/space/ |
04-space-rebuild.md + voice-ids | 演练做错重教、保护期撞不掉血、同向判定、归因语音、里程碑 |
每游戏目录下还有自带 README.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 对应游戏的章节有没有该行为的检查单条目;没有就按"关键路径 / 边界断言 / 全局通用"三类补一条,再在 playtest.mjs 里实现。
- 新游戏:复制任一现有 playtest.mjs 的 mock 层(虚拟时钟 + 引擎 mock 是通用的),只重写游戏特定的路径断言;断言清单先在 13 号文档登记。
- 重构已知偏差时:13 号文档里有
known-issue标记的预期失败断言,修正落地后翻正。
5.3 其他质量手段
- JS 语法校验:
tools/node/bin/node --check web/<game>/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 §4。
6. 已知问题与限制
| 问题 | 现状 | 后续处理建议 |
|---|---|---|
isVoicePlaying |
已解决(R7):audio.isVoicePlaying() 公开,游戏层全部收编 |
— |
已解决(R7):audio.setRateBoostEnabled(false),rhythm/space 演奏期已豁免 |
— | |
已根治(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) |
引擎层已固化,新游戏零改动继承;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。摘要:
- 交互研究 v2 清单(round4 终评裁定移交,详见 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 §3 分期裁定):通勤两遍式播报 / 摸鱼震动语言 / 睡前定时器 / 下班容错档——入口显式选择+记忆,不做自动切换。
- 语速 3x+:真机人耳验证 SoundTouch 高 tempo 质量后再上。
- RPG 第二/三章(内容灌入,模式已定型):ch2《腐沼泽》(毒状态、蛊师先攻、Boss 召唤二阶段);ch3《无瞳峰》(无声前摇敌人→终 Boss 三阶段全无声,震动格挡是高潮机制)。需策划补发两章台词表 → 音频录制 → 开发灌入。新台词必须同步向导规范(00 文档 §6)。
- storyline 打磨:菜单统一到全球约定;knowTrap 死标记修复(只写不读,需在北区节点接入或删除);ui_confirm/ui_menu 提示音排查替换;结局 X/4 轻量进度。
- 存量打磨小项:rhythm 结算末位语音修正(
no_more_song补录)、escape PLAY 中回大厅入口、大厅设置试听句。 - 商业化前置清单: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 并跑全部 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)。如发现与代码不符,以代码为准并修正本文。