This commit is contained in:
2026-04-19 20:33:18 +08:00
parent 692643136f
commit 67c584b4df
123 changed files with 11898 additions and 4082 deletions

View File

@@ -15,6 +15,7 @@
- [FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md](./FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md)Function 运行时完整测试、服务端承接验证与当前门禁缺口。
- [ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md](./ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md):物品生成与 Build 标签系统对 PRD 的落地情况。
- [CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md](./CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md):自定义世界创作工具当前问题、体验断层和优化优先级审计。
- [engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md):未引用垃圾、旧入口残留、前后端双份真相与后端迁移项的专项审计。
## 推荐使用方式

View File

@@ -0,0 +1,524 @@
# 工程清理与后端边界审计2026-04-19
更新时间:`2026-04-19`
## 0. 审计目标
本次审计只回答四类问题:
1. 项目里哪些内容已经是高置信度的垃圾、临时产物或无入口代码。
2. 哪些实现属于双份真相、重复映射或旧链路残留。
3. 哪些前端代码仍然承担了应迁移到 Express 后端的职责。
4. 哪些文件已经大到会持续拖累迭代效率,需要优先拆分。
---
## 1. 结论先行
当前仓库的主要问题不是“有一些小工具没人用”,而是四类结构性噪音同时存在:
1. **仓库噪音产物仍然很多。**
根目录残留了大量 `.codex-*.log``tmp_*`、旧截图/HTML以及 `temp-build-goal-check/` 这类大体量检查产物,已经不是单个文件层面的脏数据,而是在持续污染工程视野。
2. **旧入口和新入口并存,形成了明显的冗余链路。**
`scripts/dev-server/localApiPlugins.ts` 已经退出当前正式开发入口,但仍保留了 LLM proxy、JSON 写盘、资产发布等整套旧 Vite 本地 API 机制。
3. **前端仍然承载了过多运行时规则与 AI 编排。**
`src/services/ai.ts``src/services/customWorld.ts``src/hooks/story/npcEncounterActions.ts` 这类文件,仍在浏览器里承担 prompt 组装、规则判定、奖励结算、剧情推进等职责。
4. **后端边界还没有真正闭合。**
`server-node` 虽然已经承接了大量路由和运行时动作,但仍直接 import `src/services/customWorld*.ts``src/types.ts`,说明后端领域层还没有完全从前端目录中独立出来。
一句话判断:
**这轮优先级不该再是继续堆功能,而是先清仓库噪音与无入口孤岛,再把前后端双份真相收口,最后拆新的巨型热点文件。**
---
## 2. 本次审计方法与口径
### 2.1 方法
本次审计结合了四类证据:
1. 文档基线:
- `docs/audits/engineering/CURRENT_ENGINEERING_OPTIMIZATION_PRIORITIES_2026-04-10.md`
- `docs/planning/EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md`
- `docs/planning/EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md`
- `scripts/dev-server/README.md`
2. 当前入口核对:
- `src/main.tsx`
- `src/routing/appRoutes.tsx`
- `src/App.tsx`
- `package.json`
- `server-node/package.json`
3. 静态依赖扫描:
-`src/``server-node/src/``packages/shared/src/``scripts/``650` 个 TS/JS 文件做本地依赖图扫描。
4. 定向 grep
- 核对旧 dev 插件入口、后端跨层 import、localStorage 使用、运行时快照双写、重复映射代码。
### 2.2 口径说明
为避免误判,本次审计明确排除了两类对象:
1. **包脚本入口**:例如 `scripts/build-gate.mjs``scripts/check-encoding.mjs``server-node/build.mjs` 这类由 `package.json` 直接执行的脚本,不因“无 import”而判为垃圾。
2. **字符串路径消费的资源**:例如 `src/data/itemOverrides.json``src/data/monsterOverrides.json` 会被校验脚本和 editor route 以文件路径读取,不按“无 import”处理。
另外,当前工作区存在未提交改动,因此本次结论以**已纳入当前主链且能确认未接线/重复/越界的内容**为主,不把明显的当日 WIP 文件计入垃圾结论。
---
## 3. 高置信度垃圾、临时产物与无入口代码
## 3.1 仓库噪音产物已经到了需要集中清理的程度
### 证据
| 项目 | 当前证据 | 判断 |
| --- | --- | --- |
| 根目录日志/临时文件 | 根目录命中 `60``.codex-*.log``.preview.*``tmp_*``npc-editor-*``temp-write-check.txt`,合计约 `52.36 MB` | 已经不是偶发临时文件,而是长期堆积的开发残留 |
| `temp-build-goal-check/` | 当前包含 `15099` 个文件,合计约 `166.56 MB` | 大体量检查产物,应该移出主工程视野 |
| Python 缓存 | 当前存在 `scripts/__pycache__/` | 纯缓存产物,不应长期留在仓库工作区中 |
### 影响
1. 根目录信噪比明显下降,真实工程文件被大量一次性产物淹没。
2. `temp-build-goal-check/` 虽然已被 `.gitignore``vite.config.ts` 的 watch 忽略模式覆盖,但 `.eslintrc.cjs``ignorePatterns` 里没有对应口径,仍存在工具口径不一致问题。
3. 这类目录会持续干扰检索、review、lint 判断和本地扫描速度。
### 建议
1. 把根目录临时日志、扫描 txt/html、旧截图统一迁到单独的 `tmp/` 或本地缓存目录,默认不留在仓库根目录。
2.`temp-build-goal-check/` 改成真正的外置检查产物目录,或者在 lint/脚本口径上一起排除。
3. 清理 `scripts/__pycache__/`,并统一补上 Python 缓存忽略规则。
---
## 3.2 旧 Vite 本地 API 插件链已经退出主入口,但仍保留整套旧实现
### 证据
1. `scripts/dev-server/README.md` 已明确写明:`scripts/dev-server/**` 不再是当前开发入口,只保留为迁移参考。
2. `scripts/dev-server/localApiPlugins.ts` 当前仍有 `1664` 行。
3. 仓库内已经找不到 `localApiPlugins` 的实际代码入口引用,当前只剩文档引用。
4. 该文件内部仍然同时定义和拼装:
- `createLlmProxyPlugin`
- `createJsonFileEditorPlugin`
- `createCustomWorldSceneImagePlugin`
- `createCharacterVisualPublishPlugin`
- `createCharacterAnimationPublishPlugin`
- `createCharacterAssetStudioPlugins`
- `createQwenSpriteSheetToolPlugins`
### 判断
这不是“一个小工具暂时没用”,而是**整条旧 editor/assets 本地 API 链路仍然完整保留在仓库里**。它在工程上已经属于高置信度的历史残留。
### 建议
1. 如果只保留迁移证据,建议把 `scripts/dev-server/localApiPlugins.ts` 和相关说明迁到 `docs/reference/` 或单独的 `archive/` 目录。
2. 如果确实还要保留参考代码,至少要在文件顶部加更强的“只读参考、禁止继续扩展”标识,并从主工程扫描面上进一步隔离。
3. 不建议继续在这条旧链路里新增任何 `/api/*` 能力。
---
## 3.3 当前存在一批“无运行时入口”或“仅测试引用”的孤岛模块
### 高置信度无入口/仅测试引用清单
| 模块 | 证据 | 判断 |
| --- | --- | --- |
| `src/components/GameShell.tsx` | 文件体量 `761` 行;当前 `src/App.tsx` 只接入 `components/game-shell/GameShellRuntime.tsx`;仓库内无其它 import | 旧版壳层残留 |
| `src/components/custom-world-home/CustomWorldCreationHub.tsx` | 仅被 `CustomWorldCreationHub.test.tsx``CustomWorldCreationHub.interaction.test.tsx` 引用;`src/routing/appRoutes.tsx` 只有 `game``qwen-sprite-tool` 两条路由 | 已做出 UI但未进入正式入口 |
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | 当前无运行时引用 | 同属未接线入口壳层 |
| `src/components/custom-world-agent/*``9` 个子模块 | 当前合计约 `826` 行;典型文件包括 `CustomWorldAgentLauncherModal.tsx``CustomWorldAgentDraftDrawer.tsx``CustomWorldAgentLockBar.tsx``CustomWorldAgentQuickActions.tsx``CustomWorldAgentSummaryPanel.tsx`;部分文件完全无引用,部分仅被测试引用 | 处于“做了一部分 UI但未进入主链”的孤岛状态 |
| `src/hooks/story/storyBootstrap.ts` | `250` 行,仓库内只定义不消费 | 已被新流程替代的可能性高 |
| `src/hooks/useEquipmentFlow.ts` / `useForgeFlow.ts` / `useInventoryFlow.ts` | 合计约 `393` 行,当前无运行时引用 | 旧流转层残留 |
| `src/editor/shared/cloneValue.ts` / `EditorEmptyState.tsx` / `EditorSelectionCard.tsx` / `useJsonSave.ts` | 当前无运行时引用 | editor 旧共享层碎片 |
| `src/services/customWorldPresentation.stub.ts` | 当前无引用,且文件本身就是 stub | 高置信度占位残留 |
| `src/services/typewriter.ts` | 当前无引用,仅提供一个 `getTypewriterDelay` | 已被其它链路内联实现替代 |
| `src/data/buildTagSimilarity.generated.ts` | 当前 `823` 行,仅能被生成脚本自身检索到,没有消费方 | 生成产物未接入任何业务链路 |
| `src/data/customWorldCharacterLoadout.stub.ts` | 当前无引用,且实现只返回空数组 | 占位残留 |
| `src/components/DeveloperTeamModal.tsx` / `src/components/LazySkillEffectPreview.tsx` | 当前无运行时引用 | 小体量零散孤岛 |
### 判断
这批文件不一定都应该“立刻删除”,但它们已经满足两个至少其一:
1. 当前正式入口完全不消费。
2. 只剩测试在消费,本体没有真实运行时位置。
所以它们至少都应该进入以下三选一处理:
1. 立即归档/删除。
2. 明确接回正式入口。
3. 改名或迁目录,标明“实验稿/参考稿/未接线”身份。
### 特别提醒
`src/components/custom-world-home/``src/components/custom-world-agent/` 这两组文件里,存在**已经有一定 UI 完成度、但没有进入真实路由/流程**的情况。
这类文件最危险的点不是体量,而是会让后来者误以为“这块功能已经在主链上”。
---
## 4. 冗余实现与双份真相
## 4.1 Story option interaction 映射在前后端各维护了一份
### 证据
1. 前端 `src/services/runtimeStoryService.ts``buildRuntimeOptionInteraction` 维护了 `npcActionMap``treasureActionMap`
2. 后端 `server-node/src/modules/story/storyActionService.ts``buildStoryOptionInteraction` 维护了几乎同构的一份 `npcActionMap``treasureActionMap`
### 风险
1. 任何一个 functionId 增删改,前后端都要同步。
2. 一边先改、一边漏改时,表现层和运行时层会出现静默漂移。
### 建议
把 interaction/view model 映射收口到后端,前端只消费后端返回的结构,不再根据 `functionId` 本地重建一遍交互语义。
---
## 4.2 浏览历史已经有后端接口,但前端仍维护本地真相与迁移状态
### 证据
1. `src/components/game-shell/PreGameSelectionFlow.tsx` 中,`appendBrowseHistoryEntry` 先调用 `writePlatformBrowseHistory` 写本地,再调用 `upsertProfileBrowseHistory` 写后端。
2. 同文件启动阶段又会先读 `readPlatformBrowseHistory`,再根据 `hasPendingPlatformBrowseHistoryMigration` 把本地历史同步回后端。
3. 后端 `server-node/src/routes/runtimeRoutes.ts` 已经提供了 `/profile/browse-history` 路由,而前端 `src/services/storageService.ts` 也已有对应 API SDK。
### 判断
当前浏览历史并不是单纯的“本地缓存”,而是**本地存储 + 远端持久化 + 迁移标记**三套状态并存。
### 建议
1. 后端结果作为唯一真相源。
2. 前端如果要保留缓存,只保留一个明确的 cache wrapper不再把它做成独立状态系统。
3. `markPlatformBrowseHistoryMigrated` 这种迁移标记应尽量在后端一次性收口,而不是长期停留在正式前端逻辑里。
---
## 4.3 运行时快照依然由前端先落本地,再与后端会话互相回填
### 证据
1. `src/hooks/story/runtimeStoryCoordinator.ts` 在读状态和提交 action 前都会先调用 `putSaveSnapshot`
2. 同文件以及 `src/services/runtimeStoryService.ts` 又会在响应后多次 `rehydrateSavedSnapshot`
3. 这意味着浏览器仍然在“后端 action 之前”先写一份自己的快照解释。
### 判断
这条链路说明当前运行时还处在**前端快照解释权没有完全退出**的过渡状态。
### 建议
1. 前端逐步退化为 view model 消费层。
2. 运行时快照、版本迁移、恢复解释权继续往后端收口。
3. 前端保留最小必要的离线展示缓存,但不再成为正式运行时状态真相来源。
---
## 4.4 旧 Vite 本地 API 与正式 Express 路由仍然形成重复能力面
### 证据
1. `scripts/dev-server/localApiPlugins.ts` 里仍有 JSON 编辑、场景图生成、角色视觉发布、角色动作发布等插件。
2. 当前正式路径已经迁到:
- `server-node/src/modules/editor/**`
- `server-node/src/modules/assets/**`
3. `scripts/dev-server/README.md` 已明确说明旧链路只保留为迁移参考。
### 判断
这属于典型的**旧能力未删除,新能力已落地,双链路长期并存**。
### 建议
尽快把旧 Vite 本地 API 参考实现移出主工程扫描面,避免后续继续被误用或被误认为正式入口。
---
## 5. 需要迁移到后端的代码
## 5.1 `src/services/ai.ts` 仍然承担了过多正式运行时职责
### 当前职责
`src/services/ai.ts` 当前约 `2632` 行,仍然同时承担:
1. function 可用性与 option 构造相关逻辑。
2. NPC 对话 / 招募 prompt 构造。
3. 自定义世界生成 prompt 与 JSON 修复请求。
4. 直接调用 `requestPlainTextCompletion` / `streamPlainTextCompletion`
5. 浏览器内 fallback 与响应解析。
### 判断
这不是单纯的“前端请求 SDK”而是**前端仍在承担正式运行时 AI orchestration**。
### 建议迁移方向
1. prompt 组装、模型调用、超时重试、JSON repair 继续收口到 `server-node/src/modules/ai/**`
2. 前端只保留轻量 SDK 和展示态拼装。
3. fallback 如果必须保留,也应明确区分“开发兜底”与“正式运行时”。
---
## 5.2 `src/services/customWorld.ts` 仍然是前端侧的大型规则中心
### 当前职责
`src/services/customWorld.ts` 当前约 `2413` 行,仍然承担:
1. 世界框架与角色/地标 outline 归一化。
2. 世界属性 schema 生成。
3. `ownedSettingLayers` 归一化。
4. 最终世界 profile 校验。
5. fallback story graph/theme pack 生成。
### 当前越界证据
后端目前直接从以下文件 import 这些能力:
1. `server-node/src/modules/ai/customWorldOrchestrator.ts`
2. `server-node/src/services/customWorldAgentFoundationDraftService.ts`
它们仍直接引用:
1. `src/services/customWorld.js`
2. `src/services/customWorldBuilder.js`
3. `src/services/customWorldCreatorIntent.js`
4. `src/types.js`
### 判断
这说明自定义世界的核心领域规则仍然以**前端目录为事实源**,后端只是在反向复用。
### 建议迁移方向
1. `types/schema/contracts` 抽到 `packages/shared`
2. 规则编译、校验、fallback 与 AI 编排迁到 `server-node`
3. 前端只保留编辑器表现层和字段草稿态。
---
## 5.3 `src/hooks/story/npcEncounterActions.ts` 仍在浏览器里做任务、奖励、战斗与招募结算
### 当前职责
`src/hooks/story/npcEncounterActions.ts` 当前约 `1623` 行,仍然直接编排:
1. `quest_accept` / `quest_turn_in`
2. 招募、切磋、离开、帮助奖励
3. 掉落/背包写入
4. HP / MP / cooldown 奖励变化
5. NPC 亲和度变化
6. 战斗场景切换与遭遇状态推进
### 判断
这条链已经明显超出“前端表现协调层”的边界,仍属于**正式运行时规则在前端执行**。
### 建议迁移方向
1. quest 信号推进 -> `server-node/src/modules/quest/**`
2. 奖励与背包变更 -> `server-node/src/modules/inventory/**`
3. 招募/关系变化 -> `server-node/src/modules/npc/**`
4. 战斗结算 -> `server-node/src/modules/combat/**`
前端应该只保留选项触发、加载态、动画态和最终结果展示。
---
## 5.4 `src/services/apiClient.ts` 仍保留了本地 token 与自动登录凭证存储
### 证据
`src/services/apiClient.ts` 当前仍把以下内容放在 `window.localStorage`
1. access token
2. 自动登录用户名
3. 自动登录密码
### 判断
这既是安全面问题,也是边界问题。
在“后端负责鉴权、前端只做表现”的目标下,正式凭证体系不应长期依赖浏览器本地保存账号密码。
### 建议迁移方向
1. 正式态优先走服务端 session / HttpOnly cookie。
2. 自动登录不要继续保存明文用户名/密码。
3. 前端仅保留最小必要的登录态感知,不保留额外认证真相。
---
## 6. 需要优先优化和拆分的代码
## 6.1 `src/components/CustomWorldEntityEditorModal.tsx`
### 当前状态
文件体量约 `4487` 行,已同时吞下:
1. 世界营地编辑
2. playable NPC 编辑
3. story NPC 编辑
4. 地标与世界地图布局
5. 场景图生成
6. 技能编辑
7. 初始物品编辑
8. 资产工作台串联
9. 多层 modal 开关与保存逻辑
### 判断
这是当前前端最明显的“巨型工作台单体文件”。
### 建议拆分方向
1. 按实体拆:营地 / playable NPC / story NPC / 地标。
2. 按能力拆:基础信息 / 关系 / 技能 / 初始物品 / 视觉资产。
3. 把 AI 生成与资产工作流进一步外置成独立 coordinator。
---
## 6.2 `server-node/src/modules/assets/characterAssetRoutes.ts`
### 当前状态
文件体量约 `3579` 行,已同时承担:
1. route 注册
2. 请求解析
3. LLM prompt bundle 生成
4. JSON 解析与修复
5. 文件系统写盘
6. visual publish
7. animation publish
8. 资产目录管理
### 直接证据
文件内同时存在:
1. `mkdir` / `writeFile`
2. `UpstreamLlmClient`
3. `parseJsonResponseText`
4. 多条 publish 路径
5. 大量本地文件落盘逻辑
### 建议拆分方向
1. route 层
2. prompt bundle service
3. file publish service
4. animation persistence service
5. asset metadata service
---
## 6.3 `src/services/ai.ts`
### 当前状态
文件体量约 `2632` 行,同时承载运行时 story、自定义世界、NPC 对话、招募等多条链路。
### 建议
即使短期内不能全部迁后端,也应该先按职责拆成:
1. runtime story client
2. npc dialogue client
3. recruit dialogue client
4. custom world generation client
5. parser / fallback / error helpers
---
## 6.4 `src/services/customWorld.ts`
### 当前状态
文件体量约 `2413`已经变成世界生成、校验、归一化、fallback 的综合体。
### 建议
至少拆成:
1. 世界框架与 outline schema
2. profile normalize / validate
3. role / landmark 编译器
4. fallback builder
5. world rule helpers
---
## 6.5 `src/hooks/story/npcEncounterActions.ts`
### 当前状态
文件体量约 `1623` 行,已经不是单纯 hook而是前端运行时 action resolver。
### 建议
按动作域拆开:
1. npc chat / recruit
2. npc help / affinity
3. quest accept / turn-in
4. battle entry / exit
5. async streaming / typewriter / presentation glue
---
## 7. 推荐执行顺序
### 第一阶段:先清仓库噪音和旧入口残留
1. 清根目录日志、扫描文件、旧截图、`__pycache__`
2. 迁出 `temp-build-goal-check/`
3. 明确处置 `scripts/dev-server/localApiPlugins.ts`
### 第二阶段:再处理无入口孤岛模块
1. 逐个确认 `GameShell.tsx`、custom-world-home、custom-world-agent、旧 flow hooks 是要接回还是归档
2. 对确认不再使用的 stub / helper / generated dead file 直接清理
### 第三阶段:把双份真相收口
1. runtime option interaction 映射只保留一份
2. 浏览历史以后端为真相源
3. 运行时快照解释权继续后移
4. 清理 `server-node -> src/**` 的反向依赖
### 第四阶段:最后拆巨型热点文件
1. `CustomWorldEntityEditorModal.tsx`
2. `characterAssetRoutes.ts`
3. `ai.ts`
4. `customWorld.ts`
5. `npcEncounterActions.ts`
---
## 8. 本文依据
文档依据:
1. `docs/audits/engineering/CURRENT_ENGINEERING_OPTIMIZATION_PRIORITIES_2026-04-10.md`
2. `docs/planning/EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md`
3. `docs/planning/EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md`
4. `scripts/dev-server/README.md`
当前仓库扫描依据:
1. `src/main.tsx`
2. `src/routing/appRoutes.tsx`
3. `src/App.tsx`
4. `package.json`
5. `server-node/package.json`
6. `vite.config.ts`
7. `.eslintrc.cjs`
8. `git grep` 对关键模块引用、后端跨层 import、localStorage、旧 dev 插件入口的扫描结果

View File

@@ -4,16 +4,21 @@
## 当前推荐入口
1. [ENGINEERING_OPTIMIZATION_REVIEW_2026-04-01.md](./ENGINEERING_OPTIMIZATION_REVIEW_2026-04-01.md)
1. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md)
这一版聚焦当前仓库里的垃圾/冗余代码、旧入口残留、前后端边界未闭合点,以及下一步最该清什么、迁什么、拆什么。
2. [ENGINEERING_OPTIMIZATION_REVIEW_2026-04-01.md](./ENGINEERING_OPTIMIZATION_REVIEW_2026-04-01.md)
这一版最适合作为当前工程基线,重点从“是否真正绿色”“门禁有没有覆盖真实风险”来判断仓库状态。
2. [ENGINEERING_OPTIMIZATION_REVIEW_2026-03-30.md](./ENGINEERING_OPTIMIZATION_REVIEW_2026-03-30.md)
3. [ENGINEERING_OPTIMIZATION_REVIEW_2026-03-30.md](./ENGINEERING_OPTIMIZATION_REVIEW_2026-03-30.md)
适合回看运行时主链路、Story/Combat 边界、分层过渡期问题。
3. [ENGINEERING_OPTIMIZATION_REVIEW_2026-03-29.md](./ENGINEERING_OPTIMIZATION_REVIEW_2026-03-29.md)
4. [ENGINEERING_OPTIMIZATION_REVIEW_2026-03-29.md](./ENGINEERING_OPTIMIZATION_REVIEW_2026-03-29.md)
适合看第一轮系统性工程扫描,了解最早的问题基线。
## 融合结论
- 当前仓库的新重点已经从“单纯补门禁”进一步演进到“清历史残留、清无入口模块、收前后端双份真相”。
- 三轮结论是一致收敛的:问题不在“有没有开始工程化”,而在“工程化是否真正覆盖了最危险的主链路”。
- 最新一轮已经把关注点集中到质量门禁、真实绿色基线、关键模块豁免和 build warning 上。
- `2026-04-19` 这一轮进一步把问题压实到了四类:仓库噪音、旧 dev 入口残留、前端越界运行时逻辑、巨型热点文件。
- 如果只是为了判断现在先做什么,直接从 `2026-04-01` 开始即可。
- 如果是要做长期重构方案,再按 `2026-03-29 -> 2026-03-30 -> 2026-04-01` 的顺序回看演进。
- 如果是要做当前清理和边界收口,优先看 `2026-04-19`
- 如果是要做长期重构方案,再按 `2026-03-29 -> 2026-03-30 -> 2026-04-01 -> 2026-04-19` 的顺序回看演进。

View File

@@ -0,0 +1,182 @@
# 平台首页公开浏览与登录弹窗拦截设计
更新时间:`2026-04-19`
## 0. 背景
当前仓库里的账号 PRD 默认要求“未登录先登录,再进入平台”。
这次产品策略调整为:
- 用户进入平台后,默认可以直接浏览首页
- 只有在尝试进入作品、进入世界、开始创作等受保护动作时,才检查登录
- 登录界面不再是完整页面,而是覆盖在当前平台上的轻量弹窗
这份设计只覆盖当前一次前台入口改造,目标是把边界写清楚到可以直接编码,不再让登录策略和平台首页互相冲突。
---
## 1. 本次目标
1. 未登录用户可以正常进入平台首页并浏览公开内容。
2. 点击作品卡片时,若未登录,弹出登录弹窗;登录成功后继续进入刚才点击的作品。
3. 打开创作类型选择后,点击具体游戏类型开始创作时,若未登录,弹出登录弹窗;登录成功后继续刚才的创作动作。
4. 登录 UI 改成极简弹窗,只保留窗口标题、必要输入框、必要按钮、错误态与关闭能力。
5. 未登录态下不要继续请求“我的作品 / 个人看板 / 云端浏览历史 / 云端存档列表”这类受保护数据,避免首页公开态出现无意义报错。
---
## 2. 公开态与受保护动作边界
## 2.1 未登录允许访问
- 平台首页主视图
- 精选推荐
- 最新发布
- 创作类型选择弹窗本身的展示
- 本地浏览历史展示(若存在)
说明:
- “允许访问”只代表允许看,不代表允许进入作品详情、开始世界或创建内容。
- 首页公开态必须保持可读,不因账号接口 401 出现整屏报错。
## 2.2 未登录必须拦截
- 点击任意作品卡片
- 点击作品详情中的“开始游戏”
- 点击作品详情中的“继续创作 / 发布 / 下架 / 删除”等作者动作
- 点击创作类型卡片,开始进入具体创作工作台
- 其他后续新增的“进入世界 / 开始正式创作”入口
拦截方式统一为:
- 保持当前页面上下文不跳走
- 直接弹出登录弹窗
- 登录成功后自动继续刚才被拦截的动作
---
## 3. 登录弹窗设计
## 3.1 展示形态
- 使用居中的 modal 覆盖层
- 背景保留平台当前页面,只加遮罩和轻微模糊
- 移动端优先,弹窗宽度贴近屏幕边缘,底部和顶部留出安全边距
- 桌面端保持紧凑,不做双栏 hero不再单独占满整页
## 3.2 内容约束
弹窗内默认只保留:
- 标题:`登录账号`
- 手机号输入框
- 验证码输入框
- 获取验证码按钮
- 登录主按钮
- 微信登录按钮(当后端开放时)
- 图形验证码输入区(仅后端要求时出现)
- 错误提示
- 关闭按钮
明确不再保留:
- 品牌副标题
- 功能介绍段落
- 规则说明卡片
- “先登录再同步进度”这类描述性文案
- 占据视觉主体的装饰信息块
## 3.3 登录成功后的行为
- 手机号登录成功后,关闭弹窗
- 当前平台页面不刷新
- 若用户是被某个受保护动作拦截进入登录,则自动恢复该动作
- 若用户只是主动点“登录”按钮,则关闭弹窗并停留在当前页面
## 3.4 关闭行为
- 用户主动关闭弹窗时,只关闭弹窗,不改变当前平台页面
- 不清空首页浏览状态
- 不自动跳转到其他 tab
---
## 4. 前端状态约束
## 4.1 AuthGate
`AuthGate` 需要从“未登录整页拦截器”调整为“平台级账号状态提供器”:
- `checking / recovering`:仍可显示加载态,避免首屏闪烁
- `unauthenticated`:渲染平台内容,同时允许按需打开登录弹窗
- `ready`:渲染平台内容和账号能力
- `pending_bind_phone`:继续保留当前绑定手机号流程,不在这次入口改造里拆散
同时需要在 context 中提供:
- 当前用户
- 打开登录弹窗
- 打开账号面板
- `requireAuth(action)` 能力
`requireAuth(action)` 约束:
- 已登录:直接执行 `action`
- 未登录:弹出登录弹窗,并缓存 `action`
- 登录成功:自动执行缓存的 `action`
## 4.2 平台首页数据加载
`PreGameSelectionFlow` 在未登录时只读取:
- 公开作品广场
- 本地浏览历史
未登录时不读取:
- 自定义世界库
- 个人看板
- 云端浏览历史
- 云端运行时设置
- 云端存档快照
- 云端存档列表
未登录态的对应前台表现:
- “我的创作”显示空态,不显示账号接口错误
- “个人页”显示未登录态入口,可手动打开登录弹窗
- 音量等运行时设置继续使用本地缓存,不触发 `/api/runtime/settings`
- 未登录态不显示“继续远端存档”能力,也不触发 `/api/runtime/save/snapshot`
- 未登录态的“存档”Tab 只展示登录引导,不触发 `/api/runtime/profile/save-archives`
---
## 5. 代码落点
本次实现最少要覆盖:
- `src/components/auth/AuthGate.tsx`
- `src/components/auth/AuthUiContext.ts`
- `src/components/auth/LoginScreen.tsx`
- `src/components/game-shell/PreGameSelectionFlow.tsx`
- `src/components/game-shell/PlatformHomeView.tsx`
- `src/components/game-shell/PlatformCreationTypeModal.tsx`
测试至少覆盖:
- 未登录时平台首页仍能渲染
- 未登录点击作品卡片会打开登录弹窗
- 未登录点击创作类型卡片会打开登录弹窗
- 登录成功后会继续刚才被拦截的动作
---
## 6. 验收标准
1. 用户首次进入平台时,不会先看到整页登录页,而是能看到首页内容。
2. 未登录点击作品时,直接弹出登录弹窗,登录后自动进入对应作品流。
3. 未登录选择 RPG 创作类型时,直接弹出登录弹窗,登录后自动进入创作工作台。
4. 登录弹窗内没有介绍性大段文字,只剩必要输入与按钮。
5. 未登录态首页不会因个人接口失败而出现“读取个人看板失败”“读取作品库失败”之类报错。

View File

@@ -0,0 +1,103 @@
# 平台层 UI 去像素化刷新设计
更新时间:`2026-04-19`
## 1. 目标
本次刷新只覆盖平台层功能 UI不改游戏内 HUD、战斗、地图、剧情面板等像素风界面。
目标有 5 个:
1. 平台层正文与功能信息不再使用像素字体
2. 平台层不再使用像素九宫格边框、像素图标、像素背景纹理这类平台 chrome
3. 原有紫蓝深色方案沉淀为平台暗色主题
4. 新参考图沉淀为平台亮色主题:白色主面板、粉橘主强调、暖白背景、高亮图卡
5. 平台默认使用亮色主题,移动端保持现有布局结构不变,桌面端允许在不改变业务入口的前提下重组为控制台式平台壳层
## 2. 覆盖范围
本次统一按 `!gameState.worldType` 的平台态处理,覆盖:
- 平台首页 `PlatformHomeView`
- 作品详情 `PlatformWorldDetailView`
- 创作类型弹窗 `PlatformCreationTypeModal`
- 平台创作链路中的生成页、结果页、目录页、编辑弹窗
明确不覆盖:
- 进入世界后的游戏内 UI
- 地图、战斗、剧情面板、角色面板、背包面板等像素 RPG 界面
- 世界内容本身的数据图片、角色主图、场景图等作品内容素材
说明:
- “不再引用像素素材”指平台 chrome 不再依赖像素框、像素按钮、像素关闭图标、像素底纹等 UI 资源
- 作品内容图仍可展示,但平台层不再用 `image-rendering: pixelated` 强化像素感
## 3. 视觉原则
### 3.1 风格来源
直接对齐现有登录页和绑定手机号页的成熟样式,并吸收本次参考图的桌面端气质:
- 暗色主题:顶部与边缘的紫蓝径向高光 + 深色纵向渐变背景
- 亮色主题:暖白控制台外壳 + 粉橘主强调 + 轻紫细节高光
- 大圆角卡片
- 半透明玻璃质感
- 平台正文与功能信息统一使用 `Inter + Noto Serif SC`
主题基准:
- 暗色主题:
底色以深靛蓝、深紫黑为主,高光以亮紫、蓝青为主
- 亮色主题:
底色以暖白、浅粉白、浅橘白为主,强调色以高饱和粉色、橘粉色为主,局部可带少量紫色作装饰
- 平台默认主题使用亮色主题;暗色主题保留为可切换方案,不作为当前默认展示
### 3.2 排版
- 平台层正文、按钮、说明、功能标签统一使用非像素字体
- 主标题保留明显层级,但不再做像素描边效果
- 微型标签维持高字距英文/中文短标签,用来保留产品感和秩序感
### 3.3 组件约束
- 面板:使用玻璃卡片,不再用九宫格像素框
- 按钮:使用圆角胶囊按钮或渐变主按钮,不再用像素按钮框
- 图标:优先使用 `lucide-react`
- Tab移动端底部结构不变但图标与底座改成非像素风桌面端切换为左侧纵向导航轨道
- 弹窗:沿用登录页的圆角浮层和半透明遮罩,不再使用像素弹窗边框
- 桌面壳层:首页允许增加顶部工具栏、左侧导航轨、中央内容舞台与右侧趋势面板的组合
- 登录页、绑定手机号、账户弹窗、平台详情、创作生成页、结果页、编辑弹窗都必须共享同一套平台主题 token禁止再各自写一套独立旧色板
- 平台“我的”页中的“设置”入口必须打开真正的设置面板;账号信息、设备管理、安全状态属于设置面板中的分区,不允许再把账号信息弹层直接充当设置页
- 设置面板必须支持平台亮色 / 暗色主题切换,并复用同一套平台 token 驱动登录页、首页、详情页与二三级面板
## 4. 交互与布局约束
- 移动端保持原有页面布局层级、区块顺序、操作入口位置不变
- 桌面端首页允许参考图示重组为“顶部工具栏 + 左侧纵向导航 + 主 Hero 卡 + 右侧趋势列表 + 下方内容卡组”
- 桌面端的重组只改变视觉排布;自 `2026-04-19` 起平台主入口调整为“首页 / 创作 / 存档 / 我的”,四个入口的操作路径都必须保持清晰稳定
- 移动端优先,底部 tab 与主卡片点击区域不能缩小
- 不在平台 UI 面板里额外堆砌规则说明
- 所有视觉替换必须是局部补丁,不做无必要的大规模结构重写
## 5. 实现约束
- 平台态从 `fusion-pixel-app` 中隔离,避免被全局像素字体覆盖
- 平台态背景不再使用 `/UI/Background_fill.png`
- 新样式优先沉淀为平台专用 class / theme token避免把游戏内像素 class 改坏
- 平台默认挂载亮色主题 class旧紫蓝方案保留为暗色主题 class
- 亮色主题需要补齐统一的 overlay、progress track、status pill token登录弹层与二三级功能面板禁止继续沿用旧深色遮罩与紫蓝强调残留
- 编辑弹窗保留业务结构与表单逻辑,只替换壳层样式
## 6. 验收标准
达到以下结果才算完成:
1. 平台首页、详情、登录、绑定手机号、账户弹窗、创作入口、创作结果页不再出现像素字体
2. 平台层按钮、面板、关闭按钮、底部 tab 不再依赖像素 UI 素材
3. 平台默认展示亮色主题,暗色主题保留为独立主题方案
4. 平台层二三级面板、表单、状态卡、弹窗与登录体系不再残留旧金橙 / 青蓝 / 深黑混搭方案
5. 平台层世界封面与角色预览不再使用 `pixelated` 渲染
6. 游戏内像素 UI 保持原样,不出现误改
7. 手机端布局保持稳定,桌面端在参考图方向下完成控制台化重组

View File

@@ -113,4 +113,12 @@
---
## 8. 2026-04-18 补充记录
- `GameShellRuntime` 进入游戏壳时,会主动隐藏认证层提供的右上角全局账号信息条。
- 原因不是账号功能下线,而是这个悬浮条会遮挡冒险主场景内容,移动端更明显。
- 账号相关入口保留在平台首页 / 个人页内部按钮与账号弹窗,不再占用游戏 HUD 区域。
---
*文档目的:交接给下一个 Agent 时,优先读本文件 + `UI_CODING_STANDARD.md`,再改 `uiAssets.ts` / `App.tsx` / `index.css`。*

View File

@@ -89,6 +89,12 @@
- 在底部工具区,队伍/背包改成 icon 后更紧凑。
- 但必须保留 `aria-label`,保证语义清晰、后续也方便测试。
### 4.5 冒险主场景不要挂右上角账号悬浮条
- 冒险页右上角属于画面演出和战斗/剧情信息的高频观察区。
- 全局账号信息条挂在这里,会直接压住场景、敌人血条或顶部提示,手机端尤其明显。
- 结论:
账号入口应收回平台首页、个人页或设置面板,不要在实际冒险主场景常驻悬浮显示。
## 5. 队伍面板经验
### 5.1 移动端成员列表不能太“卡片化”

View File

@@ -76,6 +76,19 @@
- 流程层优先按“职责”拆,不按“文件长度”拆。
- 状态修改逻辑尽量集中到 hook 内,不要散落在多个组件按钮回调里。
## 3.1 AI 草稿数据进列表前,要先补本地稳定标识
自定义世界、角色草稿、澄清问题、生成结果卡片这类数据,在草稿态或兼容旧数据时,`id` 可能为空。
经验:
- React 列表的 `key` 不要直接裸用这类可能为空的 `id`
- 当前选中态、草稿缓存、轮播焦点也不要直接绑空 `id`,否则会出现“点了第二张卡,结果还是第一张卡被选中”的错位。
- 更稳的做法是:
- 业务数据层尽量补齐真实 id
- UI 层再补一层本地稳定 `selectionKey` / fallback render key
- fallback 至少带上 `index + 名称种子`,保证当前列表内唯一
## 4. AI 只适合生成叙事,不适合决定关键规则
实践中最稳定的策略是:

View File

@@ -1,6 +1,13 @@
# 账号系统与登录入口重构 PRD
更新时间:`2026-04-09`
更新时间:`2026-04-19`
> 2026-04-19 入口策略补充:
> 平台首页现调整为“未登录也可浏览公开首页”,不再要求用户先登录才能进入平台。
> 登录拦截点改为“点击作品进入详情/世界”与“选择游戏类型开始创作”等受保护动作触发时再弹出登录弹窗。
> 本次入口策略与弹窗约束以
> [`docs/design/PLATFORM_HOME_PUBLIC_BROWSE_AND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md`](../design/PLATFORM_HOME_PUBLIC_BROWSE_AND_LOGIN_MODAL_GATING_DESIGN_2026-04-19.md)
> 为准;本 PRD 中“先登录再进入开始界面”的旧表述不再作为当前前台入口实现依据。
## 0. 目标
@@ -175,7 +182,7 @@ MVP 阶段建议采用最稳妥规则:
4. 微信后强制绑定手机号
5. 账号会话管理
6. 账号与存档/自定义世界/运行时设置统一绑定
7. 基础账号中心与退出登录
7. 基础账号中心、平台设置面板与退出登录
## 3.2 本期不做
@@ -460,6 +467,7 @@ MVP 阶段建议至少提供一个轻量账号中心,包含:
- 已绑定手机号(脱敏展示)
- 微信绑定状态
- 最近登录时间
- 平台设置面板中的亮色 / 暗色主题切换
- 退出登录
二期可以再补:

View File

@@ -1,6 +1,6 @@
# AI 角色形象与角色动画 MVP PRD
更新时间:`2026-04-04`
更新时间:`2026-04-19`
## 0. 一句话结论
@@ -254,6 +254,15 @@ MVP 支持三种主形象输入方式:
MVP 必须与当前项目可扮演角色动作槽位对齐。
当前落地实现补充约束(`2026-04-19`
- 角色资产工坊默认固定生成入口收敛为 `idle / run / attack / die`
- `hurt` 不再作为固定按钮动作
- 图生视频默认走火山方舟 `Seedance` 首尾帧方案
- 接口请求体中的两张参考图分别固定为 `first_frame / last_frame`
- 固定参数为 `1:1``480p``4 秒`、单次 `1` 个视频
- 提示词中的动作名统一传英文动作名
第一版要求以下基础动作槽位不能为空:
| 动作槽位 | 是否必填 | 备注 |
@@ -345,7 +354,6 @@ MVP 支持两种方式:
- `attack`
- `jump_attack`
- `hurt`
- `die`
要求末帧清晰,不与下一动作切换冲突。
@@ -634,4 +642,3 @@ type GeneratedCharacterAnimationAsset = {
- 路径清晰
- 能真正进入当前仓库
- 后续可以在此基础上再加技能动作、剧情演出和多供应商增强路线

View File

@@ -0,0 +1,226 @@
# AI Native 战斗单行为 Function PRD2026-04-18
## 1. 目标
本次迭代把战斗中的 function 从“战术风格 function”收敛为“单次可直接结算的原子行为 function”。
核心目标:
1. 战斗中一次点击只完成一个明确行为,不再做连续多轮击打、连续多 actor 轮转的 function 设计。
2. 战斗中除逃跑外,不再为每次动作额外触发剧情推理,而是直接结算数值并刷新下一轮战斗选项。
3. 只有在逃跑成功或战斗正式结束后,才触发一次剧情推理,生成脱战后的 storyText 与后续剧情选项。
---
## 2. 新战斗 option 池
`inBattle = true` 时,默认战斗选项池固定收敛为以下结构,顺序按下列规则输出:
1. `battle_attack_basic`
2. `battle_recover_breath`
3. `inventory_use`
4. `battle_use_skill`
5. `battle_escape_breakout`
其中第 4 项不是单个 option而是“每个技能一个 option 实例”。
### 2.1 普通攻击
- functionId`battle_attack_basic`
- 含义:不消耗灵力的基础攻击。
- 结算:直接结算一次基础伤害。
- 不触发剧情推理。
### 2.2 恢复
- functionId`battle_recover_breath`
- 含义:本回合做恢复与节奏调整。
- 结算:直接恢复血量/灵力,并推进技能冷却。
- 不触发剧情推理。
### 2.3 使用物品
- functionId`inventory_use`
- 含义:战斗中直接使用一个可结算的消耗品。
- 本期战斗选项池只给一个“推荐可用物品” option不展开整包物品列表。
- option 必须携带 `runtimePayload.itemId`
- 若当前没有可用消耗品,则仍保留该项,但以 disabled 态展示。
- 不触发剧情推理。
### 2.4 使用技能
- functionId`battle_use_skill`
- 每个角色技能都生成一个独立 option。
- option 文案直接对应技能名,不再包装成“稳扎试探 / 破架 / 终结窗口”这类抽象战术文案。
- option 必须携带 `runtimePayload.skillId`
- 若技能因蓝量不足或冷却中不可用,仍保留该 option但以 disabled 态展示。
- 点击后直接结算该技能本次效果,不触发剧情推理。
### 2.5 逃跑
- functionId`battle_escape_breakout`
- 含义:立即尝试脱离当前战斗。
- 结算:直接处理脱战结果。
- 逃跑成功后必须触发剧情推理。
---
## 3. 旧战斗 function 的处理
以下旧 function 不再进入默认战斗选项池:
- `battle_all_in_crush`
- `battle_guard_break`
- `battle_probe_pressure`
- `battle_feint_step`
- `battle_finisher_window`
兼容规则:
- 后端仍允许解析这些旧 functionId避免旧存档 / 旧 currentStory 点击时报错。
- 兼容结算统一按“单次攻击型行为”处理,不再保留旧的战术风格分支。
- 新生成的新选项、新 currentStory、新 viewModel 不再继续下发这些旧 function。
---
## 4. 单行为结算规则
### 4.1 单次点击的边界
一次点击只允许完成一次玩家声明行为:
- 普通攻击
- 恢复
- 使用物品
- 使用某个具体技能
- 逃跑
不再允许一次点击里继续串:
- 多轮连续攻击
- 多个技能连续释放
- 多个角色依次轮转
- 为了“表现完整”再补一整串额外战斗回合
### 4.2 回合感保留
虽然不再做连续多轮击打,但每个战斗动作仍然视为消耗了一个战斗回合,因此:
- 技能冷却要按“本次动作结束后”推进
- 恢复类动作可额外提供冷却推进收益
- 物品动作在战斗态下也算一次战斗回合
### 4.3 结果文本
ongoing battle 的本地/后端结果文本只负责说明这一次动作结算结果,不负责续写新的剧情段落。
例如:
- 你挥出一记普通攻击,命中前方敌人。
- 你稳住呼吸,恢复了部分气血与灵力。
- 你立刻服下疗伤药,当前状态回升。
- 你释放了【试锋斩】,直接压低了对方血线。
---
## 5. 剧情推理触发边界
### 5.1 不触发剧情推理的情况
当动作执行后仍处于战斗中时,以下 function 不触发剧情推理:
- `battle_attack_basic`
- `battle_recover_breath`
- `inventory_use`
- `battle_use_skill`
- 旧攻击类兼容 function
此时系统行为为:
1. 直接结算动作
2. 更新 HP / MP / CD / 物品 / 战斗状态
3. 直接刷新新一轮战斗选项
4. `storyText` 直接使用本次结算结果文本,不请求 AI 续写
### 5.2 必须触发剧情推理的情况
以下情况必须触发剧情推理:
1. `battle_escape_breakout` 执行后成功脱战
2. 任意战斗动作执行后,战斗正式结束
战斗正式结束包括:
- 敌方被击败
- 切磋结束
- 玩家被系统判定为本轮战斗已断开
此时系统行为为:
1. 先完成数值结算与状态落地
2. 再以“本次动作 + 本次战斗结果”为上下文触发一次剧情推理
3. 生成脱战后的 `storyText` 与非战斗态 options
---
## 6. 前后端数据约束
### 6.1 Option 扩展字段
为了支持“单 functionId + 多实例技能/物品 option”战斗 option 允许携带以下运行时字段:
- `runtimePayload`
- `skillId?: string`
- `itemId?: string`
- `disabled?: boolean`
- `disabledReason?: string`
### 6.2 前端职责
- 前端只负责展示 option、透传 `runtimePayload`、展示 disabled 态
- 前端不再自己推导战斗中“是否需要剧情推理”
- 前端不再把技能 option 重写成抽象战术描述
### 6.3 后端职责
- 后端负责生成战斗 option 池
- 后端负责解析 `skillId / itemId`
- 后端负责决定 battle ongoing / battle end / escape 后是否触发剧情推理
---
## 7. 本次落地范围
本期必须落地:
1. 后端 runtime 战斗 option 池切换到单行为模型
2. 后端 combat resolution 支持普通攻击 / 指定技能 / 恢复 / 战斗物品 / 逃跑
3. 后端只在逃跑或战斗结束后做剧情推理
4. 前端支持透传战斗 option 的 `runtimePayload`
5. 前端支持 disabled battle option 展示
6. 文档、测试同步更新
本期不做:
1. 新增复杂目标选择 UI
2. 一次展开完整背包的战斗 item 子面板
3. 重做整套战斗演出系统
4. 把所有旧本地 battle plan 彻底删除到只剩后端一条链
---
## 8. 验收口径
满足以下条件视为本次需求完成:
1. 战斗中不再出现 `battle_all_in_crush / battle_guard_break / battle_probe_pressure / battle_feint_step / battle_finisher_window` 作为默认候选项。
2. 战斗默认候选项能看到:
- 普通攻击
- 恢复
- 使用物品
- 每个技能一个独立技能项
- 逃跑
3. 点击普通攻击 / 恢复 / 使用物品 / 技能时,不请求新的剧情推理,直接返回结算结果并刷新下一轮战斗 options。
4. 点击逃跑成功后,会请求一次剧情推理并切回脱战后的剧情 options。
5. 任意攻击或技能把敌人打死后,会请求一次剧情推理并切回脱战后的剧情 options。
6. 旧存档里残留旧 battle functionId 时,不会因为 function 不识别而报错。

View File

@@ -484,6 +484,29 @@ interface ListCustomWorldWorksResponse {
- 当前用户作品量预计不大
- 先把结构做稳,比先做分页更重要
### 公开浏览与登录边界
创作首页与世界选择页必须拆分两类数据:
1. 公开浏览数据
2. 当前用户私有数据
其中以下接口必须定义为公开只读:
- `GET /api/runtime/custom-world-gallery`
- `GET /api/runtime/custom-world-gallery/:ownerUserId/:profileId`
明确约束:
1. 未登录用户进入世界选择页时,也必须能读取公开作品广场
2. 公开作品广场读取不能依赖 access token也不能因为 refresh 失败返回 401
3. 已发布作品详情允许未登录用户查看
4. 只有“继续创作 / 发布 / 下架 / 删除 / 查看我的草稿 / 查看我的统计”等私有能力必须要求登录
也就是说:
**平台首页要支持“先浏览公开作品,再决定是否登录进入世界或开始创作”。**
## 9.3 数据来源
### 草稿来源

View File

@@ -17,17 +17,20 @@
## 1. 当前“我的”Tab 功能拆分
当前页面可拆成以下 `9` 个独立功能
说明
-`2026-04-19` 起,“最近游玩 / 历史浏览”已从“我的”页迁出,改为平台一级主 Tab“存档”。
- 对应母文档见 [PLATFORM_SAVE_TAB_PRD_2026-04-19.md](/E:/Repos/Genarrative/docs/prd/PLATFORM_SAVE_TAB_PRD_2026-04-19.md)。
当前“我的”页保留以下 `7` 个独立功能:
1. 账号资料与身份卡
2. 会员中心与充值
3. 我的数据看板
4. 最近游玩
5. 历史浏览
6. 邀请好友
7. 填邀请码
8. 玩家社区
9. 设置与账号安全
4. 邀请好友
5. 填邀请码
6. 玩家社区
7. 设置与账号安全
---
@@ -36,12 +39,11 @@
1. [MY_TAB_PROFILE_IDENTITY_CARD_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_PROFILE_IDENTITY_CARD_PRD_2026-04-16.md)
2. [MY_TAB_MEMBERSHIP_CENTER_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_MEMBERSHIP_CENTER_PRD_2026-04-16.md)
3. [MY_TAB_DATA_DASHBOARD_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_DATA_DASHBOARD_PRD_2026-04-16.md)
4. [MY_TAB_RECENT_PLAY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_RECENT_PLAY_PRD_2026-04-16.md)
5. [MY_TAB_BROWSE_HISTORY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_BROWSE_HISTORY_PRD_2026-04-16.md)
6. [MY_TAB_INVITE_FRIENDS_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_INVITE_FRIENDS_PRD_2026-04-16.md)
7. [MY_TAB_INVITE_CODE_REDEMPTION_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_INVITE_CODE_REDEMPTION_PRD_2026-04-16.md)
8. [MY_TAB_PLAYER_COMMUNITY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_PLAYER_COMMUNITY_PRD_2026-04-16.md)
9. [MY_TAB_SETTINGS_AND_SECURITY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_SETTINGS_AND_SECURITY_PRD_2026-04-16.md)
4. [PLATFORM_SAVE_TAB_PRD_2026-04-19.md](/E:/Repos/Genarrative/docs/prd/PLATFORM_SAVE_TAB_PRD_2026-04-19.md)
5. [MY_TAB_INVITE_FRIENDS_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_INVITE_FRIENDS_PRD_2026-04-16.md)
6. [MY_TAB_INVITE_CODE_REDEMPTION_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_INVITE_CODE_REDEMPTION_PRD_2026-04-16.md)
7. [MY_TAB_PLAYER_COMMUNITY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_PLAYER_COMMUNITY_PRD_2026-04-16.md)
8. [MY_TAB_SETTINGS_AND_SECURITY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_SETTINGS_AND_SECURITY_PRD_2026-04-16.md)
---
@@ -51,20 +53,19 @@
1. 账号资料与身份卡
2. 设置与账号安全
3. 最近游玩
4. 历史浏览
5. 我的数据看板
6. 会员中心与充值
7. 邀请好友
8. 填邀请码
9. 玩家社区
3. 我的数据看板
4. 平台存档 Tab
5. 会员中心与充值
6. 邀请好友
7. 邀请
8. 玩家社区
原因:
- `1 + 2` 复用现有账号系统最多,最容易先落地
- `3 + 4 + 5` 直接增强“我的”页内容密度,短期收益高
- `6 + 7` 涉及商业化和关系绑定,依赖结算与奖励台账
- `8` 最适合放在平台内容层能力稳定后再做
- `3 + 4` 直接增强账号资产与回流体验,短期收益高
- `5 + 6` 涉及商业化和关系绑定,依赖结算与奖励台账
- `7` 最适合放在平台内容层能力稳定后再做
---

View File

@@ -0,0 +1,252 @@
# 平台“存档”Tab PRD
更新时间:`2026-04-19`
## 0. 目标
把原本堆在“我的”页中的“最近游玩 / 历史浏览”移出,新增平台一级主 Tab“存档”用于承载当前账号在平台里玩过的所有游戏留下的最近可恢复存档。
这次改动的核心目标不是做复杂多槽位存档系统,而是先落地一个稳定、可跨设备同步、可直接继续游玩的账号级存档入口。
---
## 1. 信息架构调整
## 1.1 平台主导航
平台主导航从:
- 首页
- 创作
- 我的
调整为:
- 首页
- 创作
- 存档
- 我的
移动端底部导航与桌面端左侧纵向导航都必须同步调整。
## 1.2 “我的”页调整
“我的”页删除以下内容块:
- 最近游玩
- 历史浏览
“我的”页保留:
- 账号资料与身份卡
- 数据看板
- 常用功能
- 设置与账号安全
说明:
- 历史浏览本期直接从“我的”页移除,不再占据个人页首屏空间。
- 存档能力统一收口到平台一级“存档”Tab不再同时在“我的”页重复展示。
---
## 2. 存档定义
## 2.1 本期存档口径
本期“存档”Tab 展示的是:
- 当前账号在每个已游玩游戏 / 世界下保留的最近一个可恢复存档
不是:
- 同一游戏下的完整多槽位存档管理页
- 手动重命名 / 置顶 / 删除存档系统
## 2.2 世界唯一键
服务端必须按 `worldKey` 聚合最近存档:
- 自定义世界:`custom:<profileId>`
- 内建世界:`builtin:<worldType>`
同一账号、同一 `worldKey` 只保留最近一次成功保存的可恢复存档。
## 2.3 生命周期
1. 玩家每次成功写入运行时快照时,同步刷新该世界的最近存档记录。
2. 删除当前活动快照时,不删除历史存档归档。
3. 点击“继续游玩”时,从该世界最近存档恢复为当前活动快照,再进入游戏。
---
## 3. 界面设计
## 3.1 存档 Tab 首屏结构
页面由两部分组成:
1. 顶部摘要卡
2. 存档列表
顶部摘要卡用于表达:
- 当前共有多少个可恢复存档
- 最近一次更新的存档是谁
不要在 UI 中默认堆规则说明文案,只保留简洁的状态表达。
## 3.2 列表排序
列表按 `lastPlayedAt` 倒序。
最近更新的存档始终在最前面。
## 3.3 列表项字段
每个列表项必须展示:
- 游戏名称
- 最后游玩时间
- 游戏信息
其中“游戏信息”优先级如下:
1. `continueGameDigest`
2. 当前故事文本摘要
3. 世界简介 / 场景简介
4. 若都没有则给出简洁兜底文案
可附带展示封面,但封面不是必填验收项。
## 3.4 点击行为
点击列表项后:
1. 调用后端恢复接口
2. 将所选存档切换为当前活动快照
3. 直接进入游戏继续游玩
前端不允许自行拼装恢复上下文。
## 3.5 空状态
### 已登录但无存档
- 展示轻量空态
- 引导去首页开始游玩
### 未登录
- 展示登录态空壳
- 不请求受保护的云端存档列表接口
---
## 4. 默认进入逻辑
当满足以下条件时玩家进入网站后的平台首页默认进入“存档”Tab
1. 当前处于登录状态
2. 当前账号至少存在一个存档
否则:
- 仍默认进入“首页”Tab
注意:
- 这个默认进入逻辑只在平台首屏初始化时执行,不能覆盖用户手动切换后的选择。
---
## 5. 后端设计
## 5.1 新增数据表
建议新增 `profile_save_archives`
- `user_id`
- `world_key`
- `owner_user_id`
- `profile_id`
- `world_type`
- `world_name`
- `world_subtitle`
- `summary_text`
- `cover_image_src`
- `saved_at`
- `bottom_tab`
- `game_state_json`
- `current_story_json`
- `updated_at`
约束:
- 主键:`user_id + world_key`
- 排序索引:`user_id + saved_at desc`
## 5.2 写入规则
每次 `/api/runtime/save/snapshot` 成功写入后:
1. 正常更新当前活动快照
2. 同步 upsert 对应 `world_key` 的存档归档
3. 继续保留原有个人看板 / 已玩作品同步逻辑
## 5.3 列表接口
### `GET /api/runtime/profile/save-archives`
返回:
- 当前账号全部最近存档
字段至少包含:
- `worldKey`
- `worldName`
- `worldSubtitle`
- `summaryText`
- `coverImageSrc`
- `lastPlayedAt`
- `worldType`
- `profileId`
- `ownerUserId`
## 5.4 恢复接口
### `POST /api/runtime/profile/save-archives/:worldKey/resume`
用途:
- 将指定存档归档恢复为当前活动快照
- 返回恢复后的快照
限制:
- 恢复动作不能重复记账,不得再次累计个人资产流水
- 恢复动作不能重复累计已玩时长
- 恢复动作不能破坏现有快照水合逻辑
---
## 6. 前端实现要求
1. `PlatformHomeView` 新增 `存档` 主 Tab。
2. `PreGameSelectionFlow` 在平台数据加载时同时拉取存档列表。
3. 已登录且有存档时,平台首屏默认选中 `存档` Tab。
4. “我的”页删除“最近游玩 / 历史浏览”两个区块。
5. 点击存档列表项时必须经过后端恢复接口,恢复成功后直接进入游戏。
6. 移动端优先,列表项点击区域不能过小。
---
## 7. 验收标准
1. 已登录账号可以在“存档”Tab 看到所有已玩过世界的最近存档。
2. 列表按最近更新时间倒序。
3. 列表项可看到游戏名称、最后游玩时间和游戏信息。
4. 点击列表项后可直接继续对应游戏。
5. 已登录且至少有一个存档时进入网站默认打开“存档”Tab。
6. 未登录时不请求云端存档列表,也不会出现受保护接口报错。

View File

@@ -265,6 +265,15 @@
但对“第一版角色动作资产生产”来说,它更适合作为增强通道,不建议先做成唯一主依赖。
实现更新(`2026-04-19`
- 当前仓库的 `image-to-video` 角色动作生成入口已切到火山方舟 `Seedance`
- 采用双参考图首尾帧方案:图片 1 约束首帧,图片 2 约束尾帧
- 当前请求体中的两张参考图角色分别固定为 `first_frame / last_frame`
- 当前固定参数为 `1:1``480p``4 秒`、单次 `1` 个视频
- 当前固定动作入口收敛为 `idle / run / attack / die`,不再内置固定 `hurt`
- 提示词里传给视频模型的动作名统一使用英文动作名
## 5.3 补充路线:腾讯云相关能力
腾讯云相关接口里,`提交图片跳舞任务` 提供了:
@@ -422,12 +431,12 @@
- `idle`
- `run`
- `attack`
- `jump`
- `hurt`
- `die`
系统自动选择对应参考视频模板。
`jump``hurt` 这类扩展动作不再作为当前编辑器固定按钮,改为后续扩展动作槽位或手动补齐。
### B. 视频驱动
用户上传参考动作视频,系统抽姿态后再生成角色动作。
@@ -498,6 +507,8 @@ flowchart LR
- 文生图时,优先生成与当前项目角色素材视角一致的单人全身图
- 有参考图时,优先做“角色指定 + 风格收敛 + 视角纠偏”
- 用户直接上传素材时,先做校验、裁切、背景清理和尺寸标准化
- 编辑器未上传参考图时,主形象阶段默认附加一张由项目内可扮演角色 idle 帧拼成的风格参考板,用来锁定像素动作角色的轮廓语言、右朝向、体型比例与配色组织,避免模型只放大 Q 版比例却丢掉像素感
- 风格约束优先级里“像素动作角色感”高于“Q 版比例提示”;比例只允许轻度偏大头,不允许退化成普通软萌插画或儿童绘本风
### 角色视角要求
@@ -623,6 +634,16 @@ flowchart LR
8. 生成 Sprite Sheet
9. 输出动画元数据
### 当前工程的抠像补充策略
针对角色动作视频抽帧后常见的“后段帧出现白底”“角色轮廓残留绿幕像素点”问题,当前工程内的背景清理不再只依赖单一绿幕阈值,而是统一改为以下顺序:
1. 先识别边界连通的可移除背景区域,同时覆盖纯绿色绿幕和高亮低色差白底。
2. 再向主体边缘的半透明软边做一轮有限扩张,把压缩后残留的白边、绿边纳入透明化处理。
3. 最后对贴近透明边缘的像素做去污,优先压掉绿色溢色,并把白边/绿边颜色拉回附近前景主体颜色,减少抽帧后的轮廓发白、发绿。
这样可以避免把角色内部的白色高光、白色装备整体误删,同时能更稳定地清理视频模型在末段帧里偶发的白背景和压缩噪点。
### 像素化策略
推荐做法:
@@ -703,7 +724,14 @@ export interface GeneratedCharacterAnimationAsset {
id: string;
characterId: string;
visualAssetId: string;
action: BaseAnimationSlot | 'cast' | 'talk' | 'skill1' | 'skill2' | 'skill3' | 'skill4';
action:
| BaseAnimationSlot
| 'cast'
| 'talk'
| 'skill1'
| 'skill2'
| 'skill3'
| 'skill4';
sourceProvider: 'aliyun-wan' | 'volc-seedance' | 'tencent' | 'local';
sourceMode: 'template' | 'video-drive' | 'audio-drive';
frameCount: number;
@@ -914,20 +942,26 @@ draft
第一版要求以下基础动作槽位全部有内容:
| 动作槽位 | 是否必填 | 建议来源 |
| --- | --- | --- |
| `idle` | 必填 | 模板生成 |
| `acquire` | 必填 | 可由短持物 / 抬手动作生成 |
| `attack` | 必填 | 模板生成 |
| `run` | 必填 | 模板生成 |
| `jump` | 必填 | 模板生成 |
| `double_jump` | 必填 | 可由跳跃二次变体生成 |
| `jump_attack` | 必填 | 跳跃攻击模板 |
| `dash` | 必填 | 冲刺模板 |
| `hurt` | 必填 | 受击模板 |
| `die` | 必填 | 倒地 / 消散模板 |
| `climb` | 必填 | 攀爬模板 |
| `wall_slide` | 必填 | 可由攀爬或停滞帧变体生成 |
当前编辑器固定生成入口补充说明(`2026-04-19`
- 固定按钮只保留 `idle / run / attack / die`
- `hurt` 不再作为固定生成按钮
- 如果运行时仍需 `hurt` 资源,应通过后续扩展动作槽位或手动补齐
| 动作槽位 | 是否必填 | 建议来源 |
| ------------- | -------- | ------------------------- |
| `idle` | 必填 | 模板生成 |
| `acquire` | 必填 | 可由短持物 / 抬手动作生成 |
| `attack` | 必填 | 模板生成 |
| `run` | 必填 | 模板生成 |
| `jump` | 必填 | 模板生成 |
| `double_jump` | 必填 | 可由跳跃二次变体生成 |
| `jump_attack` | 必填 | 跳跃攻击模板 |
| `dash` | 必填 | 冲刺模板 |
| `hurt` | 必填 | 受击模板 |
| `die` | 必填 | 倒地 / 消散模板 |
| `climb` | 必填 | 攀爬模板 |
| `wall_slide` | 必填 | 可由攀爬或停滞帧变体生成 |
这里“不能为空”指的是:
@@ -961,14 +995,13 @@ draft
先优先做这些高价值模板:
| 模板 | 推荐时长 | 是否循环 | 说明 |
| --- | --- | --- | --- |
| `idle` | 2s-4s | 是 | 微动作、呼吸 |
| `run` | 2s-3s | 是 | 固定侧向 |
| `attack` | 2s-4s | 否 | 近战基础攻击 |
| `jump` | 1s-2s | 否 | 起跳与空中姿态 |
| `hurt` | 1s-2s | 否 | 受击短动作 |
| `die` | 2s-4s | 否 | 倒下或消散 |
| 模板 | 推荐时长 | 是否循环 | 说明 |
| -------- | -------- | -------- | -------------- |
| `idle` | 2s-4s | 是 | 微动作、呼吸 |
| `run` | 2s-3s | 是 | 固定侧向 |
| `attack` | 2s-4s | 否 | 近战基础攻击 |
| `jump` | 1s-2s | 否 | 起跳与空中姿态 |
| `die` | 2s-4s | 否 | 倒下或消散 |
### 12.4 不建议第一阶段就重投入的动作

View File

@@ -0,0 +1,143 @@
# Prompt 目录收口方案2026-04-19
## 1. 这次调整解决什么问题
此前后端提示词分散在多个业务模块里:
- `server-node/src/modules/ai/**`
- `server-node/src/modules/quest/**`
- `server-node/src/modules/runtime-item/**`
- `server-node/src/services/customWorld*.ts`
问题主要有三类:
1. 业务逻辑和 prompt 文本混写,改提示词时容易顺手改坏运行时逻辑。
2. 同一类 prompt 缺少集中入口,排查系统 prompt / user prompt / repair prompt 成本高。
3. 老桥接层、测试和新业务链路同时依赖时,迁移成本高,容易出现导出断裂。
这次收口目标不是“重写全部 AI 链路”,而是先把当前后端主链 prompt 收到单独目录,业务模块退化成“准备上下文 + 调用 prompt 脚本”。
## 2. 新目录
本轮新增目录:
```text
server-node/src/prompts/
├─ chatPromptBuilders.ts
├─ customWorldAgentPrompts.ts
├─ customWorldEntityPrompts.ts
├─ customWorldOrchestratorPrompts.ts
├─ customWorldSceneNpcPrompts.ts
├─ questPrompts.ts
├─ runtimeItemPrompts.ts
├─ storyOrchestratorPrompts.ts
└─ storyPromptBuilders.ts
```
当前职责划分:
- `chatPromptBuilders.ts`
- 角色私聊 / NPC 聊天 / 招募对话 prompt
- `storyPromptBuilders.ts`
- 主剧情 system prompt 与 user prompt builder
- `storyOrchestratorPrompts.ts`
- 剧情语言修复 prompt
- `questPrompts.ts`
- 任务意图 system prompt 与 user prompt builder
- `runtimeItemPrompts.ts`
- 运行时物品意图 system prompt 与 user prompt 文本装配
- `customWorldOrchestratorPrompts.ts`
- 自定义世界主编排 JSON 生成与 repair prompt
- `customWorldAgentPrompts.ts`
- 世界草稿 JSON prompt、补角色 / 补地点 prompt
- `customWorldEntityPrompts.ts`
- 世界编辑器角色 / 场景实体生成 prompt
- `customWorldSceneNpcPrompts.ts`
- 世界编辑器场景 NPC 生成 prompt
## 3. 落地规则
### 3.1 业务模块只做两件事
1. 整理运行时上下文
2. 调用 `server-node/src/prompts/**` 下的脚本输出 prompt
不要在业务模块里继续直接内联大段 system prompt / repair prompt / user prompt 模板文本。
### 3.2 Prompt 文件只放文本相关职责
允许放:
- system prompt 常量
- user prompt builder
- repair prompt builder
- prompt 专用的文本摘要函数
不建议放:
- 运行时状态 mutation
- 仓储读写
- HTTP 处理
- 与 prompt 无关的领域推导
### 3.3 兼容层保留旧导出
本轮对已有纯 prompt builder 文件采取了兼容迁移:
- `server-node/src/modules/ai/chatPromptBuilders.ts`
- `server-node/src/modules/ai/storyPromptBuilders.ts`
旧路径现在作为薄 re-export 保留,避免测试、桥接层和旧引用一次性全部断掉。
对于 `runtimeQuestModule.ts``runtimeItemModule.ts` 这类被桥接层直接引用的模块,本轮保留原导出名,通过 re-export 指向新 prompt 文件,保证兼容性。
## 4. 后续新增 prompt 的写法
新增提示词时按下面顺序处理:
1. 先判断是否属于已有领域。
2. 如果属于已有领域,优先补到对应 `server-node/src/prompts/*.ts`
3. 如果是新领域,再新增一个独立 prompt 脚本文件。
4. 业务模块只传入已经整理好的上下文字段,不在模块内部继续拼长文本。
5. 至少补一条该 prompt 的调用链测试或现有测试断言。
建议命名:
- system prompt`XXX_SYSTEM_PROMPT`
- repair prompt`buildXXXRepairPrompt`
- user prompt`buildXXXPrompt`
- 纯文本装配:`buildXXXPromptText`
## 5. 本轮范围与剩余事项
本轮已经收口:
- Story
- Chat
- Quest
- Runtime Item
- Custom World 主编排
- Custom World Agent 草稿增补
- Custom World 编辑器角色 / 场景 / 场景 NPC 生成
本轮尚未完全收口的内联 prompt 聚集区:
- `server-node/src/modules/assets/characterAssetRoutes.ts`
- `server-node/src/services/eightAnchorPromptBuilder.ts`
这两块后续继续沿用同一规则:
- 先抽出 prompt 文本与 builder
- 再让业务文件只保留参数整理与调用
## 6. 验证方式
本轮调整后建议至少执行:
- `npm run check:encoding`
- `npm run server-node:test`
- `npm --prefix server-node run build`
说明:
- 当前仓库里 `server-node/src/db.test.ts` 仍有一条与新增迁移版本号相关的既有失败,不属于本次 prompt 目录改造引入的问题。

View File

@@ -4,6 +4,7 @@
## 文档列表
- [PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md](./PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md):后端提示词收口到 `server-node/src/prompts/` 的目录方案、兼容策略与后续新增规则。
- [NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md](./NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md):当前 Node 运行时后端的技术栈、入口、鉴权、存储与接口知识图谱。
- [EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md](./EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md)Express 后端当前 contract 冻结版本、热点文件编辑规则与集成窗口清单。
- [EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md](./EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md):按并行工作流文档逐项核对后的完成度审计与剩余收口点。