Files
xsl ee5d4d2544 feat(playbook): 26 号交互手册全量落地——剩余 12 款深度重构 + 语音全量重制
storyline/escape/simon 首批之后的推广收官:15 款全部按 26 号模式运行
(发言权/回执/三档提示/迷茫接管/手势阶梯/断点复述),旧「双击重听/格挡/
菜单确认」等反模式口径全线废除,开场零规则念白(首句即动手)。

游戏层(12 款):rpg(格挡=前摇窗口内再单击)/ rhythm / space / radio /
dungeon / abyss / detective / cipher / teahouse / keeper / bridge /
hunt(联机切片):
- 每款 game.js 接引擎六模块 + makeInputPipeline(doubleTapWindow:0);
  四向玩法类 swipeCore + 长按帮助;双击是玩法的(space 护盾 / hunt
  旋风斩)按手势阶梯阶段 3 分档恢复双击窗口(doubletapCore)
- 每款 playtest 重写:玩法断言 + §6.2 乱点机器人(无声操作 / 被动
  原句重复 / 打断失败 = 0);15 款 3900+ 断言全绿
- 12 份 docs/design/26-apply-*.md 施工单 + tools/voice_lines_26/
  台词清单 + voice-ids 文档同步 + 转写会话剧本按新口径重写

引擎层(web/engine/,6 处修复):pipeline 增 doubletapCore;novice
teachLine 带 voice/ 前缀(此前教学句被静默丢弃);confusion.record
前置到新手门(锁定手势的乱点也计信号);InvalidHints 播完恢复解释前
状态(根治孤儿 BUSY);WaitPoint takeover(2) 台账去重;台账只在
speak 真正播出时登记。遗留引擎债登记 roadmap §3.1。

语音资产:台词表合并(新增 ~250 系统句 / 改 ~50 旧口径 / 删 ~110
废止句;合并器 tools/merge_voice_lines_26.py + 引用校验器
tools/validate_voice_refs.py),GPU 重录 1536 wav → 4204 ogg/m4a
落地,check_all_assets + validate_voice_refs 双绿;键盘变体同步扩表。

大厅/文档:15 款统一新交互口径(「新交互」徽标退役);README /
HANDOVER / rpg README 旧口径修正;roadmap P0-P3 置完成。
2026-10-02 12:33:20 +08:00

158 lines
13 KiB
Markdown
Raw Permalink 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.
# 26-apply · 《守塔人》重构施工单(26 号文档落地)
> **设计单正文见 [21-keeper.md](21-keeper.md) 附录 C**(一句话核心动作、状态×手势
> 矩阵、等待点配置表、首 3 分钟逐秒脚本、失败表——不在本文重复)。本文件是瘦版
> 施工单:只写实现接线、偏差记录、台词类别映射、测试记录。台词登记见
> [21-keeper-voice-ids.md](21-keeper-voice-ids.md) R2 增量节;清单见
> `tools/voice_lines_26/keeper.md`。交互权威:
> [26-audio-interaction-playbook.md](26-audio-interaction-playbook.md)。
> 范式对齐 [26-apply-storyline.md](26-apply-storyline.md)(纯叙事主参考)、
> [26-apply-radio.md](26-apply-radio.md) 与 [26-apply-abyss.md](26-apply-abyss.md)
> (叙事型 + 双音色组同型——KEEPER/SHORE 与 HOST/PROD 同构;pendingChoice 缓存、
> 打断快照 `_chainSpeaking`、sessions 范式重点参考 abyss)。
## 1. 一句话核心动作
**听一夜值守,单击继续;听到选项时左右滑:守灯还是救人、说出还是守住。**
## 2. 实现接线(web/keeper/game.js + index.html)
六模块(§4.1/§4.2/§4.3/§4.4/§4.5/§4.12)全部接通,玩法核心(风暴夜时间轴
INTRO→C1→CALM→C2→CALM→C3→p9→ENDING、回忆插叙三段、trust×truth 双标量、
9 抉择 4 结局、KEEPER/SHORE 双音色 + NPC 三代声、800ms 级结算保护、底噪互斥
vinyl/storm、雾角四处兑现、存档 summary)不动,交互层整体换成 26 号模式:
- **接线**:`this.receipts = new Receipts(audio)`、`this.floor = new Floor(audio)`、
`this.confusion = new Confusion({ onConfused: (lvl) => waitPoint?.takeover(lvl) })`、
`this.invalidHints = new InvalidHints().bind(this.floor)`、`this.ladder = new
GestureLadder()`(叙事类长按不占用:`setRateBoostEnabled(false)`,新手期
longpress 由管道判 invalid)。`index.html` 照 storyline 同构:
`makeInputPipeline({ floor, confusion, receipts, invalidHints, game, ladder,
opts: game.PIPELINE_OPTS })` + `attachGestures(root, pipe, { doubleTapWindow: 0 })`,
启动遮罩保留。doubleTapWindow: 0 → 未解锁双击由管道折算成 tap。
- **`onGesture` 返回值收口**(§4.2):`'ok'`(继续/抉择/菜单/状态)|`'hold'`
(重听、菜单换项——等待点保留)|`'silent-ok'` 本作无(无即时内容音手势)|
`'invalid'`(pipeline 给回执 + explainOnce + 迷茫信号 + settleWaitPoint(false))。
- **语音链 = floor.speak(critical/kind)**:节点链全部改走 floor;拆链实现句级
critical(abyss `_speakNodeVoices` parts 模式)。跳句/打断由 floor 收口:
tap=consumed 跳本句、滑动=打断并执行、critical=busy——旧 PROMPT_RE 门 / 锚句
空点 beat 震 / F4 恢复锁 / F5 交接尾句保护 / G5 首播锁被结构性消解。
- **等待点(§4.4 附录 A)**:intro(6/15s)|continue(13/30s)|choice(25/50s,
full=当前 pN 且链播即登台账)|settle(20/45s)|reopen(12/30s)|menu(20/45s)。
三档提示 + 30s 台账 + 主动重听「再说一遍:」全在 engine/hints.js。
- **开场 §4.10**:冷启动第一句 = `sys_first_tap`(critical 指令句,0~3s 动手);
第一下单击 → `[b_open, b_rain]`(雾角挂 b_rain 播完)→ `b_goal` 极短目标 →
continue 等待点;`sys_turn_teach` 挂 amo_a 链尾、「轮到你」状态声首现教学,
`sys_skip` 挂 amo_b 链尾(radio z1_a/z1_b 先例)。**b_rule 开场规矩念白与
gd_brief 操作念白废除**;重开新夜链 = sys_new_night → b_open → b_rain(雾角)
→ b_goal,教学句不再播(原则 11)。
- **手势阶梯(§4.3)**:第一次抉择(choose 首次)→ `ladder.onGoal()` 解锁上滑,
「对。」(sys_praise)挂下一段链头、教学句挂链尾;第一结局(enterEnding)→
`ladder.onGameDone()` 解锁下滑/第 3 局双击,教学句挂结局链尾。`teachLine()`
已带 `voice/` 前缀,游戏侧直接引用不拼前缀。
- **上滑「我在哪」(21 附录 C §3:时位句先行 → 信任档 → 一个动作)**:
now 线 = `prog_m{act}` → `tr_{tier}` → `tru_{truth}` → 动作尾巴(choice 等待=
status_choice / 其余= sys_hint_continue_full);MEMORY = `prog_mem_*` → `tr_*`
→ `tru_*` → `sys_mem_back`;ENDING = 结局主句 → `tr_*` → settle 动作句。
状态句全量 markHintSaid(原则 9);播完回原等待点(radio 口径 resumeTurn,
档位计数保留),等待点不在(旁白被打断/自动流)则按来源重建,不重播节点。
G6 顺序(prog → tr → tru)由 playtest 断言锁定;G2 的 tr_thin 附 warning 震
保留首夜首幕豁免(自然起点不是警告)。
- **断点复述(§4.12)**:每抉择结算、CALM/ENDING 进入、菜单「保存并回大厅」写
`soundgame.progress.keeper`(含 timeline 时空位 + goalMet/turnTaught/skipHintShown
教学标志;**summary 必带**;MENU 落盘记回原状态)。回来:sys_continue_ask 询问
(tap=继续上次 / right=新风暴夜);MEMORY 存档恢复链 = prog_m → prog_mem →
重播当前回忆句起链(首句 critical,F4 等价),≤5s 回到可玩。
- **迷茫检测(§4.5)**:confusion 信号(含管道在 invalid 时 recordInvalid、等待点
静默阈值喂 recordSilence)→ 当前等待点三级接管(L1 短句 → L2 只留期待手势 →
L3 演示:intro/continue 替玩家走一步,choice 只复述方向不替选)。
## 3. 偏差记录(与 26 号手册 / 21 号附录 C 的实现偏差)
1. **800ms 结算死窗升级为整句 critical**(abyss 先例):结局链首句(e1~e4_a)、
c3_dark(灯灭差分插播,auto+@x 尾句锁)、rev_teach(时空教学)、插叙锚句首播
(rev_g1/g4、rev_f1/f5、rev_c1/c5)、恢复链首句(_resumeGuard)整句 critical
——tap/滑动给 busy 回执不截链,覆盖旧 `_settleGraceUntil` 800ms 定时窗且更强。
插叙入口 600ms 静默拍期间 floor=BUSY,手势同样 busy 回执(死窗语义等价)。
2. **p* 选项句整句 critical**(radio 口径):p1~p7、p8_boat/p8_reef、p9a/p9b 首播
不可跳(tap=busy),链播即 markHintSaid——被动提示永不逐字复述选项。21 附录 C
§8 台词表把 p* 归 content 指内容属性;矩阵 §4「p* 首播不可跳」以 critical 落地。
3. **旁白链滑动 = 缓存抉择 + 跳选项句**(abyss 模式,兑现矩阵 §4「缓存抉择,不
盲选」):旁白(含被打断快照 `_chainSpeaking`)中 left/right 若落在抉择点
(本节点 next 直入 p*),缓存 pendingChoice 并 playNode(p*);选项句整句 critical
播完当刻缓存生效(ui_confirm → 结果节点,W2 契约 + 盲玩公平)。非抉择点滑动
→ invalid + `_recoverInterrupted` 交回 continue 等待点(零无声死锁)。
4. **MEMORY 打断恢复 = 重播当前回忆节点**:插叙是 auto 链不设等待点;滑动打断/
双击重听/菜单关闭/上滑播完都从「当前回忆句」(memIdx,由 audio.play 钩子实时
维护)重播起链,复播不锁锚句(G5 复播可掐);链末照常自动回返现在线。
MEMORY 中 left/right = invalid(插叙无选择,21 附录 C §4)。
5. **CALM 幕间为自动流(BUSY)**:链播中 tap=跳句(consumed)、空档手势=busy;
滑动打断后不重交话轮——`_ensureWait` CALM 分支直接挂喘息定时器推进下一幕
(radio BRIDGE 同款)。跨档 tr_* 账目在链构造时结清(radio enterBridge 口径;
不再逐句起播钩子)。
6. **等待声**:六等待点统一引擎合成「嘟—嘟」bed;插叙/幕间/危机拍为 BUSY 演出
态无等待声(原「统一 8 音词表纪律、时空不换 earcon」继续成立——本作不新增
任何 earcon,时空签名全靠内容层底噪/BGM/锚句)。
7. **过渡音 idle 门简化**:memory_in/out、static_burst 只在语音空闲时播出(原
「挂队句间补发」依赖游戏层句级钩子,floor 时代无此钩子;调用点全在链入口前,
在播即丢弃,playtest 断言成对性不受影响)。
8. **`_chainSpeaking` 打断快照为游戏层补丁**(abyss 同款):pipeline 的
floor.handleInput 对滑动「打断并执行」先杀链置 BUSY,游戏侧 floor.speaking
已 false——快照在 speak 置位、onDone/interrupt 清零,让被掐断的旁白链按矩阵
落「旁白中」分支(上游修复后可撤)。
9. **旧交互债务清除**:双击=重听节点旧口令废止(阶段 3 起=重听当前等待点完整句
/当前回忆节点);菜单改 00 号 §5.4(左右滑换项 + 单击确认,旧「单击循环+双击
确认」= 26 §7 反模式 5);guide 层看门狗双轨/无进展轨/sys_help 帮助溢出全部
废止(三档提示 + 迷茫接管 + 手势阶梯取代)。
## 4. 台词类别映射(类别标注;增量清单见 `tools/voice_lines_26/keeper.md`)
- `critical`:sys_first_tap(开场 ≤3s 唯一指令);p1~p7、p8_boat/p8_reef、p9a/p9b
选项句(整句,首播不可跳);rev_teach(时空签名教学,全局一次);插叙锚句首播
六句(rev_g1/g4、rev_f1/f5、rev_c1/c5);c3_dark(灯灭差分);结局链首句
(e1~e4_a);恢复链首句(F4 等价)。
- `content`:b_*、c*、amo_*、rev_* 中段句、e*_b、ep_*、prog_m1..3、prog_mem_g/f、
tr_deep/half/thin、tru_zero..full、lull_1/2、sys_turn_teach、sys_skip、
sys_unlock_*、sys_new_night、sys_continue_ask、sys_menu、menu_help、
sys_menu_resume/restart/lobby、sys_settings。
- `hint`:sys_hint_continue_full/short、sys_hint_choice_short、sys_hint_again_full、
sys_hint_menu_short、sys_only_choice、sys_demo_continue、sys_demo_choice、
sys_mem_back、status_choice、sys_say_again(「再说一遍:」前缀,engine/hints.js
播出)、sys_first_tap_short。
- `feedback`:inv_nosel、inv_mem、inv_generic、inv_up_locked、inv_down_locked、
sys_praise(「对。」首抉择链头)。
- 音色组:系统/交互层句子全部 `_SHORE`(岸台值班员=系统音,与 radio PROD、
abyss DECK 同型);剧情守塔人 `_KEEPER`、NPC 平铺(阿澈/父/祖)不动。通用系统
句与 STORYLINE_LINES 的 sys_* 段逐字一致;键盘变体照 KEY_LINES["storyline"];
多音字「重听」→「重新听/再听一遍」。
- 完整登记(新增 24 / 修改 1 / 删除 8)见 `tools/voice_lines_26/keeper.md` 与
[21-keeper-voice-ids.md](21-keeper-voice-ids.md) R2 增量节。
## 5. 测试记录
- 无头 playtest:`web/keeper/test/playtest.mjs` **272 断言全绿**(`tools/node/bin/node
web/keeper/test/playtest.mjs` 退出码 0;`node --check web/keeper/game.js` 通过;
`game.floor.bedEnabled = false` 防周期定时器不排水)。覆盖:§4.10 首 3 分钟
(3s 内动手、critical 指令句、规则念白零播出、开局 40s 内听到阿澈);剧本 A~F 六路径
四结局 + 信任/真相逐档验算 + 尾声回响差分;时空签名(vinyl 与 storm/room/engine
播放区间零重叠、memory_in/out 成对 ×3、BGM 切换、危机拍前置 2s);上滑状态链
G6 顺序(prog → tr → tru → 动作)与 tr_thin 首夜豁免;pendingChoice 时序
(旁白滑动缓存 → 选项句播完 → ui_confirm → 结果句);锚句首播 critical /
复播可掐;结算保护(结局链/c3_dark 首句 critical,幽灵手势不截链);等待点三档
(continue 13/30、主动重听「再说一遍:」);迷茫接管三级;手势阶梯(阶段 1/2
教学句挂链头/尾);§4.12 断点复述(ASK 左/右、MEMORY 恢复链时位句先行、F4
恢复首句锁);菜单(左右滑换项 + 单击确认 + 插叙中开关菜单底噪不丢);CALM
幕间打断后喘息照走;资产缺失续链(Floor 哨兵 3s 宽限);键盘变体路由;
**§6.2 乱点机器人**:无声操作 0、被动原句重复 0、打断失败 0、第一次操作
≤10s、第一次成功 ≤20s、乱按不锁死(零死锁收在合法等待态或结局);静态审计
(无运行时 id 拼接、8 句废止台词零引用、20 条游戏引用新台词待生成豁免 +
引擎侧 4 条入清单一致)。
- 玩家感知转写:`web/harness/sessions/keeper.mjs` 已同步 26 号口径(开场第一下
tap、floor.state 链级门控、菜单左右滑换项+单击确认、插叙中不动手——「回忆没有
选择」、CALM/危机拍 BUSY 段等它走完),`tools/node/bin/node
web/harness/transcribe.mjs keeper`(含 `--session sessionStress`)两剧本零死锁
跑通(主线虚拟 290s 到 E1 灯与归人;乱按剧本 643s 同样走完结局链)。
- 新语音资产(24 句 SHORE 组 + 键盘变体)由主会话统一生成;playtest mock 与真实
资产解耦(voice 层按可用处理,Floor 哨兵兜底缺失)。
- 真人冷启动:待测(26 §6.3,3~5 人)。