# Roadmap: 魔塔游戏引擎(mota-ts) ## Overview 引擎从旧 mota-js 运行时逐步重构,渲染端已重构完成,数据端接口设计中。本路线图沿「事件系统 → 寻路 → 数据端完成 → 渲染适配 → legacy 移植 → 单元测试」的依赖顺序推进:先补齐剧情事件、自动寻路两大玩法系统,再完成数据端 L0–L3 接口落地,随后把新数据层与已重构渲染端打通并支持双布局,接着清理被新接口覆盖的 legacy,最后以单元测试兜底,使引擎能完整跑通一部魔塔。接口/架构设计由用户主导,AI 负责实现与测试;验证通过后 AI 可自行创建 git commit。 ## Phases **Phase Numbering:** - Integer phases (1, 2, 3): Planned milestone work - Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED) Decimal phases appear between their surrounding integers in numeric order. - [ ] **Phase 1: 事件系统** - blockly 式低代码事件定义,驱动简单场景事件流程(验证已通过,待完成阶段收尾) - [ ] **Phase 2: 寻路系统** - 自动寻路与移动端点击地图触发移动 - [x] **Phase 3: 数据端完成** - 数据端 L0–L3 接口全部落地,可在 Node 环境独立跑回放验证 (completed 2026-09-10) - [ ] **Phase 4: 渲染适配与双布局**(已过时) - 新数据层 ↔ 已重构渲染端对接,支持移动端与桌面端双布局 - [ ] **Phase 5: Legacy 移植**(已过时) - 删除被新接口覆盖的旧系统,迁移仍需要的内容 - [ ] **Phase 6: 单元测试**(已过时) - 为核心系统补齐单元测试 - [ ] **Phase 9: 最小浏览器可运行版本** - 在已完成的数据端(Node 可运行)之上完成渲染端框架,并验证可在浏览器上运行 ## Phase Details ### Phase 1: 事件系统 **Goal**: 引擎能以 blockly 式低代码定义事件,并驱动简单场景的事件流程 **Depends on**: Nothing (first phase) **Requirements**: EVT-01, EVT-02, EVT-03 **Success Criteria** (what must be TRUE): 1. 开发者能通过数据/序列化接口定义事件(blockly 式低代码可序列化为引擎事件数据,编辑器在外部项目) 2. 引擎能执行踩踏触发事件(角色踩上地板触发对应事件) 3. 引擎能执行踩踏触发事件驱动的事件执行链路(对话/开门依赖 A2 内建函数清单,延后到收尾工作) 4. 事件系统保持面向初学者的简单抽象,未引入复杂场景的通用表达能力 **Plans**: 13/13 plans executed Plans: - [x] 01-13-PLAN.md - [x] 01-04-PLAN.md - [x] 01-05-PLAN.md - [x] 01-06-PLAN.md - [x] 01-07-PLAN.md - [x] 01-08-PLAN.md — GameEventStore add/get/duplicate-warning regression; rawEvent and cycle baselines preserved - [x] 01-09-PLAN.md — GameMap point-event-only save aggregation; production registration deferred - [x] 01-10-PLAN.md - [x] 01-11-PLAN.md — CoreState legacy map initialization selects eventLayer; existing source-aware movement path remains reachable - [x] 01-12-PLAN.md — Close phase-owned type diagnostics and CRLF/Prettier quality-gate gaps without behavior changes **Wave 1** - [x] 01-01-PLAN.md — L0/L1 事件数据契约落地 + 图块/点位事件视图 + 存读档迁移 **Wave 2** *(blocked on Wave 1 completion)* - [x] 01-02-PLAN.md — 执行器接口用户确认(checkpoint)+ 执行器实现 + 删除旧 ITrigger(D-13)+ CoreState 装配 **Wave 3** *(blocked on Wave 2 completion)* - [x] 01-03-PLAN.md — moverImpl 踩踏触发重写为事件执行 + 阶段验收 **Wave 8** *(blocked on completed event ingestion, dispatch, and persistence gap plans)* - [x] 01-11-PLAN.md — CoreState legacy map initialization selects eventLayer; existing source-aware dispatch remains reachable **Wave 9** *(blocked on Wave 8 completion)* - [x] 01-12-PLAN.md — Phase-owned type and CRLF/Prettier gap closure ### Phase 2: 寻路系统 **Goal**: 引擎支持自动寻路,移动端点击地图即可触发移动 **Depends on**: Phase 1 **Requirements**: PATH-01, PATH-02 **Success Criteria** (what must be TRUE): 1. 角色能在地图上自动寻路移动到指定格 2. 移动端点击地图上的可达格时,角色自动寻路移动到该格 3. 寻路正确避开不可通行格(碰撞/障碍/墙体) **Plans**: 5/5 plans executed **Scope correction (2026-09-10):** 用户审查确认本阶段不交付未授权的 `HeroPathfinding` L3 勇士封装;当前阶段保留 L2 寻路核心、共享通行性谓词与 DataCommon 方向映射依赖,勇士或渲染侧接线不作为本阶段实现内容。 **UI hint**: yes Plans: - [x] 02-01-PLAN.md — 接口草案 + mover.ts:651 缺陷调查 + 回归脚手架 + D-07 用户拍板关卡(checkpoint) - [x] 02-02-PLAN.md — L0 坐标回写缺陷修复 + L2 寻路核心(有向图 + 最小损失 + 仅取路径 + 回退策略槽位) - [x] 02-03-PLAN.md — L3 接线(逐步/瞬移/回退默认策略/D-08 双语义/打断接管)+ barrel/logger 装配 + 阶段门禁 - [x] 02-04-PLAN.md — 恢复用户授权的 path/types.ts 契约并收口 moverImpl TS18047 - [x] 02-05-PLAN.md — 稳定全量 Vitest 门禁并提供非 watch 测试命令 **Wave 1** - [x] 02-01-PLAN.md — 接口草案与拍板关卡(autonomous: false) **Wave 2** *(blocked on Wave 1 用户拍板)* - [x] 02-02-PLAN.md — L0 修复 + L2 寻路核心 **Wave 3** *(blocked on Wave 2)* - [x] 02-03-PLAN.md — L3 接线与阶段门禁 ### Wave 4 *(gap closure; blocked on Wave 3 completion)* - [x] 02-04-PLAN.md — 用户契约范围与阶段类型错误收口 - [x] 02-05-PLAN.md — 全套件超时与跳过测试门禁收口 ### Phase 3: 数据端完成 **Goal**: 数据端 L0–L3 接口实现完成,数据层各系统可用并可在 Node 环境独立运行回放验证 **Depends on**: Phase 2 **Requirements**: DATA-01 **Success Criteria** (what must be TRUE): 1. 用户设计的 L0–L3 数据层接口全部落地,地图/角色/敌人/flag/战斗/触发器/存档/回放各系统可用 2. 数据端可在 Node 环境独立运行回放验证,无 DOM 依赖 3. 数据端与渲染端保持双端分离,渲染相关代码经 `r()`/`rf()` 门控或走 hook,渲染端不向数据端推送更新 4. 接口设计由用户主导,AI 仅负责实现 **Plans**: 19/19 plans executed Plans: - [x] 03-17-PLAN.md - [x] 03-18-PLAN.md - [x] 03-19-PLAN.md - [x] 03-10-PLAN.md - [x] 03-11-PLAN.md - [x] 03-12-PLAN.md - [x] 03-13-PLAN.md - [x] 03-14-PLAN.md - [x] 03-15-PLAN.md - [x] 03-16-PLAN.md - [x] 03-07-PLAN.md - [x] 03-08-PLAN.md - [x] 03-09-PLAN.md - [x] 03-01-PLAN.md — Node-safe CoreState、内部 legacy 依赖边界与最小 replay tracer - [x] 03-02-PLAN.md — 八个事件内建函数契约 checkpoint 与最小注册实现 - [x] 03-03-PLAN.md — 稳定 replay enum、异步 command 与 top-level 注册 - [x] 03-04-PLAN.md — 固定 Node 回放 fixture、首分歧 thrown diagnostic 与最终快照 - [x] 03-05-PLAN.md — DATA-01 focused closure 与四包 type/circular 最终门禁 - [x] 03-06-PLAN.md — Tile events contract 与 legacy conversion 收口 **Wave 1** - [x] 03-01-PLAN.md — Node-safe CoreState、内部 legacy 依赖边界与最小 replay tracer **Wave 2** *(blocked on Wave 1 completion)* - [x] 03-02-PLAN.md — 八个事件内建函数契约 checkpoint 与最小注册实现 - [x] 03-06-PLAN.md — Tile events contract 与 legacy conversion 收口 **Wave 3** *(blocked on Wave 2 completion)* - [x] 03-03-PLAN.md — 稳定 replay enum、异步 command 与 top-level 注册 **Wave 4** *(blocked on Wave 3 completion)* - [x] 03-04-PLAN.md — 固定 Node 回放 fixture、首分歧 thrown diagnostic 与最终快照 **Wave 5** *(blocked on Wave 4 completion)* - [x] 03-05-PLAN.md — DATA-01 focused closure 与四包 type/circular 最终门禁 ### Phase 4: 渲染适配与双布局(已过时) > **已过时(2026-10-08)**:原规划不再合理,由 Phase 9「最小浏览器可运行版本」承接;保留历史记录,不再据此推进。 **Goal**: 渲染端通过新数据层接口驱动,并同时支持移动端与桌面端布局 **Depends on**: Phase 3 **Requirements**: REND-01, REND-02 **Success Criteria** (what must be TRUE): 1. 用新数据层接口加载一张地图后,已重构的渲染端能正确渲染该地图场景 2. 桌面端布局下,地图、角色、界面元素正常显示并可操作 3. 移动端(窄屏)布局下,同一场景正常显示且可操作 4. 数据端与渲染端保持双端分离——数据端无 DOM,仍可在 Node 环境跑回放验证 **Plans**: 15 已执行 + 1 已规划待执行(04-16) — 04-01..04-07 已执行(04-06 = material 接口影响范围清点·只读;04-07 = material 接口适应实施·第二步);04-08(TextureManager 新接口影响范围清点·只读,D-38/D-39/D-40/D-41/D-42 第一步)已执行;04-09(TextureManager 新接口适应实施·第二步·代码改动,D-43..D-50)已执行;04-10(渲染端结构性重构影响范围清点·只读,D-51..D-57 第一步)已执行;04-11(渲染端结构性重构·第二步·移植实施·代码改动,D-58..D-68)已执行;04-12(04-11 落地修正·桶导出边界 + 消费者直连 + shared 单文件·代码改动,D-69/D-70)已执行(异地执行,commit 81e4e98;`8b114c7 docs(04-12): sync tracking`);**04-13(部分 UI 的进一步接口适配·第一步·只读收集,D-71/D-72/D-73)已执行**(交付 `04-UI-ADAPTATION-IMPACT.md`;A7/B5/C2/D5/E4/F5 + 8 行修改点汇总);**04-14(部分 UI 的进一步接口适配·第二步·适配实施,D-74..D-78)已执行**;**04-15(渲染端去单例化·第一步·只读收集,用户 2026-10-01 裁定)已执行**(交付 `04-RENDER-SINGLETON-AUDIT.md`,commit 6cff487);**04-16(渲染端去单例化·第二步·挂载 + 接口继承重构,用户 2026-10-01 裁定,F-01..F-07 已裁定)已规划待执行**(执行前须 Task 0 汇报关卡等待用户「可以执行」);渲染适配与移动端/桌面端双布局(REND-01/REND-02)整体仍未完成 **Plan register note (2026-09-21):** 第五个增量 `04-05`(收口 `#04-01-M-06` / `#04-01-M-09`:状态栏 9 个数值属性改经 `client.hero.attribute.getFinalAttribute(...)` 读取 + 逐图层钩子类 `RendererLayerHook`,2026-09-20 执行)此前未登记进本路线图,本次一并补登;第六个增量 `04-06` = material 接口适应(D-30/D-31/D-32)**第一步·只读影响清点**,产出 `04-MATERIAL-INTERFACE-IMPACT.md`,第二步(实施)待用户审阅后另行规划。第七个增量 `04-07` = material 接口适应实施(**第二步·代码改动**,D-33..D-37),2026-09-22 已执行(10 文件原子提交)。**第八个增量 `04-08` = TextureManager 新接口适应(D-38..D-42)第一步·只读影响清点**,产出 `04-TEXTURE-INTERFACE-IMPACT.md`;第二步(实施)待用户审阅后另行规划。 **Plan register note (2026-09-24):** 第十个增量 `04-10` = 渲染端结构性重构(用户裁定 2026-09-23 · D-51..D-57)**第一步·只读影响清点**:把 `packages-user/client-modules/src/render/` 下的通用内容(`render/components`、`render/elements`、`render/map` 三文件夹 + `render/utils/layout.ts`,规划日实测 **39** 文件)迁往渲染系统层 `packages-user/client-base/src/`(D-51/D-52;目标布局按 D-53:`client-base/src/{components,elements,map}/` + `client-base/src/layout/`,**不新建 `render/` 目录**);不移植 `render/utils/` 其余(`index.ts`/`saves.ts`/`use.ts`)与 `ui`/`fx`/`weather`/`render` 顶层文件(D-54);legacy 一律只报告(D-55);用户并发改动零触碰(D-56)。台账按 A 被移集合内部交叉引用 / B 外部导入点(含 `entry-client` / `entry-data` / `packages/legacy-ui` 经 `@user/client-modules` 公共面的间接依赖)/ C barrel 与导出面 / D 分层与循环依赖风险(`client-base` 不得反向依赖 `client-modules`,含 `package.json` 依赖现状)/ E legacy 命中(仅报告)/ F 未确定 六类分组,每行精确到文件或符号 + `file:line` 且 ≥2 锚点;产出 `04-STRUCTURE-MIGRATION-IMPACT.md`,生产代码零改动且**零命名变更**;**已规划待执行**,执行前须 Task 0 汇报关卡等待用户「可以执行」;第二步(移植实施)待用户审阅后另行规划;`REND-01` / `REND-02` 仍 Pending。 **Plan register note (2026-09-24 · 04-11 第二步):** 第十一个增量 `04-11` = 渲染端结构性重构**第二步·移植实施(代码改动)**(用户裁定 2026-09-24 · D-58..D-68)。**移植按 MOVE 落地**:把 D-52 的 **39** 文件(`render/components` 13 / `render/elements` 5 / `render/map` 20 / `render/utils/layout.ts` 1)按 D-53 放进 `packages-user/client-base/src/{components,elements,map}/` 与 `client-base/src/layout/layout.ts`(并新增 `layout/index.ts`,D-61),**并删除 `client-modules/src/render/` 下的原件**;D-58 另新建 `client-base/src/shared/`(从 `client-modules/src/shared.ts` 摘取被移 `map` 文件所需的 10 个常量,原文件保留);D-63 `client-base/src/index.ts` 新增 `./components` / `./elements` / `./map` / `./layout` / `./shared` 五条桶导出,实现层消费者(`render/ui` 8 文件 11 处含 `toolbar.tsx` 两处深层导入、`fallback/ui.ts:2`、`render/index.tsx:5,45,46`、`client.ts:25`、`types.ts:2`)改指 `@user/client-base`;被移 `map` 文件的 shared 说明符改指 4 处(D-58);D-59 / D-68 的架构耦合(`render/renderer` 3 处 + `render/use.ts` 5 处)与 D-60 的 `render/utils/` 断链(`index.ts:1` / `saves.ts:2`)共 **10** 处以带原因的 `// @ts-expect-error` 暂记,**不反向引用、不解耦**;D-66 `client-base/package.json` 新增 5 条 `workspace:*` 依赖(`@motajs/animate` / `@motajs/common` / `@motajs/render-vue` / `@motajs/system` / `@user/data-common`)并执行 `pnpm i`;D-64 `?raw` 不处理、D-65 legacy 一律不管、D-62 命名一律不变;门禁 = 目标落位 / 移动已发生 / 桶导出 / 依赖与 lockfile / 消费者改指 / 反向引用零命中 / `@ts-expect-error` 落点(10 处新增 + 既有 7 条保留)/ 39 文件允许差异 / 实现层差异 / 范围与用户改动 / 无 `import type` / CRLF 共 12 道 + 计划文件范围门禁 + 人工复核(**D-68 明示不要求可运行、不要求零类型错误,故不设 `check:type` / `build` / TS 诊断数类门禁**);`autonomous: false`(Task 0 汇报关卡);第二步的后续余留(自包引用未验证 / 两行同源星导出 / 8 处反向耦合接线 / D-60 断链)由用户接手;`REND-01` / `REND-02` 仍 Pending。 **Plan register note (2026-09-24 · 04-12 落地修正):** 第十二个增量 `04-12` = **04-11 落地修正·桶导出边界 + 消费者直连 + `shared` 单文件(代码改动)**(用户裁定 2026-09-24 · **D-69 / D-70**)。**D-69(桶导出边界原则,硬约束)**:一个 barrel(`index.ts` / `index.tsx`)**只允许 `export * from './<同目录下的文件或子文件夹>'`**、不得导出本文件夹之外的任何内容;反过来,任何需要被移内容的**消费端必须直接 `import ... from '@user/client-base'`**、**不得经任何 barrel 转发导出**。**D-70 的 6 条修正**:① `client-modules/src/render/utils/index.ts` **删除**指向 `./layout` 的越界转发 `export *` 及其 `@ts-expect-error`(保留 `./saves` / `./use`);② `render/ui/save.tsx` **拆分** `../utils` 导入(`adjustGrid` / `IGridLayoutData` → `@user/client-base`,`getSave` / `SaveData` 仍留 `../utils`)、`render/ui/title.tsx` 的 `adjustCover` → `@user/client-base`;③ `render/utils/saves.ts` 的 `getConfirm` / `waitbox` → `@user/client-base` 并**删除**其 `@ts-expect-error`;④ `client-base/src/shared/{shared.ts,index.ts}` **折成单文件** `client-base/src/shared.ts` 并删除 `shared/` 目录(`client-base/src/index.ts` 的 `export * from './shared'` 与 `map/*` 的 `'../shared'` / `'../../shared'` 说明符**不受影响**,无需改动);⑤ **逐字保留** `client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}` 内 **8** 处引用 `render/use.ts` / `render/renderer` 的架构耦合 `@ts-expect-error`(属 D-59 / D-67,留待用户收尾;`textboxTyper.ts` 另有 1 处既有 `无法推导` 标注同属保留,故这 7 文件合计 9 处);⑥ **不得**新增任何转发导出,`client-modules/src/render/index.tsx` **维持现状**(用户已删除越界两行,现合规)。旁注(仅报告):`packages/client/src/index.ts:1` 的 `export * from '@motajs/client-base'` 亦违反 D-69,但在 `packages/`(D-33 只报告)。改动面 = `client-base/src/shared.ts` + `client-modules/src/render/{utils/index.ts,utils/saves.ts,ui/save.tsx,ui/title.tsx}` 五个生产文件 + `files_deleted` 的 `client-base/src/shared/{shared.ts,index.ts}`;门禁 = 桶边界(8 个 in-scope barrel 的 `export * from` 全为 `./` 前缀 + `render/utils/index.ts` 不再转发 `./layout`)/ F1..F4 收口自检 / F5 的 8 处标注逐字保留 + porcelain 零命中 / 范围与用户改动 / CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);无依赖变更、不执行 `pnpm i`;本步不引入任何新命名;`REND-01` / `REND-02` 仍 Pending。 **Plan register note (2026-09-30 · 04-13 第一步):** 第十三个增量 `04-13` = **部分 UI 的进一步接口适配·第一步·只读收集需要修改的点(只读)**(用户裁定 2026-09-25 · **D-71 / D-72 / D-73**)。**要解决的问题**:数据端经 `d8fa4b8 refactor: Delete global loading & hook object` 与加载系统重构后,渲染端部分 UI 仍以旧接口编写——① 全局 `loading` / `hook` 对象已删除,组件不得再依赖它们监听全局钩子、**必须在对应对象上监听**(残留:`render/ui/main.tsx:146-151` 的 `hook.on('statusBarUpdate', ...)`、`render/index.tsx:35-38` 的 `hook.on('restart', ...)`,及 `main.tsx:140-143` 的手工单次调用);② 加载系统重构,旧加载 UI(`render/ui/load.tsx` 的 `LoadScene` / `LoadSceneUI`)已不能用,仍调用 `loader.initSystemLoadTask()` / `loader.load()` / `loader.progress`(`:71,72,76-79,91-92,118-119,139`),须重新适配新加载系统(`@motajs/loader` 的 `LoadManager` + `packages-user/data-state/src/loader/**` 的 `MotaDataLoader` / `IMotaDataLoader`)。**D-72**:本目标至少两个计划——第一个只读收集(生产代码零改动),第二个及后续才执行;第一个计划的产出是后续执行计划的输入。**D-73**:沿用 D-33 / D-42 / D-48 / D-49 / D-55 / D-65 / D-56 / D-68,**D-69 桶导出边界继续适用**。**交付物** = `.planning/phases/04-render-adaptation/04-UI-ADAPTATION-IMPACT.md`(只读影响台账):元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / A 全局 loading / hook 使用点(UI 面)/ B 目标对象与钩子 API 证据 / C 旧加载 UI 清单与新加载系统 / D 分层与 barrel(D-69)检查 / E legacy 命中(仅报告)/ F 未能从阅读确定(未猜测)/ 修改点汇总(供后续执行计划消费)/ 处置;A–E 固定列序表 `| ID | 项目 | 命中处 file:line | 目标锚点 / 证据 file:line | 问题描述 | 影响 | 置信 |`,事实行每行 ≥2 个 `file:line` 锚点、证据行带 `[证据行]` 标记;每个 A 点给出「应改监听 / 使用的对象」+ 现行源码证据,或显式 undetermined(进 F 类)。**边界**:被查 = 渲染端部分 UI(`client-modules/src/render/ui/**` + `render/index.tsx`);`client.ts` / `client-modules/src/index.ts` / `entry-client/src/create.ts` 的 `loading` / `hook` 使用点**只报告**(非 UI,是否纳入由用户裁定);`packages/` 与 `src/` 仅报告(D-33)。**门禁**:只读基线逐条一致 + 台账结构 / 内容 / 证据纪律(≥2 锚点)+ 范围与用户改动 + 既有 `04-01`..`04-12` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);**本步为只读、不引入任何命名变更**;`REND-01` / `REND-02` 仍 Pending。 **Plan register note (2026-09-30 · 04-14 第二步):** 第十四个增量 `04-14` = **部分 UI 的进一步接口适配·第二步·适配实施(代码改动)**(用户裁定 2026-09-30 · **D-74 / D-75 / D-76 / D-77 / D-78**)。**要解决的问题**:`04-13` 只读台账确认,数据端 `d8fa4b8 refactor: Delete global loading & hook object` 与加载系统重构后,渲染端部分 UI 仍以已删全局 `loading` / `hook` 与旧加载接口编写。**D-74..D-78 逐条落地**:① **D-78(tracer)** `render/ui/main.tsx` 删除全局 `hook` 状态栏监听残留(`:145-152`)与手工单次调用垫片(`:140-143`),改为在**勇士属性对象** `client.hero.attribute` 上 `addHook({ onUpdateAttribute })` 并在 `onUnmounted` 注销(接口 `packages-user/data-base/src/hero/types.ts:95-106`;触发点 `packages-user/data-base/src/hero/attribute.ts:89`),新增局部常量 `attributeHook`;② **D-74 / D-75** `render/ui/load.tsx` 以 `client.loader.start()`(`AsyncIterable`)取代旧「系统加载任务初始化 + 加载 + `progress` 迭代」三件套,进度 / 字节 / 任务读数一律取自 `client.loader.manager`(`ILoadManager`)的 `getLoadedTasks` / `getAddedTasks` / `getTotalByte` / `getLoadedByte` / `getByteRatio`,并移除 `:75` 失效 `@ts-expect-error`;③ **D-76** 删除 `render/index.tsx:35-38` 被注释 `restart` 监听块;④ **D-77** 删除 `client.ts:88-92,124-127` 两段被注释兼容层(含「兼容层」标签)与 `entry-client/src/create.ts:16,31,34-41` 被注释接线及模块创建函数块(`client-modules/src/index.ts` 经 `git grep` 实证**零残留、不编辑**)。**沿用约束** D-33 / D-42 / D-48 / D-49 / D-55 / D-56 / D-65 / D-68 / **D-69(本步零新增转发、不改任何 barrel)**。**开点(未裁定、默认不处置)**:旧加载 UI 的装配 / 可达性 —— `createGameRenderer`(`render/index.tsx:13`)无调用者、`LoadSceneUI` 仅在 `:25` 被 `sceneController.open`,本计划默认**不重新接线**,须用户另行裁定。**命名**:仅新增局部常量 `attributeHook`(Task 0 获批);不新增 / 改名任何公共 / 受保护 / 私有成员。**门禁**:编辑集最终形状 + 残留清零 + 范围(`material/` / `packages/` / `src/` / 数据端 / `packages/common` 零改动)+ 用户改动保留(`packages/common/src/{hook.ts,types.ts}` 与 `04-CONTEXT.md`,D-56)+ 白名单提交 + 既有 `04-01`..`04-13` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);无依赖变更、不执行 `pnpm i`;`REND-01` / `REND-02` 仍 Pending。 **Plan register note (2026-10-01 · 04-15 第一步):** 第十五个增量 `04-15` = **渲染端去单例化·第一步·只读收集(只读,用户 2026-10-01 裁定)**。**用户裁定**:渲染端(`packages-user/client-modules` 与 `packages-user/client-base`)**不得再保留单例**;现行一切单例须改为**挂载在主类上**(`ClientCore` / `client`),且各子系统须**继承 / 实现 `IClientBaseExtended`(`client-base/src/types.ts:27`)或 `ICoreStateExtended`(`data-state/src/types.ts:45`)**,镜像数据端模式(数据端单例 `data-state/src/ins.ts:11`;既有先例 `client-base/src/material/types.ts:94,218,406,439`)。**两步走**:第一步(本计划)= 只读清点全部单例(枚举 / 分类 / 消费者 / 目标映射;生产代码零改动、不引入任何命名变更);第二步(后续 04-16)= 挂载 + 接口继承重构。**交付物** = `04-RENDER-SINGLETON-AUDIT.md`(元信息块 + `只读起始基线` / `背景` / `方法` / `枚举口径` / A 模块级实例化对象 / B 可变模块级状态与全局注册表 / C 全局访问器与框架级全局引用 / D 顶层副作用模块 / E 主类关系与目标挂载面映射 / F 未能从阅读确定(未猜测)/ 单例→目标映射汇总 / 处置;事实行每行 ≥2 个 `file:line` 锚点,证据行 `[证据行]` 标记)。**沿用约束** D-33 / D-42 / D-48 / D-49 / D-55 / D-56 / D-65 / D-68 / D-69。**门禁** = 只读基线一致(含用户未提交 `data-system/src/combat/context.ts` 的正面对照 + 哈希)+ 台账结构 / 内容 / 证据纪律 + 范围与用户改动 + 既有 `04-01`..`04-14` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);**本步为只读、不引入任何命名变更**;`REND-01` / `REND-02` 仍 Pending。 **Plan register note (2026-09-23):** 第九个增量 `04-09` = TextureManager 新接口适应**第二步(实施·代码改动)**(用户裁定 D-43..D-50:`renderWithoutCheck` 三处调用点改新 `render(tile, connection)`;`BlockCls` / `cls` 判定改为 `tileType === TileType.Autotile`、不做映射表;`extension/hero.ts` 勇士字面量填 `tileType: TileType.Unknown`;`MapRenderer` 不再自建 `AutotileProcessor` 而取 `manager.autotile`、保留 `readonly autotile` 字段与 `IMapRenderer` 签名;不改 `material/**` 与加载面;不考虑 legacy 兼容)。对象 = `packages-user/client-modules/src/render/map/{vertex.ts,renderer.ts,extension/hero.ts}` 的 **13 条** texture 归属 TS 诊断(vertex 6 / renderer 5 / hero 2),目标归零;`moving.ts` 与 `render/map/types.ts` 经核实无需改动。**已规划待执行**,执行前须 Task 0 汇报关卡等待用户「可以执行」;`REND-01` / `REND-02` 仍 Pending(本步仅为 REND-01 的 texture 子切片)。 Plans: **Wave 1** - [x] 04-01-PLAN.md — 渲染端 ↔ 数据端接口对账(只读清点,产出 `04-RENDER-INTERFACE-AUDIT.md`;按 ① 错配 / ② 数据端缺失 / ③ 多余旧路径 三类登记) **Wave 2** *(blocked on Wave 1 completion)* - [x] 04-02-PLAN.md — 勇士移动接口探索(只读,D-17):产出 `04-HERO-MOVER-INTERFACE.md`(数据端现行接口 / 渲染端现状 / 逐成员三态对账 / 缺失接口候选 / 未确定 / 处置;排除 `HeroRendering`(D-18)与 `core.*`(D-12);不改任何代码,适配(04-03+)未规划) **Wave 3** *(blocked on Wave 2 completion)* - [x] 04-03-PLAN.md — 勇士本体适配(渲染端被动重接):`render/map/extension/{hero,types,manager}.ts` 绑定 `IHeroLocation` / `IHeroMover`,改接现有钩子 `IHeroLocationHooks` / `IObjectMoverHooks`(D-21),按 D-20 裁剪 `IMapHeroRenderer` 的外部驱动成员;排除贴图/不透明度(D-18)、跟随者(D-22)、移动控制(D-19)、`core.*`(D-12)与裸函数(D-11),不新增数据端接口 **Wave 4** *(blocked on Wave 3 completion)* - [x] 04-04-PLAN.md — 勇士渲染修正(04-03 人工审查反馈 D-24..D-29):`render/map/extension/{hero,types,manager}.ts` 注入 `IFaceManager`(`faceManager`;`degrade`/`next` 走 `Dir4FaceHandler`、`movement` 走勇士 `mover.faceHandler`(Dir8)——D-24/D-29)并替换三个弃用 helper;`IMapExtensionManager.addHero(state, layer, faceManager)` 新增参数(D-29,改 `types.ts` 接口签名);拆分 `MapHeroLocationHook` / `MapHeroMoverHook` 且 `onSetPos` 无条件(D-25)、补 `AnimDir`(D-26)、改 `@motajs/animate` 的 `ExcitationCurve2D`(D-27)、保留存量 `state` 用法(D-28);不新增数据端接口,排除 D-18/D-19/D-22 **Wave 5** *(blocked on Wave 4 completion)* - [x] 04-05-PLAN.md — 收口 `#04-01-M-06` / `#04-01-M-09`:状态栏 9 个数值属性从失效的 `getHeroStatusOn` 改经 `client.hero.attribute.getFinalAttribute(...)` 读取(并移除 `main.tsx:28` 失效的 `@ts-expect-error`);新增模块内不导出类 `RendererLayerHook`(`Partial`)把逐图层 `onUpdateArea` / `onUpdateBlock` 转发到 `MapRenderer.updateLayerArea` / `updateLayerBlock`,并在 `setLayerState` / `updateLayerList` 两条路径注册与注销(M-06 使用 `client` 单例经用户裁定为 D-23 的显式例外)— **2026-09-20 已执行**(本次补登) - [x] 04-06-PLAN.md — material 接口影响范围清点(**只读**,D-30/D-31/D-32 第一步):以 `4e305e3` 后的 `client-base/src/{types.ts,material/types.ts}` 为基准,清点 `packages-user` 内对已移除 7 符号(`IBigImageReturn` / `isBigImage` / `getBigImage` / `getIfBigImage` / `getBigImageByAlias` / `setBigImage` / `bigImageStore`)、3 个改名接口、新增 `textures` 与 4 处 `ICoreStateExtended` 约束未实现、以及所有 big-image 残留(含 `material/manager.ts` 与 `render/elements/cache.ts`)的引用,按 A 已移除 / B 改名 / C 约束未实现 / D big-image 残留 / E 范围外命中(`src/`、`packages/` 仅报告)/ F 未确定 六类分组,每行精确到符号 + `file:line`;产出 `04-MATERIAL-INTERFACE-IMPACT.md`,生产代码零改动,第二步实施待用户审阅后另行规划 **Wave 6** *(blocked on Wave 5 completion)* - [x] 04-07-PLAN.md — material 接口适应实施(**第二步·代码改动**,D-30/D-31/D-32 第二步 + D-33..D-37):按 04-06 清点的 A/C/D/E 四类落地——A 类(D-34)删除全部 big-image 引用并把 `getIfBigImage` 的 7 处消费者(`door.ts` 2 / `hero.ts` 3 / `renderer.ts` 1 / `vertex.ts` 1)改为行为等价的 `getTile`、删除 `renderer.ts` `getOffsetPool` 的 big-image 偏移收集;C 类(D-35)为 `MaterialManager` 补 `textures`、为 `MaterialManager` / `AutotileProcessor` / `AssetBuilder` / `TrackedAssetData` 补构造器注入的 `state`(不取全局单例,D-23;`renderer.ts` 从 `manager.state` 取值);D 类(D-36)删除 `MaterialManager` 的 big-image 实现残留(`bigImageStore` / `bigImageData` / `bigImageId` / 五个方法 / `setDefaultFrame` 耦合)与 `render/elements/cache.ts` 的 legacy big-image 路径;E 类(D-37)为 `client-base/package.json` 补 `@user/data-state` 声明(不安装、不同步 lockfile)。10 个文件原子提交;门禁 = material 归属诊断归零 + 在范围文件零诊断 + 总行数不增加(规划日 199 / 19 → ≤ 180)+ `packages-user` 内 big-image 记号归零 + eslint / CRLF / 范围(基线感知)/ 并发基线;运行时 UAT 不可得(渲染端无测试设施)如实声明 **Wave 7** *(blocked on Wave 6 completion)* - [x] 04-08-PLAN.md — TextureManager 新接口影响范围清点(**只读**,D-38/D-39/D-40/D-41/D-42 第一步):以 `d36ea69`(`refactor: 贴图存储方式`)后的 `client-base/src/{types.ts,material/types.ts,material/manager.ts,material/autotile.ts,material/index.ts}` 为基准,清点 `packages-user` 消费者面对改名(`MaterialManager`→`TextureManager` 与构造器)、移除(`BlockCls` 枚举 / `IMaterialFramedData.cls`→`tileType` / `IAutotileProcessor` 三方法合一 / `renderAnimatedWith`→`renderAnimated` / `getIdentifierByAlias` / `getAliasByIdentifier` / `getBlockCls(ByAlias)` / `IClientBase.autotile` / `create()` 与 `createMaterial()`)与新增收紧(`tiles` / `autotile` / `tilesetReserve` / `tilesetUnit` / `getFrameCount` / 四个 `add*` 参数 / `flatten` / `AutotileType` / `IClientCoreConfig` 两个必填字段)的引用,按 A 符号改名与移除 / B 成员与签名变化 / C 地图渲染消费者定位索引 / D 被删且无替代(需用户反馈)/ E 加载相关与添加素材(仅报告,D-39/D-41)/ F 未确定 六类分组,每行精确到符号 + `file:line` 且 ≥2 锚点;产出 `04-TEXTURE-INTERFACE-IMPACT.md`,生产代码零改动(`material/` 按 D-42 只登记),第二步实施待用户审阅后另行规划 **Wave 8** *(blocked on Wave 7 completion)* - [x] 04-09-PLAN.md — TextureManager 新接口适应实施(**第二步·代码改动**,D-43..D-50):`renderWithoutCheck` 的三处调用点(`render/map/vertex.ts:461`、`render/map/vertex.ts:874`、`render/map/renderer.ts:1253`)改新 `render(tile, connection)` 且不保留跳过检查入口(D-43);自动元件判定与解构(`render/map/renderer.ts:1252` / `:1263`、`render/map/vertex.ts:517` / `:561` / `:872` 与 `:852`)改 `tileType === TileType.Autotile`,不做映射表、不用 `AutotileType` 分类(D-44);`render/map/extension/hero.ts:167` 填 `tileType: TileType.Unknown`(D-45,D-18 不排除该文件);`MapRenderer` 保留 `readonly autotile: IAutotileProcessor` 字段与 `IMapRenderer` 签名、构造器改取 `manager.autotile`、不再自建 `AutotileProcessor`(D-46);只做接口适应不重设计 `textures` / `tileStore` / `tiles`(D-47)、`material/**` 零改动(D-48)、不考虑 legacy 兼容(D-49)、`IBlockIdentifier` 零出现(D-50);`moving.ts` 与 `render/map/types.ts` 无需改动;门禁 = 三文件 texture 归属诊断 13→0 + eslint / prettier / CRLF / 符号零命中 / 基线与禁用路径;`autonomous: false`(Task 0 汇报关卡);`REND-01` / `REND-02` 仍 Pending **Wave 9** *(blocked on Wave 8 completion)* - [x] 04-10-PLAN.md — 渲染端结构性重构影响范围清点(**只读**,D-51..D-57 第一步):把 `packages-user/client-modules/src/render/` 的通用内容(`render/components`、`render/elements`、`render/map` 三文件夹 + `render/utils/layout.ts`,规划日实测 **39** 文件)迁往渲染系统层 `packages-user/client-base/src/`(D-51/D-52),目标布局按 D-53(`client-base/src/{components,elements,map}/` + `client-base/src/layout/`,不新建 `render/`);不移植 `render/utils/` 其余(`index.ts`/`saves.ts`/`use.ts`)与 `ui`/`fx`/`weather`/`render` 顶层文件(D-54);legacy 只报告(D-55)、用户并发改动零触碰(D-56)。台账按 A 被移集合内部交叉引用(8 方向:`components→elements`、`elements→map`、→ `render/renderer`、→ `render/use.ts`、→ `client-modules/src/shared.ts`、→ `@user/client-base` 自包引用、`map/extension/*→map/types`、零命中机器证据)/ B 外部导入点(`client-modules/src/{client.ts,types.ts}`、`render/index.tsx`、`render/ui` 8 文件 11 处含深层导入、`render/utils/{saves.ts,index.ts}`、`fallback/ui.ts`,以及 `entry-client` / `entry-data` / `packages/legacy-ui` 经公共面的间接依赖)/ C barrel 与导出面(7 节点 + 断链判定)/ D 分层与循环依赖风险(`client-base` 不得反向依赖 `client-modules`;`client-base/package.json` 依赖缺口;`?raw` shader;`dev.md` 规则对照)/ E legacy 命中(仅报告)/ F 未确定 六类分组,每行 ≥2 个 `file:line` 锚点;产出 `04-STRUCTURE-MIGRATION-IMPACT.md`,生产代码零改动且零命名变更;门禁 = 只读基线逐条一致 + 10 节结构 / 39 文件清单 / 类别行数与双锚点 / 两处零命中机器证据 / CRLF / 既有产物保护与计划范围 + 人工复核;`autonomous: false`(Task 0 汇报关卡);第二步(移植实施)待用户审阅后另行规划;`REND-01` / `REND-02` 仍 Pending **Wave 10** *(blocked on Wave 9 completion)* - [x] 04-11-PLAN.md — 渲染端结构性重构·**第二步·移植实施(代码改动)**(D-58..D-68):把 D-52 的 **39** 文件(`render/components` 13 / `render/elements` 5 / `render/map` 20 / `render/utils/layout.ts` 1)按 D-53 放进 `packages-user/client-base/src/{components,elements,map}/` 与 `client-base/src/layout/layout.ts`(新增 `layout/index.ts`,D-61)并**删除 `client-modules/src/render/` 下的原件**(MOVE);D-58 新建 `client-base/src/shared/`(摘取被移 `map` 文件所需的 10 个常量,`client-modules/src/shared.ts` 保留)并把被移 `map` 文件的 shared 说明符改指 4 处(`'../shared'` × 3 / `'../../shared'` × 1);D-63 `client-base/src/index.ts` 新增 `./components` / `./elements` / `./map` / `./layout` / `./shared` 五条桶导出,实现层消费者(`render/ui` 8 文件 11 处含 `toolbar.tsx` 两处深层导入、`fallback/ui.ts:2`、`render/index.tsx:5,45,46`、`client.ts:25`、`types.ts:2`)改指 `@user/client-base`;D-59 / D-68 的 `render/renderer`(3 处)与 `render/use.ts`(5 处)耦合、D-60 的 `render/utils/`(`index.ts:1` / `saves.ts:2`)断链共 **10** 处加带原因 `// @ts-expect-error`,**不反向引用、不解耦**;D-66 `client-base/package.json` 新增 5 条 `workspace:*` 依赖(`@motajs/animate` / `@motajs/common` / `@motajs/render-vue` / `@motajs/system` / `@user/data-common`)并执行 `pnpm i`;D-64 `?raw` 不处理、D-65 legacy 一律不管、D-62 命名一律不变;门禁 = 目标落位 / 移动已发生 / 桶导出 / 依赖与 lockfile / 消费者改指 / 反向引用零命中(`@user/client-modules` 于 `client-base`)/ `@ts-expect-error` 落点(10 新增 + 7 既有)/ 39 文件允许差异 / 实现层差异 / 范围与用户改动 / 无 `import type` / CRLF 共 12 道 + 计划文件范围门禁 + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);`REND-01` / `REND-02` 仍 Pending **Wave 11** *(blocked on Wave 10 completion)* - [x] 04-12-PLAN.md — 04-11 落地修正·**桶导出边界 + 消费者直连 + `shared` 单文件(代码改动)**(D-69 / D-70):按 **D-69(硬约束:barrel 只允许 `export * from './<同目录项>'`,消费者必须直连 `@user/client-base`、不得经 barrel 转发)** 落地 D-70 的 6 条修正——① `client-modules/src/render/utils/index.ts` **删除**指向 `./layout` 的越界转发 `export *` 与其 `@ts-expect-error`(保留 `./saves` / `./use`);② `render/ui/save.tsx` 拆分 `../utils` 导入(`adjustGrid` / `IGridLayoutData` → `@user/client-base`,`getSave` / `SaveData` 仍留 `../utils`)、`render/ui/title.tsx` 的 `adjustCover` → `@user/client-base`;③ `render/utils/saves.ts` 的 `getConfirm` / `waitbox` → `@user/client-base` 并删除其 `@ts-expect-error`;④ `client-base/src/shared/{shared.ts,index.ts}` 折成单文件 `client-base/src/shared.ts` 并删除 `shared/` 目录(`client-base/src/index.ts` 的 `./shared` 与 `map/*` 的 4 处相对说明符**一字不改**、仍解析);⑤ **逐字保留** `client-base/src/{components/{choices,input,misc,scroll,textboxTyper,tip}.tsx,elements/index.ts}` 内 **8** 处引用 `render/use.ts` / `render/renderer` 的架构耦合 `@ts-expect-error`(D-59 / D-67,留待用户收尾;`textboxTyper.ts` 另有 1 处既有 `无法推导` 标注同属保留,故这 7 文件合计 9 处);⑥ **零新增转发导出**、`client-modules/src/render/index.tsx` 维持现状;门禁 = 桶边界(8 个 in-scope barrel 的 `export * from` 全为 `./` 前缀 + `render/utils/index.ts` 不再转发 `./layout`)/ F1..F4 收口自检 / F5 的 8 处标注逐字保留 + porcelain 零命中 / 范围与用户改动 / CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);无依赖变更、不执行 `pnpm i`;本步不引入任何新命名;`REND-01` / `REND-02` 仍 Pending **Wave 12** *(blocked on Wave 11 completion)* - [x] 04-13-PLAN.md — 部分 UI 的进一步接口适配·**第一步·只读收集需要修改的点(只读,D-71 / D-72 / D-73)**:以 `d8fa4b8 refactor: Delete global loading & hook object` 后的工作树为基准,收集渲染端**部分 UI** 对已删全局 `loading` / `hook` 与旧加载系统的使用点,产出 `04-UI-ADAPTATION-IMPACT.md`(元信息块 + `只读起始基线` / `背景` / `方法` / `基准变更(d8fa4b8)` / A 全局 loading / hook 使用点(UI 面)/ B 目标对象与钩子 API 证据 / C 旧加载 UI 清单与新加载系统 / D 分层与 barrel(D-69)检查 / E legacy 命中(仅报告)/ F 未能从阅读确定(未猜测)/ 修改点汇总 / 处置;A 类 = `render/ui/load.tsx` 旧加载接口(`:71,72,76-79,91-92,118-119,139`)+ `render/ui/main.tsx` `statusBarUpdate`(`:140-143,146-151`)+ `render/index.tsx` `restart`(`:35-38`),边界非 UI 面(`client.ts:88-92,124-127` / `client-modules/src/index.ts` / `entry-client/src/create.ts:16,31,34-41`)只报告;B 类逐处给目标对象证据(`IMotaDataLoader` / `ILoadManager` / 数据端可 hook 对象接口)或 undetermined;C 类登记旧 `LoadScene` / `LoadSceneUI` 与已删 `client-base/src/load/**` + 新 `@motajs/loader` / `data-state/src/loader/**` / `CoreState.loader` / `loadManager`;D 类 4 个 barrel 节点(只报告);E 类 legacy 只报告;F 类 ≥ 5 条未确定项;事实行每行 ≥2 个 `file:line` 锚点),**本步生产代码零改动、不引入任何命名变更**;门禁 = 只读基线一致 + 台账结构 / 内容 / 证据纪律 + 范围与用户改动 + 既有 `04-01`..`04-12` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);第二步(适配实施)待用户审阅后另行规划(D-72);`REND-01` / `REND-02` 仍 Pending **Wave 13** *(blocked on Wave 12 completion)* - [x] 04-14-PLAN.md — 部分 UI 的进一步接口适配·**第二步·适配实施(代码改动,D-74 / D-75 / D-76 / D-77 / D-78)**:`render/ui/main.tsx` 状态栏改在勇士属性对象 `client.hero.attribute` 上注册 `onUpdateAttribute` 钩子(tracer,删除全局 `hook` 残留与手工调用垫片,新增局部 `attributeHook`);`render/ui/load.tsx` 改依 `client.loader.start()` + `client.loader.manager.get*`;删除 `render/index.tsx:35-38` 的 `restart` 注释块与 `client.ts:88-92,124-127` / `entry-client/src/create.ts:16,31,34-41` 的非 UI 残留(`client-modules/src/index.ts` 零残留不编辑);默认不重新接线旧加载 UI 装配点(开点,待用户裁定);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);门禁全静态(不设 `check:type` / `build` / TS 诊断数类门禁,D-68 的延续);`REND-01` / `REND-02` 仍 Pending **Wave 14** *(blocked on Wave 13 completion)* - [x] 04-15-PLAN.md — 渲染端去单例化·**第一步·只读收集(只读,用户 2026-10-01 裁定)**:收集 `packages-user/client-modules` 与 `packages-user/client-base` 内**全部单例**(模块级实例化对象 / 可变模块级状态 / 全局注册表 / 全局访问器 / 框架级全局引用 / 顶层副作用模块),产出 `04-RENDER-SINGLETON-AUDIT.md`(元信息块 + `只读起始基线` / `背景` / `方法` / `枚举口径` / A 模块级实例化对象 / B 可变模块级状态与全局注册表 / C 全局访问器与框架级全局引用 / D 顶层副作用模块 / E 主类关系与目标挂载面映射 / F 未能从阅读确定(未猜测)/ 单例→目标映射汇总 / 处置;每个单例映射到「挂主类 `ClientCore` / `client` + `IClientBaseExtended`(`client-base/src/types.ts:27`)/ `ICoreStateExtended`(`data-state/src/types.ts:45`)之一 + 既有先例证据」,无法确定者进 F 类;事实行每行 ≥2 个 `file:line` 锚点);**本步只读、生产代码零改动、不引入任何命名变更**;门禁 = 只读基线一致(含用户未提交 `data-system/src/combat/context.ts` 的正面对照 + 哈希)+ 台账结构 / 内容 / 证据纪律 + 范围与用户改动 + 既有 `04-01`..`04-14` 产物保护 + CRLF + 人工复核(**不设 `check:type` / `build` / TS 诊断数类门禁**,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);第二步(04-16:挂载 + 接口继承重构)待用户审阅后另行规划;`REND-01` / `REND-02` 仍 Pending **Wave 15** *(blocked on Wave 14 completion)* - [ ] 04-16-PLAN.md — 渲染端去单例化·**第二步·挂载 + 接口继承重构(代码改动,用户 2026-10-01 裁定,F-01..F-07 已裁定)**:镜像数据端分层(单一 `ClientCore implements IClientCore extends IClientSystem extends IClientBase`;字段声明在层接口):把 client-modules 的 `using` / `sceneController` / `mainUIController` 在 `ClientCore` 构造器中实例化并挂为 `IClientCore` 字段(F-02);重复实例以 `ClientCore` 为准(F-03);`GameUI` 不挂、`UIController` 挂(F-04);`texture`(F-01)/ `DEFAULT_FONT` / 所有 `GameUI` 保留不动(F-04/F-07);client-base 层与 `client-system` 不改;`this.state` 可调用处迁移、其余先不管;不新增全局 `client` 引用(D-23)、不建转发别名(dev.md);门禁全静态(不设 `check:type` / `build` / TS 诊断数类门禁,D-68 的延续);`autonomous: false`(Task 0 汇报关卡等待用户「可以执行」);`REND-01` / `REND-02` 仍 Pending **UI hint**: yes ### Phase 5: Legacy 移植(已过时) > **已过时(2026-10-08)**:原规划不再合理,由 Phase 9「最小浏览器可运行版本」承接;保留历史记录,不再据此推进。 **Goal**: 删除被新接口覆盖的 legacy 系统,迁移仍需要的内容 **Depends on**: Phases 1-4 **Requirements**: LEGACY-01, LEGACY-02 **Success Criteria** (what must be TRUE): 1. 被新接口覆盖的 legacy 系统已删除,代码中无残留引用 2. 仍需要的 legacy 内容已迁移到新接口 3. 仅当无新接口覆盖时才新增接口,且接口设计经用户 review 4. 移植后引擎仍能完整跑通一部魔塔,无功能回归 **Plans**: TBD ### Phase 6: 单元测试(已过时) > **已过时(2026-10-08)**:原规划不再合理,由 Phase 9「最小浏览器可运行版本」承接;保留历史记录,不再据此推进。 **Goal**: 为核心系统(数据层等)补齐单元测试 **Depends on**: Phases 1-5 **Requirements**: TEST-01 **Success Criteria** (what must be TRUE): 1. 核心数据层系统有单元测试覆盖 2. 测试覆盖关键行为(战斗伤害、触发器、寻路、事件等) 3. 测试在本地可运行且全部通过 4. 测试由 AI 编写并运行,通过验证后可提交 **Plans**: 9/9 原计划 executed replanned (D-28;旧 06-01/06-02 执行结果标记 superseded,按同号重跑;数据端切片,非数据 render/legacy 覆盖延后) + gap-fill 06-10..06-15 (D-46;人工评审缺口补测,只补测试不改生产代码;15/15 executed) + perf 06-16 (性能测试补充;只加测试与配置,不改生产代码) + perf 06-17 (真实地图存读档性能补充;移入 13 张真实地图夹具,只加测试与夹具) + perf 06-18 (真实大地图场景性能补充;整条 lane 计时改为 `performance.mark`/`measure` + 新增 `mapScenario.perf.ts`,只加测试不改生产代码) Plans: - [x] 06-01-PLAN.md — Combat L2 (data-system/src/combat) + EnemyContext aura pipeline / effect combos / full interface & code coverage (D-21..D-27) - [x] 06-02-PLAN.md — enemy top-level BASIC functionality only (data-state/src/enemy;单分支,无组合,无 save/load) - [x] 06-03-PLAN.md — Enemy data model full public surface except legacy (data-base/src/enemy;无 save/load) - [x] 06-04-PLAN.md — Replay focus ReplayArray ops + encode/decode + system/sandbox/decorators (data-common/src/replay;无 save/load,完整播放→06-07) - [x] 06-05-PLAN.md — Hero ALL files incl. rendering + async mover (data-base/src/hero;无 save/load) - [x] 06-06-PLAN.md — Map ALL interfaces, emphasis static/dynamic tiles + static arrays (data-base/src/map;无 save/load) - [x] 06-07-PLAN.md — Top-level integration: damage combos + map+replay play + second-play re-record equality; error 2001–2008 (user confirmed replay recording wired) - [x] 06-08-PLAN.md — Flag full surface + common (utils/indexer/faceManager+face/mover) (无 save/load) - [x] 06-09-PLAN.md — Save/load independent system: every saveState/loadState class + CoreState top-level (BLOCKED: pre-execution user confirmation) **Wave 1** *(independent test-writing plans; no shared production edits)* - [x] 06-01-PLAN.md - [x] 06-02-PLAN.md - [x] 06-03-PLAN.md - [x] 06-04-PLAN.md - [x] 06-05-PLAN.md - [x] 06-06-PLAN.md - [x] 06-08-PLAN.md **Wave 2** *(blocked on Wave 1 + user confirmation)* - [x] 06-07-PLAN.md — depends on 06-02/06-04/06-06; replay recording wired by user (17d7c8f), SUMMARY complete - [x] 06-09-PLAN.md — depends on 06-03/06-05/06-06/06-08; requires user to adjust CoreState saveables + add public save/load entry **Wave 3** *(gap-fill batch, D-46; extends existing `*.test.ts`, no production edits)* - [x] 06-10-PLAN.md — combat/enemy combination gaps: G-06-01-A/B/C + G-06-07-A - [x] 06-11-PLAN.md — hero/map gaps: G-06-05-A + G-06-06-A/B/C - [x] 06-12-PLAN.md — replay/enemy gaps: G-06-04-B (runnable) + G-06-04-A/G-06-03-A (correct-expectation skip) - [x] 06-13-PLAN.md — save/load gaps: G-06-09-A/B (only plan testing saveState/loadState, D-32) **Wave 4** *(G-06-04-C follow-up gap-fill, D-46; serialized after 06-12 because it shares `array.test.ts`)* - [x] 06-14-PLAN.md — replay read-stream gaps: G-06-04-C/A (stream-only complex route + middle start index) + G-06-04-C/B (per-param typed assertions, index progression, expired-after-mutation); blocked `#06-04-3`/`#06-04-4` as correct-expectation `it.skip` **Wave 5** *(G-06-01-D interface-coverage gap-fill, D-46; serialized after 06-14)* - [x] 06-15-PLAN.md — combat interface gap: G-06-01-D (`EnemyContext.deleteAura` normal case — `addAura` applies `atk 2→5` → `deleteAura` same instance → `buildup` expects `2`); blocked `#06-15-1` (same root cause as `#06-01-4`) as correct-expectation `it.skip`, pending user decision **Wave 6** *(performance-test supplement, user-authorized; appended after 06-15; isolated `test:perf` lane + new `*.perf.ts` files, no production edits, no new dependencies)* - [x] 06-16-PLAN.md — perf supplement: `vitest.perf.config.ts` + `test:perf` script (isolated from `pnpm test:ci`); 18 cases = ② critical calc (`1000/10000/50000`) + ① enemy-context `buildup` (N = `50/200/1000`) + ③ hero attribute recalc (M = `10/100/1000`) + ④ CoreState save/load round trip (`10/100/1000` items × `NoCompression`/`LowCompression`/`HighCompression`); warmup 3 + 20 samples → median/min/p95 via `console.table`, **zero assertions**, results recorded in `06-16-SUMMARY.md` **Wave 7** *(realistic map save/load perf supplement, user-authorized; appended after 06-16; reuses the same isolated `test:perf` lane; one fixture move + one new `*.perf.ts`, no production edits, no new dependencies)* - [x] 06-17-PLAN.md — realistic map save/load perf: move the root `floors.json` (13 real 13×13 maps) into `packages-user/data-state/test/fixtures/`; new `packages-user/data-state/test/saveablesReal.perf.ts` measuring `存档`/`读档`/`往返` (save-only / load-only / round trip) for map scale `1/5/13` × `NoCompression`/`LowCompression`/`HighCompression` (27 rows) with a fixed realistic side load (50 flags, 20 hero modifiers incl. 4 from equipped items, 4 equipped instances, 20 item kinds, 1000 replay steps); cleared live map (`2/3/4/6` → `0`) vs original `compareWith` reference so `HighCompression` stores changed rows; warmup 3 + 20 samples → median/min/p95 via `console.table`, **zero assertions**, results recorded in `06-17-SUMMARY.md` **Wave 8** *(realistic large-map combat scenario perf supplement + lane-wide timing-method upgrade, user-authorized; appended after 06-17; reuses the same isolated `test:perf` lane; timing helper switch in 5 existing files + one new `*.perf.ts`, no production edits, no new dependencies)* - [x] 06-18-PLAN.md — timing method upgrade + realistic large-map combat scenario perf: switch the inlined `measureCase` in **all** `*.perf.ts` from `globalThis.performance.now()` to `performance.mark` + `performance.measure` (unique per-case tags, per-sample `clearMarks`/`clearMeasures`; same `case`/`scale`/`median ms`/`min ms`/`p95 ms` columns, warmup 3 + 20 samples, record-only); new `packages-user/data-state/test/mapScenario.perf.ts` merging the 13 real 13×13 maps into ONE grid-tiled map (`ceil(sqrt(n))` columns, placed at `(col*13, row*13)`) for scale `1/5/13` → `13×13`/`39×26`/`52×52` with 11/79/204 monster tiles, 12 real `Enemy` prefabs (4 carrying real auras: `CommonAura` Full/Manhattan/Rect + `GuardAura`), `mulberry32`-seeded assignment, `createCoreState()` real wiring + `resize` + `addPrefab` + `fromRaw` + per-tile `setEnemyAt`; measures ① `enemyContext.buildup()` ② `mapDamage.refreshAll()` + per-monster `getSeparatedDamage`/`getReducedDamage` ③ one real `calculateCritical(view, 'atk')` per monster (plus a second table reporting `monsters`/`total ms`/`avg ms`); results recorded in `06-18-SUMMARY.md` ### Phase 7: 数据端缺陷修复 **Goal**: 修复 Phase 6 单元测试暴露的数据端疑似缺陷,使正确预期用例转绿,且仅限数据端、不涉及渲染端 **Depends on**: Phase 6 **Requirements**: FIX-01 **Success Criteria** (what must be TRUE): 1. 06-TEST-FINDINGS.md 登记的数据端疑似缺陷全部处置完毕(修复或经用户裁定改契约/不修复):#06-01-1..4、#06-03-1、#06-04-1..4、#06-05-1..3、#06-06-1、#06-07-1、#06-08-1、#06-09-1/2/3/5,以及同根因的 #06-15-1(#06-09-4 已作废) 2. 对应的正确预期 it.skip 用例在修复后取消 skip 并通过;无法修复的缺陷经用户确认后同步修正接口文档/契约 3. pnpm test:ci 全绿且不新增跳过用例,数据范围 check:type / check:circular 门禁通过 4. 改动仅限数据端(packages 与 packages-user/data-*),不改动渲染端 @user/client-* 与 legacy 渲染接线,双端分离约束保持 **Plans**: 16 plans — 07-01..07-15 已执行(07-15 完成 4 条复审缺口修复);**07-16 标记为 SUPERSEDED(2026-10-04)**:寻路重构后的测试对齐批次不再执行,其缺口清单转为 Phase 8 的对齐输入(按 D-02 一系统一计划;每个计划以 D-09 预执行汇报关卡开头,`autonomous: false`) > **阶段重开(2026-09-16)**:`07-LOADSTATE-AUDIT.md` 登记的同引用审计条目 `#06-17-1`(A)与 `#06-17-2`(B)在本阶段收口后追加为计划 `07-09`,Phase 7 因此由 `Complete` 回到未完成;执行 07-09 后 `07-VERIFICATION.md`(2026-09-16 结论仅覆盖 8/8 计划的工作树)**失效,必须重跑 `/gsd-verify-work`** 重新出具验证结论。 > **阶段二次追加(2026-09-16)**:`07-LOADSTATE-AUDIT.md` 的同引用审计条目 **C–H**(`#06-17-3..8`)、`07-REVIEW.md` 的 **CR-01 / CR-02** 与 4 条相关警告(WR-01/02/03/07、WR-04/05/06)、以及 `06-TEST-FINDINGS.md` 中此前「只登记不修」的部分,经用户裁定**由「登记」转为「修复」**,追加为计划 `07-10`(replay 编解码与索引编辑)、`07-11`(容器同引用存读档)、`07-12`(装备/属性存档正确性)、`07-13`(地图失效边界)、`07-14`(legacy hero 代理)。07-09 的范围守卫(「C–H 只登记不修」)据此**解除**。 > 每个计划以 `checkpoint:decision`(`gate="blocking-human"`)关卡开头,逐条列出需用户裁决的契约点(`set()` 语义、录像格式版本、溢出处置、诊断码、逐子系统同引用保留、读档禁录、失效契约等);**契约未裁决前不得执行**。执行完毕后 `07-VERIFICATION.md` 必须重跑。 > **阶段三次追加(2026-09-17)**:Phase 7 关闭后的增量代码复审 `07-REVIEW-recheck.md` 报出 8 条发现(1 Critical + 3 Warning + 4 Info)。其中 4 条 Info 由用户自行修复并提交(`34ba9e8`/`219ac49`/`3a3a6ac`/`a2a8e6e`);剩余 **CR-01 / WR-01 / WR-02 / WR-03** 追加为计划 `07-15`,**已执行完毕**(`53f067a`/`a7c9f97`/`49116c0`/`bb19865` + `07-15-SUMMARY.md`)。共同成因:第二轮批次仅以「让目标用例转绿」为目标,未按设计语言把契约、簿记与边界条件一次做对。 > **阶段四次追加(2026-09-17)**:用户完成寻路系统重构(`4aaea68`)后,数据端 **17 个测试文件 / 73 用例**因接口变动与形状变化失败(接口族:寻路 `useMapState`/`useDirGroup` 变更、录像 `route`→`array` 与 `onRecordCommand` 0-based 索引、`HeroLocation.setFloor(IGameMap)`、`CoreState.initMapState` 删除;另含 5 个疑似行为变化的文件)。经用户要求追加计划 `07-16`(**只改测试、不改生产代码**),已完成规划并登记缺口(`07-VERIFICATION.md` 的 `### Post-Refactor Test Breakage`)。 > **该计划暂缓(DEFERRED)**:用户观察到数据端仍需大量手工修改、并将继续导致测试报错,故等数据端全部改完后再执行。恢复时该缺口清单(2026-09-17 快照)与 `07-16-PLAN.md` **须先重新核对(很可能需要重规划)**,再走 `/gsd-execute-phase 7 --gaps-only`;随后 `/gsd-verify-work 7` 重出验证。 > **该计划 SUPERSEDED(2026-10-04)**:用户已完成数据端「系统性收尾」,接口再次变动,17 行快照与 `07-16-PLAN.md` 均已过期;该计划退役、不再执行,测试文件迁移与接口对齐整体转由 **Phase 8** 承接,`07-VERIFICATION.md` 的 `### Post-Refactor Test Breakage` 作为 Phase 8 的对齐输入。 Plans: - [x] 07-16-PLAN.md — **SUPERSEDED(2026-10-04)**:寻路重构后的测试对齐批次——原计划把 17 个测试文件对齐到 2026-09-17 快照的接口(只改测试、不改生产代码),含 5 个疑似行为变化文件待用户 Task 0 逐行裁决。因数据端「系统性收尾」再次变动接口,该快照与计划均已过期,**转由 Phase 8 承接**(缺口清单作为 Phase 8 输入) - [x] 07-15-PLAN.md — 复审缺陷批次:CR-01(`HeroEquipment.compareEquip` 对已装备项漏算)/ WR-01(`normalizeParam` 回退口径致字节偏移错位)/ WR-02(`checkBufferExpand` 乘数为 1 时自我递归)/ WR-03(`HeroAttribute.clone()` 绕过簿记)——**已执行**(`07-15-SUMMARY.md`) - [x] 07-10-PLAN.md — replay:CR-01(`set()` 索引数组损坏,与 `delete()` 对齐)/ 审计 H `#06-17-3`(`setReplayArray` 漏 `expireStreams`)/ WR-01(bigint 长度字节溢出)/ WR-02(参数计数用未截断长度)/ WR-03(编解码格式版本)/ WR-07(`insert`/`delete`/`set` 越界校验) - [x] 07-11-PLAN.md — 容器同引用:`#06-17-4`(`equipStore` 重建实例脱钩)/ `#06-17-5`(`flag/system` 字段脱钩)/ `#06-17-6`(followers 重建脱钩) - [x] 07-12-PLAN.md — 装备/属性存档正确性:WR-04(装备修饰器活值未持久化)/ WR-05(`deleteModifierByIndex` 簿记残留)/ WR-06(`HeroEquipment.loadState` 读档写录像) - [x] 07-13-PLAN.md — 地图:CR-02(`MapDamage` 幽灵伤害:来源消失/范围收缩后缓存残留)/ `#06-17-8`(`MapLayer.setMapRef` 失效契约 + 读档旧动态块累积) - [x] 07-14-PLAN.md — legacy:`#06-17-7`(`data-fallback` `core.status.hero` 代理闭包持有读档前属性)——**经用户裁定 WONTFIX(不修复)**:兼容层即将删除,Q1..Q4 一律不改动;零代码改动、零新增测试(`07-14-SUMMARY.md`) - [x] 07-09-PLAN.md — hero:`#06-17-1` / `#06-17-2` 同引用修复(`HeroAttribute` 自身实现 `ISaveableContent`,属性存读档在自身实例上原地完成;`IHeroStateSave` 形状变更 + 装备修饰器不入属性存档) - [x] 07-01-PLAN.md — combat:`#06-01-1` / `#06-01-2` / `#06-01-3` / `#06-01-4`(含 `#06-15-1`) - [x] 07-02-PLAN.md — enemy:`#06-03-1` 创建入口接入复用映射 - [x] 07-03-PLAN.md — replay:`#06-04-1` / `#06-04-2` / `#06-04-3` / `#06-04-4` - [x] 07-04-PLAN.md — hero:`#06-09-1`(高)/ `#06-09-2` / `#06-05-1` / `#06-05-2` / `#06-05-3`(D-06 保留) - [x] 07-05-PLAN.md — map:`#06-06-1`(D-04 改发 128)/ `#06-09-3` - [x] 07-06-PLAN.md — flag+common:`#06-08-1` 后退基准修正 - [x] 07-07-PLAN.md — save:`#06-09-5`(D-05 差集方向取反 + 既有用例纠偏) - [x] 07-08-PLAN.md — path:`#06-07-1`(D-07 用户接线后取消 skip 验证) **Wave 1** - [x] 07-01-PLAN.md — combat 四条根因(含既有 3 条绿用例纠偏) **Wave 2** *(blocked on Wave 1)* - [x] 07-02-PLAN.md — enemy 复用映射 **Wave 3** *(blocked on Wave 2)* - [x] 07-03-PLAN.md — replay 编解码与索引编辑 **Wave 4** *(blocked on Wave 3)* - [x] 07-04-PLAN.md — hero 存读档与属性/槽位 **Wave 5** *(blocked on Wave 4)* - [x] 07-05-PLAN.md — map 诊断码与动态图块读档 **Wave 6** *(blocked on Wave 5)* - [x] 07-06-PLAN.md — flag+common 后退基准与契约注释 **Wave 7** *(blocked on Wave 6)* - [x] 07-07-PLAN.md — save 码 178 语义与既有用例纠偏 **Wave 8** *(blocked on Wave 7 + 用户完成 D-07 接线)* - [x] 07-08-PLAN.md — path 顶层录像瞬移验证(用户负责接线,AI 仅取消 skip) **Wave 9** *(blocked on Wave 8)* - [x] 07-09-PLAN.md — hero 属性同引用存读档(`#06-17-1` / `#06-17-2`;`HeroAttribute` 实现 `ISaveableContent`) **Wave 10** *(blocked on Wave 9;用户裁决 Task 0 契约后执行)* - [x] 07-10-PLAN.md — replay 编解码与索引编辑(CR-01 / `#06-17-3` / WR-01 / WR-02 / WR-03 / WR-07) **Wave 11** *(blocked on Wave 10)* - [x] 07-11-PLAN.md — 容器同引用存读档(`#06-17-4` / `#06-17-5` / `#06-17-6`) **Wave 12** *(blocked on Wave 11)* - [x] 07-12-PLAN.md — 装备/属性存档正确性(WR-04 / WR-05 / WR-06) **Wave 13** *(blocked on Wave 12)* - [x] 07-13-PLAN.md — 地图失效边界与动态块(CR-02 / `#06-17-8`) **Wave 14** *(blocked on Wave 13)* - [x] 07-14-PLAN.md — legacy hero 代理:经用户裁定 **WONTFIX**(`#06-17-7`;兼容层即将删除,零代码、零测试;计划原定的该包首个测试文件按裁决不产出) ### Phase 8: 测试重构与接口对齐 **Goal**: 将全部测试文件(`.test.ts` / `.perf.ts`)迁入 `__test__` 目录,并按数据端「系统性收尾」后的当前接口重对齐测试、修复重构遗漏的细节问题,使 `pnpm test:ci` / `test:perf` 重新全绿 **Depends on**: Phase 7(数据端缺陷修复) **Requirements**: TEST-02 **Success Criteria** (what must be TRUE): 1. 全部 `.test.ts` 与 `.perf.ts` 均位于各自源码目录下的 `__test__` 文件夹内,测试命令仍能发现并运行它们 2. 因数据端接口变动而失效的测试全部对齐到当前 shipped 接口,`pnpm test:ci` 0 失败 3. 重构遗漏的细节问题已修复(测试面或经用户确认的数据端细节),不弱化既有断言 4. `pnpm test:perf` 仍可运行;不新增跳过用例 **Plans**: 11/11 plans completened(08-01..08-11;规划 2026-10-04,`gsd-plan-checker` 判 PASS / 0 blocker / 3 非阻塞 warning)——迁移 `08-01`(独立先行)→ 子系统对齐 `08-02..08-09` → 错误码与接口覆盖 `08-10` → 收口 `08-11`;每个计划 `autonomous: false`,以 blocking-human Task 0 汇报关卡开头 Plans: - [x] 08-01-PLAN.md — 全量目录迁移到 `__test__/`(Rule A/B 分流改相对导入 + `script/test-data-node.ts:67,122` 硬编码路径;门禁=文件数守恒 66/6、零配置/零生产改动) - [x] 08-02-PLAN.md — data-common 对齐(`utils.test.ts` 退役、`DirectionMapper` 删除、`addHook().load()` 移除、158/175→72;含经确认的 sandbox 首步预读生产修复) - [x] 08-03-PLAN.md — data-base enemy+flag 对齐(真实 `TileStore` + 注册图块、删 legacy bridge、`getPrefab` 签名 `number|string` 类型修正、flag 读档重建语义对齐) - [x] 08-04-PLAN.md — data-base hero 对齐(录像桩 `array`、删 `.load()`、真实 `TileStore`/`ItemStore(tileStore)`、`setFloor(IGameMap|null)`、`getItem`→`addItem`;含经确认的 `equipment.loadState` 读档禁录修复) - [x] 08-05-PLAN.md — data-base map 对齐(`addLayer(alias)`、`MapState(state)`;陈旧码 62/63/64/84/130/125 裁决;含 D-10 生产修复,map 聚焦 108/108 通过) - [x] 08-06-PLAN.md — data-system combat+event 对齐(`CombatFlow` 构造、`.load()` 移除、DEV 守卫码) - [x] 08-07-PLAN.md — data-system path 对齐(`useMapState` 删除、`useFaceHandler` 注入) - [x] 08-08-PLAN.md — data-state src 对齐(`createCoreState` 删除→`CoreState({loadStarter,coreURL})`;`coreEventLayer` A1/A2) - [x] 08-09-PLAN.md — data-state 集成对齐(共享夹具 `closed-loop.ts`、`tileLegacy` 去留、寻路注入) - [x] 08-10-PLAN.md — 错误码 21 缺口 + loader 公共接口覆盖盘点与补测 - [x] 08-11-PLAN.md — 收口(`test:ci`+`test:perf` 全绿、skipped=1、零生产改动终审、阶段 SUMMARY) **Scope note (2026-10-04)**: 由原 `07-16`(寻路重构后的测试对齐,已 SUPERSEDED)转来并扩展,加入「测试文件迁入 `__test__`」的组织重构要求。用户并发进行渲染端收尾,可能触及数据端内容但不改接口设计、不影响测试;AI 不得提交用户改动的文件,发生冲突须暂停汇报。 **Input (2026-10-04)**: `07-VERIFICATION.md` 的 `### Post-Refactor Test Breakage`(2026-09-17 的 17 行快照)作为对齐起点,但**必须先重测当日失败清单**,不得直接沿用旧快照。 ### Phase 9: 最小浏览器可运行版本 **Goal**: 在已完成的数据端(可在 Node 环境独立运行/回放验证)之上完成渲染端框架,产出可在浏览器中运行并验证的最小版本 **Requirements**: TBD **Depends on**: Phase 8 **Plans**: 10/10 plans executed (任务 1·UI 接口适配,D-10..D-14 已闭环;任务 2·迁移后 UI 修复,D-15..D-17 已闭环;任务 3·legacy UI 移植,book/equipbox/toolbox 已规划(09-06..09-08)并已按用户补齐的数据端接口修订——裸怪物临界 `calculateEnemyCritical`、与空装备对比 `compareEquip(-1)`、道具枚举 `iterateItems`、`@user/data-system` 依赖已声明;shop 已规划(09-09,D-38..D-41)并已按用户补齐的接口修订——价格 `IShopState.getPrice`/`setPrice`(GAP-S1 闭合)、交易 `IShopSystem.buyItem`/`sellItem`(GAP-S2 闭合)、支付资源 `money`(GAP-S3 闭合)、`IShopState` 已从 `@user/data-base` 导出(GAP-S0 闭合),**GAP-S4 已闭合(用户补齐 `@user/data-system` 的 `shop` 导出:`data-system/src/index.ts` `export * from './shop'` + `data-system/src/shop/index.ts`,`IShopSystem` / `IShopHeroAttr` 现可导入)**;本阶段增量派发,其余任务待用户再派发;**任务 5(09-11·legacy 接口只读统计)已规划、待用户派发后执行(只读产物,wave 8)**) Plans: **Wave 1** - [x] 09-01-PLAN.md — 任务 1·D-10(上):`render/ui/` → `src/ui/` 迁移叶子/基础模块(save/statistics/viewmap/controller 去重)+ barrel 骨架 + `load.tsx`/`title.tsx` props 基类型修正 **Wave 2** *(blocked on Wave 1 completion)* - [x] 09-02-PLAN.md — 任务 1·D-10(收口):剩余模块(main/settings/statusBar/toolbar)迁移 + 跨目录引用改写 + 删尽 `render/ui/` + D-69 桶收口(公共面经包根 `./ui` 承接)+ `pnpm test:ci` 回归 **Wave 3** *(blocked on Wave 2 completion)* - [x] 09-03-PLAN.md — 任务 1·D-11 + D-13:`client` 单例消除(改经 `props.state`)+ 旧→新映射表落地 + 嵌套 `state` 透传 + flags `// TODO`(模块单例 `using`/`mainUIController`/`sceneController` 与 `state`(data-state) 列为阻断项待裁定) **Wave 4** *(blocked on Wave 3 completion)* - [x] 09-04-PLAN.md — 任务 1·D-12(定向重设计):把 `leftStatus` / `rightStatus` 迁入 `statusBar.tsx` 由状态栏组件自持 + 属性 9 字段与 `lv` 走 `hero.attribute` 钩子、`floor` 走 `hero.location` 钩子、无钩子字段 `// TODO` + 清理 `main.tsx` **Wave 5** *(blocked on Wave 4 completion)* - [x] 09-05-PLAN.md — 任务 2·A + B + C:prettier 格式化 `background.tsx`/`statusBar.tsx`(D-15)+ `IUIController`/`UIController` 补 ``(14 处调用点 + 2 构造点,D-16)+ `src/ui/**` 迁移遗留类型错误修复(`main.tsx` `p`→`props`;`statusBar.tsx`/`toolbar.tsx` props 基类型归位;`settings.tsx` `loc` 窄化,D-17)+ 定向 `vue-tsc`/prettier 门禁 **Wave 6** *(blocked on Wave 5 completion · 三个界面互相独立、可并行)* - [x] 09-06-PLAN.md — 任务 3·book 怪物手册(D-23..D-27):列表 `book.tsx`(绑定 `props.state.enemyContext`、按 `code` 去重、`baseAttribute`、9 项数值含「1 防」、滚动、点击开详情)+ 独立详情 `bookDetail.tsx`(`IEnemy|IEnemyView`、基础↔计算后切换、仅特殊列表、临界走系统二分法接口、左下切换/右下返回) - [x] 09-07-PLAN.md — 任务 3·equipbox 装备界面(D-28..D-32):`equipbox.tsx`(左列状态区域 + 右侧 装备描述/装备槽横滚/拥有装备纵滚;选中增减;点击选中/再点穿上/拖拽装脱/右下退出;入参 `IHeroState` + 属性 id+中文名列表) - [x] 09-08-PLAN.md — 任务 3·toolbox 道具栏(D-34..D-36):`toolbox.tsx`(三列 永久/可消耗/名称+说明;数量降序同数量按 id;单击选中/再点使用 `useItem`;无丢弃拖拽;入参 `IHeroState`) - [x] 09-09-PLAN.md — 任务 4·shop 商店界面(D-38..D-41,已按用户补齐接口修订):`shop.tsx`(顶部 购买/售出 切换;左 商店列表 id 排序/库存右对齐/显滚动条;右 名称·描述·购入量选择(按钮上方 买价/卖价/存货/拥有/总价,买价/卖价经 `IShopState.getPrice`)·购买/售出按钮;四按钮 `<< < {量} > >` ±10/±1、按物品分别记忆;右下退出;入参 `IShopState` + `IHeroState` + `IShopSystem`(交易经 `buyItem`/`sellItem`);**GAP-S4 已闭合:`IShopSystem` / `IShopHeroAttr` 已从 `@user/data-system` 公共面导出**) **Wave 7** *(blocked on Wave 6 completion · 对四个界面(五文件)的复查修正,R-1..R-8)* - [x] 09-10-PLAN.md — 任务 3·复查修正(R-1..R-8):对 `book.tsx`/`bookDetail.tsx`/`equipbox.tsx`/`toolbox.tsx`/`shop.tsx` 统一应用——R-1 移除自绘背景、R-2 长文本改 `TextContent`、R-3 顶层 jsDoc、R-4 JSX 分段注释、R-5 取消 `IShopItemEntry`/`IHeroAttrItem` 导出、R-6 非空判断(字面量 `isNil`/对象 `!`,去 `=== null`/`=== undefined`)、R-7 `shop` 的 `openShop` 移入 `onMounted`、R-8 `bookDetail` 改 `instanceof EnemyView`(已核实 `EnemyView` 为运行期类) **Wave 8** *(独立于 Wave 6/7 · 任务 5·legacy 接口只读统计,只读产物)* - [ ] 09-11-PLAN.md — 任务 5·legacy 接口只读统计(D-42..D-45):只读扫描 `packages-user/client-base` + `packages-user/client-modules` 两包,产出统计文档 `.planning/phases/09-minimum-browser-runnable/09-LEGACY-INTERFACES-AUDIT.md`(第 0 节分类口径 A-1..A-7 + A 残余 legacy 接口 + B `@deprecated` + C `core.*` 调用点 + 汇总表 + 每类计数);**全程只读,零 `.ts`/`.tsx` 改动** ## Progress **Execution Order:** Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9(4/5/6 已过时,实际推进 1 → 2 → 3 → 7 → 8 → 9) | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. 事件系统 | 13/13 | In Progress| | | 2. 寻路系统 | 5/5 | In Progress| | | 3. 数据端完成 | 19/19 | Complete | 2026-09-12 | | 4. 渲染适配与双布局 | 15/16 | Obsolete(由 Phase 9 承接) | - | | 5. Legacy 移植 | 0/TBD | Obsolete(由 Phase 9 承接) | - | | 6. 单元测试 | 18/18 | Obsolete(由 Phase 9 承接) | - | | 7. 数据端缺陷修复 | 15/16 | Complete(07-16 superseded) | - | | 8. 测试重构与接口对齐 | 11/11 | Complete | 2026-10-08 | | 9. 最小浏览器可运行版本 | 10/11 | In Progress| |