Files
SoundGame/docs/design/17-abyss.md
T
xsl 566241e05d feat(platform/P1): 配对码跨设备 + 认领打磨 + 键盘语音双套资产(两 agent 并行 + 集成收口)
配对码与认领(B):
- POST /api/pair/start|join:6 位码 10 分钟单次有效、仅存内存零泄露面、5 连错 per-IP 封锁 10 分钟;join=新设备档案按桶 LWW 并入老档案+token 改绑(复用 claim-merge);日志脱敏
- 大厅:生成配对码(speechSynthesis 逐位朗读+aria-live+重听)/从其他设备转入(one-time-code 输入框)/从本机移除/401 过期自愈引导/aria 补全/玩家名可听化
- api-smoke 12/12(配对全流程/频控/封锁/过期自愈/移除/digitsToCn)+ CDP 真浏览器 E2E 22/22

键盘语音双套资产(A,路线 a):
- 164 变体句(8 游戏 grep 实测,超出调研预估 153:含轻触/点两下/按住变体)×2 性别=328 生成 656 文件 36.9 分钟;触屏主资产零字节改动(PCM 逐样本比对后还原)
- 引擎 _candidates 三跳路由 key→gender→平铺(inputMode 跟随);缓存键 mode|gender|id;engine-input 新增 K9 路由断言(72 条)
- check_all_assets 增 key 列(两性别一致且 ⊆ 主集)8 游戏全绿;voice_text.json 增 __key__ 表;live control.mjs key 会话对照键盘措辞验收(集成)
- voice-ids 文档:8 游戏键盘变体小节由 KEY_LINES 程序化生成(与台词表逐字断言一致);补齐 storyline/escape/simon 三个历史缺失文档;design README 增 new8 索引
- mock 适配:playtest persona 加 maxTouchPoints=1 保持触屏链断言语义零改动

回归:12 套件全绿(8 playtest + guide 122 + engine-voice 19 + engine-input 72 + api-smoke 12/12)
同批入库:批次 2/3 已完稿设计文档(17-abyss/18-detective/19-cipher 全套,20-22 在途)
2026-09-10 00:43:23 +08:00

47 KiB
Raw Blame History

17 · 《深海回音》(abyss) — 深海救援叙事 RPG 设计文档

给开发的实现要点摘要

  1. 叙事模式(声命线范式,radio 同骨架):节点链 onComplete 串行 + seqToken 打断作废 + pendingChoice 缓存;复制 web/radio/ 结构起步,状态机 6 宏状态(INTRO/DIVE/COMMS/SURFACE/ENDING + MENU 覆盖层)。
  2. 手势零豁免:全部走全局默认映射(单击=继续/检查(搜索等待=发声呐脉冲,宪法 §5.1「检查」义,escape 先例)/跳句、双击=重听、左右滑=抉择、上滑=状态、下滑=模态菜单、长按=引擎快进)。
  3. 台词依据 17-abyss-voice-ids.md(148 句:双性别 127 + 平铺 NPC 21);NPC 水声电台滤波在资产侧 ffmpeg 带通(radio 先例),引擎零改动。
  4. 氧气=步进资源非实时倒计时:只在潜次边界与阈值跨越时播报(分档整句、账目真实);软失败=「被迫取消第四潜/单载」而非玩家死亡,结算链完整播出(含 800ms 手势死窗)。
  5. 声呐双通道:回波类信息音与语音绝不重叠(游戏层 sonarGate 空闲门,R1 规则 §6.2);并发声流 ≤2。
  6. 章程任务 N2(research/new8/00-program.md §2):单局 15-25 分钟、9 抉择点(实走 7-9)、4 结局、分支局部化。
  7. 断言清单住本文档 §9(radio §20 先例);13 号文档已登记指针(§21)。

1. 概述

  • 一句话:你是深潜救援员,声呐里是被困海沟的潜艇「海燕号」——氧气在倒数,每次下潜都是抉择:先救谁、花多少气、留不留、上不上去。
  • 题材(声音即世界):黑暗深海里视觉归零,声呐回波=空间、电台人声=生命、氧气=代价——「用耳朵救人」与纯音频载体天然同构。声呐脉冲/回波/管路敲击/船体呻吟是叙事本体,不是装饰。
  • 单局:一次完整救援(一条抉择路径)20-22 分钟;四次下潜共享主干,分歧局部化在每潜内部;9 个抉择点(单局实走 7-9 个),4 结局。
  • 核心循环:下潜(声呐搜索拍:单击发脉冲→回波→调度解读)→ 通讯(船员对话+抉择)→ 带人上浮 → 水面结算(氧气扣账+档位播报)→ 下一潜。跨潜积累氧气存量与船员生死/好感,最后一潜的氧气余量决定救援形态(双载/单载/取消),收队前 p9 决定你自己的心结。
  • 与 radio 的差异点(骨架同、压力源不同):radio 零压力(口碑只涨不跌);abyss 引入氧气稀缺——但全部宽限化:无实时倒计时、无中途死亡、软失败只损失「机会」不损失「已有」、最优省气路径恰好全员生还(P4 友好默认)。

2. 状态机

2.1 状态列表

状态 内容 BGM guide.state
INTRO 开场链:甲板口播 + 一句规矩 + 今晚目标 bgm/deck explore
DIVE 下潜过程:下潜链(auto)→ 搜索等待(单击=发脉冲,声呐主导)→ 回波+接通 bgm/dive explore;搜索等待由 turn cue 承担
COMMS 通讯叙事:船员对白链 + 抉择点 + 结果 bgm/comms explore;抉择点=choice
SURFACE 上浮结算:出水确认 + 氧气扣账/档位 + 补给(D2 后),自动链 bgm/deck settle
ENDING 结局链 + 尾声回响(epilogue),结算态 bgm/ending settle
MENU 模态覆盖层(任意叙事态下滑呼出,暂停一切链) bgm/deck(低响度淡入) menu

2.2 转移图(文本)

                     ┌──────────── 结算单击=新救援 ─────────────┐
                     ▼                                         │
 INTRO ──链完单击──> DIVE(1) ──脉冲找到──> COMMS(1) ──链完──> SURFACE(1) ─┤→ DIVE(2)
                     │下潜链 auto;搜索等待=单击脉冲              │       …(D2/D3 同型)…
                     └─────────────────────────────────────────┘
 SURFACE(3) ──氧气门──┬─ oxy≥4: DIVE(4 双载)  ──链完──> SURFACE(4) ──链完──> 签收 ◆p9
                      ├─ oxy=3: DIVE(4 单载: p7_chen|p7_zheng) ──链完──> SURFACE(4) ─┘
                      └─ oxy≤2: 终局取消链(dv4_none→gao_final) ─────────────────────┘
                                                                   ▼
                                        d9 结果链 ──> ENDING(e1..e4 + ep 回响链)

 任意叙事态(INTRO/DIVE/COMMS/SURFACE/ENDING):下滑 → MENU(模态)
   MENU:单击=循环切换选项 → 双击=确认执行 → 上滑=帮助 → 下滑/「回到水下」项=关闭回原状态(重播当前节点)
  • INTRO/DIVE/COMMS/SURFACE/ENDING 均为节点链驱动(radio playNode 模式);下潜链与上浮结算链 auto:true,COMMS 叙事节点链末等待单击(radio 实现核对 #1 同口径)。
  • SURFACE 自动链 ≤15s:扣账句(d*_surf)→ 补给句(仅 D2 后)→ 档位句(跨档才播)→ 直接进下一 DIVE;第四潜位置由氧气门分三形态(§4.3)。
  • 终局取消链与结局链入口处盖 _settleGraceUntil = now+800ms 手势死窗(dungeon H1 热修同款),窗内手势一律吞掉,结算链完整播出。
  • MENU 打开时 guide.disarm() + 取消一切看门狗/自动链;关闭后重播当前节点(局面复述,radio closeMenu 先例)。

2.3 每状态手势映射(6+2 全覆盖,零豁免)

手势 INTRO DIVE(下潜/搜索) COMMS SURFACE ENDING MENU
上滑 帮助+状态,随后重播当前段 帮助+状态(潜次+氧档),留在搜索等待 帮助+状态,随后重播当前节点 帮助+状态,自动链继续 帮助+状态(结局名+氧档) 帮助(sys_help)
下滑 模态菜单 模态菜单 模态菜单 模态菜单 模态菜单 关闭菜单
左滑 无效 → error 震+gd_invalid 无效 → gd_invalid(喂无进展轨) 抉择=左 无效 → gd_invalid 无效 → gd_invalid 无效 → error 震
右滑 无效 → gd_invalid 无效 → gd_invalid(喂无进展轨) 抉择=右;ASK 态=新救援 无效 → gd_invalid 无效 → gd_invalid 无效 → error 震
单击 播放中=跳过本句;链末=开始下潜 播放中=跳过本句;搜索等待=发一枚声呐脉冲 播放中=跳过本句(p* 不可跳);链末=继续 跳过本句(自动链) 再来一局(新救援) 循环切换选项
双击 重听当前段 重听上一条回波+其解读句(尚无回波=无效,首潜前零静默) 重听当前节点台词(含抉择提示) 重听结算链 重听结局链 确认执行(菜单约定覆盖重听)
长按 引擎接管:旁白临时 1.7×(12 号 §2.2,叙事类不豁免) 同左 同左 同左 同左 同左(快进菜单语音)
长按松开 引擎接管:恢复 settings.speed 同左 同左 同左 同左 同左
  • 豁免登记:无。六个基础手势全部符合全局宪法默认语义——单击在搜索等待=「检查」(宪法 §5.1 原文即含检查,escape 检查房间同款);菜单走 §5.2 R3 模态约定(单击循环+双击确认)。
  • ASK(存档询问态,radio 同款):单击=继续上次 / 右滑=新救援;上滑/下滑/左滑/双击=无效(error 震+gd_invalid)。
  • 抉择 prompt(voice/p1..p9)播放中单击不可跳(PROMPT_RE 门)、左右滑缓存 pendingChoice 播完即生效(radio W2 契约照抄)。
  • 继承 radio G5 跳过公平契约原文:首播必完整(p 首播不可跳 / 链末关键句保护 / ASK 恢复首句锁)、复播可即掐(锁不随复播重新武装、链中段句可跳、复播滑动照常预缓存)*;p* 复播(双击重听/看门狗复述)仍不可跳、句尾生效。
  • 无效手势零静默:所有「无效」格均有 error 震 + gd_invalid(onceKey 同局限次,F1.4 idle-only:语音在播时跳过语音只发震)。
  • 键盘通道:三通道并行,游戏代码零改动;操作提示句按 inputMode() 选 _k 变体资产(§7.3、voice-ids 集中分组)。

3. 抉择树

3.1 全局骨架(四潜共享主干,分歧局部化)

INTRO: b_open → b_rule → b_goal → b_go ──> 下潜①
【D1 找船·教学潜】救小舟 · 2 抉择(p1/p2)──> SURFACE(1) ──> 下潜②
【D2 机舱·老白】危机拍#1 · 2 抉择(p3/p4)──> SURFACE(2·补给+3) ──> 下潜③
【D3 病舱·生死抉择】回波预警 · 2 抉择(p5/p6)──> SURFACE(3) ──氧气门──> 下潜④ 或 终局取消链
【D4 指挥舱·高潮】滑坡危机 · p7(双形态)+ p8 ──> SURFACE(4) ──> 签收 ◆p9(心结)──> ENDING

分支纪律:每潜内部分支、上浮时收敛到结算句 → SURFACE;跨潜只传标量(oxy、saved{}、stayer、5 个 flag),不生成组合节点。最坏路径与最好路径节点数同型(剧本 A 与剧本 C 深度相同)。

3.2 分潜结构(◆=抉择点,〔〕=条件差分)

【D1 找船·小舟】(教学潜)
下潜链 dv1_down → dv1_teach →【搜索等待:单击脉冲】→ echo_metal_l + dv1_metal(教「金属回波=钢板」)
  → dv1_link → COMMS: z1_a → z1_b → z1_knock(垫 pipe_knock)→ ◆p1
   ├左 听暗号: d1_listen → pipe_knock → d1_code(knowsPipe=true,-1 气)─┐
   └右 直接上: d1_up → z1_bye ─────────────────────────────────────────┤
                                                                       ▼
                                  小舟拉住你 → ◆p2
   ├左 等日志: d1_log(hasLog=true,-1 气)─┐
   └右 不等:   d1_nolog ────────────────────┴→ 上浮 → d1_surf(扣 3 格)→ 档位 → SURFACE(1)

【D2 机舱·老白】
dv2_down →【搜索:脉冲 → echo_debris+pipe_knock → dv2_found】→ bai_a → bai_b → ◆p3
   ├左 泄压慢撬: d2_pry →〔knowsPipe ? d2_pry_ok(-0): d2_pry_slow(-1)〕─┐
   └右 切割快切: d2_cut →【危机拍: danger 签名+spark_flash 前置 2s】→ d2_flash ─┤
                                                                               ▼
                                bai_out → ◆p4
   ├左 陪关阀门: d2_valve → valve_close → d2_valve_e(valve=true,-2)→ bai_thanks ─┐
   └右 直接上浮: d2_leave ──────────────────────────────────────────────────────────┴→ d2_surf
   → d2_supply + oxy_gain(应急瓶+3,全局唯一一次)→ 档位 → SURFACE(2)

【D3 病舱·陈医官/小郑(小郑无台词,吊床固定)】
dv3_down →【搜索:脉冲 → echo_groan → dv3_groan(船体呻吟预警)】→ chen_a → chen_b → ◆p5
   ├左 先带陈医官: d3_chen → chen_up → d3_chen_e(小郑留守)─┐
   └右 先带小郑:   d3_zheng → d3_zheng_e → chen_stay(stayer=chen)┤
                                                                  ▼
                                            ◆p6
   ├左 留备用瓶: d3_spare → d3_spare_e(spareGift=true,-2,floor 至 0 触发干涸链)─┐
   └右 约定来接: d3_promise ────────────────────────────────────────────────────────┴→ d3_surf → 档位 → SURFACE(3)

【SURFACE(3) 氧气门】oxy≥4 → D4 双载 | oxy=3 → D4 单载 | oxy≤2 → 终局取消链(dv4_none → gao_final,800ms 死窗)→ ◆p9

【D4 指挥舱·高船长】
dv4_down →【搜索:脉冲 → echo_groan 渐强 → 危机拍: danger+landslide 前置 2s → dv4_slide】→ gao_a → gao_b
  双载形态 → ◆p7(快慢浮)
   ├左 慢浮: d4_slow → d4_slow_e(-2)─┐
   └右 快浮: d4_fast → d4_fast_e ──────┤
  单载形态 → ◆p7_chen|p7_zheng(按 stayer 选提示,谁上)
   ├左 带船长: d4_pick_gao →〔stayer=chen ? chen_last : d4_stay_lost〕─┐
   └右 带留守者: d4_pick_chen|d4_pick_zheng → gao_last(p8 跳过)─────┴→ 直达 d4_surf
                                        ▼(船长在乘时)
              〔hasLog ? gao_confess : gao_c〕→ ◆p8
   ├左 说出来: d4_talk → gao_peace(gaoPeace=true)─┐
   └右 不问:   d4_silent ────────────────────────────┴→ d4_surf → 档位 → SURFACE(4)

【签收】g9_in → g9_knot → ◆p9
   ├左 取船钟(需 oxy≥1): d9_bell → bell_toll → d9_bello(bell=true)─┐
   └右 进医疗舱: d9_rest ────────────────────────────────────────────────┤
   〔oxy<1 时左路封锁: g9_dry 播出后自动走右,不摆假选项〕                ▼
ENDING: e*_a → e*_b(按 savedCount × p9 四选一)→ ep_lead → ep_*(按好感/存活/flag 选播)

3.3 分支局部化说明

  • 跨潜状态全部是标量:oxy(int)、saved(5 个 0/1)、stayer(null/chen/zheng)、flag 5 个(knowsPipe/hasLog/valve/spareGift/gaoPeace)+ p9 派生 bell。没有任何「潜 i 分支 × 潜 j 分支」组合节点。
  • 条件差分全部是节点内选播(radio w1_say/w1_say2 先例):d2_pry_ok/slow(knowsPipe)、gao_c/gao_confess(hasLog)、p7 双/单形态(氧气门)、p7_chen/p7_zheng 与留别句(stayer)、ep_* 选播。树形不变。
  • 树规模:148 句台词、约 70 个节点;任一路径实走 7-9 个抉择点(D4 取消路径少 p7/p8;单载右路少 p8)。

3.4 四结局达成条件

结局 条件 主题 开环钩子
e1 海燕归钟 saved=5 且 p9=左 全员生还+船钟出水,告别完整 「明天,想再潜一次」
e2 满载的黎明 saved=5 且 p9=右 人都救回来了,钟留在沟底 「半夜总听见钟在响」
e3 最后一潜 saved<5 且 p9=左 没能都救回,但下去敲响了钟 「钟声替他们响了一声」
e4 按规程上浮 saved<5 且 p9=右 规程之内,难过之外 「安静得像三年前那天」
  • 尾声回响(P2 回响感):epilogue 逐人点名——小舟/老白/陈医官/小郑/船长各按「好感/生死」双线播(voice-ids EP 组),沟底一句按 bell 二选一;玩家每一潜的救与错过都被点名(radio ep_* 同款)。

4. 数值设计

4.1 变量

变量 类型 初值 说明
oxy(氧气格) int 12 步进资源:只在事件点扣(下潜/抉择),无实时倒计时
saved map zhou:0 其余 0 小舟/老白/陈医官/小郑/高船长 各 0/1
stayer str null p5 后留守病舱者('chen'/'zheng')
knowsPipe/hasLog/valve/spareGift/gaoPeace/bell bool false p1 左/p2 左/p4 左/p6 左/p8 左/p9 左 置位
supply bool false D2 上浮后应急瓶已发(全局唯一)
endings{} / runs map/int — 结局收集与重玩计数(存档展示用)

4.2 抉择计分表(左=走心·多花气 / 右=克制·省气)

抉择 左(走心) 右(克制) 备注
p1 听暗号/直接上 -1 气,knowsPipe=true 0 左路获 D2 情报(下潜 EFF 的唯一免气左路)
p2 等日志/不等 -1 气,hasLog=true 0 hasLog 兑现 D4 船长坦白差分
p3 慢撬/快切 knowsPipe?0:-1 气 0 右路挂危机拍#1(火花虚惊,两路都活着)
p4 关阀门/直接走 -2 气,valve=true 0 左路兑现在回响(干净海)
p5 先带医官/先带小郑 0(chen 上,stayer=zheng) 0(zheng 上,stayer=chen) 唯一无气差的双义抉择;stayer 决定 D4 单载差分
p6 留备用瓶/约定来接 -2 气,spareGift=true(可触发干涸链) 0 左路兑现在留守者存活回响
p7 慢浮/快浮(双载) -2 气 0 右路兑现在 e1/e2 回响(医疗舱灯)
p7 带船长/带留守者(单载) 0 0 另一人随海燕号滑入沟底(措辞克制)
p8 说出来/不问 0,gaoPeace=true 0 hasLog 时 gao_confess 差分前置
p9 取船钟/进医疗舱 需 oxy≥1,bell=true 0 oxy<1 时左路封锁(g9_dry,不摆假选项)

4.3 氧气经济(单位/消耗/宽限/软失败)

项 规则
单位 「格」(内部 int)。初始 12(叙事=双瓶满气,够四次往返);D2 上浮后应急瓶 +3(oxy_gain 播报,全局唯一),总预算 15
固定消耗 每次下潜开始扣 3(往返);D4 双载额外 +1(慢浮+减压成本按 p7 计)
抉择消耗 见 §4.2;mid-dive 扣至负数一律 floor 到 0,不中断当前救援(人已挂上吊索,照常带上)
阈值播报 分档整句(下表),只在跨档时播(挂上浮结算链尾);上滑 status 随时可查;oxy_crit 各播报位附 warning 震(radio G2 同款)
第四潜氧气门 SURFACE(3) 结算时:oxy≥4 → 双载(带船长+留守者);oxy=3 → 单载(p7 谁上);oxy≤2 → 终局取消链(第四潜取消,船长与留守者随海燕号滑入沟底——措辞克制、零描写)
宽限设计 ① 学习期零惩罚:D1 两个左路合计 -2,恰好被 D2 后应急瓶 +3 兜底,教学潜永不亏局;② 到点不是死:软失败只损失「机会」(少带一人/少下一潜),已救上的人永不失去;③ 无实时倒计时、无 mid-dive 打断(P4 无高压);④ p9 左路是「氧气的礼物」——省下的气兑换终局抉择
干涸链(软失败结算) mid-dive floor 至 0 触发:dry_a →(当前救援照常完成)→ 上浮结算内 dry_b(归因真话:指向实际花掉最后两格的那个左选择)。链入口 800ms 手势死窗

氧气档位表(账目真实:每格取值下句义皆为真)

档 oxy 区间 整句 真实性核验
full ≥9(floor(oxy/3)≥3) 「气瓶还足,救得动。」 ≥3 潜气量 ✓
ok 6-8(floor=2) 「氧气还够两潜。」 恰可下 2 潜 ✓
low 3-5(floor=1) 「氧气告急,只够最后一潜。」 恰可下 1 潜 ✓
crit 0-2(floor=0) 「氧气见底,必须上浮。」 mid-dive=必须上浮 ✓ / 水面=一潜都下不去 ✓
  • 档位以 floor(oxy/3)(可下潜次数)划界而非绝对半数——句子说的就是判定用的(radio rep_low 教训内化:措辞与数值对得上)。
  • 低氧混音签名:tier=low/crit 期间 DIVE/COMMS 垫 breath_loop(低响度呼吸声,SA3 循环);引擎无运行时滤波,BGM 闷化降级为该呼吸层(显式降级,不阻塞管线)。

4.4 船员好感/存活矩阵

船员 好感来源(bond) 存活条件 回响句
小舟(声呐兵) p1 左 或 p2 左 恒活(D1 教学潜保底救上) ep_zhou_ok / ep_zhou_no
老白(轮机长) p3 左 或 p4 左 恒活(D2 恒可成——预算数学保证,见 §9 验算) ep_bai_ok / ep_bai_no
陈医官 p5 左(当场救上);或留守时 p6 左 p5 左即活;p5 右留守 → D4 双载或被选则活,否则失 ep_chen_ok / ep_chen_lost
小郑(无台词角色) —(吊床上的沉默存在,radio 老主播「带子里只有电流声」先例) p5 右即活;p5 左留守 → D4 双载或被选则活,否则失 ep_zheng_ok / ep_zheng_lost
高船长 p8 左(gaoPeace) D4 双载 或 单载选左则活;单载右/终局取消则失 ep_gao_peace / ep_gao_up / ep_gao_lost
  • 好感只影响回响选播(情绪差分),不影响结局判定——结局由 savedCount × p9 决定,账目单一可验算。
  • 生死分支覆盖 3 人(陈医官/小郑/高船长),措辞全部克制(「滑进了沟底」「灯还亮着」),无临场描写;失败归因走干涸链/取消链的真话句。

4.5 氧气收支验算(设计期穷举,playtest 剧本 A-D 引用)

设 lefts = 前 3 潜左路气耗之和(p7/p9 不在前 3 潜):

  • SURFACE(3) 时 oxy = 15 − 9(基础)− lefts = 6 − lefts → 双载 ⟺ lefts≤2;单载 ⟺ lefts=3;取消 ⟺ lefts≥4。
  • 双载收队 oxy_end = 2 − lefts(p7 右)或 0 −(lefts−2)(p7 左,floor 0)→ p9 左可用 ⟺ lefts≤1。
  • 单载收队 oxy_end = 3 − lefts = 0(lefts=3)→ p9 左恒封锁 → 单载路径必 e4。
  • 取消收队 oxy_end = 6 − lefts ∈ {2,1,0}(lefts=4,5,≥6)→ lefts≤5 时 p9 左可用 → e3。
  • 前 3 潜恒可完成的预算证明:D1 最大支出 5(12→7);D2 最大支出 6(7→1)后应急瓶 +3(→4)≥3 ✓;D3 恒可下(最差 4→1,p6 左 floor 0 走干涸链)✓。教学潜与机舱潜永不被氧气卡死(P4)。

5. 音频三层映射

5.1 BGM(状态→曲目,Mureka instrumental,4 首 ≈ $0.12)

状态 曲目 切换 Mureka prompt 草稿(英文,seamless loop)
INTRO/SURFACE/MENU bgm/deck 开局淡入 800ms;MENU 呼出低响度淡入 500ms "Night sea surface from a rescue ship deck, sparse cello and low piano over gentle waves, distant rigging creak and engine hum, melancholic but purposeful, no vocals, seamless loop, 60-90 seconds"
DIVE bgm/dive crossfade 800ms 进;接通 COMMS 淡至 comms 600ms "Deep ocean descent ambience, dark ambient drone with a slow sonar-like pulse, immense water pressure, distant whale-like tones, subtle tension, no vocals, seamless loop, 60-90 seconds"
COMMS bgm/comms crossfade 600ms;上浮淡回 deck "Underwater radio contact scene, warm muted piano over a deep water drone, faint hydrophone static, intimate and quietly hopeful, no vocals, seamless loop, 60-90 seconds"
ENDING bgm/ending p9 结果链播完后淡入 1500ms "Dawn on the sea after a deep sea rescue, warm strings and soft piano, exhausted hope and quiet triumph, no vocals, seamless loop, 60-90 seconds"
  • bgm=0 时全部静默(引擎约定);menu 用 deck 同曲(省 1 首,海面场景同构);共性后缀(10 号 §8)照 radio 追加。

5.2 SFX 清单(SA3=Stable Audio 3 / SYN=程序合成;one-shot 真峰值 ≤-3dBFS;amb 循环由游戏层 buffer.loop 实现,radio phone_ring 先例)

id 用途 来源 prompt(英文)/ 合成参数
sfx/sonar_ping 你发出的声呐脉冲(搜索单击) SYN 1.4→0.9kHz 正弦 chirp 220ms,指数衰减,-6dBFS(回波家族统一音头)
sfx/echo_metal_l / _r 钢板回波(左/右声像;「金属回波=海燕号」承诺音) SA3 "Sonar echo returning from a steel submarine hull, resonant metallic ping with slow decay, panned slightly left(→right), underwater, 2 seconds"
sfx/echo_debris 碎石回波(D2 机舱外) SA3 "Sonar echo returning from an underwater rubble and debris field, diffuse granular reverberation, 2 seconds"
sfx/echo_groan 船体呻吟(D3 预警/D4 滑坡前奏,可变增益复用) SA3 "Stressed submarine hull groaning deep underwater, long metallic moan under immense pressure, 4 seconds"
sfx/pipe_knock 管路敲击暗号(老白 SOS) SYN 三短三长三短固定节拍金属敲击(节拍精确可复现、断言可数)
sfx/link_beep 电台接通 SYN 双音上行 0.3s
sfx/static_burst 通讯静电/断续 SA3 "Shortwave radio static burst with faint ghost of a distorted voice, 2 seconds"
sfx/amb_deep 深潜底噪 loop SA3 "Deep ocean ambient loop, low pressure hum, distant current wash, occasional far creak, seamless loop"
sfx/amb_deck 甲板底噪 loop(风+浪+缆绳) SA3 "Night ship deck ambience, wind, gentle waves against hull, distant rigging creak and engine hum, seamless loop"
sfx/breath_loop 低氧呼吸 loop(仅 low/crit 档垫,混音签名) SA3 "Slow scuba regulator breathing loop, calm but slightly labored, underwater, seamless loop"
sfx/spark_flash D2 危机拍:切割火花+氢气虚惊 SA3 "Underwater cutting torch sparks with a brief muffled gas pop, 2 seconds"
sfx/valve_close 重阀关闭(p4 左) SA3 "Heavy submarine valve wheel shutting, metal rotation clunk and water seal, 2 seconds"
sfx/landslide D4 危机拍:海底滑坡轰鸣(前置 2s 渐强) SA3 "Underwater landslide rumble, rolling sediment and rocks, ominous low roar building, 4 seconds"
sfx/surf_splash 破水出水(每潜上浮) SA3 "Diver breaking through the sea surface, splash and one gasp, 2 seconds"
sfx/ascent_chime 出水确认音 SYN 上行三音琶音 0.4s
sfx/bell_toll 船钟(p9 左 payoff 音) SA3 "Old ship brass bell, single clean toll with warm resonance, 3 seconds"
sfx/ui_confirm / ui_menu 菜单/确认(程序合成兜底) SYN 同全局先例
  • 预警窗纪律:D2 火花与 D4 滑坡均前置 2s 起渐强(L2),danger 签名与音效同窗(radio C5 刹车先例);D4 另叠 danger 震循环(每遍间隔 ≥400ms)。
  • 承诺兑现绑定:dv1_metal 教「金属回波=钢板」后,凡叙事提到船身/找到船的节点必播 echo_metal*;D2 找人必播 pipe_knock(§6.3 清单 + §9 断言)。

5.3 Voice 划分(详见 17-abyss-voice-ids.md)

组 声部 落位 数量
潜航员(你)DIVER 双性别(female=Serena / male=Uncle_Fu + DIVER instruct 常量) voice/female|male/ 30 句
调度/系统/向导 DECK 双性别(female=Vivian / male=Dylan + DECK instruct 常量) voice/female|male/ 97 句
船员 NPC ×4 平铺单音色(小舟=Serena / 老白=Uncle_Fu / 陈医官=Vivian / 高船长=Eric),不做双性别 voice/ 根(平铺回退命中)+ 电台滤波转码 21 句
  • 船员 ≤4 个单音色约束满足;玩家自己的声音跟随全局 settings.voice;调度是向导人设(L4 角色化系统声,radio 导播同型)。
  • 合计 148 句(≤170 GPU 预算 ✓,含 _k 键盘变体 11 对);音频文件 = 127×2 + 21 = 275 条(×2 格式 = 550 文件)。

6. 声呐双通道设计(本作核心差异层)

6.1 引擎能力边界(对照 web-engine-api.md)

能力 引擎现状 方案
voice 运行时 EQ/滤波 ❌(voice 链无滤波插入点) 资产侧转码滤波(radio §6.2 先例):ffmpeg highpass+lowpass+压缩器 逐船员定档(§5.3/voice-ids)
sfx 循环 ❌ 即发即弃 游戏层 buffer.loop=true 持句柄(amb_deep/amb_deck/breath_loop),切换档位时停(radio _ringSrc 先例)
语音 duck 垫乐 ✅ 内置(duck 20%,300ms) 直接依赖;BGM 不再手工让路
sfx vs voice 互让 ❌ sfx 总线独立,无 duck 游戏层 sonarGate 空闲门(§6.2 R1):信息类回波只在 !audio.isVoicePlaying() 时播出,否则挂队列表、voice onComplete/句间轮询补发
sfx 声像 ❌ 运行时无 pan API 资产侧 pan(echo_metal_l/_r 两条,escape 先例);其余方向信息由调度语音明说(「左前方」)
变速不变调 ✅ SoundTouch 直接依赖(长按 1.7× / 2.2× 视障档)

6.2 通道仲裁规则(并发声流 ≤2 约束)

  • 通道定义:声呐通道 = sfx 层的脉冲/回波/敲击/呻吟/环境 loop;通讯通道 = voice 层(调度+船员+你)。BGM 是第三层背景(voice 播时引擎自动 duck)。
  • R1 回波不叠语音:信息类回波(echo_*、pipe_knock、groan 渐强段)与任何 voice 播放区间零重叠——sonarGate 只在 voice idle 时放行,在播则排队到句间空隙(≥600ms);玩家主动脉冲只在搜索等待(voice 恒静)受理,按构造不重叠。
  • R2 声呐主导段(DIVE 搜索等待):前景=脉冲+回波余音+amb_deep,BGM=dive 曲低响度;voice 只出调度短句(解读句),且解读句固定在回波结束后接播(回波→静默一拍→解读,给耳朵留定位时间)。
  • R3 常驻脉冲退位:语音在播时,环境内的周期性声呐元素(母船远程脉冲垫)降 -6dB 或暂停(游戏层 gain 控制),不消失(保持声场存在感,A2 无静默死局)。
  • R4 危机拍优先:D2/D4 危机音(spark/landslide)为即发即弃 sfx,可叠在 amb 上;danger 签名同窗;当前 voice 句播完后危机链才插续(radio C5 同款;呼救类短句若必须抢时,走 sfx 层不占 voice)。
  • R5 回波可重听:搜索等待双击=重听「上一条回波+其解读句」(P1 关键线索可重听);COMMS 双击=重听当前节点(radio 同款)。
  • 声流账:任意时刻 ≤2 条前景流(voice 串行 1 + 声呐信息音 1),BGM/amb 为背景层——满足 ASA ≤2 注意流约束。

6.3 教学承诺清单(dungeon「铁器=楼梯」教训:每句承诺的机制必须真实存在且可感知)

教学句 承诺 兑现点(断言锁定)
dv1_metal「金属回波,钢板。听见这个,就是海燕号的船身」 金属回波=找到船 D1 找到/D4 接近指挥舱均播 echo_metal*;全剧本任何「船身」节点零漏播
dv1_teach「单击,发一枚脉冲」(+gd_ping1) 单击=脉冲 搜索等待单击恒出 sonar_ping(非跳句、非无效);无超时不惩罚
b_goal「五个人。你的双瓶,够下四潜」 5 人/4 潜 基础消耗恰 3 格×4=12(§4.5 验算);剧本 A 恰 4 潜走完
b_rule「气不够一潜,人就必须上浮」 氧气门 取消门恰在 oxy<3(§4.3/§4.5);剧本 C/D 实证
d1_surf「往返,扣三格气」 每潜扣 3 每次下潜开始扣 3(账目断言)
d1_code「记住这个敲法」 敲管=老白的信号 D2 搜索以 pipe_knock 引导找到机舱
oxy_gain「应急瓶接上了,多三格」 +3 恰一次、恰 +3、恰在 D2 上浮后

7. 向导层接入

7.1 状态签名 earcon / turn cue

时机 向导动作 说明
INTRO 进入 guide.state('explore') 叙事态签名
搜索等待武装(下潜链末) guide.turn({haptic:true})(无语音) turn 签名+confirm 震=「轮到你发脉冲」;首次前 dv1_teach 已口播
每个抉择点 p* 起播 guide.state('choice') 选项句本身即 turn cue(W2 契约零插播)
SURFACE 进入 guide.state('settle') 结算签名
ENDING 进入 guide.state('settle') 同上
MENU 打开 guide.state('menu') 菜单签名
D2/D4 危机拍 guide.state('danger') 音效前置 2s 渐强同窗(全游戏仅两处)
无效手势 guide.error({voice:'gd_invalid', onceKey}) error 震 + full 档语音,idle-only(F1.4)
  • earcon 词表:只用全项目统一 8 音(menu/explore/battle/choice/settle/danger/turn/nudge),零新增;battle 不用。

7.2 看门狗双轨(radio F1 + dungeon E0-1 教训:乱按也要被抢救)

无操作轨(guide watchdog,任何手势复位;两级不同句、用尽即停、永不惩罚):

等待点 full 档 standard 档 级别内容
搜索等待无脉冲 [10, 25] [10, 25](onEscalate 游戏层补播) ① gd_ping1 ② gd_ping2(必须不同句);两级后仅 amb+余音
INTRO/COMMS/SURFACE 链末等待 [25, 50] [13, 30] ① gd_continue ② gd_again(storyline F1.1 同款)
抉择点 p* 播完无操作 [25, 50] [25, 50] 重播当前 p* 提示句(13 号 §16 先例;空点单击=重挂计时)
ENDING 结算等待 [25, 50] [13, 30] gd_continue / gd_again

无进展轨(游戏层计时,dungeon E0-1 ②同型;仅挂搜索等待与 COMMS 链末两个可饿死点):

项 规则
进展定义 节点推进 / 发出脉冲 / 抉择结算。无效手势(滑错、空点)不计进展——无操作轨被它们复位、无进展轨不被它们复位,乱按 96s 也必被抢救
阈值 60s → gd_prog1;120s → gd_prog2;用尽即停(每等待点一轮)
有真实进展 全程零 prog 播出(不误伤正常玩家,dungeon 断言同款)
双轨去重 两轨短句内容同级交叉登记;同一等待点先播过 gd_ping* 则无进展轨跳过同义级
  • 向导插播一律 queue:true,绝不顶掉在播对白;error/watchdog 类语音 idle-only(在播则跳过且过期丢弃,F1.4)。
  • 单句语音看门狗(资产缺失兜底):30s 超时且 isVoicePlaying()===false 才自动续链,长句续约不掐(radio N1 先例照抄)。

7.3 键盘变体机制(PC 键盘玩家)

  • 运行时按 gesture.inputMode()(settings.input auto/touch/key)选 _k 变体资产:key → voice/<gender>/<id>_k.*,touch → 无后缀版;auto 跟随最近使用通道(keydown 后即切 key)。_k 缺失回退无后缀版(资产侧保证成对,check_all_assets 校验)。
  • 变体清单(11 对,集中分组见 voice-ids §G0):gd_brief / gd_continue / gd_again / gd_ping1 / gd_ping2 / sys_help / sys_menu / sys_skip / sys_continue_ask / dv1_teach / p1。
  • 抉择提示 p2..p9 措辞统一「向左滑/向右滑」;键盘玩家由 p1_k 与 sys_help_k 完成首次绑定(左=←,右=→),后续提示语义不变。
  • 启动遮罩文案引擎自理(「按空格开始」/「轻触开始」),游戏零改动。

7.4 继承 radio 三轮验证机制(照抄不重设计)

机制 来源 落点
帮助链去重(同等待点第 2 次上滑只震+nudge) radio G1 _helpSeen 按等待点键控
状态链顺序「状态在前、帮助在后」 radio G6 prog_dN → oxy 档 → sys_help
空点确认轻震(不可跳句上单击补 beat [8]) radio G4 p*/链末句/F4 锁各 tap 屏蔽分支
oxy_crit 播报位附 warning 震 radio G2 全部 crit 出口(含上滑复听)
菜单报名游戏侧排队零截断 radio 实现修复 #3 _menuQueue 排水
stop() 先 seqToken++ 作废在途链 radio 实现修复 #6 同款
新局清 choiceArmed/pendingChoice radio 实现修复 #7 newRun()
长按误报无效(longpress 全状态合法) radio 实现修复 #2 仅 left/right(ASK 另含 up/down/doubletap)报无效

8. 存档设计

8.1 进度 data 结构(PUT /api/progress {game:'abyss'})

{
  "schema": 1,
  "updatedAt": "2026-09-09T12:00:00Z",
  "summary": "第2潜·机舱 · 氧气6格 · 结局1/4",
  "phase": "COMMS",
  "node": "bai_b",
  "dive": 2,
  "oxy": 6,
  "supply": true,
  "saved": { "zhou": 1, "bai": 0, "chen": 0, "zheng": 0, "gao": 0 },
  "stayer": null,
  "flags": { "knowsPipe": true, "hasLog": false, "valve": false, "spareGift": false, "gaoPeace": false, "bell": false },
  "endings": { "e2": true },
  "runs": 3
}
  • 写入时机:每潜 DIVE 进入、每个抉择结算后、SURFACE 进入、ENDING 进入、菜单「保存并回大厅」。
  • 断点续玩:读档 → sys_continue_ask(_k)(单击=继续上次 / 右滑=新救援);继续=恢复 phase+node+全部数值并重播当前节点链=一句话局面复述(L5);重进 ≤5s 可玩;恢复首句受 F4 跳句锁(radio G5 例外条款)。
  • summary 格式:进行中 第N潜·<舱段> · 氧气K格 · 结局X/4;收队 救援收队·<结局名> · 结局X/4(大厅卡片直接显示)。

9. playtest 断言清单(登记 13 号 §21 指针;settings.set({guide:'off'}) 纯玩法验证,向导行为住 guide.test)

关键路径(剧本 A:全右+左p9 → e1,≤70 次手势):

  1. 遮罩点按 → INTRO 链(b_open 起,voice 层有播放记录)→ 链末单击 → DIVE(1) 下潜链 auto → 搜索等待武装(turn 事件 + amb_deep 循环起播)。
  2. 搜索单击 → sonar_ping → 回波静默一拍 → echo_metal_l → dv1_metal(承诺音)→ link_beep → COMMS(1):z1_a/b/knock → p1 右 → p2 右 → 上浮:surf_splash+ascent_chime → d1_surf → oxy=12-3=9 → oxy_full 播出(账目断言)。
  3. DIVE(2):脉冲 → echo_debris+pipe_knock → dv2_found → bai_a/b → p3 右(danger 签名前置 2s 与 spark_flash 同窗断言)→ p4 右 → d2_surf → d2_supply → oxy_gain(6→9,恰一次)。
  4. DIVE(3):脉冲 → echo_groan → dv3_groan → chen_a/b → p5 右 → p6 右 → d3_surf(oxy=6,ok 档)。
  5. 氧气门:6≥4 → DIVE(4) 双载:滑坡危机拍(landslide 前置 2s 渐强 + danger 签名 + danger 震)→ gao_a/b → p7 右 → gao_c → p8 右 → d4_surf → oxy=2(crit 档+warning 震)。
  6. 签收:g9_in → g9_knot → p9 左(oxy=2≥1 可用)→ d9_bell + bell_toll → ENDING(e1):e1_a/b + ep_lead + ep 链 → 结算单击 → 新救援回 INTRO。

边界断言:

  • 四结局可达(含氧气逐点验算):剧本 B(同 A 但 p9 右)→ e2;剧本 C(p1左 p2左 p4左,余右):D1 后 oxy=7(ok)/D2 后 2→supply→5(gain+low 档)/D3 后 2(crit)→ 氧气门走终局取消链(dv4_none→gao_final 完整播出)→ p9 左(2≥1)→ e3(saved=3);剧本 D(p1左 p4左,余右):D1 后 8(ok)/D2 后 3→supply→6(ok)/D3 后 3(low)→ 单载形态(p7 按 stayer 选 p7_chen|p7_zheng)→ p7 左=带船长 → 留守者留别句(chen_last|d4_stay_lost)→ p8 右 → oxy_end=0 → p9 左封锁:g9_dry 播出后自动右 → e4(saved=4)。各局 oxy 逐检查点与 §4.5 公式一致。
  • 氧气账目真实:每次扣减后播出的档位句与 floor(oxy/3) 桶一致;上滑 status 链顺序 prog_dN → oxy 档 → sys_help(G6);supply 全局恰一次;剧本 E(p2左 p3[无knows]左 p4左 p6左)mid-dive floor 至 0 → dry_a/dry_b 播出且当前救援者照常救上(人已挂上吊索不失去)。
  • 双通道仲裁:全剧本转写断言——echo_*/pipe_knock/groan 信息音播出时刻与任一 voice 播放区间零重叠(sonarGate 排队语义:晚于在播句结束);搜索等待单击恒=脉冲(sonar_ping 计数=1,无跳句无 error);双击搜索等待=回波+解读句同序重播;语音在播时 amb_deep 持续、远程脉冲垫降 -6dB(R3)。
  • 教学承诺兑现(§6.3 清单逐条):dv1_metal 后所有「船身」节点 echo_metal* 零漏播;D2 找到机舱前 pipe_knock 恒在;b_rule 与取消门一致(剧本 C 证明);b_goal 四潜=剧本 A 恰 4 潜;每潜起播扣 3 断言。
  • 看门狗双轨:搜索等待快进 10s→gd_ping1、25s→gd_ping2(两级 id ≠,绝不逐字重播;两级后仅 amb);乱按 96s(每 2s 注入一个无效滑动):无操作轨零播出(被手势复位)+ 无进展轨 60s→gd_prog1、120s→gd_prog2(乱按饿不死);有真实进展(单击脉冲推进)全程零 prog 播出;COMMS 链末 25s/50s → gd_continue/gd_again;p* 播完 25s/50s 重播 p* 两次后静默;guide=off 全程零定时器零向导事件。
  • 键盘变体:settings.input='key' 会话播出 gd_brief_k/sys_help_k/gd_ping1_k/dv1_teach_k/p1_k 且对应无后缀版零播出;'touch' 反之;'auto':keydown 后下一句用 _k。
  • 中断复述:杀进程重进(存档 node=bai_b)→ sys_continue_ask → 单击 → 重播该节点链(恢复首句不可跳,第二句起可跳);右滑=新救援(runs 口径同结算重开)。
  • 结算链死窗(H1 内化):终局取消链/干涸链/e* 结局链开播后 800ms 内注入在途 tap(mock 补派 touchend+300ms 同款序列)→ 手势被吞、链完整有序播出、结算出口手势照常。
  • pendingChoice:p* 播放中左右滑 → 播完立即生效(不丢、不重复、连滑取最后一次)。
  • p 不可跳*:p* 播放中单击 → 不跳句(PROMPT_RE 门)+ beat 轻震(G4)。
  • idle-only:向导 gd_* 在对白在播时跳过且不占 onceKey(F1.4);queue 句排在当前句后零截断。
  • 菜单:下滑开菜单 → 上滑帮助 → 双击「回到水下」→ phase/node 不变、当前节点重播;单击循环顺序 = [回到水下, 重新开始这次救援, 保存并回大厅];确认回大厅 → sys_menu_lobby 播出且 PUT/localStorage 有最新 data。
  • 资产缺失:屏蔽任意 voice 资产 → 30s 看门狗自动续链到结局不卡死;NPC 滤波资产缺失回退原声可播。
  • 数字规范:prog_/oxy_/gd_* 全部整句字面量,静态审计无运行时拼接碎片。
  • 低氧混音签名:tier=low/crit 期间 breath_loop 在播、升档/收队即停。

失败即不通过:任何等待 >5s 无声(静默死局);无效手势零反馈;回波与语音重叠;结局计数与 §3.4 不符;氧气档位句与 oxy 值不符。

10. 节奏曲线(每次下潜目标时长)

段 内容 目标时长 设计目标
开场+下潜链 甲板简报+第一潜下水+搜索 1-1.5 min 首输入 <60s(开场链 ~20s 链末单击,或 ~40s 搜索首脉冲);规矩一句讲完(P4)
D1 找船 教学潜:脉冲/回波/接通/2 抉择 4-4.5 min 首个正反馈 ≤3min(~2.5min 金属回波+接通小舟=「看见它了」);两抉择条条有出路;左路气耗被补给兜底=学习期零惩罚
D2 机舱 老白:撬/切+阀门抉择 3.5-4 min 首个危机拍(火花,前置 2s);补给+3 兑现宽限;暖拍(热粥,P4)
D3 病舱 生死抉择+回波预警 3.5-4 min 船体呻吟埋 D4 险;留守约定=段落边界(P3 中断友好:每潜一个完整存档颗粒)
D4 指挥舱 滑坡高潮+氧气门三形态 4-4.5 min 紧张峰值:danger+滑坡渐强+双人竞速;生死分支收敛
终局+结局 p9 心结+结局链+逐人回响 2.5-3 min 氧气余量兑换终局抉择;ep 点名(P2 回响);开环钩子拉下一局
  • 合计 ≈ 20-22 min(15-25 达标);每 30-60s 一个反馈颗粒(回波/解读短句/结果句/档位句),无沉默尴尬期(P3)。
  • 难度曲线 = 道德复杂度(教学二选一 → 情报投资 → 生死取舍 → 自己的心结),操作复杂度恒定(永远二选一+单击脉冲)——P4「规则一遍听懂」由恒定操作面保证。

11. 自检清单(策划交付自验;☐ = 待开发/测试轮填)

# 硬约束/教训 落地 ✓
1 FTUE 首输入 <60s 开场链 ~20s 链末单击;~40s 搜索首脉冲(§10) ☑
2 FTUE 首个正反馈 ≤3min ~2.5min 金属回波+接通小舟(§10 D1) ☑
3 学习期零惩罚 D1 左路 -2 被 D2 后 +3 兜底;搜索无超时惩罚;D1/D2 恒可完成(§4.5) ☑
4 失败三问归因+归因真话律 干涸链 dry_b 指向实际左选择;gao_final/d4 留别句克制不假安慰;§4.4 无假归因句 ☑
5 资源账目真实(radio rep_low 教训) 氧档以 floor(oxy/3) 划界、每档句义逐格为真(§4.3 表);补给恰一次 +3;扣 3 恰每次下潜 ☑
6 手势宪法 6 手势默认语义零豁免 §2.3 全覆盖;单击搜索=「检查」(宪法 §5.1+escape 先例);菜单 §5.2 模态约定 ☑
7 长按显式登记 无豁免:长按=引擎快进(12 号叙事类不豁免),§2.3 在案 ☑
8 向导:签名/turn cue/看门狗两级不同句 §7.1/§7.2;gd_ping1≠gd_ping2;gd_continue→gd_again ☑
9 看门狗双轨(dungeon E0-1/radio F1 教训) 无操作轨+无进展轨(§7.2);乱按 96s 必被抢救;有进展零打扰 ☑
10 插播 queue 不顶对白;纠错 idle-only 过期丢弃 §7.2(F1.4 契约) ☑
11 死亡/失败结算链完整(dungeon H1 教训) 终局取消链/干涸链/结局链 800ms 手势死窗;已救者永不失去(§2.2/§4.3) ☑
12 教学承诺兑现(dungeon「铁器=楼梯」教训) §6.3 承诺清单 7 条逐条绑兑现点+断言 ☑
13 单次播报 ≤3 选项 全部抉择恒 2 选项;菜单 3 项循环 ☑
14 并发声流 ≤2 + 双通道仲裁 voice 串行+声呐信息音互斥(R1-R5,§6.2);断言零重叠 ☑
15 earcon ≤7、统一词表、语义靠语音 只用统一 8 音中 7 个(battle 不用),零新增 ☑
16 台词一句一文件 ≤40 字、数字分档整句、无运行时拼接 voice-ids 全表 ≤30 字(最长 p8=30);prog/oxy 分档整句;句内数字写死 ☑
17 多音字规避/同 instruct 常量/无语速词 voice-ids 头部+文末自查(重写→补、脏/晃/闷标注试听) ☑
18 PC 键盘变体(提示句集中+标注) 11 对 _k 变体集中分组(voice-ids §G0);inputMode() 运行时选择 ☑
19 P1:可打断/重听(含回波)/status key/不当白痴 跳句+双击(回波可重听 R5)+上滑状态链+成功零补救教学 ☑
20 P2:3 分钟见效/结局回响 ~2.5min 首个改变世界的时刻;ep 逐人点名+bell 差分;e1 巧妙路径(p1左+p3左 省气取钟) ☑
21 P3:3 分钟颗粒/中断复述/单手 一潜=3.5-4.5min 完整段落+边界自动存档;重进重播当前节点;全手势免视单手 ☑
22 P4:一遍懂/容错/无高压倒计时/不骂人 一句规矩;无实时倒计时(步进资源+跨档才播);软失败零死亡;NPC 句 ≤24 字+逗号停顿 ☑
23 抉择树 4 结局可走通验算 §4.5 公式+§9 剧本 A-D 逐 oxy 检查点(e1:lefts≤1+双载;e2:lefts≤2;e3:lefts=4-5+取消;e4:单载 lefts=3 或取消右) ☑
24 单局 15-25 min §10 曲线 ≈20-22 min ☑
25 分支不爆炸(radio 纪律) 跨潜仅标量(oxy/saved/stayer/6 flag);~70 节点固定深度(§3.3) ☑
26 台词 ≤170、船员 ≤4 单音色 148 句(双 127+NPC 21)/4 个船员音色(voice-ids 账目) ☑
27 引擎边界诚实 §6.1 能力表:滤波/loop/声像/互让全写明资产侧或降级方案 ☑
28 存档带 summary、断点续玩 §8:data+summary 格式、≥5 恢复、局面复述 ☑

批 1 教训内化确认(5 条全落地)

教训 本作机制 断言
教学承诺必须兑现 §6.3 七条承诺清单(金属=钢板/单击=脉冲/四潜/氧气门/扣三格/敲管/补给) §9「教学承诺兑现」块
看门狗双轨 §7.2 无操作轨+无进展轨;无效手势不复位进展轨 §9「看门狗双轨」块
档位措辞真实 §4.3 档位=floor(oxy/3) 可下潜次数,句义逐格为真 §9「氧气账目真实」块
失败结算链完整不被打断 800ms 手势死窗盖取消链/干涸链/结局链;seqToken 作废在途链 §9「结算链死窗」块
PC 键盘操作提示 11 对 _k 变体+inputMode() 选择+集中分组标注 §9「键盘变体」块