This commit is contained in:
30
docs/README.md
Normal file
30
docs/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# 文档总览
|
||||
|
||||
`docs/` 现在按主题拆成了 6 类;旧后端路线文档开始聚合和删除,后续实现以 Rust / SpacetimeDB 当前基线为准。
|
||||
|
||||
## 快速入口
|
||||
|
||||
- [经验沉淀](./experience/README.md):项目开发经验、UI 交接、历史实现经验。
|
||||
- [审计与复盘](./audits/README.md):工程审查、文本/乱码审计、专项落地审计。
|
||||
- [系统设计](./design/README.md):玩法、关系、物品与对话设计。
|
||||
- [技术方案](./technical/README.md):动画、服务端、外部产品形态拆解。
|
||||
- [规划与优先级](./planning/README.md):当前阶段的迭代排序与落地优先级。
|
||||
- [参考目录](./reference/README.md):脚本/Function 速查入口。
|
||||
- [PRD](./prd):产品需求与阶段计划;新增 RPG 开场动画方案见 [AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md](./prd/AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md)。
|
||||
|
||||
## 推荐阅读顺序
|
||||
|
||||
1. 先看 [经验沉淀](./experience/README.md),快速建立这个项目的开发共识。
|
||||
2. 再看 [工程审查总览](./audits/engineering/README.md) 和 [文本审计总览](./audits/text/README.md),了解当前风险。
|
||||
3. 需要排期时看 [规划与优先级](./planning/README.md)。
|
||||
4. 需要补方案时进入 [系统设计](./design/README.md) / [技术方案](./technical/README.md);涉及后端先看 [当前后端实现基线](./technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md)。
|
||||
5. 需要对齐目标边界时再进入 [PRD](./prd)。
|
||||
|
||||
## 分类规则
|
||||
|
||||
- `experience/`:偏方法论、交接经验、长期有效的开发结论。
|
||||
- `audits/`:偏“现状扫描 / 问题定位 / 是否达标”的审查类文档。
|
||||
- `design/`:偏玩法机制、叙事关系、系统结构设计。
|
||||
- `technical/`:偏技术选型、实现路线、竞品/产品形态拆解。
|
||||
- `planning/`:偏阶段优先级与推进顺序。
|
||||
- `reference/`:偏目录、速查、检索辅助。
|
||||
417
docs/audits/AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md
Normal file
417
docs/audits/AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md
Normal file
@@ -0,0 +1,417 @@
|
||||
# Agent 聊天到草稿生成到进入游戏世界链路审计
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
本次审计只看一条链:
|
||||
|
||||
`Agent 聊天 -> 世界草稿生成 -> 结果页/作品库 -> 进入游戏世界`
|
||||
|
||||
聚焦回答四类问题:
|
||||
|
||||
1. 哪些数据在链路中断掉了
|
||||
2. 哪些地方在代码里同时存在多条 pipeline
|
||||
3. 哪些字段、功能、组件已经变成冗余或主链弱消费
|
||||
4. 哪些能力在 contract、PRD 或代码结构里已经定义,但并没有真正实装到当前游戏主流程
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
当前系统还没有形成“Agent 会话是唯一真相源、发布后再进入世界”的单一主链,而是处在多条 pipeline 并存、多个桥接层临时粘合的状态。
|
||||
|
||||
最关键的结论有 8 条:
|
||||
|
||||
1. 当前至少并存 `5` 条相关 pipeline,其中真正影响可玩流程的主链至少有 `3` 条。
|
||||
2. 最大的数据断点是:`CustomWorldAgentSessionSnapshot.draftProfile` 不直接进入 runtime,前端 `buildCustomWorldProfileFromAgentDraft()` 会先把它本地编译成 legacy `CustomWorldProfile`,后面的结果页、自动保存、进入世界都只认这个 legacy profile。
|
||||
3. 服务端内部也存在一次“先编成 legacy runtime profile,再转回 foundation draft”的双重编译,`draftProfile.legacyResultProfile` 是这个桥接层留下来的强耦合字段。
|
||||
4. `packages/shared/src/contracts/customWorldAgent.ts`、`server-node/src/routes/customWorldAgent.ts`、`server-node/src/services/customWorldAgentOrchestrator.ts` 三层定义不一致,`publish_world / generate_scene_assets / sync_scene_assets / expand_long_tail / lock_cards / unlock_cards / regenerate_scope` 等关键动作没有形成真实可用链路。
|
||||
5. `CustomWorldResultView.tsx` 仍保留“直接对 legacy profile 生成角色/地点、直接编辑 profile”的旧流程,会绕过 Agent session,是当前最明显的并行 pipeline 和冗余功能源。
|
||||
6. “进入世界”和“发布世界”目前是两套平行逻辑。Agent 草稿结果页可以自动保存并直接进入世界,但 `publish_world` action 仍不可用,`qualityFindings / blocker` 校验也没有真正接入。
|
||||
7. `listCustomWorldWorks()` 与 `CustomWorldWorkSummaryService` 已能聚合 Agent 草稿和已发布 profile,但平台 `create` tab 仍主要展示 `myEntries`,Agent draft session 不能自然回到主入口,恢复创作主要依赖 `activeSessionId`。
|
||||
8. Agent 工作区主 UI 只接了头部、进度、线程、输入框、操作横幅等极简子集,PRD 里规划的锁定条、草稿抽屉、详情面板、澄清面板、快捷动作、发布校验结果等大部分还没有真正进入当前游戏主流程。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标链路
|
||||
|
||||
按 `docs/prd/AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md` 和 `docs/prd/AI_NATIVE_AGENT_FIRST_EIGHT_ANCHOR_CO_CREATION_FLOW_PRD_2026-04-16.md`,目标链路应当是:
|
||||
|
||||
```text
|
||||
Agent 对话
|
||||
-> Express 后端维护结构化 eight-anchor / creatorIntent / lockState / draftSnapshot
|
||||
-> foundation draft
|
||||
-> 角色资产工坊 / 场景资产工坊
|
||||
-> sync 回 Agent session draft
|
||||
-> expand long tail
|
||||
-> publish_world
|
||||
-> 服务端执行 quality / blocker 校验
|
||||
-> 服务端编译最终 CustomWorldProfile
|
||||
-> 持久化到世界库
|
||||
-> 进入世界
|
||||
```
|
||||
|
||||
这条目标链路有 4 个硬约束:
|
||||
|
||||
1. Express 后端才是真实状态源,前端只负责展示和输入,不负责结构化草稿编译。
|
||||
2. 未发布的 Agent 草稿不应该直接污染正式世界库,主入口里应该通过“继续创作”恢复。
|
||||
3. 进入世界前应先经过 `publish_world`,并由发布校验阻止缺角色资产、缺场景资产、缺主线第一幕等 blocker。
|
||||
4. 结果页不再是旧自定义世界编辑器的平移副本,而应更接近“最终预览 / 发布确认 / 进入世界”的收口层。
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前真实链路
|
||||
|
||||
## 3.1 Agent 会话草稿链
|
||||
|
||||
当前新链路实际是:
|
||||
|
||||
```text
|
||||
PreGameSelectionFlow.tsx
|
||||
-> /api/runtime/custom-world/agent/sessions
|
||||
-> CustomWorldAgentSessionStore
|
||||
-> CustomWorldAgentOrchestrator
|
||||
-> CustomWorldAgentFoundationDraftService
|
||||
-> CustomWorldAgentAutoAssetService
|
||||
-> session.draftProfile / draftCards / assetCoverage
|
||||
-> 前端 buildCustomWorldProfileFromAgentDraft()
|
||||
-> generatedCustomWorldProfile
|
||||
-> upsertCustomWorldProfile()
|
||||
-> handleCustomWorldSelect(profile)
|
||||
-> runtime
|
||||
```
|
||||
|
||||
关键特点:
|
||||
|
||||
1. Agent session 不是 runtime 直接消费的对象。
|
||||
2. Agent 草稿完成后,会在前端先转成 `CustomWorldProfile`。
|
||||
3. 结果页阶段会自动调用 `upsertCustomWorldProfile()`,把当前 profile 写进 `custom-world-library`。
|
||||
4. “进入世界”按钮直接把这个 profile 送给 `handleCustomWorldSelect(...)`,不需要 `publish_world`。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/services/customWorldAgentDraftResult.ts`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
|
||||
## 3.2 旧自定义世界 session 链
|
||||
|
||||
旧链路仍然完整存在:
|
||||
|
||||
```text
|
||||
aiService.generateCustomWorldProfile()
|
||||
-> /api/runtime/custom-world/sessions
|
||||
-> answerCustomWorldSessionQuestion()
|
||||
-> /generate/stream
|
||||
-> generateCustomWorldProfile()
|
||||
-> CustomWorldProfile
|
||||
-> 结果页 / 作品库 / 进入世界
|
||||
```
|
||||
|
||||
关键特点:
|
||||
|
||||
1. `src/services/aiService.ts` 里的 `generateCustomWorldProfile()` 仍然会创建旧 `custom-world/sessions`。
|
||||
2. 前端会先根据 `world_hook / player_premise / opening_situation / core_conflict` 自动补默认回答,再触发流式生成。
|
||||
3. 这条链已经与 Agent 八锚点链并行存在,且依然可用。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `src/services/aiService.ts`
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `server-node/src/services/customWorldSessionStore.ts`
|
||||
|
||||
## 3.3 已保存 profile / 作品库链
|
||||
|
||||
当前作品库链是:
|
||||
|
||||
```text
|
||||
custom-world-library
|
||||
-> upsert / delete / publish / unpublish
|
||||
-> PlatformHomeView / saved profile detail
|
||||
-> CustomWorldResultView
|
||||
-> handleCustomWorldSelect(profile)
|
||||
```
|
||||
|
||||
关键特点:
|
||||
|
||||
1. 这条链直接消费 `CustomWorldProfile`,不依赖 Agent session。
|
||||
2. Agent 结果页自动保存后,也会落入这条链。
|
||||
3. `publish/unpublish` 作用在作品库 profile 上,而不是 Agent session 上。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `src/components/game-shell/PlatformHomeView.tsx`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
|
||||
## 3.4 结果页 legacy profile 直改链
|
||||
|
||||
`CustomWorldResultView.tsx` 仍保留旧能力:
|
||||
|
||||
1. `generateCustomWorldPlayableNpc({ profile })`
|
||||
2. `generateCustomWorldStoryNpc({ profile })`
|
||||
3. `generateCustomWorldLandmark({ profile })`
|
||||
4. `CustomWorldEntityEditorModal`
|
||||
|
||||
这意味着结果页不仅是预览层,还是一套独立的“legacy profile 直改工作台”。这一套能力不会回写 Agent session 的结构化状态,也不会走 Agent action route。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `src/components/CustomWorldResultView.tsx`
|
||||
- `src/services/aiService.ts`
|
||||
|
||||
## 3.5 创作中心 works 聚合链
|
||||
|
||||
后端已经能聚合两类作品:
|
||||
|
||||
1. `sourceType: 'agent_session'`
|
||||
2. `sourceType: 'published_profile'`
|
||||
|
||||
但主平台 `create` tab 现在仍主要展示 `myEntries`,没有把 `CustomWorldCreationHub.tsx` 作为主入口接上。
|
||||
|
||||
这导致:
|
||||
|
||||
1. works 聚合链存在
|
||||
2. create tab 真实消费的是另一条链
|
||||
3. Agent draft session 的继续创作入口没有真正收口到主平台
|
||||
|
||||
主要证据:
|
||||
|
||||
- `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
- `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- `src/components/game-shell/PlatformHomeView.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据断点
|
||||
|
||||
| 断点 | 当前现状 | 影响 | 主要证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| Agent session -> runtime | `buildCustomWorldProfileFromAgentDraft()` 在前端把 `session.draftProfile` 编译成 legacy `CustomWorldProfile`,后续结果页、自动保存、进入世界都只认 profile | 后端不再是最终唯一真相源,前端承担了结构化编译与字段裁决,容易产生字段丢失、语义漂移、状态失真 | `src/components/game-shell/PreGameSelectionFlow.tsx`、`src/services/customWorldAgentDraftResult.ts` |
|
||||
| foundation draft 内部双重编译 | `CustomWorldAgentFoundationDraftService` 会先 `buildCompiledCustomWorldProfile(...)`,再 `convertRuntimeProfileToFoundationDraft(...)`,并把结果塞进 `legacyResultProfile` | Agent draft 不是原生生成,而是绕了一次 legacy profile,再回 draft;后续桥接层依赖这个字段继续工作 | `server-node/src/services/customWorldAgentFoundationDraftService.ts` |
|
||||
| 创作态元数据进入最终 profile | 前端桥接时会把 `anchorContent / creatorIntent / anchorPack / lockState` 一并塞进 legacy profile;同时固定写入 `generationMode: 'fast'`、`generationStatus: 'key_only'` | 创作态数据污染运行时 profile 存储;`generationMode / generationStatus` 还会覆盖真实阶段语义 | `src/services/customWorldAgentDraftResult.ts` |
|
||||
| Agent session 元数据在结果页后被截断 | `draftCards / pendingClarifications / suggestedActions / qualityFindings / checkpoints / operations` 大多停留在 session 层;结果页与 runtime 只继续消费 profile | 进入结果页后,Agent 会话层的大量结构化上下文被切断,发布门槛、锁定、局部重生成等信息无法自然继承 | `packages/shared/src/contracts/customWorldAgent.ts`、`server-node/src/services/customWorldAgentSessionStore.ts`、`src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx` |
|
||||
| works 聚合 -> 平台 create tab | 后端 `listCustomWorldWorkSummaries(...)` 能返回 draft 与 published,但 create tab 仍只渲染 `myEntries` | Agent draft session 无法稳定出现在主入口“我的创作”里,恢复创作入口割裂 | `server-node/src/services/customWorldWorkSummaryService.ts`、`src/components/game-shell/PlatformHomeView.tsx` |
|
||||
| 发布状态 -> 可玩状态 | 结果页会自动 `upsertCustomWorldProfile()` 并允许直接 `onEnterWorld`;但 `publish_world` action 仍不可用 | “可玩”与“已发布”没有统一门槛,发布校验无法阻止未完成草稿进入世界 | `src/components/game-shell/PreGameSelectionFlow.tsx`、`server-node/src/services/customWorldAgentOrchestrator.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 多条 Pipeline
|
||||
|
||||
## 5.1 主链级 pipeline
|
||||
|
||||
| pipeline | 真相源 | 当前是否在主流程可达 | 问题 |
|
||||
| --- | --- | --- | --- |
|
||||
| Agent 会话草稿链 | `CustomWorldAgentSessionStore` + `draftProfile` | 是 | 后半段通过前端桥接成 legacy profile,未形成端到端单一真相源 |
|
||||
| 旧 custom-world session 链 | `CustomWorldSessionStore` | 是 | 与 Agent 八锚点链重复,且前端仍在补默认回答 |
|
||||
| 已保存 / 已发布 profile 链 | `custom-world-library` 中的 `CustomWorldProfile` | 是 | 与 Agent draft session 发布链平行存在 |
|
||||
| 结果页 legacy profile 直改链 | 结果页本地 `profile` | 是 | 绕过 Agent session,属于并行编辑器 |
|
||||
| works 创作中心链 | `listCustomWorldWorks()` 聚合数据 | 否,主平台未接主入口 | 后端已有聚合,但 UI 没真正切过去 |
|
||||
|
||||
## 5.2 资产子链 pipeline
|
||||
|
||||
资产相关还存在“自动补齐”和“人工工坊写回”并存:
|
||||
|
||||
1. `draft_foundation` 后,`CustomWorldAgentAutoAssetService` 会自动补角色主图和幕背景图。
|
||||
2. 角色资产又存在 `generate_role_assets -> sync_role_assets` 的手动工坊写回链。
|
||||
3. 场景资产在 contract 层定义了 `generate_scene_assets / sync_scene_assets`,但主 action 链未打通。
|
||||
|
||||
这导致当前资产链不是一条统一 pipeline,而是:
|
||||
|
||||
```text
|
||||
自动补角色 / 自动补幕背景
|
||||
并存
|
||||
手动角色工坊 -> sync_role_assets
|
||||
缺失
|
||||
手动场景工坊 -> sync_scene_assets
|
||||
```
|
||||
|
||||
主要证据:
|
||||
|
||||
- `server-node/src/services/customWorldAgentAutoAssetService.ts`
|
||||
- `server-node/src/services/customWorldAgentRoleAssetStateService.ts`
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
|
||||
---
|
||||
|
||||
## 6. 冗余字段与主链悬空字段
|
||||
|
||||
这里区分两类:
|
||||
|
||||
1. 已经明显承担桥接残留职责的冗余字段
|
||||
2. 在 contract / session 里存在,但当前主流程几乎不消费的悬空字段
|
||||
|
||||
| 字段 | 类型 | 当前状态 | 判断 |
|
||||
| --- | --- | --- | --- |
|
||||
| `draftProfile.legacyResultProfile` | 桥接残留字段 | foundation draft 服务端先生成 legacy runtime profile,再把它塞回 draft,前端桥接又优先读它 | 明显冗余,属于临时兼容字段,不应长期成为主链依赖 |
|
||||
| `generationMode: 'fast'` | 固定写死字段 | `buildCustomWorldProfileFromAgentDraft()` 固定写入 | 不是草稿真实状态,更像桥接层补丁 |
|
||||
| `generationStatus: 'key_only'` | 固定写死字段 | `buildCustomWorldProfileFromAgentDraft()` 固定写入 | 同上,会掩盖真实生成阶段 |
|
||||
| `anchorContent / creatorIntent / anchorPack / lockState` 被直接塞进 legacy profile | 创作态元数据 | 会跟随自动保存一起写进作品库 profile,但 runtime 并不以这些字段为正式运行时输入 | 当前更像创作态元数据泄漏进运行时 profile |
|
||||
| `qualityFindings` | session / contract 字段 | contract、session store、测试里存在,但没形成生成、渲染、发布阻断闭环 | 当前主链悬空 |
|
||||
| `checkpoints` | session 字段 | session store 会记录,但主工作区和结果页没有真实展示入口 | 当前主链悬空 |
|
||||
| `suggestedActions` | session 字段 | session 会生成,但当前正式工作区没有对应消费面;旧 `QuickActions` 面板已在 `2026-04-21` 判定退出当前版本主链并物理删除 | 当前主链悬空 |
|
||||
| `pendingClarifications` | session 字段 | session 有数据,但当前正式工作区没有对应消费面;旧澄清面板已在 `2026-04-21` 判定退出当前版本主链并物理删除 | 当前主链悬空 |
|
||||
| `operations` 历史 | session 字段 | 主工作区只展示当前 `activeOperation` 横幅,不展示完整历史 | 当前主链弱消费 |
|
||||
| `roleAssetSummaryLabel / cover* / counts` 等 works 字段 | works 聚合字段 | 后端能返回,但主平台 create tab 没走 `works` 入口 | 当前主链弱消费 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 冗余功能与冗余组件
|
||||
|
||||
## 7.1 冗余功能
|
||||
|
||||
| 功能 | 当前状态 | 问题 |
|
||||
| --- | --- | --- |
|
||||
| 结果页直接生成 playable/story/landmark | `CustomWorldResultView.tsx` 仍可直接调用 AI 生成 | 与 Agent 对象精修链重复,且不会同步回 session |
|
||||
| 结果页直接编辑 `CustomWorldProfile` | `CustomWorldEntityEditorModal` 仍挂在结果页 | 把结果页继续维持成旧编辑器,而不是 Agent 流程的收口层 |
|
||||
| 旧 `custom-world/sessions` 世界生成 | `2026-04-20` 审计时仍完整可用;`2026-04-21` 已完成物理删除 | 与 Agent 八锚点世界创建重复;当前遗留问题已转为文档口径清理 |
|
||||
| 作品库 `publish/unpublish` 与 Agent `publish_world` | 两套“发布”概念并行 | 一套作用于 library profile,一套想作用于 Agent session,但后者还未打通 |
|
||||
| 结果页自动保存 | `generatedCustomWorldProfile` 变化时自动 `upsertCustomWorldProfile()` | 让“草稿保存”“作品库存档”“正式发布”语义混在一起 |
|
||||
|
||||
## 7.2 冗余或已退出当前版本主链的组件
|
||||
|
||||
`src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx` 当前只真正接了:
|
||||
|
||||
1. `CustomWorldAgentHeader`
|
||||
2. `EightAnchorProgressBar`
|
||||
3. `CustomWorldAgentOperationBanner`
|
||||
4. `CustomWorldAgentThread`
|
||||
5. `CustomWorldAgentComposer`
|
||||
|
||||
在 `2026-04-21` 清理前,同目录下还存在一组未接线旧组件:
|
||||
|
||||
1. `CustomWorldAgentLockBar.tsx`
|
||||
2. `CustomWorldAgentDraftDrawer.tsx`
|
||||
3. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
4. `CustomWorldAgentQuickActions.tsx`
|
||||
5. `CustomWorldAgentSummaryPanel.tsx`
|
||||
6. `CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
7. `CustomWorldAgentClarificationPanel.tsx`
|
||||
8. `CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
其中:
|
||||
|
||||
1. `CustomWorldAgentDraftDrawer.tsx` 已在批次 A 清理中删除
|
||||
2. `CustomWorldAgentLockBar.tsx`
|
||||
3. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
4. `CustomWorldAgentQuickActions.tsx`
|
||||
5. `CustomWorldAgentSummaryPanel.tsx`
|
||||
6. `CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
7. `CustomWorldAgentClarificationPanel.tsx`
|
||||
8. `CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
已在批次 D 清理中判定为退出当前版本主链,并完成物理删除。
|
||||
|
||||
因此这里的审计结论需要更新为:
|
||||
|
||||
1. 它们不再属于“待接线组件”
|
||||
2. 它们属于已确认退场的旧副面板链
|
||||
3. 当前版本如果还要补 `suggestedActions / pendingClarifications / draftCards` 的消费面,应基于新的主链设计重新定义,而不是默认把旧面板接回来
|
||||
|
||||
另外,`src/components/custom-world-home/CustomWorldCreationHub.tsx` 也已存在,但平台 `create` tab 还没有把它接成主入口。
|
||||
|
||||
---
|
||||
|
||||
## 8. 当前没有真正实装到游戏主流程中的项
|
||||
|
||||
| 能力 | 设计 / 定义位置 | 当前状态 |
|
||||
| --- | --- | --- |
|
||||
| `publish_world` 真正发布链 | contract、PRD、route、orchestrator | route 能接,orchestrator 直接 `throw badRequest('publish_world is not available in phase5')` |
|
||||
| `generate_scene_assets` | contract、PRD | contract 定义了,但 action route 未接,主链无执行实现 |
|
||||
| `sync_scene_assets` | contract、PRD | contract 定义了,但 action route 未接,主链无执行实现 |
|
||||
| `expand_long_tail` | contract、PRD | contract 定义了,但主 action 链未接 |
|
||||
| `lock_cards / unlock_cards` | contract、PRD | contract 定义了,但 route / UI / orchestrator 主链未接 |
|
||||
| `regenerate_scope` | contract、PRD | contract 定义了,但 route / UI / orchestrator 主链未接 |
|
||||
| `qualityFindings` 与 blocker 发布门禁 | contract、PRD、技术进度文档 | 字段存在,但没有真实的生成、展示、阻止发布闭环 |
|
||||
| 场景资产工坊从 Agent workspace 打开并写回 | PRD | 主工作区未接详情面板与场景资产 action |
|
||||
| 通过 works 统一恢复 Agent draft / 已发布作品 | works service + creation hub | 后端已有聚合,主平台入口未收口 |
|
||||
| 发布前只允许预览、发布后再进入世界 | PRD | 当前 Agent 草稿结果页可自动保存并直接进入世界 |
|
||||
|
||||
补充说明:
|
||||
|
||||
`docs/technical/SCENE_MULTI_ACT_CREATOR_IMPLEMENTATION_PROGRESS_2026-04-20.md` 已明确写到,发布期 `qualityFindings / blocker` 正式接入仍未完成,这与当前代码状态一致。
|
||||
|
||||
---
|
||||
|
||||
## 9. 优先级建议
|
||||
|
||||
## P0:先收一条真正的单一主链
|
||||
|
||||
建议明确把下面这条定为唯一正式主链:
|
||||
|
||||
```text
|
||||
Agent session
|
||||
-> 服务端 draft snapshot
|
||||
-> 服务端质量检查 / 发布动作
|
||||
-> 服务端编译 final CustomWorldProfile
|
||||
-> 世界库
|
||||
-> runtime
|
||||
```
|
||||
|
||||
对应动作:
|
||||
|
||||
1. 结果页不再承担“主编辑器”职责,至少对 Agent draft 结果页关闭 legacy profile 直改能力。
|
||||
2. 用服务端 preview / compile 接口替代前端 `buildCustomWorldProfileFromAgentDraft()` 的最终裁决职责。
|
||||
3. `publish_world` 打通后,再决定是否允许“发布后立即进入世界”。
|
||||
|
||||
## P0:把“进入世界”和“发布世界”重新绑回同一门槛
|
||||
|
||||
建议收口为:
|
||||
|
||||
1. 未发布 Agent 草稿只能继续创作或查看预览。
|
||||
2. 只有 `publish_world` 成功后,才产出正式 `CustomWorldProfile` 并允许主入口进入世界。
|
||||
3. `qualityFindings / blocker` 必须在 foundation draft 完成、资产写回后、publish 前持续重跑。
|
||||
|
||||
## P1:继续做旧 world session 链的文档收口
|
||||
|
||||
`2026-04-21` 更新:
|
||||
|
||||
旧 `custom-world/sessions` 链已经完成物理删除。
|
||||
|
||||
因此这里不再是“保留还是淘汰”的开放问题,而是:
|
||||
|
||||
1. 继续清理由这条旧链残留在审计、PRD、知识图谱中的过时口径
|
||||
2. 把当前正式主链与仍保留的兼容层边界写清楚
|
||||
|
||||
## P1:把 works 创作中心接回主平台
|
||||
|
||||
建议:
|
||||
|
||||
1. 平台 `create` tab 改成消费 `listCustomWorldWorks()`。
|
||||
2. 草稿 session 通过“继续创作”恢复。
|
||||
3. 已发布 profile 通过“进入世界”或“查看详情”进入。
|
||||
4. `myEntries` 退回为作品库子集,而不是 create tab 的唯一数据源。
|
||||
|
||||
## P1:为悬空 session 字段重新定义最小闭环
|
||||
|
||||
`2026-04-21` 更新:
|
||||
|
||||
原文这里建议把旧 `QuickActions / DraftDrawer / DraftDetailPanel / ClarificationPanel` 接回主工作区。
|
||||
|
||||
但这些旧副面板已经在当前版本收口判断中被明确认定为:
|
||||
|
||||
1. 不属于现行主链
|
||||
2. 不再作为当前版本默认待落地项
|
||||
3. 已完成物理删除
|
||||
|
||||
因此当前更准确的建议应该是:
|
||||
|
||||
1. 如果 `suggestedActions / pendingClarifications / draftCards` 仍要进入正式主流程,需要先重新定义符合当前极简工作区的消费方式
|
||||
2. 不应再以“把旧副面板接回来”作为默认方案
|
||||
3. 在没有新主链设计前,这些字段继续标记为“主链悬空”
|
||||
|
||||
## P2:等主链收口后再清桥接字段
|
||||
|
||||
下面这些字段不建议现在立刻删,但应在主链收口后尽快移除:
|
||||
|
||||
1. `draftProfile.legacyResultProfile`
|
||||
2. 前端桥接里固定写死的 `generationMode / generationStatus`
|
||||
3. 仅为兼容旧编辑器而塞进 legacy profile 的创作态元数据
|
||||
|
||||
---
|
||||
|
||||
## 10. 一句话总评
|
||||
|
||||
当前“Agent 聊天 -> 草稿生成 -> 进入世界”已经能跑通一条可玩链,但它还不是 PRD 要求的“后端单一真相源 + 发布门禁收口”的正式链路,而是 `Agent session`、`legacy profile`、`旧 session`、`作品库` 四层并存、靠前端桥接和结果页兼容能力临时拼起来的过渡态。
|
||||
332
docs/audits/CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md
Normal file
332
docs/audits/CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# 角色资产 Prompt 链路审计(2026-04-20)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 本次审计回答什么问题
|
||||
|
||||
本次只回答角色资产相关的 4 个问题:
|
||||
|
||||
1. `characterAssetPrompts.ts` 里的 `visualPromptText` 和 `animationPromptText`,是不是“生成角色形象 / 动作形象的默认描述”。
|
||||
2. 生成角色形象的系统提示词在哪个文件,生成默认角色形象描述文本的提示词在哪个文件。
|
||||
3. 生成角色动作的系统提示词在哪个文件,生成默认角色动作描述文本的提示词在哪个文件。
|
||||
4. 当前链路里是否存在冗余流程、保留接口或无效代码。
|
||||
|
||||
---
|
||||
|
||||
## 1. 先说结论
|
||||
|
||||
结论不是“只有一套 prompt”,而是:
|
||||
|
||||
**当前角色资产链路仍然有两层 prompt,但“默认描述文本”已经统一成单一主源。**
|
||||
|
||||
### 1.1 默认描述文本层
|
||||
|
||||
这层的目标是:
|
||||
|
||||
**先给资产工坊里的输入框一个默认可编辑文本。**
|
||||
|
||||
这层不直接拿去生成图片或动作视频。
|
||||
|
||||
当前实际主链来源:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
它会把角色已有字段映射成:
|
||||
|
||||
- `visualPromptText`
|
||||
- `animationPromptText`
|
||||
- `scenePromptText`
|
||||
|
||||
其中:
|
||||
|
||||
- `visualPromptText` 优先取 `visualDescription`
|
||||
- `animationPromptText` 优先取 `actionDescription`
|
||||
- `scenePromptText` 优先取 `sceneVisualDescription`
|
||||
|
||||
这层是**默认描述文本**,不是正式图像模型 prompt。
|
||||
|
||||
### 1.2 正式模型 prompt 层
|
||||
|
||||
这层的目标是:
|
||||
|
||||
**把“默认描述文本”进一步编译成正式给图像模型 / 动作模型的完整 prompt。**
|
||||
|
||||
当前主链来源:
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
也就是说:
|
||||
|
||||
1. 前端先有一段短文本
|
||||
2. 后端再用正式 prompt builder 把它扩成模型真正使用的完整 prompt
|
||||
|
||||
---
|
||||
|
||||
## 2. 角色形象生成链路
|
||||
|
||||
## 2.1 生成角色形象的系统提示词在哪
|
||||
|
||||
如果这里问的是“正式生成角色主图时,真正控制模型输出方向的 prompt 主源在哪”,答案是:
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
更准确说:
|
||||
|
||||
1. `buildNpcVisualPrompt`
|
||||
- 文件:`server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- 作用:把短描述文本和角色摘要合并
|
||||
2. `buildMasterPrompt`
|
||||
- 文件:`packages/shared/src/prompts/qwenSprite.ts`
|
||||
- 作用:提供正式的角色主图 prompt 骨架
|
||||
|
||||
最终角色形象正式生成请求使用的是:
|
||||
|
||||
- `buildNpcVisualPrompt(...)`
|
||||
|
||||
调用位置:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
|
||||
即:
|
||||
|
||||
**角色主图正式生成的系统提示词主链,不在前端默认值文件,而在后端 `characterAssetPrompts.ts` + 共享 `qwenSprite.ts`。**
|
||||
|
||||
## 2.2 生成默认角色形象描述文本的提示词在哪
|
||||
|
||||
当前资产工坊默认输入框实际使用:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
这不是 LLM system prompt,而是本地字段映射规则。
|
||||
|
||||
换句话说,当前页面上的默认“形象描述”主要来自:
|
||||
|
||||
- `role.visualDescription`
|
||||
- 或回退到 `role.description`
|
||||
|
||||
---
|
||||
|
||||
## 3. 角色动作生成链路
|
||||
|
||||
## 3.1 生成角色动作的系统提示词在哪
|
||||
|
||||
当前正式动作生成主链在:
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
其中分两类:
|
||||
|
||||
1. `buildArkCharacterAnimationPrompt`
|
||||
- 当前图生视频动作链路主入口
|
||||
2. `buildNpcAnimationPrompt`
|
||||
- 通用动作视频 prompt builder
|
||||
3. `buildImageSequencePrompt`
|
||||
- 连续帧方案动作 prompt builder
|
||||
4. `buildVideoActionPrompt`
|
||||
- 共享动作模板骨架,在 `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
当前主动作链路更偏向:
|
||||
|
||||
- `buildArkCharacterAnimationPrompt`
|
||||
|
||||
调用位置:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
|
||||
## 3.2 生成默认角色动作描述文本的提示词在哪
|
||||
|
||||
当前资产工坊真实默认“动作描述”来源:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
规则是:
|
||||
|
||||
- 优先 `actionDescription`
|
||||
- 回退 `combatStyle`
|
||||
|
||||
这仍然是**默认描述文本层**,不是最终动作模型 prompt。
|
||||
|
||||
---
|
||||
|
||||
## 4. `characterAssetPrompts.ts` 里的 `visualPromptText` / `animationPromptText` 到底是什么
|
||||
|
||||
这两个字段容易混淆,因为它们名字里带 `Prompt`。
|
||||
|
||||
但当前工程里它们更准确的定位是:
|
||||
|
||||
**“默认描述文本 bundle 字段名”,不是最终图像模型请求体里的最终 prompt 名称。**
|
||||
|
||||
也就是:
|
||||
|
||||
- `visualPromptText`
|
||||
- 在 UI 里更像“角色形象描述默认文本”
|
||||
- 之后会再被编译进正式图像 prompt
|
||||
- `animationPromptText`
|
||||
- 在 UI 里更像“角色动作描述默认文本”
|
||||
- 之后会再被编译进正式动作 prompt
|
||||
|
||||
所以对你的问题可以直接回答为:
|
||||
|
||||
**是,它们在当前语义上确实可以看作“默认角色形象 / 动作描述文本”。**
|
||||
|
||||
但需要补一句:
|
||||
|
||||
**它们不是最终一步的正式模型系统提示词,而是正式模型 prompt 的上游输入。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前真实调用链
|
||||
|
||||
## 5.1 当前资产工坊页面初始默认值主链
|
||||
|
||||
当前真实主链:
|
||||
|
||||
1. 角色对象已有字段进入前端
|
||||
2. `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
3. `CustomWorldRoleAssetStudioModal.tsx`
|
||||
4. 输入框初始值:
|
||||
- `visualPromptText`
|
||||
- `animationPromptText`
|
||||
|
||||
这条链:
|
||||
|
||||
- 快
|
||||
- 本地可控
|
||||
- 不依赖额外一次 LLM 调用
|
||||
|
||||
## 5.2 当前正式角色主图生成主链
|
||||
|
||||
1. 前端把输入框里的 `visualPromptText` 提交到后端
|
||||
2. `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `buildNpcVisualPrompt`
|
||||
3. `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `buildMasterPrompt`
|
||||
4. 图像模型正式生成
|
||||
|
||||
## 5.3 当前正式角色动作生成主链
|
||||
|
||||
1. 前端把输入框里的 `animationPromptText` 提交到后端
|
||||
2. `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `buildArkCharacterAnimationPrompt`
|
||||
- 或 `buildNpcAnimationPrompt`
|
||||
- 或 `buildImageSequencePrompt`
|
||||
3. `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `buildVideoActionPrompt`
|
||||
4. 动作模型正式生成
|
||||
|
||||
---
|
||||
|
||||
## 6. 冗余流程与当前问题
|
||||
|
||||
## 6.1 默认描述文本双链已收口
|
||||
|
||||
此前默认描述文本同时存在:
|
||||
|
||||
1. 前端本地字段映射
|
||||
2. 后端 bundle 编译接口
|
||||
|
||||
本轮已经统一为:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
也就是:
|
||||
|
||||
**默认描述文本现在只有一条真实主源。**
|
||||
|
||||
对应变化:
|
||||
|
||||
1. 不再保留后端独立的默认 bundle 编译接口。
|
||||
2. 不再保留前端对应的 bundle 生成 API 壳层。
|
||||
3. `server-node/src/prompts/characterAssetPrompts.ts` 只保留正式模型 prompt builder。
|
||||
|
||||
判断:
|
||||
|
||||
**默认描述文本层的双份真相已经被消除。**
|
||||
|
||||
## 6.2 `scenePromptText` 结构存在,但当前资产工坊没有完整承接
|
||||
|
||||
当前这套链路里:
|
||||
|
||||
- `customWorldRolePromptDefaults.ts` 会返回 `scenePromptText`
|
||||
- `characterAssetPrompts.ts` 也会返回 `scenePromptText`
|
||||
|
||||
但当前资产工坊 UI 里并没有完整对应输入框链路。
|
||||
|
||||
这说明:
|
||||
|
||||
**场景描述文本在结构层存在,但在当前角色资产工坊里没有形成完整的用户可编辑闭环。**
|
||||
|
||||
## 6.3 共享模板与工具模板存在相似实现,但职责不同
|
||||
|
||||
仓库里同时有:
|
||||
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
|
||||
它们都提供类似的主图 / 动作模板能力。
|
||||
|
||||
但当前定位不同:
|
||||
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- 正式角色资产主链共享模板
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
- Qwen 工具链 prompt
|
||||
|
||||
它们不是同一条业务主链里的重复实现,但确实容易让人误读为“双份正式模板”。
|
||||
|
||||
判断:
|
||||
|
||||
**这是“职责上可解释,但认知上高混淆”的并行模板,不建议现在直接删,但需要文档明确边界。**
|
||||
|
||||
## 6.4 当前没有证据说明正式主图 / 动作 prompt builder 是无效代码
|
||||
|
||||
以下 builder 当前都有正式调用点:
|
||||
|
||||
- `buildNpcVisualPrompt`
|
||||
- `buildNpcVisualNegativePrompt`
|
||||
- `buildArkCharacterAnimationPrompt`
|
||||
- `buildNpcAnimationPrompt`
|
||||
- `buildImageSequencePrompt`
|
||||
|
||||
因此它们不能算“无效代码”。
|
||||
|
||||
真正已经被清理掉的保留链路,是此前未接入主 UI 的默认 bundle 接口:
|
||||
|
||||
- `CHARACTER_PROMPT_BUNDLE_SYSTEM_PROMPT`
|
||||
- `buildCharacterPromptBundleUserPrompt`
|
||||
- `/api/assets/character-prompts/generate`
|
||||
|
||||
这套链路已经不再保留在当前仓库主线中。
|
||||
|
||||
---
|
||||
|
||||
## 7. 本次建议
|
||||
|
||||
如果后续要继续收口,建议按顺序处理:
|
||||
|
||||
1. 继续以前端本地映射作为默认描述文本唯一主源。
|
||||
2. 对 `scenePromptText` 做完整承接,不要继续停留在结构存在但 UI 不消费的状态。
|
||||
3. 继续保留 `packages/shared/src/prompts/qwenSprite.ts` 与工具链 prompt 分层,但在文档里强制写清“正式主链 / 工具链”边界。
|
||||
|
||||
---
|
||||
|
||||
## 8. 本次审计覆盖文件
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
- `src/components/CustomWorldRoleAssetStudioModal.tsx`
|
||||
- `src/components/asset-studio/characterAssetWorkflowPersistence.ts`
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
|
||||
---
|
||||
|
||||
## 9. 一句话版结论
|
||||
|
||||
一句话总结就是:
|
||||
|
||||
**当前角色资产系统把“默认描述文本”和“正式模型 prompt”拆成了两层,这是合理的;默认描述文本层已经统一为前端本地映射单一主源,当前剩余主要问题不再是双主源,而是 `scenePromptText` 仍未形成完整 UI 闭环。**
|
||||
444
docs/audits/CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md
Normal file
444
docs/audits/CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 自定义世界创作工具问题审计与优化建议
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 结论先说
|
||||
|
||||
当前自定义世界创作工具已经有了比较强的生成骨架、锚点结构和结果编辑能力,但整体仍处在一个很明显的“半收口状态”:
|
||||
|
||||
**设计目标已经走到“创作者工作台”,数据结构已经支持“锚点化输入”,但实际体验仍然更像“大文本生成器 + 大型结果总表编辑器”。**
|
||||
|
||||
如果用一句话概括当前问题,就是:
|
||||
|
||||
**高杠杆创作入口还不够强,低杠杆编辑负担还偏重,局部重生成与后端收口也还没有真正闭环。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 审计范围
|
||||
|
||||
本次审计主要对照了三类信息:
|
||||
|
||||
1. 目标设计与 PRD
|
||||
- `docs/prd/AI_NATIVE_CUSTOM_WORLD_CREATION_FLOW_OPTIMIZATION_PRD_2026-04-06.md`
|
||||
- `docs/design/CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md`
|
||||
- `docs/design/CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md`
|
||||
- `docs/design/CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md`
|
||||
|
||||
2. 当前前端主流程与工作台
|
||||
- `src/components/SelectionCustomizationModals.tsx`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/components/CustomWorldGenerationView.tsx`
|
||||
- `src/components/CustomWorldResultView.tsx`
|
||||
- `src/components/CustomWorldEntityCatalog.tsx`
|
||||
- `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
|
||||
3. 当前生成链与后端会话层
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `src/services/customWorldCreatorIntent.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `server-node/src/services/customWorldSessionStore.ts`
|
||||
- `server-node/src/services/customWorldGenerationService.ts`
|
||||
- `server-node/src/bridges/legacyAiRuntimeBridge.ts`
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前主要问题
|
||||
|
||||
## 2.1 输入层和意图结构已经脱节
|
||||
|
||||
当前数据结构已经支持:
|
||||
|
||||
- 世界一句话
|
||||
- 主题关键词
|
||||
- 气质约束
|
||||
- 玩家身份
|
||||
- 开局处境
|
||||
- 核心冲突
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 禁止事项
|
||||
|
||||
但实际入口 `src/components/SelectionCustomizationModals.tsx` 里,创作者弹窗仍然基本只有:
|
||||
|
||||
- 生成模式
|
||||
- 一块大 textarea
|
||||
|
||||
这导致两个直接后果:
|
||||
|
||||
1. 设计里已经想清楚的“高杠杆锚点输入”,还没有真正变成主入口。
|
||||
2. `CustomWorldCreatorIntent` 虽然已经能表达卡片化输入,但 UI 并没有把它转成真正可用的创作工作台。
|
||||
|
||||
目前 `card` 模式更多还停留在类型和测试层,没有成为真实用户路径。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把当前创建弹窗升级成“快速文本模式 / 创作卡片模式”双入口。
|
||||
- 快速文本模式保留,但提交后应自动拆出建议锚点,而不是直接把整段文本原封不动送进生成链。
|
||||
- 卡片模式先只做最关键的 `5~6` 张卡,不要一开始把所有高级字段都铺开。
|
||||
- 允许空卡提交,但明确区分“已锁定锚点”和“允许 AI 自由补全”的内容。
|
||||
|
||||
---
|
||||
|
||||
## 2.2 澄清机制已经存在,但没有真正服务创作者
|
||||
|
||||
`server-node/src/services/customWorldSessionStore.ts` 已经支持:
|
||||
|
||||
- 根据输入缺口生成澄清问题
|
||||
- 世界核心不足时追问
|
||||
- 玩家身份缺失时追问
|
||||
- 开局处境缺失时追问
|
||||
- 核心冲突缺失时追问
|
||||
|
||||
但 `src/services/aiService.ts` 当前做法是:
|
||||
|
||||
- 创建 session
|
||||
- 读取问题
|
||||
- 直接用 fallback 文案自动回答
|
||||
- 然后继续生成
|
||||
|
||||
这意味着:
|
||||
|
||||
**系统表面上已经有“先澄清再生成”的能力,但实际体验里,创作者并没有真正参与这一步。**
|
||||
|
||||
结果就是:
|
||||
|
||||
- 低信息量输入并没有被真正补强
|
||||
- 澄清问题变成了内部兜底,而不是创作协作
|
||||
- 很容易继续生成出“完整但不够像用户想要的世界”
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把 session question 真正接到前端,作为生成前的二次确认步骤。
|
||||
- 每次只问 `1~3` 个最关键问题,不要把它做成问卷。
|
||||
- 支持“一键使用系统建议”,但必须让创作者可见,而不是静默自动填充。
|
||||
- 把回答结果回写到 `creatorIntent`,而不是只作为一次性会话答案。
|
||||
|
||||
---
|
||||
|
||||
## 2.3 新建完成后的工作台闭环没有成立
|
||||
|
||||
设计文档里,自定义世界应该是:
|
||||
|
||||
`输入 -> 生成 -> 结果页确认/编辑 -> 保存并进入世界`
|
||||
|
||||
但当前 `src/components/game-shell/PreGameSelectionFlow.tsx` 里,新建世界生成成功后会:
|
||||
|
||||
- 直接保存到世界库
|
||||
- 清空 `generatedCustomWorldProfile`
|
||||
- 返回世界列表页
|
||||
|
||||
而不是进入 `custom-world-result` 结果工作台。
|
||||
|
||||
这会带来几个问题:
|
||||
|
||||
1. 新建后的第一时间确认感不够强。
|
||||
2. 快速模式生成出的“关键对象预览”没有自然承接页。
|
||||
3. 用户生成完后,如果想继续看结果、继续补全、继续编辑,还要再从世界列表里点一次“编辑”。
|
||||
|
||||
这条链路会让“创作中”与“已保存”之间的体验断开。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 新建完成后默认进入结果工作台,而不是直接跳回世界列表。
|
||||
- 保存动作留在结果页显式触发。
|
||||
- 可以增加“自动保存草稿,但仍停留在结果页”的策略,兼顾安全感和连贯性。
|
||||
- 世界列表更适合作为“已归档内容入口”,不适合作为新建完成页。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 结果页仍然偏“数据总表”,低杠杆编辑负担偏重
|
||||
|
||||
当前结果页已经有 `世界 / 锚点 / 可扮演角色 / 场景角色 / 场景` 五个页签,这是正确方向。
|
||||
|
||||
但问题在于,进入编辑器后暴露出来的字段仍然太“底层”了,例如:
|
||||
|
||||
- `backstoryReveal`
|
||||
- 技能列表
|
||||
- 初始物品
|
||||
- 场景 NPC 分配
|
||||
- 场景连接关系
|
||||
|
||||
这些字段对少数深度编辑场景有用,但不应该成为默认主编辑内容。
|
||||
|
||||
当前 `src/components/CustomWorldEntityEditorModal.tsx` 已经变成一个非常重的综合编辑器,里面同时承担:
|
||||
|
||||
- 角色完整档案编辑
|
||||
- 形象编辑入口
|
||||
- AI 资产生成入口
|
||||
- 背景章节编辑
|
||||
- 技能与初始物品编辑
|
||||
- 场景内 NPC 分配
|
||||
- 场景连接维护
|
||||
|
||||
这会带来三层问题:
|
||||
|
||||
1. 创作者负担过重
|
||||
- 很多字段属于“系统编译层”,不属于“创作决策层”。
|
||||
|
||||
2. 移动端负担过重
|
||||
- 大量长表单、长弹窗和多级编辑,对手机创作并不友好。
|
||||
|
||||
3. 工程复杂度过高
|
||||
- 前端工作台承担了太多不同层级的编辑职责。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 默认只暴露高杠杆编辑:
|
||||
- 世界核心命题
|
||||
- 主题与气质
|
||||
- 玩家身份与开局
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 把技能、初始物品、章节 reveal、连接网络等移到“高级模式”或“系统层编辑”。
|
||||
- 结果页结构从“按对象字段堆表单”改成“按创作价值组织”。
|
||||
- 移动端优先改成分段式面板或底部工作台,不要把长表单都塞进同一个大 modal。
|
||||
|
||||
---
|
||||
|
||||
## 2.5 锁定与局部重生成机制还不完整
|
||||
|
||||
当前已经有两套看起来相关的能力:
|
||||
|
||||
1. `creatorIntent` 里的 `locked`
|
||||
2. `lockState` 里的角色 / 地点 / 势力锁定字段
|
||||
|
||||
但实际重生成时,`src/components/game-shell/PreGameSelectionFlow.tsx` 里的合并逻辑只真正处理了:
|
||||
|
||||
- 已锁定角色
|
||||
- 已锁定地点
|
||||
|
||||
而且还是按“名称匹配”保留,不是按稳定 id 或字段级锁定来处理。
|
||||
|
||||
这带来的问题很明显:
|
||||
|
||||
1. 角色或地点一旦重命名,锁定可能失效。
|
||||
2. 势力、冲突、世界概述等高价值内容没有真正进入局部重生成保护范围。
|
||||
3. 当前“锁定能力”更像一个早期过渡实现,还没有形成统一的重生成规则。
|
||||
|
||||
同时,结果页的“重新生成”提示文案仍然是“整世界覆盖式”的语义,这也会进一步削弱用户对重生成的信任感。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把锁定语义统一收口到后端,以 `lockState` 为唯一事实来源。
|
||||
- 锁定粒度改成:
|
||||
- 世界字段锁定
|
||||
- 势力锁定
|
||||
- 关键角色锁定
|
||||
- 关键地点锁定
|
||||
- 长尾内容可重生成
|
||||
- 局部重生成至少拆成几类:
|
||||
- 仅补长尾角色
|
||||
- 仅补长尾场景
|
||||
- 仅重做场景网络
|
||||
- 仅重做支持性 NPC
|
||||
- 合并逻辑不要再靠名称匹配,改成稳定 id 或锚点映射。
|
||||
|
||||
---
|
||||
|
||||
## 2.6 快速模式还不够“快”,生成页也还不够“创作者视角”
|
||||
|
||||
当前快速模式的主要区别,是把数量降成:
|
||||
|
||||
- 可扮演角色 `3`
|
||||
- 场景角色 `8`
|
||||
- 场景 `4`
|
||||
|
||||
但主生成链本身仍然会继续跑:
|
||||
|
||||
- framework
|
||||
- theme pack
|
||||
- story graph
|
||||
- role narrative
|
||||
- role dossier
|
||||
- narrative profile
|
||||
- finalization
|
||||
|
||||
也就是说:
|
||||
|
||||
**现在的 fast 更像“缩数量版 full”,还不是“先出关键锚点与关键对象的创作预览模式”。**
|
||||
|
||||
同时,`src/components/CustomWorldGenerationView.tsx` 当前展示的重点仍然是:
|
||||
|
||||
- 当前批次
|
||||
- 预计等待
|
||||
- 计时
|
||||
- 模型阶段
|
||||
|
||||
而不是创作者真正关心的:
|
||||
|
||||
- 关键角色有没有成型
|
||||
- 核心冲突有没有稳定
|
||||
- 哪些锚点已经锁定
|
||||
- 当前正在补的是关键对象还是长尾内容
|
||||
|
||||
可优化点:
|
||||
|
||||
- 快速模式改成真正的“关键锚点预览模式”:
|
||||
- 先只生成关键角色、关键地点、核心冲突摘要
|
||||
- 暂不补全所有长尾档案
|
||||
- 生成页改成“创作者视角进度”:
|
||||
- 世界灵魂已确定
|
||||
- 关键角色已成型
|
||||
- 关键地点已落地
|
||||
- 长尾扩展准备开始
|
||||
- 把技术批次隐藏到二级信息里,默认只展示创作状态。
|
||||
|
||||
---
|
||||
|
||||
## 2.7 自定义世界底层仍然没有完全脱离模板世界依赖
|
||||
|
||||
这部分设计文档和参考清单已经说得比较清楚,代码里也能看到对应痕迹:
|
||||
|
||||
- `templateWorldType`
|
||||
- `WUXIA / XIANXIA` 兼容字段
|
||||
- 规则层 fallback
|
||||
- 视觉参考池 fallback
|
||||
- 角色骨架与怪物池 fallback
|
||||
|
||||
当前问题不在于“还没完全去模板化”本身,而在于:
|
||||
|
||||
**这层依赖仍然深入到了生成、运行时规则、表现词汇和参考资源,不只是一个兼容字段。**
|
||||
|
||||
这会限制:
|
||||
|
||||
1. 跨题材表达稳定性
|
||||
2. 自定义世界的自有设定层独立性
|
||||
3. 后续真正做到“任何题材都能稳定跑”
|
||||
|
||||
可优化点:
|
||||
|
||||
- 继续按现有设计稿,把模板依赖逐步迁成:
|
||||
- 语义锚层
|
||||
- 规则层
|
||||
- 表现层
|
||||
- 原型参考层
|
||||
- 兼容迁移层
|
||||
- 在迁移完成前,保留兼容字段,但让新逻辑优先读取 `ownedSettingLayers`。
|
||||
- 明确哪些是“兼容桥”,哪些还是“真实主依赖”,避免继续混用。
|
||||
|
||||
---
|
||||
|
||||
## 2.8 前后端边界仍处于过渡态,和项目约束还有距离
|
||||
|
||||
当前自定义世界已经有了:
|
||||
|
||||
- Node 路由
|
||||
- session
|
||||
- 流式生成
|
||||
- 世界库存储接口
|
||||
|
||||
这是对的。
|
||||
|
||||
但问题是,`server-node/src/services/customWorldGenerationService.ts` 仍然通过 `server-node/src/bridges/legacyAiRuntimeBridge.ts` 去桥接 `src/services/ai.ts`。
|
||||
|
||||
这说明:
|
||||
|
||||
**核心生成逻辑虽然已经被路由包起来了,但真正的生成实现还没有完全成为 Express 侧自己的领域服务。**
|
||||
|
||||
同时,前端仍然承担了不少流程语义:
|
||||
|
||||
- 锁定内容合并
|
||||
- 重生成确认
|
||||
- 结果页覆盖提示
|
||||
- 工作台状态切换
|
||||
|
||||
这和当前仓库“前端只负责表现,逻辑与数据尽量收口到 Express 后端”的方向还有距离。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把自定义世界生成链正式下沉到 `server-node` 领域服务。
|
||||
- 把锁定、局部重生成、澄清会话、结果归档规则都放到后端。
|
||||
- 前端只负责:
|
||||
- 输入展示
|
||||
- 进度展示
|
||||
- 结果工作台展示
|
||||
- 明确的用户确认动作
|
||||
|
||||
---
|
||||
|
||||
## 2.9 移动端工作台仍有明显压迫感
|
||||
|
||||
项目文档已经明确要求移动端优先,但当前自定义世界工作台里仍有几个典型问题:
|
||||
|
||||
- 大量长 modal
|
||||
- 多段长表单
|
||||
- `window.confirm / window.alert` 原生弹框较多
|
||||
- 结果页与编辑器中同时承载太多操作密度
|
||||
|
||||
这些在桌面端还能勉强接受,但在手机上会很容易变成:
|
||||
|
||||
- 滚动层级混乱
|
||||
- 退出成本高
|
||||
- 修改焦点不明确
|
||||
- 确认感不稳定
|
||||
|
||||
可优化点:
|
||||
|
||||
- 移动端改成底部工作台 / 分步面板 / 可折叠分区。
|
||||
- 用项目内统一确认弹层替换 `window.confirm / window.alert`。
|
||||
- 让“保存”“继续补全”“局部重生成”这些关键动作固定在底部安全区附近。
|
||||
- 把搜索、批量删除、创建动作做成更轻的操作条,而不是持续挤压正文区。
|
||||
|
||||
---
|
||||
|
||||
## 3. 优先级建议
|
||||
|
||||
### P0:先修主链路闭环
|
||||
|
||||
- 补卡片化输入入口,至少把关键锚点输入真正开放出来。
|
||||
- 把澄清问题正式接入创作者流程,不再静默自动兜底。
|
||||
- 修正“新建完成后直接回世界列表”的流程,生成后默认进入结果工作台。
|
||||
- 统一锁定与局部重生成规则,先让“创作者不怕重生成”成立。
|
||||
|
||||
### P1:再降低工作台负担
|
||||
|
||||
- 结果页默认只展示高杠杆编辑。
|
||||
- 低杠杆字段进入高级模式。
|
||||
- 快速模式改成真正的关键对象预览模式。
|
||||
- 生成页改成创作者视角进度,而不是模型批次视角。
|
||||
|
||||
### P2:最后做架构收口与去模板化
|
||||
|
||||
- 把生成链、锁定规则、会话澄清彻底收回 Express 后端。
|
||||
- 持续推进 `ownedSettingLayers` 成为真实主设定层。
|
||||
- 逐步去掉自定义世界对模板世界的深依赖。
|
||||
- 针对移动端重做工作台的操作密度和确认路径。
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐落地顺序
|
||||
|
||||
如果只按“最小投入、最大体验收益”排序,建议按下面四步做:
|
||||
|
||||
1. 先改输入与结果闭环
|
||||
- 卡片化最小入口
|
||||
- 澄清问题接入
|
||||
- 新建后进入结果页
|
||||
|
||||
2. 再改锁定与局部重生成
|
||||
- 用稳定 id
|
||||
- 用统一 lockState
|
||||
- 增加局部重生成类型
|
||||
|
||||
3. 再改结果工作台结构
|
||||
- 默认高杠杆
|
||||
- 高级模式收纳低杠杆字段
|
||||
- 移动端拆分长表单
|
||||
|
||||
4. 最后做后端收口与去模板化
|
||||
- 服务端领域化
|
||||
- 设定层自有化
|
||||
- 跨题材泛化
|
||||
|
||||
---
|
||||
|
||||
## 5. 一句话判断
|
||||
|
||||
当前自定义世界创作工具最需要的,不是再继续补更多字段或更多生成步骤,而是:
|
||||
|
||||
**把“创作者先决定灵魂锚点,系统再稳定展开世界”这条主逻辑真正落到 UI、流程和后端边界上。**
|
||||
621
docs/audits/CUSTOM_WORLD_PROFILE_MAPPING_AUDIT_2026-04-18.md
Normal file
621
docs/audits/CUSTOM_WORLD_PROFILE_MAPPING_AUDIT_2026-04-18.md
Normal file
@@ -0,0 +1,621 @@
|
||||
# 世界 Profile 到预设内容与实时生成规则映射审计
|
||||
|
||||
更新时间:`2026-04-18`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
本次审计只回答一个问题:
|
||||
|
||||
**当前仓库里的世界 profile 设定,是否已经完整、合理地映射到游戏的预设内容与实时生成内容规则中。**
|
||||
|
||||
这里的“世界 profile”包含两层:
|
||||
|
||||
1. `CustomWorldProfile` 顶层世界数据
|
||||
2. `ownedSettingLayers` 派生设定层
|
||||
|
||||
这里的“预设内容”包含:
|
||||
|
||||
1. 角色运行时预设
|
||||
2. 场景预设
|
||||
3. 默认视觉与怪物匹配
|
||||
4. 初始装备 / 初始背包 / 经济与术语表现
|
||||
|
||||
这里的“实时生成规则”包含:
|
||||
|
||||
1. 主剧情 prompt
|
||||
2. NPC 对话 / 招募 / 私聊 prompt
|
||||
3. 任务生成
|
||||
4. 运行时物品生成
|
||||
5. 故事线程、可见性、叙事 QA 与推进规则
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
结论不是“完全映射”,而是:
|
||||
|
||||
**已完成基础映射,但没有达到“完全且合理”的程度。**
|
||||
|
||||
当前状态更准确地说是:
|
||||
|
||||
1. `世界基础骨架 -> 角色 / 场景 / 属性 / prompt` 这条主链已经打通。
|
||||
2. `叙事层 -> 主剧情/NPC 可见性规则` 已经有比较扎实的接入。
|
||||
3. `规则层 -> UI术语 / 经济 / 属性` 已经接入。
|
||||
4. 但 `模板兼容层` 仍然过强,跨题材世界会被粗暴压回 `WUXIA/XIANXIA`。
|
||||
5. 但 `后端运行时任务/物品模块` 只拿到了瘦身版 profile,没有真正吃到完整世界叙事层。
|
||||
6. 但 `世界级 items / faction / conflict` 仍然更多是文本种子,而不是可操作的游戏内容对象。
|
||||
|
||||
如果按结果判断:
|
||||
|
||||
1. **预设内容映射:部分完整,约 70%。**
|
||||
2. **实时生成规则映射:前端剧情主链较完整,后端运行时子链不完整,整体约 60%。**
|
||||
3. **跨题材合理性:明显不足。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 本次审计覆盖的核心文件
|
||||
|
||||
类型与编译链:
|
||||
|
||||
- `src/types/customWorld.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
- `src/services/customWorldOwnedSettingLayers.ts`
|
||||
- `src/services/customWorldTheme.ts`
|
||||
|
||||
预设内容落地:
|
||||
|
||||
- `src/data/characterPresets.ts`
|
||||
- `src/data/scenePresets.ts`
|
||||
- `src/data/customWorldCharacterLoadout.ts`
|
||||
- `src/data/customWorldRuntime.ts`
|
||||
- `src/data/customWorldVisuals.ts`
|
||||
- `src/data/customWorldNpcMonsters.ts`
|
||||
- `src/data/worldAttributeSchemas.ts`
|
||||
- `src/data/economy.ts`
|
||||
- `src/services/customWorldPresentation.ts`
|
||||
|
||||
实时生成规则:
|
||||
|
||||
- `src/hooks/story/storyContextBuilder.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/characterChatPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- `src/services/questDirector.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `src/data/runtimeItemNarrative.ts`
|
||||
- `src/services/storyEngine/themePack.ts`
|
||||
- `src/services/storyEngine/worldStoryGraph.ts`
|
||||
- `src/services/storyEngine/actorNarrativeProfile.ts`
|
||||
- `src/services/storyEngine/knowledgeGraph.ts`
|
||||
- `src/services/storyEngine/threadContract.ts`
|
||||
- `src/services/storyEngine/visibilityEngine.ts`
|
||||
- `src/services/storyEngine/authorialConstraintPack.ts`
|
||||
- `src/hooks/story/progressionActions.ts`
|
||||
|
||||
后端运行时链:
|
||||
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
- `server-node/src/modules/runtime-item/runtimeItemModule.ts`
|
||||
- `server-node/src/modules/quest/runtimeQuestModule.ts`
|
||||
- `server-node/src/modules/runtime/runtimeSnapshotHydration.ts`
|
||||
|
||||
---
|
||||
|
||||
## 3. 映射总表
|
||||
|
||||
| 设定层/字段 | 映射到预设内容 | 映射到实时生成规则 | 判断 |
|
||||
| --- | --- | --- | --- |
|
||||
| `name/subtitle/summary/tone/playerGoal` | 已映射到角色 opening、场景提示、视觉匹配、程序化物品关键词 | 已映射到主剧情 prompt、任务 prompt、物品 prompt、ThemePack/StoryGraph 派生 | 基本成立 |
|
||||
| `templateWorldType/compatibilityTemplateWorldType` | 强影响角色模板、场景图参考池、怪物池、兼容 schema | 影响 ThemePack fallback 与部分运行时回退 | 已接入,但合理性不足 |
|
||||
| `majorFactions/coreConflicts` | 主要进入 ThemePack / StoryGraph / tension state,未落成具体 faction 实体 | 影响 authorial constraints、线程图谱、任务与剧情语义 | 有映射,但偏文本种子 |
|
||||
| `camp` | 已映射为开局 camp scene、camp 图、camp 连接 | 通过世界参考文本和开局内容进入 prompt | 成立 |
|
||||
| `attributeSchema` | 已映射到角色/NPC 属性、战斗面板、属性展示 | 已映射到 prompt 属性描述与运行时计算 | 成立 |
|
||||
| `ownedSettingLayers.ruleProfile.resourceLabels` | 已映射到 UI 血量/法力/货币等术语 | 主要通过 UI/经济层体现,prompt 侧间接使用 | 成立 |
|
||||
| `ownedSettingLayers.ruleProfile.economyProfile.initialCurrency` | 已映射到初始货币与快照恢复 | 对运行时奖励规则影响弱,更多是初始化 | 成立但范围有限 |
|
||||
| `playableNpcs` | 已映射到可玩角色预设、技能变体、初始物品、home scene | 已映射到剧情 prompt、私聊 prompt、叙事档案 | 成立 |
|
||||
| `storyNpcs` | 已映射到场景 NPC、怪物判定、角色运行时预设 | 已映射到遭遇 prompt、任务发布者、叙事可见性 | 成立 |
|
||||
| `landmarks` | 已映射到 scene presets、连接网络、场景视觉、treasure hints | 已映射到世界参考文本、scene residues、故事线程关联 | 成立 |
|
||||
| `items` | 生成主链默认清空,世界级 item 几乎未形成正式内容层 | `knowledgeFacts` 可支持 item,但主链无内容可用 | 映射明显不足 |
|
||||
| `themePack/expressionProfile` | 已映射到视觉/命名/技能名/场景语义 | 已映射到 prompt 基调、reveal 风格、故事图谱 | 成立 |
|
||||
| `referenceProfile.roleArchetypes` | 已映射到角色模板骨架选择 | 运行时规则直接消费较少 | 部分成立 |
|
||||
| `referenceProfile.sceneBuckets` | 已映射到场景默认图匹配 | 运行时 prompt 直接消费较少 | 部分成立 |
|
||||
| `referenceProfile.creatureArchetypes` | 已映射到怪物 preset 池筛选 | 运行时规则间接消费 | 部分成立 |
|
||||
| `storyGraph` | 预设层主要影响 narrative residues 与 faction tension | 已映射到 active threads、constraints、visibility、chapter/campaign | 成立 |
|
||||
| `narrativeProfile` | 已映射到 scene NPC 简介和遭遇资料 | 已映射到 prompt 可见性、任务/物品关系生成 | 成立 |
|
||||
| `knowledgeFacts` | 不直接生成预设内容 | 已映射到 visibility slice 与 prompt 裁剪 | 成立 |
|
||||
| `threadContracts` | 不直接生成预设内容 | 已映射到 story signal / thread update / QA | 成立 |
|
||||
| `creatorIntent/anchorPack/lockState/anchorContent` | 主要留在创作工作区与结果页整理 | 几乎不直接进入正式游戏运行时 | 创作层有用,运行时映射弱 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 已经成立的映射链
|
||||
|
||||
## 4.1 世界基础骨架已经能稳定进入角色、场景与剧情主链
|
||||
|
||||
`CustomWorldProfile` 的基础字段已经不是“只存档不消费”的状态。
|
||||
|
||||
它们已经实际进入:
|
||||
|
||||
1. 角色开局文案与 opening 动机
|
||||
2. 角色技能变体
|
||||
3. 场景预设名称、描述、连接、treasure hints
|
||||
4. 主剧情 prompt 中的世界补充档案
|
||||
5. 私聊 / 任务 / 运行时物品 prompt 的世界摘要
|
||||
|
||||
这说明:
|
||||
|
||||
**世界 profile 的基础文本层已经真正进入游戏主链。**
|
||||
|
||||
---
|
||||
|
||||
## 4.2 规则层已经落到真实游戏表现
|
||||
|
||||
`ownedSettingLayers.ruleProfile` 目前已真实影响:
|
||||
|
||||
1. `attributeSchema`
|
||||
- 角色/NPC 属性计算
|
||||
- prompt 中的属性描述
|
||||
- 面板展示
|
||||
2. `resourceLabels`
|
||||
- HP/MP/伤害/冷却/货币等 UI 术语
|
||||
3. `economyProfile.initialCurrency`
|
||||
- 自定义世界初始货币
|
||||
- 快照恢复时的默认初始化
|
||||
|
||||
这部分不是空壳。
|
||||
|
||||
**规则层已经从 profile 进入真实结算和 UI。**
|
||||
|
||||
---
|
||||
|
||||
## 4.3 叙事层已经进入 prompt 可见性与推进规则
|
||||
|
||||
`themePack -> storyGraph -> narrativeProfile -> knowledgeFacts -> visibilitySlice`
|
||||
这条链已经是当前自定义世界最完整的一条映射链。
|
||||
|
||||
它已经支撑:
|
||||
|
||||
1. NPC 首遇/低披露 prompt 裁剪
|
||||
2. 当前线程可见性控制
|
||||
3. 当前压力、错位、禁区、已解锁章节等信息分层
|
||||
4. 章节/战役/约束/QA 的继续推进
|
||||
|
||||
这说明:
|
||||
|
||||
**世界 profile 里的叙事层不只是展示文本,而是真的在控制“模型这轮能知道什么、不能知道什么”。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 关键问题
|
||||
|
||||
## 5.1 高优先级问题:模板兼容层仍然是二元锚点,跨题材世界会被错误压缩
|
||||
|
||||
当前主生成链仍要求模型输出:
|
||||
|
||||
- `templateWorldType: WUXIA | XIANXIA`
|
||||
|
||||
而兼容解析也会把世界最终压回:
|
||||
|
||||
1. `arcane -> XIANXIA`
|
||||
2. 其它几乎全部回到 `WUXIA`
|
||||
|
||||
这会直接影响:
|
||||
|
||||
1. 角色模板骨架选择
|
||||
2. 场景默认图参考池
|
||||
3. 怪物 preset 池
|
||||
4. 兼容性 fallback
|
||||
|
||||
问题不在“有兼容字段”,而在于:
|
||||
|
||||
**当前兼容字段仍然过度参与真实内容映射。**
|
||||
|
||||
对现代金融、科幻 AI 战争、校园、都市、调查等题材来说,这种二元压缩并不合理。
|
||||
|
||||
仓库日志里已经出现了典型样本:
|
||||
|
||||
1. 股市世界被要求产出 `XIANXIA`
|
||||
2. AI 战争世界也被要求产出 `XIANXIA`
|
||||
3. 魔法科技融合世界被要求产出 `WUXIA`
|
||||
|
||||
这意味着:
|
||||
|
||||
**世界 profile 虽然支持跨题材文本输入,但底层预设内容映射仍带着明显的“武侠/仙侠残余偏置”。**
|
||||
|
||||
相关文件:
|
||||
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
- `src/services/customWorldTheme.ts`
|
||||
- `src/data/customWorldVisuals.ts`
|
||||
- `src/data/customWorldNpcMonsters.ts`
|
||||
- `src/data/characterPresets.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**这是当前“合理映射”最大缺口。**
|
||||
|
||||
---
|
||||
|
||||
## 5.2 高优先级问题:后端运行时任务/物品模块只消费了瘦身版 world profile
|
||||
|
||||
前端剧情主链里,`customWorldProfile` 会带着:
|
||||
|
||||
1. `themePack`
|
||||
2. `storyGraph`
|
||||
3. `knowledgeFacts`
|
||||
4. `threadContracts`
|
||||
5. `ownedSettingLayers`
|
||||
|
||||
但后端运行时模块里:
|
||||
|
||||
1. `runtimeItemModule` 的 `customWorldProfile` 只有 `{ name, summary }`
|
||||
2. `runtimeQuestModule` 的 `customWorldProfile` 也只有 `{ name, summary }`
|
||||
|
||||
这直接导致后端运行时生成无法真正读取:
|
||||
|
||||
1. 世界线程图谱
|
||||
2. 世界可见性事实
|
||||
3. 参考原型层
|
||||
4. 规则层
|
||||
5. 表达层
|
||||
|
||||
结果是:
|
||||
|
||||
1. 主剧情/NPC prompt 已经较强依赖世界叙事层
|
||||
2. 但后端任务/物品生成还只是吃世界摘要
|
||||
|
||||
这会把系统拆成两种强度不同的世界消费链:
|
||||
|
||||
1. 前端剧情链较“懂世界”
|
||||
2. 后端运行时奖励链较“不懂世界”
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/hooks/story/storyContextBuilder.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- `server-node/src/modules/runtime-item/runtimeItemModule.ts`
|
||||
- `server-node/src/modules/quest/runtimeQuestModule.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**世界 profile 到实时生成规则的映射,在后端链路上是不完整的。**
|
||||
|
||||
---
|
||||
|
||||
## 5.3 高优先级问题:世界级 `items` 没有真正接进主生成链
|
||||
|
||||
类型里存在:
|
||||
|
||||
- `CustomWorldProfile.items`
|
||||
|
||||
构建器也支持:
|
||||
|
||||
1. item 归一化
|
||||
2. `attributeResonance`
|
||||
3. item knowledge facts
|
||||
|
||||
但真正的世界生成主链里:
|
||||
|
||||
1. orchestrator prompt 明确要求不要预生成物品档案
|
||||
2. `attachRuntimeGenerationMetadata(...)` 会把 `items` 直接压成空数组
|
||||
|
||||
这会带来两个结果:
|
||||
|
||||
1. 世界 profile 的“世界级物品层”几乎为空
|
||||
2. 运行时背包、掉落、交易更多依赖程序化生成和角色初始物品
|
||||
|
||||
于是目前的物品系统更像:
|
||||
|
||||
1. 有角色初始物品
|
||||
2. 有运行时程序化物品
|
||||
3. 但没有稳定的“世界物品图谱”
|
||||
|
||||
这意味着:
|
||||
|
||||
**世界 profile 在物品层没有形成完整映射。**
|
||||
|
||||
相关文件:
|
||||
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
- `src/data/customWorldRuntime.ts`
|
||||
- `src/data/customWorldCharacterLoadout.ts`
|
||||
- `src/services/storyEngine/knowledgeGraph.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**这是“预设内容”和“实时生成规则”共同缺失的一块。**
|
||||
|
||||
---
|
||||
|
||||
## 5.4 中优先级问题:`majorFactions/coreConflicts` 仍然是文本种子,不是可操作游戏对象
|
||||
|
||||
当前 `majorFactions` 与 `coreConflicts` 已经被大量消费,但主要消费方式是:
|
||||
|
||||
1. 拼进 `ThemePack`
|
||||
2. 派生 `WorldStoryGraph`
|
||||
3. 派生 `AuthorialConstraintPack`
|
||||
4. 派生 `FactionTensionState`
|
||||
|
||||
问题在于它们还没有形成:
|
||||
|
||||
1. 可索引 faction 实体
|
||||
2. faction 与 NPC 的显式归属关系
|
||||
3. faction 与场景/商店/敌对阵营的显式绑定
|
||||
4. 冲突与任务/势力状态的强约束关系
|
||||
|
||||
当前更多是:
|
||||
|
||||
**“文本里提到过 -> 图谱做字符串匹配 -> 运行时拿去写 prompt”**
|
||||
|
||||
而不是:
|
||||
|
||||
**“世界里真的存在这些派系与冲突对象,并驱动交互规则”**
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/services/storyEngine/themePack.ts`
|
||||
- `src/services/storyEngine/worldStoryGraph.ts`
|
||||
- `src/services/storyEngine/factionTensionState.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**已有映射,但离“完全落地”为具体游戏内容对象还有明显距离。**
|
||||
|
||||
---
|
||||
|
||||
## 5.5 中优先级问题:场景预设会额外注入模板怪物,弱化 landmark 的原始设定控制力
|
||||
|
||||
`buildCustomScenePresets(profile)` 在每个 landmark scene 中,除了把 `landmark.sceneNpcIds` 指向的角色放进去,还会:
|
||||
|
||||
1. 从怪物 preset 池按 scene index 截两只怪
|
||||
2. 直接拼进 `combinedNpcs`
|
||||
|
||||
这意味着即使 profile 本身没有明确要求某个 landmark 出现这些敌对实体,运行时场景仍会被额外补入模板怪物。
|
||||
|
||||
这会导致:
|
||||
|
||||
1. 场景内容不完全由 `landmark + storyNpcs` 决定
|
||||
2. 地标设定与实际可战斗内容之间存在偏移
|
||||
3. 跨题材世界会更容易被模板怪物池拖偏
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/data/scenePresets.ts`
|
||||
- `src/data/customWorldNpcMonsters.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**landmark 到实际场景实体池的映射,不是完全忠实映射,而是“设定 + 模板补丁”。**
|
||||
|
||||
---
|
||||
|
||||
## 5.6 中优先级问题:后端运行时物品线程并不是真正世界线程
|
||||
|
||||
前端剧情链里的 `activeThreadIds` 来自:
|
||||
|
||||
1. `storyEngineMemory`
|
||||
2. `storyGraph`
|
||||
3. `knowledgeFacts`
|
||||
4. `visibilitySlice`
|
||||
|
||||
但后端 `runtimeItemModule` 的 loose context 里,`activeThreadIds` 只是:
|
||||
|
||||
1. `thread:${encounter.id}`
|
||||
2. 或 `thread:${scene.id}`
|
||||
|
||||
这不是世界线程图谱,而是临时合成 id。
|
||||
|
||||
结果是:
|
||||
|
||||
1. 名义上后端物品模块也有“active threads”
|
||||
2. 实际上它拿到的并不是 `WorldStoryGraph` 中的真实线程
|
||||
|
||||
这会让运行时物品的“为什么现在出现”更像局部上下文推断,而不是来自世界故事结构。
|
||||
|
||||
相关文件:
|
||||
|
||||
- `server-node/src/modules/runtime-item/runtimeItemModule.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**这是实时生成规则层的结构性弱映射。**
|
||||
|
||||
---
|
||||
|
||||
## 5.7 中优先级问题:`referenceProfile.roleArchetypes` 只从 playableNpcs 派生,storyNpcs 覆盖不够
|
||||
|
||||
当前 `roleArchetypes` 的编译来源是:
|
||||
|
||||
1. `profile.playableNpcs.slice(0, 6)`
|
||||
|
||||
而不是:
|
||||
|
||||
1. `playableNpcs + storyNpcs` 的综合原型池
|
||||
|
||||
这导致两个问题:
|
||||
|
||||
1. 世界里的长尾 story NPC 原型没有进入 reference archetype 编译
|
||||
2. 某些场景角色/怪物/平民的模板骨架选择更多依赖启发式 fallback
|
||||
|
||||
这会让:
|
||||
|
||||
1. 可玩角色映射较稳定
|
||||
2. 长尾场景角色映射不够稳定
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/services/customWorldOwnedSettingLayers.ts`
|
||||
- `src/services/customWorldReferenceSignals.ts`
|
||||
- `src/data/characterPresets.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**参考层映射存在明显“主角优先、长尾不足”的偏差。**
|
||||
|
||||
---
|
||||
|
||||
## 5.8 低优先级问题:创作元数据并未进入正式游戏运行时
|
||||
|
||||
`creatorIntent / anchorPack / lockState / anchorContent` 当前主要服务于:
|
||||
|
||||
1. 创作工作区
|
||||
2. Agent session
|
||||
3. 结果页和编辑器
|
||||
|
||||
它们对正式运行时的直接作用主要是:
|
||||
|
||||
1. 参与 `ownedSettingLayers` 的编译
|
||||
|
||||
但不会直接变成:
|
||||
|
||||
1. 正式战斗规则
|
||||
2. 场景交互规则
|
||||
3. faction 状态
|
||||
4. 任务目标约束
|
||||
|
||||
这不一定是 bug,但如果把“世界 profile 设定”理解为所有 profile 元数据,那么:
|
||||
|
||||
**创作层数据目前并没有完整进入游戏运行时。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 分层判断
|
||||
|
||||
## 6.1 预设内容映射判断
|
||||
|
||||
### 已经合理接入的部分
|
||||
|
||||
1. 可玩角色
|
||||
2. 场景角色
|
||||
3. 地标场景
|
||||
4. 属性 schema
|
||||
5. 资源术语
|
||||
6. 初始货币
|
||||
7. camp 开局归处
|
||||
8. 默认场景图匹配
|
||||
|
||||
### 仍然不足的部分
|
||||
|
||||
1. 世界级 items
|
||||
2. faction 实体化
|
||||
3. 冲突到任务/场景状态的强绑定
|
||||
4. 跨题材世界的模板偏置问题
|
||||
5. 地标与怪物注入之间的忠实性
|
||||
|
||||
结论:
|
||||
|
||||
**预设内容层是“能跑且已有骨架”,但还不是“设定完全落地”。**
|
||||
|
||||
---
|
||||
|
||||
## 6.2 实时生成规则映射判断
|
||||
|
||||
### 已经合理接入的部分
|
||||
|
||||
1. 主剧情 prompt
|
||||
2. NPC 可见性控制
|
||||
3. 私聊与对话 prompt
|
||||
4. 叙事线程图谱
|
||||
5. 事实图谱
|
||||
6. 作者性约束与 QA
|
||||
|
||||
### 仍然不足的部分
|
||||
|
||||
1. 后端任务模块 world profile 过瘦
|
||||
2. 后端物品模块 world profile 过瘦
|
||||
3. 后端物品线程是伪线程
|
||||
4. 世界级 item 图谱为空
|
||||
5. faction/conflict 仍偏语义层,不够规则化
|
||||
|
||||
结论:
|
||||
|
||||
**实时生成规则层呈现出“前端剧情链强、后端奖励链弱”的不均衡状态。**
|
||||
|
||||
---
|
||||
|
||||
## 7. 最终判定
|
||||
|
||||
如果问题是:
|
||||
|
||||
**“世界 profile 设定是否已经完全地、合理地映射到游戏的预设内容、实时生成内容规则中?”**
|
||||
|
||||
我的结论是:
|
||||
|
||||
**没有。**
|
||||
|
||||
更准确地说:
|
||||
|
||||
1. 已经完成了主干映射。
|
||||
2. 但还没有完成全量映射。
|
||||
3. 也还没有完成跨题材下的合理映射。
|
||||
|
||||
当前系统最准确的状态是:
|
||||
|
||||
**世界 profile 已经成为真实驱动源之一,但还没有成为所有预设内容与实时规则的一致单一真相源。**
|
||||
|
||||
---
|
||||
|
||||
## 8. 建议的修复优先级
|
||||
|
||||
## P1:先补“真实消费不完整”的链路
|
||||
|
||||
1. 让后端 `runtimeItemModule` / `runtimeQuestModule` 接收完整 `customWorldProfile` 子集
|
||||
2. 至少补进:
|
||||
- `ownedSettingLayers`
|
||||
- `storyGraph`
|
||||
- `knowledgeFacts`
|
||||
- `themePack`
|
||||
- `majorFactions/coreConflicts`
|
||||
|
||||
---
|
||||
|
||||
## P1:把 `templateWorldType` 退回兼容字段,而不是主导字段
|
||||
|
||||
1. 生成期保留兼容输出
|
||||
2. 运行时优先读取:
|
||||
- `ownedSettingLayers`
|
||||
- `themeMode`
|
||||
- `referenceProfile`
|
||||
3. 不再让 `WUXIA/XIANXIA` 主导现代/科幻/海洋/裂界世界的视觉与怪物选择
|
||||
|
||||
---
|
||||
|
||||
## P1:补世界级 item 层
|
||||
|
||||
1. 允许世界生成阶段产出一批世界级 items seed
|
||||
2. 让 `knowledgeFacts / runtime item / quest reward / treasure hint` 能挂到这些 seed 上
|
||||
3. 形成“世界物件图谱”,而不是只有角色初始物品和程序化临时物品
|
||||
|
||||
---
|
||||
|
||||
## P2:把 faction/conflict 从文本种子升级成结构对象
|
||||
|
||||
1. faction 实体
|
||||
2. faction -> NPC 归属
|
||||
3. faction -> 场景控制
|
||||
4. conflict -> 任务/线程/场景压力绑定
|
||||
|
||||
---
|
||||
|
||||
## P2:去掉地标场景里的固定模板怪物补丁式注入
|
||||
|
||||
1. 优先使用 landmark 自己的敌对角色设计
|
||||
2. 模板怪物只作为缺口补位
|
||||
3. 补位也要受 landmark/theme/thread 约束
|
||||
|
||||
---
|
||||
|
||||
## P3:扩充 reference archetype 的来源
|
||||
|
||||
1. role archetypes 不只从 playableNpcs 编
|
||||
2. storyNpcs 也应参与 archetype 归纳
|
||||
3. 为平民、敌对、怪物、势力成员建立更细 archetype
|
||||
|
||||
---
|
||||
|
||||
## 9. 一句话总评
|
||||
|
||||
**当前世界 profile 已经能驱动游戏,但还没有彻底收束成“所有预设内容与实时生成规则都优先读取它”的单一真相源。主链可用,边链仍散,跨题材合理性仍偏弱。**
|
||||
437
docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md
Normal file
437
docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# 当前 Function 设计审计(2026-04-03)
|
||||
|
||||
## 审计范围
|
||||
|
||||
本次审计重点阅读并对照了这些位置:
|
||||
|
||||
- `docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md`
|
||||
- `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
- `docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||||
- `docs/audits/engineering/README.md`
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/data/treasureInteractions.ts`
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- `src/hooks/story/npcEncounterActions.ts`
|
||||
- `src/hooks/story/npcInteraction.ts`
|
||||
- `src/hooks/story/progressionActions.ts`
|
||||
- `src/hooks/story/storyGenerationState.ts`
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/components/AdventurePanel.tsx`
|
||||
- `src/components/StateFunctionEditor.tsx`
|
||||
|
||||
## 先说结论
|
||||
|
||||
当前运行时的“function”不是单一体系,而是至少分成了 4 层:
|
||||
|
||||
1. `stateFunctions.ts` 里的基础战斗 / 空闲 function。
|
||||
2. `npcInteractions.ts` 里的 NPC 交互 function。
|
||||
3. `treasureInteractions.ts` 里的宝藏交互 function。
|
||||
4. `useStoryGeneration.ts` / `npcInteraction.ts` / 背包装备锻造里额外加出来的“流程控制型 functionId”。
|
||||
|
||||
“选完选项触发 function 后没有触发剧情推理”这类现象,当前主要有 3 种来源:
|
||||
|
||||
1. **按设计先走本地分流,不会在第一次点击时立刻推理。**
|
||||
2. **剧情推理其实已经完成,但被“继续冒险”这道 UI 中转门挡住了。**
|
||||
3. **真正的可见性 bug:`story_continue_adventure` 的文案常量已经乱码,导致 UI 提示失效,用户很容易误判为没继续推理。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前 function 体系分层
|
||||
|
||||
### 1.1 基础状态 function:`src/data/stateFunctions.ts`
|
||||
|
||||
这一层才是严格意义上的“状态 function 注册表”,由 `resolveFunctionOption` 统一解析。
|
||||
|
||||
当前运行时实际启用 12 个:
|
||||
|
||||
- 战斗类 7 个:
|
||||
- `battle_all_in_crush`
|
||||
- `battle_guard_break`
|
||||
- `battle_probe_pressure`
|
||||
- `battle_feint_step`
|
||||
- `battle_recover_breath`
|
||||
- `battle_finisher_window`
|
||||
- `battle_escape_breakout`
|
||||
- 空闲类 5 个:
|
||||
- `idle_explore_forward`
|
||||
- `idle_travel_next_scene`
|
||||
- `idle_rest_focus`
|
||||
- `idle_observe_signs`
|
||||
- `idle_call_out`
|
||||
|
||||
关键设计点:
|
||||
|
||||
- 定义源头是 `BATTLE_FUNCTIONS` / `IDLE_FUNCTIONS`。
|
||||
- 最终运行时集合由 `buildStateFunctionDefinitions` 产出。
|
||||
- 可执行过滤走 `getExecutableFunctions`。
|
||||
- 文案和视觉包装走 `resolveFunctionOption`。
|
||||
- 默认选项池走 `getDefaultFunctionIdsForContext`。
|
||||
|
||||
注意:
|
||||
|
||||
- `idle_follow_clue` 仍然留在源码和 prompt 描述里,但在 `applyRuntimeFunctionAdjustments` 中被直接过滤掉,不会进入运行时 function 集合。
|
||||
- `src/components/game-shell/useSceneTransitionModel.ts` 里仍然保留了 `idle_follow_clue` 的转场映射,这说明当前 function 清单并不完全一致。
|
||||
|
||||
### 1.2 NPC 交互 function:`src/data/npcInteractions.ts`
|
||||
|
||||
这一层不是通过 `resolveFunctionOption` 生成的,而是 `buildNpcEncounterStoryMoment` 直接拼出 `StoryOption`,并挂上 `interaction.kind = 'npc'`。
|
||||
|
||||
按功能类型看,当前会出现这些 `functionId`:
|
||||
|
||||
- `npc_preview_talk`
|
||||
- `npc_trade`
|
||||
- `npc_fight`
|
||||
- `npc_spar`
|
||||
- `npc_help`
|
||||
- `npc_chat`(可重复出现 2 个以上,代表不同聊天话题)
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `npc_leave`
|
||||
|
||||
关键设计点:
|
||||
|
||||
- 这一层的 function 是“眼前 NPC 交互目录”,不是基础状态机目录。
|
||||
- 真正执行分流不在 `stateFunctions.ts`,而在 `handleNpcInteraction` / `resolveNpcInteractionDecision`。
|
||||
- prompt 层通过 `availableOptions` 把这些 function 当作“固定可选项列表”交给模型,要求模型保留数量和 `functionId`。
|
||||
|
||||
### 1.3 宝藏交互 function:`src/data/treasureInteractions.ts`
|
||||
|
||||
这一层同样不是 `resolveFunctionOption` 体系,而是直接构造带 `interaction.kind = 'treasure'` 的选项。
|
||||
|
||||
当前有 3 个:
|
||||
|
||||
- `treasure_secure`
|
||||
- `treasure_inspect`
|
||||
- `treasure_leave`
|
||||
|
||||
执行时由 `useTreasureFlow.ts` 接管,最终再回到 `commitGeneratedState` 继续剧情推理。
|
||||
|
||||
### 1.4 流程控制 / 面板动作 functionId
|
||||
|
||||
这类 `functionId` 会进入 `lastFunctionId` 或 `commitGeneratedState`,但不在 `stateFunctions.ts` 注册表里:
|
||||
|
||||
- 流程控制:
|
||||
- `story_continue_adventure`
|
||||
- `camp_travel_home_scene`
|
||||
- `story_opening_camp_dialogue`
|
||||
- 面板动作:
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `equipment_unequip`
|
||||
- `forge_craft`
|
||||
- `forge_dismantle`
|
||||
- `forge_reforge`
|
||||
|
||||
这说明当前项目里“functionId”已经同时承担了 3 个角色:
|
||||
|
||||
- 运行时基础状态动作 ID
|
||||
- NPC / 宝藏交互动作 ID
|
||||
- 流程 / 面板事件 ID
|
||||
|
||||
这能跑,但可追踪性已经开始分裂。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前剧情推理触发链路
|
||||
|
||||
### 2.1 会立刻触发剧情推理的主链
|
||||
|
||||
这类点击后会直接走 AI 续推:
|
||||
|
||||
- 普通战斗 / 空闲 function
|
||||
- `handleChoice`
|
||||
- `buildResolvedChoiceState`
|
||||
- `playResolvedChoice`
|
||||
- `generateNextStep`
|
||||
- 这些 NPC 交互
|
||||
- `npc_preview_talk`
|
||||
- `npc_help`
|
||||
- `npc_chat`
|
||||
- `npc_fight`
|
||||
- `npc_spar`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `npc_leave`
|
||||
- 宝藏交互确认后
|
||||
- `treasure_secure`
|
||||
- `treasure_inspect`
|
||||
- `treasure_leave`
|
||||
- 面板动作确认后
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `equipment_unequip`
|
||||
- `forge_*`
|
||||
|
||||
共性是:
|
||||
|
||||
- 要么直接在 `handleChoice` 里调用 `generateNextStep`。
|
||||
- 要么先走 `commitGeneratedState` / `commitGeneratedStateWithEncounterEntry`,再统一调用 `generateStoryForState`。
|
||||
|
||||
### 2.2 第一次点击不会立刻触发剧情推理的分流
|
||||
|
||||
这类最容易被误判成“function 触发了,但剧情没继续”:
|
||||
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`(队伍满时必进 modal;队伍未满时会先进招募对话流)
|
||||
|
||||
原因不是漏调,而是当前设计明确先走:
|
||||
|
||||
- `resolveNpcInteractionDecision`
|
||||
- `trade_modal`
|
||||
- `gift_modal`
|
||||
- `recruit_modal`
|
||||
- `recruit_immediate`
|
||||
|
||||
也就是说:
|
||||
|
||||
- 第一次点击只是**打开模态框 / 进入招募流程**。
|
||||
- 真正推进剧情推理,要等到:
|
||||
- `confirmTrade`
|
||||
- `confirmGift`
|
||||
- `confirmRecruit`
|
||||
- `executeRecruitment`
|
||||
|
||||
如果产品预期是“用户每点一次选项就必须立即看到剧情继续”,这一层现在不满足。
|
||||
|
||||
### 2.3 `npc_chat` 是“先推理,再延迟展示选项”
|
||||
|
||||
`npc_chat` 不是普通的“生成下一幕 + 立刻给选项”,而是单独走这条链:
|
||||
|
||||
1. `commitNpcChatState` 先流式生成聊天正文。
|
||||
2. 聊天结束后,再调用一次 `generateNextStep`。
|
||||
3. 新一轮冒险选项不直接显示,而是塞进 `deferredOptions`。
|
||||
4. 当前界面只先显示一个 `story_continue_adventure`。
|
||||
5. 用户再点一次,才把 `deferredOptions` 放出来。
|
||||
|
||||
所以这里常见的误判是:
|
||||
|
||||
- **剧情推理其实已经做完了。**
|
||||
- 只是 UI 先让用户“继续冒险”一次,才把新选项展示出来。
|
||||
|
||||
---
|
||||
|
||||
## 3. 本次排查发现的重点问题
|
||||
|
||||
### 3.1 真正最像“没触发剧情推理”的地方:模态框型 NPC function
|
||||
|
||||
定位:
|
||||
|
||||
- `src/hooks/story/npcEncounterActions.ts:427-449`
|
||||
- `src/hooks/story/storyGenerationState.ts:41-80`
|
||||
- `src/hooks/story/npcInteraction.ts:427-585`
|
||||
|
||||
现象:
|
||||
|
||||
- 点击 `npc_trade` / `npc_gift` / `npc_recruit` 后,故事文本区通常不会立刻变化。
|
||||
- 当前故事也不会马上追加一段新的 `storyText`。
|
||||
|
||||
原因:
|
||||
|
||||
- 这些 function 的第一次点击只做本地 UI 分流。
|
||||
- 直到用户在 modal 里确认,才会真正调用 `commitGeneratedState` 继续推理。
|
||||
|
||||
判断:
|
||||
|
||||
- **这不是单纯 bug,而是当前设计本身如此。**
|
||||
- 但如果玩家从“选项即剧情推进”的心智出发,会非常像“点了没反应”。
|
||||
|
||||
建议优先级:高。
|
||||
|
||||
### 3.2 最关键的实际 bug:`story_continue_adventure` 文案乱码,导致“已推理但未显式提示”
|
||||
|
||||
定位:
|
||||
|
||||
- `src/hooks/useStoryGeneration.ts:92-96`
|
||||
- `src/hooks/story/npcEncounterActions.ts:281-400`
|
||||
- `src/components/AdventurePanel.tsx:534`
|
||||
- `src/components/AdventurePanel.tsx:860`
|
||||
- `src/components/AdventurePanel.tsx:879`
|
||||
|
||||
现象:
|
||||
|
||||
- `npc_chat` 完成后,系统本应展示一个“继续冒险”按钮,提示“剧情推理完成,继续后显示新的冒险选项”。
|
||||
- 但当前 `CONTINUE_ADVENTURE_ACTION_TEXT` 常量已经写成了乱码:`缁х画鍐掗櫓`。
|
||||
- `AdventurePanel` 又是靠 `option.actionText === '继续冒险'` 来识别这个特殊按钮。
|
||||
|
||||
直接后果:
|
||||
|
||||
- 特殊提示 UI 不会出现。
|
||||
- 玩家只会看到一个普通且乱码的单选项。
|
||||
- 实际上 `deferredOptions` 已经算好了,但用户极容易误会为“剧情没有继续推理”。
|
||||
|
||||
判断:
|
||||
|
||||
- **这是本次排查里最明确的实现级 bug。**
|
||||
- 它不会阻止底层推理发生,但会严重破坏“推理已完成”的可见性。
|
||||
|
||||
建议优先级:最高。
|
||||
|
||||
### 3.3 `StateFunctionEditor` 覆盖不到真正最容易出问题的 function
|
||||
|
||||
定位:
|
||||
|
||||
- `src/components/StateFunctionEditor.tsx:13-21`
|
||||
- `src/components/StateFunctionEditor.tsx:488`
|
||||
- `src/components/StateFunctionEditor.tsx:772-838`
|
||||
- `src/components/StateFunctionEditor.tsx:992-1211`
|
||||
|
||||
现象:
|
||||
|
||||
- 编辑器预览只接了 `buildStateFunctionDefinitions` / `getAllStateFunctionDefinitions` / `resolveFunctionOption`。
|
||||
- 也就是它只能预览 `stateFunctions.ts` 那 12 个基础 function。
|
||||
|
||||
覆盖不到的关键分支:
|
||||
|
||||
- `npc_*`
|
||||
- `treasure_*`
|
||||
- `npc_preview_talk`
|
||||
- `story_continue_adventure`
|
||||
- modal 分流
|
||||
- `npc_chat` 的 `deferredOptions`
|
||||
|
||||
判断:
|
||||
|
||||
- 这不是运行时 bug,但它解释了为什么这类问题很难在编辑器里提前暴露。
|
||||
- 当前“Function 编辑器”并没有覆盖到最复杂、最容易让用户感知为异常的 function 链路。
|
||||
|
||||
建议优先级:高。
|
||||
|
||||
### 3.4 function 清单存在“源码有、运行时无、别处还在引用”的分裂
|
||||
|
||||
定位:
|
||||
|
||||
- `src/data/stateFunctions.ts:350`
|
||||
- `src/data/stateFunctions.ts:429-441`
|
||||
- `src/components/game-shell/useSceneTransitionModel.ts:19-25`
|
||||
|
||||
现象:
|
||||
|
||||
- `idle_follow_clue` 仍在定义表、提示词描述、若干 `switch` 分支中存在。
|
||||
- 但最终在 `applyRuntimeFunctionAdjustments` 被过滤掉,不会进入运行时 function 集合。
|
||||
- `useSceneTransitionModel` 里却还保留着它的转场模式映射。
|
||||
|
||||
判断:
|
||||
|
||||
- 这不是“没触发剧情推理”的直接原因。
|
||||
- 但会让维护者误判当前真实 function 清单,也会增加后续继续扩 function 时的混乱。
|
||||
|
||||
建议优先级:中。
|
||||
|
||||
### 3.5 自动化测试几乎没有覆盖“最容易让人误会没推理”的链路
|
||||
|
||||
定位:
|
||||
|
||||
- 当前已有测试主要是 `src/hooks/story/storyGenerationState.test.ts`
|
||||
|
||||
已覆盖:
|
||||
|
||||
- `trade_modal`
|
||||
- `recruit_modal`
|
||||
- 地图切场景
|
||||
|
||||
未覆盖:
|
||||
|
||||
- `npc_chat` 的 `deferredOptions -> story_continue_adventure -> 真正显示新选项`
|
||||
- `npc_trade` / `npc_gift` / `npc_recruit` 确认后是否一定调用 `commitGeneratedState`
|
||||
- `story_continue_adventure` 文案与 UI 特判是否一致
|
||||
- `npc_preview_talk -> enterNpcInteraction -> generateStoryForState`
|
||||
- 宝藏分支确认后是否稳定续推
|
||||
|
||||
判断:
|
||||
|
||||
- 这类问题之所以能长期存在,一个核心原因就是**最关键的续推分支没有测试兜底**。
|
||||
|
||||
建议优先级:高。
|
||||
|
||||
---
|
||||
|
||||
## 4. 按“首次点击是否立即触发剧情推理”整理
|
||||
|
||||
### 4.1 首次点击就会继续推理
|
||||
|
||||
- `battle_*`
|
||||
- `idle_*`
|
||||
- `npc_preview_talk`
|
||||
- `npc_help`
|
||||
- `npc_chat`
|
||||
- `npc_fight`
|
||||
- `npc_spar`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `npc_leave`
|
||||
- `treasure_*`
|
||||
- `inventory_use`
|
||||
- `equipment_*`
|
||||
- `forge_*`
|
||||
|
||||
### 4.2 首次点击不会立刻继续推理
|
||||
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`(至少会先进入确认 / 对话流)
|
||||
- `story_continue_adventure`
|
||||
|
||||
这里要特别分清:
|
||||
|
||||
- `npc_trade` / `npc_gift` / `npc_recruit` 是**先分流,后确认,确认后再推理**。
|
||||
- `story_continue_adventure` 是**推理已经完成,只是先把结果选项延后展示**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 建议的修正顺序
|
||||
|
||||
### P0
|
||||
|
||||
- 修掉 `CONTINUE_ADVENTURE_ACTION_TEXT` 的乱码。
|
||||
- `AdventurePanel` 不要再靠 `actionText === '继续冒险'` 判定特殊按钮,改成按 `functionId === 'story_continue_adventure'` 判定。
|
||||
|
||||
### P1
|
||||
|
||||
- 明确产品规则:
|
||||
- `npc_trade` / `npc_gift` / `npc_recruit` 第一次点击是否就应该写入一条“进入交易 / 送礼 / 招募确认”的剧情反馈。
|
||||
- 如果答案是“应该”,那这些 modal 型 function 需要补一层轻量 story feedback,而不是只弹框。
|
||||
|
||||
### P1
|
||||
|
||||
- 给 `npc_chat` 补自动化测试:
|
||||
- 聊天后必须出现 `story_continue_adventure`
|
||||
- 第二次点击后必须能展示 `deferredOptions`
|
||||
|
||||
### P1
|
||||
|
||||
- 给 `npc_trade` / `npc_gift` / `npc_recruit` 补自动化测试:
|
||||
- 第一次点击只分流
|
||||
- 确认后一定触发 `commitGeneratedState`
|
||||
- 后续一定能拿到新的 `StoryMoment`
|
||||
|
||||
### P2
|
||||
|
||||
- 扩展 `StateFunctionEditor` 或补新的“交互 function 预览器”,把 `npc_*` / `treasure_*` / `story_continue_adventure` 也纳入可预演范围。
|
||||
|
||||
### P2
|
||||
|
||||
- 清理 `idle_follow_clue` 这类“半退场”的 function,保证:
|
||||
- 运行时集合
|
||||
- prompt 描述
|
||||
- 编辑器
|
||||
- 转场映射
|
||||
- 测试
|
||||
|
||||
保持一致。
|
||||
|
||||
---
|
||||
|
||||
## 最后结论
|
||||
|
||||
当前最值得优先处理的,不是再继续加新的 function,而是先把这 3 个点收拢:
|
||||
|
||||
1. **把“首次点击只分流、不推理”的 function 明确标出来。**
|
||||
2. **把 `npc_chat -> story_continue_adventure -> deferredOptions` 这条延迟展示链做清楚。**
|
||||
3. **先修掉 `story_continue_adventure` 的乱码和基于文案的 UI 判断。**
|
||||
|
||||
如果不先处理这几个点,用户会持续把“按设计延迟”与“真实漏调剧情推理”混在一起感知,后面 function 越多,这类问题会越难排查。
|
||||
@@ -0,0 +1,163 @@
|
||||
# Function 需求完整性核查(2026-04-14)
|
||||
|
||||
## 1. 核查范围
|
||||
|
||||
本次核查按当前线程上下文,聚焦 function 体系相关文档与实现,不扩大到整个项目全部 PRD。
|
||||
|
||||
本次实际对照了这些文档:
|
||||
|
||||
- `docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md`
|
||||
- `docs/reference/FUNCTION_SCRIPT_CATALOG_2026-04-04.md`
|
||||
- `docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md`
|
||||
- `docs/audits/engineering/README.md`
|
||||
|
||||
本次实际核对了这些实现入口:
|
||||
|
||||
- `src/data/functionCatalog/**`
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/components/AdventurePanel.tsx`
|
||||
- `src/hooks/story/choiceActions.ts`
|
||||
- `src/hooks/story/npcEncounterActions.ts`
|
||||
- `src/hooks/story/npcInteraction.ts`
|
||||
- `src/services/runtimeStoryService.ts`
|
||||
- `server-node/src/modules/story/**`
|
||||
- `server-node/src/modules/inventory/**`
|
||||
- `server-node/src/modules/runtime-item/**`
|
||||
- `server-node/src/modules/quest/**`
|
||||
|
||||
## 2. 核查结论
|
||||
|
||||
结论先说:
|
||||
|
||||
- function 主链路需求已经基本落地,不需要再继续“为了完整而过度迭代”。
|
||||
- 当前最主要的缺口不是再发明一套新 function 流程,而是把已有链路补齐回归测试,确保后续不会回退。
|
||||
- 本轮核查后,已把两条仍缺直接测试兜底的核心链路补上。
|
||||
|
||||
## 3. 已确认已经落地的需求
|
||||
|
||||
### 3.1 function 目录化与分层收口
|
||||
|
||||
已实现:
|
||||
|
||||
- `state / npc / treasure / flow / panel` 五类 function 已统一收口到 `src/data/functionCatalog/`
|
||||
- `src/data/functionCatalog/index.ts` 已提供统一导出
|
||||
- `SERVER_RUNTIME_FUNCTION_IDS` 也已和 catalog 文档映射对齐
|
||||
|
||||
判断:
|
||||
|
||||
- 这部分需求已完成,不需要继续重做结构。
|
||||
|
||||
### 3.2 `story_continue_adventure` 延迟展示链路
|
||||
|
||||
已实现:
|
||||
|
||||
- `npc_chat` 在 `npcEncounterActions.ts` 中先生成聊天正文,再把后续选项写入 `deferredOptions`
|
||||
- `choiceActions.ts` 在点击 `story_continue_adventure` 时会直接恢复 `deferredOptions`
|
||||
- `AdventurePanel.tsx` 已按 `functionId` 而不是 `actionText` 识别该特殊按钮
|
||||
|
||||
判断:
|
||||
|
||||
- 这条主功能链路已经真正存在,不属于“文档写了、实现没跟上”。
|
||||
|
||||
### 3.3 modal 型 function 的首次点击分流
|
||||
|
||||
已实现:
|
||||
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
|
||||
这些 function 当前都明确是“首次点击先分流,再在确认后进入真正执行链”。
|
||||
|
||||
当前实现路径:
|
||||
|
||||
- 首次点击:
|
||||
- `choiceActions.ts`
|
||||
- `storyGenerationState.ts`
|
||||
- `npcInteraction.ts`
|
||||
- 确认后:
|
||||
- `trade / gift / quest` 进入 server runtime action
|
||||
- `recruit` 进入本地招募对白与本地状态提交链
|
||||
|
||||
判断:
|
||||
|
||||
- 这不是未实现,而是当前架构设计如此。
|
||||
- 文档里“确认后要继续推进剧情/结算”的要求已经满足。
|
||||
|
||||
### 3.4 Task6 function 的服务端化
|
||||
|
||||
已实现:
|
||||
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `equipment_unequip`
|
||||
- `forge_craft`
|
||||
- `forge_dismantle`
|
||||
- `forge_reforge`
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `treasure_secure`
|
||||
- `treasure_inspect`
|
||||
- `treasure_leave`
|
||||
|
||||
这些 function 已经在前端 `runtimeStoryService.ts`、服务端 `story runtime / inventory / runtime-item / quest` 模块里形成闭环。
|
||||
|
||||
判断:
|
||||
|
||||
- 这部分不需要再回退到前端本地重写。
|
||||
|
||||
## 4. 本轮发现的真实缺口
|
||||
|
||||
本轮真正仍未完整落地的,不是功能行为本身,而是下面两条回归保护:
|
||||
|
||||
### 4.1 `npc_chat -> story_continue_adventure -> deferredOptions`
|
||||
|
||||
问题:
|
||||
|
||||
- 文档明确要求这条链路要清楚、可验证。
|
||||
- 代码已经有,但之前没有直接测试“点击继续冒险后必须展示 deferredOptions”。
|
||||
|
||||
本轮已补:
|
||||
|
||||
- `src/hooks/story/choiceActions.test.ts`
|
||||
- 新增 `reveals deferred adventure options when story_continue_adventure is selected`
|
||||
|
||||
### 4.2 `AdventurePanel` 对 continue option 的识别方式
|
||||
|
||||
问题:
|
||||
|
||||
- 文档明确要求不要再靠文案识别 continue option。
|
||||
- 实现已经改成按 `functionId` 识别,但之前没有组件层测试锁住。
|
||||
|
||||
本轮已补:
|
||||
|
||||
- `src/components/AdventurePanel.test.tsx`
|
||||
- 验证 `story_continue_adventure` 即使 actionText 改掉,仍然显示延迟选项提示
|
||||
- 验证仅 actionText 相同但 functionId 不同,不会误触发提示
|
||||
|
||||
## 5. 本轮新增测试
|
||||
|
||||
本轮新增:
|
||||
|
||||
- `src/components/AdventurePanel.test.tsx`
|
||||
- `src/hooks/story/choiceActions.test.ts`
|
||||
- 新增 deferred options 恢复用例
|
||||
|
||||
## 6. 验收结论
|
||||
|
||||
按当前 function 相关文档要求判断:
|
||||
|
||||
- 核心运行时需求:已实现
|
||||
- 延迟展示链路:已实现
|
||||
- modal 分流架构:已实现
|
||||
- Task6 服务端承接:已实现
|
||||
- 回归测试盲区:本轮已补齐关键缺口
|
||||
|
||||
最终建议:
|
||||
|
||||
- 这块现在不应该继续过度迭代。
|
||||
- 后续应以“新增需求再增量补测试”为主,而不是再次重构 function 主链路。
|
||||
- 除非后续 PRD 明确要求“modal 首次点击也必须立刻生成一段剧情反馈”,否则不建议为了形式统一再强行改写当前分流模型。
|
||||
212
docs/audits/FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md
Normal file
212
docs/audits/FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# Function 运行时完整测试审计(2026-04-16)
|
||||
|
||||
## 1. 本次目标
|
||||
|
||||
本次不是泛泛地跑一遍前端页面,而是围绕“游戏运行中的 function 主链路”做系统化核查,重点确认下面 4 件事:
|
||||
|
||||
- 当前运行时 function 集合是否还能正确构建、过滤、排序和解析。
|
||||
- function 命中的前端承接链路是否仍然稳定。
|
||||
- 已服务端化的 runtime action function 是否还能闭环执行。
|
||||
- 工程门禁是否处于可持续回归的状态。
|
||||
|
||||
## 2. 本次实际覆盖范围
|
||||
|
||||
本轮重点覆盖了这些实现入口:
|
||||
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `src/data/functionCatalog/**`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/hooks/story/**`
|
||||
- `src/services/runtimeStoryService.ts`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
- `server-node/src/modules/story/**`
|
||||
- `server-node/src/modules/inventory/**`
|
||||
- `server-node/src/modules/runtime-item/**`
|
||||
- `server-node/src/modules/quest/**`
|
||||
- `scripts/smoke-server-node.ts`
|
||||
|
||||
## 3. 实际执行的测试与检查
|
||||
|
||||
### 3.1 前端 Vitest 全量测试
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd test
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `110` 个测试文件全部通过
|
||||
- `276` 条测试全部通过
|
||||
|
||||
其中与 function 主链路直接相关、并已确认通过的测试包括:
|
||||
|
||||
- `src/data/stateFunctions.test.ts`
|
||||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||||
- `src/data/npcInteractions.test.ts`
|
||||
- `src/hooks/story/choiceActions.test.ts`
|
||||
- `src/hooks/story/storyGenerationState.test.ts`
|
||||
- `src/hooks/story/runtimeStoryCoordinator.test.ts`
|
||||
- `src/components/AdventurePanel.test.tsx`
|
||||
- `src/services/runtimeStoryService.test.ts`
|
||||
|
||||
补充说明:
|
||||
|
||||
- 运行 `hostileNpcPresets.test.ts` 时会看到 “network disabled in test” 的日志。
|
||||
- 这不是本轮失败项,测试已验证在 LLM 不可达时会正确走 deterministic fallback。
|
||||
|
||||
### 3.2 内容数据校验
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run check:content
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `check:data` 通过
|
||||
- `check:overrides` 通过
|
||||
- `check:smoke` 通过
|
||||
- 输出为:`Content validation passed. scenes=24 monsters=16 characters=5 functions=12`
|
||||
|
||||
结论:
|
||||
|
||||
- 当前基础内容数据、override 与 smoke 内容校验没有发现新的 function 数据层问题。
|
||||
|
||||
### 3.3 服务端测试
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run server-node:test
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `108` 条服务端测试全部通过
|
||||
|
||||
本轮已确认通过的 function 相关服务端能力包括:
|
||||
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `treasure_inspect`
|
||||
- 战斗结算与 quest signal 推进
|
||||
|
||||
结论:
|
||||
|
||||
- 已服务端化的 runtime function 承接链路当前单测层面是稳定的。
|
||||
|
||||
### 3.4 服务端 smoke
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run server-node:smoke
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 失败
|
||||
- 报错:
|
||||
|
||||
```text
|
||||
TypeError: Cannot read properties of undefined (reading 'enabled')
|
||||
```
|
||||
|
||||
### 3.5 TypeScript 类型检查
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run typecheck
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 失败
|
||||
- 失败位置:
|
||||
- `src/hooks/useGameFlow.ts:339`
|
||||
|
||||
### 3.6 生产构建
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run build
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 通过
|
||||
|
||||
结论:
|
||||
|
||||
- 当前代码可构建,但并不代表类型门禁与 smoke 门禁同样健康。
|
||||
|
||||
## 4. 本轮确认的问题
|
||||
|
||||
## P1:`server-node:smoke` 已失效,无法完成服务端运行时冒烟验证
|
||||
|
||||
- 现象:
|
||||
- `npm.cmd run server-node:smoke` 无法启动临时 Express 服务,直接在 `createSmsVerificationService` 处报错。
|
||||
- 直接原因:
|
||||
- [`scripts/smoke-server-node.ts`](../../scripts/smoke-server-node.ts) 里的 `createSmokeConfig()` 只构造了 `llm`、`dashScope` 等字段,没有补齐后续新增的 `smsAuth`、`wechatAuth`、`authSession` 配置块。
|
||||
- [`server-node/src/config.ts`](../../server-node/src/config.ts) 中 `AppConfig` 已把这些字段定义为必需项。
|
||||
- [`server-node/src/services/smsVerificationService.ts`](../../server-node/src/services/smsVerificationService.ts) 在 `createSmsVerificationService` 中直接读取 `config.smsAuth.enabled`,因此 smoke 配置一进入 `createAppContext` 就会崩。
|
||||
- 影响:
|
||||
- 本地无法再用 smoke 脚本验证“服务端真实启动 + 认证 + runtime save/settings 回路”。
|
||||
- 这会让 function 服务端化之后的真实接线路径少掉一层最接近运行时的保护。
|
||||
- 判断:
|
||||
- 这是本轮最明确、最稳定复现的真实 bug。
|
||||
|
||||
## P1:`typecheck` 门禁已破,`useGameFlow` 的 starter inventory 合并存在类型漂移
|
||||
|
||||
- 现象:
|
||||
- `npm.cmd run typecheck` 在 [`src/hooks/useGameFlow.ts`](../../src/hooks/useGameFlow.ts) 第 `339` 行失败。
|
||||
- 直接原因:
|
||||
- 同文件中的 `mergeStarterInventoryItems<T extends { category: string; name: string }>` 会优先从显式 starter item 推断出一个“字段更严格”的 `T`。
|
||||
- 但 fallback 侧传入的是 [`InventoryItem`](../../src/types/items.ts) 数组,而 `InventoryItem.description`、`equipmentSlotId`、`runtimeMetadata` 等字段本身是可选的。
|
||||
- 于是 `explicitItems` 与 `fallbackItems` 在泛型推断后不再兼容,类型门禁被打穿。
|
||||
- 影响:
|
||||
- 当前 starter inventory 初始化链路虽然能跑、也能通过构建,但已经失去 TypeScript 对结构一致性的保护。
|
||||
- 这类问题后续很容易演变成“自定义世界显式初始物品”和“默认初始物品”在字段形态上继续分叉。
|
||||
- 判断:
|
||||
- 这是一个真实的工程 bug,优先级高于纯测试文案问题。
|
||||
|
||||
## 5. 本轮已确认通过的结论
|
||||
|
||||
- state function 运行时构建、过滤、优先级、选项解析当前测试全绿。
|
||||
- function catalog 文档映射、helper option、trade/gift/recruit modal helper 当前测试全绿。
|
||||
- 前端 function 主链路相关测试在最新工作区状态下已全部通过。
|
||||
- 服务端 runtime story action、inventory、runtime-item、quest 承接链路当前测试全绿。
|
||||
- 内容数据层校验通过。
|
||||
- 生产构建通过。
|
||||
|
||||
## 6. 结论
|
||||
|
||||
如果只看“游戏运行中的 function 主链路”,当前结论是:
|
||||
|
||||
- 前端 function 运行时逻辑:通过
|
||||
- 服务端 function action 承接:通过
|
||||
- 内容数据与 function 基础目录:通过
|
||||
- 工程回归门禁:不完整
|
||||
|
||||
当前最需要处理的不是再扩 function 范围,而是先修复这两个门禁缺口:
|
||||
|
||||
1. 修好 `server-node:smoke` 的配置构造,让服务端冒烟恢复可用。
|
||||
2. 修好 `useGameFlow` 的 starter inventory 类型漂移,让 `typecheck` 回到绿色基线。
|
||||
|
||||
## 7. 备注
|
||||
|
||||
本轮没有做两类事情:
|
||||
|
||||
- 没有接入真实外部 LLM 做在线回归,本轮依赖的是本地测试里已有的 fallback 断言。
|
||||
- 没有人手逐个点击整局游戏所有 function 的视觉回放,本轮重点是自动化测试、服务端测试、内容校验与 smoke 门禁。
|
||||
|
||||
因此,本审计可以说明“当前 function 系统的自动化测试层状况”,但不等于“所有视觉演出与在线模型联动都已人工验证完毕”。
|
||||
128
docs/audits/FUNCTION_TEST_AUDIT_2026-04-14.md
Normal file
128
docs/audits/FUNCTION_TEST_AUDIT_2026-04-14.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Function 测试审计(2026-04-14)
|
||||
|
||||
补充更新:
|
||||
|
||||
- 本文记录的 2 个 bug 已在同日完成代码修复。
|
||||
- 对应测试已经从“稳定复现旧行为”切换为“验证修复后行为”。
|
||||
|
||||
## 1. 本次新增测试
|
||||
|
||||
本轮新增了两组 function 相关测试:
|
||||
|
||||
- `src/data/stateFunctions.test.ts`
|
||||
- 覆盖 state function 的运行时过滤、优先级、选项解析、排序逻辑。
|
||||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||||
- 覆盖 function 文档映射、flow helper、NPC helper modal 初始化逻辑。
|
||||
|
||||
这两组测试都直接挂在现有 `vitest` 体系里,没有新建独立测试框架。
|
||||
|
||||
## 2. 本次执行结果
|
||||
|
||||
本轮实际执行了以下测试:
|
||||
|
||||
```bash
|
||||
npx vitest run src/data/stateFunctions.test.ts src/data/functionCatalog/functionCatalog.test.ts
|
||||
npx vitest run src/data/npcInteractions.test.ts src/hooks/story/storyGenerationState.test.ts src/services/runtimeStoryService.test.ts
|
||||
```
|
||||
|
||||
执行结果:
|
||||
|
||||
- 新增测试:`2` 个文件,`12` 条测试,全部通过。
|
||||
- 复跑已有 function 相关测试:`3` 个文件,`17` 条测试,全部通过。
|
||||
- 修复回归测试:`5` 个文件,`30` 条测试,全部通过。
|
||||
- 编码检查:`1516` 个文件全部通过。
|
||||
|
||||
说明:
|
||||
|
||||
- 本轮不是“测试全绿就代表没有问题”。
|
||||
- 最初定位出的 2 个问题,已经在后续修复回合里转成了回归测试。
|
||||
|
||||
## 3. 历史 bug 与修复结果
|
||||
|
||||
### 3.1 `battle_recover_breath`
|
||||
|
||||
- 所在位置:`src/data/stateFunctions.ts`
|
||||
- 状态:已修复
|
||||
- 原始问题表现:
|
||||
- 当 `inBattle = true`,但当前没有存活敌人时,`battle_recover_breath` 仍会留在可执行 function 列表中。
|
||||
- 直接原因:
|
||||
- `matchesCategory` 对 `recovery` 分类只判断了是否处于战斗态,没有像 `battle` / `escape` 分类那样额外校验 `hasAliveMonsters(context.monsters)`。
|
||||
- 修复方式:
|
||||
- 已在 `matchesCategory` 的 `recovery` 分支中,为战斗恢复类 function 补上 `hasAliveMonsters(context.monsters)` 判断。
|
||||
- 修复前影响:
|
||||
- 在“敌人已死但战斗态尚未清理干净”的边界帧里,界面仍可能出现战斗恢复类选项。
|
||||
- 这会让 function 池和真实战斗状态产生残留错位。
|
||||
- 当前验证方式:
|
||||
- `inBattle = true`
|
||||
- `monsters = [{ hp: 0, ... }]`
|
||||
- 调用 `getExecutableFunctions(context)`
|
||||
- 现在返回结果应为空,不再包含 `battle_recover_breath`
|
||||
- 对应用例:
|
||||
- `src/data/stateFunctions.test.ts`
|
||||
- 用例名:`removes battle_recover_breath when combat has no living monsters`
|
||||
|
||||
### 3.2 `npc_trade`
|
||||
|
||||
- 所在位置:`src/data/functionCatalog/npc/npcTrade.ts`
|
||||
- 状态:已修复
|
||||
- 原始问题表现:
|
||||
- trade modal 初始化时,`selectedPlayerItemId` 直接取 `state.playerInventory[0]?.id`。
|
||||
- 如果玩家背包第一项数量为 `0`,modal 默认会选中一件不可出售物品。
|
||||
- 直接原因:
|
||||
- `buildNpcTradeModalState` 没有过滤 `quantity <= 0` 的物品,也没有寻找第一个可交易物品。
|
||||
- 修复方式:
|
||||
- 已改为优先选择 `quantity > 0` 的可交易物品。
|
||||
- 同时对 NPC 库存和玩家背包都使用同一条筛选规则,避免默认选中空物品。
|
||||
- 修复前影响:
|
||||
- 交易面板第一次打开时,默认状态可能就是不可确认的。
|
||||
- 用户需要手动切换到第二件物品,才会进入可提交状态。
|
||||
- 当前验证方式:
|
||||
- `playerInventory[0].quantity = 0`
|
||||
- `playerInventory[1].quantity > 0`
|
||||
- 调用 `buildNpcTradeModalState(...)`
|
||||
- 现在 `selectedPlayerItemId` 应该自动落到第一件可交易物品
|
||||
- 对应用例:
|
||||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||||
- 用例名:`prefers the first tradable player item when zero-quantity items exist`
|
||||
- `src/hooks/story/storyGenerationState.test.ts`
|
||||
- 用例名:`skips zero-quantity player items when opening the trade modal`
|
||||
|
||||
## 4. 本轮已验证通过的 function 能力
|
||||
|
||||
以下内容本轮已通过测试验证,没有发现新的明显问题:
|
||||
|
||||
- state function runtime 构建:
|
||||
- `idle_follow_clue` 已正确从运行时候选池移除。
|
||||
- `idle_explore_forward` 的运行时文案覆盖仍然生效。
|
||||
- state function 选项行为:
|
||||
- 高压战斗下 `battle_recover_breath` 会被正确提权。
|
||||
- 营地场景会正确隐藏 `idle_explore_forward`。
|
||||
- `idle_travel_next_scene` 会强制使用运行时建议 actionText。
|
||||
- `battle_all_in_crush` 会保留外部传入的自定义 actionText。
|
||||
- story option 排序仍保持“前 2 个 model 锁定 + 后续按 priority 排序”。
|
||||
- flow helper:
|
||||
- `story_continue_adventure`
|
||||
- `camp_travel_home_scene`
|
||||
- NPC helper:
|
||||
- `npc_preview_talk`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
- 文档映射:
|
||||
- 当前 `SERVER_RUNTIME_FUNCTION_IDS` 全部都能在 function catalog 文档中找到对应条目。
|
||||
- 本轮扫描到的 function `source` 路径全部存在,没有出现失效引用。
|
||||
|
||||
## 5. 本轮修复动作
|
||||
|
||||
- `battle_recover_breath`
|
||||
- 已补充战斗恢复类 function 的存活敌人校验,避免战斗边界帧残留非法选项。
|
||||
- `npc_trade`
|
||||
- 已把 trade modal 默认选中逻辑改为优先寻找可交易物品,不再直接吃数组第一项。
|
||||
- 回归测试
|
||||
- 原先记录旧行为的测试已翻转为修复后预期,并额外补了一条 `storyGenerationState` 接入层测试。
|
||||
|
||||
## 6. 备注
|
||||
|
||||
这次测试资产的意义分两步:
|
||||
|
||||
- 第一步先把 bug 稳定复现出来,避免问题只停留在口头描述。
|
||||
- 第二步在修复后把断言翻转成“正确行为”,让它们正式成为回归测试。
|
||||
133
docs/audits/ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md
Normal file
133
docs/audits/ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 物品生成系统与 Build 标签系统 PRD 落地审计
|
||||
|
||||
审计时间:2026-04-05
|
||||
|
||||
审计范围:
|
||||
|
||||
- `docs/prd/AI_NATIVE_RUNTIME_ITEM_GENERATION_DESIGN.md`
|
||||
- `docs/prd/RUNTIME_ITEM_GENERATION_CURRENT_SYSTEM_DESIGN.md`
|
||||
- `docs/prd/BUILD_SYSTEM_ATTRIBUTE_SIMILARITY_PRD_2026-04-02.md`
|
||||
- `docs/design/EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md`
|
||||
|
||||
## 结论速览
|
||||
|
||||
### 1. 物品生成系统
|
||||
|
||||
当前状态可以判定为:**主链已补齐落地**。
|
||||
|
||||
已经落地的是:
|
||||
|
||||
- 有独立的运行时上下文层、导演层、本地编译层、叙事回写层。
|
||||
- 宝藏、怪物掉落、通用 NPC 商店已经能走统一的 runtime item director。
|
||||
- 永久 build 标签物品、限时 build buff 物品、少量数值物品三种骨架都已经能编译出来,并接进现有背包 / 装备 / build 结算。
|
||||
|
||||
本轮已补齐的是:
|
||||
|
||||
- 新增了 runtime item AI 意图导演与 prompt,并接入 NPC 帮助奖励主链,失败时自动回退到本地导演。
|
||||
- NPC 交易库存改成按玩家当前 build 生成,并通过 `tradeStockSignature` 只在 build 变化时刷新。
|
||||
- NPC 帮助奖励、委托奖励已经统一接入 runtime item director。
|
||||
- 怪物掉落已经改成“基础掉落 + 语义掉落”双层叠加。
|
||||
|
||||
### 2. Build 标签系统
|
||||
|
||||
当前状态可以判定为:**核心已按 PRD 落地,且实现范围比 PRD 更大**。
|
||||
|
||||
已经落地的是:
|
||||
|
||||
- `BuildTagDefinition.attributeAffinity` 已扩展。
|
||||
- `buildDamage.ts` 已改成“标签分别匹配角色属性画像”的加法模型,不再做标签两两网络效应。
|
||||
- Buff / 角色固有 / 武器 / 护甲 / 饰品 / 套装标签都能进入最终倍率。
|
||||
- Character 面板已经切到“属性适配度”展示,并能拆出单标签的属性贡献明细。
|
||||
- 有针对新公式的测试覆盖。
|
||||
|
||||
还存在的尾项主要是:
|
||||
|
||||
- 实现用的是“世界属性 schema 六轴模型”,不是 PRD 文字里的固定四维属性。
|
||||
- 旧的标签相似度辅助能力没有完全清干净,重铸仍在用 `getSimilarBuildTags` 做候选标签替换。
|
||||
|
||||
## 物品生成系统审计
|
||||
|
||||
| PRD 项 | 当前实现 | 判定 | 代码证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 上下文采样层 | 已有 `buildRuntimeItemGenerationContext` / `buildQuestRuntimeItemGenerationContext`,会收集场景、遭遇、关联 NPC、最近剧情、玩家 build 标签与 build gap。 | 已落地 | `src/data/runtimeItemContext.ts:157-188`、`src/data/runtimeItemContext.ts:191-252` |
|
||||
| AI 意图层 | 已新增 `runtimeItemAiDirector` / `runtimeItemAiPrompt`,`buildRuntimeItemAiPromptInput` 已进入真实 prompt 组装;NPC 帮助奖励主链会先请求 AI 物品意图,再回落到本地意图导演。 | 已补齐 | `src/services/runtimeItemAiPrompt.ts`、`src/services/runtimeItemAiDirector.ts`、`src/data/runtimeItemDirector.ts`、`src/hooks/story/npcEncounterActions.ts` |
|
||||
| 本地编译层 | 已按 channel / slot / permanence 做 rarity 与预算编译,并产出 `statProfile`、`useProfile.buildBuffs`、`buildProfile`、`runtimeMetadata`。 | 已落地 | `src/data/runtimeItemCompiler.ts:77-101`、`src/data/runtimeItemCompiler.ts:122-206`、`src/data/runtimeItemCompiler.ts:245-276` |
|
||||
| 叙事回写层 | 会把锚点、来源理由、build 倾向回写进物品名和描述。 | 已落地 | `src/data/runtimeItemNarrative.ts:171-189` |
|
||||
| 永久标签 / 限时标签 / 少量数值三类物品 | 永久物品走 `buildProfile`,限时物品走 `useProfile.buildBuffs`,并可附带少量数值。 | 已落地 | `src/data/runtimeItemCompiler.ts:104-155`、`src/data/runtimeItemCompiler.ts:157-206` |
|
||||
| 宝藏入口 | 宝藏奖励已经走 `buildRuntimeItemGenerationContext + buildDirectedRuntimeReward`,并把结果写回 story hint。 | 已落地 | `src/data/treasureInteractions.ts:52-89`、`src/hooks/useTreasureFlow.ts:45-75` |
|
||||
| NPC 交易入口 | 通用 NPC 商店已改成按玩家当前 build 生成;初始 NPC 状态、交易模态打开时刷新、场景预览读取都会带上完整 `GameState`,并用 `tradeStockSignature` 避免无意义重刷。角色型 NPC 仍保留既有角色装备/背包模板。 | 已补齐 | `src/data/npcInteractions.ts`、`src/hooks/story/npcInteraction.ts`、`src/hooks/useStoryGeneration.ts`、`src/components/NpcModals.tsx` |
|
||||
| NPC 帮助 / 关系奖励 | `npc_reward` 已真正接入主链。帮助奖励现在会生成带 `runtimeMetadata` 的 runtime item,并保留数值恢复、冷却缩减与 story hint。 | 已补齐 | `src/data/npcInteractions.ts`、`src/hooks/story/npcEncounterActions.ts` |
|
||||
| 委托奖励入口 | Quest reward 已改为走 runtime director,支持 `buildQuestRuntimeItemGenerationContext`,领取时发放的是 runtime item。主 NPC 接任务流程也已切到 `generateQuestForNpcEncounter`。 | 已补齐 | `src/data/questFlow.ts`、`src/hooks/story/npcEncounterActions.ts`、`src/services/questDirector.ts` |
|
||||
| 怪物掉落双层设计 | 普通世界掉落已改成预设 `lootTable` 基础掉落与 `monster_drop` runtime 语义掉落并存,不再互相覆盖。 | 已补齐 | `src/data/hostileNpcPresets.ts`、`src/data/hostileNpcPresets.test.ts` |
|
||||
|
||||
### 物品系统的具体判断
|
||||
|
||||
#### 已经明显符合 PRD 的部分
|
||||
|
||||
1. 系统分层已经形成。
|
||||
`runtimeItemContext -> runtimeItemDirector -> runtimeItemCompiler -> runtimeItemNarrative` 这条链已经非常接近 PRD 里“上下文采样 / AI 意图 / 本地编译 / 叙事回写”的结构。
|
||||
|
||||
2. build 导向优先于纯数值。
|
||||
`buildRuntimeItemContext` 会先算 `playerBuildTags` 和 `playerBuildGaps`,导演层再优先把 gap tag 与现有 build tag 拼进 `targetBuildDirection`,编译层才决定数值预算。
|
||||
|
||||
3. 奖励已经进入真实玩法结算。
|
||||
runtime item 生成出的 `buildProfile` 会进入装备 build 结算,`useProfile.buildBuffs` 会在使用物品时写入 `activeBuildBuffs`。
|
||||
|
||||
#### 本轮补齐后的说明
|
||||
|
||||
1. 运行时物品意图已经进入真实主链。
|
||||
当前至少在 NPC 帮助奖励链路中,已经先走 AI 意图导演,再走本地编译与叙事回写;如果模型不可用,会回退到既有启发式导演,保证玩法不断。
|
||||
|
||||
2. 交易库存已经真正读取玩家当前构筑。
|
||||
通用交易 NPC 的库存会基于玩家当前 build、装备标签和 build gap 生成,而不是继续依赖 NPC 自身偏好标签。
|
||||
|
||||
3. 帮助奖励、委托奖励、怪物掉落都已并入统一 runtime director。
|
||||
现在三条链路都能产出带 relation anchor / source reason / runtime metadata 的 runtime item。
|
||||
|
||||
## Build 标签系统审计
|
||||
|
||||
| PRD 项 | 当前实现 | 判定 | 代码证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| `BuildTagDefinition.attributeAffinity` 扩展 | 类型已扩展,标签注册表也会为每个标签注入 affinity。 | 已落地 | `src/types/build.ts:6-13`、`src/data/buildTags.ts:66-69` |
|
||||
| 静态标签亲和度表 | 已有 `buildTagAttributeAffinity.ts`,提供标签到属性轴的静态 affinity 表。 | 已落地 | `src/data/buildTagAttributeAffinity.ts:127-183` |
|
||||
| 从“标签互相影响”改为“标签分别匹配角色属性” | `buildDamage.ts` 已按单标签计算 `fitScore`、`bonusDelta` 和属性贡献,最后做加法累积,不再做 pair/cluster 乘法网络。 | 已落地 | `src/data/buildDamage.ts:236-318` |
|
||||
| 来源系数 | Buff / 角色 / 武器 / 护甲 / 饰品 / 套装都有独立 source coefficient,和 PRD 基本一致。 | 已落地 | `src/data/buildDamage.ts:95-114` |
|
||||
| 最终伤害接入 | `resolvePlayerOutgoingDamage` / `resolveCompanionOutgoingDamage` / `resolveMonsterOutgoingDamage` 都已接 `buildDamageMultiplier`。 | 已落地 | `src/data/buildDamage.ts:498-542` |
|
||||
| 展示层从“标签协同”改成“属性适配度” | Character 面板已经按标签展示 bonus、来源、主导属性,并能打开明细弹窗。 | 已落地 | `src/components/CharacterPanel.tsx:205-247`、`src/components/CharacterPanel.tsx:497-539` |
|
||||
| 验收测试 | 已覆盖单标签可拆分、删一个标签不重算其余标签、不同属性角色用同一套装倍率不同、Buff/套装来源正常进入等场景。 | 已落地 | `src/data/buildDamage.test.ts:125-313` |
|
||||
| 四维属性口径 | PRD 写的是四维固定属性;实现已经提升为 world schema 六轴模型。目标一致,但口径不再一一对应。 | 已落地,但实现已外延扩展 | `src/types/attributes.ts:3-15`、`src/data/worldAttributeSchemas.ts:4-155` |
|
||||
| 旧标签相似度清理 | 核心伤害结算已不再依赖旧矩阵,但 `getSimilarBuildTags` 仍存在,重铸继续用它挑候选标签,`generate:build-tags` 脚本也还保留。 | 收尾未完成 | `src/data/buildTags.ts:183-215`、`src/data/forgeSystem.ts:371-399`、`package.json:21-24` |
|
||||
|
||||
### Build 系统的具体判断
|
||||
|
||||
#### 已经符合 PRD 核心目标的部分
|
||||
|
||||
1. 可解释性已经建立。
|
||||
现在每个标签都有自己的 `fitScore`、`attributeContributions` 和 `attributeModifierDeltas`,玩家可以看到“这个标签为什么强、强在哪条属性轴上”。
|
||||
|
||||
2. 新增标签不会反向扰动旧标签贡献。
|
||||
`buildDamage.test.ts` 已专门验证“删掉一个标签,只会移除它自己的 row,不会重算其他 row”。
|
||||
|
||||
3. 套装标签、Buff 标签、装备标签都能统一进入同一公式。
|
||||
这点和 PRD 的来源规则一致,且测试已经覆盖。
|
||||
|
||||
#### 需要注意但不构成核心未落地的问题
|
||||
|
||||
1. 实现已经超出 PRD 的四维设计。
|
||||
现在不是固定 `strength / agility / intelligence / spirit` 四维,而是通过 `WorldAttributeSchema` 映射成武侠/仙侠/自定义世界都能共用的语义属性轴。这更适合当前仓库的世界化属性系统,但也意味着 PRD 文案需要同步。
|
||||
|
||||
2. 旧相似度能力没有完全退场。
|
||||
核心伤害结算已经不用标签两两矩阵,但锻造重铸仍然会根据标签相似度挑换洗标签,所以“旧体系相关命名/脚本”还没彻底收尾。
|
||||
|
||||
## 综合判断
|
||||
|
||||
如果按“是否已经把 PRD 的主战场落到代码里”来判断:
|
||||
|
||||
- **Build 标签系统:可以认为已经落地。**
|
||||
- **物品生成系统:可以认为主链已经落地,之前审计出的缺口已在本轮补齐。**
|
||||
|
||||
如果接下来继续做收尾,更建议做的是:
|
||||
|
||||
1. 把 runtime item AI 意图层继续扩到宝藏、怪物掉落、委托奖励以外的更多同步入口,减少启发式 fallback 的覆盖面。
|
||||
2. 给 Build 系统补一版文档同步,明确当前实现已经从 PRD 四维模型升级为世界属性 schema 模型,并清理剩余旧相似度脚本/命名。
|
||||
3. 评估 `origin: 'ai_compiled'` 的语义是否还要细分成“AI 意图 + 本地编译”与“纯本地 fallback”两档,方便后续观测与埋点。
|
||||
27
docs/audits/README.md
Normal file
27
docs/audits/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 审计与复盘
|
||||
|
||||
这一组文档聚焦“当前状态是否健康、问题在哪里、和目标设计差多少”。
|
||||
|
||||
## 系列总览
|
||||
|
||||
- [engineering/README.md](./engineering/README.md):当前工程优化审查与历史结论聚合入口。
|
||||
- [text/README.md](./text/README.md):文本、英文残留、乱码审计系列的融合入口。
|
||||
|
||||
## 专项审计
|
||||
|
||||
- [FUNCTION_DESIGN_AUDIT_2026-04-03.md](./FUNCTION_DESIGN_AUDIT_2026-04-03.md):Function 体系分层、职责边界和当前结构问题。
|
||||
- [FUNCTION_REQUIREMENT_COMPLETENESS_AUDIT_2026-04-14.md](./FUNCTION_REQUIREMENT_COMPLETENESS_AUDIT_2026-04-14.md):Function 相关文档需求与当前实现对齐核查。
|
||||
- [FUNCTION_TEST_AUDIT_2026-04-14.md](./FUNCTION_TEST_AUDIT_2026-04-14.md):Function 运行时测试补充、已确认 bug 与当前验证结果。
|
||||
- [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):自定义世界创作工具当前问题、体验断层和优化优先级审计。
|
||||
- [AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md](./AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md):Agent 聊天、草稿生成、作品库存储与进入世界之间的断点、多 pipeline、冗余与未实装项审计。
|
||||
- [CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md](./CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md):角色资产默认描述文本、正式图像/动作 prompt、共享模板与保留接口的分层与冗余审计。
|
||||
- [engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md](./engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md):对 `2026-04-19` 工程清理审计的当前仓库复核,区分已完成项、仍存边界问题和新的热点迁移。
|
||||
- [engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md):未引用垃圾、旧入口残留、前后端双份真相与后端迁移项的专项审计。
|
||||
|
||||
## 推荐使用方式
|
||||
|
||||
1. 先读系列总览,确认“最新结论在哪一份”。
|
||||
2. 再按需要进入具体日期文档,查看当时的证据和上下文。
|
||||
3. 做方案设计前,优先把对应审计文档看完,避免重复踩已知问题。
|
||||
@@ -0,0 +1,29 @@
|
||||
# RPG 运行时直读世界草稿 Profile 检查 2026-04-25
|
||||
|
||||
## 结论
|
||||
|
||||
RPG 运行时进入游戏时不应再通过 `resultPreview.preview` 或 legacy runtime profile 做中间转换,主数据源统一为 Agent session 的 `draftProfile`。
|
||||
|
||||
本次检查确认:
|
||||
|
||||
1. Rust 侧 `custom_world_foundation_draft` 已直接产出 `draftProfile`。
|
||||
2. 前端原先 `buildCustomWorldProfileFromAgentSession()` 仍只读取 `session.resultPreview.preview`,这会绕过草稿 profile 中已经存在的角色形象、关系、压力等字段。
|
||||
3. 角色选择页与游戏内角色本身可以消费 `CustomWorldProfile.playableNpcs[].imageSrc`,断点在“session -> profile”的入口,而不是角色选择页。
|
||||
4. “进入世界”按钮原先还会先执行 `sync_result_profile`,把当前结果页旧快照再同步回 session;如果结果页 profile 没有最新角色图,会在进入角色选择页前覆盖掉 `draftProfile` 中的正确形象。
|
||||
|
||||
## 已修正
|
||||
|
||||
- `buildCustomWorldProfileFromAgentSession()` 改为直接归一化 `session.draftProfile`。
|
||||
- `resultPreview` 只保留为发布质量、blocker、预览外壳信息,不再作为进入游戏 profile 的数据源。
|
||||
- Agent 草稿结果进入游戏时直接使用最新 `agentSessionProfile`,不再把当前结果页 profile 回写成新的运行时 profile。
|
||||
- 前端 `normalizeCustomWorldProfileRecord()` 补齐 rs 草稿角色字段兼容:
|
||||
- `publicMask/publicIdentity` -> `description/visualDescription/personality` fallback
|
||||
- `currentPressure/hiddenHook` -> `backstory/actionDescription/sceneVisualDescription` fallback
|
||||
- `relationToPlayer` -> `motivation/relationshipHooks` fallback
|
||||
- `imageSrc/generatedVisualAssetId/generatedAnimationSetId/animationMap` 保持直通
|
||||
|
||||
## 后续约束
|
||||
|
||||
- 新 RPG 运行时链路只允许读取 `draftProfile`。
|
||||
- 不再为进入游戏构造额外 legacy profile,也不再把 `resultPreview.preview` 当作运行时真相源。
|
||||
- 如果草稿中新增角色、场景、物品字段,应优先扩展 `draftProfile` 的归一化读取,而不是增加中间转换结构。
|
||||
@@ -0,0 +1,369 @@
|
||||
# 当前工程优化点盘点(2026-04-20)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 盘点目标
|
||||
|
||||
这份文档用于回答一个更直接的问题:
|
||||
|
||||
**基于当前仓库状态,接下来最值得投入工程时间的优化点是什么。**
|
||||
|
||||
本轮只做文档盘点,不直接修改业务代码;结论同时参考了当前工作区现状。
|
||||
需要注意,仓库当前存在一批未提交改动,尤其集中在 `custom world`、`assets`、`platform shell` 相关模块,所以本文更强调“优先级与切入方式”,而不是要求做大范围整仓改写。
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前快照
|
||||
|
||||
## 1.1 本轮复核方式
|
||||
|
||||
本轮主要复核了以下内容:
|
||||
|
||||
1. 现有工程优化审计文档与目录索引
|
||||
2. `package.json`、`vite.config.ts`、`.eslintrc.cjs` 等门禁脚本
|
||||
3. 当前前端、后端、脚本目录的大文件热点
|
||||
4. 运行时、鉴权、自定义世界、资产链路的边界实现
|
||||
5. 当前 `typecheck / lint / build` 状态
|
||||
|
||||
---
|
||||
|
||||
## 1.2 当前门禁结果
|
||||
|
||||
| 项目 | 结果 | 当前判断 |
|
||||
| --- | --- | --- |
|
||||
| `npm run typecheck` | 失败 | 当前第一优先级问题,类型基线已失真 |
|
||||
| `npm run lint:eslint` | 失败 | `136` 个 error、`4` 个 warning,且 `95` 个可自动修复 |
|
||||
| `npm run build` | 通过 | 发布链路未红,但体积压力仍明显存在 |
|
||||
|
||||
### 关键说明
|
||||
|
||||
当前状态和 `2026-04-10` 那轮“build warning 直接拦截”的状态不同:
|
||||
|
||||
1. **构建现在可以通过。**
|
||||
2. **真正变成第一阻塞项的是 `typecheck` 与 `lint`。**
|
||||
3. **构建虽然通过,但主包、功能包、CSS 体积依然偏重,说明性能类优化仍然值得做。**
|
||||
|
||||
---
|
||||
|
||||
## 1.3 当前热点文件快照
|
||||
|
||||
本轮按源码目录统计的大文件热点如下:
|
||||
|
||||
| 文件 | 当前行数 | 判断 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `6122` | 当前前端最大热点 |
|
||||
| `server-node/src/app.test.ts` | `3568` | 后端测试聚合度过高 |
|
||||
| `server-node/src/modules/assets/characterAssetRoutes.ts` | `2802` | 资产路由职责过重 |
|
||||
| `src/services/ai.ts` | `2432` | 浏览器侧 AI 编排仍然偏重 |
|
||||
| `server-node/src/modules/story/storyActionRoutes.test.ts` | `2402` | 运行时路由测试聚合度过高 |
|
||||
| `src/data/npcInteractions.ts` | `2274` | NPC 规则数据仍然集中 |
|
||||
| `src/prompts/storyPromptBuilders.ts` | `1728` | prompt 构造成为新的复杂度中心 |
|
||||
| `server-node/src/modules/custom-world/runtimeProfile.ts` | `1623` | custom world runtime 编译热点 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `1582` | NPC 行动流仍然偏重 |
|
||||
| `src/components/game-shell/PlatformHomeView.tsx` | `1474` | 平台首页壳层继续膨胀 |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `1418` | 前置选择流程职责过多 |
|
||||
| `src/services/customWorld.ts` | `1383` | 自定义世界服务虽然收缩,但仍偏大 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 结论先行
|
||||
|
||||
当前仓库的优化重点,已经不是“继续清旧 Vite 插件链路”或者“继续讨论前后端是否要分离”。
|
||||
|
||||
更准确地说,当前最值得做的优化点已经收敛成四类:
|
||||
|
||||
1. **先恢复可信的工程基线。**
|
||||
`typecheck` 与 `lint` 当前都是红线,继续扩功能会放大返工成本。
|
||||
2. **拆掉正在持续膨胀的新热点。**
|
||||
热点已经从早期运行时主链,迁移到 `custom world`、`asset routes`、`platform shell`、`prompt builders`。
|
||||
3. **继续把前端退出“运行时真相”和“鉴权真相”。**
|
||||
当前前端仍保留本地快照镜像与自动登录凭证持久化。
|
||||
4. **补一轮入口归档,减少疑似孤岛模块和大测试聚合文件。**
|
||||
这部分不一定最急,但会持续拉低仓库可维护性。
|
||||
|
||||
一句话判断:
|
||||
|
||||
**当前最值得投入的不是横向加功能,而是把质量门禁重新拉绿,再把 custom world / asset / platform 这批新复杂度中心拆开。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 优化点清单
|
||||
|
||||
## 3.1 P0:先恢复类型基线
|
||||
|
||||
这是当前最优先的工程优化点。
|
||||
|
||||
### 证据
|
||||
|
||||
`npm run typecheck` 当前失败,主要问题集中在两类:
|
||||
|
||||
1. `CustomWorldCampScene` 结构漂移
|
||||
- `src/components/CustomWorldEntityEditorModal.test.tsx`
|
||||
- `src/data/customWorldLibrary.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/customWorldCamp.ts`
|
||||
2. 局部实现与类型定义不同步
|
||||
- `src/components/auth/AccountModal.test.tsx` 的测试数据缺少新增字段
|
||||
- `src/components/game-canvas/GameCanvasShared.tsx` 引用了未定义的 `DEFAULT_IMAGE_STYLE`
|
||||
|
||||
### 影响
|
||||
|
||||
1. 类型系统已经不能提供可信回归信号。
|
||||
2. 自定义世界链路当前正在迭代,如果继续在红线状态叠加修改,后续会反复出现“改 A 崩 B”的情况。
|
||||
3. 测试 fixture 与正式类型脱节,会让测试文件逐渐失去文档价值。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 先补一个统一的 `CustomWorldCampScene` 构造/归一化入口,禁止在多个文件里手写不完整字面量。
|
||||
2. 把 `auth`、`custom world` 的测试 fixture 改成工厂函数,避免字段新增后多处漏改。
|
||||
3. 单独清掉 `GameCanvasShared.tsx` 这类“编译即失败”的确定性问题,优先恢复 `typecheck` 绿色基线。
|
||||
|
||||
---
|
||||
|
||||
## 3.2 P0:恢复 lint 可信度,区分机械问题和真实问题
|
||||
|
||||
这项和类型基线同级。
|
||||
|
||||
### 证据
|
||||
|
||||
`npm run lint:eslint` 当前结果是:
|
||||
|
||||
- `136` 个 error
|
||||
- `4` 个 warning
|
||||
- 其中 `95` 个问题可自动修复
|
||||
|
||||
当前 lint 问题明显分成两层:
|
||||
|
||||
1. 机械问题
|
||||
- import 排序
|
||||
- export 排序
|
||||
- 未使用导入
|
||||
2. 真实问题
|
||||
- `server-node/src/modules/inventory/inventoryStoryActionService.ts` 出现 React Hook 规则错误
|
||||
- `server-node/src/migrate.ts` 仍触发 `no-console`
|
||||
- `packages/shared/src/http.ts` 触发 `@typescript-eslint/ban-types`
|
||||
- 若干文件存在真正未使用变量、转义和规则误配问题
|
||||
|
||||
### 影响
|
||||
|
||||
1. 当前 lint 信号噪音仍然较高,不利于 review。
|
||||
2. 真实问题会被大量机械问题掩盖。
|
||||
3. 团队会更倾向于跳过 lint,而不是信任 lint。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 先跑一轮仅机械修复的清理批次,优先吃掉 import sort、unused imports 这类低风险项。
|
||||
2. 再单独处理 Hook 误用、共享契约类型、脚本规则豁免这类语义问题。
|
||||
3. 之后把“自动可修复问题”与“必须人工处理的问题”拆成两个门禁视角,减少下次再次堆积。
|
||||
|
||||
---
|
||||
|
||||
## 3.3 P1:拆 custom world / asset / platform 新热点
|
||||
|
||||
这是当前最有性价比的结构性优化点。
|
||||
|
||||
### 证据
|
||||
|
||||
当前复杂度最高的业务热点,已经集中在这些模块:
|
||||
|
||||
1. `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
2. `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
3. `src/services/ai.ts`
|
||||
4. `src/prompts/storyPromptBuilders.ts`
|
||||
5. `server-node/src/modules/custom-world/runtimeProfile.ts`
|
||||
6. `src/components/game-shell/PlatformHomeView.tsx`
|
||||
7. `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
8. `src/hooks/story/npcEncounterActions.ts`
|
||||
|
||||
### 问题本质
|
||||
|
||||
这些文件并不是单纯“代码多”,而是同时承载了多类职责:
|
||||
|
||||
1. UI 状态
|
||||
2. 领域规则
|
||||
3. 请求编排
|
||||
4. 文本构造
|
||||
5. 运行时映射
|
||||
6. 面板切换与流程控制
|
||||
|
||||
### 建议
|
||||
|
||||
1. `CustomWorldEntityEditorModal.tsx`
|
||||
- 先按“实体列表/表单区/资源区/高级设置/预览区”拆组件
|
||||
- 再把数据准备与提交编排抽成 hook
|
||||
2. `characterAssetRoutes.ts`
|
||||
- 拆成 route、prompt payload、job orchestration、产物发布、错误响应五层
|
||||
3. `PlatformHomeView.tsx` 与 `PreGameSelectionFlow.tsx`
|
||||
- 把页面壳层、数据加载、卡片渲染、弹层控制拆开
|
||||
4. `storyPromptBuilders.ts` 与 `runtimeProfile.ts`
|
||||
- 把“模板片段”“上下文归一化”“规则裁剪”“最终拼接”分层
|
||||
|
||||
---
|
||||
|
||||
## 3.4 P1:继续控制构建产物体积
|
||||
|
||||
构建虽通过,但体积已经给出明显信号。
|
||||
|
||||
### 当前证据
|
||||
|
||||
本轮 `npm run build` 输出里,几个值得关注的点是:
|
||||
|
||||
1. `dist/assets/AuthenticatedApp-*.js`:`794.77 kB`
|
||||
2. `dist/assets/index-*.js`:`197.44 kB`
|
||||
3. `dist/assets/CustomWorldResultView-*.js`:`163.38 kB`
|
||||
4. `dist/assets/ai-*.js`:`131.73 kB`
|
||||
5. `dist/assets/PreGameSelectionFlow-*.js`:`96.39 kB`
|
||||
6. `dist/assets/index-*.css`:`201.44 kB`
|
||||
|
||||
### 影响
|
||||
|
||||
1. 虽然还没触发新的 build gate 红线,但首屏、缓存和移动端体验会继续承压。
|
||||
2. `AuthenticatedApp` 主包偏大,说明平台壳层仍然装入了过多首屏不必需能力。
|
||||
3. CSS 体积继续上涨,说明样式正在跨模块相互堆叠。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 继续把 custom world、asset studio、平台详情页、角色资产工具从主壳层路径中抽离。
|
||||
2. 审查 `ai.ts`、`custom world result view`、`pregame selection` 是否还能再延迟加载。
|
||||
3. 对全局样式做一次按模块归属清理,减少公共样式无限增长。
|
||||
|
||||
---
|
||||
|
||||
## 3.5 P1:继续收紧前端与后端边界
|
||||
|
||||
这项已经不是“要不要做”的问题,而是“还剩多少尾巴没收完”。
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/services/apiClient.ts`
|
||||
- 当前仍把 `access token`
|
||||
- 自动登录用户名
|
||||
- 自动登录密码
|
||||
写入 `window.localStorage`
|
||||
2. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
- 当前仍会在调用后端运行时前先 `putSaveSnapshot(...)`
|
||||
- 响应后继续 `rehydrateSavedSnapshot(...)`
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 当前仍从前端动作流触发 `generateQuestForNpcEncounter(...)`
|
||||
- 说明 NPC 任务“换单/重抽”分支尚未完全后端化
|
||||
|
||||
### 影响
|
||||
|
||||
1. 前端仍保留了一部分运行时真相与鉴权真相。
|
||||
2. 自动登录凭证持久化在边界和安全上都不理想。
|
||||
3. 运行时快照前置写入,会让“前端镜像状态”和“后端会话状态”继续纠缠。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 优先移除自动登录用户名/密码本地持久化,收敛到服务端 session / refresh 机制。
|
||||
2. 把运行时快照改为“展示缓存”而不是“提交前真相源”。
|
||||
3. 把 NPC 任务更换动作补齐到后端 runtime/session 边界,不再由前端直接发起生成决策。
|
||||
|
||||
---
|
||||
|
||||
## 3.6 P2:做一次疑似孤岛模块与旧入口归档
|
||||
|
||||
这项不一定最紧急,但现在做会明显降低后续维护噪音。
|
||||
|
||||
### 当前现象
|
||||
|
||||
从当前入口关系看,以下模块值得做一次正式复核:
|
||||
|
||||
1. `src/components/GameShell.tsx`
|
||||
2. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
3. `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx`
|
||||
4. `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx`
|
||||
5. `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
6. `src/hooks/story/storyBootstrap.ts`
|
||||
7. `src/hooks/useEquipmentFlow.ts`
|
||||
8. `src/hooks/useForgeFlow.ts`
|
||||
9. `src/hooks/useInventoryFlow.ts`
|
||||
10. `src/services/typewriter.ts`
|
||||
|
||||
### 当前判断
|
||||
|
||||
这批模块不一定全部是垃圾代码,但至少说明一件事:
|
||||
|
||||
**仓库里仍然存在一批“不是正式入口、也没有清晰归档标签”的过渡实现。**
|
||||
|
||||
### 建议
|
||||
|
||||
把这类模块统一分成三类:
|
||||
|
||||
1. 正式保留并接回入口
|
||||
2. 明确标记为实验稿
|
||||
3. 直接归档或删除
|
||||
|
||||
这样可以减少后续开发时的误判成本。
|
||||
|
||||
---
|
||||
|
||||
## 3.7 P2:拆测试聚合文件,恢复测试的定位能力
|
||||
|
||||
当前测试文件也已经出现“大一统热点”。
|
||||
|
||||
### 证据
|
||||
|
||||
1. `server-node/src/app.test.ts`:`3568` 行
|
||||
2. `server-node/src/modules/story/storyActionRoutes.test.ts`:`2402` 行
|
||||
3. `server-node/src/modules/assets/characterAssetRoutes.test.ts`:`1235` 行
|
||||
4. `src/hooks/story/npcEncounterActions.test.ts`:`1199` 行
|
||||
|
||||
### 影响
|
||||
|
||||
1. 失败定位成本高。
|
||||
2. fixture 复用差,字段一变容易整片测试跟着漂移。
|
||||
3. 测试文件本身开始变成新的维护热点。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 按领域动作拆测试文件,而不是继续堆到单一总测文件中。
|
||||
2. 补 fixture builder / factory,减少字面量散落。
|
||||
3. 对 `runtime / auth / custom world / assets` 这几条链路增加更明确的契约测试分层。
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐执行顺序
|
||||
|
||||
如果只按工程收益排序,建议按下面的顺序推进:
|
||||
|
||||
1. 先修 `typecheck`
|
||||
2. 再把 `lint` 分成机械修复和语义修复两轮
|
||||
3. 然后拆 `custom world / asset / platform` 热点
|
||||
4. 再继续收前端运行时与鉴权边界
|
||||
5. 最后处理孤岛模块归档和测试拆分
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前不建议优先做的事
|
||||
|
||||
1. 不建议在 `typecheck` 和 `lint` 仍为红线时继续横向扩功能。
|
||||
2. 不建议直接在 `CustomWorldEntityEditorModal.tsx`、`characterAssetRoutes.ts`、`PlatformHomeView.tsx` 里继续堆新逻辑。
|
||||
3. 不建议把 bundle 体积问题简单理解为“先放宽阈值”,当前更适合继续拆职责和延迟加载。
|
||||
4. 不建议在未确认入口关系前随手删除可疑旧模块,先做归档分类更稳。
|
||||
|
||||
---
|
||||
|
||||
## 6. 本文依据
|
||||
|
||||
文档依据:
|
||||
|
||||
1. `docs/audits/engineering/README.md`
|
||||
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
3. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`
|
||||
4. `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
|
||||
当前仓库复核依据:
|
||||
|
||||
1. `package.json`
|
||||
2. `.eslintrc.cjs`
|
||||
3. `vite.config.ts`
|
||||
4. `scripts/build-gate.mjs`
|
||||
5. `src/App.tsx`
|
||||
6. `src/services/apiClient.ts`
|
||||
7. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
8. `src/hooks/story/npcEncounterActions.ts`
|
||||
9. 当前源码大文件体量扫描结果
|
||||
10. `npm run typecheck`
|
||||
11. `npm run lint:eslint`
|
||||
12. `npm run build`
|
||||
@@ -0,0 +1,606 @@
|
||||
# 工程清理与后端边界审计(2026-04-19)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0.1 执行回填(2026-04-19)
|
||||
|
||||
本文审计项 `3.2` 与 `4.4` 已于 `2026-04-19` 当日完成首轮处置:
|
||||
|
||||
1. 已删除 `scripts/dev-server/localApiPlugins.ts`
|
||||
2. 已删除 `scripts/dev-server/characterAssetStudioPlugins.ts`
|
||||
3. 已删除 `scripts/dev-server/qwenSpriteSheetToolPlugins.ts`
|
||||
4. `scripts/dev-server/` 目录仅保留迁移说明,不再保留旧 Vite 本地 API 实现代码
|
||||
5. 当前正式入口统一为 `scripts/dev-node.mjs + vite proxy + server-node/src/modules/**`
|
||||
|
||||
本文其余段落保留为本次审计时的原始问题快照,用于解释为什么要做这轮删除。
|
||||
|
||||
## 0.2 执行回填(2026-04-19,仓库噪音产物)
|
||||
|
||||
本文审计项 `3.1` 已于 `2026-04-19` 当日完成首轮处置:
|
||||
|
||||
1. 已从版本库删除以下根目录历史扫描/截图产物:
|
||||
- `npc-editor-dom.html`
|
||||
- `npc-editor-shot.png`
|
||||
- `temp-write-check.txt`
|
||||
- `tmp_character_presets_scan.txt`
|
||||
- `tmp_jsx_text_scan.txt`
|
||||
- `tmp_runtime_text_scan.txt`
|
||||
- `tmp_text_candidates.txt`
|
||||
- `tmp_text_candidates_refined.txt`
|
||||
- `tmp_visible_props_scan.txt`
|
||||
- `tmp_volc_seedance_doc.html`
|
||||
2. 已从版本库删除 `scripts/__pycache__/generate-build-tag-similarity.cpython-313.pyc`。
|
||||
3. 已清理本地工作区中的 `.codex-*.log`、`.preview.*`、`npc-editor-console.log` 与 `temp-build-goal-check/`,清理前对应体量约为:
|
||||
- 根目录噪音文件 `60` 个,约 `49.94 MB`
|
||||
- `temp-build-goal-check/` 共 `15620` 个条目,约 `158.85 MB`
|
||||
4. 已补齐 `.gitignore`、`.prettierignore` 与 `.eslintrc.cjs` 的忽略口径,显式覆盖 `tmp_*`、`tmp/`、`npc-editor-*`、`temp-write-check.txt`、`temp-build-goal-check/`、`__pycache__/`。
|
||||
5. `scripts/dev-server/localApiPlugins.ts` 之外的后端边界收口项不在本轮噪音清理范围内,后续继续按本文第二至第四阶段推进。
|
||||
|
||||
## 0.3 执行回填(2026-04-19,运行时边界第一轮收口)
|
||||
|
||||
本文审计项 `4.1` 与 `5.1` 已于 `2026-04-19` 当日完成一轮工程收口:
|
||||
|
||||
1. `RuntimeStoryOptionView` 现在由后端直接附带 `interaction` 元数据。
|
||||
2. `server-node/src/modules/story/runtimeSession.ts` 已成为 runtime option interaction 的唯一构建位置。
|
||||
3. `src/services/runtimeStoryService.ts` 不再根据 `currentEncounter + functionId` 在前端本地重建一份 interaction 映射。
|
||||
4. `/api/custom-world/scene-image` 已补齐服务端 prompt 兜底组装能力,允许前端只提交 `profile + landmark + userPrompt` 上下文。
|
||||
5. `src/services/aiService.ts` 的场景图 SDK 已改为直接调用后端接口,不再为了该链路动态加载 `src/services/ai.ts`。
|
||||
|
||||
## 0.4 执行回填(2026-04-19,自定义世界后端边界第二轮收口)
|
||||
|
||||
本文审计项 `5.2` 与“第三阶段第 4 条:清理 `server-node -> src/**` 的反向依赖”已于 `2026-04-19` 当日完成第二轮工程收口:
|
||||
|
||||
1. `server-node/src/modules/custom-world/` 已新增服务端自持 runtime 模块,承接:
|
||||
- `creator intent` 归一化
|
||||
- `anchorPack / lockState` 推导
|
||||
- custom world framework/profile compile 与 normalize
|
||||
2. `server-node/src/modules/ai/customWorldOrchestrator.ts` 与 `server-node/src/services/customWorldAgentFoundationDraftService.ts` 已不再运行时依赖:
|
||||
- `src/services/customWorld.js`
|
||||
- `src/services/customWorldBuilder.js`
|
||||
- `src/services/customWorldCreatorIntent.js`
|
||||
- `src/types.js`
|
||||
3. `server-node/src/prompts/customWorldPrompts.ts` 已成为后端自持的 custom world prompt source,`scene image` 与 `foundation draft` 相关 builder 不再从前端 `src/prompts/customWorldPrompts.ts` 反向 import。
|
||||
4. 本轮只迁移 prompt source 位置,没有改动任何 custom world 提示词正文,也没有改动功能需求。
|
||||
|
||||
## 0.5 执行回填(2026-04-20,NPC 待接委托正式接取收口)
|
||||
|
||||
本文审计项 `5.3` 已于 `2026-04-20` 完成一轮补充收口:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts` 中“聊天里的待接委托正式接取”已不再由前端本地直接写入:
|
||||
- `quests`
|
||||
- `runtimeStats.questsAccepted`
|
||||
- `npcChatState.pendingQuestOffer`
|
||||
2. `server-node/src/modules/quest/questStoryActionService.ts` 现在会优先读取服务端快照里已保存的 `pendingQuestOffer.quest`,按当前聊天态中已经展示给玩家的那份委托完成正式接取。
|
||||
3. `server-node/src/modules/story/storyActionService.ts` 已补齐待接委托接取后的聊天态投影:
|
||||
- 保留 NPC 对话展示模式
|
||||
- 清空 `pendingQuestOffer`
|
||||
- 回到既有的三条自由追问建议
|
||||
4. 本轮没有新增任何 runtime functionId,也没有改动任务生成提示词或任务需求,只是把既有“接任务”正式结算权收回到后端。
|
||||
|
||||
## 0.6 执行回填(2026-04-20,NPC 聊天任务草案与浏览器 LLM fallback 收口)
|
||||
|
||||
本文审计项 `5.1` 与 `5.3` 已于 `2026-04-20` 完成一轮补充收口:
|
||||
|
||||
1. `server-node/src/modules/ai/chatOrchestrator.ts` 现在会基于 `NPC chat turn` 的运行时上下文,在后端判断是否触发 `pendingQuestOffer`,并把 quest draft 与引导文案一并回填给前端。
|
||||
2. `src/hooks/story/npcEncounterActions.ts` 不再在 NPC 单轮聊天完成后本地调用 `generateQuestForNpcEncounter(...)` 再决定是否挂出待接委托。
|
||||
3. `src/services/questDirector.ts` 浏览器端在后端失败时不再退回本地 LLM 生成 quest draft,而是直接走 deterministic fallback compile。
|
||||
4. `src/services/runtimeItemAiDirector.ts` 浏览器端在后端失败时不再退回本地 LLM 生成 runtime item intent,而是直接返回 deterministic fallback intents。
|
||||
5. 本轮仍未改动任何业务提示词正文,也没有改动 quest / runtime item 的需求能力面,只是继续清理浏览器里的正式 AI orchestration 残留。
|
||||
|
||||
## 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/README.md`
|
||||
- `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.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/README.md`
|
||||
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
3. `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 插件入口的扫描结果
|
||||
@@ -0,0 +1,382 @@
|
||||
# 工程清理与后端边界复核审计(2026-04-20)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
这份文档不是重复 `2026-04-19` 的原始扫描,而是基于当前仓库状态做一轮复核,重点回答三个问题:
|
||||
|
||||
1. 昨天审计里已经提出的问题,哪些今天已经真正落地。
|
||||
2. 哪些结论在当前代码里仍然成立,哪些表述需要纠正。
|
||||
3. 当前工程热点和边界问题有没有发生迁移。
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
和 `2026-04-19` 那份基线相比,当前仓库已经有一批明确进展:
|
||||
|
||||
1. **旧 Vite 本地 API 链路已经真正出清。**
|
||||
`scripts/dev-server/` 当前只剩一份 `README.md`,旧的 `localApiPlugins.ts`、角色资产插件、精灵表插件都不在仓库里了。
|
||||
2. **根目录噪音产物已经清理完成。**
|
||||
当前根目录临时日志/扫描产物扫描结果为空,`temp-build-goal-check/` 也不存在。
|
||||
3. **`server-node -> src/**` 反向依赖已经收掉。**
|
||||
当前复核没有再发现 `server-node/src/**` 直接 import 前端 `src/**` 的情况。
|
||||
4. **runtime option interaction 已经收口成后端单一真相。**
|
||||
这部分现在由 `server-node/src/modules/story/runtimeSession.ts` 统一构造,前端 `src/services/runtimeStoryService.ts` 不再本地再建一份映射表。
|
||||
|
||||
但这不代表边界问题已经结束,当前剩余问题主要集中在三块:
|
||||
|
||||
1. **前端仍保留运行时镜像与登录凭证本地真相。**
|
||||
`runtimeStoryCoordinator.ts` 仍会先写本地快照,`apiClient.ts` 仍把 token/自动登录凭证放在 `localStorage`。
|
||||
2. **NPC 聊天任务链路还没有完全后端化。**
|
||||
“聊天后挂出待接委托”已经移到后端,但“更换待接委托”这条分支仍由前端 `npcEncounterActions.ts` 触发 `generateQuestForNpcEncounter(...)`。
|
||||
3. **未接线孤岛和热点文件问题仍然明显。**
|
||||
一批 UI/Hook/Prompt 残留模块还没有正式入口;同时热点已经从已删除的旧插件链路,转移到 `CustomWorldEntityEditorModal.tsx`、`storyPromptBuilders.ts`、`runtimeProfile.ts`、`PreGameSelectionFlow.tsx`、`PlatformHomeView.tsx` 等新中心。
|
||||
|
||||
一句话判断:
|
||||
|
||||
**当前仓库已经完成“清垃圾、拆旧入口、切断后端反向依赖”的第一阶段,但还没有完成“前端退出运行时真相”和“未接线孤岛归档”的第二阶段。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 已完成项复核
|
||||
|
||||
## 2.1 旧 dev-server 链路已经不是“逻辑上废弃”,而是“代码上删除”
|
||||
|
||||
### 当前证据
|
||||
|
||||
| 项目 | 当前状态 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| `scripts/dev-server/` | 当前只剩 `README.md` 一份说明文件 | 旧 Vite 本地 API 链路已从仓库代码层出清 |
|
||||
| `scripts/dev-server/README.md` | 已明确声明当前正式入口为 `scripts/dev-node.mjs + server-node/src/modules/**` | 文档与代码状态一致 |
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档里关于旧本地 API 插件链路的清理结论,在当前仓库里已经可以确认成立,不再只是“计划删除”。
|
||||
|
||||
---
|
||||
|
||||
## 2.2 根目录噪音产物已经从当前工作区移除
|
||||
|
||||
### 当前证据
|
||||
|
||||
| 项目 | 当前状态 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| 根目录历史日志/扫描产物 | 本轮扫描结果为空 | 之前的 `.codex-*.log`、`tmp_*`、旧截图/HTML 不再占据当前工作区 |
|
||||
| `temp-build-goal-check/` | 当前不存在 | 大体量检查产物已移出当前仓库视野 |
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档中关于“仓库噪音产物”的问题,在当前工作区层面已经完成首轮治理。
|
||||
这部分不再是当前工程第一优先级。
|
||||
|
||||
---
|
||||
|
||||
## 2.3 `server-node -> src/**` 反向依赖已清零
|
||||
|
||||
### 当前证据
|
||||
|
||||
本轮用脚本复核 `server-node/src/**` 中所有 `import` 后,当前结果为:
|
||||
|
||||
`NO_DIRECT_SERVER_TO_FRONTEND_SRC_IMPORTS`
|
||||
|
||||
同时,仓库里已经看不到类似下面这类旧反向依赖:
|
||||
|
||||
1. `server-node -> src/services/customWorld.js`
|
||||
2. `server-node -> src/services/customWorldBuilder.js`
|
||||
3. `server-node -> src/services/customWorldCreatorIntent.js`
|
||||
4. `server-node -> src/types.js`
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档里“清理 `server-node -> src/**` 反向依赖”的阶段性目标,在当前仓库里已经真正落地。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 runtime option interaction 已经收口到后端
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `server-node/src/modules/story/runtimeSession.ts` 当前仍保留 `buildOptionInteraction(...)`,负责构造:
|
||||
- `npcActionMap`
|
||||
- `treasureActionMap`
|
||||
2. `src/services/runtimeStoryService.ts` 当前只做:
|
||||
- 直接读取 `option.interaction`
|
||||
- 把后端返回的 interaction 投影成 `StoryOption`
|
||||
3. 前端文件里已经找不到旧的 `buildRuntimeOptionInteraction` / `npcActionMap` / `treasureActionMap` 实现。
|
||||
|
||||
### 结论
|
||||
|
||||
这项收口已经成立,当前不会再出现“前后端各维护一份 interaction 映射表”的旧问题。
|
||||
|
||||
---
|
||||
|
||||
## 2.5 浏览器端的 quest/runtime item 本地 LLM fallback 已移除
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
- 浏览器路径先请求 `/api/runtime/quests/generate`
|
||||
- 后端失败时只走 deterministic fallback compile
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
- 浏览器路径先请求 `/api/runtime/items/runtime-intent`
|
||||
- 后端失败时只返回 deterministic fallback intents
|
||||
3. 这两个文件虽然仍保留 `requestChatMessageContent(...)` 分支,但那是非浏览器分支,不再是浏览器端正式兜底链路。
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档里关于“浏览器本地 LLM fallback”这部分,当前应更新为:
|
||||
|
||||
**浏览器端本地 LLM fallback 已移除,但这两个模块仍然是双环境混合实现,还没有彻底后端化。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 需要纠正的旧文档表述
|
||||
|
||||
## 3.1 NPC 任务链路不是“全部后端化”,而是“挂单已后移、换单仍前触发”
|
||||
|
||||
### 需要纠正的点
|
||||
|
||||
`2026-04-19` 文档中的回填里有一条表述是:
|
||||
|
||||
“`src/hooks/story/npcEncounterActions.ts` 不再在 NPC 单轮聊天完成后本地调用 `generateQuestForNpcEncounter(...)` 再决定是否挂出待接委托。”
|
||||
|
||||
### 当前代码状态
|
||||
|
||||
这句话对“聊天后挂出待接委托”这条主链是成立的,因为当前后端 `server-node/src/modules/ai/chatOrchestrator.ts` 已经会回填 `pendingQuestOffer`。
|
||||
|
||||
但它对整条 NPC 任务链路来说并不完整,因为当前前端仍保留这条分支:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts`
|
||||
2. `replacePendingNpcQuestOffer()`
|
||||
3. `generateQuestForNpcEncounter(...)`
|
||||
|
||||
也就是:
|
||||
|
||||
**待接委托的“正式挂出”已后端化,但“更换委托”仍然由前端动作流发起。**
|
||||
|
||||
### 当前应改成的结论
|
||||
|
||||
更准确的描述应该是:
|
||||
|
||||
1. NPC 单轮聊天里“是否挂出待接委托”的决定权已收回后端。
|
||||
2. 但待接委托的“换单/重抽”分支仍通过前端 `npcEncounterActions.ts -> questDirector.ts` 发起。
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前仍然成立的遗留问题
|
||||
|
||||
## 4.1 未接线/仅测试引用孤岛模块仍然明显
|
||||
|
||||
本轮依赖图复核后,当前仍能确认一批高置信度孤岛模块:
|
||||
|
||||
| 模块 | 当前状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/GameShell.tsx` | `765` 行,无运行时引用 | 旧版壳层残留仍在 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationHub.tsx` | `161` 行,仅测试引用 | UI 已有完成度,但仍未进入正式入口 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | `147` 行,无运行时引用 | 未接线入口壳层 |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx` | `91` 行,无运行时引用 | agent UI 孤岛仍在 |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx` | `116` 行,无运行时引用 | agent UI 孤岛仍在 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | `250` 行,无运行时引用 | 旧 bootstrap hook 仍未归档 |
|
||||
| `src/hooks/useEquipmentFlow.ts` | `134` 行,无运行时引用 | 旧 flow hook 残留 |
|
||||
| `src/hooks/useForgeFlow.ts` | `159` 行,无运行时引用 | 旧 flow hook 残留 |
|
||||
| `src/hooks/useInventoryFlow.ts` | `100` 行,无运行时引用 | 旧 flow hook 残留 |
|
||||
| `src/services/customWorldPresentation.stub.ts` | `55` 行,无运行时引用 | 占位 stub 仍在 |
|
||||
| `src/services/typewriter.ts` | `7` 行,无运行时引用 | 小型 helper 残留 |
|
||||
| `src/prompts/customWorldOrchestratorPrompts.ts` | `9` 行,无运行时引用 | prompt source 已迁走后留下的孤岛 |
|
||||
| `src/prompts/storyOrchestratorPrompts.ts` | `6` 行,无运行时引用 | prompt source 已迁走后留下的孤岛 |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | `823` 行,无运行时引用 | 生成产物未接入正式业务链路 |
|
||||
|
||||
### 说明
|
||||
|
||||
`src/data/itemOverrides.json`、`src/data/monsterOverrides.json` 这类文件虽然没有 import 引用,但会被脚本和 editor route 以路径消费,所以不计入垃圾判断。
|
||||
|
||||
### 结论
|
||||
|
||||
仓库已经完成“删旧插件”,但还没有完成“清未接线孤岛”。
|
||||
当前这批模块应该进入明确处置表:
|
||||
|
||||
1. 直接归档/删除
|
||||
2. 正式接回入口
|
||||
3. 改名/迁目录,标记为实验稿
|
||||
|
||||
---
|
||||
|
||||
## 4.2 前端仍保留运行时镜像真相
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
- 仍会在读状态和提交动作前先 `putSaveSnapshot(...)`
|
||||
- 仍会在响应后多次 `rehydrateSavedSnapshot(...)`
|
||||
2. `src/services/runtimeStoryService.ts`
|
||||
- 仍对响应快照做 `rehydrateSavedSnapshot(...)`
|
||||
|
||||
### 结论
|
||||
|
||||
当前运行时已经不是“前端主算”,但仍然是:
|
||||
|
||||
**前端先写一份本地镜像,再和后端会话互相回填。**
|
||||
|
||||
这说明前端还没有完全退出正式运行时状态解释层。
|
||||
|
||||
---
|
||||
|
||||
## 4.3 前端仍保留本地登录凭证真相
|
||||
|
||||
### 当前证据
|
||||
|
||||
`src/services/apiClient.ts` 当前仍把以下内容写入 `window.localStorage`:
|
||||
|
||||
1. `ACCESS_TOKEN_KEY`
|
||||
2. `AUTO_AUTH_USERNAME_KEY`
|
||||
3. `AUTO_AUTH_PASSWORD_KEY`
|
||||
|
||||
对应代码仍包括:
|
||||
|
||||
1. `window.localStorage.getItem(...)`
|
||||
2. `window.localStorage.setItem(...)`
|
||||
3. `window.localStorage.removeItem(...)`
|
||||
|
||||
### 结论
|
||||
|
||||
这一点和“前端只做表现、后端负责鉴权”的目标仍然不一致。
|
||||
尤其是自动登录用户名/密码继续存本地,风险和边界问题都还在。
|
||||
|
||||
---
|
||||
|
||||
## 4.4 quest/runtime item 仍是双环境混合实现
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
- 浏览器路径走 `requestJson('/api/runtime/quests/generate')`
|
||||
- 非浏览器路径仍有 `requestChatMessageContent(...)`
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
- 浏览器路径走 `requestJson('/api/runtime/items/runtime-intent')`
|
||||
- 非浏览器路径仍有 `requestChatMessageContent(...)`
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 当前仍 import `generateQuestForNpcEncounter`
|
||||
- `replacePendingNpcQuestOffer()` 仍会调用它
|
||||
|
||||
### 结论
|
||||
|
||||
浏览器兜底已经收掉,但模块职责仍然是混合的:
|
||||
|
||||
1. 同一个文件同时承担前端 SDK 和非浏览器编排逻辑
|
||||
2. NPC 换单动作仍由前端发起服务调用
|
||||
|
||||
这部分还不能算真正后端化完成。
|
||||
|
||||
---
|
||||
|
||||
## 4.5 `src/services/ai.ts` 仍然是浏览器端正式 AI orchestration 热点
|
||||
|
||||
### 当前证据
|
||||
|
||||
`src/services/ai.ts` 当前约 `2608` 行,仍直接使用:
|
||||
|
||||
1. `requestChatMessageContent`
|
||||
2. `requestPlainTextCompletion`
|
||||
3. `streamPlainTextCompletion`
|
||||
|
||||
### 结论
|
||||
|
||||
这说明浏览器侧的大型 AI orchestration 仍然没有真正退出主工程。
|
||||
虽然部分链路已经迁走,但整体边界还没有收完。
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前热点已经发生迁移
|
||||
|
||||
## 5.1 当前主要大文件快照
|
||||
|
||||
| 文件 | 当前行数 | 判断 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `4898` | 仍是前端最大热点 |
|
||||
| `server-node/src/modules/assets/characterAssetRoutes.ts` | `3181` | 仍是后端资产链路最大热点 |
|
||||
| `src/services/ai.ts` | `2608` | 浏览器 AI orchestration 热点仍在 |
|
||||
| `src/data/npcInteractions.ts` | `2409` | 仍是大型规则数据中心 |
|
||||
| `server-node/src/services/customWorldAgentFoundationDraftService.ts` | `1902` | custom world agent 后端热点上升 |
|
||||
| `src/prompts/storyPromptBuilders.ts` | `1882` | prompt source 已成为新的前端热点 |
|
||||
| `server-node/src/modules/custom-world/runtimeProfile.ts` | `1735` | custom world runtime 编译中心已转到后端 |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `1547` | 平台/入口流程热点上升 |
|
||||
| `src/components/game-shell/PlatformHomeView.tsx` | `1522` | 平台首页热点上升 |
|
||||
| `src/services/customWorld.ts` | `1489` | 仍然大,但已明显缩小 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `1434` | 仍然是前端 action 热点 |
|
||||
|
||||
---
|
||||
|
||||
## 5.2 热点变化判断
|
||||
|
||||
和 `2026-04-19` 相比,当前热点不是单纯“没变”,而是出现了明显迁移:
|
||||
|
||||
1. `characterAssetRoutes.ts` 从 `3579` 行降到 `3181` 行,说明资产路由已经有过一轮拆分,但仍然偏大。
|
||||
2. `src/services/customWorld.ts` 从 `2413` 行降到 `1489` 行,说明自定义世界规则已拆出一部分。
|
||||
3. `src/hooks/story/npcEncounterActions.ts` 从 `1623` 行降到 `1434` 行,说明 NPC 运行时逻辑也有收口。
|
||||
4. 新的复杂度中心开始转移到:
|
||||
- `src/prompts/storyPromptBuilders.ts`
|
||||
- `server-node/src/modules/custom-world/runtimeProfile.ts`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/components/game-shell/PlatformHomeView.tsx`
|
||||
|
||||
### 结论
|
||||
|
||||
当前问题已经不再是“原来的热点完全没动”,而是:
|
||||
|
||||
**部分旧热点正在缩小,但复杂度正在向 prompt source、custom world runtime profile、平台入口壳层继续迁移。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 最新建议执行顺序
|
||||
|
||||
### 第一阶段:先清理当前仍明确无入口的孤岛
|
||||
|
||||
1. 处理 `GameShell.tsx`
|
||||
2. 处理 `custom-world-home/*`
|
||||
3. 处理 `custom-world-agent/*`
|
||||
4. 处理 `storyBootstrap.ts`、`useEquipmentFlow.ts`、`useForgeFlow.ts`、`useInventoryFlow.ts`
|
||||
5. 处理已脱钩的 `src/prompts/*OrchestratorPrompts.ts`
|
||||
|
||||
### 第二阶段:再收运行时和鉴权真相
|
||||
|
||||
1. 收掉 `runtimeStoryCoordinator.ts` 的本地快照前置写入
|
||||
2. 收掉 `apiClient.ts` 中的自动登录用户名/密码本地持久化
|
||||
3. 优先把 token/session 统一到服务端鉴权边界
|
||||
|
||||
### 第三阶段:补完 NPC 任务链路的后端化
|
||||
|
||||
1. 把“更换待接委托”从 `npcEncounterActions.ts -> questDirector.ts` 继续迁到后端
|
||||
2. 把 `questDirector.ts` / `runtimeItemAiDirector.ts` 拆成明确的后端服务与前端 SDK 两层
|
||||
|
||||
### 第四阶段:最后拆新热点
|
||||
|
||||
1. `CustomWorldEntityEditorModal.tsx`
|
||||
2. `characterAssetRoutes.ts`
|
||||
3. `storyPromptBuilders.ts`
|
||||
4. `runtimeProfile.ts`
|
||||
5. `PreGameSelectionFlow.tsx`
|
||||
6. `PlatformHomeView.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 7. 本文依据
|
||||
|
||||
文档依据:
|
||||
|
||||
1. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md`
|
||||
2. `docs/audits/engineering/README.md`
|
||||
3. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
|
||||
当前仓库复核依据:
|
||||
|
||||
1. `scripts/dev-server/README.md`
|
||||
2. `server-node/src/modules/story/runtimeSession.ts`
|
||||
3. `src/services/runtimeStoryService.ts`
|
||||
4. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
5. `src/hooks/story/npcEncounterActions.ts`
|
||||
6. `src/services/questDirector.ts`
|
||||
7. `src/services/runtimeItemAiDirector.ts`
|
||||
8. `src/services/apiClient.ts`
|
||||
9. 当前依赖图扫描结果与当前大文件体量扫描结果
|
||||
@@ -0,0 +1,141 @@
|
||||
# 工程死分支清理执行记录 A(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
这份记录对应:
|
||||
|
||||
- `docs/planning/ENGINEERING_DEAD_CODE_AND_HIDDEN_BRANCH_CLEANUP_PLAN_2026-04-21.md`
|
||||
- 其中的 `P0 + 批次 A`
|
||||
|
||||
本批次只做一件事:
|
||||
|
||||
**先清理高置信度、低耦合、无正式入口的小型孤岛与残留壳子。**
|
||||
|
||||
这批对象有一个共同特征:
|
||||
|
||||
1. 当前没有正式运行时引用
|
||||
2. 没有当前主链计划要接回
|
||||
3. 删除后有明确替代路径,或者本身只是历史占位
|
||||
|
||||
因此这批次不碰运行时真相链、不碰鉴权链、不碰任务物品主链,只先做低风险去噪。
|
||||
|
||||
---
|
||||
|
||||
## 1. 本批次已处理对象
|
||||
|
||||
## 1.1 已删除文件
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 | 验证口径 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/customWorldPresentation.stub.ts` | 无引用占位 stub | 文件本身就是占位实现,且正式逻辑已由 `customWorldPresentation.ts` 承接 | `src/services/customWorldPresentation.ts` | 符号级检索确认正式调用方都指向正式实现 |
|
||||
| `src/services/typewriter.ts` | 无引用 helper 残留 | 独立 helper 已失效,正式链路已在 `storyPresentation.ts` / `storyRenderingHelpers.ts` 等处内联或迁移 | `src/hooks/story/storyPresentation.ts`、`src/hooks/story/storyRenderingHelpers.ts` | `getTypewriterDelay` 调用点未指向该文件 |
|
||||
| `src/prompts/customWorldOrchestratorPrompts.ts` | 前端孤岛 prompt 壳 | 当前无正式 import,正式主编排 prompt 已收口到后端 prompt 目录,前端 `ai.ts` 也保留自己的现行实现 | `server-node/src/prompts/customWorldOrchestratorPrompts.ts`、`src/services/ai.ts` | 全仓检索仅剩文档引用,无代码消费 |
|
||||
| `src/prompts/storyOrchestratorPrompts.ts` | 前端孤岛 prompt 壳 | 当前无正式 import,剧情语言修复 prompt 已由后端 prompt 目录承接,前端当前执行路径不依赖该文件 | `server-node/src/prompts/storyOrchestratorPrompts.ts`、`src/services/ai.ts` | 全仓检索仅剩文档引用,无代码消费 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | 无入口 UI 壳层 | 最近两轮工程审计都确认无运行时引用,当前平台主流程未接这条入口 | 当前平台正式入口链 | 文件级检索确认无组件 import |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx` | 无入口 UI 壳层 | Agent 创作主流程已切到当前工作区链路,这个旧 modal 没有接线价值 | 当前 Agent 工作区主链 | 文件级检索确认无组件 import |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx` | 无入口 UI 壳层 | 只有孤立 UI 实现,没有正式调用链,也不在当前结果页 / 工作区主链中 | 当前 Agent 工作区与结果页正式链 | 文件级检索确认无组件 import |
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次为什么先删这 7 个
|
||||
|
||||
这批文件适合先处理,不是因为它们最大,而是因为它们最清晰:
|
||||
|
||||
1. **没有正式入口。**
|
||||
本轮检索没有发现主工程 import。
|
||||
2. **删除后不会形成职责空洞。**
|
||||
要么已有正式替代路径,要么本身只是历史占位。
|
||||
3. **不会误伤当前重点链路。**
|
||||
这批不涉及运行时快照、鉴权、任务、物品、AI 正式编排主链。
|
||||
4. **可以最快降低目录噪音。**
|
||||
先把真假并存的壳子删掉,后面做批次 B/C/D 时判断成本会更低。
|
||||
|
||||
---
|
||||
|
||||
## 3. 本批次暂不处理对象
|
||||
|
||||
以下对象虽然已进入首轮台账,但本批次暂不删除:
|
||||
|
||||
1. `src/components/GameShell.tsx`
|
||||
2. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
3. `src/hooks/story/storyBootstrap.ts`
|
||||
4. `src/hooks/useEquipmentFlow.ts`
|
||||
5. `src/hooks/useForgeFlow.ts`
|
||||
6. `src/hooks/useInventoryFlow.ts`
|
||||
7. `src/data/buildTagSimilarity.generated.ts`
|
||||
|
||||
暂缓原因分别是:
|
||||
|
||||
1. 仍属于旧主流程 / 旧 flow 级别对象,删除前要先核对更多历史依赖和替代路径
|
||||
2. 部分对象仍有测试引用或更大的上下文耦合
|
||||
3. `buildTagSimilarity.generated.ts` 虽无正式业务 import,但属于生成产物,处理前还要确认脚本链与文档链
|
||||
|
||||
这批对象更适合进入:
|
||||
|
||||
1. `批次 B:旧 flow / 旧 shell / 旧 hook`
|
||||
2. 或独立的数据产物复核批次
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次同步更新的文档
|
||||
|
||||
本批次除了删文件,还同步做了文档回填:
|
||||
|
||||
1. 新增本执行记录,说明本批删了什么、为什么删、哪些对象暂缓
|
||||
2. 更新 `docs/audits/engineering/README.md`,把这份执行记录加入当前审计入口
|
||||
|
||||
这样做的目的,是避免再次出现:
|
||||
|
||||
1. 代码删了
|
||||
2. 但审计入口还是旧状态
|
||||
3. 后续开发又从旧清单里重复判断一遍
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证方式
|
||||
|
||||
本批次验证采用两层口径:
|
||||
|
||||
## 5.1 删除前验证
|
||||
|
||||
1. 文件级检索确认无正式 import
|
||||
2. 符号级检索确认关键导出没有被主链消费
|
||||
3. 结合 `2026-04-20` 工程审计交叉确认这些对象已被标记为高置信度孤岛
|
||||
|
||||
## 5.2 删除后验证
|
||||
|
||||
建议至少执行:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run build`
|
||||
|
||||
说明:
|
||||
|
||||
- 当前仓库已知 `typecheck` 与 `lint` 仍处于红线阶段,因此本批不把它们作为“由本批引入的新失败”判断口径
|
||||
- 本批主要验证目标是:删除小残留后,不产生新的导入断裂和构建断裂
|
||||
|
||||
---
|
||||
|
||||
## 6. 本批次结果判断
|
||||
|
||||
本批次完成后,工程至少获得了 3 个直接收益:
|
||||
|
||||
1. `src/prompts/`、`src/services/`、`src/components/custom-world-*` 中少了一批无入口孤岛
|
||||
2. 当前目录里“看起来像正式入口,其实已经废弃”的误导性对象减少
|
||||
3. 后续可以把精力集中到真正高价值的批次 B/C/D,而不是继续被小残留分散判断成本
|
||||
|
||||
---
|
||||
|
||||
## 7. 下一批建议
|
||||
|
||||
建议严格按计划继续往下推进:
|
||||
|
||||
1. 批次 B:`GameShell`、`storyBootstrap`、`useEquipmentFlow`、`useForgeFlow`、`useInventoryFlow`
|
||||
2. 批次 C:`runtimeStoryCoordinator`、`runtimeStoryService`、`apiClient`
|
||||
3. 批次 D:`npcEncounterActions`、`questDirector`、`runtimeItemAiDirector`、`ai.ts`
|
||||
|
||||
一句话总结本批次:
|
||||
|
||||
**先把最确定的死分支和占位壳子清掉,让主工程少一些假入口、假主源、假能力,再进入更重的主链收口。**
|
||||
@@ -0,0 +1,145 @@
|
||||
# 工程死分支清理执行记录 B(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
这份记录对应清洗计划中的:
|
||||
|
||||
- `批次 B:旧 flow / 旧 shell / 旧 hook`
|
||||
|
||||
本批次聚焦的不是小型 stub,而是:
|
||||
|
||||
**已经退出正式主流程、但仍占着高辨识度命名和旧职责心智的壳层与流程 Hook。**
|
||||
|
||||
这类文件如果继续留在仓库里,问题比小 helper 更大,因为它们会持续制造误判:
|
||||
|
||||
1. 新人会以为它们还是正式入口
|
||||
2. 后续开发会误判“应该往这里接逻辑”
|
||||
3. review 时会多出一层“旧主链是不是还活着”的判断成本
|
||||
|
||||
---
|
||||
|
||||
## 1. 本批次已处理对象
|
||||
|
||||
## 1.1 已删除文件
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 | 验证口径 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/GameShell.tsx` | 旧主流程壳层残留 | 当前正式壳层已由 `src/components/game-shell/GameShellRuntime.tsx` 承接,旧文件无正式 import | `src/components/game-shell/GameShellRuntime.tsx`、`src/hooks/useGameShellRuntime.ts` | 全仓检索未发现对旧 `GameShell` 组件的正式消费 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | 旧启动流程 Hook 残留 | 当前主剧情启动链已不再调用该 Hook,继续保留只会误导人以为它还是故事初始化入口 | 当前 story runtime / coordinator 链 | 全仓检索未发现 `useStoryBootstrap` 消费方 |
|
||||
| `src/hooks/useEquipmentFlow.ts` | 旧装备流程 Hook 残留 | 当前正式背包与装备链未消费该 Hook,属于旧流程实现残留 | 当前 inventory / runtime 正式链 | 符号级检索仅命中定义文件自身 |
|
||||
| `src/hooks/useForgeFlow.ts` | 旧锻造流程 Hook 残留 | 当前正式锻造入口未通过该 Hook 进入主链,保留会制造旧流程错觉 | 当前 inventory / runtime 正式链 | 符号级检索仅命中定义文件自身 |
|
||||
| `src/hooks/useInventoryFlow.ts` | 旧背包使用流程 Hook 残留 | 当前主流程未消费该 Hook,属于旧状态推进实现残留 | 当前 inventory / runtime 正式链 | 符号级检索仅命中定义文件自身 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 为什么这批要紧跟批次 A 处理
|
||||
|
||||
批次 A 清掉的是“小型假入口”。
|
||||
|
||||
批次 B 清掉的是“高辨识度旧主链”。
|
||||
|
||||
这批必须紧跟着做,原因是:
|
||||
|
||||
1. 它们虽然比 stub 更大,但引用关系同样清楚
|
||||
2. 它们的误导性比小残留更强
|
||||
3. 不先处理这批,后面做批次 C/D 时,很容易继续有人拿旧 flow Hook 当候选接线点
|
||||
|
||||
一句话讲:
|
||||
|
||||
**批次 A 是去噪,批次 B 是拔掉旧路牌。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 本批次删除后的结构变化
|
||||
|
||||
本批次完成后,仓库里的流程心智会更清楚:
|
||||
|
||||
1. 游戏壳层正式入口继续收敛到 `src/components/game-shell/**`
|
||||
2. 旧 `GameShell.tsx` 不再和 `GameShellRuntime.tsx` 并存
|
||||
3. 旧的装备 / 锻造 / 背包单独 flow Hook 不再伪装成还在生效的正式实现
|
||||
4. 旧 `storyBootstrap` 不再和当前 story runtime 链并存
|
||||
|
||||
这会直接减少两类误判:
|
||||
|
||||
1. “是不是还有旧主流程没迁完”
|
||||
2. “我是不是应该把新逻辑继续补进这些旧 Hook”
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次暂不处理对象
|
||||
|
||||
虽然批次 B 已经处理了旧 shell / old flow / old bootstrap,但以下对象仍暂缓:
|
||||
|
||||
1. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
2. `src/data/buildTagSimilarity.generated.ts`
|
||||
3. 批次 C 的运行时真相链:
|
||||
- `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
- `src/services/runtimeStoryService.ts`
|
||||
- `src/services/apiClient.ts`
|
||||
4. 批次 D 的混合执行层:
|
||||
- `src/hooks/story/npcEncounterActions.ts`
|
||||
- `src/services/questDirector.ts`
|
||||
- `src/services/runtimeItemAiDirector.ts`
|
||||
- `src/services/ai.ts`
|
||||
|
||||
暂缓原因很明确:
|
||||
|
||||
1. 这些对象要么仍在当前正式链上
|
||||
2. 要么涉及运行时真相与鉴权边界
|
||||
3. 不能按“无引用旧壳”同一口径直接删除
|
||||
|
||||
---
|
||||
|
||||
## 5. 本批次验证方式
|
||||
|
||||
## 5.1 删除前验证
|
||||
|
||||
1. 全仓检索 `GameShell` 旧组件消费方,确认当前正式壳层已切到 `game-shell/` 目录
|
||||
2. 全仓检索 `useStoryBootstrap`
|
||||
3. 全仓检索旧装备 / 锻造 / 背包 flow Hook 导出的 handler 名称
|
||||
4. 交叉确认当前正式主链入口已存在替代实现
|
||||
|
||||
## 5.2 删除后验证
|
||||
|
||||
建议至少执行:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run build`
|
||||
|
||||
如果这两项通过,说明:
|
||||
|
||||
1. 删除没有引入新的导入断裂
|
||||
2. 主工程构建链仍然成立
|
||||
|
||||
---
|
||||
|
||||
## 6. 本批次结果判断
|
||||
|
||||
本批次完成后,工程获得的直接收益是:
|
||||
|
||||
1. 旧主流程壳层不再和现行壳层并存
|
||||
2. 旧流程 Hook 不再占据 `src/hooks/` 的主路径注意力
|
||||
3. 当前正式入口和历史残留的边界更清楚
|
||||
4. 后续开发更不容易把新逻辑接回旧流程壳子
|
||||
|
||||
---
|
||||
|
||||
## 7. 下一批建议
|
||||
|
||||
建议下一步进入真正有结构价值的收口:
|
||||
|
||||
1. `批次 C:运行时真相收口`
|
||||
- `runtimeStoryCoordinator`
|
||||
- `runtimeStoryService`
|
||||
- `apiClient`
|
||||
2. `批次 D:任务 / 物品 / AI 混合执行层收口`
|
||||
- `npcEncounterActions`
|
||||
- `questDirector`
|
||||
- `runtimeItemAiDirector`
|
||||
- `ai.ts`
|
||||
|
||||
一句话总结本批次:
|
||||
|
||||
**这一步不是在“删几个没用 Hook”,而是在把已经退场的旧主流程壳层和旧 flow 路牌从主工程里真正拔掉,让现行架构不再和历史壳子并排站着。**
|
||||
@@ -0,0 +1,241 @@
|
||||
# 工程死分支清理执行记录 C(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
这份记录对应清洗计划中的:
|
||||
|
||||
- `批次 C:运行时真相收口`
|
||||
|
||||
但这次不是“一口气把运行时真相链全删干净”,而是先做其中最明确、风险最低、最不该继续拖的那一段:
|
||||
|
||||
1. **收掉前端本地自动登录用户名 / 密码真相**
|
||||
2. **把登录恢复改成优先依赖服务端 session / refresh**
|
||||
|
||||
同时,这一批也明确记录了一件事:
|
||||
|
||||
**运行时快照前置写入链当前还不能直接砍。**
|
||||
|
||||
原因不是“不想动”,而是服务端当前 `runtime story` 动作入口仍然以远端快照作为执行基线。
|
||||
在后端 contract 没先改好之前,前端不能假装自己已经退出这条链。
|
||||
|
||||
---
|
||||
|
||||
## 1. 本批次已处理对象
|
||||
|
||||
## 1.1 已收口的鉴权链
|
||||
|
||||
| 文件 | 处理动作 | 本批结论 |
|
||||
| --- | --- | --- |
|
||||
| `src/services/apiClient.ts` | 删除本地自动登录用户名 / 密码存取逻辑 | 前端不再保存 auto auth 账号密码 |
|
||||
| `src/services/authService.ts` | 去掉对本地游客凭证的读写依赖 | 自动游客登录改为仅本次生成凭证,不再长期落本地 |
|
||||
| `src/components/auth/AuthGate.tsx` | 去掉“必须先有本地 access token 才尝试恢复”的前置假设 | 登录恢复改为优先尝试服务端 `getCurrentAuthUser()` / refresh session |
|
||||
| `src/services/authService.test.ts` | 改写游客自动登录相关断言 | 验证改为“生成临时凭证并完成登录”,而不是“落本地账号密码” |
|
||||
| `src/components/auth/AuthGate.test.tsx` | 改写登录恢复 mock | 验证改为“先尝试服务端会话恢复,再决定是否走游客兜底” |
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次为什么先做这段
|
||||
|
||||
这批优先级高,是因为它同时满足 4 条:
|
||||
|
||||
1. **风险明确。**
|
||||
浏览器保存自动登录用户名 / 密码,本身就不符合“前端只做表现、后端负责鉴权真相”的方向。
|
||||
2. **替代路径已经存在。**
|
||||
后端已经有 refresh session cookie 与 `getCurrentAuthUser()`,不是没有可替代能力。
|
||||
3. **改动边界清楚。**
|
||||
这一段主要落在前端鉴权恢复逻辑和测试,不会直接波及运行时战斗、任务、物品、剧情主链。
|
||||
4. **收益直接。**
|
||||
一旦收掉,前端就少了一份最不该长期保留的高风险真相。
|
||||
|
||||
一句话讲:
|
||||
|
||||
**这一步先把“浏览器记住游客账号密码再重登”这条假真相链拔掉。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 本批次明确没做的事
|
||||
|
||||
## 3.1 没有直接删除 `runtimeStoryCoordinator.ts` 里的前置 `putSaveSnapshot(...)`
|
||||
|
||||
这不是漏做,而是明确暂缓。
|
||||
|
||||
当前复核结果是:
|
||||
|
||||
1. `server-node/src/modules/story/storyActionService.ts`
|
||||
2. `server-node/src/routes/runtimeRoutes.ts`
|
||||
3. `server-node/src/repositories/runtimeRepository.ts`
|
||||
|
||||
这条后端链当前仍然通过远端快照读取运行时状态,再执行:
|
||||
|
||||
1. `getRuntimeStoryState`
|
||||
2. `resolveRuntimeStoryAction`
|
||||
|
||||
也就是说,当前真实情况不是“前端多写了一份完全没用的镜像”,而是:
|
||||
|
||||
**前端在提交动作前先把当前状态写回远端快照,后端再基于这份快照执行业务动作。**
|
||||
|
||||
在这个 contract 没先升级为“前端只发 action,后端自己持有完整 session 真相”之前,前端不能直接把这一步砍掉。
|
||||
|
||||
否则会出现:
|
||||
|
||||
1. 动作请求仍在走
|
||||
2. 但服务端读取到的执行基线不完整
|
||||
3. 最后不是收口真相,而是把主链打断
|
||||
|
||||
## 3.2 没有删除 `runtimeStoryService.ts` / `runtimeStoryCoordinator.ts` 的快照再水合逻辑
|
||||
|
||||
这一步本轮也做了复核,结论是:
|
||||
|
||||
1. 我曾尝试把 `runtimeStoryCoordinator.ts` 中对服务端返回快照的重复再水合去掉
|
||||
2. 但对应的 `runtimeStoryCoordinator` 测试立即暴露出:当前后端返回的快照在部分战斗场景下还不是完整水合态
|
||||
3. 说明前端当前这层再水合仍然有现实职责,不是纯多余代码
|
||||
|
||||
所以这一步本批明确结论是:
|
||||
|
||||
**暂不删除,等后端快照 contract 先补完整后再做。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次验证结果
|
||||
|
||||
本批次已完成的定向验证:
|
||||
|
||||
1. `npx vitest run src/services/authService.test.ts`
|
||||
2. `npx vitest run src/components/auth/AuthGate.test.tsx`
|
||||
3. `npx vitest run src/hooks/story/runtimeStoryCoordinator.test.ts`
|
||||
4. `npm run check:encoding`
|
||||
|
||||
结果:
|
||||
|
||||
1. `authService` 测试通过
|
||||
2. `AuthGate` 测试通过
|
||||
3. `runtimeStoryCoordinator` 测试通过
|
||||
4. 编码检查通过
|
||||
|
||||
另外执行了:
|
||||
|
||||
1. `npm run build`
|
||||
|
||||
结果:
|
||||
|
||||
构建产物生成成功,但 `build-gate` 仍因主包 chunk warning 拦截失败。
|
||||
当前失败点仍是已知的主包体积问题:
|
||||
|
||||
- `AuthenticatedApp-*.js` 超过当前 warning 门槛
|
||||
|
||||
这属于仓库当前既有工程问题,不是本批次引入的新断裂。
|
||||
|
||||
## 4.1 2026-04-21 补充修正:会话探测 401 自触发循环
|
||||
|
||||
在这批收口完成后,前端又暴露出一条更细的鉴权恢复回路问题:
|
||||
|
||||
1. `AuthGate` 启动时会调用 `getCurrentAuthUser()` 探测现有会话
|
||||
2. `/api/auth/me` 返回 `401` 时,`apiClient.ts` 会默认广播一次 `AUTH_STATE_EVENT`
|
||||
3. `AuthGate` 自己又监听这个事件并重新 `hydrate()`
|
||||
4. 最终形成 `hydrate -> /auth/me 401 -> emit -> hydrate` 的自触发循环
|
||||
|
||||
这条链的问题不在“是否允许 401”,而在:
|
||||
|
||||
**会话探测请求把“未登录态探测”错误地当成了“全局登录态变更”。**
|
||||
|
||||
因此这里补了一条更细粒度的约束:
|
||||
|
||||
1. `apiClient.ts` 新增 `notifyAuthStateChange` 选项,默认仍保持原有广播行为
|
||||
2. `getCurrentAuthUser()` 作为会话探测请求,显式关闭这类 401 广播
|
||||
3. 真实登录、登出、刷新成功后,仍保留全局鉴权变更通知
|
||||
|
||||
这样修完后:
|
||||
|
||||
1. `AuthGate` 仍会优先尝试服务端会话恢复
|
||||
2. 无会话时会正常落回未登录分支
|
||||
3. 不会因为探测型 401 把自己重新唤醒并刷爆控制台
|
||||
|
||||
## 4.2 2026-04-22 补充修正:公开认证入口误触发 refresh
|
||||
|
||||
在登录弹窗链路继续联调时,又暴露出一条更细的请求边界问题:
|
||||
|
||||
1. 用户处于未登录态,浏览器本地没有 access token
|
||||
2. 点击“获取验证码”会调用 `sendPhoneLoginCode()`
|
||||
3. `authService.ts` 复用了通用 `requestJson(...)`
|
||||
4. `apiClient.ts` 在“无本地 token 且未显式关闭 refresh”时,会先尝试 `POST /api/auth/refresh`
|
||||
5. 若当前浏览器本来也没有 refresh session cookie,就会先打出一条 `401 Unauthorized`
|
||||
6. 最终表现成:验证码接口真正发送前,前端控制台先报一次 `/api/auth/refresh 401`
|
||||
|
||||
这条链的问题不在“验证码接口失败”,而在:
|
||||
|
||||
**登录前公开认证入口被错误当成了需要先补票的受保护请求。**
|
||||
|
||||
因此这里再补一条明确约束:
|
||||
|
||||
1. `sendPhoneLoginCode()`
|
||||
2. `loginWithPhoneCode()`
|
||||
3. `authEntry()`
|
||||
4. `getAuthLoginOptions()`
|
||||
5. `startWechatLogin()`
|
||||
|
||||
以上这些“获取登录态之前”的公开认证入口,统一显式传入:
|
||||
|
||||
1. `skipAuth: true`
|
||||
2. `skipRefresh: true`
|
||||
|
||||
这样修完后:
|
||||
|
||||
1. 未登录用户点击“获取验证码”不会先打 `/api/auth/refresh`
|
||||
2. 公开认证入口不会误带旧 token,也不会制造无意义的 401 噪音
|
||||
3. 真正需要 refresh 的仍然只有已拿到登录态后的受保护请求
|
||||
|
||||
本次补修的定向验证:
|
||||
|
||||
1. `npx vitest run src/services/authService.test.ts`
|
||||
2. `npm run check:encoding`
|
||||
|
||||
---
|
||||
|
||||
## 5. 本批次完成后的实际收益
|
||||
|
||||
这一步完成后,工程在鉴权边界上有了两个明确改善:
|
||||
|
||||
1. **前端不再保存自动登录用户名 / 密码。**
|
||||
浏览器只保留 access token,本地高风险游客凭证真相已经收掉。
|
||||
2. **登录恢复逻辑更接近服务端为真相源。**
|
||||
`AuthGate` 不再假设“没有本地 token 就一定还没登录”,而是优先尝试服务端会话恢复。
|
||||
|
||||
这意味着前端鉴权链已经从:
|
||||
|
||||
```text
|
||||
本地用户名/密码 -> 再次 entry -> 拿 token
|
||||
```
|
||||
|
||||
进一步收到了:
|
||||
|
||||
```text
|
||||
refresh session / 当前会话 -> 恢复用户
|
||||
兜底时才创建一次游客凭证
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 本批次后续建议
|
||||
|
||||
要继续完成批次 C,下一步不该直接在前端硬删,而应该先补后端 contract:
|
||||
|
||||
1. 让 `runtime story` 动作链逐步摆脱“前端先写远端快照”的依赖
|
||||
2. 让服务端自己持有更完整的运行时 session 真相
|
||||
3. 等后端返回快照已经稳定水合后,再删前端的重复再水合
|
||||
|
||||
换句话说,批次 C 的后半段应该拆成:
|
||||
|
||||
1. **C-1:鉴权真相收口**
|
||||
本批已完成
|
||||
2. **C-2:运行时快照 contract 后端化**
|
||||
需要先改后端
|
||||
3. **C-3:前端镜像写入与重复水合退场**
|
||||
依赖 C-2
|
||||
|
||||
---
|
||||
|
||||
## 7. 一句话总结
|
||||
|
||||
**批次 C 这一轮已经先把“浏览器长期保存游客账号密码”这条最不该存在的鉴权假真相链收掉了;而运行时快照前置写入这条链经过复核确认仍受后端 contract 约束,不能在服务端未先补齐前硬砍。**
|
||||
@@ -0,0 +1,56 @@
|
||||
# 工程死分支清理执行记录 D(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
本批次继续清理上一轮复核后剩余的低风险数据产物与测试占位:
|
||||
|
||||
1. 未接入业务的生成产物
|
||||
2. 只为测试替换真实实现的空 stub
|
||||
3. 支撑这些残留的配置与脚本
|
||||
|
||||
---
|
||||
|
||||
## 1. 已删除对象
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | 未接入业务的生成产物 | 运行时代码不 import;Build 相似度当前由 `buildTags.ts` 中的属性亲和度逻辑计算 | `src/data/buildTags.ts` |
|
||||
| `scripts/generate-build-tag-similarity.py` | 已无输出目标的生成脚本 | 只负责生成已删除的矩阵文件,继续保留会误导后续开发恢复旧主源 | `src/data/buildTags.ts` 的手工审表逻辑 |
|
||||
| `src/data/customWorldCharacterLoadout.stub.ts` | 测试专用空 stub | 只通过 `vitest.config.ts` alias 替换真实实现;真实实现已经稳定存在 | `src/data/customWorldCharacterLoadout.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 同步更新
|
||||
|
||||
本批次同步移除了:
|
||||
|
||||
1. `vitest.config.ts` 中指向 `customWorldCharacterLoadout.stub.ts` 的 alias
|
||||
2. `BUILD_SYSTEM_ATTRIBUTE_SIMILARITY_PRD_2026-04-02.md` 中把旧 generated 矩阵描述为当前文件的表述
|
||||
3. 清理计划里对 `buildTagSimilarity.generated.ts` 的未处理状态说明
|
||||
|
||||
---
|
||||
|
||||
## 3. 验证口径
|
||||
|
||||
删除前已确认:
|
||||
|
||||
1. `buildTagSimilarity.generated.ts` 无运行时代码引用
|
||||
2. `customWorldCharacterLoadout.stub.ts` 只被 `vitest.config.ts` alias 引用
|
||||
3. 真实 `customWorldCharacterLoadout.ts` 仍被 `characterPresets.ts` 与 `npcInteractions.ts` 使用,不能删除
|
||||
|
||||
删除后建议验证:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. 与自定义世界开局物品相关的测试
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前结论
|
||||
|
||||
本批次完成后,剩余清理对象已经不再适合按“无引用直接删”推进。后续如果继续清,需要先改 contract 或主链职责:
|
||||
|
||||
1. 运行时快照真相链
|
||||
2. 任务 / 物品 / AI 混合执行层
|
||||
3. 大型主流程组件继续拆分,而不是直接删除
|
||||
@@ -0,0 +1,117 @@
|
||||
# 工程死分支清理执行记录 E(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
本批次承接批次 D,继续清掉已经退出 RPG 游戏创作主流程、RPG 运行时玩法主流程、平台基本功能主流程的历史壳层。
|
||||
|
||||
本批次不处理仍需后端 contract 先收口的对象,例如:
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
3. `src/hooks/rpg-runtime-story/runtimeStoryCoordinator.ts`
|
||||
4. `src/services/apiClient.ts`
|
||||
|
||||
这些对象仍属于“前端越界逻辑继续后端化”的后续批次,不按无引用文件直接删除。
|
||||
|
||||
---
|
||||
|
||||
## 1. 删除判定口径
|
||||
|
||||
本批只删除满足下面条件之一的对象:
|
||||
|
||||
1. 无运行时入口、无脚本入口、无当前路由挂载。
|
||||
2. 已有现行正式实现,旧文件只剩 re-export / facade / 兼容命名。
|
||||
3. 只被测试验证旧壳自身,且该测试不再服务当前主流程门禁。
|
||||
4. 文档已明确该对象处于“后续只允许收缩、不再接新逻辑”的兼容残留状态。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次已处理对象
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 |
|
||||
| --- | --- | --- | --- |
|
||||
| `server-node/src/routes/rpgCreationAgentRoutes.ts` | 旧命名 re-export | 当前后端正式路由直接使用 `customWorldAgent.ts` | `server-node/src/routes/customWorldAgent.ts` |
|
||||
| `server-node/src/routes/rpgWorldGalleryRoutes.ts` | 空路由骨架 | 世界广场实际列表和详情已经进入世界库路由 | `server-node/src/routes/rpg-entry/rpgWorldLibraryRoutes.ts` |
|
||||
| `server-node/src/services/RpgAgentOrchestrator.ts` | 旧命名 re-export | 当前正式上下文直接使用 `CustomWorldAgentOrchestrator` | `server-node/src/services/customWorldAgentOrchestrator.ts` |
|
||||
| `server-node/src/services/RpgAgentSessionStore.ts` | 旧命名 re-export | 当前正式上下文直接使用 `CustomWorldAgentSessionStore` | `server-node/src/services/customWorldAgentSessionStore.ts` |
|
||||
| `server-node/src/services/customWorldWorkSummaryService.ts` | 旧兼容入口 | 测试和路由已改为直接使用 RPG 命名服务 | `server-node/src/services/RpgWorldWorkSummaryService.ts` |
|
||||
| `server-node/src/services/customWorldAgentPublishGateService.ts` | 旧发布门禁实现 | 当前 action executor 与作品库发布链已统一走 PublishingService | `server-node/src/services/customWorldAgentPublishingService.ts` |
|
||||
| `server-node/src/services/customWorldAgentPublishService.ts` | 旧发布实现 | 当前发布链不再编译旧 legacy result profile | `server-node/src/services/customWorldAgentPublishingService.ts` |
|
||||
| `server-node/src/modules/custom-world/runtime-profile/runtimeProfileCompiler.ts` | 旧 facade | runtime profile 已拆到目录模块并由 `index.ts` / `runtimeProfile.ts` 承接 | `server-node/src/modules/custom-world/runtime-profile/index.ts` |
|
||||
| `server-node/src/bridges/legacyBuildRuntimeBridge.ts` | 无引用旧桥 | 后端 runtime build / equipment 已直接在正式模块内使用 | `server-node/src/modules/runtime/**` |
|
||||
| `server-node/src/bridges/legacyRuntimeItemResolutionBridge.ts` | 旧桥 | runtime item 解析服务一并删除,正式运行时使用 `runtimeItemModule.ts` | `server-node/src/modules/runtime-item/runtimeItemModule.ts` |
|
||||
| `server-node/src/modules/runtime-item/runtimeItemResolutionService.ts` | 无正式入口 wrapper | 只被 barrel 和自身测试引用,未挂入 Express 运行时主链 | `server-node/src/modules/runtime-item/runtimeItemModule.ts` |
|
||||
| `server-node/src/modules/**/index.ts` | 无引用 barrel | 这些 barrel 没有被当前后端入口消费,反而制造“公共模块入口仍存在”的错觉 | 直接 import 具体正式模块 |
|
||||
| `server-node/src/routes/rpg-*/index.ts` | 无引用 barrel | 当前 Express app 直接 import 具体 route 文件 | `server-node/src/app.ts` 中的具体路由 |
|
||||
| `server-node/src/repositories/rpg-*/index.ts` | 无引用 barrel | 当前上下文直接 import 具体 repository | `server-node/src/server.ts` 中的具体仓储 |
|
||||
| `src/components/DeveloperTeamModal.tsx` | 无入口 UI | 平台主流程没有打开该弹窗的入口 | 无替代 UI,删除历史壳 |
|
||||
| `src/components/LazySkillEffectPreview.tsx` | 无入口 lazy 壳 | 正式技能预览直接使用 `SkillEffectPreview` | `src/components/SkillEffectPreview.tsx` |
|
||||
| `src/components/npcVisualEditorModel.ts` | 旧 NPC 形象写回模型 | 当前 RPG 创作编辑器使用 `CustomWorldNpcVisualEditor` 与结果页新入口 | `src/components/CustomWorldNpcVisualEditor.tsx`、`src/components/rpg-creation-editor/**` |
|
||||
| `src/components/npcVisualEditorPersistence.ts` | 旧 NPC 形象写回持久层 | 只被旧持久化测试引用,正式编辑入口已迁移 | `src/components/rpg-creation-editor/**` |
|
||||
| `src/components/rpg-creation-*/index.ts` | 无引用 barrel | 当前入口直接 import 具体 facade 文件,barrel 没有主流程消费 | 直接 import `RpgCreation*` 具体文件 |
|
||||
| `src/components/rpg-creation-editor/CustomWorldSceneChapterEditorSection.tsx` | 旧 facade | 当前编辑器 section 直接在 `RpgCreationEntityEditorShared.tsx` 中分发 | `src/components/rpg-creation-editor/RpgCreationEntityEditorShared.tsx` |
|
||||
| `src/data/editorValidation.ts` | 旧预设编辑器校验 | 当前主流程和内容门禁不再调用 | `scripts/validate-overrides.ts`、后端 editor API |
|
||||
| `src/editor/shared/EditorNotice.tsx` | 无入口共享 UI | 只被同批删除的 FormFields 使用 | 无替代 UI,删除历史编辑器壳 |
|
||||
| `src/editor/shared/FormFields.tsx` | 无入口共享 UI | 旧编辑器共享表单未接主流程 | 当前 RPG 编辑器组件内聚在 `rpg-creation-editor/**` |
|
||||
| `src/editor/shared/SectionCard.tsx` | 无入口共享 UI | 旧编辑器卡片未接主流程 | 当前 RPG 编辑器组件内聚在 `rpg-creation-editor/**` |
|
||||
| `src/hooks/rpg-runtime-story/npcEncounterActions.ts` | 旧 wrapper | 正式实现已在 `useRpgRuntimeNpcInteraction.ts`,测试已改到正式文件 | `src/hooks/rpg-runtime-story/useRpgRuntimeNpcInteraction.ts` |
|
||||
| `src/hooks/rpg-runtime-story/openingAdventure.ts` | 旧前端开局特殊流程 | 开局营地对白已由后端 `RpgRuntimeStoryActionDomain` 和当前 story context 承接 | `server-node/src/modules/rpg-runtime-story/RpgRuntimeStoryActionDomain.ts` |
|
||||
| `src/hooks/rpg-runtime-story/storyCampCompanion.ts` | 旧前端营地同伴 helper | 只剩旧开局流程和自身测试引用,正式开局上下文已迁到当前 runtime story 链 | 后端 runtime story action domain 与 `storyContextBuilder.ts` |
|
||||
| `src/hooks/rpg-runtime-story/storyRenderingHelpers.ts` | 无入口旧渲染 helper | 当前正式 story presentation 不再 import | `src/hooks/rpg-runtime-story/storyPresentation.ts` |
|
||||
| `src/prompts/questPrompts.ts` | 前端 prompt 残留 | Quest prompt 真相已迁到后端 | `server-node/src/prompts/questPrompts.ts` |
|
||||
| `src/prompts/runtimeItemPrompts.ts` | 前端 prompt 残留 | Runtime item prompt 真相已迁到后端 | `server-node/src/prompts/runtimeItemPrompts.ts` |
|
||||
| `src/services/questPrompt.ts` | 前端 prompt re-export | 只指向同批删除的前端 prompt | `server-node/src/prompts/questPrompts.ts` |
|
||||
| `src/services/runtimeItemAiPrompt.ts` | 前端 prompt re-export | 只指向同批删除的前端 prompt | `server-node/src/prompts/runtimeItemPrompts.ts` |
|
||||
| `src/services/storyEngine/contentDependencyGraph.ts` | 实验性孤岛 | 只被自身测试引用,没有主流程消费 | 后续如需要重新设计到后端 story graph 服务 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 同步调整
|
||||
|
||||
1. `customWorldAgentPhase2/3/4` 测试改为直接实例化 `RpgWorldWorkSummaryService`。
|
||||
2. `customWorldWorkSummaryService.integration.test.ts` 改为直接覆盖 `RpgWorldWorkSummaryService`。
|
||||
3. `npcEncounterActions.test.ts` 改为直接覆盖 `useRpgRuntimeNpcInteraction.ts`,不再通过旧 wrapper。
|
||||
4. `story_opening_camp_dialogue` 的 function catalog 执行路径改为后端 runtime action domain,不再指向已删除旧前端文件。
|
||||
5. NPC function catalog 中 `npc_chat / npc_help / npc_leave / npc_fight / npc_spar / npc_preview_talk` 的 executor 路牌改到现行 `useRpgRuntimeNpcInteraction.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次暂缓对象
|
||||
|
||||
以下对象仍然保留,原因是它们不是“无引用死代码”,而是需要下一轮按 contract 或主链职责迁移:
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
3. `src/services/ai.ts`
|
||||
4. `src/data/sceneObservation.ts`
|
||||
5. `server-node/ecosystem.config.cjs`
|
||||
6. `server-node/src/scripts/syncCustomWorldSavedProfileAssets.ts`
|
||||
|
||||
其中 `ecosystem.config.cjs` 被部署脚本直接使用;`sceneObservation.ts` 被内容 smoke 脚本验证;`syncCustomWorldSavedProfileAssets.ts` 是一次性运维脚本,后续要单独按运维脚本治理口径确认是否归档。
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证口径
|
||||
|
||||
本批删除后建议验证:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npx tsx --test server-node/src/services/customWorldWorkSummaryService.integration.test.ts`
|
||||
3. `npx vitest run src/hooks/rpg-runtime-story/npcEncounterActions.test.ts`
|
||||
4. `npm run server-node:build`
|
||||
5. `npm run build`
|
||||
|
||||
如果 `npm run build` 仍被既有 chunk warning 拦截,需要单独记录为既有门禁问题,不归因到本批删除。
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前结论
|
||||
|
||||
本批次进一步删除了“旧命名入口、旧 facade、旧 prompt 前端镜像、无入口编辑器壳层”这批容易误导后续开发的文件。
|
||||
|
||||
后续清理不应继续按“静态无引用”直接推进,而应进入两类工作:
|
||||
|
||||
1. 运行时 / 任务 / 物品 / AI 的后端 contract 收口。
|
||||
2. RPG 创作编辑器与运行时热点文件的职责拆分。
|
||||
@@ -0,0 +1,91 @@
|
||||
# 工程死分支清理执行记录 F(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
本批次承接批次 E 的验证结果,继续处理删除后暴露出的最后一组高置信残留:
|
||||
|
||||
1. 已经没有任何代码入口引用的前端任务生成 director。
|
||||
2. 只被内容 smoke 牵住、但不再是正式运行时入口的旧观察文案 helper。
|
||||
3. 带有固定用户、固定 session、固定 profile 的一次性历史同步脚本。
|
||||
4. 清理后暴露出的 function catalog 契约覆盖缺口。
|
||||
|
||||
本批次仍然不按文件名直接删除 `legacy` 命名对象。经核对,`server-node/src/bridges/legacyInventoryRuntimeBridge.ts`、`legacyNpcTask6Bridge.ts`、`legacyQuestProgressBridge.ts`、`legacyQuestRuntimeBridge.ts`、`legacyRuntimeItemBridge.ts`、`legacyTreasureRuntimeBridge.ts` 仍被后端战斗、背包、任务、宝藏主链直接引用,不能按历史命名硬删。
|
||||
|
||||
---
|
||||
|
||||
## 1. 删除判定口径
|
||||
|
||||
本批删除对象必须同时满足:
|
||||
|
||||
1. 修正 `.js -> .ts` 后端源码解析、前端懒加载入口解析后,仍不可从正式入口到达。
|
||||
2. 全仓库代码引用扫描没有正式入口引用。
|
||||
3. 如只被 smoke 或测试牵住,先把 smoke / 测试改到当前正式主链,再删除旧对象。
|
||||
4. 删除后通过对应门禁验证,没有新增悬空 import。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次已处理对象
|
||||
|
||||
| 文件 | 判定 | 删除 / 调整原因 | 替代路径 / 当前真相源 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/services/questDirector.ts` | 无代码入口残留 | 正式 quest 生成已由后端 `/api/runtime/quests/generate` 与 `questService.ts` 承接,前端当前没有任何 import | `server-node/src/services/questService.ts`、`server-node/src/modules/quest/runtimeQuestModule.ts` |
|
||||
| `src/data/sceneObservation.ts` | 旧观察文案 helper | 只被 `scripts/smoke-content.ts` 引用,正式观察动作已走 `idle_observe_signs` function 与运行时 story continuation | `src/data/functionCatalog/state/idleObserveSigns.ts`、`src/hooks/rpg-runtime-story/storyChoiceContinuation.ts` |
|
||||
| `server-node/src/scripts/syncCustomWorldSavedProfileAssets.ts` | 一次性硬编码运维脚本 | 脚本内固定用户、session、profile,只服务历史补丁,没有 CLI 参数和当前运维入口 | 无替代;如未来需要,按参数化运维脚本重新设计 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 同步调整
|
||||
|
||||
1. `scripts/smoke-content.ts` 不再 import 旧 `sceneObservation.ts`,改为通过 `resolveFunctionOption('idle_observe_signs', ...)` 验证当前正式 function 目录。
|
||||
2. `packages/shared/src/contracts/rpgRuntimeContracts.test.ts` 不再验证已移除的旧 `story` façade,改为直接验证当前拆分契约。
|
||||
3. `src/data/functionCatalog/` 补齐仍在后端运行时契约中的 function 文档:
|
||||
- `battle_attack_basic`
|
||||
- `battle_use_skill`
|
||||
- `npc_chat_quest_offer_view`
|
||||
- `npc_chat_quest_offer_replace`
|
||||
- `npc_chat_quest_offer_abandon`
|
||||
4. `battle_attack_basic` 与 `battle_use_skill` 只作为后端契约文档登记,不进入 `STATE_FUNCTION_DEFINITIONS`,避免前端本地候选池生成缺少 `runtimePayload.skillId` 的假技能 option。
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次暂缓对象
|
||||
|
||||
以下对象经本批复核后继续保留:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentRepositoryTestHelpers.ts`
|
||||
2. `server-node/src/services/customWorldAgentTestHelpers.ts`
|
||||
3. `server-node/src/testFixtures/runtimeCharacter.ts`
|
||||
4. `server-node/src/testHttp.ts`
|
||||
|
||||
这些文件不属于正式运行时入口,但当前被后端测试、smoke 与路由边界门禁使用。它们不是 RPG 创作 / 运行时玩法主流程代码,但仍是平台基本质量门禁的一部分,不能在“删除冗余业务代码”批次里直接硬删。
|
||||
|
||||
另保留:
|
||||
|
||||
1. `src/services/runtimeItemAiDirector.ts`
|
||||
2. `src/services/ai.ts`
|
||||
3. `src/services/apiClient.ts`
|
||||
|
||||
这些文件仍被当前主链或前端 SDK 入口引用,后续如继续压缩,必须先完成对应 contract / SDK 拆分,不按无引用规则删除。
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证结果
|
||||
|
||||
本批已通过:
|
||||
|
||||
1. `npx vitest run src/data/functionCatalog/functionCatalog.test.ts packages/shared/src/contracts/rpgRuntimeContracts.test.ts`
|
||||
2. `npx tsx scripts/smoke-content.ts`
|
||||
3. `npm run check:encoding`
|
||||
|
||||
并额外确认:
|
||||
|
||||
1. 全仓库代码中不再引用 `sceneObservation`、`questDirector`、`syncCustomWorldSavedProfileAssets`。
|
||||
2. `buildStateFunctionDefinitions()` 中不会出现 `battle_attack_basic` / `battle_use_skill`,这两个 function 只由后端运行时 option 池下发。
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前结论
|
||||
|
||||
本批次后,静态入口扫描中剩余的高置信“不可达源码”已经收敛为测试辅助、测试夹具和 smoke helper。继续删除前需要先重构测试基础设施或迁移剩余前端 SDK,而不应再按文件名或历史命名直接硬删。
|
||||
@@ -0,0 +1,553 @@
|
||||
# 前端应迁后端逻辑审计(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
这份文档只回答一个问题:
|
||||
|
||||
**当前前端代码里,哪些逻辑已经明显越过“前端只做表现,Express 后端负责逻辑、数据与存储”的边界,应该继续迁到后端。**
|
||||
|
||||
本轮不改业务代码,只做:
|
||||
|
||||
1. 基于当前仓库状态给出高置信度候选点
|
||||
2. 标明代码证据
|
||||
3. 给出迁移优先级
|
||||
4. 说明迁移后前端应该保留什么、移走什么
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
结合当前代码与已有边界文档,前端里仍有 7 类逻辑应该继续后移:
|
||||
|
||||
1. **运行时快照前置写入与本地镜像解释**
|
||||
2. **鉴权 token 的浏览器本地真相**
|
||||
3. **平台浏览历史的本地真相与迁移状态**
|
||||
4. **NPC 待接委托“换单”仍由前端直接触发正式生成**
|
||||
5. **quest/runtime item 的双环境混合编排**
|
||||
6. **浏览器侧大型 AI orchestration 与 prompt/repair/fallback 主链**
|
||||
7. **NPC 招募对白之后的正式结算链路**
|
||||
|
||||
一句话判断:
|
||||
|
||||
**当前前端已经不是最早那种“大量主算”的状态,但仍然保留了运行时镜像、生成编排和部分正式真相。后端边界还需要再收一轮,前端才算真正退回表现层。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 审计依据
|
||||
|
||||
### 2.1 文档依据
|
||||
|
||||
1. `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
3. `docs/technical/RUNTIME_STORY_BACKEND_BOUNDARY_MIGRATION_2026-04-19.md`
|
||||
4. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`
|
||||
5. `docs/audits/engineering/CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`
|
||||
|
||||
### 2.2 当前代码依据
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
2. `src/services/apiClient.ts`
|
||||
3. `src/services/platformBrowseHistory.ts`
|
||||
4. `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
5. `src/hooks/story/npcEncounterActions.ts`
|
||||
6. `src/services/questDirector.ts`
|
||||
7. `src/services/runtimeItemAiDirector.ts`
|
||||
8. `src/services/ai.ts`
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前高置信度应后移逻辑
|
||||
|
||||
## 3.0 本轮已完成后移
|
||||
|
||||
以下链路已在本轮或上一轮连续落地中完成后移,不再属于“仍残留在前端”的正式主链:
|
||||
|
||||
1. access token 浏览器本地真相
|
||||
2. browse history 本地真相
|
||||
3. runtime story 前置 `PUT /runtime/save/snapshot`
|
||||
4. NPC 待接委托 `replace / abandon / accept`
|
||||
5. custom world profile 正式浏览器入口
|
||||
6. `questDirector` / `runtimeItemAiDirector` 浏览器正式编排
|
||||
7. NPC 招募正式结算
|
||||
|
||||
其中 NPC 招募已从“前端本地改 companions / roster / npcStates / storyHistory”收回到后端 runtime action。
|
||||
|
||||
## 3.1 运行时快照前置写入仍在前端
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/hooks/story/runtimeStoryCoordinator.ts` 当前仍存在以下链路:
|
||||
|
||||
1. `syncRuntimeSnapshot(...)`
|
||||
2. `syncRuntimeSnapshot(...)` 内部直接调用 `putSaveSnapshot(...)`
|
||||
3. `loadServerRuntimeOptionCatalog(...)` 在请求 `getRuntimeStoryState(...)` 之前先写本地快照
|
||||
4. `resolveServerRuntimeChoice(...)` 在请求 `resolveRuntimeStoryAction(...)` 之前先写本地快照
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts:21`
|
||||
2. `src/hooks/story/runtimeStoryCoordinator.ts:25`
|
||||
3. `src/hooks/story/runtimeStoryCoordinator.ts:36`
|
||||
4. `src/hooks/story/runtimeStoryCoordinator.ts:99`
|
||||
|
||||
### 当前问题
|
||||
|
||||
这意味着运行时正式动作发起前,前端仍会先落一份自己的快照真相,再去请求后端。
|
||||
|
||||
这条链的问题不是“有没有缓存”,而是:
|
||||
|
||||
1. 前端仍在承担正式提交前的状态镜像
|
||||
2. 快照解释权没有完全收回到后端
|
||||
3. 运行时主链仍处于“本地镜像 + 服务端会话”并存状态
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. 运行时快照写入
|
||||
2. 快照版本解释
|
||||
3. 动作提交前的状态一致性校验
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 当前展示用的 view model
|
||||
2. 可选的只读恢复缓存
|
||||
3. 纯表现态的 loading / transition / animation state
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.2 鉴权 token 仍由前端 localStorage 持有真相
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/apiClient.ts` 当前仍直接访问 `window.localStorage` 保存 access token:
|
||||
|
||||
1. `getStoredAccessToken()`
|
||||
2. `setStoredAccessToken(...)`
|
||||
3. `clearStoredAccessToken(...)`
|
||||
4. `withAuthorizationHeaders(...)` 直接从本地 token 组装请求头
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/apiClient.ts:333`
|
||||
2. `src/services/apiClient.ts:341`
|
||||
3. `src/services/apiClient.ts:362`
|
||||
4. `src/services/apiClient.ts:382`
|
||||
|
||||
### 当前问题
|
||||
|
||||
第三批清理已经收掉了“自动登录用户名/密码”本地真相,但 access token 仍然由浏览器长期持有。
|
||||
|
||||
这在当前项目边界下仍有两个问题:
|
||||
|
||||
1. 正式鉴权真相仍没有完全收回后端 session 边界
|
||||
2. 前端 SDK 仍然负担 token 生命周期的关键部分
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. session / refresh / cookie 真相
|
||||
2. 鉴权状态续期
|
||||
3. token 更新与失效策略
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 当前是否已登录的展示态
|
||||
2. 统一的请求封装
|
||||
3. 401 后的 UI 响应
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.3 平台浏览历史仍是“前端本地历史 + 后端回填”的双真相
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/platformBrowseHistory.ts` 当前仍维护一整套本地历史真相:
|
||||
|
||||
1. `readPlatformBrowseHistory(...)`
|
||||
2. `writePlatformBrowseHistory(...)`
|
||||
3. `hasPendingPlatformBrowseHistoryMigration(...)`
|
||||
4. `markPlatformBrowseHistoryMigrated(...)`
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/platformBrowseHistory.ts:77`
|
||||
2. `src/services/platformBrowseHistory.ts:103`
|
||||
3. `src/services/platformBrowseHistory.ts:151`
|
||||
4. `src/services/platformBrowseHistory.ts:164`
|
||||
|
||||
`src/components/game-shell/PreGameSelectionFlow.tsx` 当前仍显式做:
|
||||
|
||||
1. 先 `writePlatformBrowseHistory(...)`
|
||||
2. 再调用 `upsertProfileBrowseHistory(...)`
|
||||
3. 同步成功后 `markPlatformBrowseHistoryMigrated(...)`
|
||||
4. 启动阶段读取 `readPlatformBrowseHistory(...)`
|
||||
5. 根据 `hasPendingPlatformBrowseHistoryMigration(...)` 决定是否补同步
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/components/game-shell/PreGameSelectionFlow.tsx:383`
|
||||
2. `src/components/game-shell/PreGameSelectionFlow.tsx:392`
|
||||
3. `src/components/game-shell/PreGameSelectionFlow.tsx:394`
|
||||
4. `src/components/game-shell/PreGameSelectionFlow.tsx:433`
|
||||
5. `src/components/game-shell/PreGameSelectionFlow.tsx:466`
|
||||
|
||||
### 当前问题
|
||||
|
||||
这条链已经不是单纯缓存,而是:
|
||||
|
||||
1. 本地历史存储
|
||||
2. 本地同步标记
|
||||
3. 后端历史持久化
|
||||
|
||||
三套状态同时存在。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. 浏览历史唯一持久化真相
|
||||
2. 历史去重、排序、截断
|
||||
3. 迁移完成标记
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 展示缓存
|
||||
2. 弱网下的临时 optimistic UI
|
||||
3. 刷新后重新拉取远端结果
|
||||
|
||||
### 优先级
|
||||
|
||||
`P1`
|
||||
|
||||
---
|
||||
|
||||
## 3.4 NPC 待接委托“换单”仍由前端直接发起正式生成
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/hooks/story/npcEncounterActions.ts` 当前仍保留:
|
||||
|
||||
1. `replacePendingNpcQuestOffer = async () => { ... }`
|
||||
2. 内部直接调用 `generateQuestForNpcEncounter(...)`
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts:1561`
|
||||
2. `src/hooks/story/npcEncounterActions.ts:1595`
|
||||
|
||||
### 当前问题
|
||||
|
||||
聊天后是否挂出待接委托已经后移,但“换一份委托”这条分支仍然是:
|
||||
|
||||
1. 前端组装上下文
|
||||
2. 前端决定调用生成
|
||||
3. 前端直接把结果写回当前 story UI
|
||||
|
||||
这仍属于正式运行时任务编排没有收干净。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. NPC 待接委托换单决策
|
||||
2. 是否允许换单
|
||||
3. 换单后的任务草案生成
|
||||
4. 对应聊天态快照回填
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 点击“换一份委托”
|
||||
2. loading / error 展示
|
||||
3. 消费后端返回的新 pending quest offer
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.5 questDirector 仍是前端 SDK 与生成编排混合体
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/questDirector.ts` 当前同时承担:
|
||||
|
||||
1. `generateQuestForNpcEncounter(...)`
|
||||
2. 浏览器路径 `requestJson('/api/runtime/quests/generate')`
|
||||
3. 非浏览器路径 `requestChatMessageContent(...)`
|
||||
4. 本地 `compileQuestIntentToQuest(...)` fallback
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/questDirector.ts:213`
|
||||
2. `src/services/questDirector.ts:242`
|
||||
3. `src/services/questDirector.ts:267`
|
||||
4. `src/services/questDirector.ts:256`
|
||||
5. `src/services/questDirector.ts:281`
|
||||
6. `src/services/questDirector.ts:293`
|
||||
|
||||
### 当前问题
|
||||
|
||||
这类文件虽然浏览器正式路径已经优先走后端,但职责仍混在一起:
|
||||
|
||||
1. 前端 SDK
|
||||
2. Quest prompt 编排
|
||||
3. Quest intent 解析
|
||||
4. deterministic fallback compile
|
||||
|
||||
这会导致边界长期模糊,也让前端仍像“半个服务端”。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. quest intent 生成
|
||||
2. prompt 组装
|
||||
3. JSON 解析
|
||||
4. fallback compile
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. `requestGenerateQuest(...)` 这类轻量 SDK
|
||||
2. 请求参数组装
|
||||
3. 结果消费
|
||||
|
||||
### 优先级
|
||||
|
||||
`P1`
|
||||
|
||||
---
|
||||
|
||||
## 3.6 runtimeItemAiDirector 仍是前端 SDK 与意图生成混合体
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/runtimeItemAiDirector.ts` 当前同时承担:
|
||||
|
||||
1. `generateRuntimeItemAiIntents(...)`
|
||||
2. 浏览器路径 `requestJson('/api/runtime/items/runtime-intent')`
|
||||
3. 非浏览器路径 `requestChatMessageContent(...)`
|
||||
4. 本地 `buildRuntimeItemAiIntent(...)` fallback
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/runtimeItemAiDirector.ts:84`
|
||||
2. `src/services/runtimeItemAiDirector.ts:94`
|
||||
3. `src/services/runtimeItemAiDirector.ts:118`
|
||||
|
||||
### 当前问题
|
||||
|
||||
它和 `questDirector` 是同类问题:
|
||||
|
||||
1. 正式浏览器路径已经走后端
|
||||
2. 但前端文件仍然承担完整生成逻辑认知
|
||||
3. 文件职责仍然是双环境混合
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. runtime item intent prompt
|
||||
2. 模型调用
|
||||
3. 结果解析与 fallback
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 轻量请求 SDK
|
||||
2. 结果到 UI 的映射
|
||||
|
||||
### 优先级
|
||||
|
||||
`P1`
|
||||
|
||||
---
|
||||
|
||||
## 3.7 `src/services/ai.ts` 仍是浏览器侧正式 AI orchestration 热点
|
||||
|
||||
### 代码证据
|
||||
|
||||
当前 `src/services/ai.ts` 仍直接承担以下正式链路:
|
||||
|
||||
1. `requestChatMessageContent(...)`
|
||||
2. `requestPlainTextCompletionFromClient(...)`
|
||||
3. `streamPlainTextCompletionFromClient(...)`
|
||||
4. `generateCustomWorldProfile(...)`
|
||||
5. `generateInitialStory(...)`
|
||||
6. `generateNextStep(...)`
|
||||
7. `streamNpcChatDialogue(...)`
|
||||
8. `streamNpcRecruitDialogue(...)`
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/ai.ts:1732`
|
||||
2. `src/services/ai.ts:1868`
|
||||
3. `src/services/ai.ts:2038`
|
||||
4. `src/services/ai.ts:2339`
|
||||
5. `src/services/ai.ts:2447`
|
||||
6. `src/services/ai.ts:2487`
|
||||
7. `src/services/ai.ts:2529`
|
||||
8. `src/services/ai.ts:2570`
|
||||
|
||||
并且文件内仍保留:
|
||||
|
||||
1. JSON repair
|
||||
2. prompt 组装
|
||||
3. response normalize
|
||||
4. fallback/offline 响应
|
||||
5. 角色聊天建议与摘要生成
|
||||
|
||||
### 当前问题
|
||||
|
||||
这说明浏览器端并不只是“请求一个后端接口”,而是还在承担:
|
||||
|
||||
1. prompt source
|
||||
2. 生成策略
|
||||
3. 错误修复
|
||||
4. fallback 编排
|
||||
5. 多类业务场景的正式 AI 出口
|
||||
|
||||
这与“前端只做表现”存在明确冲突。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. story / npc / recruit / custom-world 的 prompt 编排
|
||||
2. JSON repair
|
||||
3. fallback 策略
|
||||
4. streaming orchestration
|
||||
5. 模型调用与日志
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 轻量 AI SDK
|
||||
2. SSE 文本流展示
|
||||
3. UI fallback 呈现
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.8 NPC 招募对白之后的正式结算链路已完成后移
|
||||
|
||||
### 本轮前状态
|
||||
|
||||
迁移前,`src/hooks/story/npcInteraction.ts` 中的 `buildRecruitmentOutcome / executeRecruitment / startRecruitmentSequence` 仍在前端本地正式结算:
|
||||
|
||||
1. 改 `npcStates`
|
||||
2. 改 `companions`
|
||||
3. 改 `roster`
|
||||
4. 清 `currentEncounter / inBattle / sceneHostileNpcs`
|
||||
5. 直接写 `storyHistory`
|
||||
6. 再触发后续剧情推进
|
||||
|
||||
这与“前端只做表现,所有正式逻辑、数据都放到 Express 后端”直接冲突。
|
||||
|
||||
### 本轮后状态
|
||||
|
||||
本轮已完成:
|
||||
|
||||
1. `server-node/src/modules/story/runtimeSession.ts`
|
||||
- 正式承接完整 `companions`
|
||||
- 正式承接 `roster`
|
||||
2. `server-node/src/modules/npc/npcInteractionService.ts`
|
||||
- `npc_recruit` 已支持正常入队
|
||||
- `npc_recruit` 已支持满员换队招募
|
||||
3. `src/hooks/story/npcInteraction.ts`
|
||||
- 前端只保留招募对白流式展示
|
||||
- 正式招募结算改为调用后端 runtime action
|
||||
|
||||
### 当前判断
|
||||
|
||||
这一项已不再属于前端残留正式逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 4. 可以暂时保留在前端的部分
|
||||
|
||||
下面这些内容即使和上述模块同文件出现,也不属于必须后移的对象:
|
||||
|
||||
1. 面板开关、loading、error、streaming 文本展示
|
||||
2. 动画时间线、过场状态、临时 UI 回显
|
||||
3. 表单草稿、筛选词、排序选项
|
||||
4. 只影响表现、不影响正式真相的 view model 拼接
|
||||
|
||||
迁移时要注意:
|
||||
|
||||
**不是把所有前端代码都往后端搬,而是把“正式状态解释、规则裁决、生成编排、持久化真相”搬走。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 推荐迁移顺序
|
||||
|
||||
## 5.1 第一阶段
|
||||
|
||||
先收最危险的正式真相:
|
||||
|
||||
1. `runtimeStoryCoordinator.ts`
|
||||
2. `apiClient.ts`
|
||||
3. `npcEncounterActions.ts` 里的 quest replace 分支
|
||||
|
||||
原因:
|
||||
|
||||
1. 这三处最直接影响运行时真相和动作主链
|
||||
2. 不先收这些,前端仍然不是纯表现层
|
||||
|
||||
## 5.2 第二阶段
|
||||
|
||||
再拆双环境混合服务:
|
||||
|
||||
1. `questDirector.ts`
|
||||
2. `runtimeItemAiDirector.ts`
|
||||
3. `platformBrowseHistory.ts`
|
||||
|
||||
原因:
|
||||
|
||||
1. 这几处已经有后端承接基础
|
||||
2. 迁移成本相对可控
|
||||
|
||||
## 5.3 第三阶段
|
||||
|
||||
最后继续压缩浏览器 AI orchestration:
|
||||
|
||||
1. `src/services/ai.ts`
|
||||
2. 相关 prompt builder / repair helper / offline fallback
|
||||
|
||||
原因:
|
||||
|
||||
1. 这部分体量大
|
||||
2. 链路多
|
||||
3. 更适合在前两阶段把 contract 稳住后集中拆
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议产出物
|
||||
|
||||
如果后续按这份文档继续落地,建议每一批都至少同步产出:
|
||||
|
||||
1. 一份落地文档,说明迁移了哪条链
|
||||
2. 一组 contract/route 变更说明
|
||||
3. 一组前端 SDK 收缩说明
|
||||
4. 一组防回退测试
|
||||
|
||||
---
|
||||
|
||||
## 7. 一句话结论
|
||||
|
||||
当前前端最需要继续后移的,不是零散小工具,而是:
|
||||
|
||||
**运行时快照前置写入、鉴权 token、本地浏览历史真相、NPC 委托换单、quest/runtime item 双环境混合编排,以及 `src/services/ai.ts` 里仍然留在浏览器的正式 AI orchestration。**
|
||||
@@ -0,0 +1,173 @@
|
||||
# 怪物-NPC 脚本统一整改审计
|
||||
|
||||
日期:2026-04-06
|
||||
|
||||
## 核心结论
|
||||
|
||||
当前工程仍然没有真正落实“怪物就是初始好感度为负数的 NPC”这一原则。
|
||||
|
||||
现状不是“NPC 脚本里支持 hostile 状态”,而是同时存在两条并行链路:
|
||||
|
||||
1. `npc / encounter / npcStates / npcInteraction`
|
||||
2. `monster / hostileNpc / sceneMonsters / sceneHostileNpcs / hostileNpcPresets`
|
||||
|
||||
这会直接导致:
|
||||
|
||||
- 同一个敌对实体同时拥有 NPC 身份和 monster 身份。
|
||||
- 场景、战斗、渲染、提示词都在维护两套入口。
|
||||
- 后续修 bug 时,任何位置、死亡、血条、入场、掉落问题都要同时查两条链路。
|
||||
|
||||
本次文档的目标不是立刻改代码,而是先把应该删除的分叉脚本、应该降级成素材层的文件、以及必须合并的字段全部列清楚,作为后续统一改造的依据。
|
||||
|
||||
## 当前违背原则的根因
|
||||
|
||||
### 1. 场景数据仍然把“怪物”和“NPC”当成两类实体
|
||||
|
||||
当前场景层同时维护:
|
||||
|
||||
- `ScenePreset.monsterIds`
|
||||
- `SceneNpc[]`
|
||||
- `ScenePresetInfo.hostileNpcIds`
|
||||
- `SceneNpc.monsterPresetId / hostileNpcPresetId`
|
||||
|
||||
这意味着场景里一个敌对单位既可以来自 `monsterIds`,也可以来自 `npcs`,甚至会被脚本再生成为 hostile scene npc。
|
||||
|
||||
### 2. 运行时仍然存在“怪物专用实体状态”
|
||||
|
||||
当前运行时仍然同时维护:
|
||||
|
||||
- `GameState.sceneMonsters`
|
||||
- `GameState.sceneHostileNpcs`
|
||||
- `SceneHostileNpc / SceneMonster`
|
||||
|
||||
这和“怪物本质上只是 hostile NPC”是冲突的。真正统一后,运行时只应该保留一套“场景 NPC / 战斗 NPC”状态。
|
||||
|
||||
### 3. 战斗脚本仍然把怪物当独立 actor
|
||||
|
||||
战斗层目前不是“NPC 战斗,只是 hostile 的那部分会出手”,而是显式写了:
|
||||
|
||||
- `TurnActor = 'player' | 'companion' | 'monster'`
|
||||
- `getClosestMonster`
|
||||
- `resetCombatPresentation(monsters, ...)`
|
||||
- `sceneMonsters` 全链路结算
|
||||
|
||||
这会强制后面所有视觉、掉落、提示词、AI 上下文都跟着叫 monster。
|
||||
|
||||
### 4. 渲染层仍然有 monster 专属显示入口
|
||||
|
||||
画布层当前仍然依赖:
|
||||
|
||||
- `sceneMonsters`
|
||||
- `sceneHostileNpcs`
|
||||
- `monsterPresetId`
|
||||
- `HostileNpcAnimator`
|
||||
|
||||
也就是“敌对 NPC 是否按 NPC 脚本渲染”这件事,到最终显示层仍然没有统一。
|
||||
|
||||
## 一级删除清单
|
||||
|
||||
下面这些文件属于“业务流程分叉脚本”,不是单纯资源适配层。后续统一时应优先删除或并入 NPC 主链路。
|
||||
|
||||
| 文件 | 当前分叉角色 | 处理建议 |
|
||||
| --- | --- | --- |
|
||||
| `src/data/monsters.ts` | 对 `hostileNpcs.ts` 的别名出口 | 直接删除,禁止继续保留 monster 专属入口名。 |
|
||||
| `src/data/hostileNpcs.ts` | 负责 monster 创建、编队、距离、朝向、变化、落位 | 按 hostile NPC 运行时工具重写并并入 NPC 体系;原文件名不应继续保留。 |
|
||||
| `src/data/sceneEncounterPreviews.ts` | 单独构造 hostile encounter group、auto battle、hostile preview | 删除 monster 专线逻辑,改为“负好感 NPC 预览/入场/转战斗”。 |
|
||||
| `src/hooks/combat/battlePlan.ts` | 使用 `monster` actor、`sceneMonsters`、`getClosestMonster` | 改成统一的 hostile NPC combatant 规划脚本;monster actor 概念应移除。 |
|
||||
| `src/hooks/combat/playback.ts` | 使用 `sceneMonsters` 播放怪物战斗演出 | 改成统一 NPC 战斗回放;不再区分 monster 播放器。 |
|
||||
| `src/components/game-canvas/GameCanvasRuntime.tsx` | 运行时按 `sceneMonsters / sceneHostileNpcs` 双数据源选敌方实体 | 删除双源兜底,统一成单一 hostile NPC 列表。 |
|
||||
| `src/components/game-canvas/GameCanvasEntityLayer.tsx` | 敌方实体按 monsterPreset 分支渲染 | 改成同一套 NPC 实体渲染,视觉差异仅由 visual preset 决定。 |
|
||||
| `src/components/game-canvas/GameCanvasShared.tsx` | 定义 `sceneMonsters / sceneHostileNpcs` props 与 monster 专属计算 | 删除这些字段与 helper,改成统一 NPC 画布协议。 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | 独立怪物预设编辑面板 | 并回 NPC hostile visual preset 面板,或删除该独立编辑器入口。 |
|
||||
| `src/components/preset-editor/MonsterPresetTab.tsx` | 独立怪物预设页签 | 与上面一并删除或并入 NPC preset 编辑器。 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | 仍然单独编辑 `monsterIds` | 删除 `monsterIds` 编辑项,只保留场景 NPC 列表。 |
|
||||
|
||||
## 二级归并清单
|
||||
|
||||
下面这些文件不一定需要物理删除,但它们当前仍然在放大 monster / NPC 分轨,必须在统一改造时一起收口。
|
||||
|
||||
| 文件 | 当前问题 | 处理建议 |
|
||||
| --- | --- | --- |
|
||||
| `src/data/scenePresets.ts` | 通过 `monsterIds` 再生 hostile scene npc,并区分 `getSceneHostileNpcs / getSceneFriendlyNpcs` | 保留场景数据文件本身,但删除 `monsterIds` 体系,让敌对角色直接存在于 `npcs` 中。 |
|
||||
| `src/data/customWorldNpcMonsters.ts` | 用单独脚本推导“怪物型 NPC”预设 | 可保留为 hostile visual preset 选择器,但不能再生成第二套实体语义。 |
|
||||
| `src/data/hostileNpcPresets.ts` | 目前既是视觉预设库,也是独立 hostile 流程的数据源 | 降级为 hostile visual/combat preset 库;不再拥有独立实体生命周期。 |
|
||||
| `src/components/HostileNpcAnimator.tsx` | 当前名字和调用语义都在暗示“独立怪物实体” | 可以保留为贴图播放器,但应改为 hostile NPC 的视觉适配组件,而不是独立物种脚本。 |
|
||||
| `src/components/AdventureEntityModal.tsx` | 详情弹窗仍会优先查 monster preset / hostileNpcPreset | 统一读取 NPC 档案;视觉差异只通过 hostile preset 补充。 |
|
||||
| `src/components/SkillEffectPreview.tsx` | 预览器直接使用 `sceneMonsters` 和 `createSceneMonstersFromIds` | 改成统一 hostile NPC 预览态。 |
|
||||
| `src/components/StateFunctionEditor.tsx` | 编辑器里仍然直接造 monster battle preview | 改成 hostile NPC preview。 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | 仍然暴露 `monsterPresetId` 字段 | 改成更明确的 hostile visual preset 字段,避免“怪物类型”和“NPC 类型”双语义。 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | 虽然入口叫 npc,但内部仍然写 `sceneMonsters / sceneHostileNpcs` | 改成统一 hostile NPC 战斗状态字段。 |
|
||||
| `src/hooks/story/choiceActions.ts` | 仍然有 `buildHostileNpcBattleReward` 和 `getResolvedSceneHostileNpcs` 这一层额外概念 | 统一到 hostile NPC 结算工具,不再把“敌对 NPC”和“monster”混称。 |
|
||||
| `src/hooks/useStoryGeneration.ts` | 给 AI/剧情层传入 `sceneMonsters` 或 `sceneHostileNpcs` | 改成统一的 hostile NPC 上下文切片。 |
|
||||
| `src/services/prompt.ts` | 仍然从 `monsterIds` 和 `createSceneMonstersFromIds` 组 prompt | 改成从场景 NPC 列表中筛出 hostile NPC。 |
|
||||
| `src/services/questDirector.ts` | 仍然依赖 `monsterPresetId` 推导当前敌对目标 | 统一改为基于负好感或 hostile 标记的 NPC。 |
|
||||
| `src/services/ai.ts` | 仍然混用 `monsterIds`、sceneNpc 的 hostile 判定 | 与场景统一后改成只读 NPC 列表。 |
|
||||
| `src/services/questTypes.ts` | 仍然把 `hostileNpcIds / monsterIds` 当作 scene 快照字段 | 删除 `monsterIds`,保留 hostile NPC 语义。 |
|
||||
|
||||
## 可保留但必须降级为“素材/配置层”的内容
|
||||
|
||||
下面这些内容不一定要消失,但不能继续作为独立业务链路存在:
|
||||
|
||||
| 文件/内容 | 可以保留的原因 | 必须收口的边界 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/HostileNpcAnimator.tsx` | 怪物贴图是特殊资源,需要专门 sprite sheet 播放器 | 只负责画图,不再决定实体类型、战斗身份、交互入口。 |
|
||||
| `src/data/hostileNpcPresets.ts` | hostile visual/combat preset 仍然有价值 | 只能作为 hostile NPC 的 visual/combat preset 库,不再驱动另一套“monster 实体”。 |
|
||||
| `src/data/hostileNpcOverrides.json` | 资源级 override 仍可继续用 | 不能再配套出独立 hostile 流程。 |
|
||||
| `src/data/monsterOverrides.json` | 如果只是素材映射,可迁移到 hostile visual preset override | 不应继续以 monster 专属命名长期存在。 |
|
||||
| `src/data/customWorldNpcMonsters.ts` | 自定义世界里确实需要从文本匹配 hostile visual preset | 只能产出“NPC 使用哪个 hostile visual preset”,不能产出独立 monster 身份。 |
|
||||
|
||||
## 字段级必须合并的内容
|
||||
|
||||
后续改代码时,至少要把下面这些字段和类型一起收口:
|
||||
|
||||
| 当前字段/类型 | 问题 | 合并方向 |
|
||||
| --- | --- | --- |
|
||||
| `ScenePreset.monsterIds` | 场景里额外保存一份怪物池 | 删除,只保留 `npcs`。 |
|
||||
| `ScenePresetInfo.hostileNpcIds` | 历史遗留双字段 | 直接由 `npcs.filter(initialAffinity < 0 或 hostile)` 推导。 |
|
||||
| `Encounter.monsterPresetId` | 把 hostile NPC 再次物种化 | 改成 hostile visual preset 字段,或并入统一 visualRef。 |
|
||||
| `Encounter.hostileNpcPresetId` | 与 `monsterPresetId` 语义重叠 | 与上面合并为一个字段。 |
|
||||
| `GameState.sceneMonsters` | 把敌对 NPC 单独塞进 monster 容器 | 改成统一 `sceneNpcCombatants` 或等价单一列表。 |
|
||||
| `GameState.sceneHostileNpcs` | 历史兼容层,导致双数据源 | 删除。 |
|
||||
| `SceneHostileNpc / SceneMonster` | 类型名直接固化了分轨 | 改成统一的 hostile NPC / scene combat NPC 类型。 |
|
||||
| `SceneHostileNpcChange / SceneMonsterChange` | 继续复制同一套变更结构 | 合并成统一 NPC scene change。 |
|
||||
| `SceneNpc.monsterPresetId / hostileNpcPresetId` | 同一实体上挂两套 preset 入口 | 收敛为一个 hostile visual/combat preset 字段。 |
|
||||
|
||||
## 本轮最优先的删除顺序
|
||||
|
||||
建议后续真正改代码时,按下面顺序删并,风险最低:
|
||||
|
||||
1. 先删字段入口:`monsterIds / sceneHostileNpcs / hostileNpcPresetId`
|
||||
2. 再删运行时双轨:`src/data/monsters.ts`、`src/data/hostileNpcs.ts`、`src/data/sceneEncounterPreviews.ts`
|
||||
3. 再删战斗双轨:`battlePlan.ts`、`playback.ts` 里的 `monster` actor 与 `sceneMonsters`
|
||||
4. 再删画布双轨:`GameCanvasRuntime.tsx`、`GameCanvasEntityLayer.tsx`、`GameCanvasShared.tsx`
|
||||
5. 最后清编辑器和提示词:`MonsterPresetPanel.tsx`、`MonsterPresetTab.tsx`、`prompt.ts`、`questDirector.ts`
|
||||
|
||||
## 改造后的目标形态
|
||||
|
||||
统一后应只剩下这一套语义:
|
||||
|
||||
- 场景中所有可见角色都放在 `npcs`
|
||||
- 怪物 = `initialAffinity < 0` 或 `hostile = true` 的 NPC
|
||||
- hostile 的视觉差异只来自 hostile visual preset
|
||||
- 战斗中所有敌方单位都属于 hostile NPC combatant
|
||||
- AI、任务、渲染、详情、掉落都只读同一套 NPC 数据
|
||||
|
||||
如果后面代码里还出现下面这些关键词,基本都说明分轨没有删干净:
|
||||
|
||||
- `sceneMonsters`
|
||||
- `sceneHostileNpcs`
|
||||
- `monsterIds`
|
||||
- `hostileNpcPresetId`
|
||||
- `createSceneMonstersFromIds`
|
||||
- `getClosestMonster`
|
||||
- `TurnActor = 'monster'`
|
||||
|
||||
## 这份文档的使用方式
|
||||
|
||||
后续正式开始改造时,建议把文件分成三批执行:
|
||||
|
||||
1. “直接删掉”的入口脚本
|
||||
2. “改名并并回 NPC 主链路”的桥接脚本
|
||||
3. “仅保留素材职责”的 renderer / preset 文件
|
||||
|
||||
不要继续接受“名字叫 NPC,但内部仍然先转成 monster 再跑”的中间态。
|
||||
46
docs/audits/engineering/README.md
Normal file
46
docs/audits/engineering/README.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 工程优化审查总览
|
||||
|
||||
这一组只保留仍能指导当前 Rust / SpacetimeDB 主线的工程审查入口。早期连续扫描的有效结论已经合并到本 README 的“融合结论”,不再保留逐日旧稿。
|
||||
|
||||
## 当前推荐入口
|
||||
|
||||
1. [SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md](./SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md)
|
||||
这一版是旧 Node 后端冻结、第一批物理删除与后续批次边界记录,明确当前工程只保留 Rust / SpacetimeDB 主线入口。
|
||||
2. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_F_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_F_2026-04-21.md)
|
||||
这一版是第六批落地记录,聚焦删除无入口 `questDirector`、旧观察文案 helper、一次性硬编码同步脚本,并补齐后端运行时 function catalog 契约覆盖。
|
||||
3. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_E_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_E_2026-04-21.md)
|
||||
这一版是第五批落地记录,聚焦旧命名 re-export、空路由骨架、旧发布服务、前端 prompt 镜像与无入口编辑器壳层的物理删除。
|
||||
4. [FRONTEND_LOGIC_BACKEND_MIGRATION_AUDIT_2026-04-21.md](./FRONTEND_LOGIC_BACKEND_MIGRATION_AUDIT_2026-04-21.md)
|
||||
这一版是本轮前端越界逻辑专项审计,专门汇总当前仍应继续迁到 `server-rs` 的运行时、鉴权、生成编排与本地真相残留。
|
||||
5. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_D_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_D_2026-04-21.md)
|
||||
这一版是第四批落地记录,聚焦未接入业务的数据生成产物、测试专用 stub 与对应配置残留出清。
|
||||
6. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_C_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_C_2026-04-21.md)
|
||||
这一版是第三批落地记录,聚焦鉴权真相收口,先移除前端保存自动登录用户名/密码的本地真相,并明确运行时快照前置写入为什么当前还不能硬砍。
|
||||
7. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_B_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_B_2026-04-21.md)
|
||||
这一版是第二批落地记录,聚焦旧主流程壳层、旧 bootstrap 和旧 inventory / forge / equipment flow Hook 的正式出清。
|
||||
8. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_A_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_A_2026-04-21.md)
|
||||
这一版是第一批落地记录,聚焦高置信度小型孤岛、prompt 壳子、stub 和无入口 modal 的首轮清理。
|
||||
9. [CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md](./CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md)
|
||||
这一版是面向当前仓库状态的优化点盘点,适合直接拿来排优先级和拆执行批次。
|
||||
10. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md)
|
||||
这一版是对 `2026-04-19` 基线的当前仓库复核,明确哪些问题已经处理、哪些表述需要纠正、热点又迁移到了哪里。
|
||||
11. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md)
|
||||
这一版保留原始问题快照和执行回填,适合回看“为什么会有这轮清理与边界收口”。
|
||||
## 融合结论
|
||||
|
||||
- 最新专项审计已经把“前端哪些逻辑还该后移到后端”收敛到 6 类:运行时快照、本地 token、本地浏览历史、NPC 委托换单、quest/runtime item 混合编排、浏览器 AI orchestration。
|
||||
- 工程大清洗已经开始进入实际执行阶段,首批高置信度小型孤岛和残留壳子已开始清理。
|
||||
- 第二批已经开始清理旧主流程壳层与旧 flow Hook,当前主工程的“现行入口”和“历史入口”边界正在变得更清楚。
|
||||
- 第三批已经先完成鉴权真相收口的一段,前端不再保存自动登录用户名/密码;运行时快照链仍需先补后端 contract,再继续往前删。
|
||||
- 第四批已经继续收掉未接入业务的数据生成产物、测试专用 stub 与对应脚本/配置残留,主工程里的“假数据主源”进一步减少。
|
||||
- 第五批已经继续收掉旧命名 re-export、空路由骨架、旧发布 service、前端 prompt 镜像与无入口编辑器壳层,主工程里的“假入口”和“假 prompt 主源”进一步减少。
|
||||
- 第六批已经继续收掉无入口 `questDirector`、旧观察文案 helper、一次性硬编码同步脚本,并修复 function catalog 对后端运行时契约的覆盖缺口。
|
||||
- 当前仓库已经完成“旧 dev 插件链路删除、根目录噪音清理、`server-node -> src/**` 反向依赖切断”这批第一阶段任务。
|
||||
- 当前如果想直接判断“今天先优化什么”,优先看 `CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`。
|
||||
- 当前的新重点已经进一步收敛到三类:未接线孤岛模块、前端残留的运行时/鉴权真相、热点向 prompt/runtime profile/平台入口壳层迁移。
|
||||
- 早期三轮工程扫描的结论已经聚合为一条长期规则:工程化不能只看目录和拆分动作,必须覆盖真实主链、质量门禁、绿色基线、关键模块豁免和 build warning。
|
||||
- `2026-04-19` 这一轮把问题压实到了四类:仓库噪音、旧 dev 入口残留、前端越界运行时逻辑、巨型热点文件。
|
||||
- `2026-04-20` 这一轮进一步确认:前两类已经阶段性完成,当前真正剩下的是边界尾巴和新热点迁移。
|
||||
- 如果是要看当前清理和边界收口的最新状态,优先看 `ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`。
|
||||
- 如果是要看“当前可执行的优化点清单”,优先看 `CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`。
|
||||
- 如果是要做长期重构方案,从 `2026-04-19`、`2026-04-20` 与当前 dead-code batch 记录开始即可。
|
||||
@@ -0,0 +1,129 @@
|
||||
# server-node 冻结隔离说明(2026-04-24)
|
||||
|
||||
## 1. 当前状态
|
||||
|
||||
`server-node/` 已进入冻结隔离状态,不再作为可运行、可扩展、可引用的后端工程使用。
|
||||
|
||||
冻结原因:项目后端主线已经切到 `server-rs/` 的 Rust + SpacetimeDB 多 crate 方案,继续保留可执行的 `server-node/` 入口会误导后续开发,并增加提示词资产、AI 工作流与运行态逻辑的迁移漂移风险。
|
||||
|
||||
## 2. 冻结边界
|
||||
|
||||
1. 禁止新增任何以 `server-node/` 为目标的运行脚本、开发入口、CI 入口或工程依赖。
|
||||
2. 禁止新增从前端、Rust 后端、脚本或配置主动调用 `server-node/` 的逻辑。
|
||||
3. 禁止在 `server-node/` 内继续新增业务能力;后续能力必须落到 `server-rs/` 对应 crate。
|
||||
4. 历史文档、审计文档、迁移基线中允许保留 `server-node/` 作为旧系统来源说明,但不得把它描述成当前推荐实现。
|
||||
5. 第一批物理删除后,提示词资产与提示词相关工作流继续按迁移核对项追踪,不再恢复旧工程目录。
|
||||
|
||||
## 3. 删除前迁移核对项
|
||||
|
||||
以下资产曾作为删除前核对项。第一批物理删除后,旧实现不再从工作区直接读取;如需继续核对能力缺口,只允许通过历史提交、迁移文档或 `server-rs/` 已迁移实现追溯:
|
||||
|
||||
1. `server-node/src/prompts/customWorldEntityPrompts.ts`:自定义世界实体生成 prompt。
|
||||
2. `server-node/src/prompts/customWorldSceneNpcPrompts.ts`:自定义世界场景 NPC prompt。
|
||||
3. `server-node/src/prompts/questPrompts.ts`:任务意图识别 prompt。
|
||||
4. `server-node/src/prompts/runtimeItemPrompts.ts`:运行时物品意图识别 prompt。
|
||||
5. `server-node/src/prompts/customWorldOrchestratorPrompts.ts`:旧 Custom World JSON 生成与修复 prompt。
|
||||
6. `src/services/ai.ts` 与 `src/prompts/customWorldPrompts.ts` 中仍由前端承载的 AI orchestration / prompt 编排。
|
||||
|
||||
## 4. 工程防线
|
||||
|
||||
1. 第一批物理删除后,根目录 `package.json` 不再保留 `server-node:*`、`dev:node`、`check:server-node-freeze` 等旧入口。
|
||||
2. Vite 与本地开发脚本默认只指向 Rust `api-server`,不再保留 Node/Rust 后端切换开关。
|
||||
3. 历史文档允许保留旧 `server-node` 字样,但新增工程入口、脚本、依赖、运行说明不得再指向旧 Node 后端。
|
||||
4. 若后续需要恢复旧能力,只能迁移到 `server-rs/` 对应 crate 或 Axum facade,不恢复 `server-node/` 工程目录。
|
||||
|
||||
## 5. 后续处理顺序
|
||||
|
||||
1. 继续核对提示词资产与 prompt 工作流是否已完整落到 Rust 主线。
|
||||
2. 继续把前端残留业务编排迁入 `server-rs/`。
|
||||
3. 清理技术索引中容易误导当前入口的 Node / Express 文案。
|
||||
4. 保留历史审计材料,但不得把旧 Node 后端描述为当前推荐实现。
|
||||
|
||||
## 6. 已确认迁移项
|
||||
|
||||
### 6.1 场景幕背景图提示词
|
||||
|
||||
2026-04-25 已把旧 Node 自动资产链路中的场景幕背景图提示词包装迁移到 Rust 主线:
|
||||
|
||||
1. 旧来源:`server-node/src/services/customWorldAgentAutoAssetService.ts` 的 `buildSceneActPrompt(...)`。
|
||||
2. 新主源:`server-rs/crates/api-server/src/custom_world.rs` 的 `build_scene_act_background_image_prompt(...)`。
|
||||
3. 使用位置:`generate_draft_foundation_act_backgrounds(...)` 收集 `sceneChapterBlueprints[].acts[]` 后,先构造幕背景图专用提示词,再调用 `generate_custom_world_scene_image_for_profile(...)`。
|
||||
4. 保留语义:世界名、场景名、幕标题、幕摘要、幕目标、过渡钩子、主角色、辅助角色、世界气质、背景描述,以及“只生成环境背景,不出现角色立绘、站位 UI、对白框、按钮或文字”的约束。
|
||||
5. 迁移边界:`server-node/` 仅作为历史来源说明,不再参与运行;后续调整统一修改 Rust 主源。
|
||||
|
||||
## 7. 第一批安全删除记录(2026-04-25)
|
||||
|
||||
本批次开始把冻结隔离升级为物理删除。执行依据是项目后端主线已固定为 `server-rs/` 的 Rust + SpacetimeDB 多 crate 方案,旧 `server-node/` 不再作为可运行、可扩展、可引用的工程目录保留。
|
||||
|
||||
### 7.1 删除范围
|
||||
|
||||
1. 删除 `server-node/` 目录本体,旧实现只允许通过历史提交、迁移文档和已迁移到 `server-rs/` 的代码追溯。
|
||||
2. 删除旧 Node 后端专用入口:`scripts/dev-node.mjs`、`scripts/server-node-frozen.mjs`、`scripts/check-server-node-freeze.mjs`、`scripts/server-node-freeze-baseline.json`、`scripts/smoke-server-node.ts`、`scripts/smoke-same-origin-stack.ts`、`scripts/m7-api-compare.ts`、`scripts/deploy.sh`、`scripts/update.sh`、`view-llm-logs.ps1`。
|
||||
3. 根目录 `package.json` 删除 `server-node:*`、`dev:node`、`m7:api-compare` 与 `check:server-node-freeze` 等旧入口,并移除 `express`、`@types/express` 依赖。
|
||||
4. `npm run dev` 改为启动 Rust 本地栈;Vite 默认只代理到 Rust `api-server`,不再保留 `GENARRATIVE_BACKEND_STACK` 的 Node/Rust 双栈切换口。
|
||||
5. 清理 `.gitignore` 中只服务 `server-node/` 的忽略规则,并同步 `README.md`、`.env.example`、`server-rs/README.md` 与 `scripts/dev-server/README.md`。
|
||||
|
||||
### 7.2 暂不处理范围
|
||||
|
||||
1. 历史 PRD、审计、迁移基线中的 `server-node` 文案暂时保留为历史记录,不在第一批中大规模改写。
|
||||
2. `backend-rewrite-tasklist/` 中以旧 Node 后端为对照的迁移材料暂时保留,作为后续核对 Rust 主线能力缺口的历史审计输入。
|
||||
3. `src/services/ai.ts` 与 `src/prompts/customWorldPrompts.ts` 的前端残留编排不属于本批 Node 后端删除范围;后续继续按“前端只负责表现,业务逻辑进入 `server-rs/`”单独收口。
|
||||
|
||||
### 7.3 后续批次建议
|
||||
|
||||
1. 技术文档索引中的 Node / Express 后端条目只保留为历史资料,不再作为当前入口或推荐方案。
|
||||
2. 后续如继续整理历史文档,只把仍描述 `Express / PostgreSQL` 为当前目标架构的文字修正为“历史阶段口径”。
|
||||
3. 继续把前端残留业务逻辑迁入 `server-rs`;涉及 SpacetimeDB 的设计、实现、脚本和绑定继续显式使用相关 skill。
|
||||
|
||||
### 7.4 本轮安全核对结果
|
||||
|
||||
2026-04-25 本轮开始分批删除时,已确认第一批工程入口层面满足以下条件:
|
||||
|
||||
1. 工作区根目录下已不存在 `server-node/` 物理目录。
|
||||
2. `scripts/` 下已不存在旧 Node 后端专用运行、冻结、smoke、API 对比脚本。
|
||||
3. 根目录 `package.json` 不再包含 `server-node:*`、`dev:node`、`m7:api-compare` 与 `check:server-node-freeze` 入口。
|
||||
4. `package.json` 与 `package-lock.json` 不再包含 `express`、`@types/express`、`pg`、`postgres` 依赖包。
|
||||
5. `README.md`、`scripts/dev-server/README.md`、`server-rs/README.md`、`vite.config.ts`、`scripts/*.mjs`、`src/`、`packages/` 与 `server-rs/` 未发现仍主动启动或调用 `server-node` 的当前工程入口。
|
||||
|
||||
### 7.5 第二批删除边界
|
||||
|
||||
第二批不再删除可运行工程代码,而是清理“容易误导当前实现口径”的历史文档索引:
|
||||
|
||||
1. 只修正文档中仍把 `server-node`、Express 或 PostgreSQL 描述为当前推荐后端的句子。
|
||||
2. 保留审计、PRD、迁移基线中作为历史事实、旧实现来源、能力对照的 `server-node` 引用。
|
||||
3. 不大规模重写包含中文剧情、需求、审计结论的历史文档,避免把真实历史上下文抹平。
|
||||
4. 若发现某个历史文档仍指导新开发继续写 Node 后端,先把该文档改为“历史阶段口径”,再继续工程处理。
|
||||
|
||||
## 8. 开发命令与脚本复核(2026-04-26)
|
||||
|
||||
本轮按“`server-node/` 已完全移除”的状态复核当前开发入口、脚本和工程配置,确认不再保留旧 Node 后端或 Express 运行路径。
|
||||
|
||||
### 8.1 已复核范围
|
||||
|
||||
1. 根目录 `package.json` 与 `package-lock.json`。
|
||||
2. 根目录 `README.md`、`.env.example`、`.gitignore` 与 `vite.config.ts`。
|
||||
3. `scripts/`、`.github/`、`jenkins/` 与 `server-rs/` 下的已跟踪文本文件。
|
||||
|
||||
### 8.2 复核结论
|
||||
|
||||
1. `package.json` 中不存在 `server-node:*`、`dev:node`、`m7:api-compare`、`check:server-node-freeze` 等旧入口。
|
||||
2. `scripts/` 下不存在 `dev-node.mjs`、`smoke-server-node.ts`、`m7-api-compare.ts`、`smoke-same-origin-stack.ts` 等旧 Node 后端脚本。
|
||||
3. `package.json` 与 `package-lock.json` 中不存在 `express`、`@types/express`、`pg`、`postgres` 依赖。
|
||||
4. 当前开发入口继续固定为 `npm run dev`、`npm run dev:web`、`npm run api-server:maincloud` 与 Rust / SpacetimeDB 相关脚本,不恢复旧 Node 后端切换开关。
|
||||
|
||||
## 9. Caddy 本地服务入口移除(2026-04-26)
|
||||
|
||||
`serve:caddy` 仅服务旧的 dist 本地代理验证链路,不再属于当前 Rust / SpacetimeDB 主开发入口。本轮删除该入口和配套文件,避免开发命令继续暴露第二套本地服务方式。
|
||||
|
||||
### 9.1 删除范围
|
||||
|
||||
1. 根目录 `package.json` 删除 `serve:caddy`。
|
||||
2. 删除 `scripts/run-caddy-dev.mjs`。
|
||||
3. 删除 `tools/Caddyfile.dev`。
|
||||
4. `.env.example` 删除 `CADDY_API_UPSTREAM` 样例变量。
|
||||
|
||||
### 9.2 后续口径
|
||||
|
||||
1. 本地完整联调继续使用 `npm run dev`。
|
||||
2. 单独前端联调继续使用 `npm run dev:web` 并通过 Vite 代理到 Rust `api-server`。
|
||||
3. 生产包预览继续使用 Vite `preview`,不恢复 Caddy 专用开发入口。
|
||||
91
docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md
Normal file
91
docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 中文乱码位置清单
|
||||
|
||||
更新时间:`2026-03-24`
|
||||
|
||||
## 说明
|
||||
|
||||
- 本文档用于记录仓库内已确认或高置信度疑似存在中文乱码的位置。
|
||||
- 当前这份文档是重建版本;原有的 [`docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md`](/E:/Repos/Genarrative/docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md) 本身也已经乱码,因此已整体替换。
|
||||
- 本次整理依据:
|
||||
- 仓库内旧清单中的完整文件/行号信息
|
||||
- 本轮人工复核时再次直接看到的明显乱码位置
|
||||
- 由于仓库内同时存在“文件内容已写坏”和“终端/工具显示失真”两类情况,下面清单优先保留高置信位置,便于后续逐项修复。
|
||||
|
||||
## 扫描范围
|
||||
|
||||
- 已纳入:`src/`、`docs/`、根目录文档与元数据文件
|
||||
- 已排除:`.git/`、`node_modules/`、`dist/`、纯图片资源目录
|
||||
|
||||
## 高置信位置
|
||||
|
||||
### 文档与元数据
|
||||
|
||||
- [`docs/experience/AGENT_UI_CHANGELOG.md`](/E:/Repos/Genarrative/docs/experience/AGENT_UI_CHANGELOG.md):1, 3, 7, 9, 11-18, 24, 26-28, 32-33, 37, 39, 41-43, 47, 49, 51, 53-66, 68, 72, 74, 77-79, 83, 87, 89-90, 94, 96, 98-100, 104, 106-112, 116
|
||||
- [`UI_CODING_STANDARD.md`](/E:/Repos/Genarrative/UI_CODING_STANDARD.md):3, 91, 104, 108, 112, 156, 158, 160-166
|
||||
- [`metadata.json`](/E:/Repos/Genarrative/metadata.json):2-3
|
||||
|
||||
### 组件层
|
||||
|
||||
- [`src/components/AdventurePanel.tsx`](/E:/Repos/Genarrative/src/components/AdventurePanel.tsx):57, 65
|
||||
- [`src/components/CharacterPanel.tsx`](/E:/Repos/Genarrative/src/components/CharacterPanel.tsx):37, 65-66, 91-95, 102-103
|
||||
- [`src/components/GameCanvas.tsx`](/E:/Repos/Genarrative/src/components/GameCanvas.tsx):240, 462
|
||||
- [`src/components/GameShell.tsx`](/E:/Repos/Genarrative/src/components/GameShell.tsx):108, 116, 124, 138, 171, 181
|
||||
- [`src/components/InventoryPanel.tsx`](/E:/Repos/Genarrative/src/components/InventoryPanel.tsx):55, 58, 82-83, 181-184, 189, 191
|
||||
- [`src/components/MapModal.tsx`](/E:/Repos/Genarrative/src/components/MapModal.tsx):105, 108, 136
|
||||
- [`src/components/MedievalNpcAnimator.tsx`](/E:/Repos/Genarrative/src/components/MedievalNpcAnimator.tsx):124
|
||||
- [`src/components/NpcVisualEditor.tsx`](/E:/Repos/Genarrative/src/components/NpcVisualEditor.tsx):65, 69-71, 403, 440, 444, 446, 464, 467, 470, 482, 569, 571, 585, 610, 628, 662, 690, 694-695, 697, 722, 751, 759, 775, 777, 781, 824
|
||||
- [`src/components/PresetEditor.tsx`](/E:/Repos/Genarrative/src/components/PresetEditor.tsx):34-37, 43-44, 94, 96, 349, 470, 472, 480, 482, 512, 516, 519, 525, 568, 612, 618, 637, 639, 643, 645, 652, 661, 677, 740, 769, 771, 779, 781, 806, 809, 820, 831, 835, 837, 840, 848, 871, 894, 916, 918, 930, 932, 950, 953, 956, 960, 962, 990, 1004, 1006, 1012, 1018, 1024, 1030, 1036, 1064, 1120, 1122, 1130, 1132, 1150, 1153, 1156, 1172-1175, 1180, 1182, 1186, 1188, 1199, 1203-1204, 1208, 1240, 1242
|
||||
|
||||
### 数据层
|
||||
|
||||
- [`src/data/characterPresets.ts`](/E:/Repos/Genarrative/src/data/characterPresets.ts):97, 102, 104, 107, 129, 132-133, 142, 144, 170, 276, 302, 470, 496, 531, 540, 566, 699-700, 729, 972
|
||||
- [`src/data/medievalNpcVisuals.ts`](/E:/Repos/Genarrative/src/data/medievalNpcVisuals.ts):103, 115, 117, 119, 136, 154, 156, 161, 167, 174, 177, 189, 226, 235-236, 241, 244-245, 249-254, 256-257, 260, 262, 274, 278, 288, 451-453, 565, 568, 577, 592
|
||||
- [`src/data/monsterPresets.ts`](/E:/Repos/Genarrative/src/data/monsterPresets.ts):41-42, 54, 60-61, 79-80, 92, 98-99, 117-118, 136-137, 155-156, 171-173, 185, 191-192, 204, 210-211, 229-230, 242, 248-249, 261, 267-268, 280, 286-287, 304-305, 323-324, 335
|
||||
- [`src/data/monsters.ts`](/E:/Repos/Genarrative/src/data/monsters.ts):112
|
||||
- [`src/data/npcInteractions.ts`](/E:/Repos/Genarrative/src/data/npcInteractions.ts):68-71, 80, 82-83, 161, 165, 173, 182, 188-190, 196, 198, 205, 231, 241, 245, 255-260, 272, 296, 319-320, 372, 444-445, 449, 451, 453, 507, 569-570, 578-579, 587-588, 597, 605-606, 615, 617-618, 626-627, 634, 641-643, 652, 661, 665, 670, 672, 676
|
||||
- [`src/data/scenePresets.ts`](/E:/Repos/Genarrative/src/data/scenePresets.ts):115, 120, 122, 128, 133, 135, 141, 146, 148, 154, 159, 161, 167, 172, 174, 180, 185, 187, 192-193, 198, 200, 205-206, 211, 213, 219, 224, 226, 232, 237, 239, 245, 250, 252, 258, 263, 265, 274, 279, 281, 287, 292, 294, 299-300, 305, 307, 313, 318, 320, 326, 331, 333, 339, 344, 346, 352, 357, 359, 364-365, 370, 372, 377-378, 383, 385, 390-391, 396, 398, 404, 409, 411, 417, 422, 424, 509, 523, 525
|
||||
- [`src/data/stateFunctions.ts`](/E:/Repos/Genarrative/src/data/stateFunctions.ts):72-73, 80, 95-96, 103, 117-118, 125, 139-140, 147, 161-162, 169, 186-187, 194, 209-210, 217, 237-238, 255-256, 273-274, 294, 311-312, 329-330, 420, 430-431, 433-435, 437-438, 440-442, 444-445, 447, 449, 451-452, 454-456, 458, 460-461, 464, 466, 468, 484-485, 487, 489, 491, 493, 601, 618
|
||||
|
||||
### Hooks 与服务层
|
||||
|
||||
- [`src/hooks/useCombatFlow.ts`](/E:/Repos/Genarrative/src/hooks/useCombatFlow.ts):54, 56-58, 566
|
||||
- [`src/services/ai.ts`](/E:/Repos/Genarrative/src/services/ai.ts):200-201, 209-210, 234-235, 269-270, 309, 311, 317, 338, 341, 358, 382
|
||||
- [`src/services/prompt.ts`](/E:/Repos/Genarrative/src/services/prompt.ts):7-8, 10, 13-15, 19-20, 25-40, 43, 55, 61-62, 64, 66, 74-76, 78-79, 83-84, 87-90, 96, 103-104, 112, 115, 157, 159, 161-162, 164-165, 167-168, 170, 172-173
|
||||
|
||||
### 其他源码
|
||||
|
||||
- [`src/uiAssets.ts`](/E:/Repos/Genarrative/src/uiAssets.ts):54, 115, 122, 129, 142, 173, 180
|
||||
|
||||
## 本轮人工复核补充
|
||||
|
||||
以下位置是在本轮实现过程中直接再次看到的明显乱码文本,建议优先复查:
|
||||
|
||||
- [`src/hooks/useCombatFlow.ts`](/E:/Repos/Genarrative/src/hooks/useCombatFlow.ts):1094, 1554, 1556-1557
|
||||
|
||||
## 处理优先级建议
|
||||
|
||||
### 第一批
|
||||
|
||||
- `src/components/GameShell.tsx`
|
||||
- `src/components/InventoryPanel.tsx`
|
||||
- `src/components/CharacterPanel.tsx`
|
||||
- `src/data/characterPresets.ts`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/data/scenePresets.ts`
|
||||
- `src/services/prompt.ts`
|
||||
|
||||
### 第二批
|
||||
|
||||
- `src/components/PresetEditor.tsx`
|
||||
- `src/components/NpcVisualEditor.tsx`
|
||||
- `src/data/monsterPresets.ts`
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `docs/experience/AGENT_UI_CHANGELOG.md`
|
||||
- `UI_CODING_STANDARD.md`
|
||||
|
||||
## 备注
|
||||
|
||||
- 当前文档的目标是“先把位置收拢清楚”,不是直接修复乱码。
|
||||
- 如果你下一步要我继续,我可以基于这份清单继续做两件事之一:
|
||||
- 逐文件修复中文乱码
|
||||
- 先做一个“乱码修复优先级 + 替换建议”文档
|
||||
236
docs/audits/text/CURRENT_GAME_STORY_SOURCE_REVIEW_2026-04-07.md
Normal file
236
docs/audits/text/CURRENT_GAME_STORY_SOURCE_REVIEW_2026-04-07.md
Normal file
@@ -0,0 +1,236 @@
|
||||
# 当前游戏剧情原文整理与质量评测
|
||||
|
||||
日期:`2026-04-07`
|
||||
|
||||
## 总结先说
|
||||
- 当前游戏的剧情骨架已经能让玩家在武侠、仙侠两个世界里感到“我正在追一件事”,整体判断为:**部分达到预期**。
|
||||
- 强项在于:场景残痕、地图推进、NPC 保留、线程结构已经开始互相咬合。
|
||||
- 短板也很明确:强回收、强情感爆点、真正能改写后续理解的长线后果还没有完全跑起来。
|
||||
|
||||
## 方法
|
||||
- 先把当前仓库里的可扮演角色、场景、场景 NPC、宝藏残痕原文整理出来。
|
||||
- 再用现有 story engine 模块补出 ThemePack、WorldStoryGraph、ActorNarrativeProfile、KnowledgeGraph、ThreadContract、QA Report 和 Release Gate。
|
||||
- 最后按“玩家真实会感受到什么剧情”重组样章,并对照 PRD 的经典 RPG 体验目标做评测。
|
||||
|
||||
## 武侠世界
|
||||
|
||||
### 说明
|
||||
- “原文”部分整理的是当前仓库角色、场景、NPC 和残痕里已经存在的中文文本。
|
||||
- “引擎整理”部分是根据这些原文,经过 story engine 的主题包、线程图谱、角色叙事档案和 QA 规则重新编译出的结构化结果。
|
||||
|
||||
### 项目内原始剧情文本整理
|
||||
### 可扮演角色原文
|
||||
- 剑之公主 / 王庭剑姬
|
||||
角色原文:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
背景原文:王庭旁支出身,自幼被当作执剑者培养。一次宫变让她失去旧有庇护,也背上了亲手追回王室誓剑与真相的责任。
|
||||
表层来意:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
背景原文:曾是边境游骑与斥候,被一场伏击逼得离开旧军阵。如今他只信自己亲眼见过的风向与箭路,却仍背着守住边境故土的旧誓。
|
||||
表层来意:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
- 双刃旅者 / 疾影斥候
|
||||
角色原文:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
背景原文:她在暗巷与帮派追杀中长大,学会靠速度、直觉和先手活下去。表面上轻快利落,心里却一直在追查那封改变命运的密信去向。
|
||||
表层来意:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
|
||||
### 场景角色原文
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
保留线索:曾是边境游骑与斥候,被一场伏击逼得离开旧军…
|
||||
- 青鳞毒蛇 / 敌对角色
|
||||
角色原文:身形细长,吐信极快,最喜欢守在草木掩映和石缝交错之地。
|
||||
保留线索:青鳞毒蛇长期出没于竹林古道。身形细长,吐信…
|
||||
- 枯藤伏虫 / 敌对角色
|
||||
角色原文:像一截会蠕动的枯藤,贴地潜行,适合在林地和湿地里伏击。
|
||||
保留线索:枯藤伏虫长期出没于竹林古道。像一截会蠕动的…
|
||||
- 樵夫老周 / 樵夫
|
||||
角色原文:常在竹海边缘砍柴,对附近路数和兽踪了如指掌。
|
||||
保留线索:樵夫老周长期出没于竹林古道。常在竹海边缘砍…
|
||||
- 玄甲战锋 / 重装先锋
|
||||
角色原文:攻守兼备,推进稳健,适合喜欢扎实前排风格的玩家。
|
||||
保留线索:他长期担任重装前锋,习惯站在最危险的位置替…
|
||||
- 石背蜗怪 / 敌对角色
|
||||
角色原文:驮着厚重石壳缓慢爬行,常盘踞在石阶、桥边与潮湿山路上。
|
||||
保留线索:石背蜗怪长期出没于山门石阶。驮着厚重石壳缓…
|
||||
|
||||
### 场景原文整理
|
||||
- 竹林古道
|
||||
场景原文:风过竹叶如刀鸣,窄道蜿蜒向深处,最适合藏伏毒物和游侠。
|
||||
第一残痕:竹根旁半埋的刀鞘
|
||||
场景角色:神箭游侠(流风弓卫)、青鳞毒蛇(敌对角色)、枯藤伏虫(敌对角色)
|
||||
- 山门石阶
|
||||
场景原文:青石阶层层向上,旧山门半开半掩,守山人与伏兽都能藏得很稳。
|
||||
第一残痕:裂缝里的铜钥
|
||||
场景角色:玄甲战锋(重装先锋)、石背蜗怪(敌对角色)、岩甲蛛兽(敌对角色)
|
||||
- 雨夜长街
|
||||
场景原文:长街积水映灯,屋檐下尽是藏身空隙,最易碰见追踪者与夜行客。
|
||||
第一残痕:灯檐下浸湿的布包
|
||||
场景角色:双刃旅者(疾影斥候)、夜牙潜兽(敌对角色)、孢爆菇灵(敌对角色)
|
||||
- 荒村断垣
|
||||
场景原文:残墙和空屋挤成一团,风里总像夹着旧哭声与游荡脚步。
|
||||
第一残痕:断墙后压着的木匣
|
||||
场景角色:断骨祟灵(敌对角色)、孢爆菇灵(敌对角色)、守村妇人(遗民)
|
||||
- 古桥渡口
|
||||
场景原文:桥面潮湿,渡口雾重,来往之人不多,但每个身影都藏着故事。
|
||||
第一残痕:桥柱缝里的油纸包
|
||||
场景角色:双刃旅者(疾影斥候)、石背蜗怪(敌对角色)、夜牙潜兽(敌对角色)
|
||||
|
||||
### 引擎整理出的明线
|
||||
- 旧宫旧案仍在牵动江湖局势:旧宫旧案仍在牵动江湖局势,焦点常落在竹林古道。
|
||||
- 护送线:边关与地宫残痕正在把旧事重新拖回台前,焦点常落在山门石阶。
|
||||
- 回收线:当前武侠世界不是单点冒险,而是一张由边关军需、渡口风声、地宫旧痕和宫苑旧案交叉拉紧的追查网络。,焦点常落在雨夜长街。
|
||||
- 分歧对峙线:沿着场景残痕和人物试探,一步步追清边关与宫苑旧案背后的真相,焦点常落在荒村断垣。
|
||||
|
||||
### 引擎整理出的暗线
|
||||
- 神箭游侠的隐线:神箭游侠并不只是流风弓卫,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。
|
||||
- 青鳞毒蛇的隐线:青鳞毒蛇并不只是敌对角色,他与护送线之间还有一段未被说破的牵连。
|
||||
- 枯藤伏虫的隐线:枯藤伏虫并不只是敌对角色,他与回收线之间还有一段未被说破的牵连。
|
||||
- 樵夫老周的隐线:樵夫老周并不只是樵夫,他与分歧对峙线之间还有一段未被说破的牵连。
|
||||
- 玄甲战锋的隐线:玄甲战锋并不只是重装先锋,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。
|
||||
|
||||
### 场景旧痕
|
||||
- 竹林古道留下的旧痕:表层残痕是“风过竹叶如刀鸣,窄道蜿蜒向深处,最适合藏伏毒物和游侠。”;压着的真相是“神箭游侠并不只是流风弓卫,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。”
|
||||
- 山门石阶留下的旧痕:表层残痕是“青石阶层层向上,旧山门半开半掩,守山人与伏兽都能藏得很稳。”;压着的真相是“青鳞毒蛇并不只是敌对角色,他与护送线之间还有一段未被说破的牵连。”
|
||||
- 雨夜长街留下的旧痕:表层残痕是“长街积水映灯,屋檐下尽是藏身空隙,最易碰见追踪者与夜行客。”;压着的真相是“枯藤伏虫并不只是敌对角色,他与回收线之间还有一段未被说破的牵连。”
|
||||
- 荒村断垣留下的旧痕:表层残痕是“残墙和空屋挤成一团,风里总像夹着旧哭声与游荡脚步。”;压着的真相是“樵夫老周并不只是樵夫,他与分歧对峙线之间还有一段未被说破的牵连。”
|
||||
- 古桥渡口留下的旧痕:表层残痕是“桥面潮湿,渡口雾重,来往之人不多,但每个身影都藏着故事。”;压着的真相是“玄甲战锋并不只是重装先锋,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。”
|
||||
|
||||
### 玩家在游戏中真实感受到的剧情样章
|
||||
你来到这个武侠世界,是为追查失落王庭誓剑流入江湖的踪迹。此行最重要的目标,是在诸门派与野心家之前找回誓剑,并逼出宫变幕后之人。 第一眼看到的不是纯说明,而是 边关营地 里的环境压迫:营火与旌旗都带着风沙味,士卒、斥候和异兽都可能在这里短暂停留。
|
||||
走进边关营地时,玩家实际感受到的核心不是“到了新地图”,而是“营火与旌旗都带着风沙味,士卒、斥候和异兽都可能在这里短暂停留。”。这句场景原文会立刻把体验拉回到“旧宫旧案仍在牵动江湖局势”这条明线。神箭游侠表面只是流风弓卫,但他的公开面是“擅长远距离压制与精准射击,节奏灵活,机动性很强。”,真正压在肩上的却是“找出贩卖军情的人,并截回被转移的军械账册”。而像“废营帐里的箭囊”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,边关营地背后会逐渐显出“神箭游侠并不只是流风弓卫,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进雨夜长街时,玩家实际感受到的核心不是“到了新地图”,而是“长街积水映灯,屋檐下尽是藏身空隙,最易碰见追踪者与夜行客。”。这句场景原文会立刻把体验拉回到“护送线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“夺回密信,查清究竟是谁把你推上了被追杀的路”。而像“灯檐下浸湿的布包”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,雨夜长街背后会逐渐显出“青鳞毒蛇并不只是敌对角色,他与护送线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进古桥渡口时,玩家实际感受到的核心不是“到了新地图”,而是“桥面潮湿,渡口雾重,来往之人不多,但每个身影都藏着故事。”。这句场景原文会立刻把体验拉回到“回收线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“夺回密信,查清究竟是谁把你推上了被追杀的路”。而像“桥柱缝里的油纸包”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,古桥渡口背后会逐渐显出“枯藤伏虫并不只是敌对角色,他与回收线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
因此,武侠世界目前最容易让玩家产生真实剧情感的地方,不是某一句高光台词,而是“场景描述 -> 人物保留 -> 残痕线索 -> 线程压力”这条连续链路。它已经能让玩家觉得自己在追一件还没完全揭开的事,但离“经典 RPG 式的强收束和强情感爆点”还差最后一层回响回收。
|
||||
|
||||
### 质量评测
|
||||
整体判断:**部分达成预期**
|
||||
|
||||
### 维度评测
|
||||
- 角色记忆点:达成。当前可扮演角色的人设、背景、开局动机和首遇目标已经能形成第一轮代入,玩家能记住“谁在上路、为什么上路”。
|
||||
- 低关系也有戏:达成。低好感或首遇 NPC 不再只是“更冷淡”,而是能从当前压力、错位说辞和反应钩子里带出暗线存在感。
|
||||
- 世界互文与旧史厚度:达成。场景、NPC、旧痕和线程已经能互相指向同一批旧事,不再只是各自独立的设定块。
|
||||
- 空间与残痕叙事:达成。地点不是纯背景图,场景描述、宝藏线索和 narrative residue 已经能共同承担“空间会说话”的职责。
|
||||
- 选择后果与主线抓手:部分达成。当前任务抓手和线程合约已经存在,但真正影响关系、理解和后续回响的后果层还没有被完全跑满。
|
||||
- 长线回响与收束:未达成。从 QA 结果看,当前版本最明显的短板仍是“已经埋下的线,后面有没有被稳定回收”。这一步决定它能不能真正跨到经典 RPG 质感。
|
||||
|
||||
### 客观检查
|
||||
- Narrative QA:4 条明线 / 1 条问题。
|
||||
- Release Gate:warn。当前版本可继续观察,但仍有若干 narrative 风险。
|
||||
- Simulation:共跑了 3 条 simulation,ending family 1 类,单次最高 QA 问题 1 条。
|
||||
|
||||
### 当前主要问题
|
||||
- 有线程合约尚未在 chronicle 中留下足够的回收痕迹。
|
||||
|
||||
## 仙侠世界
|
||||
|
||||
### 说明
|
||||
- “原文”部分整理的是当前仓库角色、场景、NPC 和残痕里已经存在的中文文本。
|
||||
- “引擎整理”部分是根据这些原文,经过 story engine 的主题包、线程图谱、角色叙事档案和 QA 规则重新编译出的结构化结果。
|
||||
|
||||
### 项目内原始剧情文本整理
|
||||
### 可扮演角色原文
|
||||
- 剑之公主 / 王庭剑姬
|
||||
角色原文:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
背景原文:王庭旁支出身,自幼被当作执剑者培养。一次宫变让她失去旧有庇护,也背上了亲手追回王室誓剑与真相的责任。
|
||||
表层来意:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
背景原文:曾是边境游骑与斥候,被一场伏击逼得离开旧军阵。如今他只信自己亲眼见过的风向与箭路,却仍背着守住边境故土的旧誓。
|
||||
表层来意:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
- 双刃旅者 / 疾影斥候
|
||||
角色原文:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
背景原文:她在暗巷与帮派追杀中长大,学会靠速度、直觉和先手活下去。表面上轻快利落,心里却一直在追查那封改变命运的密信去向。
|
||||
表层来意:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
|
||||
### 场景角色原文
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
保留线索:曾是边境游骑与斥候,被一场伏击逼得离开旧军…
|
||||
- 玄甲战锋 / 重装先锋
|
||||
角色原文:攻守兼备,推进稳健,适合喜欢扎实前排风格的玩家。
|
||||
保留线索:他长期担任重装前锋,习惯站在最危险的位置替…
|
||||
- 秘匣书妖 / 敌对角色
|
||||
角色原文:像会自行翻页的秘典与宝匣,常在仙门、遗迹与禁制附近浮游。
|
||||
保留线索:秘匣书妖长期出没于云海仙门。像会自行翻页的…
|
||||
- 噬雾飞蛾 / 敌对角色
|
||||
角色原文:借雾气遮身,飞行轨迹诡谲,喜欢围着灵光和人影打转。
|
||||
保留线索:噬雾飞蛾长期出没于云海仙门。借雾气遮身,飞…
|
||||
- 守门灵官 / 门官
|
||||
角色原文:站在门阙侧旁观来者,像在等一份迟迟未到的回报。
|
||||
保留线索:守门灵官长期出没于云海仙门。站在门阙侧旁观…
|
||||
- 幽烬灵蝠 / 敌对角色
|
||||
角色原文:翅翼缭绕灰烬般的灵火,常成群出没于洞天、崖壁与灵脉附近。
|
||||
保留线索:幽烬灵蝠长期出没于悬空仙岛。翅翼缭绕灰烬般…
|
||||
|
||||
### 场景原文整理
|
||||
- 云海仙门
|
||||
场景原文:云阶在脚下翻涌,门阙后方灵光不断,来客与守门异物都极显眼。
|
||||
第一残痕:云阶尽头的灵符匣
|
||||
场景角色:神箭游侠(流风弓卫)、玄甲战锋(重装先锋)、秘匣书妖(敌对角色)
|
||||
- 悬空仙岛
|
||||
场景原文:浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。
|
||||
第一残痕:浮岛边缘的灵羽匣
|
||||
场景角色:幽烬灵蝠(敌对角色)、噬雾飞蛾(敌对角色)、云栖散修(散修)
|
||||
- 天宫长廊
|
||||
场景原文:廊柱之间回响着空灵风声,禁制和书妖都喜欢寄在这类高处回廊里。
|
||||
第一残痕:廊柱暗槽里的玉简
|
||||
场景角色:剑之公主(王庭剑姬)、玄甲战锋(重装先锋)、秘匣书妖(敌对角色)
|
||||
- 灵药花圃
|
||||
场景原文:灵草灵花层层叠开,香气诱人,却也最容易养出食灵的怪物。
|
||||
第一残痕:药圃深处的灵壶
|
||||
场景角色:噬灵妖花(敌对角色)、血瞳妖眼(敌对角色)、药圃执事(药师)
|
||||
- 寒玉洞天
|
||||
场景原文:洞壁结着寒玉光泽,地面湿滑,水灵和阴性异物都爱停在这里。
|
||||
第一残痕:寒玉裂隙里的灵髓
|
||||
场景角色:青腐泥灵(敌对角色)、幽烬灵蝠(敌对角色)、澄潮灵母(敌对角色)
|
||||
|
||||
### 引擎整理出的明线
|
||||
- 灵脉与封印正在失衡:灵脉与封印正在失衡,焦点常落在云海仙门。
|
||||
- 追索线:宗门旧案与秘境争夺彼此缠住了当下局势,焦点常落在悬空仙岛。
|
||||
- 封印失衡线:当前仙侠世界由宗门秩序、秘境余波、灵脉封印和古仙残迹共同推着故事前进,玩家每深入一层,都会撞上新的旧事回响。,焦点常落在天宫长廊。
|
||||
- 宗门旧案线:顺着灵痕、残识和人物保留,一层层摸清宗门旧案与秘境失衡的根源,焦点常落在灵药花圃。
|
||||
|
||||
### 引擎整理出的暗线
|
||||
- 神箭游侠的隐线:神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。
|
||||
- 玄甲战锋的隐线:玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。
|
||||
- 秘匣书妖的隐线:秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。
|
||||
- 噬雾飞蛾的隐线:噬雾飞蛾并不只是敌对角色,他与宗门旧案线之间还有一段未被说破的牵连。
|
||||
- 守门灵官的隐线:守门灵官并不只是门官,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。
|
||||
|
||||
### 场景旧痕
|
||||
- 云海仙门留下的旧痕:表层残痕是“云阶在脚下翻涌,门阙后方灵光不断,来客与守门异物都极显眼。”;压着的真相是“神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”
|
||||
- 悬空仙岛留下的旧痕:表层残痕是“浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。”;压着的真相是“玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。”
|
||||
- 天宫长廊留下的旧痕:表层残痕是“廊柱之间回响着空灵风声,禁制和书妖都喜欢寄在这类高处回廊里。”;压着的真相是“秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。”
|
||||
- 灵药花圃留下的旧痕:表层残痕是“灵草灵花层层叠开,香气诱人,却也最容易养出食灵的怪物。”;压着的真相是“噬雾飞蛾并不只是敌对角色,他与宗门旧案线之间还有一段未被说破的牵连。”
|
||||
- 寒玉洞天留下的旧痕:表层残痕是“洞壁结着寒玉光泽,地面湿滑,水灵和阴性异物都爱停在这里。”;压着的真相是“守门灵官并不只是门官,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”
|
||||
|
||||
### 玩家在游戏中真实感受到的剧情样章
|
||||
你来到这个仙侠世界,是因为王庭圣印坠入了云海裂隙。此行最重要的目标,是寻回圣印,截断那些企图借它开启天门禁制的野心。 第一眼看到的不是纯说明,而是 星舟甲板 里的环境压迫:甲板横在高天之上,风压和星光都很强,飞行异物最爱在这里盘旋。
|
||||
走进星舟甲板时,玩家实际感受到的核心不是“到了新地图”,而是“甲板横在高天之上,风压和星光都很强,飞行异物最爱在这里盘旋。”。这句场景原文会立刻把体验拉回到“灵脉与封印正在失衡”这条明线。神箭游侠表面只是流风弓卫,但他的公开面是“擅长远距离压制与精准射击,节奏灵活,机动性很强。”,真正压在肩上的却是“找回星图核心,查清是谁击落了你的船队”。而像“舵台后的星图匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,星舟甲板背后会逐渐显出“神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进悬空仙岛时,玩家实际感受到的核心不是“到了新地图”,而是“浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。”。这句场景原文会立刻把体验拉回到“追索线”这条明线。云栖散修表面只是散修,但他的公开面是“常坐在浮岛边缘打坐,对天风和禁制的变化很敏感。”,真正压在肩上的却是“在悬空仙岛守住自己不愿失去的那一层秩序。”。而像“浮岛边缘的灵羽匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,悬空仙岛背后会逐渐显出“玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进月湖仙洲时,玩家实际感受到的核心不是“到了新地图”,而是“湖光像铺开的镜面,水灵、章灵与花影都可能从月色里浮出来。”。这句场景原文会立刻把体验拉回到“封印失衡线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“找到残阵核心,并弄明白信里提到的“第二个你”究竟是谁”。而像“湖岸边漂来的玉匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,月湖仙洲背后会逐渐显出“秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
因此,仙侠世界目前最容易让玩家产生真实剧情感的地方,不是某一句高光台词,而是“场景描述 -> 人物保留 -> 残痕线索 -> 线程压力”这条连续链路。它已经能让玩家觉得自己在追一件还没完全揭开的事,但离“经典 RPG 式的强收束和强情感爆点”还差最后一层回响回收。
|
||||
|
||||
### 质量评测
|
||||
整体判断:**部分达成预期**
|
||||
|
||||
### 维度评测
|
||||
- 角色记忆点:达成。当前可扮演角色的人设、背景、开局动机和首遇目标已经能形成第一轮代入,玩家能记住“谁在上路、为什么上路”。
|
||||
- 低关系也有戏:达成。低好感或首遇 NPC 不再只是“更冷淡”,而是能从当前压力、错位说辞和反应钩子里带出暗线存在感。
|
||||
- 世界互文与旧史厚度:达成。场景、NPC、旧痕和线程已经能互相指向同一批旧事,不再只是各自独立的设定块。
|
||||
- 空间与残痕叙事:达成。地点不是纯背景图,场景描述、宝藏线索和 narrative residue 已经能共同承担“空间会说话”的职责。
|
||||
- 选择后果与主线抓手:部分达成。当前任务抓手和线程合约已经存在,但真正影响关系、理解和后续回响的后果层还没有被完全跑满。
|
||||
- 长线回响与收束:未达成。从 QA 结果看,当前版本最明显的短板仍是“已经埋下的线,后面有没有被稳定回收”。这一步决定它能不能真正跨到经典 RPG 质感。
|
||||
|
||||
### 客观检查
|
||||
- Narrative QA:4 条明线 / 1 条问题。
|
||||
- Release Gate:warn。当前版本可继续观察,但仍有若干 narrative 风险。
|
||||
- Simulation:共跑了 3 条 simulation,ending family 1 类,单次最高 QA 问题 1 条。
|
||||
|
||||
### 当前主要问题
|
||||
- 有线程合约尚未在 chronicle 中留下足够的回收痕迹。
|
||||
|
||||
## 最终结论
|
||||
- 如果目标只是“让玩家进入游戏后立刻感觉世界里有事正在发生”,当前文本资产已经够用,且部分环节已经明显跑起来了。
|
||||
- 如果目标是“对标经典单机 RPG 的强角色回响、强关系后果、强主线收束”,当前版本还只能算走到了一半,最该补的是 payoff 和长线回响。
|
||||
- 也就是说:**当前剧情原文的底座已经部分达到预期,但还没到可以完全放心交给玩家沉浸式吃剧情的程度。**
|
||||
@@ -0,0 +1,276 @@
|
||||
# 游戏 UI / 预设 / 编辑器 / npcInteraction / prompt 文本深度审计
|
||||
|
||||
日期:`2026-04-02`
|
||||
|
||||
## 说明
|
||||
|
||||
- 本文档基于当前仓库源码再次深搜,不直接沿用旧审计结论。
|
||||
- 审计目标:找出“可能出现在游戏 UI、预设、编辑器 UI、生成链路中的文本”里,仍然存在的:
|
||||
- `中文乱码`
|
||||
- `英文直出`
|
||||
- `中英混用`
|
||||
- 本轮重点加查:
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/characterChatPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- 说明口径:
|
||||
- “会显示给玩家/编辑器使用者”的文本,按高优先级记录。
|
||||
- “内部英文枚举/键名,但可能泄露到 prompt、编辑器或预览”的内容,也单独记录。
|
||||
- 已经转成中文且当前复查无明显问题的区域,会标记为“复查通过”。
|
||||
|
||||
## 结论摘要
|
||||
|
||||
- 当前最严重的文本污染源不是单一 UI,而是两条链路同时存在问题:
|
||||
- 运行时弹窗 / 实体详情 / NPC 交易招募弹窗
|
||||
- `prompt` 生成链路
|
||||
- `src/services/prompt.ts` 是当前最重灾区,既有大面积中文乱码,也混有英文结构词,会直接影响 AI 生成质量。
|
||||
- `src/data/npcInteractions.ts` 里“话题 actionText / detailText”大体已是正常中文,但商人来源匹配、库存种子物品类别/名称仍有明显乱码,而且阶段枚举仍是英文值。
|
||||
- 预设编辑器仍然是英文和乱码高密度区,尤其是:
|
||||
- `CharacterPresetPanel.tsx`
|
||||
- `MonsterPresetPanel.tsx`
|
||||
- `SceneNpcPresetPanel.tsx`
|
||||
- `ScenePresetPanel.tsx`
|
||||
- `StateFunctionEditor.tsx`
|
||||
- 自定义世界 NPC/场景编辑器、NPC 视觉编辑器大体已转中文,但还残留 `NPC`、`AI`、`Shift` 等中英混用。
|
||||
|
||||
## 一、游戏主流程 UI 与运行时面板
|
||||
|
||||
### 1.1 复查通过
|
||||
|
||||
| 文件 | 行号 | 当前状态 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `47-49` | 通过 | 开场联系方式已改成 `QQ群`、`微信` |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `147` | 通过 | 场景名兜底已改成 `当前区域` |
|
||||
| `src/components/adventure-panel/AdventurePanelOverlays.tsx` | `137-158` | 通过 | 任务目标眉标、宝藏踪迹、切磋会话等主文案已是中文 |
|
||||
|
||||
### 1.2 仍有问题
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `81`、`89` | 中英混用 | `正在生成核心NPC...` | `NPC` 仍在中文进度文案里直出 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `151` | 中文乱码 | `闃熶紞` / `鑳屽寘` | 队伍/背包弹层标题已写坏 |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `200-201` | 英文直出 | `GENARRATIVE` | 运行时头部品牌字样仍为英文 |
|
||||
| `src/components/adventure-panel/AdventurePanelOverlays.tsx` | `140` | 中英混用 | `未知敌对 NPC` | 已非乱码,但仍混入 `NPC` |
|
||||
|
||||
## 二、实体详情、NPC 交互弹窗、交易/招募 UI
|
||||
|
||||
### 2.1 `AdventureEntityModal.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/AdventureEntityModal.tsx` | `111` | 中文乱码 | `鏁屽 NPC` | hostile badge 已坏,同时混入 `NPC` |
|
||||
| `src/components/AdventureEntityModal.tsx` | `113`、`137-146` | 英文直出 | `NPC`、`Player`、`Companion` | 标题/副标题兜底值仍为英文 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `221`、`264`、`272`、`283`、`296`、`306` | 英文直出 | `Portrait`、`Status`、`Relation`、`Attributes`、`Encounter`、`Inventory` | 六个主区块标题都未本地化 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `266-267` | 英文直出 | `HP`、`MP` | 状态条标签未本地化 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `274-275` | 英文直出 | `Affinity`、`Recruited: Yes/No` | 关系区块仍是英文 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `298-301` | 英文直出 | `Name`、`Context`、`Type`、`Battle mode` | 遭遇信息区块仍是英文 |
|
||||
|
||||
### 2.2 `NpcModals.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/NpcModals.tsx` | `251-252` | 英文直出 | `NPC inventory` / `Your inventory` / `items` | 交易栏标题和数量单位仍是英文 |
|
||||
| `src/components/NpcModals.tsx` | `272` | 英文直出 | `This NPC has nothing to sell right now.` / `You have nothing to sell right now.` | 空状态未本地化 |
|
||||
| `src/components/NpcModals.tsx` | `290` | 英文直出 | `Purchase total` / `Sale total` | 交易总价标题未本地化 |
|
||||
| `src/components/NpcModals.tsx` | `297` | 中文乱码 | 大段价格不足提示 | 购买资金不足提示整段已坏 |
|
||||
| `src/components/NpcModals.tsx` | `303` | 中文乱码 | 大段默认说明 | 未选中物品时的说明区整段已坏 |
|
||||
| `src/components/NpcModals.tsx` | `350-399` | 英文直出 | `Item details`、`NPC item`、`Stock`、`Value`、`Purchase price`、`Buyback price`、`Slot`、`Not equippable`、`Usable immediately`、`Tags`、`None` | 物品详情弹窗几乎整屏英文 |
|
||||
| `src/components/NpcModals.tsx` | `404` | 中文乱码 + 中英混用 | 含 `MP` 的恢复说明 | 物品使用效果提示已坏 |
|
||||
| `src/components/NpcModals.tsx` | `465` | 中文乱码 | 好感变动提示 | 交易结果反馈文案已坏 |
|
||||
| `src/components/NpcModals.tsx` | `500-501` | 英文直出 | `Manage companion slot`、`Select a current companion to rotate out before recruiting this NPC.` | 招募替换同伴弹窗未本地化 |
|
||||
|
||||
## 三、预设编辑器与编辑器 UI
|
||||
|
||||
### 3.1 复查通过或基本通过
|
||||
|
||||
| 文件 | 行号 | 当前状态 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `242` | 通过 | 图片路径占位文案已中文化,不再暴露 `URL` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `463` | 基本通过 | 空状态是中文,但仍混入 `NPC` |
|
||||
| `src/components/CustomWorldNpcVisualEditor.tsx` | `88-91`、`552-765` | 基本通过 | 主体编辑项、装备类型、素材、姿态等基本都为中文 |
|
||||
|
||||
### 3.2 标签、枚举、面板标题问题
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/shared.ts` | `43` | 英文直出 | `NPC` | 预设编辑器顶层页签仍用英文 |
|
||||
| `src/components/preset-editor/shared.ts` | `62-67` | 英文枚举外露 | `idle`、`move`、`attack`、`die` | 怪物动画候选仍是英文值 |
|
||||
| `src/components/preset-editor/shared.ts` | `69-74` | 英文枚举外露 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能风格候选仍是英文值 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `702-708` | 中英混用 | `NPC 视觉编辑器` | 中文标题中混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `718` | 中英混用 | `当前 NPC` | 选择器标签混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `976-977` | 中英混用 | `拖动标记微调 NPC 的预览布局。移动时按住 Shift...` | 混入 `NPC`、`Shift` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `482-483` | 中英混用 | `AI生成NPC形象`、`NPC 形象 AI 生成功能仍在开发中。` | 模态标题与副标题仍大量混用英文术语 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `635-636` | 中英混用 | `新增 NPC`、`编辑 NPC` | 主标题和副标题混入 `NPC` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `734`、`762-763` | 中英混用 | `AI生成`、`AI生成场景`、`场景图片 AI 生成功能仍在开发中。` | 场景生成入口仍混入 `AI` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `792-793` | 中英混用 | `npc-...`、`自定义NPC...` | 新建 NPC 默认 ID/名称混有英文前缀与 `NPC` |
|
||||
|
||||
### 3.3 `CharacterPresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `262`、`264`、`277` | 中文乱码 | `瑙掕壊`、`淇濆瓨瑙掕壊瑕嗙洊` | 选择卡标题、下拉标签、保存按钮均已坏 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `320`、`326` | 中文乱码 | `鍔ㄧ敾`、`闁煎啿...` | 动画/世界标签已坏 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `418`、`427` | 中文乱码 | `涓栫晫`、`棰勮鎬墿` | 技能预览区字段标签已坏 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `313-314`、`402-403` | 通过 | `角色详情`、`技能预览` | 主体段落标题已是正常中文 |
|
||||
|
||||
### 3.4 `MonsterPresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `49-50` | 英文直出 | `Saved monster overrides...`、`Failed to save monster overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `58-59` | 中文乱码 | 空状态整段提示 | 无怪物时的空态文案已坏 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `124-126` | 英文直出 | `Section`、`Editor section.`、`Field` | 左侧选择卡是占位英文 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `135` | 中文乱码 | `闂?` | 世界与名字之间的分隔符已坏 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `139` | 英文直出 | `Save Monster Overrides` | 保存按钮未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `158-159` | 英文直出 | `Monster Override Preview`、`Editor section.` | 右侧预览卡标题/说明未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `165`、`218`、`223`、`228`、`240`、`248`、`256` | 英文直出 | `Field`、`Name`、`Intro Action` | 多个字段标签仍是英文或占位文案 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `335` | 中文乱码 | 一段动画配置标签乱码 | 帧数相关字段标题已坏 |
|
||||
|
||||
### 3.5 `SceneNpcPresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `159` | 英文直出 | `No NPC presets are available.` | 空状态未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `177-193` | 英文直出 | `NPC Library`、`Browse and select an NPC preset.`、`NPC ID`、`Save NPC Overrides` | 选择区整块未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `221-238` | 英文直出 | `Skill Preview`、`Skill`、`World` | 技能预览区未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `258-259` | 中文乱码 | 空状态/说明整段乱码 | 预览区已有损坏文本 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `264-268` | 英文直出 | `Visual Preview`、`Hostile NPCs use monster presets...`、`Narrative NPCs can preview...` | 视觉预览说明未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `310-357` | 英文直出 | `NPC Details`、`NPC ID`、`Name`、`Role`、`Avatar`、`Linked Character ID`、`Monster Preset ID`、`Initial Affinity`、`Description` | 详情字段整体未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `363` | 中文乱码 | 预览说明大段乱码 | NPC 预览描述区已坏 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `371-375` | 英文直出 | `Visual Editor`、`Hostile NPCs cannot use the visual editor...` | 可视编辑器说明未本地化 |
|
||||
|
||||
### 3.6 `ScenePresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `105-108` | 英文直出 | `Treasure Ahead`、`Treasure` | 宝藏预览实体名/头像仍是英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `132-133` | 英文直出 | `Scene Library`、`Browse and select a scene preset.` | 左侧选择区未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `162` | 英文直出 | `Save` | 保存按钮未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `170-181` | 英文直出 | `Scene Preview`、`Preview Mode`、`Monster Preview`、`NPC Preview`、`Treasure Preview`、`Empty` | 预览模式整组未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `207-226` | 英文直出 | `Hostile NPCs`、`NPCs`、`Treasure Hint`、`None` | 场景摘要卡未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `233-299` | 英文直出 | `Scene Details`、`Scene ID`、`World`、`Name`、`Description`、`Image Source`、`Forward Scene`、`Unset`、`Connected Scene IDs`、`Monster IDs`、`Treasure Hints`、`NPCs In Scene` | 详情编辑区整块未本地化 |
|
||||
|
||||
### 3.7 `StateFunctionEditor.tsx` 与共享请求层
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1060-1064` | 英文直出 | `Failed to save option behavior overrides`、`Option behavior overrides saved.` | 保存结果提示未本地化 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1138` | 中英混用 | `GameState` | 预览说明里仍混入英文类型名 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1143` | 中英混用 | `敌对NPC资源` | `NPC` 混入字段标签 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1185` | 英文枚举外露 | `AnimationState` 原始值 | 玩家动作下拉会直接显示英文枚举值 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1190` | 英文占位符外露 | `{monster}` | 占位提示面向编辑器用户直接可见 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1191` | 英文枚举外露 | `idle`、`move`、`attack` | 怪物动画下拉仍使用英文值 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1213-1217` | 基本通过 | `稳扎稳打`、`爆发`、`机动` 等 | 技能权重显示标签已是中文,但底层 key 仍是英文 |
|
||||
| `src/editor/shared/jsonClient.ts` | `29`、`43` | 英文直出 | `Request failed`、`Save failed` | 通用网络错误兜底未本地化,所有编辑器接口都可能透出 |
|
||||
|
||||
## 四、`npcInteractions.ts` 重点复查
|
||||
|
||||
### 4.1 复查通过
|
||||
|
||||
| 文件 | 行号 | 当前状态 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/data/npcInteractions.ts` | `507-657` | 通过 | `actionText` / `detailText` 话题库主体已是中文,适合作为后续清理基线 |
|
||||
|
||||
### 4.2 仍有问题
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/data/npcInteractions.ts` | `299-343` | 中文乱码 | `绋€鏈夊搧`、`鏉愭枡`、`琛屽晢鎶ょ`、`绮剧偧閾?`、`闃叉按琛屽泭`、`娌抽浘缃楃洏`、`鍏界毊`、`鐚庨拱缇藉潬`、`鎷撴湰鏂囧唽`、`娈嬬己鍦板浘`、`姝﹀櫒`、`鍒跺紡浣╁垁`、`鎶ょ敳`、`鎶よ噦`、`鏃у竷鍗?`、`闅忚韩鏃х墿` | 商人来源匹配、商品分类、商品名存在明显乱码,会直接流入交易 UI |
|
||||
| `src/data/npcInteractions.ts` | `401-424` | 英文枚举外露 | `deep`、`honest`、`partial`、`guarded`、`warm`、`cooperative`、`neutral`、`distant`、`candid`、`true_but_incomplete`、`half_truth`、`situational_only` | 阶段/回答模式仍使用英文值,虽不一定直接给玩家看,但已进入 prompt 上下文 |
|
||||
| `src/data/npcInteractions.ts` | `428-500` | 基本通过 | `已经愿意逐步谈到真实来历...` 等 | 描述层已是中文,可作为未来替换英文枚举时的文案来源 |
|
||||
| `src/data/npcInteractions.ts` | `1199`、`1209`、`1243` | 中英混用 | `向该NPC送礼`、`邀请该NPC加入队伍`、`离开当前 NPC,重新回到探索状态。` | 选项和说明里仍混入 `NPC` |
|
||||
| `src/data/npcInteractions.ts` | `1250` | 中英混用 | `当前好感为 ...` 同句包含 `NPC` | 遭遇总结文本仍有术语混入 |
|
||||
|
||||
## 五、`prompt` 链路重点复查
|
||||
|
||||
### 5.1 `src/services/prompt.ts`
|
||||
|
||||
这是当前最需要优先清理的文件。问题不是一两处,而是“结构性污染”:
|
||||
|
||||
- 前段中文描述已混入乱码。
|
||||
- 中段人物/遭遇/场景/状态描述大面积乱码。
|
||||
- 后段选项约束、战斗/观察/营地对话指令大面积乱码。
|
||||
- 同时混有 `functionId`、`actionText`、`npc|treasure|none` 等英文结构词。
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/prompt.ts` | `145`、`151` | 中文乱码 | `锛堣嚜瀹氫箟...`、`鑷畾涔変笘鐣?...` | 自定义世界描述区已坏 |
|
||||
| `src/services/prompt.ts` | `170-171`、`198-216` | 中文乱码 | 冒险开场理由、表层钩子、眼前顾虑、目标等整段乱码 | 角色开场信息会直接污染生成上下文 |
|
||||
| `src/services/prompt.ts` | `226-233` | 中文乱码 + 英文枚举外露 | `NPC`、`deep`、`warm`、`answerMode` 等 | NPC 会话阶段控制段同时存在乱码和英文枚举 |
|
||||
| `src/services/prompt.ts` | `378-451` | 中文乱码 + 中英混用 | 遭遇实体、敌对 `NPC`、玩家状态、场景说明等整段乱码 | 玩家、NPC、怪物、场景等核心提示都已受污染 |
|
||||
| `src/services/prompt.ts` | `547-568` | 中文乱码 + 英文结构词外露 | `functionId`、`actionText`、`function` | 选项约束与动作重写规则段落已坏 |
|
||||
| `src/services/prompt.ts` | `859-910` | 中文乱码 + 中英混用 | 空闲/遭遇函数说明、观察线索、开场营地跟进等整段乱码 | 后半段生成规则几乎不可维护 |
|
||||
|
||||
### 5.2 `src/services/characterChatPrompt.ts`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/characterChatPrompt.ts` | `42-54` | 英文直出 | `You are a companion character...`、`Generate exactly 3 player reply suggestions.`、`Summarize the evolving relationship...` | 系统 prompt 整段为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `57-59` | 英文直出 | `Wuxia`、`Xianxia`、`Custom World` | 世界描述仍为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `64`、`69-71`、`74-75` | 英文直出 | `Custom world reference`、`female`、`male`、`unknown`、`left`、`right` | 性别、朝向、扩展说明均为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `99-112` | 英文直出 | `Recent story: none.`、`Earlier story summary`、`Most recent 3 story rounds` | 历史摘要模板为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `123-155` | 英文直出 | `damage`、`mana`、`cooldown`、`arrival reason`、`current goal`、`world schema`、`top attributes` | 角色信息拼接模板整体为英文 |
|
||||
|
||||
### 5.3 `src/services/questPrompt.ts`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/questPrompt.ts` | `28-31` | 英文直出 | `issued by`、`No live quests` | 当前任务摘要模板为英文 |
|
||||
| `src/services/questPrompt.ts` | `35-37` | 英文直出 | `Active companions`、`Roster companions` | 同伴摘要模板为英文 |
|
||||
| `src/services/questPrompt.ts` | `41-52` | 英文直出 | `Player`、`HP`、`Mana`、`Inventory snapshot` | 玩家状态模板为英文 |
|
||||
| `src/services/questPrompt.ts` | `67-95` | 英文直出 | `You are the quest director...` 等整段 | 任务意图系统 prompt 全英文 |
|
||||
| `src/services/questPrompt.ts` | `107-123` | 英文直出 | `World`、`Issuer NPC`、`Encounter kind`、`Recent story moments` 等 | 最终拼接 prompt 仍是英文框架 |
|
||||
|
||||
### 5.4 `src/services/aiFallbacks.ts`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/aiFallbacks.ts` | `5-17` | 英文直出 | `Player: ...`、`That question is not casual...`、`I accept...` | 离线 NPC 对话与招募兜底仍是英文 |
|
||||
| `src/services/aiFallbacks.ts` | `28-35` | 英文直出 | `I will answer in my own way`、`I still remember...` | 离线角色私聊回复兜底为英文 |
|
||||
| `src/services/aiFallbacks.ts` | `40-42` | 英文直出 | 三条候选回复 | 私聊建议兜底为英文 |
|
||||
| `src/services/aiFallbacks.ts` | `52-57` | 英文直出 | `Player`、`Recent exchange`、`warmer toward the player` | 私聊摘要兜底为英文 |
|
||||
|
||||
## 六、其他会外溢到 UI / 预览 / 生成链路的文本源
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/hooks/useStoryGeneration.ts` | `578-580` | 通过 | `前往...`、`离开营地...` | 旅行选项已中文化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `599`、`602` | 英文直出 | `approaches from a short distance away...`、`steps into view...` | 初始同伴结果文本仍是英文 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `814` | 英文直出 | `Continue the camp exchange and organize the most natural next actions.` | 营地跟进生成指令仍是英文 |
|
||||
| `src/data/scenePresets.ts` | `195`、`297` | 英文枚举外露 | `trade`、`fight`、`spar`、`help`、`chat`、`recruit`、`gift` | 场景函数列表仍是英文 ID |
|
||||
| `src/data/stateFunctions.ts` | `33` | 英文枚举外露 | `idle|move|attack` | 怪物动画枚举仍是英文 |
|
||||
| `src/data/stateFunctions.ts` | `130`、`152`、`174`、`196`、`221`、`244` | 英文枚举外露 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能权重 key 仍为英文 |
|
||||
| `src/data/characterPresets.ts` | `60-76` | 英文枚举外露 | `blunt`、`wary`、`evasive`、`measured`、`gentle`、`teasing`、`dry`、`steady`、`direct`、`fragmented`、`deflecting` | 对话风格推断值仍为英文,已进入 `npcInteractions` / `prompt` 描述链路 |
|
||||
|
||||
## 七、优先级建议
|
||||
|
||||
### P0:先修,否则会持续污染生成结果或直接破坏主界面
|
||||
|
||||
1. `src/services/prompt.ts`
|
||||
2. `src/components/NpcModals.tsx`
|
||||
3. `src/components/AdventureEntityModal.tsx`
|
||||
4. `src/data/npcInteractions.ts` 的商店库存种子乱码段
|
||||
5. `src/components/game-shell/GameShellOverlays.tsx` 的标题乱码
|
||||
|
||||
### P1:紧接着修,编辑器体验当前已经明显受损
|
||||
|
||||
1. `src/components/preset-editor/MonsterPresetPanel.tsx`
|
||||
2. `src/components/preset-editor/SceneNpcPresetPanel.tsx`
|
||||
3. `src/components/preset-editor/ScenePresetPanel.tsx`
|
||||
4. `src/components/preset-editor/CharacterPresetPanel.tsx`
|
||||
5. `src/components/StateFunctionEditor.tsx`
|
||||
6. `src/editor/shared/jsonClient.ts`
|
||||
|
||||
### P2:统一术语与风格,减少中英混用
|
||||
|
||||
1. 全局统一 `NPC`、`HP`、`MP`、`AI`、`Shift` 是否保留英文缩写
|
||||
2. 将 `npcInteractions.ts` / `characterPresets.ts` / `stateFunctions.ts` 的英文枚举与键名整理为“内部值 + 中文展示层”
|
||||
3. 补齐 `aiFallbacks.ts`、`characterChatPrompt.ts`、`questPrompt.ts` 的中文 prompt / fallback 版本
|
||||
|
||||
## 八、建议的修复顺序
|
||||
|
||||
1. 先修 `prompt` 和 `npcInteractions`,因为这两处会同时污染 AI 输出和运行时文本。
|
||||
2. 再修 `NpcModals`、`AdventureEntityModal`、`GameShellOverlays`,优先恢复玩家可见界面。
|
||||
3. 再批量处理四个预设编辑器面板和 `StateFunctionEditor`,最后统一共享请求层兜底文案。
|
||||
|
||||
273
docs/audits/text/GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md
Normal file
273
docs/audits/text/GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# 游戏 UI / 预设 / 编辑器文本二次审计(扩展重查版)
|
||||
|
||||
日期:`2026-04-02`
|
||||
|
||||
说明:
|
||||
|
||||
- 本文档用于替换同名上一版审计。上一版确实漏掉了不少内容,尤其是:
|
||||
- `AdventurePanel` 里的任务概览与奖励文案
|
||||
- `npcInteractions.ts` 里的 `actionText` / `detailText`
|
||||
- 自定义世界编辑器、NPC 视觉编辑器里的英文兜底和混合术语
|
||||
- 预设编辑器里多组仍未本地化的标题、字段名、保存反馈
|
||||
- 本次以当前仓库实际内容为准,不沿用旧结论;已经修掉的内容不再重复计入。
|
||||
|
||||
## 审计范围
|
||||
|
||||
- 扫描目录:
|
||||
- `src/components/`
|
||||
- `src/data/`
|
||||
- `src/hooks/`
|
||||
- `src/services/`
|
||||
- `src/routing/`
|
||||
- `src/editor/`
|
||||
- 关注对象:
|
||||
- 玩家在主流程、冒险面板、弹窗里会看到的文本
|
||||
- 预设编辑器、自定义世界编辑器、NPC 视觉编辑器中会直接显示的文本
|
||||
- 会透传到 UI、弹窗、编辑器预览中的数据层文本源
|
||||
- 标记类型:
|
||||
- `英文直出`:面向玩家 / 编辑器用户的英文文本仍直接显示
|
||||
- `中英混用`:中文 UI 中混入 `NPC`、`HP`、`MP`、`AI`、`URL`、`Shift` 等术语
|
||||
- `异常显示`:明显乱码、截断、异常问号替代、分隔符损坏
|
||||
|
||||
## 结论摘要
|
||||
|
||||
- 游戏主流程里仍有明显英文残留:`QQ Group`、`WeChat`、`GENARRATIVE`、`Current Area`。
|
||||
- 游戏内任务 / 冒险面板仍有一批英文任务眉标和按钮辅助文案:`BOUNTY TARGET`、`CACHE TRACE`、`SPAR SESSION`、`Inspect reward item ...`、`Unknown monster`。
|
||||
- `GameShellOverlays.tsx` 仍有整组 loading fallback 出现异常编码。
|
||||
- 预设编辑器目前仍是问题最密集区域之一,`CharacterPresetPanel`、`MonsterPresetPanel`、`SceneNpcPresetPanel`、`ScenePresetPanel`、`StateFunctionEditor` 里都有明显英文直出或半成品占位。
|
||||
- 数据层里仍有大量会透出到 UI / 编辑器的英文值,重点在:
|
||||
- `npcInteractions.ts`
|
||||
- `useStoryGeneration.ts`
|
||||
- `storyGenerationState.ts`
|
||||
- `npcEncounterActions.ts`
|
||||
- `sceneObservation.ts`
|
||||
- `characterPresets.ts`
|
||||
- `stateFunctions.ts`
|
||||
|
||||
## 一、游戏主流程 UI
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `48-49` | 英文直出 | `QQ Group`、`WeChat` | 开场页联系方式标签仍是英文 |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `351` | 中英混用 | `contact.label === 'QQ Group' ? 'QQ群' : '微信'` | 逻辑分支仍依赖英文标签 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `123` | 异常显示 | `姝e湪鍔犺浇鍐掗櫓璇︽儏...` | 冒险详情 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `162` | 异常显示 | `姝e湪鍔犺浇闃熶紞闈㈡澘` | 队伍面板 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `187` | 异常显示 | `姝e湪鍔犺浇鑳屽寘闈㈡澘` | 背包面板 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `214` | 异常显示 | `姝e湪鍔犺浇闃熶紞钀ュ湴...` | 营地弹窗 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `229` | 异常显示 | `姝e湪鍔犺浇鍦板浘...` | 地图 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `248` | 异常显示 | `姝e湪鍔犺浇瑙掕壊鑱婂ぉ...` | 角色聊天 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `261` | 异常显示 | `姝e湪鍔犺浇 NPC 浜や簰...` | NPC 交互 loading fallback 同时混入 `NPC` |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `146` | 英文直出 | `Current Area` | 当前场景名缺失时的兜底文案仍是英文 |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `200` | 英文直出 | `GENARRATIVE` | 顶部 logo 文案仍是英文 |
|
||||
| `src/components/GameShell.tsx` | `311` | 英文直出 | `Current Area` | 旧壳组件里同样保留英文兜底 |
|
||||
| `src/components/GameShell.tsx` | `365` | 英文直出 | `GENARRATIVE` | 旧壳组件里同样保留英文 logo |
|
||||
| `src/components/DeveloperTeamModal.tsx` | `44` | 英文直出 | `aria-label="Close developer team modal"` | 开发团队弹窗关闭按钮辅助文案未本地化 |
|
||||
|
||||
## 二、游戏内面板 / 弹窗
|
||||
|
||||
### 2.1 冒险与任务面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/AdventurePanel.tsx` | `197-198` | 异常显示 | `适合进攻型构`、`适合防御型构` | 描述文本疑似被截断,正常语义应是“构筑” |
|
||||
| `src/components/AdventurePanel.tsx` | `206` | 异常显示 | `item.name + ' 奖励物品<E789A9>?';` | 奖励物品描述兜底尾部异常 |
|
||||
| `src/components/AdventurePanel.tsx` | `216` | 异常显示 | ``${hours}小时 ...<2E>?...秒`` | 时长格式字符串出现异常字符 |
|
||||
| `src/components/AdventurePanel.tsx` | `219` | 异常显示 | ``${minutes}<7D>?...秒`` | 分钟格式字符串同样异常 |
|
||||
| `src/components/AdventurePanel.tsx` | `248` | 英文直出 | ``aria-label={`Inspect reward item ${item.name}`}`` | 奖励物品按钮辅助文案是英文 |
|
||||
| `src/components/AdventurePanel.tsx` | `279` | 英文直出 | `BOUNTY TARGET` | 任务眉标未本地化 |
|
||||
| `src/components/AdventurePanel.tsx` | `283` | 英文直出 | `Unknown monster` | 目标怪物兜底文案是英文 |
|
||||
| `src/components/AdventurePanel.tsx` | `290` | 英文直出 | `CACHE TRACE` | 宝藏任务眉标未本地化 |
|
||||
| `src/components/AdventurePanel.tsx` | `295` | 英文直出 | `Inspect the hidden reward site` | 宝藏任务副文案未本地化 |
|
||||
| `src/components/AdventurePanel.tsx` | `302` | 英文直出 | `SPAR SESSION` | 切磋任务眉标未本地化 |
|
||||
|
||||
### 2.2 NPC / 实体 / 交易相关弹窗
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/AdventureEntityModal.tsx` | `895` | 中英混用 | `label="HP"` | 实体状态估计面板直接显示 `HP` |
|
||||
| `src/components/AdventureEntityModal.tsx` | `901` | 中英混用 | `label="MP"` | 实体状态估计面板直接显示 `MP` |
|
||||
| `src/components/NpcModals.tsx` | `252` | 中英混用 | `NPC 商品列表` / `你的背包列表` | 交易列表标题混入 `NPC` |
|
||||
| `src/components/NpcModals.tsx` | `273` | 中英混用 | `这个 NPC 当前没有可售商品。` | 空状态文案混入 `NPC` |
|
||||
| `src/components/NpcModals.tsx` | `356` | 中英混用 | `NPC 商品` | 详情弹窗标题混入 `NPC` |
|
||||
| `src/components/NpcModals.tsx` | `408` | 中英混用 | `效果预览:HP +... / MP +... / 冷却 -...` | 数值预览里直接保留 `HP`、`MP` |
|
||||
|
||||
### 2.3 自定义世界结果页
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/CustomWorldResultView.tsx` | `58` | 中英混用 | `新增 NPC` | 结果页新增操作标签混入 `NPC` |
|
||||
|
||||
## 三、自定义世界 / NPC 视觉编辑
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `242` | 英文直出 | `URL` | 图片地址输入提示词未本地化 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `464` | 英文直出 | `MedievalFantasyCharacters` | 形象编辑副标题里直接暴露素材包英文名 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `482-483` | 中英混用 | `AI生成NPC形象`、`NPC 形象 AI 生成功能仍在开发中。` | 同时混入 `AI`、`NPC` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `635-636` | 中英混用 | `新增 NPC`、`编辑 NPC:...` | NPC 档案编辑标题混入英文缩写 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `663` | 中英混用 | `修改形象` | 本行本身无问题,但上下文仍指向 `NPC` 视觉编辑入口 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `734` | 中英混用 | `AI生成` | 按钮文案混入 `AI` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `762-763` | 中英混用 | `AI生成场景`、`场景图片 AI 生成功能仍在开发中。` | 场景生成弹窗混入 `AI` |
|
||||
| `src/components/CustomWorldNpcVisualEditor.tsx` | `393` | 中英混用 | `AI生成` | 自定义 NPC 视觉编辑器按钮混入 `AI` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `263-267` | 英文直出 | `Failed to load NPC visual overrides`、`Failed to load NPC layout config` | 编辑器首屏可见的加载失败兜底为英文 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `284-308` | 英文直出 | `response was invalid, using bundled defaults` 等 | 多组降级提示未本地化 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `463` | 中英混用 | `请先选择一个 NPC 进行编辑` | 空态文案混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `539` | 英文直出 | `Save failed` | 保存失败提示仍是英文 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `702-708` | 中英混用 | `NPC 视觉编辑器`、`选择并编辑 NPC 的外观...` | 页面标题与简介多次混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `718` | 中英混用 | `当前 NPC` | 当前对象字段名混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `976-977` | 中英混用 | `拖动标记微调 NPC 的预览布局。移动时按住 Shift...` | 帮助提示同时混入 `NPC` 与 `Shift` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `1033-1052` | 英文直出 | `Unknown headgear`、`No headgear`、`Unknown main hand`、`No main hand`、`Unknown off hand`、`No off hand` | 预览状态说明仍是英文 |
|
||||
|
||||
## 四、预设编辑器
|
||||
|
||||
### 4.1 共享配置与选项枚举
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/shared.ts` | `43` | 中英混用 | `label: 'NPC'` | 预设编辑器顶部 tab 仍直接显示 `NPC` |
|
||||
| `src/components/preset-editor/shared.ts` | `63-66` | 英文直出 | `idle`、`move`、`attack`、`die` | 怪物动画可选项是原始英文值 |
|
||||
| `src/components/preset-editor/shared.ts` | `70-74` | 英文直出 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能风格可选项是原始英文值 |
|
||||
|
||||
### 4.2 角色预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `91-92` | 英文直出 | `Saved character preset overrides...`、`Failed to save character preset overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `264-279` | 英文直出 | `Characters`、`Browse the character roster...`、`Field`、`Save Character Overrides` | 左侧选择卡与保存栏均为英文 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `315-322` | 英文直出 | `Character Details`、`Field` | 详情卡标题和字段名未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `404-430` | 英文直出 | `Skill Preview`、`Preview ranged skills...`、`Preview Monster` | 技能预览区英文直出 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `450-467` | 英文直出 | `Skill Setup`、`Add Skill` | 技能配置区仍是英文 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `498-558` | 英文直出 | 大量 `label="Field"` | 多数字段仍显示占位词 `Field` |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `605` | 英文直出 | `Start Frame` | 动画字段未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `629`、`729` | 英文直出 | `Section`、`Editor section.` | 两个分区仍是半成品英文占位 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `697-698` | 英文直出 | `Attributes`、`Adjust the core character attributes.` | 属性面板未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `755` | 英文直出 | `Unset` | 场景绑定下拉空值项为英文 |
|
||||
|
||||
### 4.3 怪物预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `49-50` | 英文直出 | `Saved monster overrides...`、`Failed to save monster overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `124-139` | 英文直出 | `Section`、`Editor section.`、`Field`、`Save Monster Overrides` | 左侧选择区和保存栏未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `135` | 异常显示 | ``${WORLD_LABELS[monster.worldType]} 闂?${optionMonster.name}`` | 选择列表分隔符损坏 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `158-159` | 英文直出 | `Monster Override Preview`、`Editor section.` | 预览区标题仍是英文 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `192-201` | 英文直出 | `Attack Range`、`Speed`、`HP`、`Max HP` | 预览摘要未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `212-234` | 英文直出 | `Monster ID`、`Name`、`Intro Action` | 核心字段名仍是英文 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `343` | 英文直出 | `FPS` | 动画字段未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `207`、`275`、`307` | 英文直出 | `Section`、`Editor section.` | 多个分区标题仍为占位英文 |
|
||||
|
||||
### 4.4 场景 NPC 预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `127-128` | 英文直出 | `Saved NPC overrides.`、`Failed to save NPC overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `159` | 英文直出 | `No NPC presets are available.` | 空态文案未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `177-193` | 英文直出 | `NPC Library`、`Browse and select an NPC preset.`、`NPC ID`、`Save NPC Overrides` | 左侧选择区英文直出 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `221-237` | 英文直出 | `Skill Preview`、`Preview ranged skills from the linked character.`、`Skill`、`World` | 技能预览区未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `258` | 异常显示 | `闂?NPC` | 空态或提示文案已损坏 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `264-268` | 英文直出 | `Visual Preview`、`Hostile NPCs use monster presets...` | 视觉预览区标题与说明均未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `310-371` | 英文直出 | `NPC Details`、`Name`、`Role`、`Avatar`、`Linked Character ID`、`Monster Preset ID`、`Initial Affinity`、`Description`、`Visual Editor` | 详情区字段名大面积英文直出 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `374-375` | 英文直出 | `Hostile NPCs cannot use the visual editor...`、`Narrative NPC visual overrides can be previewed here.` | 视觉编辑区说明未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `382-384` | 异常显示 | 三整段乱码说明 + `NPC` | 视觉编辑区空态说明已严重损坏 |
|
||||
|
||||
### 4.5 场景预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `52-53` | 英文直出 | `Saved scene overrides.`、`Failed to save scene overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `62` | 英文直出 | `No scene presets are available.` | 空态文案未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `105-107` | 英文直出 | `Treasure Ahead`、`Treasure` | 宝藏预览实体名仍是英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `132-171` | 英文直出 | `Scene Library`、`Browse and select a scene preset.`、`Save`、`Scene Preview`、`Preview monsters, NPCs, and treasure...` | 场景面板主框架仍多处英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `175-181` | 英文直出 | `Preview Mode`、`Monster Preview`、`NPC Preview`、`Treasure Preview` | 预览模式切换未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `207-226` | 英文直出 | `Hostile NPCs`、`NPCs`、`None` | 预览摘要区未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `233-290` | 英文直出 | `Scene Details`、`Edit the selected scene preset.`、`Scene ID`、`World`、`Name`、`Description`、`Image Source`、`Forward Scene`、`Connected Scene IDs`、`Monster IDs`、`Treasure Hints` | 详情编辑区字段名几乎全部英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `271` | 英文直出 | `Unset` | 下拉空值项为英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `299` | 英文直出 | `NPCs In Scene` | 分区标题未本地化 |
|
||||
|
||||
### 4.6 状态函数编辑器
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/StateFunctionEditor.tsx` | `310-325` | 英文直出 | `Preview`、`Treasure` | 预览 NPC / 宝藏 context 里保留英文 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1062-1064` | 英文直出 | `Option behavior overrides saved.`、`Failed to save option behavior overrides` | 保存反馈未本地化 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1128` | 英文直出 | `无模板` 之外的模板选择逻辑仍有英文结构 | 该区主体中文,但下游模板 ID / 类型依旧偏英文 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1185` | 英文直出 | `AnimationState` 原始值直接作为选项标签 | 动画值会直接显示英文枚举 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1190` | 英文直出 | `placeholder="可使用 {monster} 占位符"` | 占位符本身暴露英文 key |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1191` | 英文直出 | `idle`、`move`、`attack` | 怪物动画下拉仍使用英文值 |
|
||||
|
||||
## 五、数据层 / 运行时文本源
|
||||
|
||||
### 5.1 直接驱动交互按钮、详情文案、结果文本的源头
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/data/npcInteractions.ts` | `444-580` | 重点补录 | 大量 `actionText` / `detailText` | 这是本轮补录重点,属于 NPC 交互选项直接展示源,需要逐条审校 |
|
||||
| `src/data/npcInteractions.ts` | `327-349` | 英文直出 | `deep`、`honest`、`partial`、`guarded`、`warm`、`cooperative`、`neutral`、`distant`、`candid`、`true_but_incomplete`、`half_truth`、`situational_only` | 这些关系 / 说话风格值虽然是逻辑枚举,但后续很容易在编辑器、调试面板、覆盖配置中直接暴露 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `576-578` | 英文直出 | `Travel to ...`、`Leave camp and head toward ...` | 旅行选项和详情文案未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `654-659` | 英文直出 | `Speak with ...`、`Focus on the person in front of you first...` | 开场对话选项未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `827`、`1297` | 英文直出 | `Exchange an opening judgment with ... at camp` | 营地开场交互 actionText 未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `1097` | 英文直出 | `Begin the adventure` | 初始 actionText 未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `1374`、`1794` | 英文直出 | `Unknown AI error` | AI 兜底错误提示仍是英文 |
|
||||
| `src/hooks/story/storyGenerationState.ts` | `137-141` | 英文直出 | `You leave ...`、`Travel to ...` | 旅行结果与 actionText 未本地化 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `277` | 英文直出 | `Victory reward: ${lootText}.` | 战斗胜利奖励结算文本未本地化 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `389` | 英文直出 | `NPC dialogue AI is unavailable.` | NPC 对话 AI 失败兜底是英文 |
|
||||
| `src/hooks/story/characterChat.ts` | `68` | 英文直出 | `Player` | 聊天摘要拼接里保留英文说话人名 |
|
||||
| `src/hooks/story/characterChat.ts` | `84` | 英文直出 | `Tell me more clearly what you mean.` | 建议起句未本地化 |
|
||||
| `src/hooks/story/characterChat.ts` | `283` | 英文直出 | `Unknown AI error` | 私聊错误兜底未本地化 |
|
||||
| `src/data/sceneObservation.ts` | `9-34` | 英文直出 | `You pause to listen...`、`Possible NPCs...`、`Possible hostile NPCs...`、`Possible treasure clues...`、`Boss clue...` | 观察环境的整组文本源仍是英文 |
|
||||
|
||||
### 5.2 会透出到编辑器 / 预览 / 覆盖系统的预设值
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/data/scenePresets.ts` | `141` | 中英混用 | `role: '敌对NPC'` | 场景 NPC 角色名混入 `NPC` |
|
||||
| `src/data/scenePresets.ts` | `194`、`294` | 英文直出 | `['trade', 'fight', 'spar', 'help', 'chat', 'recruit', 'gift']` | 场景 NPC 功能数组是英文原始值,编辑器容易直出 |
|
||||
| `src/data/stateFunctions.ts` | `33` | 英文直出 | `monsterAnimation?: 'idle' | 'move' | 'attack'` | 动画值原始英文会进入状态函数编辑器 |
|
||||
| `src/data/stateFunctions.ts` | `130`、`152`、`174`、`196`、`221`、`244` | 英文直出 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能权重 key 为英文原始值 |
|
||||
| `src/data/stateFunctions.ts` | `372`、`445`、`569`、`575-576` | 中英混用 | 描述里多次直接写 `NPC` | 虽然主体中文,但会透出到说明文字 |
|
||||
| `src/data/characterPresets.ts` | `54-70` | 英文直出 | `blunt`、`wary`、`evasive`、`measured`、`gentle`、`teasing`、`dry`、`steady`、`direct`、`fragmented`、`deflecting` | 对话风格推断返回值全为英文 |
|
||||
| `src/data/characterPresets.ts` | `362-382`、`519-539`、`738-758`、`833-853`、`1018-1041` | 英文直出 | `assetFolder`、`folder`、`prefix` 中大量英文,如 `Sword Princess`、`idle`、`Double Jump`、`Wall Slide`、`Attack` | 这些值会被预设编辑器动画区直接展示或编辑 |
|
||||
| `src/data/characterPresets.ts` | `387-389`、`544-546`、`763-765`、`858-860`、`1046-1048` | 英文直出 | `guardStyle`、`warmStyle`、`truthStyle` 使用英文值 | 会透出到预设编辑器 / 调试视图 |
|
||||
| `src/data/characterPresets.ts` | `410-501`、`575-720`、`794-1000`、`1069-1197` | 英文直出 | `style`、`delivery`、`phase`、`anchor`、`motion` 使用 `steady`、`mobility`、`ranged`、`travel`、`target`、`projectile` 等英文值 | 角色技能配置层大面积保留英文元数据 |
|
||||
| `src/data/monsterPresets.ts` | `384-817` | 英文直出 | 多处 `common`、`uncommon`、`rare`、`epic` | 怪物稀有度原始值为英文,若编辑器未做映射会直接暴露 |
|
||||
| `src/editor/shared/jsonClient.ts` | `29-43` | 英文直出 | `Request failed`、`Save failed` | 编辑器通用 JSON 客户端默认错误文案未本地化 |
|
||||
|
||||
## 六、本轮已复查、暂未记录明确问题的文件
|
||||
|
||||
以下文件本轮重新检查过,但当前内容里没有继续记录“英文直出 / 异常显示”的明确条目,暂可视为本轮通过:
|
||||
|
||||
- `src/routing/appRoutes.tsx`
|
||||
- `src/components/game-shell/CharacterSelectionFlow.tsx`
|
||||
- `src/components/game-shell/GameShellStoryPanels.tsx`
|
||||
- `src/components/CharacterPanel.tsx`
|
||||
- `src/components/InventoryPanel.tsx`
|
||||
- `src/components/MapModal.tsx`
|
||||
- `src/components/CharacterChatModal.tsx`
|
||||
- `src/components/SelectionCustomizationModals.tsx`
|
||||
- `src/components/adventure-panel/AdventurePanelOverlays.tsx`
|
||||
- `src/data/sceneEncounterPreviews.ts`
|
||||
- `src/data/customWorldVisuals.ts`
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
|
||||
## 建议修复顺序
|
||||
|
||||
1. 先修主流程直接暴露给玩家的文本:
|
||||
- `PreGameSelectionFlow.tsx`
|
||||
- `GameShellOverlays.tsx`
|
||||
- `GameShellRuntime.tsx`
|
||||
- `GameShell.tsx`
|
||||
- `AdventurePanel.tsx`
|
||||
2. 再修编辑器里最容易误导内容生产的面板:
|
||||
- `CharacterPresetPanel.tsx`
|
||||
- `MonsterPresetPanel.tsx`
|
||||
- `SceneNpcPresetPanel.tsx`
|
||||
- `ScenePresetPanel.tsx`
|
||||
- `StateFunctionEditor.tsx`
|
||||
3. 最后统一清理数据层文本源和枚举映射:
|
||||
- `npcInteractions.ts`
|
||||
- `useStoryGeneration.ts`
|
||||
- `storyGenerationState.ts`
|
||||
- `npcEncounterActions.ts`
|
||||
- `sceneObservation.ts`
|
||||
- `characterPresets.ts`
|
||||
- `stateFunctions.ts`
|
||||
18
docs/audits/text/README.md
Normal file
18
docs/audits/text/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# 文本与乱码审计总览
|
||||
|
||||
这一组只保留当前仍需要执行的文本与乱码审计入口。早期逐日扫描已经聚合到当前结论,不再保留旧稿链路。
|
||||
|
||||
## 当前推荐入口
|
||||
|
||||
1. [CHINESE_MOJIBAKE_INVENTORY.md](./CHINESE_MOJIBAKE_INVENTORY.md)
|
||||
偏全局库存清单,适合先确认问题分布范围。
|
||||
2. [GAME_UI_PRESET_EDITOR_NPC_PROMPT_TEXT_AUDIT_2026-04-02_DEEP_SCAN.md](./GAME_UI_PRESET_EDITOR_NPC_PROMPT_TEXT_AUDIT_2026-04-02_DEEP_SCAN.md)
|
||||
这是当前最完整的深度审计版本,已经扩到 `prompt`、`npcInteractions`、运行时弹窗与编辑器深层文本。
|
||||
3. [GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md](./GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md)
|
||||
适合看“扩展重查版”的 UI / 预设 / 编辑器问题面。
|
||||
|
||||
## 融合结论
|
||||
|
||||
- 早期几轮扫描已经完成使命,核心结论是:不要把乱码当成普通文案改写,先确认真实编码;文本修复要优先处理会进入玩家体验和 AI 生成链路的内容。
|
||||
- `2026-04-02` 两份文档开始把重点收敛到真正会影响玩家体验和 AI 生成质量的链路。
|
||||
- 现在做文本修复时,不必从最早一份开始逐篇读;优先看 `CHINESE_MOJIBAKE_INVENTORY` 和 `2026-04-02` 两份即可。
|
||||
650
docs/design/AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md
Normal file
650
docs/design/AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md
Normal file
@@ -0,0 +1,650 @@
|
||||
# AI 原生运行时物品生成系统重设计
|
||||
|
||||
更新时间:`2026-04-02`
|
||||
|
||||
## 0. 这次重设计要解决什么
|
||||
|
||||
基于当前仓库已经存在的系统,这次不再把“AI 原生物品生成”设计成一套独立玩法,而是把它重做成:
|
||||
|
||||
**挂在现有背包、build、宝藏、NPC、任务、自定义世界之上的统一运行时物品导演系统。**
|
||||
|
||||
它要解决的核心问题有 4 个:
|
||||
|
||||
1. 当前物品入口很多,但缺少统一导演层。
|
||||
2. 当前奖励能发物品,但和场景背景、相关 NPC、最近事件的贴合度不够高。
|
||||
3. 当前 build 标签体系已经存在,但运行时奖励还没有围绕“永久标签 / 限时标签 / 小数值补充”形成稳定规则。
|
||||
4. AI 目前只负责叙事包装,没有真正进入运行时物品生成链路。
|
||||
|
||||
这次重设计的目标不是“让 AI 直接生成 `InventoryItem`”,而是:
|
||||
|
||||
- 让 AI 负责物品的**叙事意图、关系语义、世界贴合**
|
||||
- 让本地规则负责物品的**标签、数值、稀有度、存档、平衡**
|
||||
|
||||
## 1. 设计结论先说
|
||||
|
||||
新的 AI 原生物品系统建议采用:
|
||||
|
||||
**上下文采样器 -> AI 物品意图层 -> 本地编译器 -> 渠道分发器 -> 叙事回写器**
|
||||
|
||||
其中:
|
||||
|
||||
- `InventoryItem` 继续作为唯一成品结构
|
||||
- `ItemBuildProfile` 继续承载永久 build 标签
|
||||
- `ItemUseProfile.buildBuffs` 继续承载限时 build 标签
|
||||
- `ItemStatProfile` 继续承载小数值加成
|
||||
- `buildTags.ts / buildDamage.ts` 继续承接战斗结算
|
||||
- `treasureInteractions.ts / npcInteractions.ts / forgeSystem.ts / customWorldRuntime.ts` 改为调用统一导演层
|
||||
|
||||
一句话:
|
||||
|
||||
**不要再按“宝藏怎么发、NPC 怎么卖、任务怎么奖”各写一套;而是让所有入口共用同一个运行时物品生成管线。**
|
||||
|
||||
## 2. 这套系统必须遵守的边界
|
||||
|
||||
## 2.1 AI 负责语义,不负责数值
|
||||
|
||||
AI 可以决定:
|
||||
|
||||
- 这件物品像什么
|
||||
- 它为什么在这里出现
|
||||
- 它和哪个 NPC / 势力 / 地标 / 怪物有关
|
||||
- 它更偏向什么 build 风格
|
||||
- 它应该是永久物还是限时物
|
||||
|
||||
AI 不应该直接决定:
|
||||
|
||||
- 最终 `outgoingDamageBonus` 是多少
|
||||
- 能带几个标签
|
||||
- 允许不允许进入装备槽
|
||||
- 价值多少
|
||||
- 能不能掉落
|
||||
- 能不能持久化
|
||||
|
||||
## 2.2 所有成品都必须编译回当前系统
|
||||
|
||||
新的系统不是新物品结构,而是新生成过程。
|
||||
|
||||
最终成品仍然必须落到:
|
||||
|
||||
- `InventoryItem`
|
||||
- `ItemStatProfile`
|
||||
- `ItemUseProfile`
|
||||
- `ItemBuildProfile`
|
||||
|
||||
否则现有:
|
||||
|
||||
- 背包
|
||||
- 装备
|
||||
- build 计算
|
||||
- 锻造
|
||||
- 存档
|
||||
- 交易
|
||||
|
||||
都接不上。
|
||||
|
||||
## 2.3 运行时物品的主收益必须是“构筑意义”
|
||||
|
||||
重新设计后,运行时物品的收益优先级建议固定为:
|
||||
|
||||
1. `build 标签`
|
||||
2. `功能性节奏收益`
|
||||
3. `小数值补充`
|
||||
|
||||
不建议反过来做成:
|
||||
|
||||
1. 大数值
|
||||
2. build 标签只是点缀
|
||||
|
||||
因为当前项目最强的系统基础已经是 build 标签和叙事关系,而不是传统数值刷装。
|
||||
|
||||
## 3. 新系统的整体架构
|
||||
|
||||
## 3.1 模块拆分
|
||||
|
||||
建议新增 5 个模块:
|
||||
|
||||
- `src/types/runtimeItem.ts`
|
||||
- `src/data/runtimeItemContext.ts`
|
||||
- `src/data/runtimeItemDirector.ts`
|
||||
- `src/data/runtimeItemCompiler.ts`
|
||||
- `src/data/runtimeItemNarrative.ts`
|
||||
|
||||
职责如下。
|
||||
|
||||
### A. `runtimeItemContext.ts`
|
||||
|
||||
负责统一采样生成上下文,不直接生成物品。
|
||||
|
||||
输入来自:
|
||||
|
||||
- `GameState`
|
||||
- `currentEncounter`
|
||||
- `currentScenePreset`
|
||||
- `npcStates`
|
||||
- `storyHistory`
|
||||
- `playerEquipment`
|
||||
- `activeBuildBuffs`
|
||||
|
||||
输出统一上下文对象:
|
||||
|
||||
```ts
|
||||
type RuntimeItemGenerationContext = {
|
||||
worldType: WorldType | null;
|
||||
customWorldProfile: CustomWorldProfile | null;
|
||||
sceneId: string | null;
|
||||
sceneName: string | null;
|
||||
sceneDescription: string | null;
|
||||
sceneTags: string[];
|
||||
treasureHints: string[];
|
||||
encounter: Encounter | null;
|
||||
encounterNpcId: string | null;
|
||||
encounterNpcName: string | null;
|
||||
encounterContextText: string | null;
|
||||
relatedNpcState: NpcPersistentState | null;
|
||||
recentStorySummary: string;
|
||||
recentActions: string[];
|
||||
playerCharacterId: string;
|
||||
playerBuildTags: string[];
|
||||
playerBuildGaps: string[];
|
||||
playerEquipmentTags: string[];
|
||||
generationChannel: RuntimeItemGenerationChannel;
|
||||
};
|
||||
```
|
||||
|
||||
### B. `runtimeItemDirector.ts`
|
||||
|
||||
负责根据上下文决定:
|
||||
|
||||
- 这次该不该生成上下文化物品
|
||||
- 生成几件
|
||||
- 主奖励 / 副奖励是什么
|
||||
- 是装备、消耗品、材料还是稀有物
|
||||
- 偏永久 build、限时 build,还是纯功能补给
|
||||
|
||||
它的输出不是成品,而是“导演结果”:
|
||||
|
||||
```ts
|
||||
type RuntimeItemPlan = {
|
||||
slot: "primary" | "secondary" | "support";
|
||||
itemKind: "equipment" | "consumable" | "material" | "relic" | "quest";
|
||||
permanence: "permanent" | "timed" | "resource";
|
||||
narrativeWeight: "light" | "medium" | "heavy";
|
||||
targetBuildDirection: string[];
|
||||
relationAnchor: RuntimeRelationAnchor;
|
||||
};
|
||||
```
|
||||
|
||||
### C. `runtimeItemCompiler.ts`
|
||||
|
||||
负责把导演计划 + AI 意图编译成正式 `InventoryItem`。
|
||||
|
||||
编译职责包括:
|
||||
|
||||
- build 标签规范化
|
||||
- 稀有度预算分配
|
||||
- 永久标签上限
|
||||
- 限时标签时长
|
||||
- 数值预算
|
||||
- 装备槽判定
|
||||
- 价值计算
|
||||
- metadata 生成
|
||||
|
||||
### D. `runtimeItemNarrative.ts`
|
||||
|
||||
负责把已经生成好的物品回写成叙事文本:
|
||||
|
||||
- 物品命名
|
||||
- 物品描述
|
||||
- 物品来源说明
|
||||
- 宝藏/NPC/任务文案嵌入
|
||||
|
||||
### E. `runtimeItem.ts`
|
||||
|
||||
负责声明:
|
||||
|
||||
- 渠道类型
|
||||
- 关系锚点类型
|
||||
- 运行时物品 metadata
|
||||
- AI 意图结构
|
||||
- 编译预算结构
|
||||
|
||||
## 3.2 AI 在新架构里的输入输出
|
||||
|
||||
建议 AI 只接触两种结构:
|
||||
|
||||
### 输入:压缩过的生成上下文
|
||||
|
||||
```ts
|
||||
type RuntimeItemAiPromptInput = {
|
||||
worldSummary: string;
|
||||
sceneSummary: string;
|
||||
encounterSummary: string;
|
||||
relatedNpcSummary: string;
|
||||
recentStorySummary: string;
|
||||
generationChannel: RuntimeItemGenerationChannel;
|
||||
playerBuildDirection: string[];
|
||||
playerBuildGaps: string[];
|
||||
desiredItemKind: string;
|
||||
permanence: string;
|
||||
};
|
||||
```
|
||||
|
||||
### 输出:轻量意图
|
||||
|
||||
```ts
|
||||
type RuntimeItemAiIntent = {
|
||||
shortNameSeed: string;
|
||||
sourcePhrase: string;
|
||||
reasonToAppear: string;
|
||||
relationHooks: string[];
|
||||
desiredBuildTags: string[];
|
||||
desiredFunctionalBias: Array<"heal" | "mana" | "cooldown" | "guard" | "damage">;
|
||||
tone: "grim" | "mysterious" | "martial" | "ritual" | "survival";
|
||||
};
|
||||
```
|
||||
|
||||
AI 输出长度必须短,目的明确,不允许直接产出成品 JSON 大对象。
|
||||
|
||||
## 4. 新系统里的物品收益模型
|
||||
|
||||
## 4.1 三种收益层
|
||||
|
||||
新系统建议把运行时物品分成三类收益层。
|
||||
|
||||
### 第一层:永久 build 标签
|
||||
|
||||
适用于:
|
||||
|
||||
- 武器
|
||||
- 护甲
|
||||
- 饰品
|
||||
- 稀有遗物
|
||||
|
||||
载体:
|
||||
|
||||
- `buildProfile.role`
|
||||
- `buildProfile.tags`
|
||||
- `buildProfile.setId / setName`
|
||||
|
||||
建议限制:
|
||||
|
||||
- 普通运行时装备:`1` 个主标签
|
||||
- 稀有以上:`1` 主标签 + `1` 协同标签
|
||||
- 传说或剧情物:允许带 `2` 标签 + 关系锚点
|
||||
|
||||
### 第二层:限时 build 标签
|
||||
|
||||
适用于:
|
||||
|
||||
- 药剂
|
||||
- 符箓
|
||||
- 战场工具
|
||||
- 一次性应急物
|
||||
|
||||
载体:
|
||||
|
||||
- `useProfile.buildBuffs`
|
||||
|
||||
建议限制:
|
||||
|
||||
- `1~2` 个标签
|
||||
- `1~3` 回合
|
||||
- 默认刷新持续时间,不建议无限叠层
|
||||
|
||||
### 第三层:少量直接数值
|
||||
|
||||
适用于:
|
||||
|
||||
- 补足 build 短板
|
||||
- 强化渠道差异
|
||||
- 给物品明确手感
|
||||
|
||||
载体:
|
||||
|
||||
- `statProfile`
|
||||
- `useProfile`
|
||||
|
||||
建议数值定位:
|
||||
|
||||
- 永远是“辅助收益”
|
||||
- 不和 build 标签争主导权
|
||||
|
||||
## 4.2 玩家 build 缺口驱动
|
||||
|
||||
建议新系统在生成物品时先判断当前玩家缺口,而不是先随机抽品类。
|
||||
|
||||
建议至少识别这些缺口:
|
||||
|
||||
- `survival_gap`
|
||||
- 当前缺 `守御 / 护体 / 回复 / 续战`
|
||||
- `mana_gap`
|
||||
- 当前缺 `法力 / 冷却 / 节奏恢复`
|
||||
- `finisher_gap`
|
||||
- 当前缺 `爆发 / 重击 / 追击`
|
||||
- `mobility_gap`
|
||||
- 当前缺 `突进 / 快袭 / 风行 / 游击`
|
||||
- `control_gap`
|
||||
- 当前缺 `控场 / 符阵 / 镇邪`
|
||||
|
||||
运行时物品应优先:
|
||||
|
||||
- 补当前明显缺口
|
||||
- 或强化当前已经成型的主方向
|
||||
|
||||
## 5. 如何让物品和背景 / NPC / 场景高度贴合
|
||||
|
||||
## 5.1 必须引入“关系锚点”
|
||||
|
||||
建议每个 AI 原生运行时物品都必须绑定至少一个 `relationAnchor`:
|
||||
|
||||
```ts
|
||||
type RuntimeRelationAnchor =
|
||||
| { type: "npc"; npcId?: string; npcName: string; roleText?: string }
|
||||
| { type: "scene"; sceneId?: string; sceneName: string }
|
||||
| { type: "landmark"; landmarkName: string }
|
||||
| { type: "monster"; monsterId?: string; monsterName: string }
|
||||
| { type: "faction"; factionName: string }
|
||||
| { type: "quest"; questId?: string; questName: string };
|
||||
```
|
||||
|
||||
如果没有锚点,物品最多只能作为普通补给,不进入“AI 原生重点物品”。
|
||||
|
||||
## 5.2 不同渠道对应不同贴合逻辑
|
||||
|
||||
### 宝藏
|
||||
|
||||
物品必须同时贴合:
|
||||
|
||||
- 当前场景
|
||||
- `treasureHints`
|
||||
- 最近故事动作
|
||||
|
||||
例如:
|
||||
|
||||
- 在矿道拿到的不是泛用剑,而是“矿脉巡火短铳”
|
||||
- 在旧祭坛拿到的不是泛用药,而是“断誓回神香”
|
||||
|
||||
### NPC 交易
|
||||
|
||||
物品必须贴合:
|
||||
|
||||
- NPC 身份
|
||||
- NPC 库存风格
|
||||
- NPC 和玩家关系
|
||||
|
||||
例如:
|
||||
|
||||
- 黑市牙人卖的是“快袭/情报/潜行”方向的东西
|
||||
- 医修给的是“回复/续战/净化”方向的东西
|
||||
|
||||
### 怪物掉落
|
||||
|
||||
物品必须贴合:
|
||||
|
||||
- 怪物战斗风格
|
||||
- 怪物生态来源
|
||||
- 所在场景
|
||||
|
||||
例如:
|
||||
|
||||
- 重甲守卫掉 `守御精粹`
|
||||
- 雾林伏击者掉 `风行羽囊`
|
||||
|
||||
### 任务奖励
|
||||
|
||||
物品必须贴合:
|
||||
|
||||
- 发布人
|
||||
- 任务目标
|
||||
- 完成方式
|
||||
- 当前线索推进
|
||||
|
||||
它最适合发“永久关系物”。
|
||||
|
||||
## 5.3 命名改成“锚点命名法”
|
||||
|
||||
建议运行时重点物品命名遵循:
|
||||
|
||||
```text
|
||||
来源词 + 关系词 + 功能词
|
||||
```
|
||||
|
||||
而不是:
|
||||
|
||||
```text
|
||||
稀有前缀 + 通用品类名
|
||||
```
|
||||
|
||||
例子:
|
||||
|
||||
- `锁风渡缉索短刃`
|
||||
- `裂界巡守压纹符`
|
||||
- `药谷回岚灵露`
|
||||
- `断碑旧誓护心佩`
|
||||
|
||||
其中:
|
||||
|
||||
- 来源词来自场景/地标/势力
|
||||
- 关系词来自 NPC / 怪物 / 事件
|
||||
- 功能词来自 build 或物品品类
|
||||
|
||||
## 6. 新系统里的预算规则
|
||||
|
||||
## 6.1 稀有度预算
|
||||
|
||||
建议按稀有度控制:
|
||||
|
||||
- 能有几个 build 标签
|
||||
- 能不能带关系锚点
|
||||
- 能不能有 set 倾向
|
||||
- 数值范围上限
|
||||
|
||||
建议预算如下:
|
||||
|
||||
| 稀有度 | build 标签 | 限时 buff | 数值强度 | 叙事强度 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| common | 0~1 | 1 | 很小 | 轻 |
|
||||
| uncommon | 1 | 1~2 | 小 | 轻 |
|
||||
| rare | 1~2 | 2 | 小到中 | 中 |
|
||||
| epic | 2 | 2 | 中 | 中到高 |
|
||||
| legendary | 2 + 关系锚点 | 2~3 | 中 | 高 |
|
||||
|
||||
## 6.2 渠道预算
|
||||
|
||||
不同渠道不该发同样强度的物品。
|
||||
|
||||
建议:
|
||||
|
||||
- `treasure`
|
||||
- 偏单件强语义物
|
||||
- `npc_trade`
|
||||
- 偏稳定、可预期、可补短板
|
||||
- `npc_reward`
|
||||
- 偏关系定制与限时支援物
|
||||
- `monster_drop`
|
||||
- 偏材料 / 精粹 / 生态锚点物
|
||||
- `quest_reward`
|
||||
- 偏永久 build 锚点物
|
||||
- `discovery`
|
||||
- 偏线索物 / 过渡工具物
|
||||
|
||||
## 6.3 build 方向切换限制
|
||||
|
||||
新系统建议引入一条硬规则:
|
||||
|
||||
**普通运行时物品默认只能强化当前 build 或其邻近 build,不应该高频强制转流派。**
|
||||
|
||||
也就是:
|
||||
|
||||
- 当前偏 `快剑/突进`,更容易给 `追击/风行`
|
||||
- 当前偏 `守御/护体`,更容易给 `续战/回复`
|
||||
- 当前偏 `法修/雷法`,更容易给 `过载/冷却`
|
||||
|
||||
真正能强制开新流派的物品,应只出现在:
|
||||
|
||||
- 高价值任务奖励
|
||||
- 关键宝藏
|
||||
- 重要 NPC 关系突破
|
||||
|
||||
## 7. 建议新增的数据结构
|
||||
|
||||
## 7.1 运行时 metadata
|
||||
|
||||
建议在 `InventoryItem` 上新增:
|
||||
|
||||
```ts
|
||||
interface RuntimeItemMetadata {
|
||||
origin: "catalog" | "procedural" | "ai_compiled";
|
||||
generationChannel: RuntimeItemGenerationChannel;
|
||||
seedKey: string;
|
||||
relationAnchor?: RuntimeRelationAnchor;
|
||||
sourceReason: string;
|
||||
recentEventHook?: string;
|
||||
}
|
||||
```
|
||||
|
||||
然后在 `InventoryItem` 上挂:
|
||||
|
||||
```ts
|
||||
interface InventoryItem {
|
||||
runtimeMetadata?: RuntimeItemMetadata;
|
||||
}
|
||||
```
|
||||
|
||||
这样后面:
|
||||
|
||||
- UI 可展示“来源”
|
||||
- 日志可回放“为什么拿到”
|
||||
- 剧情可引用“这是谁给你的”
|
||||
|
||||
## 7.2 运行时导演结果
|
||||
|
||||
```ts
|
||||
type DirectedRuntimeReward = {
|
||||
primaryItem?: InventoryItem | null;
|
||||
supportItems: InventoryItem[];
|
||||
hp?: number;
|
||||
mana?: number;
|
||||
currency?: number;
|
||||
storyHint?: string;
|
||||
};
|
||||
```
|
||||
|
||||
这样可以统一替代宝藏、帮助奖励、任务奖励等零散结构。
|
||||
|
||||
## 8. 与现有模块的接入方式
|
||||
|
||||
## 8.1 `treasureInteractions.ts`
|
||||
|
||||
重构方式:
|
||||
|
||||
- 现在:内部直接从世界池挑物品
|
||||
- 以后:调用 `runtimeItemDirector`
|
||||
|
||||
建议流程:
|
||||
|
||||
1. 从 `GameState + Encounter + ScenePreset` 组 context
|
||||
2. 指定 `generationChannel = "treasure"`
|
||||
3. director 产出 `DirectedRuntimeReward`
|
||||
4. 再由 `buildTreasureResultText` 读 reward 回写文本
|
||||
|
||||
这是最适合作为第一落点的入口。
|
||||
|
||||
## 8.2 `npcInteractions.ts`
|
||||
|
||||
接入方向:
|
||||
|
||||
- 商店货物补货
|
||||
- NPC 帮助奖励
|
||||
- 高好感赠与
|
||||
- 特殊 NPC 线索物
|
||||
|
||||
这里最适合体现“关系锚点”。
|
||||
|
||||
## 8.3 `forgeSystem.ts`
|
||||
|
||||
锻造系统不需要完全 AI 化,但应该读取 AI 原生物品遗留的 metadata:
|
||||
|
||||
- 拆解时保留关系信息
|
||||
- 产出对应方向的精粹
|
||||
- 重铸时优先在邻近 build 内滚动
|
||||
|
||||
这样 AI 原生物品与锻造闭环才是连通的。
|
||||
|
||||
## 8.4 `customWorldRuntime.ts`
|
||||
|
||||
这个模块不要废弃,而是改成:
|
||||
|
||||
- 继续负责“主题物品池”
|
||||
- director 在需要 fallback 或大批量补货时调用它
|
||||
|
||||
也就是说:
|
||||
|
||||
- `customWorldRuntime.ts` 保留“池”
|
||||
- `runtimeItemDirector.ts` 新增“导演”
|
||||
|
||||
## 9. 推荐实施顺序
|
||||
|
||||
## 阶段 A:先加类型和 metadata
|
||||
|
||||
先做:
|
||||
|
||||
- `runtimeItem.ts`
|
||||
- `InventoryItem.runtimeMetadata`
|
||||
- `RuntimeRelationAnchor`
|
||||
- `RuntimeItemGenerationContext`
|
||||
|
||||
目的:
|
||||
|
||||
- 不改玩法,只把类型基础搭好
|
||||
|
||||
## 阶段 B:先做 director + compiler
|
||||
|
||||
先不接所有入口,只把:
|
||||
|
||||
- context 采样
|
||||
- AI 意图结构
|
||||
- 本地编译器
|
||||
|
||||
跑通。
|
||||
|
||||
## 阶段 C:先接宝藏
|
||||
|
||||
原因:
|
||||
|
||||
- 独立
|
||||
- 风险低
|
||||
- 最容易观察“背景贴合”提升
|
||||
|
||||
## 阶段 D:再接 NPC 奖励与交易
|
||||
|
||||
这一步会明显提升:
|
||||
|
||||
- 关系系统
|
||||
- 世界贴脸感
|
||||
- 物品来源可解释性
|
||||
|
||||
## 阶段 E:最后接任务奖励与怪物语义掉落
|
||||
|
||||
因为这两类和现有逻辑耦合更深,适合后置。
|
||||
|
||||
## 10. 和旧版方案相比,这次重设计改了什么
|
||||
|
||||
相比之前偏概念化的 AI 原生物品方案,这次重设计更明确了 5 点:
|
||||
|
||||
1. **不新起物品系统**
|
||||
- 直接复用 `InventoryItem` 与现有 build 结构。
|
||||
2. **不让 AI 直接出成品**
|
||||
- 只让 AI 出意图,交给本地编译器落地。
|
||||
3. **所有渠道走同一导演层**
|
||||
- 不再把宝藏、NPC、任务各写一套。
|
||||
4. **把“关系锚点”正式数据化**
|
||||
- 不是只写在文案里。
|
||||
5. **先从宝藏接入,再逐步扩展**
|
||||
- 不是一次推全仓库。
|
||||
|
||||
## 11. 一句话总结
|
||||
|
||||
新的 AI 原生运行时物品生成系统,不应该是“让 AI 随机写几个看起来很酷的装备”,而应该是:
|
||||
|
||||
**让 AI 根据当前世界、场景、NPC、事件和玩家 build 给出物品意图,再由本地规则把这个意图编译成能进背包、能进 build、能进锻造、能进存档、还能被剧情解释的正式物品。**
|
||||
@@ -0,0 +1,797 @@
|
||||
# 角色首遇感、背景故事分层解锁与同伴私聊功能设计
|
||||
|
||||
更新时间:`2026-04-04`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份方案针对当前仓库,解决 3 个连在一起的问题:
|
||||
|
||||
1. 玩家遇见每一个角色时,在该角色当前好感度对应的关系位置上,都应该有“第一次真正接触”的感觉,而不是一上来就像已经聊过很多轮。
|
||||
2. 角色背景故事目前没有按好感度分层解锁,导致尚未建立关系时,模型和界面都可能提前拿到过深信息。
|
||||
3. 队伍中的高好感同伴虽然已经有聊天弹窗底子,但没有被“好感度 + 面板入口 + 上下文边界”真正串成完整功能。
|
||||
|
||||
这次设计不另起一套独立系统,而是基于当前仓库已有的:
|
||||
|
||||
- `useStoryGeneration` 的角色遭遇与对话流
|
||||
- `npcInteractions.ts` 的好感度与对话阶段规则
|
||||
- `prompt.ts` 的上下文注入机制
|
||||
- `useCharacterChatFlow` / `CharacterChatModal` 的私聊能力
|
||||
|
||||
继续往前补齐。
|
||||
|
||||
## 1. 当前现状与问题定位
|
||||
|
||||
## 1.1 当前“首遇感”不足的根因
|
||||
|
||||
当前问题不是只出在开局同伴,而是整套角色遭遇系统缺少“第一次真正接触”的通用状态。
|
||||
|
||||
主要有 4 个原因:
|
||||
|
||||
1. `src/data/npcInteractions.ts`
|
||||
- `buildInitialNpcState(...)` 会给角色型 NPC 一个初始好感,但当前系统直接把这个好感映射成普通对话阶段。
|
||||
- 也就是说,系统把“当前好感是多少”和“是否已经不是第一次接触”混成了一件事。
|
||||
|
||||
2. `src/data/npcInteractions.ts`
|
||||
- `getNpcChatTopics(...)` 目前只看 `guarded / partial / honest / deep`,不看“这是不是第一次真正交流”。
|
||||
- 结果是,角色只要初始好感不低,就会直接拿到像“追一点表层理由”“开始碰真正目标”这种更像熟人后续轮的聊天切口。
|
||||
|
||||
3. `src/services/prompt.ts`
|
||||
- `describePlayerState(...)` 直接把 `character.backstory` 注入为“主角背景”。
|
||||
- `describeFrontEntity(...)` 直接把 `encounterCharacter.backstory` 注入为“背景”。
|
||||
- 这样模型即使被要求“像初见”,也已经在系统层知道太多,容易写成互背设定卡。
|
||||
|
||||
4. 当前仓库虽然有 `initial_companion / camp_companion` 的开场流,但它只覆盖开局这一种遭遇。
|
||||
- 如果只靠开场特判修正,其他角色第一次见面时仍然会缺乏首遇感。
|
||||
|
||||
一句话总结:
|
||||
|
||||
**当前缺的不是“开场对白模板”,而是“所有角色共用的首遇状态机”。**
|
||||
|
||||
## 1.2 背景故事过早暴露的根因
|
||||
|
||||
当前角色数据只有一个平铺的 `character.backstory`,而没有“公开层 / 解锁层 / 核心秘密层”的结构。
|
||||
|
||||
结果是:
|
||||
|
||||
- 界面层很容易直接把完整背景展示出来。
|
||||
- prompt 层也容易直接把完整背景塞给模型。
|
||||
- 好感度虽然已经控制了 `guarded / partial / honest / deep`,但它只约束“说话方式”,没有约束“哪些背景事实可以进入上下文”。
|
||||
|
||||
这会带来两个后果:
|
||||
|
||||
1. 模型写出来的对白容易像彼此已经认识很久。
|
||||
2. 玩家还没建立关系,就已经在系统层“知道了太多”。
|
||||
|
||||
## 1.3 私聊功能现状
|
||||
|
||||
当前仓库其实已经有私聊底座:
|
||||
|
||||
- `src/hooks/story/characterChat.ts`
|
||||
- 已经有 `useCharacterChatFlow(...)`
|
||||
- 已经能生成建议、流式回复、聊天总结,并写回 `gameState.characterChats`
|
||||
|
||||
- `src/components/CharacterChatModal.tsx`
|
||||
- 已经有完整聊天弹窗
|
||||
|
||||
- `src/components/GameShell.tsx`
|
||||
- 已经挂载了 `CharacterChatModal`
|
||||
- 也把 `onOpenCharacterChat` 传给了 `CharacterPanel`
|
||||
|
||||
但缺的 3 个点还没有补上:
|
||||
|
||||
1. `CharacterPanel` 当前没有真正渲染聊天按钮。
|
||||
2. 游戏内实际查看同伴详情时打开的是 `AdventureEntityModal`,它也没有聊天入口。
|
||||
3. 私聊没有与“队伍成员 + 好感度阈值 + 已解锁背景”绑定。
|
||||
|
||||
所以现在属于“能力有了,但功能还没真正成立”。
|
||||
|
||||
## 2. 总体设计结论
|
||||
|
||||
建议把这次需求拆成 3 条链,同时落地:
|
||||
|
||||
1. **首遇感链**
|
||||
- 所有 `encounter.characterId` 的角色型 NPC,第一次真正接触时都先走通用首遇规则。
|
||||
- 首遇时的亲疏、开放程度和选项排序由“当前好感度 + 是否首遇”共同决定。
|
||||
- `initial_companion / camp_companion` 只保留场景与演出意义,不再承担特殊对话规则本体。
|
||||
|
||||
2. **背景解锁链**
|
||||
- 角色背景改成按好感度分章节解锁。
|
||||
- 未解锁章节既不能在 UI 明文显示,也不能进入 prompt 上下文。
|
||||
|
||||
3. **私聊链**
|
||||
- 队伍中的高好感同伴才能解锁私聊。
|
||||
- 在同伴详情面板中点击按钮打开现有聊天弹窗。
|
||||
- 私聊只吃“公开信息 + 已解锁背景 + 最近共同经历”,不能越权看到锁住的背景章节。
|
||||
|
||||
## 3. 所有角色通用的“首遇感”方案
|
||||
|
||||
## 3.1 核心原则
|
||||
|
||||
必须把下面两件事拆开:
|
||||
|
||||
1. 当前好感度高低
|
||||
2. 这是不是第一次真正接触
|
||||
|
||||
因为:
|
||||
|
||||
- `好感低` 不等于 `第一次见面`
|
||||
- `好感不低` 也不等于 `已经聊过很多轮`
|
||||
|
||||
正确做法应该是“双轴控制”:
|
||||
|
||||
- 好感决定:
|
||||
- 语气亲疏
|
||||
- 允许透露的信息深度
|
||||
- 哪些功能当前有机会成立
|
||||
|
||||
- 首遇状态决定:
|
||||
- 对话必须先像“第一次对上人”
|
||||
- 优先说现场判断、态度试探、短钩子
|
||||
- 不能一上来就跳到“已经熟悉彼此”的后续轮节奏
|
||||
|
||||
## 3.2 状态设计
|
||||
|
||||
建议给 `NpcPersistentState` 增加一个通用字段:
|
||||
|
||||
```ts
|
||||
interface NpcPersistentState {
|
||||
affinity: number;
|
||||
relationState?: RoleRelationState;
|
||||
helpUsed: boolean;
|
||||
chattedCount: number;
|
||||
giftsGiven: number;
|
||||
inventory: InventoryItem[];
|
||||
recruited: boolean;
|
||||
revealedFacts?: string[];
|
||||
knownAttributeRumors?: string[];
|
||||
firstMeaningfulContactResolved?: boolean;
|
||||
seenBackstoryChapterIds?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `firstMeaningfulContactResolved`
|
||||
- 适用于所有角色型 NPC
|
||||
- 表示“玩家是否已经和这个角色完成过第一轮真正接触”
|
||||
- 不等于 `chattedCount > 0`
|
||||
- 不等于 `recruited === true`
|
||||
- 不等于 `affinity` 已经较高
|
||||
|
||||
- `seenBackstoryChapterIds`
|
||||
- 用于背景章节首次解锁时的提示去重
|
||||
|
||||
建议补这组 helper:
|
||||
|
||||
```ts
|
||||
function isNpcFirstMeaningfulContact(
|
||||
encounter: Encounter,
|
||||
npcState: NpcPersistentState,
|
||||
): boolean
|
||||
|
||||
function markNpcFirstMeaningfulContactResolved(
|
||||
npcState: NpcPersistentState,
|
||||
): NpcPersistentState
|
||||
```
|
||||
|
||||
判断建议:
|
||||
|
||||
- 仅对 `encounter.characterId` 的角色型 NPC 启用
|
||||
- `firstMeaningfulContactResolved !== true` 时,进入首遇模式
|
||||
|
||||
## 3.3 首遇时的好感度矩阵
|
||||
|
||||
首遇不是永远冷冰冰,而是要落在“当前好感度对应的位置”上。
|
||||
|
||||
建议把首遇风格做成这张矩阵:
|
||||
|
||||
| 当前关系站位 | 好感区间参考 | 首遇时的感觉 | 信息上限 | 选项重心 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `guarded` | `<= 14` | 明显戒备、先观察你值不值得回应 | 只谈眼前局势、模糊钩子 | 观察、试探、判断 |
|
||||
| `neutral` | `15 - 34` | 可以正常交流,但还不是熟人 | 可给表层理由,不给深层秘密 | 互探来意、确认立场 |
|
||||
| `cooperative` | `35 - 59` | 带基础善意或认可,但仍是第一次正式接触 | 能谈轮廓,不谈全部底牌 | 确认合作、交换判断 |
|
||||
| `bonded` | `>= 60` | 明显信任,但仍应像“第一次真正见到本人/第一次正面对接” | 可谈较深动机,但不一次讲完所有旧事 | 确认并肩关系、推进共同目标 |
|
||||
|
||||
重点不是绝对数值,而是这句话:
|
||||
|
||||
**第一次见面时,角色可以按当前好感更冷或更暖,但不能直接写成“已经是后续轮”。**
|
||||
|
||||
## 3.4 首遇选项改法
|
||||
|
||||
当前 `getNpcChatTopics(...)` 和 `buildNpcEncounterStoryMoment(...)` 更像“已进入常规互动层”后的选项生成。
|
||||
|
||||
建议新增一层:
|
||||
|
||||
```ts
|
||||
function getNpcFirstContactTopics(
|
||||
encounter: Encounter,
|
||||
npcState: NpcPersistentState,
|
||||
): StoryOption[]
|
||||
|
||||
function buildNpcFirstContactOptionCatalog(
|
||||
encounter: Encounter,
|
||||
npcState: NpcPersistentState,
|
||||
baseOptions: StoryOption[],
|
||||
): StoryOption[]
|
||||
```
|
||||
|
||||
规则建议:
|
||||
|
||||
1. 只要是 `firstMeaningfulContactResolved !== true`,前 2 个选项必须来自首遇话题池。
|
||||
|
||||
2. 首遇话题池只做这几类:
|
||||
- 现场判断
|
||||
- 你为什么在这里
|
||||
- 你刚才在观察什么
|
||||
- 你对我的态度和判断
|
||||
- 前面那件事到底哪里不对
|
||||
|
||||
3. 现有其他合法功能可以继续保留,但排序必须后置:
|
||||
- `npc_trade`
|
||||
- `npc_help`
|
||||
- `npc_gift`
|
||||
- `npc_quest_accept`
|
||||
- `npc_recruit`
|
||||
|
||||
补一条实现约束:
|
||||
|
||||
- 首次进入 `npc_chat` 时,前端聊天状态里不允许直接塞预设对白充当首句。
|
||||
- 角色第一次真正对玩家开口时说什么,必须由 `npc_chat` 对应的 prompt 约束来生成,并要求首句是自然招呼或开场判断。
|
||||
- 不能再用“某人看着你,像是在等你把话接下去”这类第三人称占位旁白充当可见对话历史首句,也不能在聊天 state 里本地硬编码一条替代台词。
|
||||
- 当玩家在场景中第一次真正撞上角色型 NPC 并进入聊天时,应直接触发一轮由 NPC 主动开口的模型回复;这一轮只生成 NPC 自己的首句与后续可选回应,不得代替玩家补写未说过的话。
|
||||
- 负好感或敌对关系不应跳过主动开口;如果玩家从 NPC 交互面板点击 `npc_chat`,且该角色尚未完成 `firstMeaningfulContactResolved`,仍要走同一条 NPC 主动开场链路。负好感只影响语气、敌对聊天指令与后续可选功能,不影响“由角色先发言”的首遇行为。
|
||||
- 好感度小于 `0` 的角色在聊天终止时不进入 `story_continue_adventure` 收束态。无论是玩家主动退出聊天,还是模型通过敌对聊天指令主动结束聊天,底部选项都固定收束为 `npc_fight` 与 `battle_escape_breakout`:按钮文案分别为“战斗”“逃跑”。点击“战斗”进入 NPC 战斗结算链路;点击“逃跑”执行现有 `battle_escape_breakout` function,完成脱离演出与后续状态更新。
|
||||
|
||||
4. 首遇状态下,不允许前两项直接变成:
|
||||
- 深背景追问
|
||||
- 直接招募
|
||||
- 直接交易
|
||||
- 直接切磋
|
||||
- 直接熟人式寒暄
|
||||
|
||||
这里的关键不是“把功能全部禁掉”,而是:
|
||||
|
||||
**先保证玩家看到的是首遇节奏,再决定这一轮后面还要不要承接更深功能。**
|
||||
|
||||
## 3.5 首遇期功能排序规则
|
||||
|
||||
为了兼容“不同角色当前好感不同”的需求,建议不要把首遇期做成一刀切的硬封锁,而是做成排序和表达规则:
|
||||
|
||||
1. `npc_chat`
|
||||
- 首遇期必须优先出现
|
||||
- 至少两个切口都与“眼前”和“第一判断”有关
|
||||
|
||||
2. `npc_recruit`
|
||||
- 如果按当前好感已经合法,可以出现
|
||||
- 但不能排在前两项
|
||||
- 文案要像“确认是否并肩同行”,不能像已经熟到直接收编
|
||||
|
||||
3. `npc_trade / npc_help / npc_quest_accept`
|
||||
- 角色职业允许时可以出现
|
||||
- 但文案必须像“先试着谈这件事”,不是默认彼此早就熟悉流程
|
||||
|
||||
4. `npc_fight / npc_spar`
|
||||
- 如果剧情确实需要,可以保留
|
||||
- 但 storyText 里仍要先体现“第一次正面对上”的张力
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
- 既满足“每个角色都按当前好感落点来写”
|
||||
- 又不会把首遇感做成只能用于开局同伴的特殊模板
|
||||
|
||||
## 3.6 首遇状态何时结束
|
||||
|
||||
建议当玩家与该角色完成一次真正交互结算后,就把 `firstMeaningfulContactResolved` 设为 `true`。
|
||||
|
||||
推荐计入“真正交互”的动作:
|
||||
|
||||
- `npc_preview_talk` 后进入并完成一次正式对白
|
||||
- `npc_chat`
|
||||
- `npc_help`
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
- `npc_quest_accept`
|
||||
- `npc_spar`
|
||||
- `npc_fight`
|
||||
|
||||
不建议计入:
|
||||
|
||||
- 仅看了一眼就离开
|
||||
- 只打开 UI 没有完成结算
|
||||
|
||||
这样可以保证:
|
||||
|
||||
- 第一次接触是独立阶段
|
||||
- 第二次开始才进入当前系统已有的常规关系推进节奏
|
||||
|
||||
## 3.7 prompt 与 fallback 约束
|
||||
|
||||
建议新增一个通用的首遇指令,而不是继续把首遇逻辑绑定在开场专用 helper 上。
|
||||
|
||||
### 1. prompt 上下文字段
|
||||
|
||||
建议在 `StoryGenerationContext` 增加:
|
||||
|
||||
```ts
|
||||
isFirstMeaningfulContact?: boolean;
|
||||
firstContactRelationStance?: 'guarded' | 'neutral' | 'cooperative' | 'bonded' | null;
|
||||
```
|
||||
|
||||
### 2. prompt 约束
|
||||
|
||||
只要 `isFirstMeaningfulContact === true`:
|
||||
|
||||
- 不再把 `character.backstory` 作为“主角背景”直接注入
|
||||
- 不再把 `encounterCharacter.backstory` 作为“背景”直接注入
|
||||
- 只允许注入:
|
||||
- `publicSummary`
|
||||
- `surfaceHook`
|
||||
- `immediateConcern`
|
||||
- 已公开的角色描述
|
||||
- 现场状态
|
||||
- 当前关系站位
|
||||
|
||||
### 3. fallback 约束
|
||||
|
||||
如果保留现有 `buildInitialCompanionDialogueText(...)` 一类 helper:
|
||||
|
||||
- 它们只能作为“某个具体场景下调用通用首遇规则”的薄包装
|
||||
- 不应继续承担独立的开场规则系统
|
||||
- 更不能把本地预设对白直接写进 `npc_chat` 的可见对话历史里,`npc_chat` 首个角色台词必须由 prompt 生成
|
||||
|
||||
也就是说:
|
||||
|
||||
**开场营地只是首遇规则的一个调用场景,不是首遇规则本体。**
|
||||
|
||||
## 4. 背景故事分层解锁设计
|
||||
|
||||
## 4.1 核心原则
|
||||
|
||||
背景故事要拆成“能公开的层”和“需要建立关系后才能知道的层”。
|
||||
|
||||
约束是:
|
||||
|
||||
1. 未达到对应好感度前,该章节不能进入 prompt 上下文。
|
||||
2. 未达到对应好感度前,该章节不能在角色详情中完整展示。
|
||||
3. 即使模型之前已经从别的地方生成过相关话头,未解锁章节也不能被总结层写成稳定关系记忆。
|
||||
|
||||
## 4.2 数据结构
|
||||
|
||||
建议在 `Character` 上增加背景解锁配置:
|
||||
|
||||
```ts
|
||||
interface CharacterBackstoryChapter {
|
||||
id: string;
|
||||
title: string;
|
||||
affinityRequired: number;
|
||||
teaser: string;
|
||||
content: string;
|
||||
contextSnippet: string;
|
||||
}
|
||||
|
||||
interface CharacterBackstoryRevealConfig {
|
||||
publicSummary: string;
|
||||
chapters: CharacterBackstoryChapter[];
|
||||
privateChatUnlockAffinity?: number;
|
||||
}
|
||||
|
||||
interface Character {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
backstory: string;
|
||||
backstoryReveal?: CharacterBackstoryRevealConfig;
|
||||
}
|
||||
```
|
||||
|
||||
字段职责:
|
||||
|
||||
- `backstory`
|
||||
- 保留为原始完整设定文本
|
||||
- 不再默认直接进入运行时 prompt
|
||||
|
||||
- `publicSummary`
|
||||
- 永远允许展示和注入
|
||||
- 只用于“第一印象”和公开层信息
|
||||
|
||||
- `teaser`
|
||||
- 章节未解锁时给 UI 的短提示
|
||||
|
||||
- `content`
|
||||
- 玩家真正看到的章节正文
|
||||
|
||||
- `contextSnippet`
|
||||
- 允许注入模型上下文的精简版
|
||||
- 明确只包含“系统允许此阶段知道的事实”
|
||||
|
||||
## 4.3 推荐阈值
|
||||
|
||||
建议不要直接复用 `guarded / partial / honest / deep` 作为背景章节解锁阈值,因为当前对话阶段对“已招募”有额外放宽。
|
||||
|
||||
尤其是:
|
||||
|
||||
- `getNpcDisclosureStage(...)`
|
||||
- `getNpcWarmthStage(...)`
|
||||
|
||||
目前都会在 `recruited === true` 时直接给更高阶段。
|
||||
|
||||
这适合控制说话语气,但不适合控制“背景章节是否已解锁”。
|
||||
|
||||
因此建议新增独立阈值:
|
||||
|
||||
| 层级 | 建议阈值 | 含义 |
|
||||
| --- | --- | --- |
|
||||
| 公开层 | `0` | 只展示公开印象,不算真正解锁 |
|
||||
| 第一章 | `20` | 来路表层、最近为何会出现在这里 |
|
||||
| 第二章 | `40` | 旧事伤痕、过去某段关键经历 |
|
||||
| 第三章 | `65` | 真正目标、必须完成的事 |
|
||||
| 第四章 | `85` | 最深层秘密、最不愿轻易说出的事实 |
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
- 首遇阶段仍然有“先认识再深入”的节奏
|
||||
- 招募后也不会立刻把全部背景放开
|
||||
- 高好感的成长曲线能真正体现在“知道了多少”
|
||||
|
||||
## 4.4 运行时规则
|
||||
|
||||
建议增加这组 helper:
|
||||
|
||||
```ts
|
||||
function getUnlockedBackstoryChapters(
|
||||
character: Character,
|
||||
affinity: number,
|
||||
): CharacterBackstoryChapter[]
|
||||
|
||||
function getNextLockedBackstoryChapter(
|
||||
character: Character,
|
||||
affinity: number,
|
||||
): CharacterBackstoryChapter | null
|
||||
|
||||
function buildBackstoryPromptContext(
|
||||
character: Character,
|
||||
affinity: number,
|
||||
): string[]
|
||||
```
|
||||
|
||||
使用规则:
|
||||
|
||||
- UI 展示:
|
||||
- `publicSummary` 永远可见
|
||||
- 已解锁章节显示全文
|
||||
- 未解锁章节显示 `title + teaser + 所需好感`
|
||||
|
||||
- prompt 注入:
|
||||
- 只能使用 `publicSummary + unlocked.contextSnippet`
|
||||
- 禁止直接把 `backstory` 全文塞给模型
|
||||
|
||||
- 总结沉淀:
|
||||
- 关系总结、私聊总结只允许总结已解锁章节
|
||||
- 未解锁章节即使被模型“猜中”,也不写入稳定状态
|
||||
|
||||
## 4.5 解锁提示
|
||||
|
||||
建议当好感跨越阈值时,在运行时给一次轻提示:
|
||||
|
||||
- 文案示例:
|
||||
- `你对 宁霜 的过去有了更多了解:旧军密图`
|
||||
- `你察觉到 萧烬 愿意谈及更深的一层旧事了`
|
||||
|
||||
实现上不需要新增复杂通知系统,可以先:
|
||||
|
||||
- 在好感变化后检查本次跨越了哪些章节阈值
|
||||
- 若有新章节且 `seenBackstoryChapterIds` 未记录,则插入一条轻量 UI 提示或一条短故事结果文本
|
||||
|
||||
## 5. “未解锁背景不能加入上下文”的具体边界
|
||||
|
||||
这个需求要同时卡住 4 个入口:
|
||||
|
||||
## 5.1 主线剧情 prompt
|
||||
|
||||
`buildStoryContextFromState(...)` 与 `prompt.ts` 中:
|
||||
|
||||
- 角色背景不能再直接读取 `character.backstory`
|
||||
- 应改成读取 `buildBackstoryPromptContext(...)`
|
||||
|
||||
## 5.2 NPC 聊天 prompt
|
||||
|
||||
`buildStrictNpcChatDialoguePrompt(...)` 中:
|
||||
|
||||
- 只能拿 `publicSummary + 已解锁章节 + 最近共同经历`
|
||||
- 未解锁章节不能出现在“当前面前实体”描述里
|
||||
- 若当前还是首遇模式,还要进一步收紧到“公开层 + 当前场景判断”
|
||||
|
||||
## 5.3 私聊 prompt
|
||||
|
||||
`useCharacterChatFlow(...)` 中:
|
||||
|
||||
- `streamCharacterPanelChatReply(...)`
|
||||
- `generateCharacterPanelChatSuggestions(...)`
|
||||
- `generateCharacterPanelChatSummary(...)`
|
||||
|
||||
都只能吃已解锁背景。
|
||||
|
||||
## 5.4 关系摘要回写
|
||||
|
||||
`gameState.characterChats[characterId].summary` 是会反向进入主线上下文的。
|
||||
|
||||
所以必须再加一层约束:
|
||||
|
||||
- 如果某段私聊总结提到了未解锁章节内容,则不允许写回稳定 summary
|
||||
- 或者更稳妥地说,summary 生成 prompt 本身就只提供已解锁背景
|
||||
|
||||
推荐做法是后者,因为它更简单也更可控。
|
||||
|
||||
## 6. 高好感同伴私聊设计
|
||||
|
||||
## 6.1 解锁条件
|
||||
|
||||
建议私聊不是“所有招募同伴自动可用”,而是满足以下条件后才解锁:
|
||||
|
||||
1. 角色已在队伍体系中
|
||||
- `gameState.companions`
|
||||
- 或 `gameState.roster`
|
||||
|
||||
2. 对应 `npcState.recruited === true`
|
||||
|
||||
3. 当前好感度达到私聊阈值
|
||||
- 默认建议 `70`
|
||||
- 允许角色级配置覆盖:`backstoryReveal.privateChatUnlockAffinity`
|
||||
|
||||
之所以不用“已招募”直接等于“可私聊”,原因很简单:
|
||||
|
||||
- 当前系统里已招募会把对话阶段直接推高
|
||||
- 但用户要求的是“高好感同伴解锁私聊”
|
||||
- 所以私聊需要独立阈值,不应绑定到 `warm / deep`
|
||||
|
||||
## 6.2 入口位置
|
||||
|
||||
建议把入口放在两个地方,但以“同伴角色信息面板”为主:
|
||||
|
||||
### 1. `AdventureEntityModal`
|
||||
|
||||
这是游戏内点击同伴详情时实际打开的面板,优先级最高。
|
||||
|
||||
在 `selection.kind === 'companion'` 时增加:
|
||||
|
||||
- 已解锁:`聊天`
|
||||
- 未解锁:置灰按钮 + 提示 `好感达到 70 后解锁,当前 58`
|
||||
|
||||
点击逻辑:
|
||||
|
||||
1. 关闭 `AdventureEntityModal`
|
||||
2. 调 `characterChatUi.openChat(target)`
|
||||
3. 打开现有 `CharacterChatModal`
|
||||
|
||||
### 2. `CharacterPanel`
|
||||
|
||||
如果以后存在不走 `AdventureEntityModal` 的详情流,也应在成员详情面板里显示同样按钮,保持一致。
|
||||
|
||||
## 6.3 聊天目标结构
|
||||
|
||||
建议扩展 `CharacterChatTarget`:
|
||||
|
||||
```ts
|
||||
type CharacterChatTarget = {
|
||||
character: Character;
|
||||
npcId: string | null;
|
||||
roleLabel: string;
|
||||
hp: number;
|
||||
maxHp: number;
|
||||
mana: number;
|
||||
maxMana: number;
|
||||
affinity?: number;
|
||||
unlockedBackstoryChapterIds?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
这样聊天弹窗里可以直接显示:
|
||||
|
||||
- 当前关系热度
|
||||
- 已解锁背景章节数
|
||||
- 下一段背景解锁阈值
|
||||
|
||||
## 6.4 私聊的上下文来源
|
||||
|
||||
私聊上下文建议固定由这几部分组成:
|
||||
|
||||
1. 角色公开信息
|
||||
- `name / title / description / personality`
|
||||
|
||||
2. 当前关系信息
|
||||
- 当前好感
|
||||
- 是否出战 / 是否营地待命
|
||||
- 最近共同经历
|
||||
|
||||
3. 已解锁背景章节
|
||||
- 只传 `contextSnippet`
|
||||
|
||||
4. 最近私聊记录
|
||||
- `characterChats[characterId].history`
|
||||
- `characterChats[characterId].summary`
|
||||
|
||||
明确不传:
|
||||
|
||||
- 未解锁背景章节
|
||||
- 角色完整 `backstory`
|
||||
|
||||
## 6.5 私聊对数值的影响
|
||||
|
||||
建议本期私聊先不直接改好感数值,理由是:
|
||||
|
||||
- 避免玩家通过无限聊天刷关系
|
||||
- 先把“关系表达层”和“规则数值层”分开
|
||||
- 当前已有送礼、聊天、切磋、求助、任务等好感入口,足够支撑成长
|
||||
|
||||
私聊本期的价值应放在:
|
||||
|
||||
- 沉淀角色关系摘要
|
||||
- 解锁更深层的文本风格和背景信息
|
||||
- 让队伍中的同伴真正像“会私下说话的人”
|
||||
|
||||
如果后续要给私聊轻量数值收益,建议再单独加冷却或每日首次奖励,不要在本期一起做。
|
||||
|
||||
## 7. UI 设计建议
|
||||
|
||||
## 7.1 同伴详情面板
|
||||
|
||||
建议增加一个“关系 / 档案”区块:
|
||||
|
||||
- 当前好感:`58`
|
||||
- 关系阶段:`谨慎` / `熟络` / `深信`
|
||||
- 首遇状态:
|
||||
- `初次接触未完成`
|
||||
- 或 `已完成第一次正式对接`
|
||||
- 私聊状态:
|
||||
- `未解锁(70)`
|
||||
- 或 `已解锁`
|
||||
|
||||
下面接“背景档案”:
|
||||
|
||||
- 公开印象
|
||||
- 章节卡片列表
|
||||
|
||||
章节卡片状态:
|
||||
|
||||
- 已解锁
|
||||
- 标题
|
||||
- 正文
|
||||
|
||||
- 未解锁
|
||||
- 标题
|
||||
- `需要好感 40`
|
||||
- `teaser`
|
||||
- 遮罩态
|
||||
|
||||
## 7.2 私聊按钮状态
|
||||
|
||||
按钮文案建议:
|
||||
|
||||
- 已解锁:`聊天`
|
||||
- 未解锁:`聊天(70 解锁)`
|
||||
|
||||
按钮旁边可以补一行细字:
|
||||
|
||||
- `仅高好感同伴可进行私聊`
|
||||
|
||||
## 7.3 解锁反馈
|
||||
|
||||
建议当玩家在详情面板里刚好看到某一章解锁时:
|
||||
|
||||
- 章节卡片做一次轻量高亮
|
||||
- 私聊按钮从置灰切到可点击时也做一次轻量强调
|
||||
|
||||
这样能把“关系成长”明确反馈给玩家,而不只是静态数字变化。
|
||||
|
||||
## 8. 落地文件建议
|
||||
|
||||
## 8.1 类型与数据
|
||||
|
||||
- `src/types/characters.ts`
|
||||
- 增加 `CharacterBackstoryChapter`
|
||||
- 增加 `CharacterBackstoryRevealConfig`
|
||||
|
||||
- `src/types/scene.ts`
|
||||
- 给 `NpcPersistentState` 增加
|
||||
- `firstMeaningfulContactResolved`
|
||||
- `seenBackstoryChapterIds`
|
||||
|
||||
- `src/data/characterPresets.ts`
|
||||
- 为可招募角色补 `backstoryReveal`
|
||||
- 配置分章节阈值和 `privateChatUnlockAffinity`
|
||||
|
||||
## 8.2 关系与规则
|
||||
|
||||
- `src/data/npcInteractions.ts`
|
||||
- 增加首遇状态 helper
|
||||
- 增加首遇话题 helper
|
||||
- 增加背景章节解锁 helper
|
||||
- 增加私聊解锁 helper
|
||||
- 调整首遇期的功能排序规则
|
||||
|
||||
## 8.3 剧情与 prompt
|
||||
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- 新增通用首遇状态流转
|
||||
- 给首遇角色注入统一的 first-contact context
|
||||
- 处理好感跨章节时的解锁通知
|
||||
|
||||
- `src/services/aiTypes.ts`
|
||||
- 给 `StoryGenerationContext` 增加
|
||||
- `isFirstMeaningfulContact`
|
||||
- `firstContactRelationStance`
|
||||
- 已解锁背景片段字段
|
||||
|
||||
- `src/services/prompt.ts`
|
||||
- 移除对完整 `backstory` 的直接注入
|
||||
- 改为按已解锁章节构造角色背景上下文
|
||||
- 首遇模式下额外收紧信息披露
|
||||
|
||||
## 8.4 UI 与交互
|
||||
|
||||
- `src/components/AdventureEntityModal.tsx`
|
||||
- 显示同伴关系/档案区
|
||||
- 增加聊天按钮
|
||||
|
||||
- `src/components/CharacterPanel.tsx`
|
||||
- 补齐聊天按钮接线
|
||||
- 若保留本地详情弹窗,也同步显示档案区
|
||||
|
||||
- `src/components/GameShell.tsx`
|
||||
- 把 `characterChatUi.openChat` 透传给 `AdventureEntityModal`
|
||||
|
||||
- `src/hooks/story/characterChat.ts`
|
||||
- 私聊 prompt 只使用已解锁章节
|
||||
|
||||
## 9. 推荐开发顺序
|
||||
|
||||
建议按这 4 步做,不要反过来:
|
||||
|
||||
1. 先补数据建模
|
||||
- `backstoryReveal`
|
||||
- `firstMeaningfulContactResolved`
|
||||
- 解锁 helper
|
||||
|
||||
2. 再补规则
|
||||
- 首遇状态判断
|
||||
- 首遇选项排序
|
||||
- 首遇完成后的状态流转
|
||||
- 私聊解锁条件
|
||||
|
||||
3. 再补 prompt 上下文边界
|
||||
- 禁止未解锁背景进入模型上下文
|
||||
- 禁止首遇期被写成后续轮
|
||||
|
||||
4. 最后补 UI
|
||||
- 详情面板档案区
|
||||
- 聊天按钮
|
||||
- 解锁提示
|
||||
|
||||
## 10. 验收标准
|
||||
|
||||
做到以下几点,才算这次需求真正完成:
|
||||
|
||||
1. 玩家第一次遇见任一角色型 NPC 时,对话会像第一次真正接触,而不是像已经聊过很多轮。
|
||||
2. 同一个角色第一次见面时的冷暖程度,会落在该角色当前好感对应的位置上,而不是被强行写成统一冷场模板。
|
||||
3. 首遇阶段的前两项选项会优先围绕“眼前局势、互相判断、来意试探”,而不是直接跳进深聊、招募或熟人功能。
|
||||
4. 未达到阈值的背景章节在 UI 中不可完整查看,在 prompt 中也不可被注入。
|
||||
5. 好感提高后,角色详情面板中的背景章节会逐步解锁。
|
||||
6. 队伍中的高好感同伴会在详情面板中出现“聊天”按钮。
|
||||
7. 点击“聊天”后,能直接弹出现有私聊弹窗。
|
||||
8. 私聊内容、建议、总结都不会越权使用未解锁背景。
|
||||
9. 旧存档读取后不会崩,缺省字段能平稳兜底。
|
||||
|
||||
## 11. 一句话收束
|
||||
|
||||
这次需求的关键不是“给开局补一段特判对白”,而是把:
|
||||
|
||||
- 首遇节奏
|
||||
- 背景披露节奏
|
||||
- 私聊入口
|
||||
- 关系记忆
|
||||
|
||||
统一到同一套“好感度 + 首遇状态 + 信息解锁”的通用规则里。
|
||||
|
||||
只有这样,玩家遇见每一个角色时才都会有对应关系位置上的初识感,角色背景才会像一步步了解出来的,同伴私聊也才会真的有价值。
|
||||
@@ -0,0 +1,25 @@
|
||||
# 创作页作品删除入口设计 2026-04-24
|
||||
|
||||
## 背景
|
||||
|
||||
创作页作品卡曾把删除作为底部大按钮展示,并且只对带 `profileId` 的 RPG 作品传入删除回调,导致大鱼、拼图、以及部分草稿作品没有删除入口。用户预期是:删除不是主操作,放在卡片右上角的小 icon 即可;任何作品都应该能删除。
|
||||
|
||||
## 落地规则
|
||||
|
||||
- 作品卡整体就是继续创作 / 继续完善 / 查看详情入口,不再在底部展示“继续完善”等重复主按钮。
|
||||
- 作品卡右上角固定展示删除 icon,底部主操作区只保留体验等必须独立触发的正向操作。
|
||||
- 点击作品卡任意非独立按钮区域都进入继续完善链路;点击删除或体验时不得冒泡触发作品卡打开。
|
||||
- 作品卡保留键盘可访问性:焦点落在卡片时按 Enter 或空格等同点击作品,焦点落在删除 / 体验按钮时只执行对应按钮动作。
|
||||
- 删除入口不按发布状态隐藏:草稿、已发布作品均可删除。
|
||||
- 删除入口不按玩法类型隐藏:RPG、大鱼吃小鱼、拼图作品均应在创作页可删除。
|
||||
- 点击删除前保留浏览器确认弹窗,避免误触;删除中仅禁用当前作品卡的删除 icon。
|
||||
- 删除成功后刷新或替换对应玩法的作品列表,确保卡片立即消失。
|
||||
|
||||
## 工程边界
|
||||
|
||||
- 前端只负责表现和触发删除,实际删除由 `server-rs` API 与 SpacetimeDB 模块过程完成。
|
||||
- 大鱼作品按 `sourceSessionId` 删除创作 session,并同步清理消息、素材槽和运行快照。
|
||||
- 拼图作品按 `profileId` 删除作品 profile,并同步清理来源 Agent session、消息和入口运行快照。
|
||||
- RPG 已发布/持久草稿按 `profileId` 走既有自定义世界删除链路;纯 Agent session 草稿按 `sessionId` 走 owner-only session 删除过程,并清理消息、操作与草稿卡。
|
||||
- 自定义世界 Agent 的异步进度写回必须通过 `upsert_custom_world_agent_operation_progress` 过程落到 SpacetimeDB,`server-rs` 只做字符串入参与过程封装,不在 API 层维护额外进度状态。
|
||||
- `server-rs` 的删除路由使用 Axum 标准 `Path(sessionId)` 提取参数,并在进入 SpacetimeDB 前做 owner-only 与空值校验,避免 handler 签名和过程入参漂移。
|
||||
@@ -0,0 +1,491 @@
|
||||
# 自定义世界创作者输入与 AI 分工边界设计
|
||||
|
||||
更新时间:`2026-04-06`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份文档回答一个非常关键的问题:
|
||||
|
||||
**在“低创作门槛、高创作自由度”的前提下,自定义世界里哪些内容应该交给创作者直接定义,哪些内容应该交给 AI 和系统完成。**
|
||||
|
||||
这里默认我们的创作者:
|
||||
|
||||
- 不需要有专业作家背景
|
||||
- 不需要有专业游戏设计背景
|
||||
- 但希望作品有明显个人风格,而不是只是在用一个会自动补全设定的模板工具
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让创作者把精力放在“决定这个世界为什么值得被创作”,把 AI 用在“把这个世界展开、编译、铺开、校验、补足”。**
|
||||
|
||||
## 1. 总体结论
|
||||
|
||||
自定义世界的分工边界应该遵守 3 条硬原则:
|
||||
|
||||
1. 灵魂归创作者,杂活归 AI。
|
||||
- 凡是决定作品气质、主题、冲突、人物关系、审美方向的内容,都应由创作者掌握。
|
||||
|
||||
2. 重点对象归创作者,长尾铺量归 AI。
|
||||
- 创作者应重点塑造少量关键角色、关键地点、关键冲突、关键意象,而不是被迫手填几十个 NPC、几十个场景、几百条描述。
|
||||
|
||||
3. 决策归创作者,编译归 AI / 系统。
|
||||
- 创作者负责说“这个世界要成为什么样”,AI / 系统负责把它编译成可运行的数据、规则、文本、关系钩子和运行时结构。
|
||||
|
||||
这意味着:
|
||||
|
||||
- 创作者应该主要编辑“高杠杆创作锚点”
|
||||
- AI 应该主要承担“批量展开 + 结构编译 + 一致性维护 + 专业执行”
|
||||
|
||||
## 2. 什么内容应该交给创作者
|
||||
|
||||
真正应该交给创作者的,不是大量表格字段,而是下面这些会显著决定作品质量、且 AI 不擅长替代的内容。
|
||||
|
||||
## 2.1 世界核心命题
|
||||
|
||||
创作者应该直接定义:
|
||||
|
||||
- 这个世界的一句话设定
|
||||
- 这个世界最吸引人的核心幻想
|
||||
- 玩家来到这个世界,最想体验的感觉是什么
|
||||
- 这个世界和常规同题材作品相比,最不同的地方是什么
|
||||
|
||||
原因:
|
||||
|
||||
- 这是作品的创作方向盘
|
||||
- 一旦这一层是空的,后面所有 AI 扩写都会变成“像一个世界”,而不是“这个世界”
|
||||
|
||||
## 2.2 主题、气质与边界
|
||||
|
||||
创作者应该直接定义:
|
||||
|
||||
- 主题关键词
|
||||
- 情绪基调
|
||||
- 审美偏好
|
||||
- 禁忌内容 / 不希望出现的表达
|
||||
- 可以接受的黑暗度、浪漫度、残酷度、神秘度
|
||||
|
||||
原因:
|
||||
|
||||
- 这决定了 AI 后续生成时的“味道”
|
||||
- 这类判断很难靠 AI 替代,因为它本质上不是信息补全,而是审美取舍
|
||||
|
||||
## 2.3 玩家身份与开局处境
|
||||
|
||||
创作者应该直接定义:
|
||||
|
||||
- 玩家扮演的是什么人
|
||||
- 玩家一开始最缺什么、最想要什么
|
||||
- 开局时玩家被卷入什么局面
|
||||
- 玩家在这个世界里天然站在哪个位置上
|
||||
|
||||
原因:
|
||||
|
||||
- 这决定了整个世界的观看视角
|
||||
- 同一个世界,玩家视角不同,最终体验会完全不同
|
||||
|
||||
## 2.4 核心冲突与关键势力
|
||||
|
||||
创作者应该直接定义少量高价值内容:
|
||||
|
||||
- 世界当前最重要的 `2~4` 条明面冲突
|
||||
- 世界背后最关键的 `1~3` 条暗面问题
|
||||
- `2~6` 个关键势力
|
||||
- 这些势力各自想要什么、害怕什么、互相卡住了什么
|
||||
|
||||
原因:
|
||||
|
||||
- 冲突结构决定世界是否“有戏”
|
||||
- 势力关系是 AI 最容易写散、写平、写成百科介绍的部分
|
||||
- 这一层由创作者把握,才能真正提高作品的辨识度
|
||||
|
||||
## 2.5 关键角色与关系张力
|
||||
|
||||
创作者应该直接定义少量关键角色,而不是所有 NPC。
|
||||
|
||||
建议重点交给创作者的,是:
|
||||
|
||||
- `3~8` 个关键角色
|
||||
- 玩家与这些人的潜在关系
|
||||
- 这些角色彼此之间的债、仇、秘密、误解、利益绑定
|
||||
- 每个关键角色“表面上像什么、实际上压着什么”
|
||||
|
||||
原因:
|
||||
|
||||
- 角色关系是最能显著提升作品质量的部分之一
|
||||
- 这也是 AI 最容易写得“完整但无味”的部分
|
||||
- 创作者不需要写长篇背景,但应掌握这些角色真正的关系骨架
|
||||
|
||||
## 2.6 关键地点与空间记忆点
|
||||
|
||||
创作者应该直接定义:
|
||||
|
||||
- `4~12` 个关键地点 / 区域 / 地标
|
||||
- 这些地方为什么重要
|
||||
- 这些地方承载什么冲突、危险、秘密或情绪记忆
|
||||
- 玩家第一次来到这里时应该感到什么
|
||||
|
||||
原因:
|
||||
|
||||
- “地方感”是世界质量的重要来源
|
||||
- 关键地点一旦成立,AI 后续才能稳定地生成周边事件、物件、NPC 和线索
|
||||
|
||||
## 2.7 标志性意象、物件、怪物、制度与规则
|
||||
|
||||
创作者应该优先控制世界里最能代表它的东西:
|
||||
|
||||
- 标志性物件
|
||||
- 标志性怪物 / 生物
|
||||
- 标志性能力体系 / 修炼体系 / 技术体系
|
||||
- 标志性社会制度 / 宗教 / 仪式 / 禁忌
|
||||
- 世界的硬规则
|
||||
|
||||
原因:
|
||||
|
||||
- 这些内容决定世界的“手感”
|
||||
- 它们不是普通细节,而是会反复影响命名、剧情、视觉、对话与玩法解释的母题
|
||||
|
||||
## 2.8 创作者应直接控制的“禁止事项”
|
||||
|
||||
创作者必须能明确锁定:
|
||||
|
||||
- 什么绝对不能改
|
||||
- 什么不能被 AI 自动扩写到别的方向
|
||||
- 哪些角色、地点、关系、设定是核心锚点
|
||||
- 哪些内容允许 AI 自由发挥,哪些只能在锚点附近变体
|
||||
|
||||
原因:
|
||||
|
||||
- 高自由度不等于所有内容都开放漂移
|
||||
- 如果没有“锁定机制”,AI 会把创作者真正关心的内容稀释掉
|
||||
|
||||
## 3. 什么内容应该交给 AI 和系统
|
||||
|
||||
应该交给 AI 的,不是“重要内容”,而是“重要内容之外的大量展开、编译、补缝、校验与专业执行”。
|
||||
|
||||
## 3.1 批量生成的长尾内容
|
||||
|
||||
应该主要交给 AI:
|
||||
|
||||
- 普通 NPC
|
||||
- 路人、商贩、巡逻者、村民、杂兵
|
||||
- 次级场景
|
||||
- 场景支线事件
|
||||
- 大量普通物品
|
||||
- 世界的长尾命名与描述
|
||||
|
||||
原因:
|
||||
|
||||
- 这些内容数量大、重复度高
|
||||
- 它们需要“贴合世界”,但不需要都由创作者逐个手写
|
||||
- AI 很适合做“围绕锚点的批量铺量”
|
||||
|
||||
## 3.2 从创作锚点到系统结构的编译
|
||||
|
||||
应该交给 AI / 系统:
|
||||
|
||||
- 从自然语言世界设定中提取题材词汇
|
||||
- 从关键冲突中编译出世界叙事图谱
|
||||
- 从关键角色卡编译出角色叙事档案
|
||||
- 从创作者输入里自动生成标签、钩子、隐藏线索、章节摘要
|
||||
- 从地点和关系中编译出场景连接、事件触发和叙事回响
|
||||
|
||||
对应当前仓库,下面这些结构更适合由 AI / 系统生成,而不是让玩家直接编辑:
|
||||
|
||||
- `ThemePack`
|
||||
- `WorldStoryGraph`
|
||||
- `ActorNarrativeProfile`
|
||||
- `KnowledgeFact`
|
||||
- `VisibilitySlice`
|
||||
- `SceneNarrativeDirective`
|
||||
- `CarrierStoryFingerprint`
|
||||
- `ThreadContract`
|
||||
- `StorySignal`
|
||||
|
||||
原因:
|
||||
|
||||
- 这些是运行时结构,不是创作者真正想表达的作品内容
|
||||
- 直接暴露给玩家,会把创作过程变成专业数据填表
|
||||
|
||||
## 3.3 专业化、规则化的任务
|
||||
|
||||
应该交给 AI / 系统:
|
||||
|
||||
- 数值平衡
|
||||
- 标签归纳
|
||||
- 稀有度预算
|
||||
- 初始技能与初始物品的批量配置
|
||||
- build 方向匹配
|
||||
- 地图连接补全
|
||||
- 触发条件与推进信号编译
|
||||
- 背景章节拆分与 teaser 生成
|
||||
- 运行时物件命名与叙事描述的变体生成
|
||||
|
||||
原因:
|
||||
|
||||
- 这些工作要么重复、要么专业、要么容易做脏活累活
|
||||
- 让非专业创作者处理,会显著提高门槛,却不一定显著提高质量
|
||||
|
||||
## 3.4 一致性、纠错与查漏补缺
|
||||
|
||||
应该交给 AI / 系统持续处理:
|
||||
|
||||
- 世界设定冲突检查
|
||||
- 角色关系矛盾检查
|
||||
- 同名 / 重复 / 设定撞车检查
|
||||
- 信息越权泄露检查
|
||||
- prompt 裁剪
|
||||
- 风格一致性检查
|
||||
- “这个角色/地点/物件是否真的和世界主线有关”的弱关联检查
|
||||
|
||||
原因:
|
||||
|
||||
- 这是 AI 比人更适合做的“维护型工作”
|
||||
- 它属于创作支持,不属于创作者必须亲手完成的创作
|
||||
|
||||
## 4. 最合理的边界不是二分法,而是三层分工
|
||||
|
||||
自定义世界最合理的结构,不是“玩家写”与“AI 写”的简单二选一,而是三层。
|
||||
|
||||
## 4.1 第一层:创作者必控层
|
||||
|
||||
这一层必须给创作者高自由度,且能被锁定:
|
||||
|
||||
- 世界核心命题
|
||||
- 主题与气质
|
||||
- 玩家身份与开局
|
||||
- 核心冲突
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性物件 / 怪物 / 规则
|
||||
- 禁止事项
|
||||
|
||||
这层的原则是:
|
||||
|
||||
**少而重。**
|
||||
|
||||
## 4.2 第二层:创作者可选强化层
|
||||
|
||||
这一层不应强制填写,但应该允许创作者继续深挖:
|
||||
|
||||
- 明线 / 暗线种子
|
||||
- 角色之间的旧事
|
||||
- 地点背后的旧伤
|
||||
- 标志性物件的来历
|
||||
- 关键角色的口头习惯、禁忌、执念
|
||||
- 关键地点的视觉母题与情绪目标
|
||||
|
||||
这层的原则是:
|
||||
|
||||
**愿意细写的人可以拉高作品上限,不愿细写的人也不会被门槛卡住。**
|
||||
|
||||
## 4.3 第三层:AI 自动展开层
|
||||
|
||||
这一层默认交给 AI / 系统:
|
||||
|
||||
- 长尾 NPC
|
||||
- 次级地点
|
||||
- 章节拆分
|
||||
- 初始技能
|
||||
- 初始物品
|
||||
- 标签与属性映射
|
||||
- 任务 contract
|
||||
- 物件叙事指纹
|
||||
- 可见性裁剪
|
||||
- 运行时导演指令
|
||||
- 批量命名与文案变体
|
||||
|
||||
这层的原则是:
|
||||
|
||||
**AI 可以做多、做快、做杂,但不能越过第一层锁定内容。**
|
||||
|
||||
## 5. 具体模块的建议归属
|
||||
|
||||
| 模块 | 建议归属 | 创作者应控制什么 | AI / 系统应负责什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 世界一句话设定、核心幻想、核心卖点 | 创作者直接控制 | 直接写、直接改、可锁定 | 给出备选表述和扩展方向 |
|
||||
| 主题、基调、审美、禁忌 | 创作者直接控制 | 选择 / 改写 / 锁定 | 生成风格词、避雷词、提示词约束 |
|
||||
| 玩家身份、开局处境、玩家目标 | 创作者直接控制 | 直接定义 | 补足开局钩子和初始叙事包装 |
|
||||
| 关键势力与核心冲突 | 创作者主控,AI 辅助 | 定义核心关系和立场 | 扩展冲突支路、生成世界线程 |
|
||||
| 关键角色 | 创作者主控,AI 辅助 | 定义角色骨架、关系张力、秘密方向 | 生成长背景、章节拆分、技能、物品、叙事档案 |
|
||||
| 关键地点 | 创作者主控,AI 辅助 | 定义地点意义、气氛、秘密 | 扩展场景细节、连接关系、遭遇分布 |
|
||||
| 标志性物件 / 怪物 / 制度 / 规则 | 创作者主控,AI 辅助 | 定义代表性要素与硬边界 | 扩展变体、命名、说明、运行时挂钩 |
|
||||
| 普通 NPC / 路人 / 杂兵 / 次级地点 | 主要交给 AI | 仅在需要时抽查或替换 | 批量生成与风格保持 |
|
||||
| 角色长背景、章节 teaser、context snippet | 主要交给 AI | 创作者只改关键角色即可 | 自动拆章、压缩、解锁节奏整理 |
|
||||
| 技能、初始物品、标签、构筑倾向 | 主要交给 AI / 系统 | 提供偏好或少量 override | 按角色和世界规则自动编译 |
|
||||
| 世界图谱、知识事实、可见性、导演指令 | AI / 系统内部层 | 不应默认暴露给玩家 | 运行时编译与维护 |
|
||||
| 一致性检查、冲突检查、越权检查 | AI / 系统内部层 | 查看报告、决定是否采纳修改 | 自动扫描并提出修正建议 |
|
||||
|
||||
## 6. 不应该要求玩家直接填写的字段
|
||||
|
||||
为了真正做到低门槛,下面这些内容不应直接以“专业字段”形式强迫玩家填写。
|
||||
|
||||
## 6.1 不应该要求玩家手填原始数值
|
||||
|
||||
例如:
|
||||
|
||||
- `initialAffinity`
|
||||
- 精确数值型 build 倾向
|
||||
- 复杂掉落预算
|
||||
|
||||
更合理的做法是让创作者填写直觉表达,例如:
|
||||
|
||||
- `初见就戒备`
|
||||
- `容易合作`
|
||||
- `这里非常危险`
|
||||
- `偏爆发型`
|
||||
|
||||
再由系统编译成运行时数值。
|
||||
|
||||
## 6.2 不应该要求玩家手填技术型结构
|
||||
|
||||
例如:
|
||||
|
||||
- `tags`
|
||||
- `attributeSchema`
|
||||
- `ThemePack`
|
||||
- `WorldStoryGraph`
|
||||
- `VisibilitySlice`
|
||||
- `SceneNarrativeDirective`
|
||||
- `ThreadContract`
|
||||
|
||||
原因:
|
||||
|
||||
- 这些字段属于系统运行结构,不属于创作者自然的创作语言
|
||||
- 直接让玩家填,会把工具变成只有懂系统的人才能用
|
||||
|
||||
## 6.3 不应该要求玩家逐个补完所有人物设定字段
|
||||
|
||||
当前 `CustomWorldRoleProfile` 里这些字段:
|
||||
|
||||
- `backstory`
|
||||
- `personality`
|
||||
- `motivation`
|
||||
- `combatStyle`
|
||||
- `backstoryReveal`
|
||||
- `skills`
|
||||
- `initialItems`
|
||||
|
||||
更适合的做法不是全部让玩家手写,而是先让玩家填写更自然的“角色卡”:
|
||||
|
||||
- 这个人表面上是什么样
|
||||
- 这个人真正想要什么
|
||||
- 这个人最不想被提到什么
|
||||
- 这个人和玩家之间最可能形成什么关系
|
||||
- 这个人和哪个地点 / 物件 / 旧事绑得最紧
|
||||
|
||||
再由 AI / 系统编译成当前结构。
|
||||
|
||||
## 7. 推荐的创作输入形态
|
||||
|
||||
要让非专业创作者也能高自由度创作,输入形态必须改成“自然语言创作卡”,而不是“系统字段表单”。
|
||||
|
||||
## 7.1 世界层卡片
|
||||
|
||||
建议至少有这些卡片:
|
||||
|
||||
1. 世界一句话
|
||||
2. 主题与气质
|
||||
3. 玩家是谁
|
||||
4. 核心冲突
|
||||
5. 关键势力
|
||||
6. 关键角色
|
||||
7. 关键地点
|
||||
8. 标志性要素
|
||||
9. 禁止事项
|
||||
|
||||
## 7.2 每张卡片都允许 3 种输入方式
|
||||
|
||||
1. 一句话自由输入
|
||||
- 适合低门槛创作者
|
||||
|
||||
2. 标签 / 选项 / 语气滑条
|
||||
- 适合不想写太多字的创作者
|
||||
|
||||
3. 高级补充
|
||||
- 适合愿意继续深挖的人
|
||||
|
||||
这样才能做到:
|
||||
|
||||
- 不会逼着用户写长文
|
||||
- 但也不会限制愿意创作的人继续把世界做深
|
||||
|
||||
## 7.3 必须支持“锁定”与“局部重生成”
|
||||
|
||||
这是高创作自由度里非常关键的一点。
|
||||
|
||||
创作者应当能:
|
||||
|
||||
- 锁定一个角色
|
||||
- 锁定一个地点
|
||||
- 锁定一条冲突
|
||||
- 只重生成未锁定部分
|
||||
- 围绕锁定内容重写其余世界
|
||||
|
||||
否则创作者每次调用 AI,都会有“好不容易想好的东西被洗掉”的感受。
|
||||
|
||||
## 8. 面向当前仓库的结构映射建议
|
||||
|
||||
为了便于后续落实现有系统,这份边界建议可以直接映射到当前结构:
|
||||
|
||||
## 8.1 创作者输入层
|
||||
|
||||
建议主要映射到:
|
||||
|
||||
- `CustomWorldProfile.settingText`
|
||||
- `CustomWorldProfile.name`
|
||||
- `CustomWorldProfile.subtitle`
|
||||
- `CustomWorldProfile.summary`
|
||||
- `CustomWorldProfile.tone`
|
||||
- `CustomWorldProfile.playerGoal`
|
||||
- `CustomWorldProfile.majorFactions`
|
||||
- `CustomWorldProfile.coreConflicts`
|
||||
|
||||
以及关键角色、关键地点的创作卡输入。
|
||||
|
||||
## 8.2 AI 编译层
|
||||
|
||||
由 AI / 系统从创作者输入自动补出:
|
||||
|
||||
- `themePack`
|
||||
- `storyGraph`
|
||||
- `knowledgeFacts`
|
||||
- `threadContracts`
|
||||
- 每个关键角色的 `narrativeProfile`
|
||||
- 每个角色的 `backstoryReveal`
|
||||
- 每个角色的 `skills`
|
||||
- 每个角色的 `initialItems`
|
||||
|
||||
## 8.3 运行时支持层
|
||||
|
||||
运行时继续由 AI / 系统维护:
|
||||
|
||||
- `VisibilitySlice`
|
||||
- `SceneNarrativeDirective`
|
||||
- `CarrierStoryFingerprint`
|
||||
- `StorySignal`
|
||||
|
||||
这些内容应该是“系统如何把世界跑起来”,不是“创作者必须亲手写完的创作内容”。
|
||||
|
||||
## 9. 产品层面的最终结论
|
||||
|
||||
如果我们的目标真的是“低创作门槛、高创作自由度”,那么自定义世界不应该做成一个要求用户:
|
||||
|
||||
- 填很多字段
|
||||
- 写很多长文
|
||||
- 理解很多系统结构
|
||||
- 自己负责平衡、命名、拆章节、补标签、补长尾内容
|
||||
|
||||
的专业编辑器。
|
||||
|
||||
它应该做成这样:
|
||||
|
||||
1. 创作者决定世界的灵魂锚点。
|
||||
2. 创作者重点塑造少量关键人、关键地、关键冲突、关键物。
|
||||
3. AI 围绕这些锚点批量展开长尾内容。
|
||||
4. 系统把这些内容编译成可运行的图谱、可见性、任务、物件和关系结构。
|
||||
5. 创作者随时可以锁定核心创意,并局部重生成其余部分。
|
||||
|
||||
一句话收束:
|
||||
|
||||
**创作者应该写“这个世界为什么动人”,AI 应该负责“让这个世界长出来并跑起来”。**
|
||||
@@ -0,0 +1,721 @@
|
||||
# 自定义世界创作中手填、AI 可改与系统托管的平衡设计
|
||||
|
||||
更新时间:`2026-04-12`
|
||||
|
||||
## 0. 文档目标
|
||||
|
||||
这份文档用于回答一个更具体的问题:
|
||||
|
||||
**参考 RPG 专业剧情策划全流程后,在自定义世界创作工具里,哪些设定必须要求创作者手动填写,哪些设定应该由 AI 先生成但允许创作者修改,哪些设定应完全交给系统托管,才能在“尽可能降低门槛”和“尽可能提高作品质量”之间取一个平衡。**
|
||||
|
||||
这份文档不再只回答“创作者与 AI 怎么分工”,而是进一步把创作工作台收束成一个更可执行的三层输入结构:
|
||||
|
||||
1. 创作者必须手填的高杠杆锚点
|
||||
2. AI 先生成、创作者可修改的内容草稿层
|
||||
3. 系统自动编译和运行的托管层
|
||||
|
||||
一句话结论:
|
||||
|
||||
**让创作者只负责决定作品的灵魂、视角、冲突和关系钩子,让 AI 负责把这些锚点展开成可编辑的剧情草稿,让系统负责把草稿编译成可运行的结构。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
这套平衡设计要同时满足 5 个目标:
|
||||
|
||||
1. 低门槛
|
||||
- 新创作者不需要写长篇设定,也不需要理解底层系统结构。
|
||||
|
||||
2. 高辨识度
|
||||
- 创作者写出来的世界,不应该只是“像一个世界”,而应该保留明显的个人方向。
|
||||
|
||||
3. 高可编辑性
|
||||
- AI 不能一次生成后就不可控,创作者必须能改关键对象、关键关系和关键章节。
|
||||
|
||||
4. 高稳定性
|
||||
- 任务、章节、关系、物件和可见性等运行层结构不能依赖创作者手填专业字段。
|
||||
|
||||
5. 可扩展
|
||||
- 愿意深挖的创作者可以继续补充世界上限,不愿深挖的人也能快速产出质量不错的作品。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心原则
|
||||
|
||||
## 2.1 创作者手填的必须是“高杠杆决策”,不是“高工作量字段”
|
||||
|
||||
应该要求创作者手填的内容,必须同时满足下面两个条件:
|
||||
|
||||
1. 会显著决定作品气质和辨识度
|
||||
2. AI 很难替代判断
|
||||
|
||||
例如:
|
||||
|
||||
- 世界一句话
|
||||
- 玩家身份
|
||||
- 核心冲突
|
||||
- 关系钩子
|
||||
- 禁忌边界
|
||||
|
||||
而不应该强制手填:
|
||||
|
||||
- 全量 NPC
|
||||
- 全量场景
|
||||
- 技能列表
|
||||
- 初始物品
|
||||
- 章节拆分
|
||||
- 运行时信号结构
|
||||
|
||||
## 2.2 创作者可改层应该承接“专业策划初稿”,而不是“原始底层字段”
|
||||
|
||||
AI 生成后允许创作者修改的,不应该是一堆技术型字段,而应该是一批已经成形的内容卡片,例如:
|
||||
|
||||
- 关键角色卡
|
||||
- 势力卡
|
||||
- 关键地点卡
|
||||
- 主线章节卡
|
||||
- 支线种子卡
|
||||
- 场景章节卡
|
||||
- 标志性物件卡
|
||||
|
||||
也就是说:
|
||||
|
||||
**AI 先给创作者一个像策划初稿的东西,而不是给一堆系统字段让创作者自己拼。**
|
||||
|
||||
## 2.3 系统托管层必须彻底隐藏专业运行结构
|
||||
|
||||
以下这类结构不应该默认要求创作者理解或编辑:
|
||||
|
||||
- `ThemePack`
|
||||
- `WorldStoryGraph`
|
||||
- `KnowledgeFact`
|
||||
- `VisibilitySlice`
|
||||
- `SceneNarrativeDirective`
|
||||
- `StorySignal`
|
||||
- `ThreadContract`
|
||||
- 数值预算
|
||||
- 稀有度映射
|
||||
- 掉落和 build 权重
|
||||
|
||||
创作者应该编辑的是自然语言与内容卡,而不是运行时图结构。
|
||||
|
||||
## 2.4 先少量必填,再逐层展开
|
||||
|
||||
最合理的工作流不是“开局填一大页表”,而是:
|
||||
|
||||
```text
|
||||
先填最小必填卡
|
||||
-> AI 生成世界初稿
|
||||
-> 创作者修改关键对象
|
||||
-> 系统继续展开长尾
|
||||
-> 创作者决定是否进入高级补充
|
||||
```
|
||||
|
||||
## 2.5 默认清爽,深度能力后置
|
||||
|
||||
结合当前项目约束,创作工作台默认不要把规则说明、底层字段、专业术语堆到 UI 面板里。
|
||||
|
||||
应该做到:
|
||||
|
||||
1. 默认只展示最有创作价值的卡片
|
||||
2. 高级内容折叠到后置面板
|
||||
3. 大多数系统结构不直接暴露
|
||||
4. 移动端也能完成最小创作闭环
|
||||
|
||||
---
|
||||
|
||||
## 3. 最终建议:三层分工
|
||||
|
||||
## 3.1 第一层:必须要求创作者手动填写
|
||||
|
||||
这一层只保留最影响作品质量的高杠杆锚点,建议默认强制填写 6 张卡。
|
||||
|
||||
## 3.2 第二层:AI 生成后支持创作者修改
|
||||
|
||||
这一层由 AI 根据第一层锚点自动展开成专业剧情策划初稿,创作者可以逐项修改、锁定、局部重生成。
|
||||
|
||||
## 3.3 第三层:其余都交给系统
|
||||
|
||||
这一层是把前两层编译成可运行游戏结构所需的系统字段、数值和运行时指令,默认不要求创作者处理。
|
||||
|
||||
---
|
||||
|
||||
## 4. 最低门槛方案:只强制手填 6 张卡
|
||||
|
||||
如果目标是尽可能降低门槛,同时又保留作品辨识度,建议只强制创作者填写以下 6 张卡。
|
||||
|
||||
## 4.1 卡 1:世界一句话与核心幻想
|
||||
|
||||
创作者必须手填:
|
||||
|
||||
- 世界一句话设定
|
||||
- 玩家来到这个世界最想体验的感觉
|
||||
- 这个世界和同类题材相比最不同的一点
|
||||
|
||||
原因:
|
||||
|
||||
- 这是作品的方向盘
|
||||
- 这是后续 AI 所有扩写的总锚点
|
||||
|
||||
推荐输入形态:
|
||||
|
||||
- 一句话文本
|
||||
- `1~3` 个体验关键词
|
||||
|
||||
## 4.2 卡 2:玩家身份与开局困境
|
||||
|
||||
创作者必须手填:
|
||||
|
||||
- 玩家是谁
|
||||
- 玩家开局最缺什么
|
||||
- 玩家为什么必须进入这场故事
|
||||
- 玩家天然站在什么位置上
|
||||
|
||||
原因:
|
||||
|
||||
- 玩家视角不清,后面所有剧情都会发散
|
||||
- 这是主线入口、关系入口和任务入口的共同基础
|
||||
|
||||
## 4.3 卡 3:主题气质与禁忌边界
|
||||
|
||||
创作者必须手填:
|
||||
|
||||
- 主题关键词
|
||||
- 情绪基调
|
||||
- 审美方向
|
||||
- 禁止出现或尽量避免的内容
|
||||
|
||||
原因:
|
||||
|
||||
- 这决定世界“是什么味道”
|
||||
- 这也是避免 AI 跑偏最有效的一层
|
||||
|
||||
推荐输入形态:
|
||||
|
||||
- 标签选择
|
||||
- 语气滑条
|
||||
- 一小段补充说明
|
||||
|
||||
## 4.4 卡 4:核心冲突
|
||||
|
||||
创作者必须手填:
|
||||
|
||||
- 当前世界最重要的 `1~3` 个明面冲突
|
||||
- 至少 `1` 个隐藏问题或暗面危机
|
||||
- 玩家最先接触的是哪条冲突
|
||||
|
||||
原因:
|
||||
|
||||
- 没有冲突,世界就只剩设定
|
||||
- 没有暗面问题,后续剧情就难以产生层次和改判
|
||||
|
||||
## 4.5 卡 5:关键关系钩子
|
||||
|
||||
这里不强制创作者一开始填写完整角色档案,只要求填写更高杠杆的“关系骨架”。
|
||||
|
||||
创作者必须手填:
|
||||
|
||||
- `2~4` 条关键关系钩子
|
||||
- 每条钩子至少说明:
|
||||
- 谁和谁有关
|
||||
- 关系是债、仇、误解、旧情、利用还是血缘
|
||||
- 这条关系里压着什么秘密或代价
|
||||
|
||||
原因:
|
||||
|
||||
- 作品的人味和记忆点主要来自关系张力
|
||||
- 关系钩子比完整角色长文更容易写,也更高杠杆
|
||||
|
||||
## 4.6 卡 6:标志性要素与硬规则
|
||||
|
||||
创作者必须手填:
|
||||
|
||||
- `2~5` 个标志性要素
|
||||
- 物件
|
||||
- 怪物
|
||||
- 制度
|
||||
- 仪式
|
||||
- 能力体系
|
||||
- 社会规则
|
||||
- 至少 `1~3` 条不能被 AI 擅自改写的硬规则
|
||||
|
||||
原因:
|
||||
|
||||
- 这决定世界是否有独特手感
|
||||
- 后续命名、剧情、物件和场景都会反复依赖这些母题
|
||||
|
||||
---
|
||||
|
||||
## 5. 不建议强制手填,但应该让 AI 生成后支持创作者修改的设定
|
||||
|
||||
这一层是平衡“低门槛”和“高质量”的关键。
|
||||
|
||||
创作者不需要从零填写这些内容,但 AI 生成后必须能看、能改、能锁定、能局部重生成。
|
||||
|
||||
## 5.1 世界外观层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 世界名称
|
||||
- 副标题
|
||||
- 世界简介
|
||||
- 宣传短句
|
||||
- 主题母题摘要
|
||||
- 命名风格建议
|
||||
|
||||
原因:
|
||||
|
||||
- 这些内容影响观感,但不值得强制占用开局填写成本
|
||||
|
||||
## 5.2 势力层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- `2~6` 个关键势力
|
||||
- 每个势力的公开目标
|
||||
- 每个势力的隐藏目标
|
||||
- 势力间的主要矛盾
|
||||
- 代表人物
|
||||
- 势力资源与禁忌
|
||||
|
||||
原因:
|
||||
|
||||
- 势力很重要,但让新手一开始手写完整势力表太重
|
||||
- 更合理的做法是让 AI 基于核心冲突先出草稿,再由创作者修正
|
||||
|
||||
## 5.3 关键角色层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 关键角色姓名
|
||||
- 外显身份
|
||||
- 公众面具
|
||||
- 当前压力
|
||||
- 表面目标
|
||||
- 真实目标
|
||||
- 背景旧事
|
||||
- 禁区
|
||||
- 与玩家关系方向
|
||||
- 角色个人线阶段
|
||||
- 背景章节 teaser
|
||||
|
||||
原因:
|
||||
|
||||
- 创作者已经通过“关系钩子”给出最关键的人物骨架
|
||||
- AI 负责把钩子展开成可编辑角色卡,创作者再做精修
|
||||
|
||||
## 5.4 关键地点层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- `4~10` 个关键地点
|
||||
- 每个地点的功能定位
|
||||
- 气氛和视觉母题
|
||||
- 涉及的线程和秘密
|
||||
- 首次进入时的情绪目标
|
||||
- 关联角色和标志性载体
|
||||
|
||||
原因:
|
||||
|
||||
- 地点是世界感的重要来源
|
||||
- 但新创作者未必能一开始就写出完整地点网络
|
||||
|
||||
## 5.5 世界线程层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 明线线程
|
||||
- 暗线线程
|
||||
- 旧事伤痕
|
||||
- 误导信息
|
||||
- 主要 handoff
|
||||
- 阶段揭示节奏
|
||||
|
||||
原因:
|
||||
|
||||
- 线程是专业剧情结构,适合 AI 先搭骨架
|
||||
- 但创作者必须有权修正哪条线更重要、哪条线该隐藏
|
||||
|
||||
## 5.6 主线章节层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 幕结构建议
|
||||
- 章节标题
|
||||
- 章节承诺
|
||||
- 转折设计
|
||||
- 高潮行动
|
||||
- 章节 handoff
|
||||
|
||||
原因:
|
||||
|
||||
- 创作者已经给出了世界目标、冲突和关系
|
||||
- AI 可以先把它们编成主线章节初稿
|
||||
- 创作者再选择保留、删减或重排
|
||||
|
||||
## 5.7 支线、角色线、阵营线层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 支线种子
|
||||
- 角色线阶段事件
|
||||
- 阵营线分歧点
|
||||
- 私聊或同伴互动节点
|
||||
- 支线和主线的互文关系
|
||||
|
||||
原因:
|
||||
|
||||
- 这是最适合 AI 拉开内容宽度的部分
|
||||
- 也是最需要创作者局部精修的部分
|
||||
|
||||
## 5.8 场景章节层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 场景章节标题
|
||||
- `opening / expansion / turning_point / climax / aftermath`
|
||||
- 情感锚点 NPC
|
||||
- 现场压力
|
||||
- 转折信息
|
||||
- 局部收束
|
||||
- 下一跳 handoff
|
||||
|
||||
原因:
|
||||
|
||||
- 当前项目已经在走“场景 = 章节单元”的方向
|
||||
- 这层非常适合 AI 编排出第一版,再由创作者补强记忆点
|
||||
|
||||
## 5.9 叙事载体层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 标志性物件
|
||||
- 文书
|
||||
- 残痕
|
||||
- 证物
|
||||
- 场景遗物
|
||||
- 怪物命名及其故事指向
|
||||
|
||||
创作者主要修改:
|
||||
|
||||
- 哪些载体最重要
|
||||
- 哪些载体和哪条线程绑定
|
||||
- 哪些载体需要更强的个人风格
|
||||
|
||||
## 5.10 文案包装层
|
||||
|
||||
建议 AI 先生成后可改:
|
||||
|
||||
- 角色简介
|
||||
- 地点短描述
|
||||
- 势力介绍
|
||||
- 章节标题候选
|
||||
- 任务标题与简述
|
||||
- 物件命名候选
|
||||
|
||||
原因:
|
||||
|
||||
- 这些内容适合 AI 批量铺量
|
||||
- 创作者只需要挑、改、锁定,不必从零起草
|
||||
|
||||
---
|
||||
|
||||
## 6. 其余设定应交给系统托管
|
||||
|
||||
以下内容不建议默认暴露给创作者编辑,应由系统根据前两层自动编译和维护。
|
||||
|
||||
## 6.1 题材与术语编译层
|
||||
|
||||
交给系统:
|
||||
|
||||
- `ThemePack`
|
||||
- 题材词汇表
|
||||
- 命名模式映射
|
||||
- 母题标签映射
|
||||
|
||||
原因:
|
||||
|
||||
- 这是系统为了统一生成风格而维护的内部层
|
||||
|
||||
## 6.2 世界图谱运行层
|
||||
|
||||
交给系统:
|
||||
|
||||
- `WorldStoryGraph`
|
||||
- `KnowledgeFact`
|
||||
- 事实 id
|
||||
- 线程内部关联
|
||||
- 旧事与角色的细粒度映射
|
||||
|
||||
原因:
|
||||
|
||||
- 创作者要的是“故事线能对”,不是维护图数据库
|
||||
|
||||
## 6.3 可见性和 prompt 裁剪层
|
||||
|
||||
交给系统:
|
||||
|
||||
- `VisibilitySlice`
|
||||
- 禁止注入信息列表
|
||||
- 当前可说信息
|
||||
- 推测信息
|
||||
- 越权泄露检查
|
||||
|
||||
原因:
|
||||
|
||||
- 这层必须稳定、严格、自动化
|
||||
- 不适合依赖创作者手动维护
|
||||
|
||||
## 6.4 运行时导演层
|
||||
|
||||
交给系统:
|
||||
|
||||
- `SceneNarrativeDirective`
|
||||
- 节奏推进指令
|
||||
- 披露预算
|
||||
- 当前主压力判断
|
||||
- 当前前景角色和前景载体
|
||||
|
||||
原因:
|
||||
|
||||
- 这是剧情运行时调度逻辑,不是创作表达层
|
||||
|
||||
## 6.5 任务编译层
|
||||
|
||||
交给系统:
|
||||
|
||||
- `ThreadContract`
|
||||
- `StorySignal`
|
||||
- step id
|
||||
- step 类型映射
|
||||
- 触发条件编译
|
||||
- 结算条件编译
|
||||
|
||||
说明:
|
||||
|
||||
- 创作者可以编辑“任务卡”和“章节卡”
|
||||
- 但不应默认编辑底层 contract 结构
|
||||
|
||||
## 6.6 数值与配置层
|
||||
|
||||
交给系统:
|
||||
|
||||
- 技能数值
|
||||
- 初始物品预算
|
||||
- 稀有度分布
|
||||
- 掉落权重
|
||||
- build 标签映射
|
||||
- 关系数值初始值
|
||||
- 敌对强度预算
|
||||
|
||||
说明:
|
||||
|
||||
- 创作者可以给“偏向”
|
||||
- 系统负责编译成具体数值
|
||||
|
||||
## 6.7 QA 与一致性层
|
||||
|
||||
交给系统:
|
||||
|
||||
- 设定冲突检查
|
||||
- 同名检查
|
||||
- 风格漂移检查
|
||||
- 关系矛盾检查
|
||||
- 主线与支线弱关联检查
|
||||
- 未解锁信息泄露检查
|
||||
- 长尾内容覆盖率检查
|
||||
|
||||
原因:
|
||||
|
||||
- 这属于高频维护型工作,最适合系统自动做
|
||||
|
||||
---
|
||||
|
||||
## 7. 按模块划分的最终边界表
|
||||
|
||||
| 模块 | 必须手填 | AI 生成后可改 | 系统托管 |
|
||||
| --- | --- | --- | --- |
|
||||
| 世界定位 | 世界一句话、核心幻想、差异点 | 世界名称、副标题、简介 | 题材词汇编译 |
|
||||
| 玩家视角 | 玩家身份、开局困境、初始动机 | 开局剧情摘要、开局目标文案 | 开局状态初始化 |
|
||||
| 主题边界 | 主题、气质、禁忌、硬边界 | 主题母题摘要、风格建议 | 风格约束编译 |
|
||||
| 核心冲突 | 明面冲突、隐藏危机 | 线程草稿、旧事伤痕、误导设计 | 世界图谱、事实映射 |
|
||||
| 关系骨架 | 关键关系钩子 | 关键角色卡、个人线阶段、背景章节 teaser | 关系数值、解锁条件 |
|
||||
| 标志性要素 | 标志物、怪物、制度、规则 | 标志载体卡、命名候选、衍生变体 | 物件指纹、掉落映射 |
|
||||
| 势力 | 不强制首轮手填 | 势力卡、代表人物、势力冲突 | 阵营状态映射 |
|
||||
| 地点 | 不强制首轮手填 | 关键地点卡、场景网络、氛围描述 | 场景连接编译 |
|
||||
| 主线 | 不强制首轮手写完整主线 | 幕结构、章节卡、高潮与 handoff | 章节状态编译 |
|
||||
| 支线/角色线 | 不强制首轮手写完整矩阵 | 支线种子、角色线事件、阵营线分歧 | 任务 contract 编译 |
|
||||
| 场景章节 | 不强制首轮手写全量章节 | 场景章节卡、阶段内容、章节载体 | signal 与导演层 |
|
||||
| 运行时结构 | 不建议创作者接触 | 不建议默认编辑 | 可见性、导演、信号、编译、QA |
|
||||
|
||||
---
|
||||
|
||||
## 8. 推荐创作流程
|
||||
|
||||
## 8.1 第一步:只填写最小必填集
|
||||
|
||||
创作者只需要完成:
|
||||
|
||||
1. 世界一句话与核心幻想
|
||||
2. 玩家身份与开局困境
|
||||
3. 主题气质与禁忌边界
|
||||
4. 核心冲突
|
||||
5. 关键关系钩子
|
||||
6. 标志性要素与硬规则
|
||||
|
||||
这一步应控制在:
|
||||
|
||||
- `5~15` 分钟
|
||||
- `200~800` 字
|
||||
- 或更少文字配合标签选择
|
||||
|
||||
## 8.2 第二步:AI 生成“策划初稿包”
|
||||
|
||||
系统根据最小输入,生成一份结构化初稿包,建议至少包括:
|
||||
|
||||
1. 世界标题与摘要
|
||||
2. `3~5` 个关键角色卡
|
||||
3. `2~4` 个势力卡
|
||||
4. `4~8` 个关键地点卡
|
||||
5. `3~5` 条世界线程
|
||||
6. `3~6` 个场景章节卡
|
||||
7. 一批支线种子和标志性载体
|
||||
|
||||
这里的重点不是一次补满全世界,而是先形成一个像样的内容骨架。
|
||||
|
||||
## 8.3 第三步:创作者只精修高价值卡片
|
||||
|
||||
建议默认优先让创作者编辑这 4 类卡片:
|
||||
|
||||
1. 关键角色
|
||||
2. 核心冲突与线程
|
||||
3. 关键地点
|
||||
4. 主线第一幕或前几个场景章节
|
||||
|
||||
这样能以最低编辑成本,最大幅度提升作品质量。
|
||||
|
||||
## 8.4 第四步:系统继续展开长尾
|
||||
|
||||
在关键卡片被锁定后,再由系统补:
|
||||
|
||||
- 长尾 NPC
|
||||
- 支持性地点
|
||||
- 次级支线
|
||||
- 普通物件
|
||||
- 任务包装
|
||||
- 文案变体
|
||||
|
||||
## 8.5 第五步:创作者按需进入高级模式
|
||||
|
||||
高级模式只对愿意深挖的人开放:
|
||||
|
||||
- 角色背景章节编辑
|
||||
- 场景章节细化
|
||||
- 支线矩阵补完
|
||||
- 阵营线分歧补强
|
||||
- 结局变量微调
|
||||
|
||||
这一步不是默认主流程。
|
||||
|
||||
---
|
||||
|
||||
## 9. 哪些内容应该支持“锁定 + 局部重生成”
|
||||
|
||||
为了既保证低门槛,又保证创作安全感,第二层内容必须支持锁定和局部重生成。
|
||||
|
||||
建议至少支持锁定这些对象:
|
||||
|
||||
1. 世界一句话与主题边界
|
||||
2. 核心冲突
|
||||
3. 关键角色
|
||||
4. 关键地点
|
||||
5. 势力卡
|
||||
6. 主线章节卡
|
||||
7. 场景章节卡
|
||||
8. 标志性载体
|
||||
|
||||
建议至少支持这些局部重生成动作:
|
||||
|
||||
1. 仅重生成长尾角色
|
||||
2. 仅重生成长尾地点
|
||||
3. 仅重生成支线种子
|
||||
4. 仅重生成物件与残痕
|
||||
5. 仅重生成某个角色卡
|
||||
6. 仅重生成某个场景章节
|
||||
7. 围绕已锁定角色重做主线第一幕
|
||||
|
||||
原则是:
|
||||
|
||||
**越高价值的锚点越要支持锁定,越低价值的铺量内容越适合重生成。**
|
||||
|
||||
---
|
||||
|
||||
## 10. 产品实现建议
|
||||
|
||||
## 10.1 默认 UI 只展示三段
|
||||
|
||||
建议工作台默认只展示:
|
||||
|
||||
1. 必填锚点
|
||||
2. AI 初稿卡片
|
||||
3. 高级模式入口
|
||||
|
||||
不要默认展示底层系统字段。
|
||||
|
||||
## 10.2 每张卡只保留自然语言输入
|
||||
|
||||
不要强迫创作者在首轮填写:
|
||||
|
||||
- tags
|
||||
- ids
|
||||
- 数值
|
||||
- 稀有度
|
||||
- 信号枚举
|
||||
- step schema
|
||||
|
||||
更合理的做法是:
|
||||
|
||||
- 让创作者输入自然语言或选择直觉标签
|
||||
- 再由系统编译成结构化字段
|
||||
|
||||
## 10.3 首轮生成后默认先看“精修建议”
|
||||
|
||||
AI 初稿生成后,不应该把创作者直接扔进一个大编辑器。
|
||||
|
||||
更好的做法是先给出:
|
||||
|
||||
1. 哪些卡片最值得改
|
||||
2. 哪些内容已经比较稳定
|
||||
3. 哪些内容仍然偏泛,需要创作者补个性
|
||||
|
||||
这样能明显提高创作者的修改效率。
|
||||
|
||||
## 10.4 移动端优先只保留高杠杆操作
|
||||
|
||||
移动端默认只应该支持:
|
||||
|
||||
1. 编辑必填卡
|
||||
2. 浏览和修改关键角色卡
|
||||
3. 浏览和修改关键地点卡
|
||||
4. 锁定 / 重生成
|
||||
5. 保存和继续创作
|
||||
|
||||
长表单和底层结构不要默认放在移动端主流程里。
|
||||
|
||||
---
|
||||
|
||||
## 11. 最后结论
|
||||
|
||||
如果目标是在自定义世界创作中真正平衡“降低门槛”和“提高作品质量”,最好的做法不是让创作者填更多字段,也不是把一切都交给 AI。
|
||||
|
||||
更合理的平衡是:
|
||||
|
||||
1. 创作者必须手填最小但高杠杆的 6 张卡,掌握世界灵魂。
|
||||
2. AI 根据这 6 张卡生成一套可编辑的专业剧情初稿,负责把骨架展开成角色、地点、线程、章节和载体。
|
||||
3. 创作者只精修最有价值的关键对象,锁定真正重要的内容。
|
||||
4. 其余运行结构、数值、可见性、任务编译和 QA 检查都交给系统托管。
|
||||
|
||||
一句话收束:
|
||||
|
||||
**创作者负责决定“这个世界为什么值得被创作”,AI 负责把它整理成可修改的策划初稿,系统负责把它稳定地跑成一个游戏世界。**
|
||||
@@ -0,0 +1,724 @@
|
||||
# 纯 Agent 式对话创作工具与结构化创作方案的对比评估及转型设计
|
||||
|
||||
更新时间:`2026-04-12`
|
||||
|
||||
## 0. 文档目标
|
||||
|
||||
这份文档用于评估两种自定义世界创作形态:
|
||||
|
||||
1. 当前方向
|
||||
- 基于“最小必填锚点 + AI 初稿卡片 + 系统托管层”的结构化创作方案
|
||||
|
||||
2. 纯 Agent 式方向
|
||||
- 以前台对话为唯一主交互,创作者主要通过和 Agent 聊天来完成世界构建、角色塑造、剧情扩展和修改
|
||||
|
||||
文档需要回答 3 个问题:
|
||||
|
||||
1. 两种方案各自的优缺点是什么?
|
||||
2. 对当前项目来说,纯 Agent 式是否更优?
|
||||
3. 如果要转换成纯 Agent 式对话创作工具,应该怎么设计,才能不把质量和可控性一起丢掉?
|
||||
|
||||
一句话结论先说:
|
||||
|
||||
**纯 Agent 式对话创作工具更适合当“低门槛入口”和“陪创作过程”,但不适合把整个创作系统做成无结构、无锁定、无摘要、无编译层的纯聊天黑箱。**
|
||||
|
||||
更稳的方向不是“只有聊天”,而是:
|
||||
|
||||
**前台主交互纯 Agent,后台继续保留结构化世界模型、锁定机制、局部重生成、编译层和质量护栏。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 对比对象定义
|
||||
|
||||
## 1.1 当前结构化创作方案是什么
|
||||
|
||||
当前方案的核心是:
|
||||
|
||||
1. 创作者手填最小高杠杆锚点
|
||||
2. AI 生成一批可编辑的剧情策划初稿卡片
|
||||
3. 系统把内容编译成运行时结构
|
||||
|
||||
它本质上是:
|
||||
|
||||
**结构化工作台 + AI 协作生成。**
|
||||
|
||||
创作者的主要行为是:
|
||||
|
||||
1. 填写关键卡片
|
||||
2. 修改关键角色、地点、势力、章节等内容卡
|
||||
3. 锁定重要内容
|
||||
4. 局部重生成次级内容
|
||||
|
||||
## 1.2 纯 Agent 式对话创作工具是什么
|
||||
|
||||
纯 Agent 式不是指“系统内部没有结构”,而是指:
|
||||
|
||||
**创作者前台几乎不需要面对表单和卡片编辑器,主要通过自然语言对话来完成创作。**
|
||||
|
||||
创作者的主要行为变成:
|
||||
|
||||
1. 用自然语言描述世界想法
|
||||
2. 回答 Agent 的追问
|
||||
3. 让 Agent 生成角色、地点、剧情和章节
|
||||
4. 通过聊天指令要求修改、锁定、重做、总结和导出
|
||||
|
||||
它本质上是:
|
||||
|
||||
**对话式创作入口 + Agent 主导的协同编排。**
|
||||
|
||||
## 1.3 真正需要比较的不是“聊天 VS 表单”,而是“主交互模式 VS 后台结构”
|
||||
|
||||
很多产品会把问题误判成:
|
||||
|
||||
- 要么做聊天
|
||||
- 要么做工作台
|
||||
|
||||
更准确的判断应该是:
|
||||
|
||||
1. 前台用户主要通过什么方式思考和输入?
|
||||
2. 后台系统是否仍然有稳定的世界模型和编译层?
|
||||
3. 创作者是否还能看见摘要、锁定内容和修改范围?
|
||||
|
||||
对当前项目来说,真正危险的不是“转成聊天”,而是:
|
||||
|
||||
**误把“纯 Agent 式”理解成“完全不需要结构化世界状态”。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 总体结论
|
||||
|
||||
## 2.1 纯 Agent 式的主要优势
|
||||
|
||||
纯 Agent 式最大的价值,在于降低开局压力和创作焦虑。
|
||||
|
||||
它更擅长:
|
||||
|
||||
1. 帮不擅长表单和结构思考的创作者起步
|
||||
2. 在创作者思路模糊时做追问和陪创作
|
||||
3. 把“我要做一个世界”变成一次自然聊天
|
||||
4. 动态决定追问深度,而不是一上来摆很多字段
|
||||
5. 让创作者感觉自己是在和一个懂 RPG 的剧情搭档共创
|
||||
|
||||
## 2.2 纯 Agent 式的主要问题
|
||||
|
||||
纯 Agent 式最大的问题,不是能不能生成内容,而是:
|
||||
|
||||
**长项目一旦进入中后期,它会天然丢失可控性、可扫描性、可局部编辑性和可审计性。**
|
||||
|
||||
它最容易出现这些问题:
|
||||
|
||||
1. 聊天很多,但世界状态越来越难总览
|
||||
2. 角色、地点、势力和章节信息散落在多轮消息里
|
||||
3. 锁定范围不清,重生成容易误伤已有内容
|
||||
4. Agent 很容易“替创作者决定太多”
|
||||
5. 长会话越来越贵,越来越慢,也越来越容易漂移
|
||||
|
||||
## 2.3 对当前项目的判断
|
||||
|
||||
对当前项目而言:
|
||||
|
||||
1. 纯 Agent 式非常适合做创作入口
|
||||
2. 纯 Agent 式也很适合做关键对象的精修与头脑风暴
|
||||
3. 纯 Agent 式不适合作为唯一内容管理方式
|
||||
|
||||
因此更推荐的方向是:
|
||||
|
||||
**Agent-first,而不是 Agent-only。**
|
||||
|
||||
也就是:
|
||||
|
||||
1. 前台以对话为主
|
||||
2. 后台仍保留结构化世界状态
|
||||
3. 关键内容仍然可被锁定、摘要、对比、局部重生成和导出
|
||||
|
||||
---
|
||||
|
||||
## 3. 纯 Agent 式对比当前方案的优缺点
|
||||
|
||||
## 3.1 对比表
|
||||
|
||||
| 维度 | 当前结构化方案 | 纯 Agent 式方案 | 更优者 |
|
||||
| --- | --- | --- | --- |
|
||||
| 首次上手门槛 | 比纯聊天高,需要理解少量卡片与阶段 | 最低,只需开口描述想法 | 纯 Agent |
|
||||
| 创作陪伴感 | 中等,AI 更像工具 | 很强,Agent 更像搭档 | 纯 Agent |
|
||||
| 思路模糊时的引导能力 | 有限,更多靠卡片提示 | 很强,可动态追问和启发 | 纯 Agent |
|
||||
| 世界整体可扫描性 | 强,卡片和结构更容易总览 | 弱,聊天记录天然碎片化 | 当前方案 |
|
||||
| 单对象精确编辑 | 强,适合定点修改 | 中等,容易在对话里带出额外变化 | 当前方案 |
|
||||
| 锁定与局部重生成 | 容易做明确边界 | 容易模糊,需额外设计指令语义 | 当前方案 |
|
||||
| 长项目稳定性 | 高,适合几十个对象持续维护 | 中等偏弱,越长越依赖摘要和记忆管理 | 当前方案 |
|
||||
| 内容一致性维护 | 更容易做编译与 QA | 纯聊天很难稳定维护,需要后台隐藏编译 | 当前方案 |
|
||||
| 移动端输入体验 | 表单负担偏大 | 聊天输入天然更友好 | 纯 Agent |
|
||||
| 移动端结果总览 | 卡片更好浏览 | 长聊天记录不利于回看 | 当前方案 |
|
||||
| 专业策划生产效率 | 中后期更高 | 前期更快,中后期容易反复确认 | 当前方案 |
|
||||
| 新手用户心理压力 | 偏高,容易觉得要“填很多东西” | 低,更像在聊一个想法 | 纯 Agent |
|
||||
| 实现复杂度 | 已有方向较明确 | 真正做好会更复杂,需要对话层和隐藏结构双系统 | 当前方案 |
|
||||
| Token / 成本 / 延迟 | 更容易按模块调用 | 长会话上下文更重,成本更高 | 当前方案 |
|
||||
| 可审计和交接 | 强,更适合多人协作 | 弱,需要额外导出和摘要机制 | 当前方案 |
|
||||
|
||||
## 3.2 当前结构化方案的主要优点
|
||||
|
||||
当前方案更强的地方在于:
|
||||
|
||||
1. 有明确的内容边界
|
||||
2. 更容易做锁定、重生成和局部修改
|
||||
3. 更适合中大型世界的长期维护
|
||||
4. 更适合和后端编译层、任务层、章节层做稳定映射
|
||||
5. 更容易把专业剧情策划流程映射成可执行数据
|
||||
|
||||
它的本质优势是:
|
||||
|
||||
**稳定、清楚、可扩展。**
|
||||
|
||||
## 3.3 当前结构化方案的主要缺点
|
||||
|
||||
当前方案更弱的地方在于:
|
||||
|
||||
1. 仍然有“我要开始填工具了”的压力
|
||||
2. 对不擅长结构化思考的新手不够友好
|
||||
3. 澄清、启发和陪创作感不够强
|
||||
4. 很容易从“低门槛工作台”滑向“字段很多的编辑器”
|
||||
5. 移动端如果处理不好,会有明显表单压迫感
|
||||
|
||||
## 3.4 纯 Agent 式方案的主要优点
|
||||
|
||||
纯 Agent 式更强的地方在于:
|
||||
|
||||
1. 入口极低
|
||||
2. 更符合普通人“先说想法”的自然习惯
|
||||
3. 更适合模糊创意逐步收束
|
||||
4. 更容易把澄清问题变成真实协作
|
||||
5. 更容易营造“有专业编剧陪你做世界”的体验
|
||||
|
||||
它的本质优势是:
|
||||
|
||||
**自然、轻松、像在共创。**
|
||||
|
||||
## 3.5 纯 Agent 式方案的主要缺点
|
||||
|
||||
纯 Agent 式更弱的地方在于:
|
||||
|
||||
1. 世界模型隐藏得太深时,创作者会失去整体掌控感
|
||||
2. 多轮对话后,已确定内容不容易被清晰回看
|
||||
3. 局部重做和精确编辑边界会变模糊
|
||||
4. Agent 容易过度代写、过度主导
|
||||
5. 没有强摘要和锁定机制时,创意很容易漂移
|
||||
|
||||
它的本质问题是:
|
||||
|
||||
**天然更擅长起步,不天然擅长收口。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 对当前项目是否值得转成纯 Agent 式的判断
|
||||
|
||||
## 4.1 值得转的部分
|
||||
|
||||
以下环节非常适合转成纯 Agent 主交互:
|
||||
|
||||
1. 首次创作入口
|
||||
2. 世界灵魂锚点收集
|
||||
3. 低信息量输入后的澄清与启发
|
||||
4. 关键角色、关键地点、核心冲突的初稿展开
|
||||
5. 对单个角色或单个章节做陪创作式精修
|
||||
|
||||
因为这些环节的关键问题不是“字段如何摆放”,而是:
|
||||
|
||||
**创作者有没有被真正引导出自己想做的世界。**
|
||||
|
||||
## 4.2 不值得直接转成纯聊天黑箱的部分
|
||||
|
||||
以下环节不适合彻底做成无结构纯聊天:
|
||||
|
||||
1. 长项目世界管理
|
||||
2. 大量角色、地点、支线、章节的总览
|
||||
3. 锁定与局部重生成
|
||||
4. 运行时结构编译
|
||||
5. 质量审计与一致性检查
|
||||
6. 导出和交付
|
||||
|
||||
这些环节需要的是:
|
||||
|
||||
**稳定的结构化世界状态,而不是越来越长的聊天记录。**
|
||||
|
||||
## 4.3 最合理的判断
|
||||
|
||||
如果硬要二选一:
|
||||
|
||||
1. 对新手用户和移动端体验,纯 Agent 更有吸引力
|
||||
2. 对专业生产、长期维护和内容质量,当前结构化方案更稳
|
||||
|
||||
所以真正适合当前项目的不是完全替换,而是:
|
||||
|
||||
**把当前方案的“结构和护栏”保留,把用户感受到的“入口和协作方式”改成纯 Agent。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 如果要转换成纯 Agent 式,对什么必须保持不变
|
||||
|
||||
纯 Agent 式可以改变前台交互,但不应该改变下面这些底层原则。
|
||||
|
||||
## 5.1 内容分层边界不能变
|
||||
|
||||
即使转成纯 Agent 式,也仍然要保留这三层:
|
||||
|
||||
1. 创作者必须确认的高杠杆锚点
|
||||
2. AI 生成但允许创作者修改的策划初稿层
|
||||
3. 系统托管的运行时编译层
|
||||
|
||||
变化的只是:
|
||||
|
||||
- 这些内容不一定通过卡片表单采集
|
||||
- 可以通过对话逐步收集和确认
|
||||
|
||||
不应该变化的是:
|
||||
|
||||
- 谁来决定世界灵魂
|
||||
- 谁来决定运行时结构
|
||||
|
||||
## 5.2 锁定机制不能变
|
||||
|
||||
纯 Agent 式必须仍然支持:
|
||||
|
||||
1. 锁定世界主题
|
||||
2. 锁定核心冲突
|
||||
3. 锁定关键角色
|
||||
4. 锁定关键地点
|
||||
5. 锁定主线章节
|
||||
6. 锁定场景章节
|
||||
7. 只重做未锁定部分
|
||||
|
||||
否则纯 Agent 式会很快变成:
|
||||
|
||||
**每次聊一句,世界都在偷偷漂移。**
|
||||
|
||||
## 5.3 局部重生成机制不能变
|
||||
|
||||
纯 Agent 式里也必须支持:
|
||||
|
||||
1. 只重生成长尾 NPC
|
||||
2. 只重生成次级地点
|
||||
3. 只重生成某个角色卡
|
||||
4. 只重生成某个章节
|
||||
5. 围绕锁定对象重做剩余草稿
|
||||
|
||||
如果这点没有做好,对话就会越来越像“整世界覆盖式重写”。
|
||||
|
||||
## 5.4 摘要、快照、差异对比不能变
|
||||
|
||||
纯 Agent 工具如果没有这些能力,后期一定失控:
|
||||
|
||||
1. 当前世界摘要
|
||||
2. 已锁定内容清单
|
||||
3. 本轮修改了什么
|
||||
4. 当前有哪些待确认假设
|
||||
5. 能否回退到上一版本
|
||||
|
||||
所以:
|
||||
|
||||
**前台可以纯聊天,后台不能没有版本化世界圣经。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 转成纯 Agent 式后的产品定义
|
||||
|
||||
## 6.1 定义
|
||||
|
||||
建议把转型后的工具定义为:
|
||||
|
||||
**以 Agent 对话为主交互的 RPG 世界共创工具。**
|
||||
|
||||
它不是:
|
||||
|
||||
- 单纯聊天框
|
||||
- 一次性大文本生成器
|
||||
- 没有状态的陪聊机器人
|
||||
|
||||
它应该是:
|
||||
|
||||
1. 会主动澄清
|
||||
2. 会阶段性总结
|
||||
3. 会把聊天结果沉淀成结构化世界状态
|
||||
4. 会提醒风险和冲突
|
||||
5. 会在创作者要求时进行局部重写和定向扩展
|
||||
|
||||
## 6.2 正确理解
|
||||
|
||||
最重要的一句定义是:
|
||||
|
||||
**界面可以纯 Agent,数据层绝不能纯会话。**
|
||||
|
||||
也就是说:
|
||||
|
||||
1. 创作者看到的是对话
|
||||
2. 系统内部维护的是世界模型、锁定状态、摘要和编译结果
|
||||
|
||||
---
|
||||
|
||||
## 7. 纯 Agent 式工具的推荐交互模型
|
||||
|
||||
## 7.1 阶段 A:创作意图收集
|
||||
|
||||
Agent 不直接要求用户填表,而是通过 `1~3` 轮自然对话收集最小锚点。
|
||||
|
||||
目标是确认:
|
||||
|
||||
1. 世界一句话
|
||||
2. 玩家身份
|
||||
3. 核心冲突
|
||||
4. 主题气质
|
||||
5. 关键关系钩子
|
||||
6. 标志性要素
|
||||
|
||||
这实际上和当前“最小必填 6 张卡”是同一套内容,只是采集方式改成对话。
|
||||
|
||||
## 7.2 阶段 B:Agent 输出首轮世界底稿
|
||||
|
||||
Agent 首轮不应该直接铺满全世界,而应该给出一份简明底稿,例如:
|
||||
|
||||
1. 世界标题和摘要
|
||||
2. 玩家开局定位
|
||||
3. 核心冲突结构
|
||||
4. `3~5` 个关键角色
|
||||
5. `4~6` 个关键地点
|
||||
6. `2~4` 个势力
|
||||
7. 主线第一幕简稿
|
||||
|
||||
同时必须明确分成 3 类:
|
||||
|
||||
1. 已确认内容
|
||||
2. 建议内容
|
||||
3. 待确认内容
|
||||
|
||||
## 7.3 阶段 C:创作者锁定锚点
|
||||
|
||||
在纯 Agent 模式里,锁定行为必须被显式支持。
|
||||
|
||||
用户可以自然说:
|
||||
|
||||
- 这个世界观锁定
|
||||
- 这个角色保留,不要再改
|
||||
- 只把第一幕重做一下
|
||||
- 势力关系别动,重新想地点
|
||||
|
||||
系统需要把这些自然语言翻译成正式的锁定状态和重生成范围。
|
||||
|
||||
## 7.4 阶段 D:按对象逐步精修
|
||||
|
||||
Agent 不应该每轮都继续扩全局,而应该支持“单对象工作模式”。
|
||||
|
||||
例如:
|
||||
|
||||
1. 只精修某个角色
|
||||
2. 只精修某个地点
|
||||
3. 只精修某个场景章节
|
||||
4. 只精修主线第一幕
|
||||
5. 只精修一条支线
|
||||
|
||||
这样可以避免每轮修改都把整个世界重新搅动一次。
|
||||
|
||||
## 7.5 阶段 E:系统后台自动编译与审计
|
||||
|
||||
每一轮重要修改后,系统后台应自动做:
|
||||
|
||||
1. 世界图谱更新
|
||||
2. 可见性边界更新
|
||||
3. 章节和任务编译
|
||||
4. 设定冲突检查
|
||||
5. 弱关联检查
|
||||
6. 风格一致性检查
|
||||
|
||||
这些结果不一定全部展示,但必须被系统持续维护。
|
||||
|
||||
## 7.6 阶段 F:导出世界圣经和可编辑初稿
|
||||
|
||||
纯 Agent 模式的最终产物不能只是一串聊天记录。
|
||||
|
||||
至少要能导出:
|
||||
|
||||
1. 世界摘要
|
||||
2. 锁定锚点
|
||||
3. 关键角色卡
|
||||
4. 关键地点卡
|
||||
5. 势力卡
|
||||
6. 主线章节简稿
|
||||
7. 支线种子
|
||||
8. 场景章节草稿
|
||||
9. 风险与待确认项
|
||||
|
||||
---
|
||||
|
||||
## 8. 纯 Agent 式工具需要的后台结构
|
||||
|
||||
## 8.1 会话层之外必须维护的核心状态
|
||||
|
||||
建议后台至少维护下面这些结构:
|
||||
|
||||
| 结构 | 作用 |
|
||||
| --- | --- |
|
||||
| `creatorIntentProfile` | 当前创作者最初和最新的创作意图 |
|
||||
| `lockedAnchors` | 已确认不可自动改写的内容 |
|
||||
| `worldDraftSnapshot` | 当前世界底稿快照 |
|
||||
| `editableDraftCards` | 角色、地点、势力、章节等可编辑初稿 |
|
||||
| `pendingClarifications` | 当前还未确认的问题 |
|
||||
| `changeLog` | 每轮发生了什么变化 |
|
||||
| `qualityFindings` | 冲突、泄露、弱关联和风格漂移结果 |
|
||||
|
||||
## 8.2 每轮对话后的处理流程
|
||||
|
||||
建议每次用户发言后走这条后台链:
|
||||
|
||||
```text
|
||||
用户消息
|
||||
-> 意图识别
|
||||
-> 判断是在回答问题 / 修改对象 / 请求重生成 / 请求总结 / 请求锁定
|
||||
-> 更新 creatorIntentProfile 或 worldDraftSnapshot
|
||||
-> 重新编译相关草稿对象
|
||||
-> 运行质量检查
|
||||
-> 生成本轮回复
|
||||
-> 同步更新摘要、待确认项和 changeLog
|
||||
```
|
||||
|
||||
这条流程说明:
|
||||
|
||||
**纯 Agent 的前台体验背后,实际仍然是一个结构化内容状态机。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 纯 Agent 式前台应该如何设计
|
||||
|
||||
## 9.1 主界面以对话为主
|
||||
|
||||
主界面可以只有一个核心聊天线程,但不建议只有聊天气泡。
|
||||
|
||||
建议保留 3 个轻量辅助区:
|
||||
|
||||
1. 顶部固定摘要
|
||||
- 当前世界名
|
||||
- 当前阶段
|
||||
- 当前聚焦对象
|
||||
|
||||
2. 锁定内容条
|
||||
- 展示已锁定的世界观、角色、地点、章节
|
||||
|
||||
3. 当前草稿摘要抽屉
|
||||
- 展示关键角色、关键地点、主线第一幕等的简要卡片
|
||||
|
||||
这些区域不是表单编辑器,而是:
|
||||
|
||||
**对话模式下帮助用户保持掌控感的最小结构提示。**
|
||||
|
||||
## 9.2 支持快捷动作
|
||||
|
||||
为了防止用户每次都要自己组织复杂自然语言,建议保留轻量快捷动作:
|
||||
|
||||
1. 总结当前设定
|
||||
2. 锁定当前版本
|
||||
3. 只重做这一项
|
||||
4. 展开主线第一幕
|
||||
5. 增加一个关键角色
|
||||
6. 给我 3 个更有辨识度的版本
|
||||
7. 检查是否有设定冲突
|
||||
|
||||
这类动作按钮不破坏纯 Agent 主交互,反而能显著降低误解成本。
|
||||
|
||||
## 9.3 Agent 的提问规则
|
||||
|
||||
Agent 不能像问卷系统,也不能一次追问太多。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 一次最多追问 `1~3` 个问题
|
||||
2. 问题必须是当前最缺的高杠杆信息
|
||||
3. 每次追问都给默认建议方向
|
||||
4. 如果创作者不想细答,允许 Agent 先代补一个版本再确认
|
||||
|
||||
这样才能保持“像聊天”,而不是“像客服表单”。
|
||||
|
||||
## 9.4 Agent 的总结规则
|
||||
|
||||
纯 Agent 工具必须高频做阶段性总结。
|
||||
|
||||
建议在这些时机自动总结:
|
||||
|
||||
1. 首轮世界底稿生成后
|
||||
2. 锁定任意关键锚点后
|
||||
3. 完成某个角色精修后
|
||||
4. 主线第一幕生成后
|
||||
5. 每累计 `5~8` 轮重要对话后
|
||||
|
||||
总结必须包含:
|
||||
|
||||
1. 已确认内容
|
||||
2. 新增内容
|
||||
3. 待确认内容
|
||||
4. 潜在风险
|
||||
|
||||
---
|
||||
|
||||
## 10. 纯 Agent 式下的锁定、重生成与修改语义
|
||||
|
||||
## 10.1 锁定语义
|
||||
|
||||
建议支持以下语义:
|
||||
|
||||
1. 锁定对象
|
||||
2. 锁定字段
|
||||
3. 锁定关系
|
||||
4. 锁定当前版本
|
||||
|
||||
例如:
|
||||
|
||||
- 锁定这个角色的身份和秘密,但可以重写语气
|
||||
- 锁定这条冲突,不要再改动它的基本方向
|
||||
- 锁定第一幕结构,只优化角色高光
|
||||
|
||||
## 10.2 重生成语义
|
||||
|
||||
建议支持以下语义:
|
||||
|
||||
1. 完整替换
|
||||
2. 保留锚点重做
|
||||
3. 仅补长尾
|
||||
4. 给出多个候选版本
|
||||
|
||||
例如:
|
||||
|
||||
- 保留世界观和角色,重做关键地点
|
||||
- 保留第一幕结构,给我三个更强的转折版本
|
||||
- 只补 5 个更有辨识度的路人 NPC
|
||||
|
||||
## 10.3 修改语义
|
||||
|
||||
Agent 应能识别这些常见修改类型:
|
||||
|
||||
1. 收紧风格
|
||||
2. 增强冲突
|
||||
3. 提高角色辨识度
|
||||
4. 减少套路感
|
||||
5. 让地点更有故事残痕
|
||||
6. 把支线和主线绑定得更紧
|
||||
7. 提高队友反应和选择后果
|
||||
|
||||
这些应该是内容层意图,而不是要求用户直接碰底层字段。
|
||||
|
||||
---
|
||||
|
||||
## 11. 纯 Agent 式的主要风险与防护
|
||||
|
||||
## 11.1 风险 1:对话越长,世界越散
|
||||
|
||||
防护方式:
|
||||
|
||||
1. 周期性强制摘要
|
||||
2. 关键内容结构化落库
|
||||
3. 锁定内容固定展示
|
||||
4. 提供“当前世界圣经”入口
|
||||
|
||||
## 11.2 风险 2:Agent 过度代写,创作者失去作品归属感
|
||||
|
||||
防护方式:
|
||||
|
||||
1. 高杠杆锚点必须要求确认
|
||||
2. 重要改动前先说“我准备改什么”
|
||||
3. 默认优先给多个候选,而不是直接盖写
|
||||
4. 允许创作者随时回退到旧版本
|
||||
|
||||
## 11.3 风险 3:局部修改带出全局漂移
|
||||
|
||||
防护方式:
|
||||
|
||||
1. 只在目标作用域内修改
|
||||
2. 修改后自动展示影响范围
|
||||
3. 对高风险改动要求二次确认
|
||||
|
||||
## 11.4 风险 4:看起来轻松,实际上难以收口
|
||||
|
||||
防护方式:
|
||||
|
||||
1. 阶段化工作流
|
||||
2. 每阶段有明确产物
|
||||
3. 不是无限聊天,而是要进入“底稿确认 -> 精修 -> 导出”
|
||||
|
||||
## 11.5 风险 5:成本和延迟持续上升
|
||||
|
||||
防护方式:
|
||||
|
||||
1. 长会话摘要压缩
|
||||
2. 按对象加载上下文
|
||||
3. 局部编译,而不是每轮重编整世界
|
||||
|
||||
---
|
||||
|
||||
## 12. 推荐转型路线
|
||||
|
||||
不建议一步到位把当前方案彻底替换成纯聊天。
|
||||
|
||||
更稳的路线是分 3 步走。
|
||||
|
||||
## 12.1 第一步:先把纯 Agent 做成默认入口
|
||||
|
||||
这一阶段:
|
||||
|
||||
1. 用户进入后直接和 Agent 聊
|
||||
2. Agent 帮用户收集最小锚点
|
||||
3. 系统在后台仍然生成当前方案里的结构化初稿
|
||||
4. 结果页仍保留为可选工作台
|
||||
|
||||
这一阶段的目标是:
|
||||
|
||||
**把“起步方式”改成聊天,但不动后端结构主链。**
|
||||
|
||||
## 12.2 第二步:让关键对象编辑也支持 Agent 化
|
||||
|
||||
这一阶段:
|
||||
|
||||
1. 角色、地点、势力、主线第一幕都支持在聊天里精修
|
||||
2. Agent 支持锁定、重做、总结、对比
|
||||
3. 工作台逐步退成辅助视图,而不是默认主路径
|
||||
|
||||
这一阶段的目标是:
|
||||
|
||||
**让大多数高价值修改都可以通过聊天完成。**
|
||||
|
||||
## 12.3 第三步:工作台只保留总览和导出
|
||||
|
||||
到了这一阶段,前台已经基本纯 Agent 化,但仍建议保留:
|
||||
|
||||
1. 世界圣经总览
|
||||
2. 已锁定对象列表
|
||||
3. 版本快照
|
||||
4. 风险与 QA 结果
|
||||
5. 导出面板
|
||||
|
||||
这一阶段的目标不是消灭结构,而是:
|
||||
|
||||
**让结构从“编辑入口”退成“掌控和收口工具”。**
|
||||
|
||||
---
|
||||
|
||||
## 13. 最后结论
|
||||
|
||||
纯 Agent 式对话创作工具的最大优势,是把创作入口从“填写工具”变成“和懂创作的人对话”。
|
||||
|
||||
它会明显提升:
|
||||
|
||||
1. 首次上手意愿
|
||||
2. 创作陪伴感
|
||||
3. 模糊想法的收束效率
|
||||
4. 移动端可用性
|
||||
|
||||
但它也天然会削弱:
|
||||
|
||||
1. 世界总览
|
||||
2. 精确编辑
|
||||
3. 局部重生成边界
|
||||
4. 长项目稳定性
|
||||
5. 质量审计与交接能力
|
||||
|
||||
因此,对当前项目最合理的方向不是彻底放弃结构化方案,而是把它升级成:
|
||||
|
||||
**前台纯 Agent 主交互,后台结构化世界模型持续存在,锁定、摘要、快照、局部重生成和质量护栏全部保留。**
|
||||
|
||||
一句话收束:
|
||||
|
||||
**可以把“创作入口”彻底 Agent 化,但绝不能把“世界状态管理”也做成纯聊天。**
|
||||
@@ -0,0 +1,660 @@
|
||||
# 自定义世界自有设定层优化方案
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份文档要解决的问题是:
|
||||
|
||||
**当前自定义世界虽然已经是唯一正式可玩的世界入口,但它底层仍依赖武侠 / 仙侠模板设定。**
|
||||
|
||||
本次优化目标不是直接删除这些依赖,而是把它们逐步改造成:
|
||||
|
||||
**属于自定义世界自身的设定层,并且这套设定层必须能通用于任何题材。**
|
||||
|
||||
同时必须满足一条底线:
|
||||
|
||||
**不能破坏当前自定义世界生成流程的任何可用功能。**
|
||||
|
||||
一句话定义:
|
||||
|
||||
**让自定义世界从“借模板世界运行”,升级成“拥有自有设定层、可跨题材运行”的架构。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计原则
|
||||
|
||||
这次优化必须同时遵守 4 条原则:
|
||||
|
||||
1. 设定归自定义世界自身所有
|
||||
- 运行时、生成期、表现层真正依赖的世界设定,应该落回 `CustomWorldProfile` 或由它直接编译出的配置。
|
||||
|
||||
2. 设定必须跨题材
|
||||
- 新设定不能只是把“武侠 / 仙侠”换一个更抽象的名字。
|
||||
- 它必须能支撑奇幻、科幻、悬疑、校园、末世、神话、现代、海洋、裂界等任何题材。
|
||||
|
||||
3. 优化优先做兼容迁移
|
||||
- 不能先删旧字段,再补新结构。
|
||||
- 必须先补新设定层,再逐步迁读,最后再让旧模板字段退化成兼容层。
|
||||
|
||||
4. 不能增加创作者负担
|
||||
- 这次不是让创作者多填一堆底层 schema。
|
||||
- 这些设定仍然应由 AI / 系统编译出来,只是所有权从模板世界转移到自定义世界自己。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前自定义世界实际依赖了什么
|
||||
|
||||
根据 [CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md](../reference/CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md),当前依赖可以归纳成 6 组:
|
||||
|
||||
1. 模板锚点字段
|
||||
- `templateWorldType`
|
||||
- `WorldTemplateType`
|
||||
|
||||
2. 规则桥接
|
||||
- `resolveRuleWorldType(...)`
|
||||
|
||||
3. 主题与词汇底板
|
||||
- `detectCustomWorldThemeMode(...)`
|
||||
- `buildThemePackFromWorldProfile(...)`
|
||||
|
||||
4. 属性、资源词与经济 fallback
|
||||
- 预设属性 schema
|
||||
- 资源命名
|
||||
- 初始货币规则
|
||||
|
||||
5. 内容骨架
|
||||
- 角色模板骨架
|
||||
- 怪物模板池
|
||||
- 场景视觉参考池
|
||||
|
||||
6. prompt 兼容字段
|
||||
- `framework` 生成仍要求输出 `templateWorldType`
|
||||
|
||||
这些东西现在还不能直接删,因为:
|
||||
|
||||
**它们不是单纯的预设世界残留,而是当前自定义世界生成与运行时的真实支撑层。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 本次优化的核心思路
|
||||
|
||||
这次不建议新增很多彼此平行的新系统,而是把现有模板依赖统一收束成:
|
||||
|
||||
**自定义世界自己的 5 层设定层。**
|
||||
|
||||
这 5 层分别是:
|
||||
|
||||
1. 语义锚层
|
||||
2. 规则层
|
||||
3. 表现层
|
||||
4. 原型参考层
|
||||
5. 兼容迁移层
|
||||
|
||||
这样可以让现在分散在:
|
||||
|
||||
- 模板世界枚举
|
||||
- 预设 schema
|
||||
- 视觉参考池
|
||||
- 怪物池
|
||||
- ThemePack 底板
|
||||
|
||||
这些地方的依赖,被重新编译回 `CustomWorldProfile` 自己的配置。
|
||||
|
||||
---
|
||||
|
||||
## 4. 目标结构
|
||||
|
||||
## 4.1 语义锚层:替代 `templateWorldType`
|
||||
|
||||
当前 `templateWorldType` 实际在回答的不是“你是不是武侠”,而是:
|
||||
|
||||
1. 这个世界更接近哪类冲突结构
|
||||
2. 这个世界更接近哪类制度和禁忌
|
||||
3. 这个世界更接近哪类叙事载体与力量来源
|
||||
|
||||
所以应把它升级成一套真正属于自定义世界自己的语义锚:
|
||||
|
||||
```ts
|
||||
interface CustomWorldSemanticAnchor {
|
||||
genreSignals: string[];
|
||||
conflictForms: string[];
|
||||
institutionTypes: string[];
|
||||
tabooTypes: string[];
|
||||
carrierTypes: string[];
|
||||
forceSystemTypes: string[];
|
||||
atmosphereTags: string[];
|
||||
}
|
||||
```
|
||||
|
||||
这层应该回答:
|
||||
|
||||
1. 这个世界的主要矛盾像什么
|
||||
2. 这个世界的秩序结构像什么
|
||||
3. 这个世界的危险和禁忌像什么
|
||||
4. 这个世界的线索、遗物、文书、证物、技术、仪式像什么
|
||||
|
||||
关键点:
|
||||
|
||||
- 这里不再出现“武侠 / 仙侠”的模板世界名
|
||||
- 只保留通用语义
|
||||
|
||||
例如:
|
||||
|
||||
- `institutionTypes`
|
||||
- 宗门
|
||||
- 公司
|
||||
- 学园
|
||||
- 教团
|
||||
- 调查局
|
||||
- 舰队
|
||||
- 部族
|
||||
|
||||
- `forceSystemTypes`
|
||||
- 灵脉
|
||||
- 科技
|
||||
- 仪式
|
||||
- 契约
|
||||
- 血统
|
||||
- 神谕
|
||||
- 污染
|
||||
|
||||
这就天然跨题材了。
|
||||
|
||||
---
|
||||
|
||||
## 4.2 规则层:把 fallback 变成自定义世界自己的规则设定
|
||||
|
||||
当前很多规则仍然会回落到武侠 / 仙侠:
|
||||
|
||||
- 属性 schema
|
||||
- 资源命名
|
||||
- 经济命名
|
||||
- 初始货币
|
||||
|
||||
优化后应由自定义世界自己持有:
|
||||
|
||||
```ts
|
||||
interface CustomWorldRuleProfile {
|
||||
attributeSchema: WorldAttributeSchema;
|
||||
resourceLabels: {
|
||||
hp: string;
|
||||
mp: string;
|
||||
maxHp: string;
|
||||
maxMp: string;
|
||||
damage: string;
|
||||
guard: string;
|
||||
range: string;
|
||||
cooldown: string;
|
||||
manaCost: string;
|
||||
currency: string;
|
||||
};
|
||||
economyProfile: {
|
||||
initialCurrency: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
这意味着以后运行时读取逻辑应优先变成:
|
||||
|
||||
1. 先读 `profile.ruleProfile`
|
||||
2. 再读 `profile.attributeSchema`
|
||||
3. 最后才允许读兼容 fallback
|
||||
|
||||
而不是:
|
||||
|
||||
1. 先判断 `WUXIA / XIANXIA`
|
||||
2. 再猜自定义世界应该像哪边
|
||||
|
||||
这层的原则是:
|
||||
|
||||
**规则是这个自定义世界自己的,不再借模板世界托管。**
|
||||
|
||||
---
|
||||
|
||||
## 4.3 表现层:把 ThemePack 变成自定义世界自身的派生物
|
||||
|
||||
当前 `ThemePack` 仍然是“预设底板 + 自定义词汇补丁”。
|
||||
|
||||
优化后应改成:
|
||||
|
||||
```ts
|
||||
interface CustomWorldExpressionProfile {
|
||||
themePack: ThemePack;
|
||||
presentationTone: string[];
|
||||
namingDirectives: string[];
|
||||
clueDirectives: string[];
|
||||
revealDirectives: string[];
|
||||
}
|
||||
```
|
||||
|
||||
也就是说:
|
||||
|
||||
- `ThemePack` 仍然可以保留
|
||||
- 但它不再被理解为“武侠底板 / 仙侠底板的延伸”
|
||||
- 它应当是:
|
||||
- `semanticAnchor`
|
||||
- `creatorIntent`
|
||||
- `majorFactions`
|
||||
- `coreConflicts`
|
||||
- `world text`
|
||||
共同编译出来的结果
|
||||
|
||||
这一步非常关键,因为它会决定:
|
||||
|
||||
1. 物件命名
|
||||
2. 势力命名
|
||||
3. 线索形式
|
||||
4. 提示词词汇风格
|
||||
5. reveal 风格
|
||||
|
||||
只有把这层做成自定义世界自己的派生物,后面跨题材才会真的稳。
|
||||
|
||||
---
|
||||
|
||||
## 4.4 原型参考层:把模板骨架改成通用原型库
|
||||
|
||||
当前自定义世界借用模板的最深部分是:
|
||||
|
||||
1. 角色模板骨架
|
||||
2. 场景视觉参考池
|
||||
3. 怪物模板池
|
||||
|
||||
这三类不能粗暴删除,但可以改造成:
|
||||
|
||||
**通用原型参考层。**
|
||||
|
||||
建议统一成:
|
||||
|
||||
```ts
|
||||
interface CustomWorldReferenceProfile {
|
||||
roleArchetypes: RoleArchetypeProfile[];
|
||||
sceneBuckets: SceneArchetypeBucket[];
|
||||
creatureArchetypes: CreatureArchetypeProfile[];
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4.1 角色原型
|
||||
|
||||
角色原型应描述的是:
|
||||
|
||||
- 正面推进型
|
||||
- 远程压制型
|
||||
- 控场解构型
|
||||
- 续航承压型
|
||||
- 潜行爆发型
|
||||
|
||||
而不是:
|
||||
|
||||
- 剑之公主
|
||||
- 神箭游侠
|
||||
- 双刃旅者
|
||||
|
||||
也就是说:
|
||||
|
||||
**保留战斗骨架和技能骨架,不保留模板角色人格设定。**
|
||||
|
||||
### 4.4.2 场景原型
|
||||
|
||||
场景原型应描述的是:
|
||||
|
||||
- 高压入口区
|
||||
- 雨湿街巷区
|
||||
- 临水渡口区
|
||||
- 仪式神殿区
|
||||
- 高空通路区
|
||||
- 工业热区
|
||||
- 地底遗迹区
|
||||
- 群落聚居区
|
||||
|
||||
而不是:
|
||||
|
||||
- 竹林古道
|
||||
- 云海仙门
|
||||
|
||||
也就是说:
|
||||
|
||||
**保留“空间语义 -> 视觉参考”的逻辑,不保留模板世界场景名作为中心。**
|
||||
|
||||
### 4.4.3 生物原型
|
||||
|
||||
生物原型应描述的是:
|
||||
|
||||
- 潜伏袭击者
|
||||
- 重甲承压者
|
||||
- 群居骚扰者
|
||||
- 远程威胁者
|
||||
- 异化污染体
|
||||
- 灵体回响体
|
||||
- 机关守卫体
|
||||
|
||||
而不是:
|
||||
|
||||
- 某个武侠怪
|
||||
- 某个仙侠怪
|
||||
|
||||
这样之后:
|
||||
|
||||
- 自定义世界依赖的是“通用原型”
|
||||
- 原型再映射到底层素材与 preset
|
||||
|
||||
---
|
||||
|
||||
## 4.5 兼容迁移层:旧字段继续保留一段时间
|
||||
|
||||
为了不破坏当前流程,短期内不能直接删除:
|
||||
|
||||
- `templateWorldType`
|
||||
- `WorldTemplateType`
|
||||
- 以及相关 normalize / save / read 逻辑
|
||||
|
||||
这层应被降级成:
|
||||
|
||||
```ts
|
||||
interface CustomWorldCompatibilityProfile {
|
||||
legacyTemplateWorldType?: 'WUXIA' | 'XIANXIA' | null;
|
||||
migrationVersion: string;
|
||||
}
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
1. 旧存档兼容
|
||||
2. 旧 prompt 兼容
|
||||
3. 旧测试兼容
|
||||
4. 旧工具链兼容
|
||||
|
||||
但它不再应是新生成世界的第一真相来源。
|
||||
|
||||
---
|
||||
|
||||
## 5. 现有每类依赖如何改造成自定义世界自己的设定
|
||||
|
||||
下面把现有依赖逐项映射成未来目标。
|
||||
|
||||
## 5.1 `templateWorldType`
|
||||
|
||||
当前作用:
|
||||
|
||||
- 世界锚点
|
||||
- 规则 fallback
|
||||
- 视觉和怪物参考入口
|
||||
|
||||
目标改造:
|
||||
|
||||
- 拆成:
|
||||
- `semanticAnchor`
|
||||
- `ruleProfile`
|
||||
- `referenceProfile`
|
||||
- `compatibilityProfile`
|
||||
|
||||
迁移方式:
|
||||
|
||||
1. 旧字段保留
|
||||
2. 新字段生成后优先读新字段
|
||||
3. 旧字段只做迁移 fallback
|
||||
|
||||
## 5.2 `resolveRuleWorldType(...)`
|
||||
|
||||
当前作用:
|
||||
|
||||
- 把 `CUSTOM` 解析回 `WUXIA / XIANXIA`
|
||||
|
||||
目标改造:
|
||||
|
||||
- 改成:
|
||||
|
||||
```ts
|
||||
resolveCustomWorldRuleProfile(profile)
|
||||
```
|
||||
|
||||
运行时不再需要知道“它更像武侠还是仙侠”,而只需要知道:
|
||||
|
||||
- 这个世界的规则 profile 是什么
|
||||
|
||||
## 5.3 `getPresetWorldAttributeSchema(...)`
|
||||
|
||||
当前作用:
|
||||
|
||||
- 自定义世界 schema 的参考底板
|
||||
|
||||
目标改造:
|
||||
|
||||
- 把预设 schema 底板重构成:
|
||||
- 通用 schema seeds
|
||||
|
||||
例如按功能分:
|
||||
|
||||
1. 承压轴
|
||||
2. 机动轴
|
||||
3. 洞察轴
|
||||
4. 决断轴
|
||||
5. 共鸣轴
|
||||
6. 续航轴
|
||||
|
||||
然后由自定义世界的 `semanticAnchor + creatorIntent` 生成最终命名与说明。
|
||||
|
||||
## 5.4 `PRESET_CHARACTERS`
|
||||
|
||||
当前作用:
|
||||
|
||||
- 自定义世界角色的战斗模板和技能骨架
|
||||
|
||||
目标改造:
|
||||
|
||||
- 抽出:
|
||||
- `RoleArchetypeProfile`
|
||||
- `SkillArchetypeProfile`
|
||||
|
||||
也就是说:
|
||||
|
||||
- 还可以继续复用当前角色的战斗结构
|
||||
- 但不应再让自定义世界依赖那些模板角色的人设文本
|
||||
|
||||
## 5.5 场景图片参考池
|
||||
|
||||
当前作用:
|
||||
|
||||
- 自定义世界默认场景图匹配
|
||||
|
||||
目标改造:
|
||||
|
||||
- 改成:
|
||||
- `SceneArchetypeBucket`
|
||||
|
||||
每个 bucket 只表达通用空间语义,不表达模板世界名。
|
||||
|
||||
## 5.6 怪物池
|
||||
|
||||
当前作用:
|
||||
|
||||
- 自定义世界敌对单位匹配 preset
|
||||
|
||||
目标改造:
|
||||
|
||||
- 改成:
|
||||
- `CreatureArchetypeProfile`
|
||||
|
||||
由 archetype 再映射到底层怪物素材与 preset。
|
||||
|
||||
## 5.7 `buildThemePackFromWorldProfile(...)`
|
||||
|
||||
当前作用:
|
||||
|
||||
- 以模板题材包为底生成自定义世界 ThemePack
|
||||
|
||||
目标改造:
|
||||
|
||||
- 变成:
|
||||
- `buildThemePackFromCustomWorldSemanticAnchor(...)`
|
||||
|
||||
即 ThemePack 以自定义世界自己的语义锚和词汇锚为底。
|
||||
|
||||
---
|
||||
|
||||
## 6. 不破坏当前流程的迁移顺序
|
||||
|
||||
这是最关键的落地顺序。
|
||||
|
||||
## 阶段 A:先给 `CustomWorldProfile` 补新设定层
|
||||
|
||||
先补:
|
||||
|
||||
1. `semanticAnchor`
|
||||
2. `ruleProfile`
|
||||
3. `expressionProfile`
|
||||
4. `referenceProfile`
|
||||
5. `compatibilityProfile`
|
||||
|
||||
这一步只做新增,不删旧字段。
|
||||
|
||||
## 阶段 B:旧字段自动编译新字段
|
||||
|
||||
当前已有 profile、旧存档、旧生成结果,先统一经过:
|
||||
|
||||
```ts
|
||||
compileOwnedSettingLayersFromLegacyTemplate(profile)
|
||||
```
|
||||
|
||||
让:
|
||||
|
||||
- 旧世界也拥有新设定层
|
||||
- 新运行时可优先消费新字段
|
||||
|
||||
## 阶段 C:生成链开始直接产出新设定层
|
||||
|
||||
修改:
|
||||
|
||||
- `framework prompt`
|
||||
- `normalizeCustomWorldGenerationFramework(...)`
|
||||
- `customWorld.ts`
|
||||
|
||||
使新生成世界优先产出:
|
||||
|
||||
- `semanticAnchor`
|
||||
- `ruleProfile hints`
|
||||
- `referenceProfile hints`
|
||||
|
||||
而不是只产出 `templateWorldType`
|
||||
|
||||
## 阶段 D:运行时逐步改读新设定层
|
||||
|
||||
优先改:
|
||||
|
||||
1. 资源词与货币
|
||||
2. attribute schema
|
||||
3. ThemePack
|
||||
4. 视觉参考
|
||||
5. 怪物映射
|
||||
6. 角色原型引用
|
||||
|
||||
要求:
|
||||
|
||||
- 每次只切一层
|
||||
- 每层都保留 fallback
|
||||
|
||||
## 阶段 E:把旧模板字段降级为兼容层
|
||||
|
||||
当上面的读取已经都切走后:
|
||||
|
||||
- `templateWorldType` 就不再是主链依赖
|
||||
- 只作为:
|
||||
- migration
|
||||
- 老存档兼容
|
||||
- 老工具兼容
|
||||
|
||||
---
|
||||
|
||||
## 7. 推荐新增的最小字段
|
||||
|
||||
为了避免系统膨胀,建议只先补最小集合。
|
||||
|
||||
## 7.1 `CustomWorldOwnedSettingLayers`
|
||||
|
||||
```ts
|
||||
interface CustomWorldOwnedSettingLayers {
|
||||
semanticAnchor: CustomWorldSemanticAnchor;
|
||||
ruleProfile: CustomWorldRuleProfile;
|
||||
expressionProfile: CustomWorldExpressionProfile;
|
||||
referenceProfile: CustomWorldReferenceProfile;
|
||||
compatibilityProfile?: CustomWorldCompatibilityProfile | null;
|
||||
}
|
||||
```
|
||||
|
||||
然后挂到:
|
||||
|
||||
```ts
|
||||
interface CustomWorldProfile {
|
||||
ownedSettingLayers?: CustomWorldOwnedSettingLayers | null;
|
||||
}
|
||||
```
|
||||
|
||||
这样好处是:
|
||||
|
||||
1. 不用在 `CustomWorldProfile` 顶层堆太多字段
|
||||
2. 迁移更集中
|
||||
3. 后续删除兼容层更容易
|
||||
|
||||
---
|
||||
|
||||
## 8. 对当前功能链的保护要求
|
||||
|
||||
这次优化过程中,下面这些能力不能坏:
|
||||
|
||||
1. 自定义世界创建
|
||||
2. 自定义世界保存 / 读取
|
||||
3. 自定义世界角色生成
|
||||
4. 自定义世界场景生成
|
||||
5. 自定义世界开局
|
||||
6. 自定义世界运行时的:
|
||||
- 属性
|
||||
- 资源词
|
||||
- 经济
|
||||
- 场景图
|
||||
- 敌对实体
|
||||
- ThemePack
|
||||
- prompt 组织
|
||||
|
||||
也就是说:
|
||||
|
||||
**任何一次迭代都必须是“新层可用 + 旧层仍可兜底”。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 验收标准
|
||||
|
||||
当下面这些标准成立时,说明这套优化开始有效:
|
||||
|
||||
1. 新生成的自定义世界不再必须依赖 `templateWorldType` 才能表达自身设定。
|
||||
2. 运行时优先读取 `ownedSettingLayers`,而不是先问武侠 / 仙侠。
|
||||
3. 自定义世界的属性、资源词、经济、视觉参考、怪物映射、ThemePack 都能从自身设定层派生出来。
|
||||
4. 新设定层描述的是通用语义,不是模板世界换皮。
|
||||
5. 当前自定义世界生成流程、旧存档、旧结果页工作台仍然可用。
|
||||
|
||||
---
|
||||
|
||||
## 10. 最后结论
|
||||
|
||||
如果目标是:
|
||||
|
||||
**让这些依赖都变成属于自定义世界的设定,而且这些设定要通用于任何题材。**
|
||||
|
||||
那么最正确的方向不是“继续弱化武侠 / 仙侠字样”,而是:
|
||||
|
||||
**把模板支撑层整体迁移成自定义世界自己的设定层。**
|
||||
|
||||
更具体地说,就是把当前依赖重组为:
|
||||
|
||||
1. 自定义世界自己的语义锚
|
||||
2. 自定义世界自己的规则 profile
|
||||
3. 自定义世界自己的表达 profile
|
||||
4. 自定义世界自己的原型参考 profile
|
||||
5. 只负责兼容的旧模板字段
|
||||
|
||||
这样之后,自定义世界才会真正从:
|
||||
|
||||
**模板依赖型生成架构**
|
||||
|
||||
迁移成:
|
||||
|
||||
**跨题材、自有设定层、且兼容当前流程的生成架构。**
|
||||
@@ -0,0 +1,656 @@
|
||||
# 自定义世界去模板依赖与跨题材通用化优化设计
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份文档解决的是一个已经明确暴露出来的问题:
|
||||
|
||||
**当前玩家主流程虽然已经移除了武侠 / 仙侠两个预设世界,但自定义世界底层仍然依赖武侠 / 仙侠模板设定。**
|
||||
|
||||
本次优化的目标不是简单“删掉模板字段”,而是要在不破坏当前自定义世界生成流程的前提下,把这些依赖逐步改造成:
|
||||
|
||||
**属于自定义世界自身、且能通用于任何题材的设定层。**
|
||||
|
||||
一句话定义:
|
||||
|
||||
**让自定义世界从“挂靠武侠 / 仙侠模板运行”,升级成“基于通用世界设定层独立运行”。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 优化原则
|
||||
|
||||
这次优化必须同时满足 3 条硬原则:
|
||||
|
||||
1. 设定归自定义世界自身所有
|
||||
- 任何运行时、生成期、表现层真正依赖的设定,都应尽量落回 `CustomWorldProfile` 或由它直接编译出的通用配置,不再默认挂在 `WUXIA / XIANXIA` 两个模板世界上。
|
||||
|
||||
2. 设定必须跨题材通用
|
||||
- 不能把“自定义世界去模板化”理解成“再做一套更抽象的武侠 / 仙侠替代字段”。
|
||||
- 新结构必须能容纳奇幻、科幻、悬疑、末世、现代、神话、校园等任何题材。
|
||||
|
||||
3. 不能破坏当前自定义世界生成流程
|
||||
- 现有 `framework -> themePack -> storyGraph -> role / landmark -> runtime` 主链必须继续能跑。
|
||||
- 优化应以兼容迁移为主,而不是大爆破式重写。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前问题归纳
|
||||
|
||||
根据 [CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md](../reference/CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md),当前自定义世界仍依赖模板层的地方主要有:
|
||||
|
||||
1. 模板锚点类型
|
||||
- `templateWorldType`
|
||||
- `WorldTemplateType`
|
||||
- `resolveRuleWorldType(...)`
|
||||
|
||||
2. 主题与规则回退
|
||||
- `detectCustomWorldThemeMode(...)`
|
||||
- `resolveCustomWorldAnchorWorldType(...)`
|
||||
- `buildThemePackFromWorldProfile(...)` 底板
|
||||
|
||||
3. 属性与表现
|
||||
- 预设世界属性 schema
|
||||
- 资源词、数值命名、货币命名
|
||||
|
||||
4. 角色骨架
|
||||
- `PRESET_CHARACTERS`
|
||||
- 模板技能定义
|
||||
- 模板 opening 接口
|
||||
|
||||
5. 场景与视觉参考
|
||||
- 武侠 / 仙侠场景图片参考池
|
||||
- 模板 camp 场景映射
|
||||
|
||||
6. 怪物模板池
|
||||
- 武侠 / 仙侠怪物 preset 池
|
||||
|
||||
这些依赖本质上说明:
|
||||
|
||||
**当前自定义世界不是完全自足,而是“先生成自定义内容,再把它映射回两套模板世界骨架”。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 这次优化不应该怎么做
|
||||
|
||||
先明确几个错误方向:
|
||||
|
||||
## 3.1 不能直接删掉 `templateWorldType`
|
||||
|
||||
如果直接删除:
|
||||
|
||||
- `templateWorldType`
|
||||
- `WorldTemplateType`
|
||||
- `WUXIA / XIANXIA` 相关回退
|
||||
|
||||
而不先补新的通用设定层,那么当前自定义世界会立刻失去:
|
||||
|
||||
1. 规则桥接
|
||||
2. 主题底板
|
||||
3. 场景图参考
|
||||
4. 怪物池匹配
|
||||
5. 属性 schema fallback
|
||||
|
||||
这会直接打断现有生成和运行链路。
|
||||
|
||||
## 3.2 不能把新设定继续写成“武侠 / 仙侠的抽象别名”
|
||||
|
||||
例如下面这种思路是不够的:
|
||||
|
||||
- 把 `templateWorldType` 改名成 `worldFamily`
|
||||
- 但值仍然只有两类近似武侠 / 仙侠的内部枚举
|
||||
|
||||
这不是真正跨题材,只是换了名字。
|
||||
|
||||
## 3.3 不能让创作者承担更多底层配置工作
|
||||
|
||||
这次优化不是让创作者额外填写:
|
||||
|
||||
- 怪物模板表
|
||||
- 场景参考池
|
||||
- 属性 schema 槽位
|
||||
- 规则 profile
|
||||
|
||||
正确方向应该是:
|
||||
|
||||
**这些通用设定仍由系统生成 / 编译,但所有权回到自定义世界自身。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 目标结构:把模板依赖改造成自定义世界自己的 4 层通用设定
|
||||
|
||||
为了避免系统越改越散,这次建议不要新增很多彼此平行的新系统,而是把现有模板依赖统一收束成 4 层通用设定。
|
||||
|
||||
## 4.1 第一层:世界语义锚层
|
||||
|
||||
这是替代 `templateWorldType` 的核心层。
|
||||
|
||||
它不再回答“你更像武侠还是仙侠”,而回答:
|
||||
|
||||
1. 这个世界的主要冲突形式是什么
|
||||
2. 这个世界的制度、禁忌、叙事载体、力量来源是什么
|
||||
3. 这个世界更接近哪类表现模式
|
||||
|
||||
建议由自定义世界自己持有一个通用结构,例如:
|
||||
|
||||
```ts
|
||||
interface CustomWorldSemanticAnchor {
|
||||
genreSignals: string[];
|
||||
conflictModel: string[];
|
||||
institutionHints: string[];
|
||||
tabooHints: string[];
|
||||
carrierHints: string[];
|
||||
forceSystemHints: string[];
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 它是自定义世界自己的语义锚。
|
||||
- 它可以表示:
|
||||
- 宗门与灵脉
|
||||
- 财团与实验体
|
||||
- 学园与旧规
|
||||
- 边境与裂界
|
||||
- 海潮与失落群岛
|
||||
- 神话与誓约
|
||||
- 不再强制回落到武侠 / 仙侠二选一。
|
||||
|
||||
## 4.2 第二层:规则与表现配置层
|
||||
|
||||
这是替代:
|
||||
|
||||
- `resolveRuleWorldType(...)`
|
||||
- 预设属性 schema fallback
|
||||
- 资源命名 fallback
|
||||
- 经济 fallback
|
||||
|
||||
建议改成由自定义世界持有一份通用 `WorldRuleProfile`:
|
||||
|
||||
```ts
|
||||
interface WorldRuleProfile {
|
||||
attributeSchema: WorldAttributeSchema;
|
||||
resourceLabels: {
|
||||
hp: string;
|
||||
mp: string;
|
||||
maxHp: string;
|
||||
maxMp: string;
|
||||
damage: string;
|
||||
guard: string;
|
||||
range: string;
|
||||
cooldown: string;
|
||||
manaCost: string;
|
||||
currency: string;
|
||||
};
|
||||
economyProfile: {
|
||||
initialCurrency: number;
|
||||
rarityValueScale: Record<string, number>;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
关键点:
|
||||
|
||||
1. 以后运行时不要再优先问“这是武侠还是仙侠”。
|
||||
2. 应该直接问:
|
||||
- `profile.ruleProfile.attributeSchema`
|
||||
- `profile.ruleProfile.resourceLabels`
|
||||
- `profile.ruleProfile.economyProfile`
|
||||
|
||||
这样:
|
||||
|
||||
- 奇幻世界可以叫“体魄 / 法力”
|
||||
- 末世世界可以叫“生命 / 电量”
|
||||
- 校园悬疑世界甚至可以弱化“mana”概念,改成“专注 / 压力”
|
||||
|
||||
## 4.3 第三层:内容骨架与参考层
|
||||
|
||||
这是替代:
|
||||
|
||||
- 预设角色模板骨架
|
||||
- 武侠 / 仙侠场景图参考池
|
||||
- 武侠 / 仙侠怪物 preset 池
|
||||
|
||||
这里不建议让自定义世界自己保存大批素材,而是建议让自定义世界持有:
|
||||
|
||||
**对内容骨架的“编译后引用配置”。**
|
||||
|
||||
建议统一成一个 `ContentReferenceProfile`:
|
||||
|
||||
```ts
|
||||
interface ContentReferenceProfile {
|
||||
roleArchetypes: RoleArchetypeProfile[];
|
||||
sceneReferenceBuckets: SceneReferenceBucket[];
|
||||
creatureArchetypes: CreatureArchetypeProfile[];
|
||||
}
|
||||
```
|
||||
|
||||
其中每个子项都应是通用语义,而不是模板世界名:
|
||||
|
||||
1. `RoleArchetypeProfile`
|
||||
- 例如:
|
||||
- 正面压制型
|
||||
- 远程游击型
|
||||
- 灵术控制型
|
||||
- 重装承压型
|
||||
- 潜行刺击型
|
||||
|
||||
2. `SceneReferenceBucket`
|
||||
- 例如:
|
||||
- 高压门禁区
|
||||
- 雨夜街巷区
|
||||
- 高空通道区
|
||||
- 神殿 / 仪式区
|
||||
- 工业热区
|
||||
- 潮湿临水区
|
||||
|
||||
3. `CreatureArchetypeProfile`
|
||||
- 例如:
|
||||
- 潜伏掠食者
|
||||
- 重甲承压者
|
||||
- 群居灵体
|
||||
- 远程骚扰者
|
||||
- 寄生污染体
|
||||
|
||||
关键点:
|
||||
|
||||
- 这些 archetype 可以继续映射到底层素材和 preset。
|
||||
- 但对自定义世界来说,它依赖的是“通用原型”,不是“武侠怪物池 / 仙侠怪物池”。
|
||||
|
||||
## 4.4 第四层:叙事与词汇编译层
|
||||
|
||||
这是替代:
|
||||
|
||||
- 以模板世界为底的 `ThemePack` fallback
|
||||
- prompt 中的模板世界兼容字段
|
||||
|
||||
建议做法:
|
||||
|
||||
1. `ThemePack` 继续保留,但它的来源变成:
|
||||
- `semanticAnchor + creatorIntent + world text + content reference profile`
|
||||
|
||||
2. 生成框架 prompt 不再要求输出:
|
||||
- `templateWorldType: WUXIA|XIANXIA`
|
||||
|
||||
3. 改为要求输出:
|
||||
- 世界语义锚
|
||||
- 规则表现关键词
|
||||
- 冲突和制度线索
|
||||
|
||||
例如:
|
||||
|
||||
```ts
|
||||
interface CustomWorldGenerationFramework {
|
||||
name: string;
|
||||
subtitle: string;
|
||||
summary: string;
|
||||
tone: string;
|
||||
playerGoal: string;
|
||||
semanticAnchor: CustomWorldSemanticAnchor;
|
||||
majorFactions: string[];
|
||||
coreConflicts: string[];
|
||||
camp: CampOutline;
|
||||
}
|
||||
```
|
||||
|
||||
这样:
|
||||
|
||||
- 生成流程仍然是 `framework -> themePack -> storyGraph -> role / landmark`
|
||||
- 只是 framework 的核心锚不再依赖预设世界枚举
|
||||
|
||||
---
|
||||
|
||||
## 5. 现有依赖如何一一改造
|
||||
|
||||
## 5.1 `templateWorldType` -> `semanticAnchor + ruleProfile`
|
||||
|
||||
当前用途:
|
||||
|
||||
- 表示自定义世界挂靠武侠还是仙侠
|
||||
|
||||
目标改造:
|
||||
|
||||
- 运行时不再直接读取 `templateWorldType`
|
||||
- 改为读取:
|
||||
- `semanticAnchor`
|
||||
- `ruleProfile`
|
||||
|
||||
迁移策略:
|
||||
|
||||
1. 先保留 `templateWorldType` 作为兼容字段
|
||||
2. 新增 `semanticAnchor / ruleProfile`
|
||||
3. 由旧字段自动编译出新字段
|
||||
4. 所有读取逻辑逐步切到新字段
|
||||
5. 最后把 `templateWorldType` 降级为 migration-only 字段
|
||||
|
||||
## 5.2 `resolveRuleWorldType(...)` -> `resolveWorldRuleProfile(...)`
|
||||
|
||||
当前用途:
|
||||
|
||||
- 把 `CUSTOM` 解析回 `WUXIA / XIANXIA`
|
||||
|
||||
目标改造:
|
||||
|
||||
- 不再返回模板 world type
|
||||
- 直接返回自定义世界自己的 `ruleProfile`
|
||||
|
||||
即:
|
||||
|
||||
```ts
|
||||
resolveWorldRuleProfile(worldType, customWorldProfile)
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
- `attributeSchema`
|
||||
- `resourceLabels`
|
||||
- `economyProfile`
|
||||
- 其它规则信息
|
||||
|
||||
## 5.3 预设属性 schema -> 通用 attribute schema seed
|
||||
|
||||
当前用途:
|
||||
|
||||
- 用武侠 / 仙侠 schema 作为自定义世界 schema 参考底板
|
||||
|
||||
目标改造:
|
||||
|
||||
- 不再直接引用“武侠六脉 / 仙侠六轴”作为唯一底板
|
||||
- 改为维护一组通用 `attribute schema seeds`
|
||||
|
||||
例如可按世界体验而不是题材命名:
|
||||
|
||||
1. 正面对抗型
|
||||
2. 机动博弈型
|
||||
3. 灵知洞察型
|
||||
4. 共鸣契约型
|
||||
5. 生存续航型
|
||||
6. 高危推进型
|
||||
|
||||
然后由自定义世界的 `semanticAnchor` 决定如何组合或命名这些槽位。
|
||||
|
||||
## 5.4 预设角色模板 -> 通用角色原型骨架
|
||||
|
||||
当前用途:
|
||||
|
||||
- 从 `PRESET_CHARACTERS` 选模板角色,再覆写自定义世界内容
|
||||
|
||||
目标改造:
|
||||
|
||||
- 把当前模板角色骨架抽成“通用战斗原型角色”
|
||||
|
||||
例如保留的是:
|
||||
|
||||
- 技能骨架
|
||||
- 动作风格
|
||||
- build 倾向
|
||||
- 动画资源挂载方式
|
||||
|
||||
而不是保留“剑之公主 / 神箭游侠”这样的预设世界人格设定。
|
||||
|
||||
关键点:
|
||||
|
||||
- 动画素材和技能骨架可以保留
|
||||
- 但运行时不应再依赖具体模板角色的人设文本
|
||||
|
||||
## 5.5 武侠 / 仙侠场景图参考池 -> 通用场景参考桶
|
||||
|
||||
当前用途:
|
||||
|
||||
- 用武侠 / 仙侠场景关键词为自定义世界匹配默认背景图
|
||||
|
||||
目标改造:
|
||||
|
||||
- 改成通用 `SceneReferenceBucket`
|
||||
- 每个 bucket 对应一类空间语义
|
||||
|
||||
例如:
|
||||
|
||||
1. 落脚处 / 归舍
|
||||
2. 高压入口
|
||||
3. 雨湿街巷
|
||||
4. 高空通路
|
||||
5. 仪式空间
|
||||
6. 工业热区
|
||||
7. 临水空间
|
||||
8. 地底遗迹
|
||||
|
||||
这样就能让:
|
||||
|
||||
- 科幻世界
|
||||
- 校园世界
|
||||
- 神话世界
|
||||
- 末世世界
|
||||
|
||||
都共享同一套“空间语义 -> 视觉参考”的逻辑。
|
||||
|
||||
## 5.6 武侠 / 仙侠怪物池 -> 通用生物原型库
|
||||
|
||||
当前用途:
|
||||
|
||||
- 从武侠 / 仙侠怪物池里为自定义世界匹配怪物
|
||||
|
||||
目标改造:
|
||||
|
||||
- 改成通用 `CreatureArchetypeProfile`
|
||||
- 再由 archetype 去映射底层 preset / 数值 / 动画素材
|
||||
|
||||
这样做的好处:
|
||||
|
||||
1. 自定义世界依赖的是“潜伏者 / 重压者 / 群居体 / 异化体”
|
||||
2. 而不是“这更像武侠怪还是仙侠怪”
|
||||
|
||||
## 5.7 `ThemePack` 底板 -> 通用语义底板
|
||||
|
||||
当前用途:
|
||||
|
||||
- 自定义世界的 ThemePack 还是从预设题材包底板开始
|
||||
|
||||
目标改造:
|
||||
|
||||
- 让 ThemePack 直接从:
|
||||
- `semanticAnchor`
|
||||
- `creatorIntent`
|
||||
- `majorFactions`
|
||||
- `coreConflicts`
|
||||
- `contentReferenceProfile`
|
||||
编译出来
|
||||
|
||||
也就是说:
|
||||
|
||||
**ThemePack 应变成自定义世界自己的派生物,而不是模板世界的扩写版。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 不破坏现有生成流程的迁移方案
|
||||
|
||||
这是这份文档最重要的部分。
|
||||
|
||||
正确做法不是一口气替换,而是兼容迁移。
|
||||
|
||||
## 阶段 A:新增通用设定字段,但不删旧字段
|
||||
|
||||
先做:
|
||||
|
||||
1. 在 `CustomWorldProfile` 上新增:
|
||||
- `semanticAnchor`
|
||||
- `ruleProfile`
|
||||
- `contentReferenceProfile`
|
||||
|
||||
2. 保留:
|
||||
- `templateWorldType`
|
||||
|
||||
3. 由当前旧字段自动编译出新字段
|
||||
|
||||
目标:
|
||||
|
||||
- 先让新结构出现
|
||||
- 但现有流程完全不受影响
|
||||
|
||||
## 阶段 B:生成流程改为优先产出新字段
|
||||
|
||||
先改:
|
||||
|
||||
- `framework prompt`
|
||||
- `customWorld.ts`
|
||||
|
||||
让 AI 先输出:
|
||||
|
||||
- 通用语义锚
|
||||
- 规则提示
|
||||
- 通用 archetype 线索
|
||||
|
||||
同时在 normalize 层继续兼容旧的 `templateWorldType`
|
||||
|
||||
目标:
|
||||
|
||||
- 新生成的自定义世界开始“原生带通用设定”
|
||||
- 旧存档仍可继续读取
|
||||
|
||||
## 阶段 C:运行时读取切到新设定
|
||||
|
||||
依次改:
|
||||
|
||||
1. 规则层
|
||||
- 从 `resolveRuleWorldType` 切到 `resolveWorldRuleProfile`
|
||||
|
||||
2. 属性层
|
||||
- 优先读 `profile.ruleProfile.attributeSchema`
|
||||
|
||||
3. 资源词与经济层
|
||||
- 优先读 `profile.ruleProfile.resourceLabels / economyProfile`
|
||||
|
||||
4. 场景图与怪物映射
|
||||
- 优先读 `contentReferenceProfile`
|
||||
|
||||
目标:
|
||||
|
||||
- 让模板世界字段不再是运行时第一来源
|
||||
|
||||
## 阶段 D:模板世界字段退化为兼容层
|
||||
|
||||
这一步完成后:
|
||||
|
||||
1. `templateWorldType` 只用于:
|
||||
- 旧存档迁移
|
||||
- 老测试兼容
|
||||
- 数据修复 fallback
|
||||
|
||||
2. 不再用于:
|
||||
- 正式生成主链
|
||||
- 正式运行时主链
|
||||
|
||||
## 阶段 E:再做深清理
|
||||
|
||||
只有当上面几步都完成后,才适合继续清理:
|
||||
|
||||
1. 非必要的模板回退逻辑
|
||||
2. 非必要的主流程模板枚举消费点
|
||||
3. 非必要的审计 / 工具硬编码
|
||||
|
||||
---
|
||||
|
||||
## 7. 对当前主链的兼容要求
|
||||
|
||||
这次优化过程中,下面这些链路必须始终可用:
|
||||
|
||||
1. `PreGameSelectionFlow -> generateCustomWorldProfile(...)`
|
||||
2. `framework -> themePack -> storyGraph -> role / landmark`
|
||||
3. 保存 / 读取自定义世界 profile
|
||||
4. 自定义世界开局
|
||||
5. 自定义世界角色与场景生成
|
||||
6. 自定义世界运行时怪物 / 物品 / 场景图 /词汇表现
|
||||
|
||||
也就是说:
|
||||
|
||||
**任何迁移都必须先补新字段,再迁读,再退旧字段,不能先删旧字段。**
|
||||
|
||||
---
|
||||
|
||||
## 8. 建议新增或改造的最小数据结构
|
||||
|
||||
为了避免系统膨胀,这次不建议引入很多彼此割裂的新系统,建议只在 `CustomWorldProfile` 周边增量补三块。
|
||||
|
||||
## 8.1 `semanticAnchor`
|
||||
|
||||
```ts
|
||||
interface CustomWorldSemanticAnchor {
|
||||
genreSignals: string[];
|
||||
conflictModel: string[];
|
||||
institutionHints: string[];
|
||||
tabooHints: string[];
|
||||
carrierHints: string[];
|
||||
forceSystemHints: string[];
|
||||
}
|
||||
```
|
||||
|
||||
## 8.2 `ruleProfile`
|
||||
|
||||
```ts
|
||||
interface WorldRuleProfile {
|
||||
attributeSchema: WorldAttributeSchema;
|
||||
resourceLabels: {
|
||||
hp: string;
|
||||
mp: string;
|
||||
maxHp: string;
|
||||
maxMp: string;
|
||||
damage: string;
|
||||
guard: string;
|
||||
range: string;
|
||||
cooldown: string;
|
||||
manaCost: string;
|
||||
currency: string;
|
||||
};
|
||||
economyProfile: {
|
||||
initialCurrency: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 8.3 `contentReferenceProfile`
|
||||
|
||||
```ts
|
||||
interface ContentReferenceProfile {
|
||||
roleArchetypes: string[];
|
||||
sceneReferenceBuckets: string[];
|
||||
creatureArchetypes: string[];
|
||||
}
|
||||
```
|
||||
|
||||
这三块足够作为第一轮去模板化的最小自定义世界设定层。
|
||||
|
||||
---
|
||||
|
||||
## 9. 验收标准
|
||||
|
||||
做到以下几点,才能说明自定义世界真正开始脱离模板依赖:
|
||||
|
||||
1. 新生成的自定义世界框架不再需要直接输出 `WUXIA|XIANXIA` 才能工作。
|
||||
2. 运行时核心逻辑优先读取 `semanticAnchor / ruleProfile / contentReferenceProfile`。
|
||||
3. 自定义世界的属性 schema、资源词、经济词不再默认直接回退到武侠 / 仙侠文案。
|
||||
4. 自定义世界的角色骨架、场景视觉、怪物映射能通过通用 archetype 表达。
|
||||
5. 现有生成流程、存档读取、运行时体验不受破坏。
|
||||
6. 旧存档仍能通过兼容层运行。
|
||||
|
||||
---
|
||||
|
||||
## 10. 最后结论
|
||||
|
||||
当前自定义世界真正缺的,不是“再删一点武侠 / 仙侠字样”,而是:
|
||||
|
||||
**把模板世界支撑层改写成自定义世界自己的通用设定层。**
|
||||
|
||||
更准确地说,这次优化要完成的是:
|
||||
|
||||
1. 把模板锚点改成自定义世界自己的语义锚
|
||||
2. 把模板回退改成自定义世界自己的规则配置
|
||||
3. 把模板角色 / 场景 / 怪物参考改成通用原型引用
|
||||
4. 把 ThemePack 和生成 prompt 从“依附模板世界”改成“直接从自定义世界自身编译”
|
||||
|
||||
同时整个过程必须遵守一条底线:
|
||||
|
||||
**任何优化都不能破坏当前自定义世界生成与运行主链。**
|
||||
|
||||
所以这不是“删模板”的问题,而是一次:
|
||||
|
||||
**在兼容现有流程前提下,把自定义世界从模板依赖型架构,迁移成真正跨题材、自足型架构。**
|
||||
882
docs/design/EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md
Normal file
882
docs/design/EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md
Normal file
@@ -0,0 +1,882 @@
|
||||
# 配装构筑 + 合成/锻造闭环详细设计
|
||||
|
||||
更新时间:`2026-03-25`
|
||||
|
||||
## 0. 设计前提
|
||||
|
||||
这份方案基于当前仓库已经存在的运行时结构来设计,不另起一套独立系统。
|
||||
|
||||
- 现有物品结构已经有 `InventoryItem.tags`、`statProfile`、`useProfile`、`buildProfile`。
|
||||
- 现有装备位只有 `weapon / armor / relic` 三槽,因此本期套装与 build 成型必须围绕 2 件和 3 件完成。
|
||||
- 现有战斗结算已经有 `functionEffect.damageMultiplier / incomingDamageMultiplier`,但 `equipmentEffects.ts` 中的装备数值聚合仍然基本为空壳。
|
||||
- 现有素材库中已经出现 `setId`、`setName`、`pieceName`、`synergy` 等 build 元数据,但尚未进入真实伤害结算。
|
||||
- 现有角色、怪物、消耗品、掉落、宝藏、NPC 交易都已经形成了资源入口,适合继续补成“获取 -> 拆解 -> 锻造 -> 配装 -> 战斗 -> 再获取”的闭环。
|
||||
|
||||
因此,本方案的目标不是“再做一层 UI”,而是补齐以下 4 层:
|
||||
|
||||
1. 标签规范化层:把当前中英混用、结构标签与语义标签混用的问题拆开。
|
||||
2. 语义相似度层:用 embedding 相似度把“相近标签”自动组织为 build 与套装簇。
|
||||
3. 伤害修正层:把标签结果稳定接入当前伤害公式。
|
||||
4. 合成/锻造闭环:让掉落、材料、装备、buff、交易真正循环起来。
|
||||
|
||||
## 1. 结合当前系统的落地判断
|
||||
|
||||
### 1.1 现有可复用基础
|
||||
|
||||
- `src/types.ts`
|
||||
- 已有 `ItemStatProfile`
|
||||
- 已有 `ItemUseProfile`
|
||||
- 已有 `ItemBuildProfile`
|
||||
- 已有 `EquipmentLoadout`
|
||||
- 已有 `GameState.playerEquipment`
|
||||
- `src/data/itemDesign.ts`
|
||||
- 已经能为装备自动生成 `buildProfile`
|
||||
- 已经有 `setId / setName / pieceName / synergy`
|
||||
- 已经有一批 role/tag 原型,例如 `assassin / caster / ward / fate`
|
||||
- `src/data/monsterPresets.ts`
|
||||
- 已经有 `habitatTags`
|
||||
- 已经有较完整的 `lootTable`
|
||||
- `src/data/treasureInteractions.ts`
|
||||
- 已经有材料、消耗品、稀有品产出入口
|
||||
- `src/hooks/useCombatFlow.ts`
|
||||
- 玩家、同伴、怪物三条伤害结算路径已经齐备
|
||||
- 只差把 build 结果统一注入 `damage`
|
||||
|
||||
### 1.2 当前缺口
|
||||
|
||||
- 当前 `InventoryItem.tags` 同时承担了“分类标签”和“战斗语义标签”,例如 `weapon / armor / relic / material / mana / healing` 混在一起。
|
||||
- 当前角色正式数据结构里没有稳定的 `combatTags`,角色标签主要还停留在 UI 展示常量。
|
||||
- 当前怪物只有 `habitatTags`,更适合掉落/生态,不适合直接进入伤害 build。
|
||||
- 当前技能/物品可以恢复数值,但还不能稳定施加“限回合 build buff 标签”。
|
||||
- 当前 `getEquipmentBonuses()` 没有真正读取 `statProfile + buildProfile`,导致 build 无法进入伤害。
|
||||
|
||||
结论:
|
||||
|
||||
- 现有系统已经具备 build 系统的数据骨架。
|
||||
- 真正需要补的是“标签语义层”和“统一伤害入口”。
|
||||
|
||||
## 2. Build 标签设计原则
|
||||
|
||||
### 2.1 标签必须贴近实体语义
|
||||
|
||||
参与 build 的标签应尽量是玩家能直觉理解的“风格词”,而不是纯系统词。
|
||||
|
||||
推荐使用:
|
||||
|
||||
- 行为风格:`快剑`、`突进`、`追击`、`反击`、`蓄力`、`控场`
|
||||
- 输出方式:`重击`、`连段`、`远射`、`雷法`、`符阵`、`毒雾`
|
||||
- 生存节奏:`护体`、`守御`、`回复`、`续战`、`压血`
|
||||
- 材料/流派气质:`寒铁`、`星砂`、`灵木`、`骨纹`、`镇邪`
|
||||
- 阵营/身份风格:`先锋`、`游击`、`法修`、`命纹`、`统御`
|
||||
|
||||
不推荐直接把以下内容当作伤害 build 标签:
|
||||
|
||||
- `weapon`
|
||||
- `armor`
|
||||
- `relic`
|
||||
- `material`
|
||||
- `piece:weapon`
|
||||
- `world:xianxia`
|
||||
|
||||
这些更适合保留为筛选、配方、掉落、编辑器过滤用的结构标签。
|
||||
|
||||
### 2.2 标签分层
|
||||
|
||||
建议把标签拆成三层:
|
||||
|
||||
| 层级 | 用途 | 示例 |
|
||||
| --- | --- | --- |
|
||||
| 结构标签 | 分类、筛选、配方、存档兼容 | `weapon`、`armor`、`material`、`set:steel` |
|
||||
| 战斗语义标签 | 进入 build 相似度和伤害修正 | `快剑`、`突进`、`护体`、`雷法` |
|
||||
| 生态/素材标签 | 掉落、锻造、配方倾向 | `矿道`、`雾林`、`寒铁`、`星砂` |
|
||||
|
||||
推荐约束:
|
||||
|
||||
- `InventoryItem.tags` 继续保留结构标签与通用筛选标签。
|
||||
- `ItemBuildProfile.tags` 只保留会进入 build 计算的语义标签。
|
||||
- `MonsterPreset.habitatTags` 保留生态用途,不直接参与伤害。
|
||||
- 新增 `combatTags` 给角色/怪物,用于战斗 build。
|
||||
|
||||
### 2.3 中英混用兼容
|
||||
|
||||
当前素材生成中已有较多英文 role/tag,角色 UI 和自定义世界中又偏中文标签,因此需要加一层标签规范化。
|
||||
|
||||
建议建立 `buildTagRegistry`:
|
||||
|
||||
```ts
|
||||
type BuildTagDefinition = {
|
||||
id: string; // ASCII 稳定 id,例如 "quickblade"
|
||||
label: string; // 展示名,例如 "快剑"
|
||||
category: "role" | "style" | "resource" | "element" | "defense" | "craft";
|
||||
aliases: string[]; // 兼容 assassin / duelist / 快剑流 等历史写法
|
||||
description: string; // 供 embedding 使用
|
||||
};
|
||||
```
|
||||
|
||||
示例映射:
|
||||
|
||||
| 现有值 | 规范标签 |
|
||||
| --- | --- |
|
||||
| `assassin` | `快袭` / `切后` / `突进` |
|
||||
| `duelist` | `快剑` / `连段` / `对拼` |
|
||||
| `vanguard` | `先锋` / `稳压` / `护体` |
|
||||
| `ward` | `守御` / `镇邪` / `护体` |
|
||||
| `berserker` | `压血` / `重击` / `爆发` |
|
||||
| `caster` | `法修` / `法力` / `远程` |
|
||||
| `support` | `护持` / `回复` / `增益` |
|
||||
| `fortress` | `重甲` / `格挡` / `反击` |
|
||||
| `fate` | `命纹` / `机缘` / `冷却` |
|
||||
| `commander` | `统御` / `均衡` / `队伍增益` |
|
||||
|
||||
## 3. 标签来源设计
|
||||
|
||||
### 3.1 装备标签
|
||||
|
||||
装备是 build 的主来源,但要区分“结构标签”和“build 标签”。
|
||||
|
||||
建议:
|
||||
|
||||
- 武器、护甲、饰品各自最多提供 `2` 个核心 build 标签。
|
||||
- 若装备存在 `setId`,运行时根据套装件数额外生成“合成标签”。
|
||||
- 同一标签在多个装备上重复出现时,只记一次,不按件数无限叠加。
|
||||
|
||||
装备运行时推荐结构:
|
||||
|
||||
```ts
|
||||
type RuntimeEquipmentBuildSource = {
|
||||
itemId: string;
|
||||
slot: "weapon" | "armor" | "relic";
|
||||
coreTags: string[];
|
||||
setId?: string;
|
||||
setName?: string;
|
||||
forgeRank?: number;
|
||||
};
|
||||
```
|
||||
|
||||
### 3.2 角色/怪物标签
|
||||
|
||||
角色和怪物都应该有自己的 `combatTags`。
|
||||
|
||||
建议:
|
||||
|
||||
- 角色固定提供 `2~3` 个核心战斗语义标签。
|
||||
- 怪物固定提供 `2~3` 个核心战斗语义标签。
|
||||
- `habitatTags` 不直接参与 build 伤害,而是决定掉落材料簇、锻造路线和部分弱点设计。
|
||||
|
||||
例子:
|
||||
|
||||
- 剑系角色:`快剑`、`突进`、`压制`
|
||||
- 重甲怪物:`重甲`、`震击`、`守势`
|
||||
- 雾林怪物生态标签:`雾林`、`湿毒`、`潜伏`
|
||||
- 其中 `湿毒`、`潜伏` 可提升为 `combatTags`
|
||||
- `雾林` 保留为生态/掉落标签
|
||||
|
||||
### 3.3 Buff 标签
|
||||
|
||||
buff 标签是 build 的短时放大器,也是技能与物品进入构筑闭环的关键。
|
||||
|
||||
buff 标签来源:
|
||||
|
||||
- 技能施加的限回合标签
|
||||
- 消耗品施加的限回合标签
|
||||
- 锻造出的铭刻/附魔效果施加的限回合标签
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
type TimedBuildBuff = {
|
||||
id: string;
|
||||
sourceType: "skill" | "item" | "forge";
|
||||
sourceId: string;
|
||||
name: string;
|
||||
tags: string[];
|
||||
durationTurns: number;
|
||||
maxStacks?: number;
|
||||
};
|
||||
```
|
||||
|
||||
推荐时长:
|
||||
|
||||
- 强爆发 buff:`1~2` 回合
|
||||
- 节奏/机动 buff:`2~3` 回合
|
||||
- 防御/续航 buff:`2~4` 回合
|
||||
|
||||
重复规则:
|
||||
|
||||
- 同名 buff 默认刷新持续时间,不新增一套完全重复标签。
|
||||
- 不同来源但规范化后相同的标签,只保留一个 build 标签实例。
|
||||
- 重复来源只提高优先级或刷新,不增加额外 `+1` 基础值。
|
||||
|
||||
## 4. 语义 embedding 与套装 build 形成方式
|
||||
|
||||
### 4.1 为什么要引入 embedding
|
||||
|
||||
如果只靠显式 `setId`,build 会很死板。
|
||||
|
||||
引入 embedding 后,可以让这些组合自然成型:
|
||||
|
||||
- `快剑` + `突进` + `追击` + `风行`
|
||||
- `重甲` + `护体` + `守御` + `反击`
|
||||
- `雷法` + `法器` + `过载` + `法力`
|
||||
|
||||
也就是说:
|
||||
|
||||
- 显式套装仍然存在
|
||||
- 隐式语义套装也能成立
|
||||
- 两者都走同一套 build 标签计算,不必再写第二套特殊规则
|
||||
|
||||
### 4.2 embedding 计算对象
|
||||
|
||||
不要对每个物品实例现算 embedding,而是只对“规范标签定义”计算。
|
||||
|
||||
推荐流程:
|
||||
|
||||
1. 为 `buildTagRegistry` 中每个规范标签生成一条 embedding 文本。
|
||||
2. 文本内容由 `label + aliases + description` 组成。
|
||||
3. 预计算标签相似度矩阵并缓存到本地数据文件。
|
||||
4. 运行时只读相似度,不现算模型。
|
||||
|
||||
示例 embedding 文本:
|
||||
|
||||
```text
|
||||
快剑:以高速轻兵器、连续出手、贴身追击为核心的近战风格;别名 duelist, swift blade, 快袭。
|
||||
```
|
||||
|
||||
### 4.3 相似度函数
|
||||
|
||||
建议使用余弦相似度,并且只保留正向相似。
|
||||
|
||||
```ts
|
||||
similarity(a, b) = max(0, cosine(embedding(a), embedding(b)))
|
||||
```
|
||||
|
||||
建议阈值:
|
||||
|
||||
- `< 0.35`:视为无关,按 `0`
|
||||
- `0.35 ~ 0.65`:弱协同
|
||||
- `0.65 ~ 0.82`:强协同
|
||||
- `> 0.82`:视为同 build 簇强关联
|
||||
|
||||
### 4.4 语义套装簇形成
|
||||
|
||||
推荐同时保留两种 build 成型路径:
|
||||
|
||||
#### A. 显式套装
|
||||
|
||||
- 依据 `setId`
|
||||
- 2 件时生成一个合成标签:`套装:<setName>`
|
||||
- 3 件时再生成一个进阶标签:`宗匠:<setName>`
|
||||
|
||||
由于当前 runtime 只有三槽,所以 2 件和 3 件阈值最合适。
|
||||
|
||||
#### B. 隐式语义套装
|
||||
|
||||
当激活标签里存在 `3` 个及以上标签两两相似度超过阈值时,形成“语义 build 簇”。
|
||||
|
||||
例如:
|
||||
|
||||
- `快剑`
|
||||
- `突进`
|
||||
- `追击`
|
||||
- `风行`
|
||||
|
||||
它们无需拥有相同 `setId`,也能形成一组高相似 build。
|
||||
|
||||
## 5. 标签修正值与伤害公式
|
||||
|
||||
### 5.1 核心规则
|
||||
|
||||
用户给出的核心要求是:
|
||||
|
||||
- 每个标签修正值都是 `1`
|
||||
- 每多一个标签修正值加一
|
||||
- 同时所有标签的 `1` 需要额外乘上与新标签的相似度
|
||||
- 修正结果作用于输出伤害
|
||||
|
||||
将这条规则做成稳定、顺序无关的公式,可以写成:
|
||||
|
||||
```text
|
||||
rawBuildScore(T) = |T| + Σ similarity(t_i, t_j)
|
||||
(i < j)
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `|T|` 是激活标签数量,每个标签天然贡献 `1`
|
||||
- 每对标签之间再贡献一段相似度分
|
||||
|
||||
这个公式与“新增一个标签时,额外 +1,并让旧标签的 1 再乘上与新标签的相似度”完全等价。
|
||||
|
||||
对应的增量写法:
|
||||
|
||||
```text
|
||||
score_1 = 1
|
||||
score_k = score_(k-1) + 1 + Σ similarity(t_i, t_k)
|
||||
(1 <= i < k)
|
||||
```
|
||||
|
||||
### 5.2 激活标签集的选取
|
||||
|
||||
为了防止标签爆炸,建议运行时只取 `MAX_ACTIVE_BUILD_TAGS = 8`。
|
||||
|
||||
推荐优先级:
|
||||
|
||||
1. 限回合 buff 标签
|
||||
2. 角色/怪物核心标签
|
||||
3. 武器 build 标签
|
||||
4. 饰品 build 标签
|
||||
5. 护甲 build 标签
|
||||
6. 2 件/3 件套装合成标签
|
||||
|
||||
重复标签去重后再参与计算。
|
||||
|
||||
### 5.3 从 raw score 到伤害倍率
|
||||
|
||||
`rawBuildScore` 不直接等于伤害倍率,否则会过大。建议再做一层线性缩放与封顶。
|
||||
|
||||
```text
|
||||
buildDamageBonus = clamp((rawBuildScore - 1) * 0.03, 0, 0.45)
|
||||
buildDamageMultiplier = 1 + buildDamageBonus
|
||||
```
|
||||
|
||||
推荐解释:
|
||||
|
||||
- 单标签时没有 build 成型,不给明显收益
|
||||
- 2~4 标签形成初步风格,获得 5%~18% 左右伤害增益
|
||||
- 5~8 标签形成成熟 build,伤害增益逐步逼近 45% 上限
|
||||
|
||||
### 5.4 与当前战斗公式的接法
|
||||
|
||||
当前战斗中,伤害基本来自:
|
||||
|
||||
- 技能基础伤害
|
||||
- `functionEffect.damageMultiplier`
|
||||
- 装备 stat 值
|
||||
|
||||
建议统一改成:
|
||||
|
||||
```text
|
||||
finalOutgoingDamage =
|
||||
round(
|
||||
baseSkillDamage
|
||||
* functionDamageMultiplier
|
||||
* equipmentStatMultiplier
|
||||
* buildDamageMultiplier
|
||||
)
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `equipmentStatMultiplier` 来自武器/护甲/饰品的 `statProfile`
|
||||
- `buildDamageMultiplier` 来自标签相似度 build
|
||||
- 先乘完再 `round`
|
||||
|
||||
本期先只影响“输出伤害”。
|
||||
|
||||
也就是:
|
||||
|
||||
- 玩家攻击怪物时用玩家侧标签
|
||||
- 同伴攻击怪物时用同伴侧标签
|
||||
- 怪物攻击玩家/同伴时用怪物侧标签
|
||||
|
||||
防御端 build 抵抗可以放到下一期,不必一开始就加复杂。
|
||||
|
||||
### 5.5 示例
|
||||
|
||||
某角色当前激活标签为:
|
||||
|
||||
- `快剑`
|
||||
- `突进`
|
||||
- `追击`
|
||||
- `风行`
|
||||
- `套装:百炼争锋`
|
||||
|
||||
假设相似度如下:
|
||||
|
||||
- `快剑-突进 = 0.82`
|
||||
- `快剑-追击 = 0.78`
|
||||
- `快剑-风行 = 0.65`
|
||||
- `突进-追击 = 0.80`
|
||||
- `突进-风行 = 0.72`
|
||||
- `追击-风行 = 0.70`
|
||||
- 套装标签与前四者平均相似度 `0.76`
|
||||
|
||||
则:
|
||||
|
||||
```text
|
||||
rawBuildScore
|
||||
= 5
|
||||
+ (0.82 + 0.78 + 0.65 + 0.80 + 0.72 + 0.70)
|
||||
+ (0.76 * 4)
|
||||
= 11.51
|
||||
|
||||
buildDamageBonus
|
||||
= clamp((11.51 - 1) * 0.03, 0, 0.45)
|
||||
= 0.3153
|
||||
|
||||
buildDamageMultiplier = 1.3153
|
||||
```
|
||||
|
||||
若本次技能基础伤害为 `28`,动作倍率为 `1.2`,装备数值倍率为 `1.14`,则:
|
||||
|
||||
```text
|
||||
finalDamage = round(28 * 1.2 * 1.14 * 1.3153) = 50
|
||||
```
|
||||
|
||||
## 6. 合成 / 锻造 / 回收闭环设计
|
||||
|
||||
### 6.1 闭环目标
|
||||
|
||||
让当前已有入口真正连起来:
|
||||
|
||||
- 怪物掉落
|
||||
- 宝藏奖励
|
||||
- NPC 交易
|
||||
- 背包积累
|
||||
- 装备更替
|
||||
- 消耗品 buff
|
||||
- 锻造与回收
|
||||
|
||||
形成闭环后,物品系统就不再只是“剧情资源池”,而是成长系统。
|
||||
|
||||
### 6.2 资源分层
|
||||
|
||||
建议把资源拆成 4 类:
|
||||
|
||||
| 类型 | 作用 | 当前可复用入口 |
|
||||
| --- | --- | --- |
|
||||
| 基础材料 | 进入配方、升级、重铸 | 怪物掉落、宝藏、NPC 交易 |
|
||||
| 标签精粹 | 决定 build 方向 | 拆解装备、精炼材料 |
|
||||
| 套装蓝图 | 决定显式 setId 结果 | 宝藏、精英怪、任务 |
|
||||
| 催化剂 | 提升稀有度、锁词条、转流派 | 稀有品、商店、Boss 掉落 |
|
||||
|
||||
### 6.3 推荐闭环
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["遭遇 / 战斗 / 宝藏 / 交易"] --> B["获得装备 / 材料 / 消耗品 / 蓝图"]
|
||||
B --> C["直接装备"]
|
||||
B --> D["拆解回收"]
|
||||
D --> E["基础材料"]
|
||||
D --> F["标签精粹"]
|
||||
D --> G["蓝图碎片"]
|
||||
E --> H["合成精炼材料"]
|
||||
F --> H
|
||||
G --> I["完整蓝图"]
|
||||
H --> J["锻造新装备"]
|
||||
I --> J
|
||||
J --> K["重铸 / 淬炼 / 铭刻"]
|
||||
K --> C
|
||||
C --> L["形成 build 与伤害提升"]
|
||||
L --> A
|
||||
```
|
||||
|
||||
### 6.4 关键环节
|
||||
|
||||
#### A. 拆解
|
||||
|
||||
目标:
|
||||
|
||||
- 回收无用装备
|
||||
- 提取 build 倾向
|
||||
- 让玩家可以主动转流派
|
||||
|
||||
建议产出:
|
||||
|
||||
- 基础材料:按装备部位与稀有度产出
|
||||
- 标签精粹:按 `buildProfile.tags` 产出对应流派精粹
|
||||
- 套装碎片:带 `setId` 的装备有概率掉落
|
||||
|
||||
推荐规则:
|
||||
|
||||
- 普通/优秀:返还 `1~2` 基础材料 + `1` 标签精粹
|
||||
- 稀有/史诗:返还 `2~4` 基础材料 + `1~2` 标签精粹
|
||||
- 传说:返还 `4+` 基础材料 + `2~3` 标签精粹 + 套装碎片
|
||||
|
||||
#### B. 合成
|
||||
|
||||
目标:
|
||||
|
||||
- 把零散材料往更高层资源转化
|
||||
|
||||
推荐配方:
|
||||
|
||||
- `3` 个同系基础材料 -> `1` 个精炼材料
|
||||
- `2` 个相近标签精粹 -> `1` 个簇催化剂
|
||||
- `3` 个蓝图碎片 -> `1` 个完整蓝图
|
||||
|
||||
#### C. 锻造
|
||||
|
||||
目标:
|
||||
|
||||
- 制造三槽位装备
|
||||
- 明确把材料生态和 build 流派联系起来
|
||||
|
||||
建议锻造公式:
|
||||
|
||||
```text
|
||||
成品 = 槽位模板 + 基础材料 + 标签精粹 + 蓝图/催化剂
|
||||
```
|
||||
|
||||
推荐规则:
|
||||
|
||||
- 武器:决定主要输出 build 标签
|
||||
- 护甲:决定生存/反击/续战方向
|
||||
- 饰品:决定资源、冷却、机动、控场补短板
|
||||
|
||||
#### D. 重铸
|
||||
|
||||
目标:
|
||||
|
||||
- 保留 build 主方向
|
||||
- 调整副标签
|
||||
|
||||
推荐规则:
|
||||
|
||||
- 保留主标签与 `setId`
|
||||
- 只在同一语义簇内重掷副标签
|
||||
- 花费标签精粹 + 货币
|
||||
|
||||
这样玩家不会因为一次重铸直接从 `快剑` 跳成 `重甲`。
|
||||
|
||||
#### E. 淬炼
|
||||
|
||||
目标:
|
||||
|
||||
- 提升已有装备而不是频繁换装
|
||||
|
||||
推荐效果:
|
||||
|
||||
- 提升 `forgeRank`
|
||||
- 增加 `statProfile`
|
||||
- 提高套装合成标签的优先级
|
||||
|
||||
#### F. 铭刻 / 附魔
|
||||
|
||||
目标:
|
||||
|
||||
- 让消耗品和锻造形成直接关系
|
||||
|
||||
推荐效果:
|
||||
|
||||
- 给装备附加可触发 buff 标签
|
||||
- 或直接生产“一次性战斗铭符”
|
||||
|
||||
例子:
|
||||
|
||||
- `疾风符`:`2` 回合获得 `风行`、`突进`
|
||||
- `镇岳印`:`2` 回合获得 `护体`、`守御`
|
||||
- `雷纹油`:`1` 回合获得 `雷法`、`过载`
|
||||
|
||||
## 7. 当前三槽系统下的 build 形态
|
||||
|
||||
由于当前只有 `weapon / armor / relic` 三槽,建议本期 build 以“2 件成型、3 件毕业”为主。
|
||||
|
||||
### 7.1 套装成型方式
|
||||
|
||||
- 1 件:只提供本件核心标签
|
||||
- 2 件:生成 `套装:<setName>` 合成标签
|
||||
- 3 件:再生成 `宗匠:<setName>` 进阶标签
|
||||
|
||||
这两个“合成标签”本质上也是普通 build 标签,因此会自动进入 embedding 相似度和伤害公式。
|
||||
|
||||
### 7.2 推荐 build archetype
|
||||
|
||||
| build | 角色/怪物核心标签 | 装备标签方向 | buff 标签方向 | 锻造材料倾向 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 快剑追袭 | `快剑`、`突进`、`追击` | 武器补 `连段`,饰品补 `风行` | `疾风`、`破绽` | `百炼钢`、`风羽`、`轻皮` |
|
||||
| 重甲反击 | `守御`、`重甲`、`反击` | 护甲补 `护体`,饰品补 `镇势` | `立壁`、`嘲压` | `寒铁`、`壳片`、`岩核` |
|
||||
| 雷法过载 | `法修`、`雷法`、`法力` | 武器补 `过载`,饰品补 `聚灵` | `引雷`、`蓄放` | `星砂`、`雷纹石`、`灵晶` |
|
||||
| 命纹机缘 | `命纹`、`冷却`、`机缘` | 饰品补 `连锁`,护甲补 `续战` | `转运`、`回转` | `命纹骨片`、`旧卷`、`秘印` |
|
||||
| 医理续战 | `回复`、`护持`、`续战` | 护甲补 `守御`,饰品补 `凝神` | `回气`、`清心` | `灵木`、`药囊`、`泉露` |
|
||||
|
||||
## 8. 与当前掉落和地图生态的关系
|
||||
|
||||
### 8.1 怪物生态标签不直接进伤害
|
||||
|
||||
当前怪物已有 `habitatTags`,更适合驱动:
|
||||
|
||||
- 掉落材料倾向
|
||||
- 可锻造流派倾向
|
||||
- 宝藏/地图资源分布
|
||||
|
||||
例如:
|
||||
|
||||
- `矿道 / 铸坊 / 废城` -> `寒铁`、`锻火`、`重甲`
|
||||
- `雾林 / 沼泽` -> `毒囊`、`湿毒`、`潜伏`
|
||||
- `祭坛 / 遗迹 / 古迹` -> `残卷`、`纹石`、`镇邪`
|
||||
- `月湖 / 灵泉 / 天河` -> `水灵`、`回气`、`法力`
|
||||
|
||||
### 8.2 当前掉落表可直接扩展
|
||||
|
||||
当前怪物掉落里已经有很多适合闭环的原型:
|
||||
|
||||
- `armor + material`
|
||||
- `weapon + material`
|
||||
- `relic + mana`
|
||||
- `consumable + material`
|
||||
|
||||
下一步不必推翻,只要再补:
|
||||
|
||||
1. 掉落物的 `craftTags`
|
||||
2. 掉落物的 `buildProfile`
|
||||
3. 拆解产物表
|
||||
|
||||
就能把这些现有掉落自然接进锻造循环。
|
||||
|
||||
## 9. 数据结构建议
|
||||
|
||||
### 9.1 类型扩展
|
||||
|
||||
建议在现有结构上最小扩展:
|
||||
|
||||
```ts
|
||||
type BuildTagCategory =
|
||||
| "role"
|
||||
| "style"
|
||||
| "resource"
|
||||
| "defense"
|
||||
| "element"
|
||||
| "craft";
|
||||
|
||||
interface BuildTagDefinition {
|
||||
id: string;
|
||||
label: string;
|
||||
category: BuildTagCategory;
|
||||
aliases: string[];
|
||||
description: string;
|
||||
}
|
||||
|
||||
interface ItemBuildProfile {
|
||||
role: string;
|
||||
tags: string[]; // 只放战斗语义标签
|
||||
setId?: string;
|
||||
setName?: string;
|
||||
pieceName?: string;
|
||||
synergy?: string[];
|
||||
craftTags?: string[]; // 新增:配方/材料倾向
|
||||
forgeRank?: number; // 新增:淬炼等级
|
||||
}
|
||||
|
||||
interface CombatTaggedActor {
|
||||
combatTags: string[];
|
||||
}
|
||||
|
||||
interface TimedBuildBuff {
|
||||
id: string;
|
||||
sourceType: "skill" | "item" | "forge";
|
||||
sourceId: string;
|
||||
name: string;
|
||||
tags: string[];
|
||||
durationTurns: number;
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 GameState 扩展
|
||||
|
||||
```ts
|
||||
interface GameState {
|
||||
activeBuildBuffs: TimedBuildBuff[];
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 技能与物品扩展
|
||||
|
||||
```ts
|
||||
interface ItemUseProfile {
|
||||
hpRestore?: number;
|
||||
manaRestore?: number;
|
||||
cooldownReduction?: number;
|
||||
buildBuffs?: TimedBuildBuff[];
|
||||
}
|
||||
|
||||
interface FunctionEffectConfig {
|
||||
damageMultiplier?: number;
|
||||
incomingDamageMultiplier?: number;
|
||||
healAmount?: number;
|
||||
manaRestore?: number;
|
||||
cooldownTickBonus?: number;
|
||||
grantedBuildBuffs?: TimedBuildBuff[];
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 运行时接入点
|
||||
|
||||
### 10.1 必须新增的规则层
|
||||
|
||||
建议新增 3 个数据/规则文件:
|
||||
|
||||
- `src/data/buildTags.ts`
|
||||
- 标签规范化
|
||||
- alias 映射
|
||||
- 相似度矩阵
|
||||
- `src/data/buildDamage.ts`
|
||||
- 聚合激活标签
|
||||
- 计算 `rawBuildScore`
|
||||
- 计算 `buildDamageMultiplier`
|
||||
- `src/data/forgeRecipes.ts`
|
||||
- 合成、锻造、拆解、重铸配方
|
||||
|
||||
### 10.2 当前代码里的关键接点
|
||||
|
||||
#### A. `src/data/equipmentEffects.ts`
|
||||
|
||||
需要从“空壳”升级为真正读取:
|
||||
|
||||
- `statProfile`
|
||||
- `buildProfile`
|
||||
- 套装件数
|
||||
|
||||
建议这里做:
|
||||
|
||||
- 读取三槽装备 stat 汇总
|
||||
- 计算显式套装件数
|
||||
- 产出装备侧 build 标签源
|
||||
|
||||
#### B. `src/hooks/useCombatFlow.ts`
|
||||
|
||||
这里是 build 进伤害的核心接点。
|
||||
|
||||
当前玩家、同伴、怪物都有单独 `damage = ...` 的结算片段,建议统一收敛成:
|
||||
|
||||
```ts
|
||||
resolveOutgoingDamage({
|
||||
actor,
|
||||
target,
|
||||
skill,
|
||||
functionEffect,
|
||||
gameState,
|
||||
})
|
||||
```
|
||||
|
||||
统一处理:
|
||||
|
||||
- actor 的 `combatTags`
|
||||
- actor 装备 build 标签
|
||||
- actor 当前限回合 buff 标签
|
||||
- 显式套装合成标签
|
||||
- embedding build 伤害修正
|
||||
|
||||
#### C. `src/data/characterPresets.ts`
|
||||
|
||||
角色需要正式持有 `combatTags`,不要再只放在 UI 常量里。
|
||||
|
||||
#### D. `src/data/monsterPresets.ts`
|
||||
|
||||
怪物新增:
|
||||
|
||||
- `combatTags`
|
||||
- `craftTags`
|
||||
|
||||
保留:
|
||||
|
||||
- `habitatTags`
|
||||
|
||||
#### E. `src/hooks/useGamePersistence.ts`
|
||||
|
||||
存档兼容必须同步补:
|
||||
|
||||
- `activeBuildBuffs`
|
||||
- 新字段默认值
|
||||
- 旧存档自动补空数组
|
||||
|
||||
## 11. 编辑器与策划工作流
|
||||
|
||||
结合当前项目“先补类型和规则,再补 UI”的经验,编辑器建议按下面顺序补。
|
||||
|
||||
### 11.1 标签注册表
|
||||
|
||||
先做一个统一标签注册表,再让各编辑器引用它。
|
||||
|
||||
编辑器最少应支持:
|
||||
|
||||
- 选择规范标签
|
||||
- 查看别名
|
||||
- 查看所属 build 簇
|
||||
- 查看与其他标签的相似度
|
||||
|
||||
### 11.2 Item Catalog Editor
|
||||
|
||||
当前它已经能展示 `buildProfile`,下一步建议补:
|
||||
|
||||
- 规范标签选择器
|
||||
- 当前装备可形成的 build 预览
|
||||
- 2 件/3 件套装合成标签预览
|
||||
- 拆解产物预览
|
||||
|
||||
### 11.3 角色/怪物编辑
|
||||
|
||||
建议把角色和怪物的 `combatTags` 录入正式数据,不再只放展示文案。
|
||||
|
||||
### 11.4 相似度预计算脚本
|
||||
|
||||
建议加一个脚本,例如:
|
||||
|
||||
```text
|
||||
scripts/build-tag-similarity.mjs
|
||||
```
|
||||
|
||||
负责:
|
||||
|
||||
- 读取标签注册表
|
||||
- 生成 embedding
|
||||
- 输出相似度矩阵 JSON
|
||||
|
||||
这样运行时就不需要联网或现算。
|
||||
|
||||
## 12. 数值与反滥用约束
|
||||
|
||||
为了让系统长期可控,建议一开始就加以下约束:
|
||||
|
||||
1. 同规范标签去重,不允许同词条多件装备无限叠加基础 `+1`。
|
||||
2. 激活标签上限 `8`,避免后期词条爆炸。
|
||||
3. 伤害 build 增益封顶 `45%`,防止纯标签乘爆。
|
||||
4. 2 件/3 件套只生成合成标签,不再额外套一层独立乘区,避免双重膨胀。
|
||||
5. `habitatTags` 不直接进伤害,避免出现“矿道标签提高输出”这种语义跑偏。
|
||||
6. buff 标签以刷新时长为主,不以无限叠层为主。
|
||||
7. 重铸只在语义近邻内滚动,避免 build 完全变异。
|
||||
8. 拆解返还率不要超过完整锻造成本的 `60%~70%`,避免无限刷循环。
|
||||
|
||||
## 13. 分阶段实施建议
|
||||
|
||||
按照当前项目文档里已经验证过的开发经验,推荐顺序是“类型 -> 规则 -> hook -> UI”,不要反过来。
|
||||
|
||||
### 阶段 A:先补数据骨架
|
||||
|
||||
- 新增 `buildTagRegistry`
|
||||
- 为角色/怪物补 `combatTags`
|
||||
- 为物品补 `craftTags / forgeRank`
|
||||
- 为 `GameState` 补 `activeBuildBuffs`
|
||||
|
||||
### 阶段 B:再补规则
|
||||
|
||||
- 实现标签规范化
|
||||
- 实现 embedding 相似度矩阵
|
||||
- 实现 `rawBuildScore`
|
||||
- 实现三槽位显式套装合成标签
|
||||
- 实现 buff 标签衰减
|
||||
|
||||
### 阶段 C:接入战斗
|
||||
|
||||
- `useCombatFlow.ts` 改为统一伤害入口
|
||||
- 玩家 / 同伴 / 怪物统一读取 build
|
||||
- `equipmentEffects.ts` 正式生效
|
||||
|
||||
### 阶段 D:补合成/锻造闭环
|
||||
|
||||
- 拆解
|
||||
- 合成
|
||||
- 锻造
|
||||
- 重铸
|
||||
- 铭刻
|
||||
|
||||
### 阶段 E:最后补编辑器与 UI
|
||||
|
||||
- 物品 build 预览
|
||||
- 套装预览
|
||||
- 锻造页
|
||||
- 材料来源与标签簇提示
|
||||
|
||||
## 14. 一句话总结
|
||||
|
||||
本方案的核心不是单独增加“套装数值”,而是把装备、角色/怪物、限回合 buff 都转成统一的语义 build 标签,再用“每标签基础值 1 + 标签间 embedding 相似度”的方式形成构筑强度,并把这份构筑强度直接接进当前伤害输出,同时让怪物掉落、宝藏、交易、拆解、合成、锻造、铭刻围绕同一套标签体系形成闭环。
|
||||
@@ -0,0 +1,887 @@
|
||||
# 等级成长、章节经验节奏与 NPC 自动定级设计
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 实现进度(2026-04-20 第一批)
|
||||
|
||||
当前仓库已按本设计先落地第一批稳定能力:
|
||||
|
||||
1. 已新增 `playerProgression` 正式成长状态,包含等级、当前等级经验、总经验与下级阈值。
|
||||
2. 已新增等级基准与经验结算服务,并接入前后端存档归一化,旧存档默认回填为 `Lv.1 / 0 XP`。
|
||||
3. 已给 `QuestReward` 补上 `experience`,新生成任务会按当前等级与任务结构给出任务经验。
|
||||
4. 已将 Express 后端 `npc_quest_turn_in` 接入经验发放与升级处理,任务交付结果会反馈 `经验 +N` 与升级信息。
|
||||
5. 已在冒险主面板补充最小等级展示:`Lv.` 与细经验条;任务奖励面板可看到经验数值。
|
||||
6. 已收回任务日志里的直接领奖入口,任务奖励结算当前以 NPC 交付链路为准。
|
||||
|
||||
## 实现进度(2026-04-20 第二批)
|
||||
|
||||
当前仓库已继续落地第二批成长能力:
|
||||
|
||||
1. 已给运行时敌对 NPC / 战斗遭遇补上 `levelProfile` 与 `experienceReward`,前后端快照、战斗态和恢复链路会保留这组元数据。
|
||||
2. 已新增敌对成长解析服务,当前先以玩家当前等级为 fallback,为 `npc_fight` / 敌对战斗入口自动生成等级、参考强度、战斗生命值与击杀经验。
|
||||
3. 已将 Express 后端战斗胜利结算接入 `hostile_npc` 经验发放,击败敌对 NPC 后会直接更新 `playerProgression`,并写回 `hostileNpcsDefeated` 统计。
|
||||
4. 已在战斗画布中补上敌对 NPC 的最小 `Lv.` 徽标展示,保持 UI 极简表达。
|
||||
|
||||
## 实现进度(2026-04-20 第三批)
|
||||
|
||||
当前仓库已继续落地第三批“章节预算 / 自动定级”能力:
|
||||
|
||||
1. 已新增服务端 `chapterProgressionPlanner`,会基于 `sceneChapterBlueprints` 编译每章的 `entry / exit pseudo level`、总经验预算、任务经验份额、敌对经验份额与预计击杀数。
|
||||
2. 已新增 `npcLevelResolver`,会根据当前章节阶段和当前 act 的 `primaryNpcId` 自动区分 `hostile_standard / hostile_elite / hostile_boss / rival`,并输出 `source = chapter_auto` 的等级档案。
|
||||
3. 已将 `npc_fight` / `npc_spar` 开战入口接入章节上下文解析;当运行时存在章节蓝图、当前章和当前 act 信息时,敌对 NPC 不再只跟随玩家当前等级,而会按章节自动定级并生成更贴合本章预算的经验奖励。
|
||||
4. 已补上规划器、定级器与路由级验证,确认同一玩家在不同章节和不同阶段触发敌对战斗时,会得到不同的等级与经验结果。
|
||||
|
||||
本轮仍未落地的部分:
|
||||
|
||||
1. `ChapterExperienceLedger` 的正式持久化、按章实际经验记账与偏差回看还未接入。
|
||||
2. 同章重复刷敌的 `repeatPenalty` 与超预算衰减还未落地,当前仍是“预算规划 + 单次掉落”版本。
|
||||
3. 当前自动定级已优先接入敌对战斗入口,友方 / 环境 NPC 的更广泛等级消费链路仍待继续铺开。
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这次设计解决 5 个必须同时成立的问题:
|
||||
|
||||
1. 玩家需要正式拥有 `等级 / 当前经验 / 总经验 / 升级` 这条成长主链。
|
||||
2. 经验只从两类明确来源进入:
|
||||
- 完成任务
|
||||
- 击败敌对 NPC
|
||||
3. 同等级实体必须具备同一档 `参考强度`,不能再靠散落在各处的静态数值各自漂移。
|
||||
4. 系统需要能按章节评估玩家经验获取速度,而不是只在整体通关后回看“升太快/升太慢”。
|
||||
5. 不同章节里的 NPC 需要按章节目标等级自动定级,保证这一章的敌我强度、经验产出和升级节奏互相闭合。
|
||||
|
||||
一句话结论:
|
||||
|
||||
**等级必须成为后端统一裁决的成长基线;章节必须先产出“目标玩家等级带 + 经验预算”,再由这套预算反推任务经验、击杀经验和本章 NPC 自动等级。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 基于当前仓库的判断
|
||||
|
||||
结合当前代码与文档,现状已经有足够好的骨架,但等级系统这一层还完全缺位。
|
||||
|
||||
### 1.1 已经具备的基础
|
||||
|
||||
1. `src/data/questFlow.ts`
|
||||
|
||||
- 已有 `QuestLogEntry / QuestStep / QuestProgressSignal / chapter quest`。
|
||||
- 已经能把场景章节任务接到运行时主链。
|
||||
|
||||
2. `server-node/src/modules/quest/questStoryActionService.ts`
|
||||
|
||||
- 已经把 `接任务 / 交任务` 收回后端。
|
||||
- 任务结算时已经集中处理货币、背包、好感变化。
|
||||
|
||||
3. `server-node/src/modules/quest/questRuntimeSignalService.ts`
|
||||
|
||||
- 已经会在 `npc_chat / 击败敌对 NPC / 宝藏 / 切磋` 后投递 quest signal。
|
||||
|
||||
4. `src/services/storyEngine/chapterDirector.ts`
|
||||
|
||||
- 已经能用当前场景章节任务推导 `opening -> expansion -> turning_point -> climax -> aftermath`。
|
||||
|
||||
5. `src/types/customWorld.ts`
|
||||
|
||||
- 已经有 `sceneChapterBlueprints`,说明章节顺序、幕推进和 NPC 编排已经有正式挂点。
|
||||
|
||||
6. `src/types/attributes.ts`、`src/data/hostileNpcPresets.ts`
|
||||
- 已经有统一属性画像、怪物/NPC 统一实体方向。
|
||||
- 当前敌对实体已有 `baseStats / attributeProfile / behaviorVectors`,可以继续向“同级同参考强度”收束。
|
||||
|
||||
### 1.2 当前缺口
|
||||
|
||||
当前最核心的缺口有 6 个:
|
||||
|
||||
1. `GameState` 没有玩家等级成长状态。
|
||||
2. `QuestReward` 没有经验字段。
|
||||
3. `SceneHostileNpc / SceneNpc` 没有正式等级和击杀经验字段。
|
||||
4. 当前 hostile preset 的 `hp/maxHp` 仍是静态绝对值,不受章节节奏控制。
|
||||
5. 章节系统没有“本章目标入场等级 / 出章等级 / 经验预算”的结构。
|
||||
6. 没有“按章节自动定级”的编译器,也没有“本章经验是否超发/欠发”的记账面板。
|
||||
|
||||
一句话总结:
|
||||
|
||||
**现在仓库里已经有章节、任务、NPC 和属性系统,但还没有“成长预算层”,所以强度、奖励和章节节奏仍然缺少同一把尺。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心决策
|
||||
|
||||
## 2.1 等级、经验与 NPC 定级全部由 Express 后端裁决
|
||||
|
||||
必须坚持:
|
||||
|
||||
1. 前端只展示 `等级 / 经验条 / 升级结果 / NPC 等级徽标`。
|
||||
2. 经验发放、升级、章节经验预算、NPC 自动定级全部在 Express 后端计算。
|
||||
3. 前端不本地推演“这次应该升几级”“这个 NPC 应该是多少级”。
|
||||
|
||||
推荐新增领域目录:
|
||||
|
||||
- `server-node/src/modules/progression/`
|
||||
|
||||
建议首批模块:
|
||||
|
||||
- `levelBenchmarks.ts`
|
||||
- `playerProgressionService.ts`
|
||||
- `chapterProgressionPlanner.ts`
|
||||
- `chapterExperienceLedger.ts`
|
||||
- `npcLevelResolver.ts`
|
||||
- `progressionRuntimeSignalService.ts`
|
||||
|
||||
## 2.2 MVP 经验来源只认两类事件
|
||||
|
||||
首版只允许两类正式经验来源:
|
||||
|
||||
1. `quest_turned_in`
|
||||
|
||||
- 任务真正交付时发经验。
|
||||
- 不在“接任务”“任务 ready_to_turn_in”时发经验。
|
||||
|
||||
2. `hostile_npc_defeated`
|
||||
- 仅限敌对 NPC / 怪物胜利结算后发经验。
|
||||
- 不对 `npc_spar_completed`、普通聊天、观察、宝藏直接发经验。
|
||||
|
||||
这样做的原因是:
|
||||
|
||||
1. 最容易和当前后端任务/战斗链路接上。
|
||||
2. 经验来源清晰,便于做章节预算。
|
||||
3. 避免系统一开始就被碎片经验源冲散。
|
||||
|
||||
## 2.3 同等级 = 同参考强度
|
||||
|
||||
这是本次设计最重要的规则:
|
||||
|
||||
1. 等级是所有可比较实体共享的强度基线。
|
||||
2. 同等级玩家、敌对 NPC、可战斗剧情 NPC,必须共享同一档 `参考强度`。
|
||||
3. 世界属性 schema 只决定“强在哪种风格上”,不决定“同级谁天然强一截”。
|
||||
|
||||
也就是说:
|
||||
|
||||
- `Lv.8` 的重甲敌人和 `Lv.8` 的迅捷刺客可以打法不同
|
||||
- 但两者的 `参考强度预算` 必须是同一档
|
||||
|
||||
真正的强弱差只允许来自:
|
||||
|
||||
1. 等级差
|
||||
2. 装备 / Build / Buff / Debuff
|
||||
3. 章节中明确声明的 `boss / elite` 角色通过更高等级体现,而不是同级偷加隐藏倍数
|
||||
|
||||
## 2.4 章节先出经验预算,再反推等级
|
||||
|
||||
章节设计从这次开始必须按下面顺序计算:
|
||||
|
||||
```text
|
||||
章节顺序
|
||||
-> 本章玩家目标入场等级 / 出章等级
|
||||
-> 本章总经验预算
|
||||
-> 任务经验份额 / 击杀经验份额
|
||||
-> 本章 NPC 自动等级
|
||||
-> 本章实际经验记账与偏差评估
|
||||
```
|
||||
|
||||
不能反过来先手写一堆 NPC 强度,再看玩家能不能接住。
|
||||
|
||||
## 2.5 UI 只做极简表达
|
||||
|
||||
为了符合当前项目“UI 不默认堆规则说明”的约束,前台只建议新增 4 个轻量展示:
|
||||
|
||||
1. 玩家信息区:
|
||||
|
||||
- `Lv. X`
|
||||
- 一条细经验条
|
||||
|
||||
2. 敌对 NPC 名牌:
|
||||
|
||||
- `Lv. X`
|
||||
|
||||
3. 任务交付结果:
|
||||
|
||||
- `经验 +N`
|
||||
|
||||
4. 升级提示:
|
||||
- 单条 toast 或单行系统反馈
|
||||
|
||||
不在界面里默认放:
|
||||
|
||||
- 经验公式说明
|
||||
- 章节经验预算说明
|
||||
- 等级规则解释文案
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据结构设计
|
||||
|
||||
## 3.1 玩家成长状态
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
export interface PlayerProgressionState {
|
||||
level: number;
|
||||
currentLevelXp: number;
|
||||
totalXp: number;
|
||||
xpToNextLevel: number;
|
||||
pendingLevelUps?: number;
|
||||
lastGrantedSource?: 'quest' | 'hostile_npc' | null;
|
||||
}
|
||||
```
|
||||
|
||||
挂载位置建议:
|
||||
|
||||
- `src/types/game.ts`
|
||||
- `GameState.playerProgression`
|
||||
|
||||
原则:
|
||||
|
||||
1. 这不是 `runtimeStats` 的一部分。
|
||||
2. `runtimeStats` 继续做统计计数。
|
||||
3. `playerProgression` 是正式玩法状态。
|
||||
|
||||
## 3.2 等级基准表
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
export interface LevelBenchmark {
|
||||
level: number;
|
||||
xpToNextLevel: number;
|
||||
cumulativeXpRequired: number;
|
||||
referenceStrength: number;
|
||||
baseHp: number;
|
||||
baseMana: number;
|
||||
baselineDamageScale: number;
|
||||
}
|
||||
```
|
||||
|
||||
单一真相源建议放在:
|
||||
|
||||
- `server-node/src/modules/progression/levelBenchmarks.ts`
|
||||
|
||||
前端只通过后端投影拿结果,不自己保存第二份表。
|
||||
|
||||
## 3.3 实体等级档案
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
export type ProgressionRole =
|
||||
| 'guide'
|
||||
| 'ambient'
|
||||
| 'support'
|
||||
| 'hostile_standard'
|
||||
| 'hostile_elite'
|
||||
| 'hostile_boss'
|
||||
| 'rival';
|
||||
|
||||
export interface EntityLevelProfile {
|
||||
level: number;
|
||||
referenceStrength: number;
|
||||
chapterId?: string | null;
|
||||
chapterIndex?: number | null;
|
||||
progressionRole: ProgressionRole;
|
||||
source: 'chapter_auto' | 'preset_override' | 'manual';
|
||||
}
|
||||
```
|
||||
|
||||
建议接入:
|
||||
|
||||
- `src/types/scene.ts`
|
||||
- `SceneNpc.levelProfile?: EntityLevelProfile`
|
||||
- `SceneHostileNpc.levelProfile?: EntityLevelProfile`
|
||||
|
||||
## 3.4 任务奖励扩展
|
||||
|
||||
建议扩展:
|
||||
|
||||
```ts
|
||||
export interface QuestReward {
|
||||
affinityBonus: number;
|
||||
currency: number;
|
||||
experience: number;
|
||||
items: InventoryItem[];
|
||||
storyHint?: string;
|
||||
intel?: { ... };
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
1. 经验是任务奖励的一等字段。
|
||||
2. 经验文本不走 story hint 兜底。
|
||||
3. 任务经验由后端编译,不交给 AI 决定。
|
||||
|
||||
## 3.5 敌对 NPC 经验掉落
|
||||
|
||||
建议扩展:
|
||||
|
||||
```ts
|
||||
export interface SceneHostileNpc {
|
||||
...
|
||||
experienceReward?: number;
|
||||
}
|
||||
```
|
||||
|
||||
首版只给运行时敌对 NPC 挂经验值,不强行把它沉到所有 preset 原始数据中。
|
||||
|
||||
原因:
|
||||
|
||||
1. 经验应该跟章节定级一起编译。
|
||||
2. 同一个 hostile preset 出现在不同章节时,等级和经验都应不同。
|
||||
3. 静态 preset 继续只表达“风格”和“原型”,不再表达最终强度。
|
||||
|
||||
## 3.6 章节成长计划
|
||||
|
||||
建议新增运行时编译结果:
|
||||
|
||||
```ts
|
||||
export interface ChapterProgressionPlan {
|
||||
chapterId: string;
|
||||
chapterIndex: number;
|
||||
totalChapters: number;
|
||||
entryPseudoLevel: number;
|
||||
exitPseudoLevel: number;
|
||||
entryLevel: number;
|
||||
exitLevel: number;
|
||||
totalXpBudget: number;
|
||||
questXpBudget: number;
|
||||
hostileXpBudget: number;
|
||||
expectedHostileDefeatCount: number;
|
||||
paceBand: 'opening_fast' | 'steady' | 'pressure' | 'finale_dense';
|
||||
}
|
||||
```
|
||||
|
||||
建议作为后端运行时编译结果缓存,不作为创作者直接编辑字段。
|
||||
|
||||
## 3.7 章节经验记账
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
export interface ChapterExperienceLedger {
|
||||
chapterId: string;
|
||||
chapterIndex: number;
|
||||
levelAtEntry: number;
|
||||
levelAtExit?: number | null;
|
||||
plannedTotalXp: number;
|
||||
plannedQuestXp: number;
|
||||
plannedHostileXp: number;
|
||||
actualQuestXp: number;
|
||||
actualHostileXp: number;
|
||||
expectedHostileDefeatCount: number;
|
||||
actualHostileDefeatCount: number;
|
||||
}
|
||||
```
|
||||
|
||||
用途:
|
||||
|
||||
1. 评估每一章经验速度。
|
||||
2. 判断本章是否超发/欠发。
|
||||
3. 为下一轮调参提供依据。
|
||||
|
||||
---
|
||||
|
||||
## 4. 等级曲线与参考强度
|
||||
|
||||
## 4.1 首版等级目标
|
||||
|
||||
首版建议:
|
||||
|
||||
1. 系统支持 `Lv.1 ~ Lv.20`
|
||||
2. 当前主线正常通章目标不是满级
|
||||
3. 标准单轮战役通关目标等级建议落在 `Lv.14 ~ Lv.15`
|
||||
|
||||
这样做的原因是:
|
||||
|
||||
1. 级差足够表达章节成长
|
||||
2. 不会让前期升级过细、后期又没有空间
|
||||
3. 还保留后续营地、精英支线、长期养成的余量
|
||||
|
||||
## 4.2 升级经验公式
|
||||
|
||||
建议基线公式:
|
||||
|
||||
```ts
|
||||
xpToNextLevel(level) = 60 + 20 * (level - 1) + 8 * (level - 1) * (level - 1);
|
||||
```
|
||||
|
||||
由此生成 `LevelBenchmark[]`,不在业务代码里散落重复公式。
|
||||
|
||||
说明:
|
||||
|
||||
1. 前期升级快,便于建立成长反馈
|
||||
2. 中后期门槛逐步拉开,避免章节尾段失控
|
||||
3. 可直接序列化成常量表用于测试
|
||||
|
||||
## 4.3 参考强度公式
|
||||
|
||||
建议基线公式:
|
||||
|
||||
```ts
|
||||
referenceStrength(level) =
|
||||
100 + 16 * (level - 1) + 6 * (level - 1) * (level - 1);
|
||||
```
|
||||
|
||||
并同步产出:
|
||||
|
||||
```ts
|
||||
baseHp(level);
|
||||
baseMana(level);
|
||||
baselineDamageScale(level);
|
||||
```
|
||||
|
||||
重要约束:
|
||||
|
||||
1. `referenceStrength` 是同级比较标尺。
|
||||
2. style 只允许在同一档预算内重分布,不允许抬高总强度。
|
||||
3. `elite / boss` 不允许用同级隐藏倍率偷强度,必须通过更高等级体现。
|
||||
|
||||
## 4.4 现有静态数值如何迁移
|
||||
|
||||
当前 `src/data/hostileNpcPresets.ts` 里的:
|
||||
|
||||
- `baseStats.hp`
|
||||
- `baseStats.maxHp`
|
||||
- `speed`
|
||||
- `attackRange`
|
||||
|
||||
不建议继续全部视为最终强度。
|
||||
|
||||
迁移原则:
|
||||
|
||||
1. `attackRange / speed` 继续保留为战斗风格参数。
|
||||
2. `hp / maxHp` 改为“风格形状参考”,最终值由 `等级基准 + 风格分布` 决定。
|
||||
3. 现有 preset 的高血量、高机动、高压制,只用于决定“同级下怎么分布”,不改变同级总参考强度。
|
||||
|
||||
---
|
||||
|
||||
## 5. 经验发放规则
|
||||
|
||||
## 5.1 任务经验
|
||||
|
||||
任务经验只在 `turn_in` 时发放。
|
||||
|
||||
建议公式:
|
||||
|
||||
```ts
|
||||
baseQuestXp(targetLevel) = xpToNextLevel(targetLevel) * 0.45;
|
||||
|
||||
questXp =
|
||||
baseQuestXp(targetLevel) *
|
||||
stepCountMultiplier *
|
||||
narrativeTypeMultiplier *
|
||||
urgencyMultiplier;
|
||||
```
|
||||
|
||||
建议倍率:
|
||||
|
||||
| 条件 | 倍率 |
|
||||
| ------------------------------------------ | ------ |
|
||||
| `steps = 1` | `0.85` |
|
||||
| `steps = 2` | `1.0` |
|
||||
| `steps >= 3` | `1.12` |
|
||||
| `investigation / retrieval / relationship` | `1.0` |
|
||||
| `trial / bounty` | `1.08` |
|
||||
| `urgency = high` | `1.05` |
|
||||
|
||||
最终规则:
|
||||
|
||||
1. 结果四舍五入到 `5` 的倍数。
|
||||
2. 章节主任务优先从本章 `questXpBudget` 出数。
|
||||
3. 普通 NPC 支线如果不绑定章节,则按 `targetLevel` 单独计算。
|
||||
|
||||
## 5.2 击败敌对 NPC 经验
|
||||
|
||||
建议公式:
|
||||
|
||||
```ts
|
||||
baseKillXp(targetLevel) = xpToNextLevel(targetLevel) * 0.08;
|
||||
|
||||
killXp =
|
||||
baseKillXp(targetLevel) *
|
||||
stageMultiplier *
|
||||
levelDeltaMultiplier *
|
||||
repeatPenalty;
|
||||
```
|
||||
|
||||
建议倍率:
|
||||
|
||||
| 条件 | 倍率 |
|
||||
| -------------------------------- | ----------------- |
|
||||
| `opening` | `0.9` |
|
||||
| `expansion` | `1.0` |
|
||||
| `turning_point` | `1.05` |
|
||||
| `climax` | `1.15` |
|
||||
| 玩家高于目标 `2` 级 | `0.7` |
|
||||
| 玩家高于目标 `4` 级 | `0.3` |
|
||||
| 玩家低于目标 `2` 级 | `1.15` |
|
||||
| 同章同类敌对实体超过预计击杀数后 | `0.5 -> 0.2 -> 0` |
|
||||
|
||||
解释:
|
||||
|
||||
1. 同章重复刷怪必须衰减。
|
||||
2. 击杀经验要响应等级差,避免低章 farming。
|
||||
3. 高潮压轴敌人可以给更多经验,但仍受章节预算约束。
|
||||
|
||||
## 5.3 经验发放顺序
|
||||
|
||||
推荐统一顺序:
|
||||
|
||||
```text
|
||||
规则动作成功
|
||||
-> 生成经验 grant
|
||||
-> 写入 playerProgression.totalXp / currentLevelXp
|
||||
-> 处理升级
|
||||
-> 回写章节 ledger
|
||||
-> 生成前端提示
|
||||
```
|
||||
|
||||
不要把经验结算拆在前端多个回调里各自加一次。
|
||||
|
||||
---
|
||||
|
||||
## 6. 章节经验速度评估
|
||||
|
||||
## 6.1 章节顺序来源
|
||||
|
||||
章节索引 `chapterIndex` 建议按下面顺序解析:
|
||||
|
||||
1. 有 `campaign pack` 时,优先用 campaign 正式顺序
|
||||
2. 否则有 `sceneChapterBlueprints` 时,用蓝图顺序
|
||||
3. 再否则,对 `landmarks` 从营地出发做最短路径排序
|
||||
4. 若存在并列,则回退到稳定的 landmark 原始顺序
|
||||
|
||||
这样才能给每章一个稳定的“这是第几章”。
|
||||
|
||||
## 6.2 目标等级带
|
||||
|
||||
建议先计算“伪等级进度”,再换算成经验预算:
|
||||
|
||||
```ts
|
||||
chapterBoundaryPseudoLevel(i) =
|
||||
1 + curve(i / totalChapters) * (terminalStoryLevel - 1);
|
||||
```
|
||||
|
||||
建议 `curve` 用轻微前快后稳的函数:
|
||||
|
||||
```ts
|
||||
curve(progress) = Math.pow(progress, 0.92);
|
||||
```
|
||||
|
||||
随后:
|
||||
|
||||
```ts
|
||||
entryPseudoLevel = chapterBoundaryPseudoLevel(chapterIndex - 1);
|
||||
exitPseudoLevel = chapterBoundaryPseudoLevel(chapterIndex);
|
||||
chapterXpBudget =
|
||||
xpForPseudoLevel(exitPseudoLevel) - xpForPseudoLevel(entryPseudoLevel);
|
||||
```
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
1. 每一章都有明确的入章/出章目标
|
||||
2. 等级增幅随章节自然变慢
|
||||
3. 经验速度评估可以直接落成表格
|
||||
|
||||
## 6.3 章节经验份额
|
||||
|
||||
默认建议:
|
||||
|
||||
| 章节类型 | 任务经验占比 | 击杀经验占比 |
|
||||
| --------------- | ------------ | ------------ |
|
||||
| 调查/关系型章节 | `75%` | `25%` |
|
||||
| 平衡型章节 | `65%` | `35%` |
|
||||
| 战斗/试炼型章节 | `55%` | `45%` |
|
||||
|
||||
章节类型判定可由下面几项共同决定:
|
||||
|
||||
1. `SceneChapterBlueprint.acts` 数量
|
||||
2. 当前章节 hostile NPC 数量
|
||||
3. 当前章节任务 step 中战斗目标占比
|
||||
5. linked thread 是否为主线高压线程
|
||||
|
||||
## 6.4 实际速度评估规则
|
||||
|
||||
每章结束后,至少计算下面三个值:
|
||||
|
||||
1. `actualTotalXp / plannedTotalXp`
|
||||
2. `actualHostileXp / plannedHostileXp`
|
||||
3. `levelAtExit - plannedExitLevel`
|
||||
|
||||
建议判定:
|
||||
|
||||
| 偏差 | 判断 |
|
||||
| ----------- | -------- |
|
||||
| `±10%` 内 | 正常 |
|
||||
| `10% ~ 20%` | 需观察 |
|
||||
| `> 20%` | 必须调参 |
|
||||
|
||||
这就是“评估每一章获得经验速度”的正式口径,不再用主观感觉判断。
|
||||
|
||||
---
|
||||
|
||||
## 7. NPC 自动定级规则
|
||||
|
||||
## 7.1 默认角色分类
|
||||
|
||||
建议默认按当前幕和敌我属性推导 `progressionRole`:
|
||||
|
||||
1. 当前幕 `primaryNpcId`
|
||||
|
||||
- 若 hostile:`hostile_elite` 或 `hostile_boss`
|
||||
- 若非 hostile:`guide` 或 `rival`
|
||||
|
||||
2. 非主角色 hostile NPC
|
||||
|
||||
- `hostile_standard`
|
||||
|
||||
3. 非主角色友方 NPC
|
||||
- `support` 或 `ambient`
|
||||
|
||||
如需修正,再允许章节蓝图加可选 override,但不要求创作者每次手填。
|
||||
|
||||
## 7.2 等级锚点
|
||||
|
||||
每章先得到:
|
||||
|
||||
1. `entryLevel`
|
||||
2. `exitLevel`
|
||||
|
||||
然后按当前阶段得到阶段锚点:
|
||||
|
||||
| 阶段 | 目标锚点 |
|
||||
| --------------- | ----------------------------- |
|
||||
| `opening` | 接近 `entryLevel` |
|
||||
| `expansion` | `entryLevel ~ exitLevel` 中段 |
|
||||
| `turning_point` | 接近 `exitLevel` |
|
||||
| `climax` | `exitLevel` |
|
||||
| `aftermath` | `exitLevel - 1` 或持平 |
|
||||
|
||||
## 7.3 最终定级
|
||||
|
||||
建议公式:
|
||||
|
||||
```ts
|
||||
baseStageLevel = interpolate(entryLevel, exitLevel, stageProgress);
|
||||
|
||||
npcLevel = round(baseStageLevel) + roleOffset(progressionRole);
|
||||
```
|
||||
|
||||
建议 offset:
|
||||
|
||||
| role | offset |
|
||||
| ------------------ | -------- |
|
||||
| `ambient` | `-1` |
|
||||
| `support` | `0` |
|
||||
| `guide` | `0` |
|
||||
| `rival` | `0 ~ +1` |
|
||||
| `hostile_standard` | `0` |
|
||||
| `hostile_elite` | `+1` |
|
||||
| `hostile_boss` | `+2` |
|
||||
|
||||
约束:
|
||||
|
||||
1. 统一 clamp 到 `1 ~ terminalStoryLevel + 2`
|
||||
2. 不允许出现“第 3 章普通怪高于第 6 章精英”的跨章倒挂
|
||||
3. `hostile_boss` 如果需要更强,必须给更高等级,不准同级偷倍数
|
||||
|
||||
## 7.4 同级不同风格
|
||||
|
||||
NPC 等级确定后,再把 `referenceStrength` 套到具体风格:
|
||||
|
||||
1. 重装型:
|
||||
|
||||
- 生命占比更高
|
||||
- 爆发占比更低
|
||||
|
||||
2. 迅捷型:
|
||||
|
||||
- 生命占比更低
|
||||
- 出手与压制占比更高
|
||||
|
||||
3. 控场型:
|
||||
- 法力/控制预算更高
|
||||
|
||||
但这一步只能做“分布调整”,不能改变同级总参考强度。
|
||||
|
||||
---
|
||||
|
||||
## 8. 与当前仓库的接入点
|
||||
|
||||
## 8.1 第一批必须改的类型
|
||||
|
||||
1. `src/types/game.ts`
|
||||
|
||||
- 新增 `playerProgression`
|
||||
|
||||
2. `src/types/story.ts`
|
||||
|
||||
- `QuestReward.experience`
|
||||
|
||||
3. `src/types/scene.ts`
|
||||
|
||||
- `SceneNpc.levelProfile`
|
||||
- `SceneHostileNpc.levelProfile`
|
||||
- `SceneHostileNpc.experienceReward`
|
||||
|
||||
4. `packages/shared/src/contracts/story.ts`
|
||||
- 如果需要让前后端合同正式共享等级展示字段,在这里补最小契约
|
||||
|
||||
## 8.2 第一批必须改的后端模块
|
||||
|
||||
1. `server-node/src/modules/quest/questStoryActionService.ts`
|
||||
|
||||
- `resolveQuestTurnInAction(...)` 里追加任务经验发放
|
||||
|
||||
2. `server-node/src/modules/quest/questRuntimeSignalService.ts`
|
||||
|
||||
- 保持 quest signal 职责
|
||||
- 不直接负责经验裁决,只把可用信号交给 progression 模块
|
||||
|
||||
3. `server-node/src/modules/combat/**`
|
||||
|
||||
- 在胜利结算后发 hostile NPC 经验
|
||||
|
||||
4. `server-node/src/modules/story/**`
|
||||
|
||||
- 在切章、进场、恢复场景时接入章节成长计划与 ledger
|
||||
|
||||
5. 新增 `server-node/src/modules/progression/**`
|
||||
- 成为等级、经验、章节定级唯一真相源
|
||||
|
||||
## 8.3 第一批不建议重写的部分
|
||||
|
||||
这轮不建议一开始就重写:
|
||||
|
||||
1. 整套前端战斗 UI
|
||||
2. 整套属性系统
|
||||
3. Quest UI 大面板结构
|
||||
4. 所有 hostile preset 原始配置文件
|
||||
|
||||
更稳的做法是:
|
||||
|
||||
1. 先让后端算出等级与经验
|
||||
2. 再把结果投影到现有运行时字段
|
||||
3. 最后再逐步清理旧静态强度残留
|
||||
|
||||
---
|
||||
|
||||
## 9. 迁移策略
|
||||
|
||||
## 9.1 旧存档兼容
|
||||
|
||||
旧存档没有 `playerProgression` 时:
|
||||
|
||||
1. 默认初始化为 `Lv.1`
|
||||
2. `totalXp = 0`
|
||||
3. `currentLevelXp = 0`
|
||||
4. `xpToNextLevel = benchmark[1].xpToNextLevel`
|
||||
|
||||
如果后续希望更平滑,可在第二轮增加“按当前章节进度反推起始等级”的迁移脚本,但首版先不要让迁移复杂化。
|
||||
|
||||
## 9.2 旧 hostile preset 兼容
|
||||
|
||||
旧 preset 里的 `hp/maxHp` 首版处理建议:
|
||||
|
||||
1. 先保留原字段作为 style hint
|
||||
2. 运行时用 level benchmark 覆盖最终 `hp/maxHp`
|
||||
3. 保证当前素材和行为标签不需要重做
|
||||
|
||||
## 9.3 旧任务兼容
|
||||
|
||||
旧任务没有 `reward.experience` 时:
|
||||
|
||||
1. 默认按 `0` 处理
|
||||
2. 仅新生成或重新编译的任务带经验
|
||||
3. 章节主任务优先切到新编译链
|
||||
|
||||
---
|
||||
|
||||
## 10. 开发顺序
|
||||
|
||||
## 阶段 A:先把等级状态立住
|
||||
|
||||
先做:
|
||||
|
||||
1. `PlayerProgressionState`
|
||||
2. `LevelBenchmark[]`
|
||||
3. 经验加点与升级服务
|
||||
|
||||
验收:
|
||||
|
||||
1. 后端能正确加经验与升级
|
||||
2. 前端能稳定展示 `Lv. X / 经验条`
|
||||
|
||||
## 阶段 B:接任务经验
|
||||
|
||||
先做:
|
||||
|
||||
1. `QuestReward.experience`
|
||||
2. `quest turn-in` 经验发放
|
||||
3. 任务结果文案里补 `经验 +N`
|
||||
|
||||
验收:
|
||||
|
||||
1. 交付任务后能加经验
|
||||
2. 升级时能正确连跳
|
||||
|
||||
## 阶段 C:接章节预算与 NPC 自动定级
|
||||
|
||||
先做:
|
||||
|
||||
1. `ChapterProgressionPlan`
|
||||
2. `npcLevelResolver`
|
||||
3. runtime hostile NPC 经验值生成
|
||||
|
||||
验收:
|
||||
|
||||
1. 进入不同章节时 NPC 等级自动变化
|
||||
2. 同级不同风格但参考强度一致
|
||||
|
||||
## 阶段 D:接击败敌对 NPC 经验与章节 ledger
|
||||
|
||||
先做:
|
||||
|
||||
1. hostile defeat 经验
|
||||
2. `ChapterExperienceLedger`
|
||||
3. 章节偏差评估输出
|
||||
|
||||
验收:
|
||||
|
||||
1. 每章都能看到计划/实际经验偏差
|
||||
2. 重复刷同章敌对 NPC 不会破坏曲线
|
||||
|
||||
---
|
||||
|
||||
## 11. 验收标准
|
||||
|
||||
做到下面这些,才算这次等级系统设计真正落地:
|
||||
|
||||
1. 玩家正式拥有 `等级 + 经验 + 升级` 主链。
|
||||
2. 经验来源只通过后端发放,前端不本地算经验。
|
||||
3. 同等级实体共享同一档 `参考强度`。
|
||||
4. 每章都能生成 `入章等级 / 出章等级 / 经验预算`。
|
||||
5. 每章的 NPC 都能按章节自动定级。
|
||||
6. 完成任务、击败敌对 NPC 都能稳定获得经验。
|
||||
7. 章节结束后能评估“这一章经验速度是否正常”。
|
||||
8. 现有任务、章节、属性和 hostile NPC 主链不被推翻,只是在其上新增成长预算层。
|
||||
|
||||
---
|
||||
|
||||
## 12. 最后结论
|
||||
|
||||
这次等级系统设计的重点,不是简单在 UI 上加一个 `Lv.1`,而是把当前仓库里已经存在的:
|
||||
|
||||
1. 章节闭环
|
||||
2. 任务结算
|
||||
3. 敌对 NPC 胜利事件
|
||||
4. 统一属性与 hostile preset
|
||||
|
||||
收束到一条新的成长主链:
|
||||
|
||||
**章节先给出目标等级与经验速度,系统再按这套速度自动设置 NPC 等级,并把任务交付与击败敌对 NPC 统一变成可控的经验入口。**
|
||||
|
||||
这样之后,等级不再只是一个展示数字,而会真正变成:
|
||||
|
||||
- 玩家成长速度的刻度
|
||||
- 同级参考强度的刻度
|
||||
- 章节节奏是否合理的刻度
|
||||
- 不同章节 NPC 强度自动落位的刻度
|
||||
@@ -0,0 +1,26 @@
|
||||
# 移动端创作页新建作品紧凑布局设计
|
||||
|
||||
## 目标
|
||||
|
||||
移动端创作页顶部的新建作品模块只承担快速进入创作模板的作用,不承担规则解释和长说明承载。模块在首屏中最多占用约 1/3 高度,把更多空间留给作品列表和筛选操作。
|
||||
|
||||
## 落地范围
|
||||
|
||||
- 入口组件:`src/components/custom-world-home/CustomWorldCreationStartCard.tsx`
|
||||
- 外层页面:`src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- 模板元数据继续复用 `PLATFORM_CREATION_TYPES`,不新增前端业务逻辑。
|
||||
|
||||
## 移动端布局规则
|
||||
|
||||
1. 顶部标题行压缩成单行:左侧标题,右侧仅保留简短状态,不再显示说明段落。
|
||||
2. 模板入口在手机端使用横向滚动胶囊卡片,每个卡片保持单行动作感,不堆叠成长列表。
|
||||
3. 卡片高度控制在约 4rem 内,标题与状态信息并排组织,避免大留白。
|
||||
4. 模块本体使用 `max-height: 33svh` 作为硬约束,内容超出时优先在模板入口行内横向滚动,不撑高页面。
|
||||
5. 桌面端保持网格入口,但同步收紧内边距和卡片留白,避免移动端与桌面端表现割裂。
|
||||
|
||||
## 文案约束
|
||||
|
||||
- UI 不新增规则说明类文案。
|
||||
- 原有“直接选择游戏创作模板,立刻进入对应的共创工作台。”说明在移动端隐藏,桌面端保留为辅助说明。
|
||||
- 锁定、可创建、正在开启等状态继续来自既有模板元数据或忙碌状态。
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
# 高好感角色聊天内委托触发与领取流程设计
|
||||
|
||||
更新时间:`2026-04-19`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这次迭代解决的是一个很具体的体验断层:
|
||||
|
||||
1. 当前角色委托主要还是从 NPC 互动菜单里直接出现,缺少“先聊上 1-2 轮,再顺着上下文自然托付任务”的过渡。
|
||||
2. 聊天态虽然已经有多轮对话、自定义输入和选项建议,但没有“临时任务 offer”这一层中间状态。
|
||||
3. 现有任务详情面板已经能看任务、领奖励,但还不能承接“任务尚未正式入日志,只是对方刚提出委托”的场景。
|
||||
|
||||
目标不是新造一套聊天任务系统,而是把现有:
|
||||
|
||||
- `npc_chat` 多轮聊天流
|
||||
- `generateQuestForNpcEncounter(...)` 任务生成链
|
||||
- `QuestLogEntry` 任务日志结构
|
||||
- `AdventurePanelOverlays` 任务详情面板
|
||||
|
||||
串成一条更自然的“聊天内委托”链路。
|
||||
|
||||
一句话目标:
|
||||
|
||||
**当玩家与好感度大于 0 的角色聊天时,先寒暄 1-2 轮,再由角色顺着上下文提出委托;玩家可查看、换任务、放弃任务,确认领取后任务才正式进入日志,并恢复自由聊天。**
|
||||
|
||||
## 1. 这次不做什么
|
||||
|
||||
为了避免系统边界漂移,这次明确不做下面这些事:
|
||||
|
||||
1. 不重写任务生成器。
|
||||
- “任务”和“更换任务”都必须复用现有 `generateQuestForNpcEncounter(...)` 链路。
|
||||
- 也就是说,仍然走现在的 `evaluateQuestOpportunity -> AI / fallback quest intent -> compileQuestIntentToQuest`。
|
||||
|
||||
2. 不把聊天态任务 offer 直接视为已接任务。
|
||||
- 对方刚把委托提出来时,它还只是 `pending offer`,不应立即写进 `gameState.quests`。
|
||||
- 只有玩家点击“领取任务”后,才正式调用现有任务接取写入逻辑。
|
||||
|
||||
3. 不在 UI 默认堆说明文字。
|
||||
- 聊天态只切换三项操作:
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
- 不额外在主界面堆功能说明。
|
||||
|
||||
4. 不改成必须走服务端聊天。
|
||||
- 当前多轮 NPC 聊天仍沿用前端本地的 `handleNpcChatTurn(...)` 流程。
|
||||
- 这次只是在聊天流程里插入任务 offer 状态。
|
||||
|
||||
## 2. 核心流程
|
||||
|
||||
## 2.1 触发条件
|
||||
|
||||
只有同时满足下面条件时,聊天中才允许提出委托:
|
||||
|
||||
1. 当前遭遇是角色型 NPC。
|
||||
- `encounter.characterId` 存在。
|
||||
|
||||
2. 当前好感度大于 `0`。
|
||||
|
||||
3. 当前角色没有未结清任务。
|
||||
- 复用 `getQuestForIssuer(...)` 判断。
|
||||
|
||||
4. 当前聊天里还没有待处理的任务 offer。
|
||||
|
||||
5. 已经完成前置寒暄轮次。
|
||||
- 默认要求先完成 `1-2` 轮自然聊天。
|
||||
- 建议规则:
|
||||
- `affinity >= 30` 时,完成 `1` 轮后即可进入委托时机。
|
||||
- `0 < affinity < 30` 时,完成 `2` 轮后再进入委托时机。
|
||||
|
||||
## 2.2 聊天轮次切换
|
||||
|
||||
正常聊天时:
|
||||
|
||||
- 保持现有三条 `npc_chat` 建议选项
|
||||
- 保持自定义输入可用
|
||||
|
||||
当触发委托时:
|
||||
|
||||
1. 先正常生成本轮 NPC 回复。
|
||||
2. 随后调用现有 `generateQuestForNpcEncounter(...)` 生成一份 `pending quest offer`。
|
||||
3. 在当前轮次追加一段 NPC 委托台词。
|
||||
4. 把当前轮次选项替换成:
|
||||
- 第一项:`查看任务`
|
||||
- 第二项:`更换任务`
|
||||
- 第三项:`放弃任务`
|
||||
5. 临时隐藏自定义输入。
|
||||
|
||||
这意味着聊天态此时进入一个短暂的“任务处理态”,直到玩家:
|
||||
|
||||
- 查看并领取
|
||||
- 更换
|
||||
- 放弃
|
||||
|
||||
其中任一分支结算完成后,再恢复自由聊天。
|
||||
|
||||
## 2.3 查看任务
|
||||
|
||||
点击 `查看任务` 时:
|
||||
|
||||
1. 不立即写入任务日志。
|
||||
2. 直接复用现有任务详情弹层展示 `pending quest offer` 的详情。
|
||||
3. 任务详情面板在这类任务上新增主按钮:
|
||||
- `领取任务`
|
||||
|
||||
这一步的关键是:
|
||||
|
||||
**查看任务只是看,不等于接。**
|
||||
|
||||
## 2.4 领取任务
|
||||
|
||||
点击 `领取任务` 时:
|
||||
|
||||
1. 使用当前 `pending quest offer` 的 `QuestLogEntry`,调用现有任务接取写入逻辑,把任务正式写入 `gameState.quests`。
|
||||
2. 同时把这轮动作写回聊天:
|
||||
- 追加玩家一句明确接受委托的话。
|
||||
- 可追加一条简短 NPC 确认回应,或直接用现有结果文案转成对话语义。
|
||||
3. 更新 `storyHistory`,确保后续聊天上下文知道“这份委托已经接下”。
|
||||
4. 清空 `pending quest offer`。
|
||||
5. 恢复正常 `npc_chat` 建议选项与自定义输入。
|
||||
|
||||
## 2.5 更换任务
|
||||
|
||||
点击 `更换任务` 时:
|
||||
|
||||
1. 必须再次调用现有 `generateQuestForNpcEncounter(...)`。
|
||||
2. 旧的 `pending quest offer` 被新的覆盖。
|
||||
3. 当前聊天追加一条“对方换了个委托”的回应。
|
||||
4. 仍然维持任务处理态:
|
||||
- 继续显示
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
- 自定义输入仍隐藏
|
||||
|
||||
这里的关键约束是:
|
||||
|
||||
**更换任务不是本地改标题或改描述,而是重新走现有任务生成链。**
|
||||
|
||||
## 2.6 放弃任务
|
||||
|
||||
点击 `放弃任务` 时:
|
||||
|
||||
1. 直接丢弃当前 `pending quest offer`。
|
||||
2. 在对话里补一条“玩家暂时不接”的回应。
|
||||
3. 恢复自由聊天:
|
||||
- 再次显示正常 `npc_chat` 建议
|
||||
- 恢复自定义输入
|
||||
|
||||
放弃这里只作用于“待领取委托”,不会影响已经入日志的正式任务。
|
||||
|
||||
## 3. 数据与状态设计
|
||||
|
||||
## 3.1 聊天态新增待领取任务状态
|
||||
|
||||
建议把这次临时状态挂在 `StoryNpcChatState` 上,而不是直接写入 `GameState.quests`。
|
||||
|
||||
```ts
|
||||
interface StoryNpcQuestOfferState {
|
||||
quest: QuestLogEntry;
|
||||
}
|
||||
|
||||
interface StoryNpcChatState {
|
||||
npcId: string;
|
||||
npcName: string;
|
||||
turnCount: number;
|
||||
customInputPlaceholder?: string;
|
||||
pendingQuestOffer?: StoryNpcQuestOfferState | null;
|
||||
}
|
||||
```
|
||||
|
||||
这样有 3 个好处:
|
||||
|
||||
1. 任务 offer 只属于当前聊天上下文,不污染正式任务日志。
|
||||
2. AdventurePanel 可以直接从 `currentStory.npcChatState` 判断是否进入任务处理态。
|
||||
3. 任务详情面板可以直接读取这份 `QuestLogEntry` 展示,而不用再造一套展示结构。
|
||||
|
||||
## 3.2 任务处理态的选项表达
|
||||
|
||||
建议不要把“查看 / 更换 / 放弃”接进服务端 runtime action。
|
||||
|
||||
原因是:
|
||||
|
||||
1. `查看任务` 只是 UI 行为,不需要服务端结算。
|
||||
2. `更换任务` 和 `放弃任务` 都是当前聊天态内部状态流转。
|
||||
3. 这三项更适合作为本地聊天态专用选项,由 `AdventurePanel + npcEncounterActions` 协同处理。
|
||||
|
||||
建议做成 3 个本地专用 `StoryOption`:
|
||||
|
||||
```ts
|
||||
{
|
||||
functionId: 'npc_chat_quest_offer_view',
|
||||
actionText: '查看任务',
|
||||
runtimePayload: { npcChatQuestOfferAction: 'view' }
|
||||
}
|
||||
```
|
||||
|
||||
其余两个同理:
|
||||
|
||||
- `replace`
|
||||
- `abandon`
|
||||
|
||||
## 3.3 接取后的正式写入
|
||||
|
||||
正式领取后才进入任务日志:
|
||||
|
||||
```ts
|
||||
nextState = {
|
||||
...state,
|
||||
quests: acceptQuest(state.quests, pendingQuest.quest),
|
||||
runtimeStats: incrementGameRuntimeStats(state.runtimeStats, {
|
||||
questsAccepted: 1,
|
||||
}),
|
||||
}
|
||||
```
|
||||
|
||||
也就是说:
|
||||
|
||||
- `pending offer` 不计入 `questsAccepted`
|
||||
- 真正点击 `领取任务` 才计数
|
||||
|
||||
## 4. UI 落点
|
||||
|
||||
## 4.1 聊天面板
|
||||
|
||||
`AdventurePanel` 中增加一个判断:
|
||||
|
||||
1. `currentStory.npcChatState?.pendingQuestOffer` 存在时:
|
||||
- 只显示三项任务处理选项
|
||||
- 隐藏自定义输入
|
||||
|
||||
2. 不存在时:
|
||||
- 保持现有聊天输入与 `npc_chat` 建议
|
||||
|
||||
## 4.2 任务详情弹层
|
||||
|
||||
`AdventurePanelOverlays` 里的任务详情弹层继续复用,但要区分两种任务来源:
|
||||
|
||||
1. 已在任务日志中的正式任务
|
||||
- 保持现有逻辑
|
||||
- 完成后仍显示 `领取奖励`
|
||||
|
||||
2. 聊天里的 `pending quest offer`
|
||||
- 底部显示 `领取任务`
|
||||
- 不显示 `领取奖励`
|
||||
|
||||
点击 `领取任务` 后:
|
||||
|
||||
- 关闭详情弹层
|
||||
- 回到聊天界面
|
||||
- 当前聊天追加“我愿意接下”这一步
|
||||
|
||||
## 5. 代码改动建议
|
||||
|
||||
建议落地在这些文件:
|
||||
|
||||
1. `src/types/story.ts`
|
||||
- 扩展 `StoryNpcChatState`
|
||||
|
||||
2. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 增加聊天内任务 offer 触发判断
|
||||
- 接入 `generateQuestForNpcEncounter(...)`
|
||||
- 增加
|
||||
- 更换任务
|
||||
- 放弃任务
|
||||
- 领取任务
|
||||
对应的本地状态流转
|
||||
|
||||
3. `src/hooks/story/useStoryInteractionCoordinator.ts`
|
||||
- 向上暴露聊天内任务 offer 的操作方法
|
||||
|
||||
4. `src/hooks/useStoryGeneration.ts`
|
||||
- 把聊天内任务 offer UI 能力透传给面板
|
||||
|
||||
5. `src/components/AdventurePanel.tsx`
|
||||
- 聊天态隐藏 / 恢复输入
|
||||
- 拦截 `查看任务 / 更换任务 / 放弃任务`
|
||||
- 让 pending quest 也能进入任务详情弹层
|
||||
|
||||
6. `src/components/adventure-panel/AdventurePanelOverlays.tsx`
|
||||
- 为 pending quest 增加 `领取任务` 按钮
|
||||
|
||||
7. `src/components/AdventurePanel.test.tsx`
|
||||
- 补聊天态输入隐藏测试
|
||||
|
||||
8. `src/hooks/story/npcEncounterActions.test.ts`
|
||||
- 补任务 offer 触发 / 更换 / 接取测试
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
做到以下几点,才算这次需求成立:
|
||||
|
||||
1. 与好感度大于 `0` 的角色聊天时,不会一上来立刻塞任务,前 `1-2` 轮先正常寒暄。
|
||||
2. 达到委托时机后,系统会调用现有 `generateQuestForNpcEncounter(...)` 生成一份待领取任务。
|
||||
3. 当前聊天轮次会出现一段明确的委托台词。
|
||||
4. 这一轮聊天选项会切成:
|
||||
- `查看任务`
|
||||
- `更换任务`
|
||||
- `放弃任务`
|
||||
5. 任务处理态下,自定义输入会被临时隐藏。
|
||||
6. 点击 `查看任务` 会弹出现有任务详情面板。
|
||||
7. 点击 `领取任务` 后,任务才正式进入任务日志,并在对话里体现“玩家愿意接下”。
|
||||
8. 领取完成后,聊天会恢复正常输入与自由继续对话。
|
||||
9. 点击 `更换任务` 时,必须重新调用现有任务生成链,而不是本地改文案。
|
||||
|
||||
## 7. 一句话收束
|
||||
|
||||
这次要做的,不是“让聊天里多一个任务按钮”,而是把:
|
||||
|
||||
- 高好感聊天
|
||||
- 上下文化任务生成
|
||||
- 临时任务 offer
|
||||
- 任务详情查看
|
||||
- 正式领取后回流聊天
|
||||
|
||||
整合成一个更自然的叙事交接过程。
|
||||
@@ -0,0 +1,64 @@
|
||||
# 平台入口分类与创作 Tab 强化设计
|
||||
|
||||
## 1. 目标
|
||||
|
||||
在不新建平台入口系统的前提下,直接扩展现有 `RpgEntryHomeView` 主 Tab:
|
||||
|
||||
- 新增“分类” Tab,用作品标签聚合所有公开发布作品。
|
||||
- 强化“创作” Tab 的导航视觉权重,让它在底部导航中居中并更醒目。
|
||||
- 登录态底部导航顺序为:首页、分类、创作、存档、我的。
|
||||
- 未登录态底部导航只保留:首页、创作、分类,其中创作保持居中。
|
||||
|
||||
## 2. 数据边界
|
||||
|
||||
本次只做前端展示重排,不新增后端接口:
|
||||
|
||||
- 分类数据来源使用现有 `latestEntries` 与 `featuredEntries` 的公开作品列表。
|
||||
- 标签来源沿用 `buildPlatformWorldTags(entry)`,公开作品会映射为题材、角色数、地标数。
|
||||
- 同一公开作品若同时出现在精选与最新中,按 `ownerUserId + profileId` 去重。
|
||||
- 点击分类作品继续走现有 `onOpenGalleryDetail`,不改变详情页和登录拦截逻辑。
|
||||
|
||||
## 3. 交互规则
|
||||
|
||||
### 3.1 登录态
|
||||
|
||||
底部导航展示 5 个入口:
|
||||
|
||||
1. 首页
|
||||
2. 分类
|
||||
3. 创作
|
||||
4. 存档
|
||||
5. 我的
|
||||
|
||||
创作入口位于第三位,视觉上使用更大的图标壳、轻微上浮、渐变高亮和阴影,保证它是主行动入口。
|
||||
|
||||
### 3.2 未登录态
|
||||
|
||||
底部导航展示 3 个入口:
|
||||
|
||||
1. 首页
|
||||
2. 创作
|
||||
3. 分类
|
||||
|
||||
不展示“存档”和“我的”,避免未登录用户在底部导航看到必须登录后才有价值的入口。创作入口位于第二位,保持几何居中。
|
||||
|
||||
### 3.3 桌面端
|
||||
|
||||
桌面侧栏同步增加“分类”,但保持纵向导航,不强行做居中布局。创作入口仍使用强调样式。
|
||||
|
||||
## 4. 分类页布局
|
||||
|
||||
分类页为独立 Tab 面板,不在首页下方展开:
|
||||
|
||||
- 顶部展示标签胶囊,默认选中作品数量最多的标签。
|
||||
- 标签切换后,下方网格展示该标签下所有公开作品。
|
||||
- 无公开作品时展示现有空状态组件。
|
||||
- 分类页不写玩法规则说明类长文案,只保留必要标题、短状态文案和作品卡片。
|
||||
|
||||
## 5. 验收点
|
||||
|
||||
- 登录态移动端底部导航顺序准确,创作在 5 个 Tab 中居中。
|
||||
- 未登录态移动端底部导航只显示 3 个 Tab,创作在中间。
|
||||
- 分类 Tab 能按标签切换并展示公开作品。
|
||||
- 创作 Tab 在移动端和桌面端都比普通 Tab 更醒目。
|
||||
- 不修改 server-node,不新增后端逻辑。
|
||||
@@ -0,0 +1,229 @@
|
||||
# 平台首页公开浏览与登录弹窗拦截设计
|
||||
|
||||
更新时间:`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.2.1 登录页签落地约束
|
||||
|
||||
账号面板需要把短信验证码登录和密码登录拆成互斥页签,避免两个登录表单在同一个面板里上下堆叠。
|
||||
|
||||
- 同时开放短信与密码登录时,面板顶部展示两个居中的文字页签,当前页签使用深色字重和短下划线强调。
|
||||
- 只渲染当前页签对应的输入区;切换页签不弹出新面板,不展示二维码入口。
|
||||
- `短信登录` 页签包含手机号、验证码、获取验证码和主按钮。
|
||||
- `密码登录` 页签只包含手机号、密码、主按钮和忘记密码入口;不支持邮箱、用户名或叙世号。
|
||||
- 密码登录只是手机号验证码登录的补充方式:只有已登录并设置过密码的手机号账号才能使用,不能在密码页签创建账号。
|
||||
- `密码登录` 主按钮固定为 `登录`,不得使用 `注册/登录`。
|
||||
- 未开放某个登录方式时不展示对应页签,避免用户进入不可用表单。
|
||||
- 移动端页签保持等分点击区域,输入框与按钮宽度仍随弹窗收缩。
|
||||
|
||||
## 3.3 登录成功后的行为
|
||||
|
||||
- 手机号登录成功后,关闭弹窗
|
||||
- 当前平台页面不刷新
|
||||
- 若用户是被某个受保护动作拦截进入登录,则自动恢复该动作
|
||||
- 若用户只是主动点“登录”按钮,则关闭弹窗并停留在当前页面
|
||||
|
||||
## 3.4 关闭行为
|
||||
|
||||
- 用户主动关闭弹窗时,只关闭弹窗,不改变当前平台页面
|
||||
- 不清空首页浏览状态
|
||||
- 不自动跳转到其他 tab
|
||||
- 登录弹窗下次重新打开时必须恢复初始表单状态:回到默认登录页签、关闭重置密码面板、清空密码 / 验证码 / 图形验证码 / 提示 / 倒计时等本次草稿状态;只允许保留“最近一次成功登录手机号”的本地回填能力。
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端状态约束
|
||||
|
||||
## 4.1 AuthGate
|
||||
|
||||
`AuthGate` 需要从“未登录整页拦截器”调整为“平台级账号状态提供器”:
|
||||
|
||||
- `checking / recovering`:仍可显示加载态,避免首屏闪烁
|
||||
- `unauthenticated`:渲染平台内容,同时允许按需打开登录弹窗
|
||||
- `ready`:渲染平台内容和账号能力
|
||||
- `pending_bind_phone`:继续保留当前绑定手机号流程,不在这次入口改造里拆散
|
||||
|
||||
首屏之后的鉴权刷新补充约束:
|
||||
|
||||
- 平台内容已经渲染后,后续 access token 刷新、401 后重试、账号状态后台重算不能再把整棵平台应用卸载成 `checking / recovering` 加载页。
|
||||
- 后台鉴权重算期间需要保持当前平台页与主 Tab 状态,避免用户手动切到“创作 / 存档 / 我的”后因为鉴权事件闪屏回到首页。
|
||||
|
||||
同时需要在 context 中提供:
|
||||
|
||||
- 当前用户
|
||||
- 打开登录弹窗
|
||||
- 打开账号面板
|
||||
- `requireAuth(action)` 能力
|
||||
|
||||
`requireAuth(action)` 约束:
|
||||
|
||||
- 已登录:直接执行 `action`
|
||||
- 未登录:弹出登录弹窗,并缓存 `action`
|
||||
- 登录成功:自动执行缓存的 `action`
|
||||
|
||||
账号入口补充约束:
|
||||
|
||||
- 不再提供 `AuthGate` 层右上角固定悬浮的全局登录 / 账号信息入口
|
||||
- 登录触发统一来自页面内受保护动作、个人页、存档页等明确入口
|
||||
- 账号信息面板只通过页面内按钮打开,不在平台右上角常驻悬浮
|
||||
- 未登录移动端底部导航不展示“我的”时,平台页头必须保留一个直接可点的 `登录` 入口,避免用户只能通过受保护动作被动触发弹窗
|
||||
- 桌面端平台页头的账号胶囊在未登录时主文案必须直接显示 `登录`,不能只显示“进入账户”这类弱入口
|
||||
|
||||
## 4.2 平台首页数据加载
|
||||
|
||||
`PreGameSelectionFlow` 在未登录时只读取:
|
||||
|
||||
- 公开作品广场
|
||||
- 本地浏览历史
|
||||
|
||||
公开作品广场前端请求约束:
|
||||
|
||||
- `listCustomWorldGallery`
|
||||
- `getCustomWorldGalleryDetail`
|
||||
|
||||
这两类公开请求必须走“公开只读请求”通道:
|
||||
|
||||
- 不主动附带 `Authorization`
|
||||
- 不因本地 access token 失效去触发 `/api/auth/refresh`
|
||||
- 若当前请求本身没有携带 access token,也不允许因为返回 `401` 就额外触发 `/api/auth/refresh`
|
||||
- refresh cookie 缺失、refresh 失败、账号状态过期时,不能把首页公开作品广场一起拖成错误态
|
||||
|
||||
受保护工作区恢复补充约束:
|
||||
|
||||
- 若 URL 或 `sessionStorage` 中残留 `customWorldSessionId`、`customWorldOperationId` 等共创工作区恢复标记,未登录态下不能直接请求对应的 Agent 会话或操作接口
|
||||
- 这类“恢复共创工作区”场景要先弹出登录弹窗,登录成功后再恢复原本的工作区或操作上下文
|
||||
- 用户未登录且关闭登录弹窗时,前端保持平台页可浏览状态,不允许持续轮询受保护接口
|
||||
|
||||
未登录时不读取:
|
||||
|
||||
- 自定义世界库
|
||||
- 个人看板
|
||||
- 云端浏览历史
|
||||
- 云端运行时设置
|
||||
- 云端存档快照
|
||||
- 云端存档列表
|
||||
|
||||
未登录态的对应前台表现:
|
||||
|
||||
- “我的创作”显示空态,不显示账号接口错误
|
||||
- “个人页”显示未登录态入口,可手动打开登录弹窗
|
||||
- 音量等运行时设置继续使用本地缓存,不触发 `/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. 未登录态首页不会因个人接口失败而出现“读取个人看板失败”“读取作品库失败”之类报错。
|
||||
6. 未登录移动端首页页头存在明确 `登录` 入口,点击后打开同一个登录弹窗。
|
||||
@@ -0,0 +1,35 @@
|
||||
# 平台首页响应式布局优化设计
|
||||
|
||||
更新时间:`2026-04-24`
|
||||
|
||||
## 1. 问题结论
|
||||
|
||||
当前平台首页桌面端视觉方向成立,但移动端存在明显横向溢出:Hero 右侧按钮、底部导航末项和部分卡片会被裁切。问题根因不是数据逻辑,而是桌面式固定宽度、外层 padding 与若干卡片最小宽度在窄屏下叠加,超过了 `100vw`。
|
||||
|
||||
## 2. 本次目标
|
||||
|
||||
- 移动端优先保证首页不横向滚动、不裁切底部导航。
|
||||
- Hero 在手机宽度下改为紧凑单列,标题、按钮和标签都完整显示。
|
||||
- 桌面端降低外框视觉噪声,让主内容和 CTA 更清晰。
|
||||
- 空状态区域收敛高度,避免首屏出现大面积空白。
|
||||
|
||||
## 3. 编码落点
|
||||
|
||||
- `src/components/rpg-runtime-shell/RpgRuntimeStageRouter.tsx`
|
||||
- 平台壳移动端使用更小边距,避免根容器加宽。
|
||||
- `src/components/rpg-entry/RpgEntryHomeView.tsx`
|
||||
- 移动端根节点显式 `min-w-0` 与 `overflow-hidden`。
|
||||
- 底部导航外层不再额外制造宽度。
|
||||
- Hero/内容卡片补充 `min-w-0`,窄屏内按容器收缩。
|
||||
- `src/index.css`
|
||||
- 全局与平台壳禁止横向溢出。
|
||||
- 移动端压缩底部导航间距、字号和图标壳尺寸。
|
||||
- 移动端收敛 `platform-page-stage` 圆角与边框层级。
|
||||
- 桌面端保留卡片质感,但弱化多层外框阴影。
|
||||
|
||||
## 4. 验收标准
|
||||
|
||||
- `390px` 宽度截图中,首页内容、Hero 按钮和底部四个导航项完整可见。
|
||||
- 桌面端首页仍保持顶部栏、侧边导航、主推荐区和右侧趋势区结构。
|
||||
- 页面不新增功能说明类 UI 文案。
|
||||
- 修改中文文件后通过编码检查。
|
||||
118
docs/design/PLATFORM_UI_NON_PIXEL_REFRESH_2026-04-19.md
Normal file
118
docs/design/PLATFORM_UI_NON_PIXEL_REFRESH_2026-04-19.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# 平台层 UI 去像素化刷新设计
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 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`
|
||||
- 左上角品牌区允许使用专用像素字标组件或直接使用 `Fusion Pixel` 文本,但仅限品牌 logo,不向正文、按钮、标签扩散
|
||||
- 品牌 logo 只能复用游戏现有 `Fusion Pixel`,不允许再引入第二套像素字体文件
|
||||
|
||||
主题基准:
|
||||
|
||||
- 暗色主题:
|
||||
底色以深靛蓝、深紫黑为主,高光以亮紫、蓝青为主
|
||||
- 亮色主题:
|
||||
底色以暖白、浅粉白、浅橘白为主,强调色以高饱和粉色、橘粉色为主,局部可带少量紫色作装饰
|
||||
- 平台默认主题使用亮色主题;暗色主题保留为可切换方案,不作为当前默认展示
|
||||
|
||||
### 3.2 排版
|
||||
|
||||
- 平台层正文、按钮、说明、功能标签统一使用非像素字体
|
||||
- 左上角 `叙世 / GENARRATIVE` 品牌字标允许单独做成像素化 logo
|
||||
- `GENARRATIVE` 与 `叙世` 都优先直接使用游戏内同款 `Fusion Pixel`
|
||||
- 品牌字标默认保持正常像素字观感,禁止再叠双层粗阴影或手动加粗到影响识别
|
||||
- 品牌字标直接使用字体文件内原字形,不额外做运行时描字、轮廓拼字或伪粗体处理
|
||||
- 主标题保留明显层级,但不再做像素描边效果
|
||||
- 微型标签维持高字距英文/中文短标签,用来保留产品感和秩序感
|
||||
|
||||
### 3.3 组件约束
|
||||
|
||||
- 面板:使用玻璃卡片,不再用九宫格像素框
|
||||
- 按钮:使用圆角胶囊按钮或渐变主按钮,不再用像素按钮框
|
||||
- 图标:优先使用 `lucide-react`
|
||||
- Tab:移动端底部结构不变,但图标与底座改成非像素风;桌面端切换为左侧纵向导航轨道
|
||||
- 弹窗:沿用登录页的圆角浮层和半透明遮罩,不再使用像素弹窗边框
|
||||
- 桌面壳层:首页允许增加顶部工具栏、左侧导航轨、中央内容舞台与右侧趋势面板的组合
|
||||
- 登录页、绑定手机号、账户弹窗、平台详情、创作生成页、结果页、编辑弹窗都必须共享同一套平台主题 token,禁止再各自写一套独立旧色板
|
||||
- 创作中心、Agent 工作台、草稿详情抽屉、资产工坊、启动弹窗、生成弹窗这类二三级平台面板必须显式挂载平台主题壳层或平台 remap 容器,禁止直接在局部面板里写死旧深色 modal 底和旧输入框底色
|
||||
- 平台“我的”页中的“设置”入口必须打开真正的设置面板;账号信息、设备管理、安全状态属于设置面板中的分区,不允许再把账号信息弹层直接充当设置页
|
||||
- 设置面板必须支持平台亮色 / 暗色主题切换,并复用同一套平台 token 驱动登录页、首页、详情页与二三级面板
|
||||
- 首页移动端底部 Tab 与桌面侧边导航的图标底座、图标颜色、文字状态必须全部由平台 token 驱动;暗色主题下不得出现过浅底座和错误文字色,亮色主题下不得残留旧灰蓝 inactive 状态
|
||||
- 首页、存档页、作品详情这类平台主导航与局部 Tab 的 active fill、active shadow、icon shell fill 必须全部来自主题 token;暗色主题禁止继续复用亮色主题的粉橘高光、白色 active 底座
|
||||
- 创作链路中的吸顶返回栏、目录 Tab 条、搜索工具条也必须走平台亮暗主题 token;暗色主题禁止继续写死暖白渐变或浅粉背景作为顶部衬底
|
||||
- “我的”页账号主卡必须跟随平台亮 / 暗主题联动,不允许继续写死浅色渐变卡面与 `slate` 系按钮
|
||||
|
||||
## 4. 交互与布局约束
|
||||
|
||||
- 移动端保持原有页面布局层级、区块顺序、操作入口位置不变
|
||||
- 桌面端首页允许参考图示重组为“顶部工具栏 + 左侧纵向导航 + 主 Hero 卡 + 右侧趋势列表 + 下方内容卡组”
|
||||
- 桌面端的重组只改变视觉排布;自 `2026-04-19` 起平台主入口调整为“首页 / 创作 / 存档 / 我的”,四个入口的操作路径都必须保持清晰稳定
|
||||
- 移动端优先,底部 tab 与主卡片点击区域不能缩小
|
||||
- 不在平台 UI 面板里额外堆砌规则说明
|
||||
- 所有视觉替换必须是局部补丁,不做无必要的大规模结构重写
|
||||
|
||||
## 5. 实现约束
|
||||
|
||||
- 平台态从 `fusion-pixel-app` 中隔离,避免被全局像素字体覆盖
|
||||
- 品牌区禁止新增额外像素字体包;平台层只允许保留现有 `public/fusion-pixel.ttf` 这一份像素字体资源
|
||||
- 平台态背景不再使用 `/UI/Background_fill.png`
|
||||
- 新样式优先沉淀为平台专用 class / theme token,避免把游戏内像素 class 改坏
|
||||
- 平台默认挂载亮色主题 class,旧紫蓝方案保留为暗色主题 class
|
||||
- 亮色主题需要补齐统一的 overlay、progress track、status pill token,登录弹层与二三级功能面板禁止继续沿用旧深色遮罩与紫蓝强调残留
|
||||
- 亮色主题下平台壳层与各个 Tab 页的 page stage 必须以暖白底为主,禁止继续让高饱和深粉底或旧深色底透成页面主背景
|
||||
- 亮色主题下平台主内容区、page stage、移动端底部 Tab 容器都必须使用接近实色的暖白底,禁止继续用高透明度浅色层叠在深底上造成整体发灰
|
||||
- 平台态中仍保留旧 Tailwind 深色类的历史组件,必须通过平台 remap 容器或平台专用 class 统一收口,不能放任 `bg-[#111318]`、`bg-black/*`、`bg-white/*` 这类旧类在亮色主题下直接裸露
|
||||
- 编辑弹窗保留业务结构与表单逻辑,只替换壳层样式
|
||||
|
||||
## 6. 验收标准
|
||||
|
||||
达到以下结果才算完成:
|
||||
|
||||
1. 除左上角品牌像素字标外,平台首页、详情、登录、绑定手机号、账户弹窗、创作入口、创作结果页不再出现像素字体
|
||||
2. 平台层按钮、面板、关闭按钮、底部 tab 不再依赖像素 UI 素材
|
||||
3. 平台默认展示亮色主题,暗色主题保留为独立主题方案
|
||||
4. 平台层二三级面板、表单、状态卡、弹窗与登录体系不再残留旧金橙 / 青蓝 / 深黑混搭方案
|
||||
5. 平台层世界封面与角色预览不再使用 `pixelated` 渲染
|
||||
6. 游戏内像素 UI 保持原样,不出现误改
|
||||
7. 手机端布局保持稳定,桌面端在参考图方向下完成控制台化重组
|
||||
39
docs/design/README.md
Normal file
39
docs/design/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 系统设计
|
||||
|
||||
这一组是玩法、关系、物品、对话等系统设计文档,偏“应该怎么设计”而不是“现在哪里出问题”。
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md](./CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md):自定义世界里创作者输入与 AI 分工边界设计。
|
||||
- [CUSTOM_WORLD_CREATOR_MANUAL_AI_SYSTEM_BALANCE_DESIGN_2026-04-12.md](./CUSTOM_WORLD_CREATOR_MANUAL_AI_SYSTEM_BALANCE_DESIGN_2026-04-12.md):自定义世界创作里“手填锚点 / AI 可改初稿 / 系统托管层”的平衡设计。
|
||||
- [CUSTOM_WORLD_CREATOR_PURE_AGENT_COMPARISON_AND_CONVERSION_DESIGN_2026-04-12.md](./CUSTOM_WORLD_CREATOR_PURE_AGENT_COMPARISON_AND_CONVERSION_DESIGN_2026-04-12.md):纯 Agent 式创作工具与结构化工作台方案的优缺点对比,以及转型设计。
|
||||
- [CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md](./CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md):把自定义世界从武侠/仙侠模板依赖迁到跨题材通用设定层的优化设计。
|
||||
- [CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md](./CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md):把模板依赖逐步迁成自定义世界自有设定层,并保证不破坏当前生成流程的优化方案。
|
||||
- [MOBILE_CREATION_NEW_WORK_COMPACT_LAYOUT_2026-04-24.md](./MOBILE_CREATION_NEW_WORK_COMPACT_LAYOUT_2026-04-24.md):移动端创作页新建作品模块最多占用首屏约 1/3 高度的紧凑布局设计。
|
||||
- [PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md](./PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md):平台入口新增分类 Tab、登录态导航裁剪与创作 Tab 视觉强化设计。
|
||||
- [UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md](./UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md):统一平台风与 RPG 像素风模态窗口外壳、交互边界和迁移顺序。
|
||||
- [AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md](./AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md):运行时物品生成系统重设计。
|
||||
- [LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md](./LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md):等级成长、章节经验节奏与 NPC 自动定级设计。
|
||||
- [RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md](./RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md):专业剧情策划构建 RPG 游戏全剧情的工作流程与交付模板。
|
||||
- [EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md](./EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md):配装构筑与合成/锻造闭环设计。
|
||||
- [COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md](./COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md):角色首遇感、关系分层解锁、私聊系统设计。
|
||||
- [NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md](./NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md):高好感角色在聊天内自然提出委托,并支持查看、更换、放弃、领取的流程设计。
|
||||
- [SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md](./SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md):把每个场景收束成章节单元,并在首进场景时开启章节任务的设计稿。
|
||||
- [SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md](./SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md):对标仙剑、博德之门、黑神话,分析单场景章节的体验缺口,并给出 AI 原生补强方案。
|
||||
- [npc-conversation-situation-draft.md](./npc-conversation-situation-draft.md):NPC 对话阶段和情景注入草案。
|
||||
|
||||
## 推荐阅读
|
||||
|
||||
- 做物品、Build、锻造相关需求时,先看前两份。
|
||||
- 做 RPG 全剧情规划、主支线矩阵、角色线、场景章节与剧情交付模板时,先看新增的全剧情策划流程。
|
||||
- 做自定义世界创作工作台、创作者输入边界、AI 分工设计时,先看第一份。
|
||||
- 做“哪些内容必须让创作者手填、哪些适合 AI 先生成再改、哪些必须系统托管”这类分层设计时,优先看新增的输入平衡设计稿。
|
||||
- 做“是否应该转成纯 Agent 式创作工具、转了之后前后台各该怎么收口”这类产品方向评估时,优先看新增的纯 Agent 对比与转型设计稿。
|
||||
- 做自定义世界去模板依赖、跨题材泛化、兼容迁移设计时,优先看新增的去模板化优化设计稿。
|
||||
- 做“模板依赖如何真正变成自定义世界自有设定层”的具体迁移方案时,优先看新增的自有设定层优化方案。
|
||||
- 做角色关系、同伴互动、对话表现时,先看后两份。
|
||||
- 做“高好感聊天里如何顺着上下文自然抛出委托、并让任务在聊天内领取”的需求时,优先看新增的聊天委托流程设计稿。
|
||||
- 做剧情引擎章节化、场景闭环、章节任务接入时,优先看新增的场景章节设计稿。
|
||||
- 做“单章节体验还缺什么、该补哪种情感 / 抉择 / 试炼模块”时,优先看新增的章节对标补强设计稿。
|
||||
- 做等级成长、任务/击败敌对 NPC 发经验、章节经验速度评估、NPC 自动定级时,优先看新增的等级系统设计稿。
|
||||
- 如果要判断是否符合目标,再和 `docs/prd/` 中对应 PRD 对照阅读。
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
# RPG NPC 聊天敌对中止与聊天内 Function 选项设计(2026-04-25)
|
||||
|
||||
## 1. 目标
|
||||
|
||||
本次迭代调整运行时 NPC 聊天,让敌对角色聊天从固定五回合上限改为由模型按当前语境判定是否中止;好感度大于等于 0 的角色继续保持可持续聊天,不由模型强制结束。
|
||||
|
||||
同时,原本部分只在退出聊天后才出现的 NPC function 选项,需要进入聊天续写候选池。模型在生成聊天候选时要能看到可触发的 function 选项,并把它们改写成玩家可直接点击的动作文本。聊天中保留“换一换”能力,用于刷新下方候选。
|
||||
|
||||
## 2. 行为规则
|
||||
|
||||
1. 负好感或敌对 NPC 进入聊天后,不再设置固定 5 回合上限。
|
||||
2. 负好感或敌对 NPC 每轮回复后,模型必须判断本轮是否结束聊天。
|
||||
3. 敌对 NPC 判定时应偏向随时结束聊天并进入对峙,但必须结合玩家刚说的话、NPC 性格、当前剧情压力和对话历史。
|
||||
4. 好感度大于等于 0 且非敌对 NPC 不启用模型终止判定,玩家可一直聊天。
|
||||
5. 模型判定终止后,聊天面板不再继续提供聊天输入,只显示“继续”按钮,点击后沿用原流程继续生成冒险选项。
|
||||
6. 点击“退出聊天”不再直接收起聊天页,也不立即进入剧情推理;它会发送一条结束聊天的玩家输入,对方回复后同样只显示“继续”按钮。
|
||||
7. 正向 NPC 的退出聊天只是玩家主动收束,不代表模型强制中止,也不展示战斗/逃跑选项。
|
||||
8. 对负好感或敌对 NPC,在聊天终止后的后续流程仍沿用原敌对出口:继续推进后回到原有战斗或逃跑选择。
|
||||
9. 聊天候选中允许混入当前 NPC 可执行 function,例如交易、送礼、请求帮助、招募、接任务、交任务、开战、离开等。
|
||||
10. Function 候选进入聊天上下文时只作为可触发动作,不在 UI 中展示说明类文本。
|
||||
11. “换一换”在聊天态可用,用于在不推进对话的情况下改排/轮换当前候选;它不调用后端,不改变聊天历史。
|
||||
|
||||
## 3. 后端契约
|
||||
|
||||
`NpcChatTurnDirective` 增加:
|
||||
|
||||
1. `terminationMode`:`none | hostile_model`
|
||||
2. `isHostileChat`:当前聊天是否按敌对中止规则处理
|
||||
3. `functionOptions`:可进入聊天候选的 function 列表,包含 `functionId`、`actionText`、`detailText`、`action`
|
||||
|
||||
`NpcChatTurnCompletionDirective` 增加:
|
||||
|
||||
1. `forceExit`:本轮回复后是否关闭聊天输入
|
||||
2. `closingMode`:保留 `free | foreshadow_close`
|
||||
3. `terminationReason`:`hostile_breakoff | player_exit | null`
|
||||
|
||||
后端返回 `suggestions` 仍是字符串数组,前端按字符串生成 `npc_chat` 续写选项;新增 `functionSuggestions`,元素包含 `functionId` 与模型生成的 `actionText`,前端按对应 function 触发原 NPC action。
|
||||
|
||||
## 4. Prompt 规则
|
||||
|
||||
回复 prompt 需要明确:
|
||||
|
||||
1. 敌对聊天可随时中止,NPC 更偏好结束谈判转入战斗或驱逐。
|
||||
2. 终止不等于在回复正文里直接执行战斗,只需要用台词把对话收束到对峙、威胁、驱逐、最后通牒或行动前一刻。
|
||||
3. 玩家主动退出聊天时,NPC 回复要对这次收束作出回应,并留下自然的后续入口。
|
||||
|
||||
建议 prompt 需要明确:
|
||||
|
||||
1. 常规聊天候选继续生成玩家台词。
|
||||
2. Function 候选要根据提供的 function 列表,改写成玩家可直接点击的动作文本。
|
||||
3. 不输出规则说明,不把 functionId 暴露给玩家。
|
||||
|
||||
## 5. 前端流程
|
||||
|
||||
1. `enterNpcChat` 与每轮 `handleNpcChatTurn` 统一构造聊天可用 function 列表。
|
||||
2. 聊天中的普通候选仍触发 `npc_chat`,function 候选触发原 `handleNpcInteraction` 分流。
|
||||
3. `exitNpcChat` 改为调用 `handleNpcChatTurn`,输入文本为结束聊天意图,并携带 `player_exit` 指令。
|
||||
4. 收到终止结果后,当前 `StoryMoment` 保留 `dialogue`,移除 `npcChatState`,`options` 只保留 `buildContinueAdventureOption()`。
|
||||
5. 点击“继续”后沿用已有 deferred continue / story continue 逻辑进入下一阶段。
|
||||
6. 聊天态“换一换”只轮换当前 `options`,若 function 候选不足则补普通聊天兜底候选。
|
||||
|
||||
## 6. 追加规则:Function 标签与场景幕推进
|
||||
|
||||
1. 运行时选项按钮需要在动作文本前展示 function 短标签,例如 `npc_chat` 显示“聊天”,`npc_quest_accept` / `npc_quest_turn_in` 显示“任务”,`npc_gift` 显示“送礼”。
|
||||
2. 标签只承担识别用途,不展示 functionId,也不展示规则说明。
|
||||
3. NPC 聊天终止后点击“继续冒险”,不再重新请求剧情推理;如果当前场景还有下一幕,直接进入下一幕并展示该幕可用的冒险选项。
|
||||
4. 当当前场景已经到最后一幕,再点击“继续冒险”应展示所有相邻场景入口;选项文案按方向表达为“向东走,前往xxxx”“向南走,前往xxxx”等。
|
||||
5. 相邻场景选项继续使用 `idle_travel_next_scene`,并在 `runtimePayload.targetSceneId` 中携带目标场景,后续点击沿用现有地图跳转结算。
|
||||
6. 若没有场景幕数据,则继续使用当前可用选项作为兜底,不额外生成规则说明文案。
|
||||
|
||||
## 7. 验收
|
||||
|
||||
1. 负好感主 NPC 不再出现固定 `turnLimit: 5`。
|
||||
2. 敌对 NPC 每轮请求会向后端传 `terminationMode: hostile_model`。
|
||||
3. 模型返回 `forceExit: true` 后,聊天输入消失,只显示继续按钮。
|
||||
4. 好感度大于等于 0 的 NPC 聊天不传敌对中止模式。
|
||||
5. 点击退出聊天会新增玩家结束聊天气泡与 NPC 回复,而不是直接切走面板。
|
||||
6. 聊天态可看到并点击 function 候选,且“换一换”可改变候选顺序。
|
||||
7. 选项文字前出现中文 function 标签,且标签不改变原 actionText。
|
||||
8. 聊天结束后的“继续冒险”直接进入下一幕;最后一幕则展示多个相邻场景方向入口。
|
||||
@@ -0,0 +1,434 @@
|
||||
# 单场景章节对标缺口与 AI 原生体验补强设计
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份文档补在:
|
||||
|
||||
- `docs/design/SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md`
|
||||
- `docs/prd/AI_NATIVE_CLASSIC_RPG_EXPERIENCE_BENCHMARK_PRD_2026-04-06.md`
|
||||
|
||||
之后,专门回答一个更具体的问题:
|
||||
|
||||
**如果把当前每个场景都视为一个章节,那么和《仙剑》《博德之门》《黑神话:悟空》里一个成立的章节相比,我们现在到底缺什么;以及结合当前项目的 AI 原生设计,应该补哪些体验层。**
|
||||
|
||||
这份文档不重复讨论“场景如何开章、任务如何挂接”的骨架问题,而是聚焦:
|
||||
|
||||
1. 单章节的体验密度还缺什么
|
||||
2. 每章最该补的体验模块是什么
|
||||
3. 哪些能力必须由服务端承接,前端只负责表现
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先说
|
||||
|
||||
当前项目把“场景 = 章节单元”的方向已经立住了一半骨架,但和这三类标杆作品相比,单章节体验还普遍缺 5 件事:
|
||||
|
||||
1. 缺一个让玩家记住“这章是关于谁”的情感锚点
|
||||
2. 缺一个让玩家中途改判的转折点
|
||||
3. 缺一个让玩家感到“这一段路在压着我走”的空间推进链
|
||||
4. 缺一个让玩家立场真正被表达出来的选择节点
|
||||
5. 缺一个能把结果写回人物、物件、后续章节的余波回响
|
||||
|
||||
一句话判断:
|
||||
|
||||
**现在的场景章节更像“带任务 lead 的剧情地点”,还不够像“有人物、有抉择、有试炼、有收束余味的一整章”。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 对标三个标杆后,当前单章节缺什么
|
||||
|
||||
## 2.1 相比《仙剑》式章节,缺的是“人和情”
|
||||
|
||||
《仙剑》式章节最强的不是题材,而是:
|
||||
|
||||
1. 一章里总有一个会被记住的人
|
||||
2. 这一章结束时,人物关系一定发生了变化
|
||||
3. 玩家记住的不是“我做了一个任务”,而是“我和谁经历了一段事”
|
||||
|
||||
当前场景章节的主要缺口如下:
|
||||
|
||||
| 维度 | 标杆章节会给玩家什么 | 当前缺口 | 应补什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 章节记忆点 | 明确的人物高光或情感切口 | 现在更多是场景 lead,不够像人物立题 | 每章必须有 `情感锚点 NPC / 关系对象` |
|
||||
| 关系推进 | 误会、试探、信任、失去、承诺会推进 | 现在 NPC 更像信息点或任务点 | 在 `opening / turning_point / aftermath` 至少安排一次关系变化 |
|
||||
| 章节余味 | 章节结束后仍有余波、牵挂、回看价值 | 现在更多是“交给下一场景” | 章节结束后补 `私聊 / 留言 / 赠礼反应 / 人物口风变化` |
|
||||
|
||||
结论:
|
||||
|
||||
**当前章节最缺的不是人物数量,而是“这一章让玩家和谁产生了关系变化”。**
|
||||
|
||||
## 2.2 相比《博德之门》式章节,缺的是“选择和反应”
|
||||
|
||||
《博德之门》式章节最强的不是分支数量,而是:
|
||||
|
||||
1. 玩家会在一章里表达立场
|
||||
2. 队友和 NPC 会明确回应这个立场
|
||||
3. 同一个问题通常不止一种处理方式
|
||||
|
||||
当前场景章节的主要缺口如下:
|
||||
|
||||
| 维度 | 标杆章节会给玩家什么 | 当前缺口 | 应补什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 处理路径 | 同一章通常有 `2~3` 种解法 | 现在大多仍是单主解推进 | 每章至少提供一次 `有限分歧结算` |
|
||||
| 队友反应 | 队友会认可、反对、沉默、插话 | 现在同伴存在感偏弱 | 每章至少有一次 `同伴反应批次` |
|
||||
| 后果落地 | 选择会改任务理解、人物态度、后续信息 | 现在选择更多是流程推进,不够像立场表达 | 把章节选择写回 `关系 / 线索可见性 / 后续 handoff` |
|
||||
|
||||
结论:
|
||||
|
||||
**当前章节最缺的不是做无限分支,而是做“有限分歧 + 强反馈”。**
|
||||
|
||||
## 2.3 相比《黑神话:悟空》式章节,缺的是“路和压迫”
|
||||
|
||||
《黑神话:悟空》式章节最强的不是题材,而是:
|
||||
|
||||
1. 一章的空间推进本身就在讲故事
|
||||
2. 玩家会记住路上的地标、残痕、敌人和压迫感
|
||||
3. 一章通常有一个明显的试炼点或高潮演出点
|
||||
|
||||
当前场景章节的主要缺口如下:
|
||||
|
||||
| 维度 | 标杆章节会给玩家什么 | 当前缺口 | 应补什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 空间推进 | 场景不是背景,而是一段穿行过程 | 现在场景更像承载节点,不够像旅程 | 每章补 `路线压力链` 和 `地标记忆点` |
|
||||
| 残痕叙事 | 地点、物件、敌人都在讲旧事 | 现在残痕有素材,但链不够强 | 每章至少串起 `2~3` 个残痕 / 证据 / 地标 |
|
||||
| 高潮试炼 | 一章通常有一个明显 setpiece / 强敌 / 对峙 | 现在收束常偏文本或任务状态 | 每章补一个 `高潮收束动作面` |
|
||||
|
||||
结论:
|
||||
|
||||
**当前章节最缺的不是更多场景描述,而是“空间本身要承担承压和收束”。**
|
||||
|
||||
## 2.4 三个标杆放在一起看,当前单章节的综合缺口
|
||||
|
||||
综合来看,当前每个场景章节最明显的缺口可以收束成下面 7 条:
|
||||
|
||||
1. 场景有主题,但缺“这一章是谁在发光”
|
||||
2. 任务有步骤,但缺“中途为什么会改判”
|
||||
3. 残痕有素材,但缺“沿路逐步加压的链条”
|
||||
4. 同伴会跟着走,但缺“针对你的立场说话”
|
||||
5. 战斗或冲突会发生,但缺“本章高潮”
|
||||
6. 章节会结束,但缺“结束后谁变了”
|
||||
7. 章节会交棒,但缺“这一章留下了什么可回响之物”
|
||||
|
||||
---
|
||||
|
||||
## 3. 每个场景章节都该补的标准体验包
|
||||
|
||||
建议以后把每个场景章节都按“九件套”来补,不要求每件都做得很重,但每章都不能缺位。
|
||||
|
||||
| 模块 | 每章最低要求 | 主要对标 |
|
||||
| --- | --- | --- |
|
||||
| 开章钩子 | 一进入场景就抛出一个异常、冲突或错位对白 | 三者共同 |
|
||||
| 情感锚点 | 至少一个本章承担关系变化的人物 | 仙剑 |
|
||||
| 路线压力链 | 至少 `2~3` 个地标、残痕或承压节点串起来 | 黑神话 |
|
||||
| 承压事件 | 一次调查、对峙、战斗或阻拦,证明这一章真有事在发生 | 三者共同 |
|
||||
| 改判节点 | 至少一条反证、误会破口或旧痕翻案 | 仙剑 + 博德之门 |
|
||||
| 立场选择 | 至少一次有代价的二选一 / 三选一 | 博德之门 |
|
||||
| 同伴反应 | 至少一次认可、反对、担忧、沉默中的一种反馈 | 博德之门 |
|
||||
| 高潮收束 | 一次明确的 confrontation、试炼、交付或揭示 | 黑神话 + 仙剑 |
|
||||
| 余波回响 | 至少留下一个后续会被提起的人、物、线索或态度变化 | 三者共同 |
|
||||
|
||||
这里的重点不是把每章都做成大体量内容,而是让每章都具备:
|
||||
|
||||
1. 可记住的人
|
||||
2. 可承压的路
|
||||
3. 可表达的立场
|
||||
4. 可回响的结果
|
||||
|
||||
---
|
||||
|
||||
## 4. 结合 AI 原生设计,单章节应该怎么补
|
||||
|
||||
## 4.1 不是做“无限分支”,而是做“有限模块 + 动态编排”
|
||||
|
||||
当前项目最适合的做法,不是给每个场景写爆炸式手工分支,而是:
|
||||
|
||||
1. 先给每章补稳定的体验模块
|
||||
2. 再让 AI 按当前线程、关系、残痕和场景状态去动态编排表达
|
||||
3. 本地规则负责章节状态、选择裁决、任务推进、关系变化和奖励回写
|
||||
|
||||
一句话说:
|
||||
|
||||
**AI 负责把这一章写活,本地规则负责保证这一章成立。**
|
||||
|
||||
## 4.2 建议新增一个章节体验画像
|
||||
|
||||
建议在现有 `ChapterState` 外,给每个场景章节补一个更偏体验编排的数据层,例如:
|
||||
|
||||
```ts
|
||||
interface ChapterExperienceProfile {
|
||||
sceneId: string;
|
||||
chapterArchetype: 'emotion' | 'choice' | 'trial' | 'hybrid';
|
||||
chapterPromise: string;
|
||||
emotionalAnchorNpcId?: string | null;
|
||||
guideNpcId?: string | null;
|
||||
opposingForceId?: string | null;
|
||||
routePressureBeats: string[];
|
||||
turningEvidenceIds: string[];
|
||||
stanceChoiceId?: string | null;
|
||||
climaxSetpieceId?: string | null;
|
||||
rewardCarrierSeed?: string | null;
|
||||
aftermathEchoTargets: string[];
|
||||
}
|
||||
```
|
||||
|
||||
它的作用不是替代现有 `ChapterState`,而是补“这一章体验上到底靠什么成立”。
|
||||
|
||||
## 4.3 每章都要有一个“人物轴”
|
||||
|
||||
这是补仙剑型体验最重要的一步。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每章必须指定一个 `emotionalAnchorNpcId`
|
||||
2. 这个角色不一定是最强、最重要的人,但一定是本章最会改变玩家理解的人
|
||||
3. 这个角色至少承担下面 2 件事:
|
||||
- `opening` 里立题或制造错位
|
||||
- `turning_point / aftermath` 里改口、揭示或留下余波
|
||||
|
||||
AI 原生补法:
|
||||
|
||||
1. AI 负责生成角色此章的表层说辞、压力表现和错位感
|
||||
2. 本地规则负责控制此章能披露哪些事实、关系如何变化
|
||||
|
||||
## 4.4 每章都要有一个“路线轴”
|
||||
|
||||
这是补黑神话型体验最重要的一步。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每章至少有 `2~3` 个 `routePressureBeats`
|
||||
2. 每个 beat 都不只是位置点,而是下面三类之一:
|
||||
- 地标记忆点
|
||||
- 场景残痕点
|
||||
- 敌对 / 阻拦 / 追索点
|
||||
3. `climax` 前必须至少有一次“越往前越不安”的空间升级
|
||||
|
||||
AI 原生补法:
|
||||
|
||||
1. AI 负责根据 `scene residue / thread / scar / motif` 生成现场感和残痕文本
|
||||
2. 本地规则负责决定 beat 顺序、是否已触发、何时进入高潮
|
||||
|
||||
## 4.5 每章都要有一个“立场轴”
|
||||
|
||||
这是补博德之门型体验最重要的一步。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每章至少抛一次立场问题
|
||||
2. 立场问题优先围绕:
|
||||
- 要不要信谁
|
||||
- 要不要公开某条线索
|
||||
- 要不要保一个人还是保规则
|
||||
- 要不要立刻动手还是继续查
|
||||
3. 不追求无限解,只要求:
|
||||
- `2~3` 个有限方案
|
||||
- 每个方案都能触发明确反应
|
||||
|
||||
AI 原生补法:
|
||||
|
||||
1. AI 负责把选择包装成角色化、情境化的动作与对白
|
||||
2. 本地规则负责裁决结果、写回 `CompanionStanceProfile / Quest / Knowledge / Echo`
|
||||
|
||||
## 4.6 每章都要有一个“高潮动作面”
|
||||
|
||||
目前很多场景的高潮更像“任务完成”,还不够像“一章真正收束了”。
|
||||
|
||||
建议每章在 `climax` 至少落成下面四类之一:
|
||||
|
||||
1. 正面对峙
|
||||
2. 小型试炼 / 强敌
|
||||
3. 真相交付
|
||||
4. 关系摊牌
|
||||
|
||||
要求:
|
||||
|
||||
1. 高潮不能只体现在任务状态变化
|
||||
2. 必须有明确前后差
|
||||
3. 必须能回写一条 `chapter aftermath`
|
||||
|
||||
## 4.7 每章都要留下一个可回响的载体
|
||||
|
||||
这是把三类标杆合在一起后最容易被低估的一层。
|
||||
|
||||
建议每章至少留下一个:
|
||||
|
||||
1. 章节证物
|
||||
2. 章节遗物
|
||||
3. 章节残痕
|
||||
4. 章节口风变化
|
||||
|
||||
它们至少要满足一条:
|
||||
|
||||
1. 下一章还能被提起
|
||||
2. 某个 NPC 会认出它
|
||||
3. 某个同伴会追加评论
|
||||
4. 某个任务会因为它改变说明或目标
|
||||
|
||||
---
|
||||
|
||||
## 5. 章节类型建议
|
||||
|
||||
不是每章都要平均模仿三款游戏,更稳的做法是:每章明确一个主类型,再配一个副类型。
|
||||
|
||||
| 章节类型 | 主对标 | 章节重点 | 必选模块 |
|
||||
| --- | --- | --- | --- |
|
||||
| 情感章 | 仙剑 | 人物关系、误会、牺牲、承诺、旧债 | 情感锚点、改判节点、余波回响 |
|
||||
| 抉择章 | 博德之门 | 立场表达、队友反应、有限分歧结算 | 立场选择、同伴反应、后果回写 |
|
||||
| 试炼章 | 黑神话 | 路线承压、地标残痕、高潮试炼 | 路线压力链、高潮收束、章节载体 |
|
||||
| 混合章 | 任选两者 | 既要有情感,也要有试炼或选择 | 视主副轴组合决定 |
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每个场景章节都标一个 `主类型`
|
||||
2. 再选一个 `副类型`
|
||||
3. 不要让所有章节都只剩“调查 + 对话 + 交任务”
|
||||
|
||||
---
|
||||
|
||||
## 6. 服务端与前端的职责边界
|
||||
|
||||
结合当前项目约束,章节体验补强必须坚持:
|
||||
|
||||
**前端只负责表现,章节逻辑、状态、选择裁决、数据编排全部放在 Express 后端。**
|
||||
|
||||
## 6.1 服务端负责什么
|
||||
|
||||
建议把下面这些能力放在 `server-node/`:
|
||||
|
||||
1. 章节体验画像生成
|
||||
2. 章节选择裁决
|
||||
3. 同伴反应批次生成
|
||||
4. 章节残痕与路线 beat 编排
|
||||
5. 章节余波与回响写回
|
||||
6. 章节奖励载体编译
|
||||
|
||||
服务端输入应来自:
|
||||
|
||||
1. 当前 `sceneId`
|
||||
2. 当前 `ChapterState`
|
||||
3. 当前队伍与关系状态
|
||||
4. 当前激活线程与知识可见性
|
||||
5. 当前章节已触发的 beat、choice、residue、setpiece
|
||||
|
||||
服务端输出应编译成前端可直接消费的结果,例如:
|
||||
|
||||
1. 当前章节标题与阶段
|
||||
2. 当前章节 promise
|
||||
3. 当前 route beats
|
||||
4. 当前可选立场
|
||||
5. 同伴反应 feed
|
||||
6. 本章高潮结果
|
||||
7. 本章 aftermath 摘要
|
||||
|
||||
## 6.2 前端负责什么
|
||||
|
||||
前端只负责:
|
||||
|
||||
1. 表现章节标题、章节目标、路线节拍
|
||||
2. 表现情感锚点人物和同伴反应
|
||||
3. 表现本章高潮演出与余波反馈
|
||||
4. 表现章节奖励载体和 chronicle 回写结果
|
||||
|
||||
前端不要负责:
|
||||
|
||||
1. 计算选择结果
|
||||
2. 推导章节阶段
|
||||
3. 生成 route beat 顺序
|
||||
4. 决定同伴 stance 更新
|
||||
|
||||
---
|
||||
|
||||
## 7. 单章节设计卡模板
|
||||
|
||||
为了让后续每个场景都能按统一方式补体验,建议每章都补一张简版设计卡:
|
||||
|
||||
```md
|
||||
- 章节标题:
|
||||
- 主类型 / 副类型:
|
||||
- 本章 promise:
|
||||
- 情感锚点人物:
|
||||
- 开章钩子:
|
||||
- 路线压力链:
|
||||
- 承压事件:
|
||||
- 改判证据:
|
||||
- 立场选择:
|
||||
- 同伴反应:
|
||||
- 高潮收束:
|
||||
- 章节奖励载体:
|
||||
- 余波回响:
|
||||
- 下一章 handoff:
|
||||
```
|
||||
|
||||
只要这张卡填不满,说明这一章还没有真正成立。
|
||||
|
||||
---
|
||||
|
||||
## 8. 推荐补强顺序
|
||||
|
||||
如果按当前项目最稳的节奏推进,建议顺序如下:
|
||||
|
||||
## 阶段 A:先补“可被记住的人”
|
||||
|
||||
先做:
|
||||
|
||||
1. 情感锚点 NPC
|
||||
2. 改判节点
|
||||
3. 章节余波
|
||||
|
||||
原因:
|
||||
|
||||
这是最接近当前项目已有 NPC、关系和私聊链的部分,投入最小,感知提升最快。
|
||||
|
||||
## 阶段 B:再补“可被表达的立场”
|
||||
|
||||
先做:
|
||||
|
||||
1. 每章一次立场选择
|
||||
2. 同伴反应批次
|
||||
3. 后果写回任务 / 关系 / 线索可见性
|
||||
|
||||
原因:
|
||||
|
||||
这是对标《博德之门》最关键,同时也是最能让 AI 原生叙事摆脱“只会往前写”的一步。
|
||||
|
||||
## 阶段 C:最后补“可被承压的路”
|
||||
|
||||
先做:
|
||||
|
||||
1. route pressure beats
|
||||
2. 地标残痕链
|
||||
3. 高潮 setpiece
|
||||
|
||||
原因:
|
||||
|
||||
空间承压最依赖完整的场景节拍和演出支持,适合在前两层站稳后继续增强。
|
||||
|
||||
---
|
||||
|
||||
## 9. 章节体验验收标准
|
||||
|
||||
如果说一个场景章节已经明显更接近《仙剑》《博德之门》《黑神话:悟空》那类标杆,至少应满足下面这些结果:
|
||||
|
||||
1. 玩家玩完这一章后,能明确说出“这章主要在讲谁 / 讲什么”
|
||||
2. 玩家在中段经历过一次改判,而不是从头到尾只在确认原判断
|
||||
3. 玩家能记住至少一个地标、残痕或证物,而不只是任务标题
|
||||
4. 玩家至少做过一次立场表达,并收到过明确反应
|
||||
5. 玩家在章节结束时感到“这一章局部收住了”,而不只是“系统让我去下个场景”
|
||||
6. 本章至少有一条人物态度、物件、线索或 chronicle 被写进后续回响
|
||||
7. 首遇与低披露阶段不会把整章暗线和角色完整背景直接灌给模型
|
||||
|
||||
---
|
||||
|
||||
## 10. 一句话结论
|
||||
|
||||
如果把每个场景都视为一个章节,那么当前最该补的,不是继续堆更多场景文本,而是让每章都真正长出:
|
||||
|
||||
1. 一个会被记住的人
|
||||
2. 一段会逐步加压的路
|
||||
3. 一次会暴露立场的选择
|
||||
4. 一个能把本章收住的高潮
|
||||
5. 一条能延续到后面的余波
|
||||
|
||||
只有这样,当前项目的“场景章节化”才会从结构成立,进一步走到体验成立。
|
||||
@@ -0,0 +1,715 @@
|
||||
# 场景章节闭环与首进章节任务设计
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份设计稿要把当前仓库里已经存在的:
|
||||
|
||||
- `章节状态`
|
||||
- `任务 contract / step`
|
||||
- `场景残痕`
|
||||
- `NPC 首遇与关系`
|
||||
- `Goal Stack`
|
||||
|
||||
进一步收束成一条更明确的结构:
|
||||
|
||||
**每个场景都是一个剧情章节单元;每个章节在当前剧情引擎里都要形成“起承转合”的完整闭环;并且在玩家首次进入该场景时,自动开启一个章节任务。**
|
||||
|
||||
这里的重点不是再造一套全新系统,而是把现有能力重新组织成:
|
||||
|
||||
1. 场景不再只是地图节点,而是章节容器。
|
||||
2. 章节不再只是背景摘要,而是有明确动作面的闭环。
|
||||
3. 任务不再只是零散委托,而是章节在前台的执行外壳。
|
||||
4. NPC 不再只是“场景里有什么人”,而是按章节节拍承担起、承、转、合的叙事职责。
|
||||
|
||||
---
|
||||
|
||||
## 1. 基于当前仓库的判断
|
||||
|
||||
结合当前文档与代码,现状已经具备一半骨架,但关键一半还没接上。
|
||||
|
||||
### 1.1 已经具备的基础
|
||||
|
||||
1. `src/services/storyEngine/chapterDirector.ts`
|
||||
- 已经有 `ChapterState`,但当前主要根据 `signalCount / chronicleCount / activeThreadCount` 推章节阶段,更像“抽象章节热度”,还不是“具体场景章节实例”。
|
||||
|
||||
2. `src/data/questFlow.ts`
|
||||
- 已经有 `QuestIntent -> QuestContract -> QuestStep -> QuestProgressSignal` 的完整任务闭环。
|
||||
- `QuestLogEntry` 也已经有 `actId / threadId / contractId / steps / activeStepId / visibleStage` 这些可扩展入口。
|
||||
|
||||
3. `src/services/storyEngine/goalDirector.ts`
|
||||
- 已经能把 `chapter + quest + journeyBeat + setpiece` 编译成玩家前台目标感。
|
||||
- 说明章节任务一旦成型,前台目标层基本不用重做,只要接正确数据。
|
||||
|
||||
4. `src/data/scenePresets.ts`
|
||||
- 已经有场景描述、敌对实体、额外 NPC、宝藏线索、narrative residues。
|
||||
- 这些字段已经够支持“场景章节蓝图”的第一版自动编译。
|
||||
|
||||
### 1.2 当前缺口
|
||||
|
||||
当前最核心的缺口有 4 个:
|
||||
|
||||
1. 没有“场景首次进入”对应的持久状态。
|
||||
- 现在能做场景切换,也能累计 `scenesTraveled`,但没有 `openedSceneChapterIds` 或等价结构。
|
||||
|
||||
2. 没有“场景章节实例”。
|
||||
- `ChapterState` 已有,但没有一个明确指向 `sceneId`、可追踪起承转合进度的运行时对象。
|
||||
|
||||
3. 没有“章节任务自动开章”的规则。
|
||||
- 现在任务更多还是由 NPC 委托机会触发,不是“首进场景即开章”。
|
||||
|
||||
4. 没有按章节节拍组织 NPC。
|
||||
- 现在场景里有 NPC、有敌人、有残痕,但还没有明确规定谁负责起、谁负责承、谁负责转、谁负责合。
|
||||
|
||||
一句话总结:
|
||||
|
||||
**当前仓库已经有章节系统、任务系统和场景叙事素材,但还没有“场景章节实例 + 首进自动开章任务 + 起承转合 NPC 编排”这条真正把它们串起来的中介层。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心决策
|
||||
|
||||
## 2.1 场景 = 章节单元
|
||||
|
||||
从这次开始,默认把每个可到达场景都视为一个章节单元。
|
||||
|
||||
这意味着:
|
||||
|
||||
1. 玩家进入一个新场景,不只是“换地图”,而是“开启一个新章节”。
|
||||
2. 该场景内必须具备一个可完成的最小剧情闭环。
|
||||
3. 即使大世界主线跨多个场景延续,每个场景也要有自己的局部收束。
|
||||
|
||||
## 2.2 章节仍然是叙事语义,任务是前台动作面
|
||||
|
||||
这点要继续保持和当前项目既有方向一致:
|
||||
|
||||
- `章节` 负责表达“这一段故事在追什么”。
|
||||
- `章节任务` 负责表达“玩家现在要做什么”。
|
||||
|
||||
也就是说:
|
||||
|
||||
**章节不是单独再做一个和任务平级的前台入口,而是通过“章节任务”落到玩家动作层。**
|
||||
|
||||
## 2.3 保留现有五阶段结构,起承转合作为体验要求理解
|
||||
|
||||
当前 `ChapterState.stage` 已经在用:
|
||||
|
||||
- `opening`
|
||||
- `expansion`
|
||||
- `turning_point`
|
||||
- `climax`
|
||||
- `aftermath`
|
||||
|
||||
这次不再新增新的叙事阶段枚举,也不再额外引入一套“四拍语义”运行时字段。
|
||||
|
||||
“起承转合”保留为章节闭环的体验要求,但在系统里直接压到现有五阶段上理解:
|
||||
|
||||
| 当前字段 | 体验语义 |
|
||||
| --- | --- |
|
||||
| `opening` | 起:开章立题 |
|
||||
| `expansion` | 承:压力展开 |
|
||||
| `turning_point` | 转:理解改判 |
|
||||
| `climax` | 合:正面收束 |
|
||||
| `aftermath` | 合后的余波与交接 |
|
||||
|
||||
这意味着:
|
||||
|
||||
1. 玩家体感上仍然能得到“起承转合”的完整闭环。
|
||||
2. 系统运行时只认现有 `stage`,不新增第二套章节阶段系统。
|
||||
3. `goalDirector / journeyBeatPlanner / setpieceDirector / UI` 都可以继续沿用现有结构。
|
||||
|
||||
---
|
||||
|
||||
## 3. 场景章节的标准闭环
|
||||
|
||||
每个场景章节都必须至少回答这 4 个问题:
|
||||
|
||||
1. 玩家刚进来时,这里有什么事正在发生?
|
||||
2. 玩家在这一章里到底要处理什么压力?
|
||||
3. 这一章中途会出现什么反转或改判?
|
||||
4. 玩家离开前,这一章给出了什么局部收束?
|
||||
|
||||
对应到现有系统里,就是当前五阶段的完整跑通。
|
||||
|
||||
## 3.1 `opening`:开章立题
|
||||
|
||||
触发时机:
|
||||
|
||||
- 玩家首次进入某场景
|
||||
|
||||
必须完成的事:
|
||||
|
||||
1. 建立场景章节标题与主题。
|
||||
2. 让一个 NPC、残痕或现场异常把问题抛出来。
|
||||
3. 自动开启本章章节任务。
|
||||
4. 给玩家一个明确的第一步。
|
||||
|
||||
适合使用的现有信号:
|
||||
|
||||
- `scene_reached`
|
||||
- 首次 NPC 对话
|
||||
- 首次观察残痕 / 宝藏线索
|
||||
|
||||
适合落地的任务 step:
|
||||
|
||||
- `reach_scene`
|
||||
- `talk_to_npc`
|
||||
- `inspect_treasure`
|
||||
|
||||
## 3.2 `expansion`:压力展开
|
||||
|
||||
触发时机:
|
||||
|
||||
- 玩家已经接住本章 lead,开始深入该场景
|
||||
|
||||
必须完成的事:
|
||||
|
||||
1. 让玩家确认“这一章不是空壳,确实有事要处理”。
|
||||
2. 把当前场景的主压力推到前台。
|
||||
3. 让场景内的敌对 NPC / 障碍 NPC / 关键残痕承担中段推进。
|
||||
|
||||
适合落地的任务 step:
|
||||
|
||||
- `inspect_treasure`
|
||||
- `defeat_hostile_npc`
|
||||
- `spar_with_npc`
|
||||
- `talk_to_npc`
|
||||
|
||||
## 3.3 `turning_point`:改判与揭示
|
||||
|
||||
触发时机:
|
||||
|
||||
- 玩家完成了承段主动作,系统需要让当前理解发生偏转
|
||||
|
||||
必须完成的事:
|
||||
|
||||
1. 出现一条新事实、矛盾证词或旧痕反证。
|
||||
2. 让至少一个 NPC 的定位发生变化。
|
||||
3. 把任务从“处理中”切到“确认真相 / 回去对话 / 做最后一跳”。
|
||||
|
||||
适合落地的任务 step:
|
||||
|
||||
- `talk_to_npc`
|
||||
- `inspect_treasure`
|
||||
- `reach_scene`
|
||||
- `item_delivered`
|
||||
|
||||
## 3.4 `climax`:本章收束
|
||||
|
||||
触发时机:
|
||||
|
||||
- 玩家已经拿到足够信息,或者已经处理完这一章的核心冲突
|
||||
|
||||
必须完成的事:
|
||||
|
||||
1. 当前场景的局部问题得到收束。
|
||||
2. 章节任务进入可交付或已交付状态。
|
||||
3. 章节回写 `chronicle`。
|
||||
4. 给出下一场景 handoff。
|
||||
|
||||
适合落地的任务 step:
|
||||
|
||||
- `talk_to_npc`
|
||||
- `item_delivered`
|
||||
|
||||
注意:
|
||||
|
||||
**`climax` 不等于世界真相彻底结束,而是这一个场景章节的核心矛盾必须在这里得到局部收束。**
|
||||
|
||||
也就是说,大主线可以继续,但当前场景不能只留下“半段没收”的悬空状态。
|
||||
|
||||
## 3.5 `aftermath`:余波与交接
|
||||
|
||||
触发时机:
|
||||
|
||||
- 章节任务已经 `ready_to_turn_in` 或 `turned_in`
|
||||
- 本章主要冲突已经完成,系统需要把结果沉淀并交给下一段
|
||||
|
||||
必须完成的事:
|
||||
|
||||
1. 把本章结果写进 `chronicle` 或最近摘要。
|
||||
2. 把当前场景的局部余波写回场景状态、NPC 态度或任务说明。
|
||||
3. 给出下一场景或下一条线程的 handoff。
|
||||
|
||||
这里的重点不是再加一轮复杂任务,而是把已有结果接住。
|
||||
|
||||
一句话总结:
|
||||
|
||||
**起承转合仍然保留为设计目标,但系统实现上直接用 `opening -> expansion -> turning_point -> climax -> aftermath` 跑完整闭环。**
|
||||
|
||||
---
|
||||
|
||||
## 4. NPC 编排规则
|
||||
|
||||
这次的 NPC 设计重点不是“一个场景塞多少人”,而是:
|
||||
|
||||
**谁在这一章里负责什么。**
|
||||
|
||||
## 4.1 不新增独立的 `npcCasting` 系统,先按现有阶段组织职责
|
||||
|
||||
这轮不建议为了章节化单独新增一套 NPC casting 数据结构。
|
||||
|
||||
更稳的做法是直接基于现有场景数据组织阶段职责:
|
||||
|
||||
1. `opening`
|
||||
- 优先由场景里的首遇 NPC、第一条残痕或第一层异动承担立题职责。
|
||||
|
||||
2. `expansion`
|
||||
- 优先由敌对单位、阻拦型 NPC、关键残痕承担压力职责。
|
||||
|
||||
3. `turning_point`
|
||||
- 优先由第二条线索、矛盾证词、返回对话的 NPC 承担改判职责。
|
||||
|
||||
4. `climax / aftermath`
|
||||
- 优先由最初开章 NPC 或新的接棒 NPC 承担收束和 handoff。
|
||||
|
||||
## 4.2 允许一人多阶段承担职责,但阶段职责不能空
|
||||
|
||||
考虑到当前有些场景 NPC 数量不多,因此允许:
|
||||
|
||||
- 同一个 NPC 同时承担 `opening + aftermath`
|
||||
- 同一个 NPC 同时承担 `expansion + turning_point`
|
||||
|
||||
如果友方 NPC 不够,可以由这些现有对象补位:
|
||||
|
||||
1. 场景残痕
|
||||
2. 宝藏线索
|
||||
3. 文书 / 道具 / 遗物
|
||||
4. 敌对单位
|
||||
|
||||
也就是说,本章的“转”不一定靠新 NPC,也可以靠现有证据或现场变化来完成。
|
||||
|
||||
## 4.3 NPC 的章节职责应该是动态解释,不是静态标签
|
||||
|
||||
不要把 NPC 只写成:
|
||||
|
||||
- 商人
|
||||
- 侍女
|
||||
- 守门人
|
||||
- 怪物
|
||||
|
||||
更应该补的是:
|
||||
|
||||
- 他在这一章里为什么是开章人
|
||||
- 他卡住玩家的是什么压力
|
||||
- 他掌握的转折信息是什么
|
||||
- 他能否承接本章结算
|
||||
|
||||
这部分优先通过现有 `npc context / dialogue / rewardText / quest step 文案` 去表达,不急着为每个 NPC 新增专门类型。
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据结构建议
|
||||
|
||||
## 5.1 扩展 `ChapterState`
|
||||
|
||||
建议扩展为:
|
||||
|
||||
```ts
|
||||
export interface ChapterState {
|
||||
id: string;
|
||||
title: string;
|
||||
theme: string;
|
||||
primaryThreadIds: string[];
|
||||
stage: 'opening' | 'expansion' | 'turning_point' | 'climax' | 'aftermath';
|
||||
chapterSummary: string;
|
||||
|
||||
sceneId?: string | null;
|
||||
chapterQuestId?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
这样当前系统读取 `stage` 的地方仍然可用,同时章节状态也能明确绑定:
|
||||
|
||||
- 这是哪个场景章节
|
||||
- 当前绑定的是哪一个章节任务
|
||||
|
||||
建议:
|
||||
|
||||
- 对“场景章节”使用稳定 id,例如 `chapter:scene:${sceneId}`
|
||||
- 不再额外发明新的章节实例类型
|
||||
|
||||
## 5.2 扩展 `StoryEngineMemoryState`
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
export interface StoryEngineMemoryState {
|
||||
openedSceneChapterIds?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
这是这次最关键的数据层补丁,因为当前仓库现在没有“首进场景已开章”的持久状态。
|
||||
|
||||
这里刻意不新增 `sceneChapterStates` 这类新的章节运行时容器,优先复用现有:
|
||||
|
||||
- `currentChapter`
|
||||
- `quests`
|
||||
- `storyHistory`
|
||||
- `chronicle`
|
||||
|
||||
## 5.3 尽量复用 `QuestLogEntry`
|
||||
|
||||
建议补充:
|
||||
|
||||
```ts
|
||||
export interface QuestLogEntry {
|
||||
chapterId?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
其他字段尽量直接复用现有结构:
|
||||
|
||||
- `sceneId`
|
||||
- `steps`
|
||||
- `activeStepId`
|
||||
- `visibleStage`
|
||||
- `status`
|
||||
|
||||
目的不是让 UI 暴露更多字段,而是让系统能知道:
|
||||
|
||||
- 这是某个场景章节自动生成的主任务
|
||||
- 该任务与当前 `ChapterState` 是否一一对应
|
||||
|
||||
一句话原则:
|
||||
|
||||
**这轮只补“老系统里真正缺的最小字段”,不再额外发明一整套章节蓝图 / 章节运行时数据模型。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 章节任务设计
|
||||
|
||||
## 6.1 首次进入场景时自动开任务
|
||||
|
||||
根据这次需求,章节任务默认不再依赖玩家额外点一次“接受委托”。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 玩家首次进入某场景时,直接创建该场景的章节任务。
|
||||
2. 章节任务默认进入 `active`。
|
||||
3. 同一场景后续再次进入时,不重复开同一任务。
|
||||
|
||||
也就是说:
|
||||
|
||||
**首进场景 = 开章节 = 章节任务自动入列。**
|
||||
|
||||
## 6.2 章节任务不强制另起一套五步或四步系统,优先复用现有 step + status
|
||||
|
||||
这次不建议为了章节化再发明一套新的任务阶段结构。
|
||||
|
||||
更稳的做法是:
|
||||
|
||||
1. 章节层继续使用现有五阶段 `stage`
|
||||
2. 任务层继续使用现有 `steps + activeStepId + status`
|
||||
3. 通过任务进度去驱动章节阶段,而不是反过来再创建一套章节 step
|
||||
|
||||
建议映射关系:
|
||||
|
||||
| 章节阶段 | 现有任务侧表现 |
|
||||
| --- | --- |
|
||||
| `opening` | 章节任务刚创建,首个 `step` 为接 lead |
|
||||
| `expansion` | 中段调查 / 战斗 / 接触 step 在推进 |
|
||||
| `turning_point` | `activeStep` 切换到改判或回报前置 step |
|
||||
| `climax` | 最后一个核心 step 正在执行,或任务刚进入 `ready_to_turn_in` |
|
||||
| `aftermath` | 任务 `turned_in`,或已经完成本章结算并进入 handoff |
|
||||
|
||||
推荐的 step 仍然复用当前支持的类型:
|
||||
|
||||
| 当前阶段 | 常见 step kind |
|
||||
| --- | --- |
|
||||
| `opening` | `reach_scene` / `talk_to_npc` / `inspect_treasure` |
|
||||
| `expansion` | `inspect_treasure` / `defeat_hostile_npc` / `spar_with_npc` |
|
||||
| `turning_point` | `talk_to_npc` / `inspect_treasure` / `reach_scene` |
|
||||
| `climax` | `talk_to_npc` / `item_delivered` / 关键收束 step |
|
||||
| `aftermath` | 优先使用 `ready_to_turn_in / turned_in` 和 handoff,不再强塞新 step |
|
||||
|
||||
## 6.3 章节任务应该服务于 Goal Stack
|
||||
|
||||
当前仓库已经有 `GoalStack`,因此章节任务一旦建立,应默认成为:
|
||||
|
||||
1. `active_contract`
|
||||
2. `immediate_step`
|
||||
|
||||
而 `ChapterState` 继续承担:
|
||||
|
||||
1. 章节主题
|
||||
2. 章节承诺
|
||||
3. 章节背景总结
|
||||
|
||||
也就是说前台玩家看到的是:
|
||||
|
||||
- 当前章节任务标题
|
||||
- 下一步去哪 / 找谁 / 做什么
|
||||
|
||||
后台章节层则继续给叙事和 prompt 提供语义。
|
||||
|
||||
---
|
||||
|
||||
## 7. 运行时流程接入建议
|
||||
|
||||
## 7.1 调整 `chapterDirector.ts`
|
||||
|
||||
当前 `chapterDirector` 更像“热度评分器”。
|
||||
|
||||
这次建议直接在它内部补两类能力:
|
||||
|
||||
1. 场景绑定
|
||||
- 当前场景存在且符合开章条件时,直接生成 `sceneId` 绑定的 `ChapterState`
|
||||
|
||||
2. 阶段推导
|
||||
- 优先从当前场景绑定的章节任务进度推导 `opening -> expansion -> turning_point -> climax -> aftermath`
|
||||
- 只有在场景章节信息不足时,才回退到现有 `signalCount / chronicleCount / activeThreadCount` 逻辑
|
||||
|
||||
建议新增的只是 `chapterDirector.ts` 内部 helper,而不是新的模块,例如:
|
||||
|
||||
```ts
|
||||
resolveSceneBoundChapterState(params)
|
||||
deriveChapterStageFromQuest(params)
|
||||
```
|
||||
|
||||
## 7.2 调整 `questFlow.ts`
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
buildChapterQuestForScene(params)
|
||||
findActiveChapterQuestForScene(params)
|
||||
```
|
||||
|
||||
这里依然放在现有 `questFlow.ts` 内部处理,不单独拆新系统。
|
||||
|
||||
章节任务 builder 的原则是:
|
||||
|
||||
1. 输入继续使用当前能拿到的场景信息
|
||||
- `scenePreset`
|
||||
- `currentSceneId`
|
||||
- `activeThreadIds`
|
||||
- `scene npcs / hostile npc / treasureHints`
|
||||
|
||||
2. 输出继续是现有 `QuestLogEntry`
|
||||
- 只是多补 `chapterId`
|
||||
- 并尽量让 `sceneId = 当前场景`
|
||||
|
||||
## 7.3 调整 `useStoryGeneration.ts` / `sessionActions.ts`
|
||||
|
||||
推荐接入点:
|
||||
|
||||
1. 场景切换完成后
|
||||
2. `scene_reached` 信号写入时
|
||||
3. 地图跳转 `travelToSceneFromMap(...)` 成功后
|
||||
|
||||
处理顺序建议为:
|
||||
|
||||
1. 先判断是否首进场景
|
||||
2. 若首进:
|
||||
- 把 `sceneId` 写入 `openedSceneChapterIds`
|
||||
- 检查当前场景是否已有未结清的章节任务
|
||||
- 若没有,则在 `questFlow.ts` 内生成章节任务
|
||||
- 写入 `chapterState(stage = opening)`
|
||||
- 触发章节 pulse
|
||||
3. 再刷新 `goalStack / chapterState / journeyBeat`
|
||||
|
||||
## 7.4 调整 `goalDirector.ts`
|
||||
|
||||
当前 `goalDirector.ts` 已经能编译:
|
||||
|
||||
- `chapter`
|
||||
- `quest`
|
||||
- `journeyBeat`
|
||||
- `setpiece`
|
||||
|
||||
因此这里只需要一个优先级调整:
|
||||
|
||||
1. 当前场景若存在匹配 `chapterId` 的章节任务
|
||||
2. 且它还未 `turned_in`
|
||||
3. 则优先把它当作当前场景的 `active_contract` / `immediate_step`
|
||||
|
||||
这样 Goal Stack 继续复用,不需要再加新层。
|
||||
|
||||
## 7.5 调整 `storyChronicle.ts`
|
||||
|
||||
建议章节至少写 3 次 chronicle:
|
||||
|
||||
1. 开章
|
||||
2. 转折发生
|
||||
3. 本章收束
|
||||
|
||||
这样章节不会只存在于当前一屏,而能进入长期回顾。
|
||||
|
||||
---
|
||||
|
||||
## 8. 首进场景的标准触发流程
|
||||
|
||||
建议标准流程如下:
|
||||
|
||||
```text
|
||||
玩家进入场景
|
||||
-> 触发 scene_reached
|
||||
-> 检查 openedSceneChapterIds 是否已包含当前 sceneId
|
||||
-> 若否:
|
||||
-> 将当前 sceneId 写入 openedSceneChapterIds
|
||||
-> 生成 chapterId = chapter:scene:${sceneId}
|
||||
-> 生成章节任务并直接设为 active
|
||||
-> 写入当前 ChapterState(stage = opening, sceneId, chapterQuestId)
|
||||
-> 触发 Goal Pulse: 新章节开启
|
||||
-> 写入 chronicle 开章记录
|
||||
-> 若是:
|
||||
-> 只同步当前章节状态,不重复开任务
|
||||
-> 随着任务 step 与 signal 推进:
|
||||
-> ChapterState.stage 依次推进到 expansion / turning_point / climax
|
||||
-> 当任务 ready_to_turn_in 或 turned_in:
|
||||
-> ChapterState.stage = aftermath
|
||||
-> 写入余波 chronicle 与下一跳 handoff
|
||||
```
|
||||
|
||||
这一步是整个方案能不能真正成立的关键,因为用户这次要的就是:
|
||||
|
||||
**“首次进入某个场景”这一刻,就要像进入新章节一样被系统接住。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 当前仓库可直接套用的样章示例
|
||||
|
||||
下面用当前仓库已经存在的 `宫苑内庭` 说明这套设计怎么落。
|
||||
|
||||
当前场景素材来自 `src/data/scenePresets.ts`:
|
||||
|
||||
- 场景:`宫苑内庭`
|
||||
- 场景描述:`回廊深处静得过分,花木修得齐整,却处处像埋着王庭旧案。`
|
||||
- 场景友方 NPC:`旧宫侍女`
|
||||
- 场景线索:`回廊暗格里的香囊`、`花圃石座下的旧金牌`
|
||||
- 相邻场景:`铸坊工场`、`雨夜长街`、`地宫通道`
|
||||
|
||||
可直接编成如下章节:
|
||||
|
||||
## 9.1 章节标题
|
||||
|
||||
`宫苑内庭·旧痕回廊`
|
||||
|
||||
## 9.2 `opening`
|
||||
|
||||
- 玩家首次进入 `宫苑内庭`
|
||||
- `旧宫侍女` 作为开章角色
|
||||
- 她不给完整解释,只提醒“最近不该过去的回廊”
|
||||
- 系统自动开启章节任务:`查明内庭异动`
|
||||
|
||||
## 9.3 `expansion`
|
||||
|
||||
- 玩家需要先调查 `回廊暗格里的香囊` 或处理场景里的敌对压力
|
||||
- 任务 step 进入“确认这条旧痕到底指向谁”
|
||||
|
||||
## 9.4 `turning_point`
|
||||
|
||||
- 玩家在第二条线索 `花圃石座下的旧金牌` 中得到反证
|
||||
- 旧宫侍女此前的说法出现缺口
|
||||
- 当前理解从“单纯禁区提醒”转成“她知道旧案,但在刻意压着不说”
|
||||
|
||||
## 9.5 `climax`
|
||||
|
||||
- 玩家返回与 `旧宫侍女` 对话
|
||||
- 她承认这里只是旧案的一层外壳,并把下一跳 handoff 到:
|
||||
- `雨夜长街`
|
||||
- 或 `铸坊工场`
|
||||
- 当前章节任务进入可交付或已交付
|
||||
|
||||
## 9.6 `aftermath`
|
||||
|
||||
- `chronicle` 写入本章收束
|
||||
- 当前章节状态进入余波
|
||||
- Goal Stack 把下一步交接到新场景或下一段线索
|
||||
|
||||
这个例子里的玩家体感仍然是完整的“起承转合”,但系统实现上始终只在跑当前已有的五阶段。
|
||||
|
||||
这个例子说明:
|
||||
|
||||
**即使大主线还没结束,`宫苑内庭` 这个单独场景也已经能形成一章完整体验。**
|
||||
|
||||
---
|
||||
|
||||
## 10. MVP 落地顺序
|
||||
|
||||
## 阶段 A:先补数据层和首进判定
|
||||
|
||||
先做:
|
||||
|
||||
1. `openedSceneChapterIds`
|
||||
2. 场景首次进入 hook
|
||||
3. `chapter:scene:${sceneId}` 的章节 id 规则
|
||||
|
||||
验收标准:
|
||||
|
||||
- 同一场景只在第一次进入时开章节任务
|
||||
|
||||
## 阶段 B:把章节任务接到现有 questFlow
|
||||
|
||||
先做:
|
||||
|
||||
1. `buildChapterQuestForScene(...)`
|
||||
2. `chapterId`
|
||||
3. 场景 lead 与当前 quest step 的默认映射
|
||||
|
||||
验收标准:
|
||||
|
||||
- 章节任务能在现有 `steps + status` 下正常推进
|
||||
|
||||
## 阶段 C:让 chapterDirector 真正按场景章节输出
|
||||
|
||||
先做:
|
||||
|
||||
1. `ChapterState.sceneId`
|
||||
2. `ChapterState.chapterQuestId`
|
||||
3. `chapterDirector` 优先从当前章节任务推导 `stage`
|
||||
|
||||
验收标准:
|
||||
|
||||
- 当前章节标题与当前场景一致
|
||||
- 章节五阶段能和任务推进基本同步
|
||||
|
||||
## 阶段 D:补 NPC 章节职责与 handoff
|
||||
|
||||
先做:
|
||||
|
||||
1. 为每个场景补默认开章 NPC / 转折线索 / 收束对话
|
||||
2. 为每个场景补 handoff 规则
|
||||
3. 回写 `chronicle`
|
||||
|
||||
验收标准:
|
||||
|
||||
- 每个场景都能给出明确的阶段承担者与下一跳
|
||||
|
||||
---
|
||||
|
||||
## 11. 验收标准
|
||||
|
||||
做到以下几点,才算真正满足这次需求:
|
||||
|
||||
1. 玩家首次进入任一可达场景时,系统会自动开启该场景的章节任务。
|
||||
2. 每个场景章节都能在当前系统里跑出 `opening -> expansion -> turning_point -> climax -> aftermath` 的完整闭环,玩家体感上形成完整的起承转合。
|
||||
3. 每个场景至少能找到开章、承压、转折、收束这些阶段承担者,允许一人多阶段承担,但阶段职责不能缺。
|
||||
4. 章节任务不是孤立任务,而是当前章节在前台的动作面。
|
||||
5. 同一场景重复进入时,不会重复开章,但会继承已存在的章节状态或余波状态。
|
||||
6. 本章收束后,系统能明确交接下一场景或下一段主线程 lead。
|
||||
7. 这轮实现主要落在现有 `chapterDirector / questFlow / useStoryGeneration / goalDirector / storyChronicle` 上,不再另起一套章节运行时系统。
|
||||
|
||||
---
|
||||
|
||||
## 12. 最后结论
|
||||
|
||||
如果我们接受“每个场景都是一个章节单元”这条方向,那么当前仓库最该补的不是一套新系统,而是对现有系统的三处收紧:
|
||||
|
||||
1. 补上 `openedSceneChapterIds`
|
||||
2. 让 `ChapterState` 显式绑定 `sceneId + chapterQuestId`
|
||||
3. 让现有章节任务与现有五阶段直接挂钩
|
||||
|
||||
这样之后,现有系统会形成更简洁的收束关系:
|
||||
|
||||
- `scenePresets` 提供场景素材
|
||||
- `questFlow` 直接把场景 lead 落成章节任务
|
||||
- `chapterDirector` 用现有五阶段输出章节状态
|
||||
- `useStoryGeneration / sessionActions` 处理首进开章
|
||||
- `goalDirector` 把章节任务继续编译成玩家当前目标
|
||||
|
||||
最终玩家感受到的就不再是“我只是进了一个新场景”,而会更接近:
|
||||
|
||||
**我进入了这一章,接住了这一章的任务,见到了这一章该见的人,也在这一章里把一段局势真正走完了。**
|
||||
93
docs/design/UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md
Normal file
93
docs/design/UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 统一模态窗口设计 2026-04-25
|
||||
|
||||
## 背景
|
||||
|
||||
当前前端已有两套稳定视觉资产:
|
||||
|
||||
- 平台侧:`platform-overlay`、`platform-modal-shell`、`platform-auth-card` 等主题变量。
|
||||
- RPG 运行时:`pixel-nine-slice`、`pixel-modal-shell` 与 `UI_CHROME.modalPanel` 九宫格边框。
|
||||
|
||||
但弹窗结构仍分散在业务组件内,常见重复包括遮罩层、点击遮罩关闭、`role="dialog"`、`aria-modal`、移动端底部贴边、桌面居中、最大高度、滚动区域和关闭按钮。新增弹窗时容易出现 z-index、无障碍属性、移动端高度和视觉边界不一致。
|
||||
|
||||
## 目标
|
||||
|
||||
新增统一组件 `UnifiedModal`,只负责弹窗外壳和交互边界,不接管业务内容:
|
||||
|
||||
- 统一遮罩、面板、标题区、内容区、底部区结构。
|
||||
- 支持平台风与像素风两种外观,不混用两套视觉资产。
|
||||
- 默认移动端优先,平台风移动端底部弹出、桌面居中;像素风保持游戏内居中弹窗。
|
||||
- 默认提供 `role="dialog"`、`aria-modal`、标题关联、Escape 关闭和遮罩点击关闭。
|
||||
- 支持禁用关闭,用于生成中、保存中等不可打断流程。
|
||||
- 支持 Portal 渲染到 `document.body`,避免被父层 `overflow` 裁剪。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不一次性迁移所有旧弹窗,避免运行时大面积回归。
|
||||
- 不把业务按钮、表单、状态文案放进通用组件。
|
||||
- 不改变现有主题变量、九宫格素材、平台和 RPG 的视觉风格。
|
||||
- 不新增第三方弹窗库。
|
||||
|
||||
## 组件接口
|
||||
|
||||
`UnifiedModal` 核心参数:
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --- | --- |
|
||||
| `open` | 是否显示。为 `false` 时返回 `null`。 |
|
||||
| `variant` | `platform` 或 `pixel`。默认 `platform`。 |
|
||||
| `title` | 标题,同时作为默认 `aria-label` 来源。 |
|
||||
| `description` | 可选副标题,显示在标题下方。 |
|
||||
| `children` | 主内容区。 |
|
||||
| `footer` | 可选底部操作区。 |
|
||||
| `onClose` | 关闭回调。 |
|
||||
| `closeDisabled` | 禁止遮罩、Escape 和关闭按钮触发关闭。 |
|
||||
| `closeOnBackdrop` | 是否允许点击遮罩关闭,默认允许。 |
|
||||
| `showCloseButton` | 是否显示右上关闭按钮,默认显示。 |
|
||||
| `size` | `sm`、`md`、`lg`、`xl`、`fullscreen`。 |
|
||||
| `zIndexClassName` | z-index class,默认 `z-[90]`。 |
|
||||
| `panelClassName` / `bodyClassName` / `footerClassName` | 局部样式扩展。 |
|
||||
| `portal` | 是否渲染到 `document.body`,默认开启。 |
|
||||
|
||||
## 使用边界
|
||||
|
||||
### 平台风弹窗
|
||||
|
||||
用于平台首页、登录注册、作品结果、创作工作台等非 RPG 运行时界面。
|
||||
|
||||
要求:
|
||||
|
||||
- 使用 `variant="platform"`。
|
||||
- 面板使用 `platform-modal-shell` 主题变量。
|
||||
- 移动端优先底部贴边,大屏居中。
|
||||
- 不在弹窗内放功能说明式长文案,只放任务所需信息。
|
||||
|
||||
### 像素风弹窗
|
||||
|
||||
用于 RPG 运行时、地图、背包、角色详情、NPC 交易等游戏内面板。
|
||||
|
||||
要求:
|
||||
|
||||
- 使用 `variant="pixel"`。
|
||||
- 面板使用 `pixel-nine-slice pixel-modal-shell`。
|
||||
- 默认使用 `getNineSliceStyle(UI_CHROME.modalPanel)`。
|
||||
- 标题、内容和底部仍由业务方控制,避免通用组件内写入玩法解释。
|
||||
|
||||
## 首批迁移
|
||||
|
||||
首批只迁移平台入口创作类型弹窗:
|
||||
|
||||
- 文件:`src/components/platform-entry/PlatformEntryCreationTypeModal.tsx`
|
||||
- 目的:验证平台风布局、关闭禁用、标题区、内容区与错误区都可由统一组件承载。
|
||||
|
||||
后续可按风险由低到高迁移:
|
||||
|
||||
1. 结果页小弹窗:`PuzzleResultView`、`BigFishResultView`。
|
||||
2. 平台创作页编辑器弹窗:`RpgCreationEntityEditorShared` 内局部 `ModalShell`。
|
||||
3. RPG 运行时像素风弹窗:`RpgAdventurePanelOverlays`、`AdventureEntityModal`、`NpcModals`。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 新增弹窗优先使用 `UnifiedModal`,不再手写完整 overlay + panel 结构。
|
||||
- 迁移后的弹窗保留原有移动端和桌面布局。
|
||||
- 关闭按钮、遮罩关闭、Escape 行为一致,`closeDisabled` 时都不会关闭。
|
||||
- 类型检查、编码检查通过。
|
||||
192
docs/design/npc-conversation-situation-draft.md
Normal file
192
docs/design/npc-conversation-situation-draft.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# NPC 对话阶段与情景注入草案
|
||||
|
||||
## 目标
|
||||
|
||||
让 NPC 对话同时受三类因素控制,而不是只靠一大段 prompt 生硬约束:
|
||||
|
||||
1. 好感与信任阶段
|
||||
2. 角色三维表述风格
|
||||
3. 当前情景与刚刚共同经历
|
||||
|
||||
最终目标不是“少说设定”,而是“像真人一样按场合和关系逐步说”。
|
||||
|
||||
## 当前已经落地的控制层
|
||||
|
||||
### 1. 好感阶段
|
||||
|
||||
- `guarded`
|
||||
- 低好感
|
||||
- 只谈眼前局势、态度和试探
|
||||
- `partial`
|
||||
- 开始松口
|
||||
- 给出表层理由或半真半假的说明
|
||||
- `honest`
|
||||
- 逐步触及真实动机的轮廓
|
||||
- `deep`
|
||||
- 可以谈更深层的来历、目标和旧事
|
||||
|
||||
### 2. 三维表述风格
|
||||
|
||||
- `guardStyle`
|
||||
- `blunt` 直硬
|
||||
- `wary` 谨慎
|
||||
- `evasive` 回避
|
||||
- `measured` 克制
|
||||
- `warmStyle`
|
||||
- `dry` 冷淡
|
||||
- `steady` 平稳
|
||||
- `gentle` 温和
|
||||
- `teasing` 带点松弛感
|
||||
- `truthStyle`
|
||||
- `direct` 说真话时直给
|
||||
- `fragmented` 碎片式透露
|
||||
- `deflecting` 先绕一下再说
|
||||
|
||||
### 3. 情景注入
|
||||
|
||||
当前新增的情景标签:
|
||||
|
||||
- `first_contact_cautious`
|
||||
- 初见试探
|
||||
- `camp_first_contact`
|
||||
- 营地第一轮正式对接
|
||||
- `camp_followup`
|
||||
- 营地里承接上轮旧话头
|
||||
- `post_battle_breath`
|
||||
- 刚打完一轮冲突后的短暂松动
|
||||
- `shared_danger_coordination`
|
||||
- 危险未解除,优先短句对接
|
||||
- `private_followup`
|
||||
- 已经聊过一轮,不再是模板式初见
|
||||
|
||||
配套压力标签:
|
||||
|
||||
- `high`
|
||||
- `medium`
|
||||
- `low`
|
||||
|
||||
并补充:
|
||||
|
||||
- `recentSharedEvent`
|
||||
- 刚刚共同经历了什么
|
||||
- `talkPriority`
|
||||
- 这轮优先先说什么
|
||||
|
||||
## 设计原则
|
||||
|
||||
### 1. 把“知道什么”和“愿意说什么”拆开
|
||||
|
||||
角色完整设定始终存在,但 prompt 不应长期直接暴露:
|
||||
|
||||
- `reason`
|
||||
- `goal`
|
||||
- 完整背景
|
||||
- 旧事全貌
|
||||
|
||||
而是按阶段只注入:
|
||||
|
||||
- `surfaceHook`
|
||||
- `immediateConcern`
|
||||
- `guardedMotive`
|
||||
- `reason`
|
||||
- `goal`
|
||||
|
||||
### 2. 初见先谈现场,不先谈人生
|
||||
|
||||
无论玩家还是 NPC,初次见面都优先:
|
||||
|
||||
- 眼前危险
|
||||
- 当前判断
|
||||
- 彼此态度
|
||||
- 一点没说透的钩子
|
||||
|
||||
不优先:
|
||||
|
||||
- 完整来意
|
||||
- 长篇背景
|
||||
- “我们的目标一致”
|
||||
- 正式自我介绍
|
||||
|
||||
### 3. 刚打完怪时优先短句
|
||||
|
||||
`post_battle_breath` 和 `shared_danger_coordination` 两类情景下,对话应该:
|
||||
|
||||
- 先接刚才发生的事
|
||||
- 先评价判断或身手
|
||||
- 句子更短
|
||||
- 少做完整背景说明
|
||||
|
||||
## 当前实现路径
|
||||
|
||||
### 上下文字段
|
||||
|
||||
`StoryGenerationContext` 目前已经承载:
|
||||
|
||||
- 对话阶段控制
|
||||
- 三维风格
|
||||
- 情景标签
|
||||
- 压力级别
|
||||
- 最近共同经历
|
||||
- 本轮说话重点
|
||||
|
||||
### prompt 注入
|
||||
|
||||
当前 prompt 会显式加入:
|
||||
|
||||
- 当前 NPC 对话阶段控制
|
||||
- 当前对话情景控制
|
||||
|
||||
目的:
|
||||
|
||||
- 不让模型自己从一堆底层状态里猜场合
|
||||
- 先让系统做好裁决,再让模型负责“怎么说”
|
||||
|
||||
## 下一步建议
|
||||
|
||||
### 1. 把 `surfaceHook` 改成更口语、更像现场句
|
||||
|
||||
当前最大风险不是结构不够,而是字段文案还可能像“作者说明”。
|
||||
|
||||
应优先改成:
|
||||
|
||||
- 能直接对人说
|
||||
- 不像自我介绍
|
||||
- 不像任务摘要
|
||||
- 更像“站在现场会脱口而出的话”
|
||||
|
||||
### 2. 引入“问题命中”判断
|
||||
|
||||
不只看好感,也看玩家这次是不是问到了点上。
|
||||
|
||||
建议:
|
||||
|
||||
- 好感够,但问题没命中 -> 仍保留
|
||||
- 好感够,问题命中 -> 松口一层
|
||||
|
||||
### 3. 使用 `revealedFacts`
|
||||
|
||||
后续可把已公开的信息记下来,避免:
|
||||
|
||||
- 重复卖同一个关子
|
||||
- 前后口径反复横跳
|
||||
|
||||
### 4. 把开场第一段从通用剧情生成中进一步拆出
|
||||
|
||||
现在开场仍部分受通用剧情引擎影响。
|
||||
|
||||
更理想的方向:
|
||||
|
||||
- 开场先走纯对白生成
|
||||
- 对话定稿后再推导后续选项
|
||||
|
||||
这样语言会比“剧情导演 + JSON + 选项合法性”混合生成更自然。
|
||||
|
||||
## 验收重点
|
||||
|
||||
改完后重点看这几类表现是否成立:
|
||||
|
||||
1. 初见不再像互背设定卡
|
||||
2. 刚打完怪时,对话明显更短、更贴眼前
|
||||
3. 同一阶段下,不同性格角色表达方式确实不同
|
||||
4. 玩家和 NPC 都不会在第一轮自曝完整动机
|
||||
5. 同一个 NPC 连续几轮聊天时,信息释放节奏是连续的,不会忽冷忽热
|
||||
255
docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md
Normal file
255
docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# 冒险运行时开发经验沉淀
|
||||
|
||||
日期:2026-03-24
|
||||
|
||||
## 1. 这轮工作主要覆盖了什么
|
||||
|
||||
这轮迭代不是单点 UI 修改,而是同时改了 4 条链路:
|
||||
|
||||
1. 战斗演绎链路:近战突进、远程施法、投射物/特效、受击结算时机。
|
||||
2. 探索链路:向前探索、呼喊、NPC 离队、切换场景时的新 encounter 生成与入场动画。
|
||||
3. NPC function 链路:聊天、招募、观察征兆、交易、离队、上下文注入边界。
|
||||
4. 面板链路:队伍页、角色详情、背包页、移动端空间分配、入口 icon 语义。
|
||||
|
||||
这类项目最重要的判断是:
|
||||
很多需求表面看是“改个界面”或“改句文案”,实际同时影响状态机、动画时序、AI 提示词、实体生成规则和移动端布局。
|
||||
|
||||
## 2. 这轮最值得沉淀的结论
|
||||
|
||||
### 2.1 function 的职责边界必须先定死
|
||||
|
||||
后面事实证明,只有少数 function 应该负责生成新 encounter:
|
||||
|
||||
- `idle_explore_forward`
|
||||
- `idle_call_out`
|
||||
- `npc_leave`
|
||||
- 进入新场景
|
||||
|
||||
其他 function 如果也偷偷新增 NPC、怪物、宝箱,后面一定会出现这些问题:
|
||||
|
||||
- 剧情上下文越来越乱
|
||||
- 场景上实体数量失控
|
||||
- 玩家以为“聊天/招募/观察”也会强行推进世界
|
||||
- AI 生成内容和本地规则互相打架
|
||||
|
||||
经验:
|
||||
先定义“谁能创造世界实体”,再写文案和动画。
|
||||
|
||||
### 2.2 动画完成点必须和数值结算点绑定
|
||||
|
||||
这轮一个关键修正是:
|
||||
攻击特效播放完后,受击目标才扣血。
|
||||
|
||||
如果不这样做,玩家看到的就是:
|
||||
|
||||
- 特效还没打到,血条先掉了
|
||||
- 投射物还在飞,目标已经结算
|
||||
- dash 还没到位,攻击已经命中
|
||||
|
||||
经验:
|
||||
战斗系统里不能只写“播放动画”,必须写清楚:
|
||||
|
||||
1. 起手阶段是什么
|
||||
2. 位移阶段是什么
|
||||
3. 命中阶段是什么
|
||||
4. 哪个阶段结束后才改数值
|
||||
|
||||
### 2.3 视觉素材选择要按“语义 + 小尺寸可读性”来做
|
||||
|
||||
这轮做过两类视觉判断:
|
||||
|
||||
- 战斗特效素材该怎么挂到角色/技能上
|
||||
- 冒险页入口 icon 应该换成什么
|
||||
|
||||
经验不是“素材越花越好”,而是:
|
||||
|
||||
- 先看素材本身表达的动作语义
|
||||
- 再看缩小到按钮尺寸后是否还能一眼看懂
|
||||
- 最后才考虑风格统一
|
||||
|
||||
例如:
|
||||
|
||||
- 队伍入口用“盔甲”不如用“盾牌”更像角色/编队
|
||||
- 背包入口用真正的包袋图,比木板式 HUD 图更直观
|
||||
- 远程施法不移动时,特效就必须承担“动作已经发生”的视觉职责
|
||||
|
||||
### 2.4 角色型 NPC 和普通 encounter 不能混着处理
|
||||
|
||||
这轮踩过的坑说明:
|
||||
|
||||
- 可扮演但未入队的 NPC
|
||||
- 已入队同伴
|
||||
- 普通场景 NPC
|
||||
|
||||
这三者虽然都可能显示为 NPC,但数据完整度、立绘来源、详情页能力并不一样。
|
||||
|
||||
经验:
|
||||
|
||||
- 角色型 NPC 要按角色数据链路渲染
|
||||
- 普通 NPC 要按 encounter/NPC state 渲染
|
||||
- 详情弹窗必须对缺失字段做空值保护
|
||||
|
||||
否则就会出现点击小人直接报 `map` 相关错误这类问题。
|
||||
|
||||
### 2.5 角色和同伴的朝向/位移必须彼此独立
|
||||
|
||||
`idle_observe_signs` 的修正说明了一件事:
|
||||
如果主角和同伴在 transform、朝向、随机停顿上仍然存在隐含父子级关系,最后视觉表现一定不自然。
|
||||
|
||||
经验:
|
||||
|
||||
- 主角随机转向和同伴随机转向要分别计算
|
||||
- 位置、朝向、停留时长都要独立采样
|
||||
- 不要让父容器顺手把子角色的朝向也带过去
|
||||
|
||||
这条经验同样适用于:
|
||||
|
||||
- 招募入队时的新同伴 dash
|
||||
- 多角色待机观察
|
||||
- 场景内多实体同步演绎
|
||||
|
||||
### 2.6 大模型负责“推理与叙述”,本地规则负责“世界变更”
|
||||
|
||||
这轮对 `npc_chat`、`npc_recruit`、`idle_observe_signs` 的调整,本质上都指向同一个原则:
|
||||
|
||||
- 大模型可以生成观察结果、聊天内容、氛围描述
|
||||
- 大模型不应该偷偷新增实体、替玩家做决定、绕开本地规则结算
|
||||
|
||||
经验:
|
||||
|
||||
1. 聊天生成要明确禁止提及其他 function 行为。
|
||||
2. 招募对话可以引导到成功入队,但最终入队仍应由本地流程触发。
|
||||
3. `idle_observe_signs` 可以走大模型推理,但写入剧情上下文的内容要可控。
|
||||
4. `npc_recruit` 这种流程不要顺手给下次推理塞一个“新 NPC”。
|
||||
|
||||
一句话总结:
|
||||
AI 可以解释世界,但不能私自改世界。
|
||||
|
||||
### 2.7 移动端面板要优先保信息密度,不要保装饰
|
||||
|
||||
这轮背包和队伍页的调整很能说明问题:
|
||||
|
||||
- 队伍页只保留成员列表
|
||||
- 成员详情放到弹窗
|
||||
- 背包页去掉多余标题、提示文案、厚重背景框
|
||||
- 装备信息移到角色详情,不和背包抢空间
|
||||
|
||||
经验:
|
||||
|
||||
- 主面板只放“高频扫读信息”
|
||||
- 低频详情放二级弹窗
|
||||
- 任何重复信息都要尽量去重
|
||||
|
||||
在小屏上,空间不是拿来“显得完整”的,而是拿来“保证可操作”的。
|
||||
|
||||
## 3. 这轮最典型的踩坑记录
|
||||
|
||||
### 3.1 encounter 生成距离只改一处是不够的
|
||||
|
||||
一开始只是把某个函数里的怪物生成位置往后挪,但后来发现:
|
||||
|
||||
- 其他会生成 encounter 的 function 仍然太近
|
||||
- 新场景进入时也可能直接出现在屏幕里
|
||||
|
||||
经验:
|
||||
“从屏幕外进场、要走 4 秒距离”必须是统一约束,不是某个函数里的特判。
|
||||
|
||||
### 3.2 详情文案改源头不一定等于改到了最终显示层
|
||||
|
||||
这轮“选项小字太长”的问题最后证明:
|
||||
真正该改的是渲染层显示的 `detailText`,而不是只改某个上游数据源。
|
||||
|
||||
经验:
|
||||
用户说“没有生效”时,要优先检查最终渲染层,而不是只检查中间数据。
|
||||
|
||||
### 3.3 新同伴入队时,尺寸问题本质是缩放基准不统一
|
||||
|
||||
招募流程里位置正确但大小不对,说明问题不在路径,而在:
|
||||
|
||||
- 新同伴使用的缩放基准
|
||||
- 主角扮演角色使用的缩放基准
|
||||
|
||||
不一致。
|
||||
|
||||
经验:
|
||||
只要角色加入到主队镜头体系里,尺寸基准必须复用主角/同伴那套规则,不能临时另开一套。
|
||||
|
||||
### 3.4 背包和角色详情职责不清,会持续挤压移动端布局
|
||||
|
||||
这轮背包页一度同时承担:
|
||||
|
||||
- 物品网格
|
||||
- 装备总览
|
||||
- 装备卸下
|
||||
- 详情查看
|
||||
|
||||
最后结果就是移动端空间不够、信息层级混乱。
|
||||
|
||||
经验:
|
||||
|
||||
- 背包负责“物品”
|
||||
- 角色详情负责“装备”
|
||||
|
||||
职责一旦分清,后面很多 UI 冲突会自然消失。
|
||||
|
||||
## 4. 可复用的开发方法
|
||||
|
||||
### 4.1 新增一个 function 前,先问 6 个问题
|
||||
|
||||
1. 它会不会生成新 encounter?
|
||||
2. 它会不会写入后续推理上下文?
|
||||
3. 它的动画分几段?
|
||||
4. 哪一刻才算真正生效?
|
||||
5. 哪些内容由 AI 生成,哪些必须本地决定?
|
||||
6. 它是否需要从屏幕外入场?
|
||||
|
||||
这 6 个问题先答清,后面返工会少很多。
|
||||
|
||||
### 4.2 配战斗动画时,至少明确 4 个时点
|
||||
|
||||
1. 起手
|
||||
2. 位移/施法
|
||||
3. 特效命中
|
||||
4. 扣血/击退/结算
|
||||
|
||||
特别是:
|
||||
|
||||
- 近战攻击前的 dash
|
||||
- 远程不移动但要挂特效
|
||||
- 受击延后到命中特效之后
|
||||
|
||||
都属于这套时点设计。
|
||||
|
||||
### 4.3 做素材替换时,不要只看资源名
|
||||
|
||||
正确顺序更接近:
|
||||
|
||||
1. 打开素材看实际形状
|
||||
2. 判断它在当前语义里是不是“最像这个功能”
|
||||
3. 缩到真实 UI 尺寸再看一遍
|
||||
4. 再决定 active/inactive 怎么处理
|
||||
|
||||
### 4.4 做聊天流式界面时,反馈一定要插到正在发生的流里
|
||||
|
||||
这轮加“好感度 +x”提示后,更明确了一件事:
|
||||
|
||||
- 系统反馈不应该只藏在最终结果
|
||||
- 要插进聊天进行中的体验里
|
||||
- 文本流超出剧情框时要自动滚动
|
||||
|
||||
否则用户会错过真正重要的状态变化。
|
||||
|
||||
## 5. 以后继续做这类需求时,建议坚持的原则
|
||||
|
||||
- 先收拢 function 边界,再改剧情文案。
|
||||
- 先确定动画结算时序,再接特效素材。
|
||||
- 先做本地规则兜底,再让大模型生成文本。
|
||||
- 先保证移动端可扫读,再考虑装饰性面板。
|
||||
- 先复用已有角色/场景坐标体系,再做个别修正。
|
||||
- 先看最终显示层,再判断“改动是否生效”。
|
||||
|
||||
## 6. 这轮最重要的一句话总结
|
||||
|
||||
这类 AI 冒险 RPG 的开发,最难的不是“把功能做出来”,而是:
|
||||
|
||||
**让 function 边界、世界状态、视觉演绎、移动端面板和大模型文本在同一套规则下稳定协作。**
|
||||
@@ -0,0 +1,18 @@
|
||||
# Agent 空会话草稿可见性修正 2026-04-26
|
||||
|
||||
用户从创作中心点进 RPG 或大鱼吃小鱼工作台时,后端会立即创建 Agent session,并写入一条助手欢迎消息。但在用户尚未发送任何消息、也没有传入种子文本时,这个 session 只是临时工作区,不应进入“我的创作”草稿列表。
|
||||
|
||||
本次规则:
|
||||
|
||||
1. 只有存在用户消息、非空 seedText、真实草稿数据或已发布状态时,Agent session 才算作品草稿。
|
||||
2. 助手欢迎消息、默认 anchorPack、空 `{}` draftProfile 不算用户创作内容。
|
||||
3. 过滤必须落在后端 works 聚合层,前端创作中心只消费结果,不负责隐藏空草稿。
|
||||
4. RPG 仍保留已发布 profile 和孤立持久草稿 profile 的展示;未发布且仍有活跃 Agent session 的编译 profile 继续去重。
|
||||
|
||||
涉及入口:
|
||||
|
||||
- `server-rs/crates/spacetime-module/src/lib.rs`
|
||||
- `server-rs/crates/spacetime-module/src/custom_world/mod.rs`
|
||||
- `server-rs/crates/spacetime-module/src/big_fish/session.rs`
|
||||
|
||||
后续如果新增玩法创作 Agent,也必须复用同一判断:创建会话不等于创建草稿,作品列表只展示已经被用户实际开始编辑或已经生成结果的会话。
|
||||
210
docs/experience/AGENT_UI_CHANGELOG.md
Normal file
210
docs/experience/AGENT_UI_CHANGELOG.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# UI 改动记录(供后续 Agent 阅读)
|
||||
|
||||
本文档汇总 **像素 RPG UI 皮肤化** 相关实现与决策,便于新会话快速接手。更细的命名与规范见同目录上一级的 **`UI_CODING_STANDARD.md`**。
|
||||
|
||||
---
|
||||
|
||||
## 1. 相关文件一览
|
||||
|
||||
| 路径 | 作用 |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| `UI_CODING_STANDARD.md` | 资源目录约定、9-slice 规则、图标语义、`Icons`/`UI` 命名解读、已知问题(含世界按钮切片) |
|
||||
| `src/uiAssets.ts` | **唯一推荐** 的 UI 资源映射:`UI_CHROME`(9-slice 配置)、`TAB_ICONS`、`WORLD_SELECT_ICONS`、`getNineSliceStyle()` |
|
||||
| `src/components/PixelIcon.tsx` | 小图标 `<img>`,`image-rendering: pixelated` |
|
||||
| `src/index.css` | `.pixel-nine-slice`、`.pixel-root-shell` / `.pixel-app-shell`、tab/按钮布局类、`--ui-scale` |
|
||||
| `src/App.tsx` | 世界选择、角色卡、底部 tab、剧情/背包面板、地图弹窗、`MudMapRoom` |
|
||||
| `src/components/GameCanvas.tsx` | 场景名按钮(9-slice `Title_frame_m`) |
|
||||
| `vite.config.ts` | `root` / `envDir` 指向 `__dirname`,保证 `.env.local` 从项目根加载 |
|
||||
| `public/UI/`、`public/Icons/` | 静态资源(路径以 `/UI/...`、`/Icons/...` 引用) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构要点
|
||||
|
||||
### 2.1 9-slice(禁止整图 `background-size: 100% 100%` 拉框体)
|
||||
|
||||
- 使用 CSS **`border-image`** + **`fill`**,通过自定义属性注入切片参数。
|
||||
- 类名:**`pixel-nine-slice`**(定义在 `src/index.css`)。
|
||||
- 行内样式由 **`getNineSliceStyle(texture, overrides?)`** 生成(`src/uiAssets.ts`),设置 `--frame-src`、`--slice-*`、`--frame-pad-*`、`--frame-repeat`、可选 `--frame-base`(一般仅在图源中心确实透明时使用)。
|
||||
|
||||
### 2.2 响应与缩放
|
||||
|
||||
- `:root` 上 **`--ui-scale`**:`clamp`(桌面)+ 小屏媒体查询内固定约 `0.8`。
|
||||
- 边框宽度 = 切片像素 × `--ui-scale`,与 padding 同逻辑,避免移动端边框比例失控。
|
||||
|
||||
### 2.3 交互
|
||||
|
||||
- **`pixel-pressable`**:hover 用 `translateY` + `brightness`,**避免**对像素框体做 `scale()` 以免糊边。
|
||||
|
||||
### 2.4 全局背景
|
||||
|
||||
- **根布局**(`App.tsx` 最外层):`pixel-root-shell` + `Background_fill.png` 平铺 + 深色半透明渐变(替代纯 `#050505` 死底)。
|
||||
- **下半屏内容区** `pixel-app-shell`:同一纹理 + **更轻**的遮罩,让纹理更明显。
|
||||
- 开局标题区已去掉单独 `bg-zinc-950`,与根背景一致。
|
||||
|
||||
---
|
||||
|
||||
## 3. `UI_CHROME` 当前用途(速查)
|
||||
|
||||
以下为 `src/uiAssets.ts` 中主要键与界面位置的对应关系(切片数值以文件内为准):
|
||||
|
||||
| Key | 资源(示例) | 用途 |
|
||||
| ----------------------------------------- | ------------------------------------- | ------------------------------------------ |
|
||||
| `appBackground` | `Background_fill.png` | 根壳 + 下半屏平铺底 |
|
||||
| `worldButtonWuxia` / `worldButtonXianxia` | `1_orange_button` / `1_violet_button` | 开局武侠/仙侠(**条高 28px**,切片见下文) |
|
||||
| `characterCardFrame` | `pick_hero_frame` | 选角卡片 |
|
||||
| `tabActive` / `tabInactive` | `Shop_tab_picked` / `Shop_tab` | 底部「角色 / 冒险 / 背包」 |
|
||||
| `panel` | `Frame_bg_big_2` | 装备区等通用面板 |
|
||||
| `storyPanel` | `Dialogue_frame` | 剧情正文区 |
|
||||
| `inventoryPanel` | `Inventory_bg` | 背包条目 |
|
||||
| `statsPanel` | `Stats_bar` | 角色数值面板 |
|
||||
| `choiceButton` | `Options_bar` | 剧情选项按钮 |
|
||||
| `modalPanel` | `Popup_window` | 地图弹窗外壳 |
|
||||
| `infoPanel` | `Dialogue_frame` | 地图弹窗内「当前地点 / 可前往」信息块 |
|
||||
| `sceneTitle` | `Title_frame_m` | 战斗画布顶部场景名按钮 |
|
||||
| `mapRoomCell` | `Map_frame` | 地图节点卡片(`MudMapRoom`) |
|
||||
| `mapDiagramPanel` | `Frame_bg_big_2` | 地图关系图整体衬底 |
|
||||
|
||||
图标路径:`TAB_ICONS`、`WORLD_SELECT_ICONS`、`CHROME_ICONS`;装备槽与背包分类见 `getEquipmentSlotIcon` / `getInventoryCategoryIcon`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 已知坑(必读)
|
||||
|
||||
### 4.1 世界选择按钮「中间发空」
|
||||
|
||||
- 图源 **`1_orange_button.png` / `1_violet_button.png` 为 125×28**。
|
||||
- 若 **`slice.top + slice.bottom >= 28`**,中间横带高度为 **0**,`border-image` 的 `fill` 异常,看起来像透明/没画上。
|
||||
- **正确做法**:减小上下切片(当前为 **9+9**),并配合 `repeat: 'stretch'` 竖向拉伸条形成品。
|
||||
- **不推荐**:用大色块 `baseColor` 糊底(与素材内渐变/内框不一致)。详见 `UI_CODING_STANDARD.md`「已知问题」。
|
||||
|
||||
### 4.2 新增 9-slice 前
|
||||
|
||||
先读 PNG **宽高**,保证 **`top+bottom < height`** 且 **`left+right < width`**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 环境与运行(与 UI 无关但易踩坑)
|
||||
|
||||
- LLM:`VITE_LLM_*` 写在项目根 **`.env.local`**;因 `vite.config.ts` 固定 `envDir: __dirname`,从任意 cwd 启动也应能读到。
|
||||
- 开发:`npm run dev`(默认端口见 `package.json`)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 尚未统一成 UI 图、仍用 Tailwind 小块面的区域(可选后续)
|
||||
|
||||
若产品要求「全盘无纯色板」,可继续替换,当前仍可能为 `bg-black/20`、`rounded-lg border` 等:
|
||||
|
||||
- 角色页装备行、属性格子
|
||||
- 地图弹窗顶栏分隔、关闭按钮外圈
|
||||
- `GameCanvas` 内血条、名字条等 HUD
|
||||
|
||||
---
|
||||
|
||||
## 7. 修改清单摘要(按主题)
|
||||
|
||||
1. **资源规范**:`UI_CODING_STANDARD.md` + 集中映射 `uiAssets.ts`。
|
||||
2. **9-slice 系统**:`index.css` + `getNineSliceStyle`。
|
||||
3. **开局 / 主界面**:世界按钮、选角卡、tab、面板、选项、背包、根与内容区背景纹理。
|
||||
4. **地图弹窗**:外壳、信息板、节点 `Map_frame`、关系图 `Frame_bg_big_2`。
|
||||
5. **画布**:场景名 `Title_frame_m`。
|
||||
6. **世界按钮**:按真实像素尺寸修正切片,去掉错误 `baseColor` 方案。
|
||||
7. **Vite**:`root`/`envDir` 保证环境变量加载稳定。
|
||||
|
||||
---
|
||||
|
||||
## 8. 2026-04-18 / 2026-04-20 账号入口补充记录
|
||||
|
||||
- 早期方案曾在 `AuthGate` 层提供右上角全局账号信息条,并在 `GameShellRuntime` 中临时隐藏。
|
||||
- 2026-04-20 起,这个全局悬浮入口已整体下线,不再区分“平台显示 / 冒险隐藏”。
|
||||
- 原因是右上角高频观察区不适合承载账号入口,且平台内已经有更明确的页面内入口。
|
||||
- 当前账号相关入口统一保留在平台首页受保护动作、个人页、存档页与账号弹窗,不再占用全局悬浮层。
|
||||
|
||||
---
|
||||
|
||||
## 9. 2026-04-20 等级 HUD / 冒险布局补充
|
||||
|
||||
- 当前运行中的等级 UI 已从 `AdventurePanel` 底部移出,改为放在 `GameShellRuntime` 左上角固定 HUD,避免把主对话区挤短。
|
||||
- 左上角 HUD 复用 `CharacterInfoShared.tsx` 里的 `PlayerLevelProgress`,角色面板、实体详情、游戏 HUD 使用同一套等级进度表现。
|
||||
- `AdventurePanel` 不再承担等级条展示,底部交互区只保留队伍 / 背包 / 刷新 / 退出聊天 / 选项 / 自定义输入,并压缩了底部留白与面板间距。
|
||||
- 角色信息不只在总 HUD 里显示:`CharacterPanel` 的队伍成员卡、角色详情面板,以及 `AdventureEntityModal` 的实体详情头部都会展示角色身份与等级信息。
|
||||
- 队长展示正式 `Lv.`;同行角色展示“参考 Lv.”;NPC 优先展示运行时 `levelProfile.level`,这样 UI 只负责表现,不在前端虚构额外成长逻辑。
|
||||
- 左上角等级 HUD 不使用背景框体,仅保留 `Lv`、等级数字与极细经验线,避免遮挡场景背景与移动端视野。
|
||||
|
||||
---
|
||||
|
||||
## 10. 2026-04-20 平台亮色主题主 Tab 修正
|
||||
|
||||
- `PlatformHomeView.tsx` 的四个主 Tab(首页 / 创作 / 存档 / 我的)现在统一挂在 `platform-remap-surface` 下,让亮色主题能接管历史遗留的 `text-zinc-*`、`bg-black/*`、`border-white/*` 组合。
|
||||
- 平台首页卡片覆层不要在组件里继续写死深色 `rgba(8,10,14,...)` 渐变;这次已收口为 `--platform-card-overlay-soft`、`--platform-card-overlay-strong`、`--platform-card-overlay-deep`,明暗主题都从 token 走。
|
||||
- 平台桌面顶栏里的账号头像、移动端底部主 Tab 分隔线,也不要保留暗色主题时留下的固定蓝色渐变和深色边线,应直接使用平台主题变量(如 `--platform-profile-avatar-fill`、`--platform-line-soft`)。
|
||||
- 后续如果继续调整平台主 Tab 视觉,优先改 `src/index.css` 的平台主题 token 和 remap 规则;只有 token 无法表达时,再做局部组件样式补丁,避免亮色主题再次出现“页面整体是亮的,但局部卡片仍是暗的”。
|
||||
- 参考图方向已明确:平台亮色主题应以白色为主底色,粉红只承担背景气氛和重点 CTA,不应让整页主壳继续像深粉底板。
|
||||
- 移动端底部 `platform-bottom-nav` 的 Tab 激活态必须与默认态使用同一套盒模型;边框要预占位,不能在 onPress / active 时临时增加边框导致按钮尺寸和留白跳变。
|
||||
- 2026-04-20 第二轮细查补色时,继续把 `PlatformWorldDetailView.tsx`、`PlatformHomeView.tsx`、`PreGameSelectionFlow.tsx` 里落在白底/浅底面板上的标题、说明、次级标签、搜索栏和加载兜底文本显式切回平台亮色 token,避免亮色主题下继续出现浅底白字或过浅灰字。
|
||||
- 2026-04-20 第三轮修正方向后,平台首页移动端底部 `platform-bottom-nav` 的高度、内边距、按钮圆角、图标尺寸、标签字号统一收口到 `src/index.css` token;`PlatformHomeView.tsx` 只保留结构类,避免 `h-14`、容器 padding、按钮内部内容间距和 active 底座各自维护半套尺寸,导致选中态看起来比 Tab 槽位更矮或更高。
|
||||
- 2026-04-20 第四轮把平台亮色主题顶部过重的红色收轻:`--platform-body-fill`、`--platform-hero-fill`、`--platform-shell-glow-*` 与 `--platform-surface-glow-*` 改成更接近暖白 + 浅珊瑚的低饱和版本,首页 / 创作页 / 详情页 Hero 覆层统一改走 `--platform-hero-overlay-strong`,避免组件里继续写死高饱和粉红渐变。
|
||||
|
||||
---
|
||||
|
||||
## 11. 2026-04-20 创作 Agent 聊天工作台亮色主题补色
|
||||
|
||||
- `src/components/custom-world-agent/*` 这一条创作 Agent 工作台链路已统一切回 `platform-subpanel`、`platform-input`、`platform-button`、`platform-banner`、`platform-progress-track`,亮色主题下不再继续裸露 `bg-[#111318]`、`bg-black/*`、`bg-white/*`、`text-white` 这类历史深色残留。
|
||||
- 聊天线程中的用户气泡、助手气泡、系统消息、推荐回复按钮、流式回复态统一映射到平台 token;后续如果继续调整创作 Agent 聊天视觉,优先改平台 token 或平台 class,不要在组件里再单独写一套聊天色板。
|
||||
- 顶栏、操作横幅、进度条、输入框的状态色统一复用平台亮暗主题变量,避免再次出现“页面整体已切亮色,但 Agent 局部还是旧暗色弹层”的割裂感。
|
||||
|
||||
---
|
||||
|
||||
## 12. 2026-04-20 NPC 聊天退出恢复与文本阅读性修正
|
||||
|
||||
- `AdventurePanel.tsx` 的叙事 `storyText` 已取消斜体,改为更大的正文尺寸,避免长段阅读时发飘。
|
||||
- 冒险面板里的 `actionText` 统一上调到聊天态同级字号;`detailText` 不再默认渲染,保持底部选项区更清爽。
|
||||
- `npcEncounterActions.ts` 在“退出聊天”后重新续写剧情时,会优先把当前故事里最近一轮已经呈现给玩家的非聊天选项文案并回 `optionCatalog`,避免高好感聊天收束后又退回 NPC 静态 fallback 文案。
|
||||
|
||||
---
|
||||
|
||||
## 13. 2026-04-21 创作中心失效草稿恢复兜底
|
||||
|
||||
- `src/components/rpg-entry/useRpgEntryLibraryDetail.ts` 现在会识别 `custom-world agent session` 的 `404 NOT_FOUND` 读取失败,不再把这类错误直接冒泡成未捕获 Promise。
|
||||
- 当用户在创作中心点击“继续创作”命中失效草稿时,前端会主动清空 `customWorldSessionId` 恢复参数,并刷新一次 works 列表,避免刷新页面后反复尝试恢复同一个坏会话。
|
||||
- 当前交互已收口成平台内可见提示:用户会停留在创作中心,并看到“这份共创草稿已失效,已为你返回创作中心,请重新开始创作。”,而不是卡在空白工作区或只在控制台看到英文异常。
|
||||
- 这次兜底只处理失效会话恢复,不改变正常草稿继续创作、结果页恢复和已发布作品进入世界的主链。
|
||||
|
||||
---
|
||||
|
||||
## 14. 2026-04-24 Agent 工作区恢复指针按用户隔离
|
||||
|
||||
- `custom-world agent session` 现在由 `server-rs` Axum 路由接入 SpacetimeDB procedure,模块内按 `owner_user_id + session_id` 查询;前端恢复旧工作区前必须确认本地指针属于当前登录用户,否则旧账号残留会先请求一次 `/api/runtime/custom-world/agent/sessions/:sessionId` 并产生 404。
|
||||
- `src/services/customWorldAgentUiState.ts` 的 URL 仍只保留 `customWorldSessionId` / `customWorldOperationId`,用户归属只写入 `sessionStorage`,避免把 `userId` 暴露到可分享链接里。
|
||||
- `src/components/rpg-entry/useRpgCreationSessionController.ts` 在恢复初始工作区时会对比 `ownerUserId`,发现不是当前用户就清空恢复指针并停留在创作入口,不再打后端失效 session。
|
||||
- 后续新增 Agent 类恢复入口时,同样要区分“可分享的 URL 指针”和“仅本机使用的登录用户归属”,不要只凭 sessionId 自动恢复受保护资源。
|
||||
|
||||
---
|
||||
|
||||
## 15. 2026-04-24 多玩法 Agent 聊天顶部文案统一隐藏
|
||||
|
||||
- `CreationAgentWorkspace` 已支持在 `title` 与 `assistantSummary` 为空时只展示返回、主操作、进度与锚点区域;各玩法适配层不要再传入“世界共创 / 玩法共创”这类模块标题或引导副文案。
|
||||
- `custom-world`、`big-fish`、`puzzle` 三条 Agent 聊天工作区现在统一隐藏顶部标题与标题下方说明,避免只有 RPG / 自定义世界生效、其他玩法模板仍残留旧文案。
|
||||
- 后续新增玩法模板时,聊天页顶部模块应保持清爽:必要状态放进进度、操作横幅或聊天消息,不把功能说明类文案默认写入 UI。
|
||||
|
||||
---
|
||||
|
||||
## 16. 2026-04-24 创作结果页亮色主题细节补色
|
||||
|
||||
- RPG / 拼图 / 大鱼结果页根容器统一挂 `platform-remap-surface`,让亮色主题能接管遗留的 `text-white`、`text-zinc-*`、`bg-white/*`、`bg-black/*` 和状态色工具类。
|
||||
- 拼图与大鱼结果页顶部 Hero 只增加 `platform-result-hero` 语义类,不改变整体布局;亮色主题下由 `src/index.css` 统一换成暖白底、轻粉高光和平台主按钮色。
|
||||
- 地图弹窗新增 `map-modal-overlay`、`map-modal-shell`、`map-modal-backdrop`、`map-modal-shade`、`map-info-panel` 语义类;亮色主题通过这些类降低暗色遮罩、提亮地图背景、统一节点卡与连线颜色。
|
||||
- 结果页中保存、生成、发布等旧的 `bg-amber-600` / `bg-cyan-600` / `bg-cyan-200` 按钮,在 `platform-remap-surface` 内被映射回 `platform-button--primary` 同款渐变,避免亮色主题下按钮体系割裂。
|
||||
- 后续继续做结果页 UI 细节时,优先补语义 class + `src/index.css` 的 light remap,不要在每个结果页组件里复制一套亮色配色,也不要调整页面整体布局结构。
|
||||
|
||||
---
|
||||
|
||||
## 17. 2026-04-26 创作编辑器关闭确认弹窗亮色主题修正
|
||||
|
||||
- `RpgCreationEntityEditorShared.tsx` 的未保存关闭确认统一收口为 `CloseConfirmDialog`,弹窗只保留确认信息和两个动作,不新增说明文案。
|
||||
- `CloseConfirmDialog` 通过 `platform-close-confirm-dialog` 语义类接入平台主题 token;提示块使用 `--platform-warm-*`,确认按钮使用 `--platform-button-primary-*`,继续编辑按钮使用 `--platform-neutral-*`。
|
||||
- 后续新增关闭 / 退出确认面板时,不要继续复制 `text-amber-50`、`text-sky-50`、`bg-black/*` 这类深色 Tailwind 组合;优先复用语义类,避免亮色主题出现浅底白字和按钮文字不可读。
|
||||
|
||||
---
|
||||
|
||||
_文档目的:交接给下一个 Agent 时,优先读本文件 + `UI_CODING_STANDARD.md`,再改 `uiAssets.ts` / `App.tsx` / `index.css`。_
|
||||
262
docs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md
Normal file
262
docs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Codex 实战经验沉淀
|
||||
|
||||
日期:`2026-03-24`
|
||||
|
||||
## 1. 先判断需求属于哪条链路
|
||||
|
||||
这个项目几乎所有需求都不是单点 UI 改动,通常会同时影响几条链路:
|
||||
|
||||
- 叙事链路:AI 剧情、提示词、选项文案
|
||||
- 状态链路:`GameState`、NPC 状态、背包、队伍、委托
|
||||
- 演出链路:屏幕外进场、战斗播放、实体站位、动画与特效
|
||||
- 工具链路:编辑器、校验脚本、存档兼容、smoke
|
||||
|
||||
经验:
|
||||
|
||||
- 每次动手前先判断“这次主要影响哪几条链路”,不要把需求误判成单纯的 UI 需求。
|
||||
- 只改表现、不改状态,最终一定会返工。
|
||||
- 只改状态、不补校验,后面也一定会返工。
|
||||
|
||||
## 2. 先补状态模型,再补交互
|
||||
|
||||
这类项目里,最稳定的顺序永远是:
|
||||
|
||||
1. 先补类型与状态字段
|
||||
2. 再补规则函数
|
||||
3. 再补 hook 流程
|
||||
4. 最后接 UI
|
||||
|
||||
已经反复验证有效的例子:
|
||||
|
||||
- `quests`
|
||||
- `playerEquipment`
|
||||
- `playerCurrency`
|
||||
- `roster`
|
||||
- `companions`
|
||||
- `currentNpcBattleMode`
|
||||
- `sparReturnEncounter`
|
||||
|
||||
经验:
|
||||
|
||||
- 如果一个功能需要“长期留存”,就不要只存在于局部组件 state。
|
||||
- 先建模后接按钮,比先堆按钮后补状态稳定得多。
|
||||
|
||||
## 3. AI 负责叙事,本地负责规则
|
||||
|
||||
项目里最稳的边界是:
|
||||
|
||||
- AI 负责:
|
||||
- `storyText`
|
||||
- 对话文本
|
||||
- 选项的自然语言表达
|
||||
- 本地规则负责:
|
||||
- 交易是否合法
|
||||
- 招募是否成立
|
||||
- 装备是否生效
|
||||
- 委托进度是否完成
|
||||
- 掉落、货币、好感、队伍编成
|
||||
|
||||
经验:
|
||||
|
||||
- 只要涉及数值、资源、状态迁移,就尽量不要让大模型即兴决定。
|
||||
- 给模型的提示词应该描述“局面”和“边界”,不要让它代替规则系统。
|
||||
|
||||
## 4. 固定选项提示不要写得太死
|
||||
|
||||
一个重要经验是:
|
||||
|
||||
- 模型需要知道每个 `functionId` 的核心含义
|
||||
- 但不需要看到“当前默认文案 / 补充信息 / 实际行为”这种过于细碎、强绑定的结构
|
||||
|
||||
更好的方式是:
|
||||
|
||||
- 保留 `functionId`、数量、顺序
|
||||
- 只提供“这个 function 的核心语义参考”
|
||||
- 让模型重写更自然、连续的 `actionText`
|
||||
|
||||
经验:
|
||||
|
||||
- 提示词越像表单,模型越容易产出僵硬选项。
|
||||
- 提示词越像“约束 + 语义边界”,剧情越自然。
|
||||
|
||||
## 5. 面前实体的提示词必须和主角对称
|
||||
|
||||
如果主角有:
|
||||
|
||||
- 描述
|
||||
- 性格
|
||||
- 状态
|
||||
- 属性
|
||||
|
||||
那么“当前面前实体”也应该尽量有同样结构。
|
||||
|
||||
经验:
|
||||
|
||||
- 只给一句“某 NPC 在这里活动”太粗,会削弱模型对局面的把握。
|
||||
- 面前实体和主角描述层级一致后,模型更容易写出有来回感、对称感的叙事。
|
||||
- 对生命/灵力这类状态,离散分档文本比裸数字更利于模型理解。
|
||||
|
||||
## 6. 屏幕外进场一定要抽成统一工具
|
||||
|
||||
这类项目很容易在多个地方各写一套“从屏幕外进入”的逻辑,结果出现:
|
||||
|
||||
- 同一实体重复进场
|
||||
- 先进入屏幕,又被拉回屏幕外再进一次
|
||||
- 多怪时只动第一个,其他直接跳终点
|
||||
|
||||
这次稳定下来的方法是:
|
||||
|
||||
- 抽统一的过渡工具
|
||||
- `buildEncounterEntryState`
|
||||
- `buildEncounterTransitionState`
|
||||
- `interpolateEncounterTransitionState`
|
||||
- 所有进场逻辑都复用这一套
|
||||
- 区分两种场景:
|
||||
- 真正从屏幕外冲入
|
||||
- 已经在屏内预览,只是收敛到正式位置
|
||||
|
||||
经验:
|
||||
|
||||
- “屏幕外进入”本质上不是动画问题,而是状态过渡问题。
|
||||
- 一旦同时存在 preview / call_out / resolve / replay,就必须统一插值逻辑。
|
||||
|
||||
## 7. 多实体系统里,不要默认“只处理第一个”
|
||||
|
||||
这个坑非常常见:
|
||||
|
||||
- 场景配置里有多个怪
|
||||
- 运行时逻辑却只用 `monsterIds[0]`
|
||||
- 或者动画只插值 `sceneMonsters[0]`
|
||||
|
||||
经验:
|
||||
|
||||
- 只要数据结构已经允许数组,就尽量按“整组”处理。
|
||||
- 即便最后 UI 只重点展示一个,也不要在底层逻辑里偷偷退化成单体。
|
||||
|
||||
## 8. 招募系统不要只做“当前队伍”
|
||||
|
||||
如果只有 `companions` 而没有 `roster`,后面一定会遇到这些问题:
|
||||
|
||||
- 队伍满员时必须强制覆盖旧同伴
|
||||
- 已招募角色很难转成待命
|
||||
- 营地/编队功能没法闭环
|
||||
|
||||
这次稳定下来的模型是:
|
||||
|
||||
- `companions`:当前上阵
|
||||
- `roster`:已招募但待命
|
||||
|
||||
经验:
|
||||
|
||||
- 只要项目里有招募,迟早就要有 roster。
|
||||
- roster 不只是 UI 功能,而是状态层能力。
|
||||
|
||||
## 9. 装备系统不要只做展示
|
||||
|
||||
装备真正形成闭环,至少要同时做到:
|
||||
|
||||
- 背包里可装备 / 卸下
|
||||
- 装备改变真实属性
|
||||
- 战斗行为读取装备加成
|
||||
- 存档兼容旧存档
|
||||
|
||||
经验:
|
||||
|
||||
- “装备栏能显示”不算完成。
|
||||
- 只有真正影响 `maxHp / maxMana / damage / incomingDamage`,它才是玩法系统。
|
||||
|
||||
## 10. 交易系统最好统一成货币价值模型
|
||||
|
||||
一开始按“品质交换”虽然简单,但很快会遇到问题:
|
||||
|
||||
- 不同类别物品难比较
|
||||
- 直接购买不好接
|
||||
- 后面加入售卖、任务赏金、宝藏货币时会冲突
|
||||
|
||||
更稳定的做法是:
|
||||
|
||||
- 所有物品都有统一价值
|
||||
- NPC 商品有购买价
|
||||
- 玩家物品有回收价
|
||||
- 货币作为通用交换媒介
|
||||
|
||||
经验:
|
||||
|
||||
- 一旦出现货币,就尽量让交易系统全面切成“价值模型”。
|
||||
- 不要同时长期维护“品质交换”和“货币购买”两套完全不同的判定逻辑。
|
||||
|
||||
## 11. 编辑器要先做保存前校验
|
||||
|
||||
编辑器进入“可持续生产内容”阶段后,最优先的不是视觉,而是:
|
||||
|
||||
- 保存前校验
|
||||
- 非法引用提示
|
||||
- 数值边界检查
|
||||
|
||||
经验:
|
||||
|
||||
- 编辑器最怕的不是“不够漂亮”,而是“保存成功但运行时报错”。
|
||||
- 只要内容开始增多,校验脚本和保存前校验就必须尽早接入。
|
||||
|
||||
## 12. 每次大改后都要补 smoke
|
||||
|
||||
对这个项目来说,`lint + build` 不够。
|
||||
|
||||
至少要补 smoke 的场景包括:
|
||||
|
||||
- 委托接取 -> 推进 -> 交付
|
||||
- 多怪遭遇
|
||||
- 装备加成
|
||||
- 队伍编成
|
||||
- 交易价值与直接购买
|
||||
- 进场插值
|
||||
|
||||
经验:
|
||||
|
||||
- 只靠人工点点看,很容易漏掉状态分支。
|
||||
- smoke 不一定要重,但要覆盖关键闭环。
|
||||
|
||||
## 13. 兼容旧存档要同步做
|
||||
|
||||
每次给 `GameState` 新增字段时,都要同步考虑:
|
||||
|
||||
- 默认值
|
||||
- 存档读取兼容
|
||||
- 旧字段缺失时如何补全
|
||||
|
||||
经验:
|
||||
|
||||
- 旧存档兼容不是“最后再说”的工作。
|
||||
- 新字段一旦进 `GameState`,就应当同一轮把持久化兼容补上。
|
||||
|
||||
## 14. 不要在坏文件上无限缝补
|
||||
|
||||
这次实际踩到过一个很明显的坑:
|
||||
|
||||
- 某些文件本身已经混入大量乱码或结构损坏
|
||||
- 在原地做小 patch 会越来越难维护
|
||||
|
||||
更稳的做法是:
|
||||
|
||||
- 保留接口
|
||||
- 整文件重写成干净版本
|
||||
- 再接回现有调用
|
||||
|
||||
经验:
|
||||
|
||||
- 当一个文件已经进入“局部 patch 很难保证正确”的状态时,重写往往比继续缝补更省时间。
|
||||
|
||||
## 15. 后续继续迭代时的建议顺序
|
||||
|
||||
如果继续推进这个项目,建议优先顺序:
|
||||
|
||||
1. 先清理中文乱码高频文件
|
||||
2. 再继续精英/Boss 层
|
||||
3. 再补营地关系事件
|
||||
4. 再做编辑器差异预览 / 导入导出
|
||||
|
||||
## 16. 一句话总结
|
||||
|
||||
这个项目最重要的经验不是“多写了多少功能”,而是:
|
||||
|
||||
**凡是会同时影响叙事、状态、演出和工具链的需求,都要先统一边界,再落实现。**
|
||||
277
docs/experience/CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md
Normal file
277
docs/experience/CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Codex Past Work Experience Summary
|
||||
|
||||
日期:`2026-03-23`
|
||||
|
||||
## 1. 工作范围概览
|
||||
|
||||
这几轮工作主要集中在 4 个方向:
|
||||
|
||||
1. 编辑器体系整理
|
||||
2. NPC 视觉编辑与素材接入
|
||||
3. 玩家角色与怪物动画资源纠偏
|
||||
4. 选项行为编辑器与预览链路升级
|
||||
|
||||
这些改动不是孤立的 UI 修补,而是横跨了:
|
||||
|
||||
- 资源定义层
|
||||
- 编辑器字段层
|
||||
- 运行时预览层
|
||||
- 游戏真实播放逻辑层
|
||||
|
||||
## 2. 已完成的核心工作
|
||||
|
||||
### 2.1 编辑器入口与页签整理
|
||||
|
||||
- 当时曾保留 `/preset-editor`、`/npc-editor`、`/function-editor`
|
||||
- 当时还新增过 `/behavior-editor` 作为“选项行为”编辑页别名
|
||||
- 将原先单独的 `NPC 视觉` 标签并回 `NPC` 编辑页
|
||||
- 将 `Function` 页签改名为 `选项行为`
|
||||
|
||||
结论:
|
||||
- 独立编辑器入口如果没有继续接入主流程,应及时物理删除,不要长期保留兼容壳
|
||||
- 页签命名要贴近创作者语言,而不是内部实现命名
|
||||
|
||||
### 2.2 NPC 视觉模块并入 NPC 编辑
|
||||
|
||||
完成内容:
|
||||
|
||||
- 当时曾将 `NpcVisualEditor` 嵌入 `PresetEditor` 的 NPC 编辑页
|
||||
- 让 NPC 文本字段与视觉字段围绕同一个当前选中 NPC 联动
|
||||
- 保留视觉覆盖保存与全局布局保存能力
|
||||
|
||||
经验:
|
||||
|
||||
- NPC 文本编辑和 NPC 视觉编辑不应分裂成两个互不关联的工作流
|
||||
- “当前选中的 NPC” 必须是两个模块共享的单一数据源
|
||||
|
||||
### 2.3 Medieval NPC 素材定义重建
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [medievalNpcVisuals.ts](/E:/Repos/Genarrative/src/data/medievalNpcVisuals.ts) 中重建了 Medieval NPC 的资产定义
|
||||
- 补齐了 cloth / leather / metal / melee / magic / ranged 六大类真实素材
|
||||
- 为素材增加了:
|
||||
- 语义化名称
|
||||
- 图块尺寸
|
||||
- 列数
|
||||
- 帧数
|
||||
- 姿态选项
|
||||
- 让编辑器不再直接使用文件名、序号名作为展示项
|
||||
|
||||
经验:
|
||||
|
||||
- 编辑器下拉项如果来自手写数组,迟早会和真实素材目录脱节
|
||||
- 素材定义最好具备“资产元数据”,而不是只有路径字符串
|
||||
- 一旦资产存在大图块,就不能再默认所有图块都是 `32x32`
|
||||
|
||||
### 2.4 NPC 动画器支持大图块武器
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [MedievalNpcAnimator.tsx](/E:/Repos/Genarrative/src/components/MedievalNpcAnimator.tsx) 中为 `AtlasSprite` 增加:
|
||||
- `tileWidth`
|
||||
- `tileHeight`
|
||||
- 对齐偏移支持
|
||||
|
||||
效果:
|
||||
|
||||
- 长柄武器
|
||||
- 巨剑
|
||||
- 64x32 远程武器
|
||||
- 64x64 投石索类武器
|
||||
|
||||
都能正确显示,不再被按 `32x32` 裁坏。
|
||||
|
||||
经验:
|
||||
|
||||
- 视觉编辑器一旦涉及装备 atlas,就必须把“资源尺寸”从数据层带到渲染层
|
||||
|
||||
### 2.5 玩家角色动画映射纠偏
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [characterPresets.ts](/E:/Repos/Genarrative/src/data/characterPresets.ts) 中重新核对 5 个玩家角色的 Hero 动画目录
|
||||
- 修正了错误帧数、错误前缀、遗漏动作
|
||||
- 补齐了真实存在但之前未接入的动作:
|
||||
- `acquire`
|
||||
- `climb`
|
||||
- `dash`
|
||||
- `die`
|
||||
- `double jump`
|
||||
- `hurt`
|
||||
- `jump`
|
||||
- `jump attack`
|
||||
- `wall slide`
|
||||
- 给角色动画配置增加了 `file` 字段,支持单文件动画
|
||||
|
||||
相关文件:
|
||||
|
||||
- [types.ts](/E:/Repos/Genarrative/src/types.ts)
|
||||
- [CharacterAnimator.tsx](/E:/Repos/Genarrative/src/components/CharacterAnimator.tsx)
|
||||
- [characterCombat.ts](/E:/Repos/Genarrative/src/data/characterCombat.ts)
|
||||
|
||||
经验:
|
||||
|
||||
- 只要编辑器允许用户切“预览动作”,就不能让未映射动作静默 fallback 到 `idle`
|
||||
- 正确做法是:
|
||||
1. 先补齐真实动作映射
|
||||
2. 再让预览下拉只显示当前角色实际可用动作
|
||||
|
||||
### 2.6 怪物动画空白帧修复
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [monsterPresets.ts](/E:/Repos/Genarrative/src/data/monsterPresets.ts) 中把怪物动画从“连续帧猜测”改成“按图集行起点取帧”
|
||||
- 补上缺失的 `die` 配置
|
||||
- 清除了所有落进空白格的动画段
|
||||
|
||||
经验:
|
||||
|
||||
- 像素怪物图集不一定按一个连续区段排完整套动作
|
||||
- 如果动作配置只写 `start + frames`,但没结合图集行结构,就非常容易踩进空白帧
|
||||
|
||||
### 2.7 选项行为编辑器重构
|
||||
|
||||
完成内容:
|
||||
|
||||
- 将原 “Function 编辑器” 改造成 “选项行为编辑器”
|
||||
- 页面文案和入口统一为“选项行为”
|
||||
- 移除“基础场景 / 结果场景”双窗格预览
|
||||
- 保留并强化:
|
||||
- 行为列表
|
||||
- 覆盖保存
|
||||
- 快速模板套用
|
||||
|
||||
经验:
|
||||
|
||||
- 创作者并不关心 “function” 这个技术词,更关心“这个选项会发生什么”
|
||||
- 同类编辑器如果只给字段表单而没有模板起稿能力,复用效率会很低
|
||||
|
||||
### 2.8 选项行为预览升级到实机回放
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [StateFunctionEditor.tsx](/E:/Repos/Genarrative/src/components/StateFunctionEditor.tsx) 中新增 `BehaviorExecutionPreview`
|
||||
- 预览不再是静态推测,而是:
|
||||
1. 构造本地 `GameState`
|
||||
2. 调用真实 `resolveFunctionOption`
|
||||
3. 再调用 [useCombatFlow.ts](/E:/Repos/Genarrative/src/hooks/useCombatFlow.ts) 的
|
||||
- `buildResolvedChoiceState`
|
||||
- `playResolvedChoice`
|
||||
- 从而直接复用游戏真实逻辑
|
||||
|
||||
覆盖能力包括:
|
||||
|
||||
- 战斗行为
|
||||
- 恢复行为
|
||||
- 脱离行为
|
||||
- 探索前探
|
||||
- 切场行为
|
||||
|
||||
经验:
|
||||
|
||||
- 编辑器预览只要和运行时逻辑写成两套,就一定会越来越不一致
|
||||
- 预览层最稳的做法是“调用真实业务逻辑”,而不是“模拟真实业务逻辑”
|
||||
|
||||
## 3. 关键踩坑记录
|
||||
|
||||
### 3.1 图标组件名覆盖原生 `Map`
|
||||
|
||||
问题:
|
||||
|
||||
- `lucide-react` 的 `Map` 图标直接命名为 `Map`
|
||||
- 在 NPC 页签里 `new Map()` 实际调用到了图标组件
|
||||
- 导致页签内容直接渲染为空
|
||||
|
||||
经验:
|
||||
|
||||
- 图标组件命名尽量使用 `MapIcon`、`UserIcon` 这类后缀
|
||||
- 避免覆盖 JS/TS 原生对象名
|
||||
|
||||
### 3.2 预览 effect 依赖不稳定导致回放反复重启
|
||||
|
||||
问题:
|
||||
|
||||
- `BehaviorExecutionPreview` 里使用了 `useCombatFlow()`
|
||||
- 但 effect 依赖了返回对象本身
|
||||
- 每次 `gameState` 更新,effect 都会被视为变更
|
||||
- 导致预览回放速度异常、重复重启、动画像加速
|
||||
|
||||
经验:
|
||||
|
||||
- 只要预览组件内部要“异步播放状态变化”,就要高度警惕 effect 依赖环
|
||||
- 解决方式是:
|
||||
- 用 `ref` 保存稳定方法引用
|
||||
- 让 effect 只依赖真正的输入配置,不依赖内部播放状态
|
||||
|
||||
### 3.3 实时面板与回放阶段不同步
|
||||
|
||||
问题:
|
||||
|
||||
- `LIVE PLAYER` 用的是实时 `gameState`
|
||||
- `BATTLE SNAPSHOT` 用的是预计算首回合快照
|
||||
- 两者不是同一时间点的数据
|
||||
- 导致面板看起来“都对,但互相对不上”
|
||||
|
||||
经验:
|
||||
|
||||
- 预览面板要么都显示“实时状态”
|
||||
- 要么都显示“同一个阶段的快照”
|
||||
- 混用实时值和预测值会让创作者误判
|
||||
|
||||
## 4. 这类项目里沉淀下来的方法论
|
||||
|
||||
### 4.1 先校验资源,再改编辑器
|
||||
|
||||
顺序建议:
|
||||
|
||||
1. 先扫真实目录
|
||||
2. 再建资产定义
|
||||
3. 再修编辑器字段
|
||||
4. 最后修预览
|
||||
|
||||
### 4.2 预览必须尽量复用游戏真实链路
|
||||
|
||||
优先级:
|
||||
|
||||
1. 复用真实函数
|
||||
2. 复用真实状态结构
|
||||
3. 复用真实渲染组件
|
||||
4. 最后才是补充编辑器专用的辅助信息
|
||||
|
||||
### 4.3 编辑器要区分“可编辑字段”和“会生效字段”
|
||||
|
||||
经验:
|
||||
|
||||
- 不是所有字段都应该在所有行为类型下开放
|
||||
- 如果某类行为最终不会直接读取某个字段,就应该禁用或弱化它
|
||||
- 否则创作者会错误地以为改动无效是 bug
|
||||
|
||||
### 4.4 模板比空白表单更重要
|
||||
|
||||
经验:
|
||||
|
||||
- 当系统里已经有多种成熟行为时,最快的创作路径不是“从零填写”
|
||||
- 而是:
|
||||
- 选一个最像的
|
||||
- 套结构
|
||||
- 微调文案和数值
|
||||
|
||||
## 5. 推荐的后续方向
|
||||
|
||||
如果继续打磨这套编辑器,建议下一步做:
|
||||
|
||||
1. 为选项行为预览增加“时间轴 / 阶段日志”
|
||||
2. 为选项行为编辑器增加“新建行为向导”
|
||||
3. 把更多系统状态引入预览上下文
|
||||
- 同伴
|
||||
- NPC 状态
|
||||
- 背包
|
||||
- 当前场景实体池
|
||||
4. 把“可编辑字段”和“只读推导字段”视觉上再分开
|
||||
|
||||
## 6. 一句话总结
|
||||
|
||||
过去这几轮最重要的经验不是“写了多少编辑器 UI”,而是:
|
||||
|
||||
**编辑器一旦想可靠,就不能只编辑静态数据,必须逐步接管真实资源定义、真实运行时状态和真实播放逻辑。**
|
||||
@@ -0,0 +1,310 @@
|
||||
# 当前游戏全流程体验报告(2026-04-07)
|
||||
|
||||
## 1. 报告说明
|
||||
|
||||
本次报告基于 `2026-04-07` 仓库现状完成,目标不是评审 PRD,而是从玩家进入游戏的第一秒开始,顺着当前可达链路实际跑一遍,记录“能不能玩、玩到哪、哪里出戏、哪里已经有感觉”。
|
||||
|
||||
本次模拟采用两段式验证:
|
||||
|
||||
- 开发服验证:直接访问本地 `http://127.0.0.1:3000`
|
||||
- 临时生产包试玩:执行 `node scripts/vite-cli.mjs build --outDir temp_playtest_build` 后,通过静态服务器预览
|
||||
- 试玩视口:移动端优先,约 `430 x 932`
|
||||
|
||||
需要先说明一个前提:
|
||||
|
||||
- 当前开发服首页会被 Vite 错误遮罩拦住,玩家无法直接进入游戏
|
||||
- 为了继续完成全流程体验,我改走了临时生产包试玩
|
||||
- 临时生产包没有本地 `/api` 代理,因此剧情区会持续出现 `501 Unsupported method ('POST')` 的报错文案,AI 文本体验会被明显污染
|
||||
|
||||
因此,这份报告同时包含两类结论:
|
||||
|
||||
- 一类是“当前版本玩家真实会撞到的入口问题”
|
||||
- 一类是“绕过入口问题后,主流程骨架本身的可玩性表现”
|
||||
|
||||
---
|
||||
|
||||
## 2. 本次实际跑通的流程
|
||||
|
||||
本次实际走通的路径如下:
|
||||
|
||||
1. 启动页
|
||||
2. 世界选择
|
||||
3. 角色选择
|
||||
4. 进入营地开场
|
||||
5. 首次剧情抉择
|
||||
6. 任务更新
|
||||
7. 场景移动到 `宫苑内庭`
|
||||
8. NPC 首次互动
|
||||
9. 交易面板
|
||||
10. 地图弹窗
|
||||
11. 队伍面板
|
||||
12. 背包 / 工坊面板
|
||||
13. 设置面板
|
||||
14. 保存并退出
|
||||
15. 继续游戏恢复存档
|
||||
|
||||
结论先说:
|
||||
|
||||
- 主流程骨架已经成型,已经不是“只有页面没有游戏”
|
||||
- 进入营地、触发任务、切场景、遇 NPC、开交易、开地图、看队伍、看背包、保存继续,这一整圈是能跑下来的
|
||||
- 但入口稳定性、错误文案兜底、语言一致性、部分中文乱码,已经直接影响玩家的第一轮真实体验
|
||||
|
||||
---
|
||||
|
||||
## 3. 分阶段体验记录
|
||||
|
||||
## 3.1 启动页
|
||||
|
||||
玩家第一眼看到的是一个相对简洁的开始页,只有标题、开始按钮、开发团队入口和联系方式,节奏是对的,确实更像游戏入口,不像表单式 Demo。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 开始动作很聚焦,玩家不会迷路
|
||||
- 首屏信息量不大,移动端阅读负担低
|
||||
- “开始游戏 / 新游戏 / 继续游戏”的结构清晰
|
||||
|
||||
问题:
|
||||
|
||||
- 当前开发服并不能进入这个页面,实际先看到的是 Vite 错误遮罩
|
||||
- “开发团队 / 联系方式”仍然偏开发样态,正式玩家会有一点出戏
|
||||
|
||||
## 3.2 世界选择
|
||||
|
||||
世界选择页目前有 `武侠`、`仙侠` 和 `自定义世界` 三个主要入口。对玩家来说,这一页的信息组织已经够直观:世界名、气质、副标题、在线人数氛围标签都能快速帮助判断。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 选世界成本低,点击欲望明确
|
||||
- 自定义世界入口放得足够醒目,不会被埋
|
||||
- 武侠 / 仙侠区分清楚,符合开局决策直觉
|
||||
|
||||
问题:
|
||||
|
||||
- “在线人数”更像氛围数字,不像真实系统状态,容易被当作假在线
|
||||
- 当前页面更偏“卡片入口”,还没有形成非常强的世界身份记忆点
|
||||
|
||||
## 3.3 角色选择
|
||||
|
||||
角色选择页已经具备“选人进入冒险”的基本仪式感。当前可见角色包括 `剑之公主`、`神箭游侠`、`双刃旅者`、`破军拳师`、`玄甲战锋`。属性、背景故事、性格标签和详情入口都齐了。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 选角信息够完整,能形成第一轮角色代入
|
||||
- “背景故事 + 标签 + 属性”三层信息组织合理
|
||||
- 移动端视口下仍然能完成浏览和确认
|
||||
|
||||
问题:
|
||||
|
||||
- 角色页里的“自定义 / 详情”会让玩家在开局阶段产生一点分心
|
||||
- 当前角色差异更多停留在说明层,开局前还没完全转化成“我为什么要选这个人”的强动机
|
||||
|
||||
## 3.4 营地开场
|
||||
|
||||
选择角色进入营地后,游戏会先给一段开场对话,再给玩家两个非常关键的初始决策:
|
||||
|
||||
- 先问问对方为什么会出现在这里
|
||||
- 直接前往下一场景
|
||||
|
||||
这一段是目前全流程里最像“正式游戏开局”的部分之一。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 营地比直接扔进战斗更稳,给了玩家进入状态的缓冲
|
||||
- 开场对话能自然把关系、任务感和前路危险感一起立起来
|
||||
- “先聊聊再走 / 直接上路”是个很好的第一轮分流
|
||||
|
||||
问题:
|
||||
|
||||
- 在静态试玩环境下,剧情区会同时出现完整 `501` HTML 报错,极度出戏
|
||||
- 开场后文本会夹杂英文 fallback,语言氛围被打断
|
||||
|
||||
## 3.5 首次选择后的反馈
|
||||
|
||||
当我选择“先问问你为什么会出现在这里”后,系统会立即给出关系变化与互动解锁反馈,例如可继续触发:
|
||||
|
||||
- 交易
|
||||
- 切磋
|
||||
- 前往下一场景
|
||||
|
||||
这一点说明“问一句话不是纯文案,而是会打开玩法分支”,这非常重要。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 玩家会感觉自己的选择真的改变了接下来能做什么
|
||||
- NPC 不是摆设,至少已经能作为玩法节点工作
|
||||
- “营地开场 -> 关系松动 -> 解锁交互”这条节奏是成立的
|
||||
|
||||
问题:
|
||||
|
||||
- 互动文案和角色名偶尔会出现中英混用
|
||||
- 某些反馈更像系统摘要,而不是完全沉浸式叙事
|
||||
|
||||
## 3.6 场景切换与任务推进
|
||||
|
||||
离开营地前往 `宫苑内庭` 后,系统会弹出任务更新提示,随后给出新的场景内可选路线,例如:
|
||||
|
||||
- 与 `旧宫侍女` 交谈
|
||||
- 继续向前探路
|
||||
- 前往 `铸坊工场`
|
||||
|
||||
这是当前版本最能证明“游戏不是单房间对话器”的一段。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 切场景后有明确任务更新,玩家知道自己没有在空转
|
||||
- 新场景不是纯背景图替换,而是伴随新的实体和路径选择
|
||||
- “NPC / 探索 / 场景跳转”三种入口并列,主循环味道出来了
|
||||
|
||||
问题:
|
||||
|
||||
- 任务弹窗表达比较清楚,但质感仍偏功能通知
|
||||
- 任务标题、阶段名、剧情节拍这些信息有时偏系统化,缺少一点戏剧包装
|
||||
|
||||
## 3.7 NPC 互动与交易
|
||||
|
||||
在 `宫苑内庭` 与 `旧宫侍女` 接触后,可以进一步进入交易。交易弹窗中已经具备:
|
||||
|
||||
- NPC 名称
|
||||
- 玩家当前货币
|
||||
- 对方库存
|
||||
- 购买数量调整
|
||||
- 总价计算
|
||||
- 取消 / 确认购买
|
||||
|
||||
这是当前版本完成度相对高的一段玩法。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 交易不是假按钮,而是完整闭环
|
||||
- 商品分类、稀有度、价格都能读懂
|
||||
- 作为玩家,会明显感觉“这个 NPC 是有功能的”
|
||||
|
||||
问题:
|
||||
|
||||
- 从“与 NPC 交谈”直接跳到“交易 / 战斗 / 切磋”,中间缺少一层更自然的对话承接
|
||||
- 当前交易更偏功能正确,角色气质和商品叙事关联还不够强
|
||||
|
||||
## 3.8 战斗 / 切磋
|
||||
|
||||
我实际触发了切磋和场景战斗。进入后,系统会给出带有数值提示的选项,例如:
|
||||
|
||||
- 耗蓝
|
||||
- 伤害
|
||||
- 正面压制 / 稳扎稳打 / 假动作切入
|
||||
|
||||
这说明战斗不是纯文案,而是有明确本地规则参与的。
|
||||
|
||||
正向感受:
|
||||
|
||||
- 玩家能看见技能选择的直接代价和收益
|
||||
- 战斗选项语义比较明确,不是模糊散文式描述
|
||||
- 从营地切磋到场景战斗的承接是通的
|
||||
|
||||
问题:
|
||||
|
||||
- 在本次静态试玩里,战斗文本会出现英文 fallback
|
||||
- 战斗推进感还不够强,玩家能感知到“进入战斗了”,但还不够容易感知“这一手到底让局势前进了多少”
|
||||
|
||||
## 3.9 地图、队伍、背包
|
||||
|
||||
我实际打开了地图、队伍和背包。
|
||||
|
||||
地图方面:
|
||||
|
||||
- 点击场景名可直接打开地图弹窗
|
||||
- 当前场景和相邻场景关系可见
|
||||
- `宫苑内庭` 可看到 `雨夜长街`、`铸坊工场`、`地宫通道`
|
||||
|
||||
队伍方面:
|
||||
|
||||
- 队伍列表能打开
|
||||
- 可读到主角状态、标签数、适配倍率
|
||||
- 但面板里已经出现明显乱码,如 `闃熼暱`
|
||||
|
||||
背包方面:
|
||||
|
||||
- 能看到初始资源、材料和工坊配方
|
||||
- 锻造 / 合成入口都已经在主流程里
|
||||
- 玩家会明确感觉到“我不是只有剧情,我还有 build 和资源循环”
|
||||
|
||||
整体判断:
|
||||
|
||||
- 三个面板都不是空壳
|
||||
- 地图和背包的功能价值已经足够成立
|
||||
- 队伍页的信息密度没问题,但乱码已经直接破坏观感
|
||||
|
||||
## 3.10 保存并退出 / 继续游戏
|
||||
|
||||
设置面板中已经有:
|
||||
|
||||
- 音乐音量
|
||||
- 运行统计
|
||||
- 保存并退出
|
||||
|
||||
我实际触发了“保存并退出”,随后回到开始页,再点击“继续游戏”,能够恢复到先前场景和流程状态。
|
||||
|
||||
这是本次试玩里最让我放心的一条链路。
|
||||
|
||||
结论:
|
||||
|
||||
- 存档与继续不是摆设,是真的通了
|
||||
- 这让整套流程第一次具备了“可以连续玩,而不是每次重开”的基础感
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前版本最明显的优点
|
||||
|
||||
1. 主循环骨架已经成立。开局、选世界、选角色、营地、任务、切场景、NPC、交易、战斗、背包、地图、存档,这些点已经能串起来。
|
||||
2. 移动端优先思路是对的。至少在窄屏下,核心路径没有因为布局崩掉而不可玩。
|
||||
3. 功能入口大多不是假入口。交易、地图、背包、保存继续都是真能执行的。
|
||||
4. “AI 叙事 + 本地规则”的边界能感知到。尤其战斗选项里的耗蓝 / 伤害提示,已经把规则感立起来了。
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前版本最影响玩家体验的问题
|
||||
|
||||
## P0
|
||||
|
||||
1. 开发入口直接被错误遮罩拦住。当前 `http://127.0.0.1:3000` 不是“有点瑕疵”,而是玩家根本进不去。
|
||||
2. 标准构建命令当前不可用。`npm run build` 会因为 `dist` 清理阶段的 `EPERM` 失败,说明发布路径并不稳定。
|
||||
3. 没有 `/api` 代理时,剧情区会直接显示完整 `501` HTML 错误正文,沉浸感几乎被瞬间打穿。
|
||||
|
||||
## P1
|
||||
|
||||
1. 多处英文 fallback 直接进入正式体验,例如营地、NPC 接触、切磋文本。
|
||||
2. 队伍面板已经出现玩家可见乱码,如 `闃熼暱`、`褰撳墠濮旀墭` 一类内容。
|
||||
3. 冒险主标签栏被隐藏后,玩家主要依赖小按钮进入队伍/背包,主导航层级不够直观。
|
||||
4. NPC 首次互动到“交易 / 战斗 / 切磋”的切换偏硬,少了一层更自然的剧情过渡。
|
||||
|
||||
## P2
|
||||
|
||||
1. 世界页和角色页已经能用,但记忆点还不够强,个体世界身份和角色差异还可以再拉开。
|
||||
2. 任务提示偏功能型,情绪包装和戏剧感还可以继续加强。
|
||||
|
||||
---
|
||||
|
||||
## 6. 玩家视角总结
|
||||
|
||||
如果只从“玩法骨架”看,这个项目已经不是 PPT,也不是只有几个页面的壳。它已经有一条能走完整圈的游戏主流程,而且最关键的交易、地图、任务、战斗、存档都不是假的。
|
||||
|
||||
但如果从“当前玩家第一次打开就会得到什么体验”来看,问题也很直接:
|
||||
|
||||
- 入口不稳
|
||||
- 构建不稳
|
||||
- 离线 / 无代理时错误文案直接冲到脸上
|
||||
- 中英混用和部分乱码会快速打断沉浸
|
||||
|
||||
一句话总结:
|
||||
|
||||
**当前版本已经具备“能玩一圈”的核心骨架,但距离“放心交给玩家体验”还差一次很扎实的入口修复、错误兜底和文本统一收尾。**
|
||||
|
||||
---
|
||||
|
||||
## 7. 建议的下一步
|
||||
|
||||
建议优先顺序如下:
|
||||
|
||||
1. 先修入口可玩性:解决开发服错误遮罩、`build` 清理失败、静态环境错误文案泄露。
|
||||
2. 再修体验一致性:清掉玩家可见英文 fallback 和明显乱码。
|
||||
3. 然后打磨主循环表达:让营地开场、任务更新、NPC 接触这三段更有戏。
|
||||
4. 最后再扩内容:因为现在真正限制体验的不是“内容太少”,而是“入口和表达不够稳”。
|
||||
218
docs/experience/MOBILE_UI_DEV_EXPERIENCE.md
Normal file
218
docs/experience/MOBILE_UI_DEV_EXPERIENCE.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# 奇幻酒馆 UI 开发经验沉淀
|
||||
|
||||
## 1. 总体原则
|
||||
|
||||
### 1.1 先保证移动端成立,再兼容网页端
|
||||
- 入口页、世界选择、角色选择、冒险页、弹窗面板,都要先按手机竖屏去定义信息密度。
|
||||
- 网页端只做“放宽容器、增加留白、补充 hover”,不要反过来让桌面布局压垮手机体验。
|
||||
- 任何区域如果在移动端需要滚动,必须明确谁滚动,不能让整页和局部同时争夺滚动。
|
||||
|
||||
### 1.2 游戏 UI 要优先“状态清晰”,而不是“文案很多”
|
||||
- 开始页应该像主菜单,不像产品介绍页。
|
||||
- 角色选择页应该像角色选择器,不像角色说明书。
|
||||
- 冒险页应该像战斗/剧情操作台,不像文档阅读器。
|
||||
|
||||
### 1.3 一屏内的层级顺序要稳定
|
||||
- 上半部分:画面演出。
|
||||
- 中间部分:剧情或核心信息。
|
||||
- 底部:操作按钮。
|
||||
- 玩家必须能快速判断“我在看什么、下一步点哪里”。
|
||||
|
||||
## 2. 入口页经验
|
||||
|
||||
### 2.1 开始页
|
||||
- 极简化是对的。
|
||||
- 当前实践证明:开始页只保留“开始游戏”和“开发团队”两个主按钮,体验明显更像游戏。
|
||||
- 游戏名和英文副标题可以保留,但不要再加长段描述。
|
||||
|
||||
### 2.2 世界选择
|
||||
- 纵向焦点轮播比普通列表更适合移动端。
|
||||
- 当前居中的卡片应该最大、最清晰、最亮;上下卡片缩放和透明度随滚动连续变化。
|
||||
- 世界确认动作应该绑定当前聚焦卡,而不是每张卡都塞太多按钮。
|
||||
|
||||
### 2.3 角色选择
|
||||
- 横向轮播是正确方向。
|
||||
- 中间卡片应承担“主视觉 + 主要信息”。
|
||||
- 左右卡片只做预览,不需要承载完整信息。
|
||||
- 左右卡片倾斜方向一定要符合透视直觉:
|
||||
左侧卡片向左外倾,右侧卡片向右外倾。
|
||||
- 中间卡片不要出现任何模糊,否则会破坏“当前选中”的确认感。
|
||||
|
||||
## 3. 角色选择页经验
|
||||
|
||||
### 3.1 聚焦卡的表现
|
||||
- 中间聚焦卡用角色 `run` 动画是有效的,能明显提升“角色活着”的感觉。
|
||||
- 但动画资源和静态立绘的锚点通常不一致,必须单独做位置与缩放修正。
|
||||
- 结论:
|
||||
动画版角色不要直接复用静态图样式,要单独给 `transform`、`height`、`transform-origin`。
|
||||
|
||||
### 3.2 信息区要紧凑
|
||||
- 角色数值和角色背景应该放在轮播下方,但必须压缩高度。
|
||||
- 如果下方面板过高,会直接破坏上半部分轮播体验,尤其在手机上。
|
||||
- 删除背景面板里的额外动画模块是正确的,因为它与主轮播重复抢视觉焦点。
|
||||
|
||||
### 3.3 文案层级
|
||||
- 页面标题只保留一句:
|
||||
“选择你扮演的角色”
|
||||
- 不要再强调 `CHARACTER SELECT` 之类的开发向分类标签。
|
||||
- 聚焦卡下方直接显示角色名,比把名字只放在卡片底部更直观。
|
||||
|
||||
### 3.4 按钮位置
|
||||
- “确认选择”必须放在角色轮播和信息区之后,作为页面最后的主动作。
|
||||
- 按钮不宜过宽过高,否则会抢轮播的视觉重心。
|
||||
|
||||
## 4. 冒险页经验
|
||||
|
||||
### 4.1 剧情区必须自适应
|
||||
- 剧情文本区不应该写死高度。
|
||||
- 正确做法是:
|
||||
让它自动填满“上方画面下缘”和“底部按钮区上缘”之间的剩余空间。
|
||||
- 这样才能同时保证:
|
||||
1. 上方画面一屏可见
|
||||
2. 下方三个选项一屏可见
|
||||
3. 中间剧情尽量大
|
||||
|
||||
### 4.2 底部操作区必须锚定到底
|
||||
- 队伍、背包、换一换、选项列表,都应该属于底部控制区。
|
||||
- 用户会天然在屏幕底部寻找交互入口,尤其是手机。
|
||||
- 因此:
|
||||
不要把这些按钮漂在中间,不要让剧情区把它们挤走。
|
||||
|
||||
### 4.3 队伍与背包不应打断主流程
|
||||
- 在冒险页内,队伍和背包更适合“弹出面板”而不是“切换整页”。
|
||||
- 原因:
|
||||
1. 不会打断当前剧情阅读
|
||||
2. 用户返回成本更低
|
||||
3. 操作像手游副面板,更符合预期
|
||||
|
||||
### 4.4 图标优于文字按钮
|
||||
- 在底部工具区,队伍/背包改成 icon 后更紧凑。
|
||||
- 但必须保留 `aria-label`,保证语义清晰、后续也方便测试。
|
||||
|
||||
### 4.5 冒险主场景不要挂右上角账号悬浮条
|
||||
- 冒险页右上角属于画面演出和战斗/剧情信息的高频观察区。
|
||||
- 全局账号信息条挂在这里,会直接压住场景、敌人血条或顶部提示,手机端尤其明显。
|
||||
- 结论:
|
||||
账号入口应收回平台首页、个人页或设置面板,不要在实际冒险主场景常驻悬浮显示。
|
||||
- 当前仓库已进一步收口为:
|
||||
不再提供右上角全局账号悬浮条,统一只保留页面内入口与独立账号面板。
|
||||
|
||||
### 4.6 冒险主场景双方角色必须按画面中线镜像
|
||||
- 非滚动画面的交谈、预览、单体对峙态,主角和对面角色不能分别用左右边距、世界坐标和角色宽度重复推算。
|
||||
- 正确做法是先定义“角色容器中心距离画面中线”的统一间距,再让主角中心落在中线左侧、对面角色中心落在中线右侧。
|
||||
- 角色容器宽度、角色图片缩放和左右朝向必须各自独立处理,不能用额外 left inset 去修正角色图片,否则会破坏左右对称。
|
||||
- 自定义图片 NPC、模板角色和组合式 NPC 都要进入同一 112px 场景容器,再按各自素材锚点做场景缩放,保证视觉大小不漂移。
|
||||
|
||||
## 5. 队伍面板经验
|
||||
|
||||
### 5.1 移动端成员列表不能太“卡片化”
|
||||
- 如果每个成员都再套一层大边框卡片,手机上会显得很挤。
|
||||
- 更好的方式是直接在主面板里陈列成员,弱化分隔、强化内容。
|
||||
|
||||
### 5.2 队伍列表展示什么
|
||||
- 头像
|
||||
- 姓名
|
||||
- 称号
|
||||
- 身份标记(领队/同行)
|
||||
- HP / MP
|
||||
|
||||
### 5.3 队伍详情弹窗
|
||||
- 弹窗必须可滚动。
|
||||
- 弹窗宽度不宜太大,手机优先单列或偏单列。
|
||||
- 技能、装备、属性三个区块保持稳定结构,便于扫读。
|
||||
|
||||
## 6. 背包页经验
|
||||
|
||||
### 6.1 格子数要优先适配手机
|
||||
- 手机端格子间距要小一号。
|
||||
- 图标尺寸和分类角标要跟着缩小。
|
||||
- 目标不是“每个格子信息很多”,而是“单屏能看更多格子”。
|
||||
|
||||
### 6.2 背包详情弹窗
|
||||
- 手机端改成单列/窄宽度布局更合理。
|
||||
- 详情窗里的信息顺序建议固定:
|
||||
1. 名称与类别
|
||||
2. 品质与数量
|
||||
3. 大图标
|
||||
4. 说明
|
||||
5. 标签
|
||||
|
||||
## 7. 样式与动画经验
|
||||
|
||||
### 7.1 轮播动画要连续,不要离散
|
||||
- 滚动时应根据“当前位置与当前卡片中心的距离”实时计算:
|
||||
- `scale`
|
||||
- `opacity`
|
||||
- `rotate`
|
||||
- `translate`
|
||||
- 不要做成“翻页后才跳变”的效果。
|
||||
|
||||
### 7.2 焦点卡与非焦点卡的职责要不同
|
||||
- 焦点卡负责可读性与确认感。
|
||||
- 非焦点卡负责预告与空间深度。
|
||||
- 所以焦点卡不该模糊,非焦点卡可以轻微降透明度、缩放、偏移。
|
||||
|
||||
### 7.3 资源锚点要单独校准
|
||||
- 静态立绘和动画帧经常不是同一锚点。
|
||||
- 只要切换成动画,就需要重新调:
|
||||
- 高度
|
||||
- Y 偏移
|
||||
- 缩放
|
||||
- `transform-origin`
|
||||
|
||||
## 8. 工程经验
|
||||
|
||||
### 8.1 组件要继续拆
|
||||
- 本轮重构证明,把入口页、冒险页、队伍页、背包页拆成独立组件是正确的。
|
||||
- 后续新增 UI 需求时,应优先落在:
|
||||
- `GameShell.tsx`
|
||||
- `AdventurePanel.tsx`
|
||||
- `CharacterPanel.tsx`
|
||||
- `InventoryPanel.tsx`
|
||||
|
||||
### 8.2 不要相信“服务已经在跑”
|
||||
- 这轮出现过“端口上有进程,但浏览器仍然拿到旧模块”的问题。
|
||||
- 实际经验:
|
||||
1. 要检查 `src` 文件内容
|
||||
2. 要检查 dev server 实际返回的模块内容
|
||||
3. 要确认启动脚本是否是当前项目真正使用的脚本
|
||||
|
||||
### 8.3 本项目当前开发服务入口
|
||||
- 本地正确启动脚本是:
|
||||
`node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0`
|
||||
- 历史脚本或旧进程会导致“代码已改但 UI 看起来没变”的假象。
|
||||
|
||||
## 9. 后续建议
|
||||
|
||||
### 9.1 可以继续统一中英混杂文案
|
||||
- 当前部分新旧文本仍有历史遗留字符问题。
|
||||
- 如果后面继续做 UI 精修,建议单独做一轮文案清洗。
|
||||
|
||||
### 9.2 可以把轮播抽成通用组件
|
||||
- 世界纵向焦点轮播
|
||||
- 角色横向倾斜轮播
|
||||
- 这两套逻辑已经足够稳定,适合后续抽成通用 hook 或通用组件。
|
||||
|
||||
### 9.3 可以补移动端安全区适配
|
||||
- 当前已经偏移动端优先,但还可以继续加:
|
||||
- `safe-area-inset-bottom`
|
||||
- `safe-area-inset-top`
|
||||
- 更细的竖屏断点处理
|
||||
|
||||
## 10. 一句话结论
|
||||
|
||||
这一轮最关键的经验是:
|
||||
**游戏 UI 的移动端优化,本质不是把元素缩小,而是重组视觉重心、固定操作锚点、让焦点内容在一屏内自然成立。**
|
||||
|
||||
### 10.1 可扮演角色形象预览保持 1:1
|
||||
- 可扮演角色的形象预览容器统一使用 1:1 方形,入口选择轮播、角色资产工坊和结果页角色卡片都不能用纵向长卡片去拉伸预览图。
|
||||
- 预览图片本身使用 `object-contain`,保证 AI 生成主形象、模板像素角色和运行时动画都在方形容器内完整显示,不裁切角色主体。
|
||||
- 卡片可以在方形预览下方放角色名、称号、状态等信息,但这些文本区不能反向影响预览区比例。
|
||||
- 编辑角色弹窗也遵循同一规则:移动端不能用固定高度压扁预览区,预览容器应随宽度保持 `aspect-square`。
|
||||
|
||||
### 10.2 运行画面怪物锚点按视觉底边校准
|
||||
- 对战预览里主角和对手要沿画面中线成对出现,但纵向不能只共用一个 `bottom` 常量。
|
||||
- 怪物精灵帧的空白、体型和脚底位置差异很大,运行画面应按帧高分档下沉,让怪物视觉底边落在主角同一条地面线上。
|
||||
- 后续新增怪物资源时,先检查红圈标注的实际落点,再调整锚点分档或单怪物偏移,避免出现“悬在地面上方”的状态。
|
||||
- 自定义世界里敌对角色已经先作为场景 NPC 存在,即使它同时携带 `characterId` 和 `monsterPresetId`,画布也不能直接沿用模板角色的 `groundOffsetY`;只要 encounter 自身有 `imageSrc` 或 `visual`,就按场景 NPC 自定义形象锚点处理。
|
||||
- 幕预览运行时还会构造“无 `characterId`、但有 `visual` 的场景 NPC”,这类和平相遇分支同样必须套用场景 NPC 自定义形象锚点,否则会停在画面中上部。
|
||||
@@ -0,0 +1,31 @@
|
||||
# PC 端世界生成与草稿页布局优化说明 2026-04-24
|
||||
|
||||
## 目标
|
||||
|
||||
在移动端现有布局不变的前提下,只优化 PC 端世界生成页与世界草稿页的信息组织,让页面更紧凑、更有层次,并保留全部已有功能入口。
|
||||
|
||||
## 范围
|
||||
|
||||
- 世界生成页:`src/components/CustomWorldGenerationView.tsx`
|
||||
- 世界草稿页 / 作品页:`src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- 新建作品入口:`src/components/custom-world-home/CustomWorldCreationStartCard.tsx`
|
||||
- 作品卡片:`src/components/custom-world-home/CustomWorldWorkCard.tsx`
|
||||
- 筛选标签:`src/components/custom-world-home/CustomWorldWorkTabs.tsx`
|
||||
|
||||
## PC 端落地规则
|
||||
|
||||
1. 移动端默认类名保持原布局语义,只通过 `lg:` / `xl:` 断点追加 PC 布局。
|
||||
2. 世界生成页在 PC 端改为左右双栏:左侧突出进度与阶段,右侧承载玩家设定 / 结构化锚点,减少纵向滚动。
|
||||
3. 世界草稿页在 PC 端将“新建作品”和“作品列表”分区强化:顶部入口更紧凑,作品卡片网格密度提升。
|
||||
4. 不新增规则说明文案,不改变按钮、筛选、删除、体验、进入等功能行为。
|
||||
5. 中文文本只做必要保留,不因为布局调整改写已有中文内容。
|
||||
|
||||
## 视觉策略
|
||||
|
||||
- PC 端使用更明确的 `xl:grid`、固定信息侧栏和更小间距,让主内容首屏承载更多信息。
|
||||
- 卡片在 PC 端降低无效高度,操作按钮与状态信息尽量同行展示。
|
||||
- 作品卡片底部统计标签必须保留在卡片圆角范围内,不能为了压缩高度让标签贴边或被 `overflow-hidden` 裁掉。
|
||||
- 卡片正文摘要优先缩短行数来给底部标签留空间;当标题、摘要或标签变长时,允许卡片自然增高。
|
||||
- RPG 作品卡片点击行为按作品状态分流:草稿统一继续创作,已发布作品进入详情或世界;不要只依赖 `sourceType` 判断草稿可打开性。
|
||||
- 整张作品卡片需要由卡片根节点承载点击与键盘打开能力,避免透明绝对定位按钮在真实浏览器中被判定不可见,导致自动化和用户点击不稳定。
|
||||
- 保留现有 `platform-*` 视觉体系,避免引入新的 UI 系统。
|
||||
@@ -0,0 +1,17 @@
|
||||
# PC 世界档案草稿编辑页布局修正 2026-04-24
|
||||
|
||||
## 背景
|
||||
|
||||
用户反馈 PC 端世界草稿页没有明显变化。复核截图后确认实际页面是世界档案草稿编辑页中的实体目录,而不是创作首页作品列表。
|
||||
|
||||
## 本次修正范围
|
||||
|
||||
- `src/components/CustomWorldEntityCatalog.tsx`
|
||||
|
||||
## 落地要求
|
||||
|
||||
1. 移动端仍保持原来的单列滚动、顶部标签与搜索结构。
|
||||
2. PC 端把超宽单列实体列表改成卡片网格,减少横向空白,提高信息密度。
|
||||
3. PC 端顶部世界标题、标签、搜索和操作按钮更紧凑,避免首屏被空白标题区占用。
|
||||
4. 功能不变:搜索、切换标签、新增、批量删除、选择、编辑、发布入口均保持原有行为。
|
||||
5. 不新增说明类文案,不改写已有中文内容。
|
||||
@@ -0,0 +1,19 @@
|
||||
# 平台首页 Banner 图尺寸修复记录
|
||||
|
||||
更新时间:`2026-04-25`
|
||||
|
||||
## 问题
|
||||
|
||||
首页 Hero / banner 使用作品封面作为背景图。全局 `.platform-surface > *` 会把所有直接子节点重新设为 `position: relative`,导致带有 Tailwind `absolute` 类的背景图和遮罩被覆盖,图片重新进入普通文档流后可能撑高首页,影响首屏布局。
|
||||
|
||||
## 落地
|
||||
|
||||
- 修改 `src/index.css`,将 `.platform-surface > *` 收敛为 `.platform-surface > :not(.absolute)`。
|
||||
- 保留普通内容层的 `z-index: 1`,让文字、按钮仍稳定压在背景之上。
|
||||
- 让 banner 背景图继续使用绝对定位和 `object-cover`,只在固定容器内裁切显示,不参与首页高度计算。
|
||||
|
||||
## 经验
|
||||
|
||||
- 首页、结果页、详情页的背景图都必须由固定尺寸容器承载,图片本身不要参与布局流。
|
||||
- 给通用容器写层级规则时,不能无差别覆盖 `.absolute` 节点,否则会破坏所有“背景图 + 遮罩 + 内容”的结构。
|
||||
- 后续若新增平台 Hero,优先沿用 `platform-surface--hero`,并确认背景图节点仍是 `absolute inset-0 h-full w-full object-cover`。
|
||||
@@ -0,0 +1,20 @@
|
||||
# 可扮演角色外观模板字段删除经验
|
||||
|
||||
## 背景
|
||||
|
||||
可扮演角色曾通过 `templateCharacterId` 保存“外观模板”选择。当前角色主形象已经由 `visualDescription`、`imageSrc` 与生成资产链路承接,外观模板不应继续作为可扮演角色档案字段暴露给用户编辑或持久化。
|
||||
|
||||
## 落地边界
|
||||
|
||||
- 可扮演角色数据结构不再声明 `templateCharacterId`。
|
||||
- 可扮演角色编辑面板删除“外观模板”下拉项,保存时不再补默认模板。
|
||||
- 草稿规范化与资料库读取时丢弃旧数据中的 `templateCharacterId`,避免旧快照把字段带回新数据。
|
||||
- 运行时如需要基础动作、默认立绘或战斗标签,只能通过角色文本、参考 profile 或固定 fallback 规则临时推导模板,不再写回角色字段。
|
||||
- 资产工坊可以继续接收运行时临时模板提示,但该提示不得成为可扮演角色的持久字段。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- 新建或编辑可扮演角色时界面不出现“外观模板”。
|
||||
- 保存后的 `playableNpcs` 条目不包含 `templateCharacterId`。
|
||||
- 旧存档带有 `templateCharacterId` 时,进入当前规范化链路后会被丢弃。
|
||||
- 自定义世界运行角色仍能通过推导模板获得基础动作与默认占位图,不因字段删除而中断。
|
||||
268
docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md
Normal file
268
docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md
Normal file
@@ -0,0 +1,268 @@
|
||||
# AI Native Visual RPG 开发经验沉淀
|
||||
|
||||
## 1. 项目特点判断
|
||||
|
||||
这个项目不是单纯的“像素 UI 项目”,而是 4 条链路同时耦合的项目:
|
||||
|
||||
1. 叙事链路:AI 生成剧情文本与选项
|
||||
2. 状态链路:玩家、怪物、NPC、背包、好感、同伴、场景流转
|
||||
3. 演出链路:战斗计划、动画播放、投射物、特效、镜头位移
|
||||
4. 界面链路:选择世界、选择角色、冒险页、背包页、地图弹窗、编辑器页
|
||||
|
||||
经验:
|
||||
|
||||
- 做功能前先判断它主要影响哪几条链路。
|
||||
- 如果一个需求同时影响“状态 + 演出 + UI”,不要只改一个点。
|
||||
- 像“初始同伴”这种功能,本质上不是 UI 需求,而是“选角流程 + 初始 encounter + NPC 好感 + 招募状态”的组合需求。
|
||||
|
||||
## 2. 先做数据建模,再做 UI
|
||||
|
||||
这一类项目最容易犯的错误,是先加按钮、再补状态。
|
||||
|
||||
实践下来更稳的顺序是:
|
||||
|
||||
1. 先把状态字段补齐
|
||||
2. 再补工具函数
|
||||
3. 再接交互入口
|
||||
4. 最后补展示层
|
||||
|
||||
已经验证有效的状态字段包括:
|
||||
|
||||
- `playerInventory`
|
||||
- `npcStates`
|
||||
- `companions`
|
||||
- `currentBattleNpcId`
|
||||
- `currentEncounter`
|
||||
- `playerActionMode`
|
||||
- `activeCombatEffects`
|
||||
|
||||
经验:
|
||||
|
||||
- “能否交易 / 能否招募 / 送礼涨多少好感”都应该由状态和规则函数决定,不能写死在按钮文本里。
|
||||
- NPC 交互尽量走本地规则,不要依赖 AI 即时决定关键数值。
|
||||
|
||||
## 3. 复杂页面一定要拆流程层
|
||||
|
||||
`App.tsx` 一旦同时承载:
|
||||
|
||||
- 游戏主状态
|
||||
- 剧情生成
|
||||
- 战斗播放
|
||||
- NPC 交互
|
||||
- 地图
|
||||
- 选角
|
||||
|
||||
就会迅速失控。
|
||||
|
||||
当前更合理的分层思路是:
|
||||
|
||||
- `useGameFlow`
|
||||
负责基础游戏状态、世界选择、角色选择、初始进入逻辑
|
||||
- `useCombatFlow`
|
||||
负责战斗计划与播放
|
||||
- `useStoryGeneration`
|
||||
负责剧情生成、NPC 本地交互分流、选项池管理
|
||||
- `useNpcInteractionFlow`
|
||||
负责同伴/NPC 展示态
|
||||
- `GameShell`
|
||||
负责主容器与选择流程
|
||||
- `AdventurePanel`
|
||||
负责冒险页文本和选项
|
||||
- `NpcModals`
|
||||
负责交易 / 送礼 / 放生招募等弹窗
|
||||
|
||||
经验:
|
||||
|
||||
- 流程层优先按“职责”拆,不按“文件长度”拆。
|
||||
- 状态修改逻辑尽量集中到 hook 内,不要散落在多个组件按钮回调里。
|
||||
|
||||
## 3.1 AI 草稿数据进列表前,要先补本地稳定标识
|
||||
|
||||
自定义世界、角色草稿、澄清问题、生成结果卡片这类数据,在草稿态或兼容旧数据时,`id` 可能为空。
|
||||
|
||||
经验:
|
||||
|
||||
- React 列表的 `key` 不要直接裸用这类可能为空的 `id`。
|
||||
- 当前选中态、草稿缓存、轮播焦点也不要直接绑空 `id`,否则会出现“点了第二张卡,结果还是第一张卡被选中”的错位。
|
||||
- 更稳的做法是:
|
||||
- 业务数据层尽量补齐真实 id
|
||||
- UI 层再补一层本地稳定 `selectionKey` / fallback render key
|
||||
- fallback 至少带上 `index + 名称种子`,保证当前列表内唯一
|
||||
|
||||
## 4. AI 只适合生成叙事,不适合决定关键规则
|
||||
|
||||
实践中最稳定的策略是:
|
||||
|
||||
- AI 负责:
|
||||
- `storyText`
|
||||
- 非 NPC 关键规则的普通探索选项文案
|
||||
- 本地规则负责:
|
||||
- NPC 交互选项
|
||||
- 交易合法性
|
||||
- 礼物好感值
|
||||
- 招募阈值
|
||||
- 战斗掉落
|
||||
- 帮助奖励
|
||||
|
||||
经验:
|
||||
|
||||
- 凡是会影响数值平衡、背包物品、好感、队伍成员的部分,都不要交给 AI 即时决定。
|
||||
- AI 生成内容要能被本地规则兜底,否则体验会不稳定。
|
||||
|
||||
## 5. NPC 系统要“角色型 NPC”和“普通 NPC”分开处理
|
||||
|
||||
项目里 NPC 实际上有两种:
|
||||
|
||||
1. 普通场景 NPC:可用通用 Medieval NPC 渲染
|
||||
2. 角色型 NPC:应该复用玩家角色对应的立绘和动画
|
||||
|
||||
经验:
|
||||
|
||||
- 只看 `encounter.kind === 'npc'` 不够,还要看 `encounter.characterId`。
|
||||
- 有 `characterId` 的 NPC,应该优先走 `CharacterAnimator`。
|
||||
- 否则就会出现:
|
||||
- 选了某个同伴,但开场看到的是另一套通用 NPC 外观
|
||||
- 战斗里角色型 NPC 看起来像普通路人
|
||||
|
||||
## 6. 位置与朝向必须统一到一套坐标规则
|
||||
|
||||
这是这类项目里最容易反复返工的点。
|
||||
|
||||
实践中踩过的坑:
|
||||
|
||||
- `sceneMonsters` 用一套坐标逻辑
|
||||
- `currentEncounter` 用另一套坐标逻辑
|
||||
- 结果开场 NPC 和遇怪站位不一致
|
||||
- 角色型 NPC 立绘比怪物更容易出现“脚没落地”“太小”“翻转方向错”
|
||||
|
||||
最终经验:
|
||||
|
||||
- 对面实体的横向定位必须统一到“怪物那套 world-space 逻辑”
|
||||
- 也就是:
|
||||
- 位置统一用怪物侧的 anchor
|
||||
- 相机平移时统一跟随同一套计算
|
||||
- 角色型 NPC 的垂直位置不能偷懒固定
|
||||
- 应该结合角色自身 `groundOffsetY`
|
||||
- 朝向规则要统一使用 `getFacingTowardPlayer`
|
||||
|
||||
一句话总结:
|
||||
|
||||
- 角色型 NPC 不应该单独发明一套站位系统,而应该尽量复用怪物对位系统。
|
||||
|
||||
## 7. “新增流程”不要破坏原有选择 UI
|
||||
|
||||
这次初始同伴功能就是一个典型经验:
|
||||
|
||||
- 用户原本对“选择扮演角色”的视觉和交互已经形成预期
|
||||
- 如果为了加“初始同伴选择”直接把角色选择页改成另一种样式,会造成明显割裂
|
||||
|
||||
经验:
|
||||
|
||||
- 新流程优先插在旧流程后面,而不是重写旧流程
|
||||
- “确认角色 -> 选择初始同伴 -> 进入冒险”比“把原选角页改成全新样式”风险小很多
|
||||
- 如果必须改 UI,也要尽量保留旧页面的视觉结构和交互节奏
|
||||
|
||||
## 8. 冒险页布局要优先保证画面和选项完整可见
|
||||
|
||||
冒险页真正的优先级是:
|
||||
|
||||
1. 上方画布要在一屏内正常显示
|
||||
2. 下方 3 个选项要在一屏内正常显示
|
||||
3. 剧情文本框剩余空间自适应
|
||||
|
||||
经验:
|
||||
|
||||
- 文本框不能无限长撑开
|
||||
- 正确做法是:
|
||||
- 文本框高度自适应剩余空间
|
||||
- 文本超长时内部滚动
|
||||
- 不能让 `storyText` 把战斗画面和选项挤出首屏
|
||||
|
||||
## 9. 编辑器页和玩家页要明确隔离
|
||||
|
||||
当前项目里存在编辑器页面:
|
||||
|
||||
- `PresetEditor`
|
||||
- `NpcVisualEditor`
|
||||
- `StateFunctionEditor`
|
||||
|
||||
玩家页和编辑器页的需求完全不同。
|
||||
|
||||
经验:
|
||||
|
||||
- 像字体切换、视觉统一这种全局改动,不要直接打到整个站点
|
||||
- 应该只挂在非编辑器根容器上
|
||||
- 比如 `fusion-pixel-app` 这种类,只挂在正式游玩界面,不挂在编辑器根节点
|
||||
|
||||
## 10. 构建环境问题要项目内消化
|
||||
|
||||
实际踩到的构建问题:
|
||||
|
||||
- Node 16 环境下,Vite 构建会因为 `crypto.getRandomValues` 缺失报错
|
||||
|
||||
沉淀出的解决方式:
|
||||
|
||||
- 不强依赖开发机立刻升级 Node
|
||||
- 在项目内增加 Vite 启动包装脚本
|
||||
- 统一让 `dev / build / preview` 都走这层 shim
|
||||
|
||||
经验:
|
||||
|
||||
- 环境兼容问题如果能在项目内吸收,就尽量不要把负担转移给每个协作者
|
||||
- 文档里要明确记录“为什么这样做”
|
||||
|
||||
## 11. 比较稳的开发顺序
|
||||
|
||||
后续继续扩展功能时,建议遵守这个顺序:
|
||||
|
||||
1. 写状态字段
|
||||
2. 写规则工具函数
|
||||
3. 写流程 hook
|
||||
4. 接 UI
|
||||
5. 跑 `npm run lint`
|
||||
6. 跑 `npm run build`
|
||||
7. 再做视觉微调
|
||||
|
||||
不要反过来做:
|
||||
|
||||
- 先做 UI
|
||||
- 再补状态
|
||||
- 最后硬修流程
|
||||
|
||||
这种顺序在状态复杂的项目里会越改越乱。
|
||||
|
||||
## 12. 当前最值得继续坚持的原则
|
||||
|
||||
- 保持 AI 生成和本地规则分工清晰
|
||||
- 保持角色型 NPC 与普通 NPC 的渲染分流
|
||||
- 保持“怪物 / encounter / 战斗 NPC”统一坐标系
|
||||
- 保持新增功能不破坏既有核心 UI 体验
|
||||
- 保持编辑器页与玩家页隔离
|
||||
- 每次大改后都用 `lint + build` 双重验证
|
||||
|
||||
## 13. 后续建议
|
||||
|
||||
下一阶段最值得继续沉淀的方向:
|
||||
|
||||
1. 把 NPC 交互逻辑继续从 `useStoryGeneration` 中独立成更纯粹的 `useNpcInteractionFlow`
|
||||
2. 把角色型 NPC 的位置、缩放、贴地参数做成可配置规则,而不是继续散落在画布里微调
|
||||
3. 针对初始同伴流程补一份单独的状态图 / 时序图
|
||||
4. 对大 chunk 警告做代码分包
|
||||
|
||||
## 14. SpacetimeDB 绑定桥接层要做同名去重
|
||||
|
||||
`server-rs/crates/spacetime-client` 里有一部分内容是围绕 SpacetimeDB 生成绑定补的手写桥接层。
|
||||
|
||||
经验:
|
||||
|
||||
- 新增 procedure、input type 或 mapper 时,先全局确认 `module_bindings/mod.rs`、`mapper.rs`、业务封装文件里是否已经存在同名声明
|
||||
- `module_bindings/mod.rs` 同一个模块只保留一条 `pub mod` 和一条 `pub use`,不要同时放在 reducer 区和 procedure 区
|
||||
- `mapper.rs` 的字符串枚举解析函数、API 入参结构只保留一个权威定义,业务侧统一复用
|
||||
- 业务封装文件里同一个 procedure 只暴露一个客户端方法,避免 Rust 在编译期出现 E0428、E0252、E0119、E0592 这类重复定义错误
|
||||
- 修复重复绑定时优先删除后追加的重复块,不要重写整文件,避免影响中文注释和生成绑定附近的大段内容
|
||||
|
||||
## 15. 一句话总结
|
||||
|
||||
这个项目真正的开发经验不是“怎么多写一个按钮”,而是:
|
||||
|
||||
- 在 AI 叙事、像素演出、战斗状态、NPC 规则、选择流程和编辑器体系同时存在的情况下,始终让每条链路各归其位。
|
||||
280
docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md
Normal file
280
docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md
Normal file
@@ -0,0 +1,280 @@
|
||||
# 奇幻酒馆项目开发经验手册
|
||||
|
||||
日期:`2026-03-24`
|
||||
|
||||
## 1. 项目本质判断
|
||||
|
||||
这个项目不是单纯的前端页面项目,也不是单纯的大模型接入项目,而是 4 条链路同时存在的复合型项目:
|
||||
|
||||
1. 叙事链路:剧情文本、选项文本、角色对话、聊天上下文。
|
||||
2. 状态链路:角色、怪物、NPC、场景、背包、装备、战斗状态、CD、蓝耗、死亡、掉落。
|
||||
3. 演出链路:角色进场、近战贴身、受击、死亡、逃跑、镜头跟随、场景切换、前探预览。
|
||||
4. 工具链路:NPC 形象编辑器、行为编辑器、预设数据、校验脚本、本地调试环境。
|
||||
|
||||
经验结论:
|
||||
|
||||
- 任何需求只要影响两条以上链路,就不能只改 UI。
|
||||
- 先判断需求落在哪些链路,再决定改哪些文件。
|
||||
- 这类项目最怕“看起来改好了”,但状态、动画、提示词和运行逻辑其实没对齐。
|
||||
|
||||
## 2. 架构拆分经验
|
||||
|
||||
已经验证更稳的结构是:
|
||||
|
||||
- `App.tsx` 保持尽量薄,只做外层挂载。
|
||||
- `GameShell.tsx` 负责主流程壳层:开始页、世界选择、角色选择、游戏内主界面切换。
|
||||
- 各类状态和流程尽量放进 hooks:
|
||||
- `useGameFlow`
|
||||
- `useCombatFlow`
|
||||
- `useStoryGeneration`
|
||||
- `useNpcInteractionFlow`
|
||||
- `useInventoryFlow`
|
||||
- `useEquipmentFlow`
|
||||
- 各类独立 UI 面板拆成独立组件:
|
||||
- `AdventurePanel`
|
||||
- `CharacterPanel`
|
||||
- `InventoryPanel`
|
||||
- `MapModal`
|
||||
- `AdventureEntityModal`
|
||||
|
||||
经验结论:
|
||||
|
||||
- 按职责拆,不按文件长度拆。
|
||||
- 状态修改尽量集中在 hook 内,不要散落在多个按钮回调里。
|
||||
- 预览系统、编辑器系统、正式游戏流程要尽量复用同一套业务逻辑,而不是各写一套。
|
||||
|
||||
## 3. AI 与本地规则的边界
|
||||
|
||||
目前最稳定的边界是:
|
||||
|
||||
- AI 负责生成:
|
||||
- `storyText`
|
||||
- `actionText`
|
||||
- 对话文本
|
||||
- 基于上下文的语气、叙事张力、选项措辞
|
||||
- 本地规则负责决定:
|
||||
- 哪些 function 当前可执行
|
||||
- 技能是否在 CD
|
||||
- 蓝量是否足够
|
||||
- 伤害、回复、掉血、死亡、掉落
|
||||
- 场景切换是否合法
|
||||
- 背包、装备、属性、队伍变化
|
||||
|
||||
经验结论:
|
||||
|
||||
- 涉及数值、资源、状态迁移的部分,不要交给模型临场决定。
|
||||
- 模型应被限制在“叙事表达层”,不要替代规则系统。
|
||||
- 用户每次选择后只做一次模型推理,因此提示词必须一次性包含足够边界,不能再依赖后处理改写和过滤。
|
||||
|
||||
## 4. Function 驱动设计经验
|
||||
|
||||
当前更合理的设计方向是:
|
||||
|
||||
- 所有可选行为都落到 function。
|
||||
- 每个 function 只有这些核心字段:
|
||||
- `id`
|
||||
- `text`
|
||||
- `description`
|
||||
- `category`
|
||||
- `功能代码`
|
||||
- 运行时先汇总当前场景的 function,再结合角色、状态、敌人、场景实体、资源状态做合法性过滤。
|
||||
- 模型只在“当前合法 function 集合”内生成选项文本和剧情文本。
|
||||
|
||||
经验结论:
|
||||
|
||||
- 选项不是自由散文,而是 function 的叙事包装。
|
||||
- function 必须和角色、状态、场景、实体绑定,不能做成完全漂浮的公共动作池。
|
||||
- “每次选择只能并且必须命中一个 function” 是保持状态稳定的关键。
|
||||
|
||||
## 5. 战斗与动画的经验
|
||||
|
||||
战斗部分已经沉淀出的几个重要规则:
|
||||
|
||||
### 5.1 结算时机
|
||||
|
||||
- 用户点击选项后,后台状态应立即推进到“动画完成后的结果状态”,并把这个新状态放入后续推理上下文。
|
||||
- 但扣血、死亡表现、消失等视觉结果要在动画播完后再体现在画面上。
|
||||
|
||||
这样做的好处:
|
||||
|
||||
- 模型推理可以立即开始,不被动画阻塞。
|
||||
- 画面依然保留正确的演出节奏。
|
||||
- 状态、上下文、下一轮推理不会落后于动画。
|
||||
|
||||
### 5.2 近战位移
|
||||
|
||||
- 近战动画不能按固定像素移动。
|
||||
- 必须按左右锚点、舞台宽度和目标位置计算真实接近距离。
|
||||
- 宽屏下如果只“往前走一点点”,基本就是位移基准用了屏幕百分比或固定偏移,而不是双方真实锚点差值。
|
||||
|
||||
### 5.3 死亡与退出战斗
|
||||
|
||||
- 怪物血量归零时先播死亡动画。
|
||||
- 死亡动画完成后怪物再消失。
|
||||
- 若敌方死亡,战斗状态应退出,切回空闲状态,并重新切换可用 function 集合。
|
||||
|
||||
### 5.4 逃跑与压迫感
|
||||
|
||||
- 逃跑镜头要跟着玩家,不是跟怪物。
|
||||
- 玩家向前跑,怪物被越甩越远,才能形成“甩开追兵”的感觉。
|
||||
- 相反,如果镜头锚在怪物侧,会让玩家像没动一样。
|
||||
|
||||
## 6. 遭遇、场景与地图经验
|
||||
|
||||
这部分已经验证有效的设计原则:
|
||||
|
||||
- 场景和背景图一一绑定,不切场景就不换背景。
|
||||
- 场景切换必须由选项命中的 function 驱动,而不是每回合自动变化。
|
||||
- 每个场景预设自己的怪物、NPC、宝藏池。
|
||||
- 玩家“继续向前探路”时,不是立刻随机弹结果,而是先预生成前方实体,再通过移动和镜头演出把它带到正式交互位。
|
||||
|
||||
经验结论:
|
||||
|
||||
- “探索”也应该是一种可演出的 function,而不只是一次文字刷新。
|
||||
- 同一时刻只应遇到一个主实体,避免一回合同时出现多只怪物造成状态混乱。
|
||||
- 地图系统适合做成场景连接图,由具体 function 触发前往某个场景。
|
||||
|
||||
## 7. 移动端优先的 UI 经验
|
||||
|
||||
已经验证有效的 UI 方向:
|
||||
|
||||
- 先保证移动端一屏成立,再兼容网页宽屏。
|
||||
- 开始页、世界选择、角色选择都要像游戏流程,而不是产品介绍页。
|
||||
- 世界选择适合纵向焦点滑动。
|
||||
- 角色选择适合横向翻卡和中心焦点展示。
|
||||
- 冒险页中:
|
||||
- 上方是画面演出
|
||||
- 中间是自适应剧情文本
|
||||
- 底部是固定的选项与功能入口
|
||||
|
||||
经验结论:
|
||||
|
||||
- 剧情区域不能写死高度,应填满画面下方和底部操作条上方之间的剩余空间。
|
||||
- 队伍、背包更适合作为弹出面板,不应该切走主流程。
|
||||
- 地图弹窗、队伍面板、背包详情都必须按手机窄屏重新组织,不要沿用桌面弹窗思路。
|
||||
|
||||
## 8. 选择页与游戏内界面经验
|
||||
|
||||
这轮迭代里比较明确的 UI 结论有:
|
||||
|
||||
- 开始页只保留核心按钮,视觉简洁更像正式游戏。
|
||||
- 世界选择页要突出当前聚焦卡,其他卡随滑动连续改变透明度和大小。
|
||||
- 角色选择页中:
|
||||
- 中间卡片不能模糊
|
||||
- 左右卡片要做正确方向的倾斜
|
||||
- 中间角色可播放 `run` 动画
|
||||
- 角色名称显示在动画下方
|
||||
- 属性和背景信息要紧凑,不能压缩掉上方卡片滑动空间
|
||||
- 游戏内按钮应尽量图标化,把更多空间留给剧情和选项。
|
||||
|
||||
## 9. NPC 形象编辑器经验
|
||||
|
||||
NPC 编辑器这部分已经沉淀出一些通用原则:
|
||||
|
||||
- 这套 Medieval Fantasy Characters 素材不是传统逐帧全身序列帧,发型、脸型、胡子、武器等部件不能按“每帧都变化”的思路处理。
|
||||
- 主手武器、副手武器、手、身体、头部、头饰需要明确图层关系。
|
||||
- 主手武器必须真正握在手里,不能只靠大概位置“看起来差不多”。
|
||||
- 因为素材高度重叠,编辑器里必须支持:
|
||||
- 底部组件模块点击选择
|
||||
- 键盘上下左右微调
|
||||
- 拖拽微调
|
||||
- 回滚按钮
|
||||
|
||||
经验结论:
|
||||
|
||||
- 视觉编辑器如果没有“可控选择 + 微调 + 回滚”,用户会很难调重叠素材。
|
||||
- 选项命名不能直接暴露英文源文件名,最好转成更贴近视觉理解的中文名称。
|
||||
- 编辑器产出的相对位置数据必须能直接落回项目运行时,不然就只是一个孤立工具。
|
||||
|
||||
## 10. 大模型接入与本地调试经验
|
||||
|
||||
这部分踩坑非常集中,结论也比较清晰:
|
||||
|
||||
### 10.1 前端不能直连目标模型接口
|
||||
|
||||
- 浏览器直连时会遇到 CORS。
|
||||
- 即使接口本身可用,浏览器环境也可能被跨域限制。
|
||||
- 更稳的方案是在开发服务器侧做代理,再由前端请求本地 `/api/llm/...`。
|
||||
|
||||
### 10.2 需要日志,但日志要聚焦
|
||||
|
||||
已经证明有价值的日志包括:
|
||||
|
||||
- 单次推理耗时
|
||||
- 原始提示词文本
|
||||
- 原始返回中的解析后文本
|
||||
- 失败时的模型名、状态码和错误正文
|
||||
|
||||
### 10.3 开发服务器要统一入口
|
||||
|
||||
本项目本地正确启动方式应统一走:
|
||||
|
||||
```bash
|
||||
node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0
|
||||
```
|
||||
|
||||
经验结论:
|
||||
|
||||
- 只要本地存在旧进程、旧脚本或错误端口映射,就很容易出现“代码改了但界面还是旧的”假象。
|
||||
- 遇到这类问题,优先检查实际启动脚本、端口占用和返回模块内容,而不是先怀疑 UI 代码没生效。
|
||||
|
||||
## 11. 编辑器与正式运行时的关系
|
||||
|
||||
已经验证最稳的做法是:
|
||||
|
||||
- 编辑器预览直接复用正式运行时函数。
|
||||
- 预览不自己模拟一套战斗和 function 执行逻辑。
|
||||
- 运行时怎么结算,编辑器就怎么调用。
|
||||
|
||||
经验结论:
|
||||
|
||||
- 只要编辑器预览和正式逻辑分成两套,后面一定会越来越不一致。
|
||||
- 预览系统的价值不是“看起来像”,而是“执行路径就是正式路径”。
|
||||
|
||||
## 12. 后续继续开发时建议遵循的顺序
|
||||
|
||||
推荐流程:
|
||||
|
||||
1. 先补数据结构和类型。
|
||||
2. 再补 function 规则和过滤条件。
|
||||
3. 再补 hook 流程与状态迁移。
|
||||
4. 再补动画和演出。
|
||||
5. 最后再做 UI 细修。
|
||||
6. 每轮改动后至少做一次类型检查和本地启动验证。
|
||||
|
||||
不推荐的流程:
|
||||
|
||||
1. 先堆 UI。
|
||||
2. 再临时塞状态。
|
||||
3. 最后补运行逻辑。
|
||||
|
||||
这类项目里,后者几乎一定导致返工。
|
||||
|
||||
## 13. 后端修改后的重启与测试
|
||||
|
||||
后端代码更新后统一执行:
|
||||
|
||||
```bash
|
||||
npm run api-server:maincloud
|
||||
```
|
||||
|
||||
执行要求:
|
||||
|
||||
- 该命令是后端更新后的默认重启入口,不再使用此前的后端重启命令。
|
||||
- 重启后必须继续执行与本次后端改动对应的自动测试;涉及 Rust workspace 时优先跑 `server-rs` 下的检查或测试脚本。
|
||||
- 若本次改动涉及 SpacetimeDB 发布、绑定生成或 Maincloud 联调,按 `spacetimedb-cli` 经验执行,并在验证记录中写清楚实际命令与结果。
|
||||
|
||||
## 14. 一句话总结
|
||||
|
||||
这个项目最重要的经验不是“做了多少页面和功能”,而是:
|
||||
|
||||
**必须把 AI 文本生成、本地规则、动画演出、场景状态、编辑器工具这几套系统严格分层,再通过 function 和统一状态流把它们重新接起来。**
|
||||
|
||||
## 15. 相关文档
|
||||
|
||||
如需继续细看已有沉淀,可结合以下文档一起阅读:
|
||||
|
||||
- `docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||||
- `docs/experience/MOBILE_UI_DEV_EXPERIENCE.md`
|
||||
- `docs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md`
|
||||
- `docs/experience/AGENT_UI_CHANGELOG.md`
|
||||
32
docs/experience/README.md
Normal file
32
docs/experience/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# 经验沉淀
|
||||
|
||||
这一组文档主要回答两个问题:
|
||||
|
||||
- 这个项目开发时有哪些稳定有效的方法论。
|
||||
- 遇到 UI、运行时、编辑器、AI 边界问题时,优先应该怎么判断。
|
||||
|
||||
## 推荐入口
|
||||
|
||||
1. [PROJECT_WORK_EXPERIENCE_PLAYBOOK.md](./PROJECT_WORK_EXPERIENCE_PLAYBOOK.md):最完整的项目开发手册,适合先建立全局认识。
|
||||
2. [PROJECT_DEVELOPMENT_EXPERIENCE.md](./PROJECT_DEVELOPMENT_EXPERIENCE.md):项目级经验浓缩版,适合快速回顾。
|
||||
3. [ADVENTURE_RUNTIME_DEV_EXPERIENCE.md](./ADVENTURE_RUNTIME_DEV_EXPERIENCE.md):专门看运行时、战斗、演出、NPC 流程时优先读。
|
||||
4. [MOBILE_UI_DEV_EXPERIENCE.md](./MOBILE_UI_DEV_EXPERIENCE.md):做移动端/游戏 UI 时的布局和交互经验。
|
||||
5. [AGENT_UI_CHANGELOG.md](./AGENT_UI_CHANGELOG.md):当前 UI 改动脉络、资产约束和已知坑。
|
||||
|
||||
## 历史实现经验
|
||||
|
||||
- [CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md](./CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md):偏“这类需求怎么拆链路”的实战经验。
|
||||
- [CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md](./CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md):偏“之前做过什么、怎么做的”的历史记录。
|
||||
|
||||
## 使用建议
|
||||
|
||||
- 只需要读一份时,优先看 `PROJECT_WORK_EXPERIENCE_PLAYBOOK`。
|
||||
- 做 UI 改动时,把本目录和根目录的 `UI_CODING_STANDARD.md` 对照着看。
|
||||
- 做运行时流程改动时,把本目录和 `docs/audits/engineering/README.md` 一起看,能更快发现风险边界。
|
||||
|
||||
## 近期专项记录
|
||||
|
||||
- [RPG_DRAFT_IMAGE_PARALLEL_GENERATION_2026-04-24.md](./RPG_DRAFT_IMAGE_PARALLEL_GENERATION_2026-04-24.md):记录 RPG 底稿阶段角色主形象与场景背景图并行生成约束。
|
||||
- [PLATFORM_HOME_BANNER_IMAGE_SIZE_FIX_2026-04-25.md](./PLATFORM_HOME_BANNER_IMAGE_SIZE_FIX_2026-04-25.md):记录首页 banner 背景图不能进入普通布局流的修复经验。
|
||||
- [RPG_PUBLISH_GALLERY_REFRESH_FIX_2026-04-25.md](./RPG_PUBLISH_GALLERY_REFRESH_FIX_2026-04-25.md):记录 RPG 发布后首页 / 分类页公开作品列表刷新链路。
|
||||
- [AGENT_EMPTY_SESSION_DRAFT_VISIBILITY_2026-04-26.md](./AGENT_EMPTY_SESSION_DRAFT_VISIBILITY_2026-04-26.md):记录 Agent 空会话不应进入作品草稿列表的后端判定规则。
|
||||
@@ -0,0 +1,32 @@
|
||||
# RPG 幕背景默认描述来源修正 2026-04-24
|
||||
|
||||
## 背景
|
||||
|
||||
草稿编辑器中“AI 生成幕背景”的“画面内容描述”曾出现类似“温馨员工宿舍第1幕背景;玩家入职后的首个落脚处;玩家会在温馨员工宿舍接住这一章的开场入口。”的默认文本。这类文本不是大模型直接写出的画面描述,而是前端或后端在缺少 `backgroundPromptText` 时,把地点名、幕标题、摘要规则句拼接出来的兜底文案。
|
||||
|
||||
## 落地约束
|
||||
|
||||
1. 幕背景图的默认画面描述必须来自草稿生成链路里的关键场景生成步骤,字段源为 `landmarks[*].actBackgroundPromptTexts[*]`。
|
||||
2. `sceneChapterBlueprints[*].acts[*].backgroundPromptText` 只承接上述幕级大模型产物,不再用 `title`、`summary`、地点描述或规则句拼接。
|
||||
3. 如果大模型漏产某一幕描述,后端规范化只保留空字符串,让后续生图前的 `backgroundPromptText` 校验暴露底稿质量问题,不能伪造可用默认文本。
|
||||
4. 前端编辑器 sanitize 只展示已有 `act.backgroundPromptText`;缺失时留空,不能在 UI 层重新拼接默认描述。
|
||||
5. 手动打开 AI 生成面板时,若字段为空,可由用户输入,但系统默认不替用户生成规则句。
|
||||
|
||||
## 当前实现
|
||||
|
||||
- `server-rs/crates/api-server/src/custom_world_foundation_draft.rs` 的关键场景框架 prompt 要求 LLM 为每个地点生成 3 条 `actBackgroundPromptTexts`。
|
||||
- 草稿合成阶段通过 `build_scene_chapter_blueprints_from_landmarks` 把这些幕级描述写入 `sceneChapterBlueprints[*].acts[*].backgroundPromptText`。
|
||||
- `normalize_scene_act_blueprint` 不再把缺失描述补成“标题 + 摘要 + 通用场景背景”格式。
|
||||
- `src/components/rpg-creation-editor/RpgCreationEntityEditorShared.tsx` 不再用地点名、幕标题和 `actSummary` 生成 `backgroundPromptText` fallback。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- 新草稿中每一幕的 `backgroundPromptText` 应该像自然的画面描述,包含主体、前中远景、站位空间、氛围识别点。
|
||||
- 不应再出现“第1幕背景;玩家会在……”这类明显拼接句。
|
||||
- 如果 LLM 漏掉 `actBackgroundPromptTexts`,生成幕背景图阶段应失败并提示缺少 `backgroundPromptText`,而不是静默使用拼接文案。
|
||||
|
||||
## 2026-04-24 并发限流错误处理补充
|
||||
|
||||
- 批量生成幕背景图时,`JoinSet` 子任务的成功值和失败值固定承载 `(chapter_index, act_index, message)`,用于把错误精确标记回对应章节幕。
|
||||
- `Semaphore::acquire` 的 `AcquireError` 不能在子任务中转成裸 `String` 后直接使用 `?`,否则会破坏子任务统一错误类型并导致 `E0277`。
|
||||
- 限流器异常应映射为同一组三元组错误,保持后续 `mark_scene_act_background_generation_error` 和部分成功保留逻辑可复用。
|
||||
@@ -0,0 +1,23 @@
|
||||
# RPG 场景幕角色配置面板布局经验 2026-04-26
|
||||
|
||||
## 背景
|
||||
|
||||
场景多幕配置里的“配置角色”面板是高频编辑弹层,移动端和桌面端都需要快速完成选择并保存。
|
||||
|
||||
## 本次约束
|
||||
|
||||
1. 面板底部不再放“取消”按钮,关闭统一交给标题栏关闭按钮和遮罩。
|
||||
2. “保存角色”必须位于面板底部操作区,角色列表较长时只滚动内容区,不把保存按钮滚出视口。
|
||||
3. 已选角色时仍允许“移除角色”,但移动端纵向排列时保存按钮保持在最底部。
|
||||
4. 不在面板内新增功能说明文本,维持清爽编辑体验。
|
||||
5. 吸底操作区必须使用平台语义色 token,不能写死深色 Tailwind 背景,避免亮色主题下出现突兀深色底栏。
|
||||
6. 已选角色时,底部操作区保持同一行:左侧“移除角色”热区占 1/4,右侧“保存角色”占 3/4;未选角色时保存按钮占满整行。
|
||||
|
||||
## 落地位置
|
||||
|
||||
- `src/components/rpg-creation-editor/RpgCreationEntityEditorShared.tsx`
|
||||
- `SceneActNpcSlotPickerModal`
|
||||
|
||||
## 后续复用
|
||||
|
||||
以后新增类似独立选择弹层时,优先采用“标题栏 + 中间滚动内容 + 底部固定主动作”的结构;取消类动作不要默认占据底部按钮位,避免和主保存动作抢焦点。
|
||||
@@ -0,0 +1,46 @@
|
||||
# RPG 底稿图片并行生成说明 2026-04-24
|
||||
|
||||
## 背景
|
||||
|
||||
RPG 草稿生成进入底稿素材阶段后,角色主形象与场景幕背景图都依赖同一份结构化底稿,但二者之间没有数据依赖。旧流程先生成所有角色主形象,再生成场景背景图,导致用户需要串行等待两类图片任务。
|
||||
|
||||
## 落地约束
|
||||
|
||||
1. 角色主形象与场景背景图必须在 API 编排层并行发起,且类内每个角色、每一幕背景也必须同时调用生图接口,不能只做到“角色大类”和“背景大类”并行。这里的场景背景图指 `sceneChapterBlueprints[*].acts[*]` 中每一幕的 `backgroundImageSrc`,不是世界封面图,也不是只按章节或地点生成一张图。
|
||||
2. SpacetimeDB reducer 只负责持久化操作进度和底稿写入,不承载外部 LLM / 图片生成调用。
|
||||
3. 生图前必须已经有文本设定:角色主形象使用角色对象的 `visualDescription`;幕背景图使用对应幕的 `backgroundPromptText`。缺字段时应中断并暴露底稿质量问题,不能退回 `description`、`summary` 或通用兜底词直接生图。
|
||||
4. 并行分支各自基于同一份底稿副本写入素材字段,完成后只合并背景图生成产物字段,避免覆盖角色图片字段或其他草稿内容。
|
||||
5. 单个大类失败仍按原有失败语义终止底稿写入,保留“生成角色主形象失败”和“生成幕背景图失败”的进度提示。
|
||||
|
||||
## 当前实现
|
||||
|
||||
- `server-rs/crates/api-server/src/custom_world.rs` 在 `spawn_custom_world_draft_foundation_job` 中使用 `tokio::join!` 同时执行:
|
||||
- `generate_draft_foundation_role_visuals`
|
||||
- `generate_draft_foundation_act_backgrounds`
|
||||
- 角色分支使用 `JoinSet` 把所有角色主形象任务一次性投递,返回后再按角色位置写入 `imageSrc` 与 `generatedVisualAssetId`。
|
||||
- 背景分支使用 `JoinSet` 把 `sceneChapterBlueprints[*].acts[*]` 的每一幕背景任务一次性投递,返回后写入 `backgroundImageSrc`、`backgroundAssetId`、`generatedScenePrompt`、`generatedSceneModel`。
|
||||
- `merge_generated_act_backgrounds` 只把背景图字段合并回角色分支副本,再进入后续草稿卡编译和 SpacetimeDB 写入。
|
||||
- 幕背景 prompt 同时兼容 `backgroundPromptText`、`scenePromptText`、`visualPromptText`、`promptText`、`imagePromptText`、`backgroundPrompt`、`visualPrompt`,避免 LLM 输出字段别名导致整批背景图被误判缺失。
|
||||
- 每个角色主形象、每一幕背景图都必须独立自动重试,单项最多尝试 3 次。幕背景图允许部分成功:只要至少一幕成功,就必须保留已成功写入的 `backgroundImageSrc` 并继续生成草稿卡;全部幕都失败时才把素材阶段标记为“生成幕背景图失败”。
|
||||
- 图片任务仍然一次性投递,保证角色与幕背景两类任务不回退到串行编排;但真正请求上游生图服务时必须共用并发闸门。并发数由 `GENARRATIVE_DRAFT_ASSET_GENERATION_MAX_CONCURRENT_REQUESTS` 或 `DRAFT_ASSET_GENERATION_MAX_CONCURRENT_REQUESTS` 配置,默认 4,避免固定为 2 导致多角色、多幕草稿总耗时过长。
|
||||
- 幕背景图失败文案必须带第几章、第几幕和幕标题,不能只显示“第1幕 / 第2幕 / 第3幕”,否则多章节同名幕会被用户误认为同一失败项重复上报。
|
||||
- 中止或部分失败前必须持久化已经成功生成的部分底稿到会话 `draftProfile`,不能因为某个角色或某一幕失败而丢掉其它已生成的 `imageSrc / generatedVisualAssetId / backgroundImageSrc / backgroundAssetId`。
|
||||
- 每一幕自动生图必须记录 operation、session、第几章、第几幕、sceneId、sceneName、attempt、elapsedMs 与供应商真实错误,避免再次出现只看到“生成幕背景图失败”但无法定位哪张图、哪次请求、哪个上游原因的问题。
|
||||
- 前端看到 `draft_foundation` operation completed 后,不能只延迟一次就读取 `resultPreview`;SpacetimeDB 写入、API 读模型和前端状态同步之间可能有短暂时差,必须短轮询等待结果页 profile 可用后再自动跳转到草稿页,避免卡在“底稿已整理”。
|
||||
- 前端 `CharacterAnimator` 对带 `generatedVisualAssetId` 但尚无 `animationMap` 的自定义角色,所有状态优先渲染生成主图;只有真正发布了动作集后才按动作帧播放,避免运行或战斗状态回落到模板 sprite。
|
||||
|
||||
## 后续注意
|
||||
|
||||
如果后续图片供应商出现强限流,再在网关层做队列或供应商侧限流;不要在 RPG 底稿编排层恢复逐张串行,否则会重新退化成多张图片总耗时累加。
|
||||
|
||||
|
||||
|
||||
|
||||
## 2026-04-25 补充:开局场景也必须逐幕生成背景图
|
||||
|
||||
本次排查发现旧草稿合成只从 `landmarks` 编译 `sceneChapterBlueprints`,导致 `camp` 开局场景只有 `camp.imageSrc`,没有进入 `sceneChapterBlueprints[*].acts[*]` 的幕背景生成队列。后续实现必须遵守:
|
||||
|
||||
1. `camp` 开局场景必须作为 `sceneChapterBlueprints[0]` 写入,`sceneId` 默认使用 `camp.id`,缺失时使用 `camp-1`。
|
||||
2. `camp.actBackgroundPromptTexts` 必须包含 3 条逐幕画面描述,并和普通场景一样生成 `acts[*].backgroundImageSrc`。
|
||||
3. 结果页场景目录可用场景图兜底展示旧草稿的幕缩略图,但新草稿不能只依赖兜底,必须让开局场景真实进入幕背景图生成链路。
|
||||
4. 手动同步场景资产时,必须同时更新 `sceneChapterBlueprints` 与兼容字段 `sceneChapters`,当前主链以 `sceneChapterBlueprints` 为准。
|
||||
@@ -0,0 +1,36 @@
|
||||
# RPG 发布作品广场刷新修复 2026-04-25
|
||||
|
||||
## 背景
|
||||
|
||||
已发布 RPG 作品会进入 `custom_world_profile`,并由 SpacetimeDB 模块同步到公开读模型 `custom_world_gallery_entry`。平台首页和分类页不直接读取“我的作品”,而是共同消费 `/api/runtime/custom-world-gallery` 返回的公开作品列表。
|
||||
|
||||
本次问题表现为:结果页显示发布完成后,作品没有立即出现在平台首页和分类页。
|
||||
|
||||
## 修复原则
|
||||
|
||||
1. `publish_world` 必须写入真实作者公开信息。
|
||||
- Axum 层在执行 `publish_world` 前补充 `authorPublicUserCode` 与 `authorDisplayName`。
|
||||
- SpacetimeDB 模块发布时优先使用 payload 中的作者公开信息,再退回历史兜底。
|
||||
|
||||
2. 发布完成后必须刷新公开广场列表。
|
||||
- 前端 `executePublishWorld` 等待发布 operation 完成后,同时刷新 `refreshPublishedGallery()` 与 `refreshCustomWorldWorks()`。
|
||||
- 首页和分类页都复用 `publishedGalleryEntries`,因此刷新 gallery 后两个页面会同步看到新发布作品。
|
||||
|
||||
## 多玩法公开列表补充
|
||||
|
||||
- 平台首页 / 分类页不是只展示 RPG 作品,也需要展示已经发布到公开接口的 Puzzle 作品。
|
||||
- Puzzle 已有 `/api/runtime/puzzle/gallery` 公开接口;平台入口额外读取该接口,并把 `PuzzleWorkSummary` 映射为首页卡片模型。
|
||||
- 首页 / 分类页按 `rpg:{ownerUserId}:{profileId}` 与 `puzzle:{ownerUserId}:{profileId}` 去重后按发布时间排序。
|
||||
- 点击 RPG 卡片仍进入 RPG 公开详情;点击 Puzzle 卡片进入现有 Puzzle 广场详情,不复用 RPG 详情链路。
|
||||
|
||||
3. 历史已发布作品必须能自动补齐 gallery 投影。
|
||||
- 公开列表读取 `list_custom_world_gallery_entries` 前,会扫描 `custom_world_profile` 中已发布且未删除的 profile。
|
||||
- 若已发布 profile 缺少 `custom_world_gallery_entry`,或缺少公开作品码 / 作者叙世号,会先补齐公开字段并同步 gallery 投影。
|
||||
- 这样旧版本发布成功但未落入广场读模型的作品,在下一次首页 / 分类页读取公开列表时会自动出现。
|
||||
|
||||
## 经验
|
||||
|
||||
- 作品发布链不能只看“我的创作”列表,必须同时检查公开读模型。
|
||||
- 分类页的数据不是独立接口,修首页公开列表通常也会影响分类页。
|
||||
- Agent 发布链和普通 library profile 发布链要共享公开作者字段语义,避免同一个 gallery card 在不同发布入口下字段不一致。
|
||||
- 已发布 profile 与 gallery 投影不是同一张表,线上修复时要考虑历史数据补投影,不能只修新增发布路径。
|
||||
@@ -0,0 +1,30 @@
|
||||
# RPG 角色形象描述数据链路核查 2026-04-24
|
||||
|
||||
## 结论
|
||||
|
||||
草稿生成阶段会让大模型为每个可扮演角色和场景角色生成 `visualDescription`,该字段是角色主形象生成和资产工坊“形象描述”输入框的同一份默认文本来源。
|
||||
|
||||
本次核查发现前端 `normalizeCustomWorldProfileRecord` 曾在规范化 `playableNpcs` / `storyNpcs` 时丢弃 `visualDescription`、`actionDescription`、`sceneVisualDescription`。因此后端草稿 JSON 中有大模型生成的文字,但草稿进入前端编辑器后,资产工坊可能只能回退到 `description`,用户看不到真正的角色形象文字描述。
|
||||
|
||||
## 数据链路
|
||||
|
||||
1. 后端草稿生成:`server-rs/crates/api-server/src/custom_world_foundation_draft.rs`
|
||||
- 角色框架名单 prompt 要求 LLM 输出 `visualDescription`、`actionDescription`、`sceneVisualDescription`。
|
||||
- `visualDescription` 定义为打开角色形象图像生成面板时默认填入的角色形象描述。
|
||||
2. 后端角色主形象生成:`server-rs/crates/api-server/src/custom_world.rs`
|
||||
- `generate_draft_foundation_role_visuals` 从角色对象读取 `visualDescription`。
|
||||
- 缺失时直接失败,提示不能在角色形象设定文本生成前生图。
|
||||
- 生图成功只写回 `imageSrc` 和 `generatedVisualAssetId`,不会覆盖 `visualDescription`。
|
||||
3. 草稿持久化:草稿 profile JSON 保留角色对象字段,`visualDescription` 应与图片字段一起进入保存载荷。
|
||||
4. 前端规范化:`src/data/customWorldLibrary.ts`
|
||||
- `normalizePlayableNpc` / `normalizeStoryNpc` 必须保留三类资产描述字段。
|
||||
5. 资产工坊展示:`src/components/rpg-creation-asset-studio/RpgCreationRoleAssetStudioModalImpl.tsx`
|
||||
- modal 用角色对象构造 `baseRole`。
|
||||
- `buildDefaultRolePromptBundle(baseRole)` 优先把 `role.visualDescription` 转成 `visualPromptText`。
|
||||
- `RpgCreationRoleVisualSection` 的“形象描述” TextArea 展示 `visualPromptText`。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- 草稿生成完毕后,打开某个角色的资产工坊,应在“形象描述”框看到 LLM 生成的 `visualDescription`。
|
||||
- 如果角色有 `visualDescription`,缓存中的旧 `visualPromptText` 不应覆盖它。
|
||||
- 如果角色缺 `visualDescription`,才允许前端回退到更弱的字段或缓存文本。
|
||||
@@ -0,0 +1,30 @@
|
||||
# 世界草稿发布面板与测试入口设计 2026-04-24
|
||||
|
||||
## 目标
|
||||
|
||||
世界草稿页底部不再只有“发布并进入世界”一个动作,而是拆成两个明确入口:
|
||||
|
||||
1. 作品测试:跳过发布阻断项检查,直接进入当前草稿游戏体验。
|
||||
2. 发布:打开发布面板,在面板内集中处理发布阻断项与封面设置,满足条件后发布到广场。
|
||||
|
||||
## 页面范围
|
||||
|
||||
- `src/components/rpg-creation-result/RpgCreationResultActionBar.tsx`
|
||||
- `src/components/rpg-creation-result/RpgCreationResultViewImpl.tsx`
|
||||
- `src/components/CustomWorldEntityCatalog.tsx`
|
||||
- `src/components/rpg-entry/useRpgCreationEnterWorld.ts`
|
||||
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
|
||||
|
||||
## 交互规则
|
||||
|
||||
1. 世界草稿页右下角显示“作品测试”和“发布”两个按钮。
|
||||
2. “作品测试”只同步当前草稿结果并进入游戏,不触发发布阻断项检查,也不执行发布动作。
|
||||
3. “发布”打开独立发布面板,不在当前页面下方展开内容。
|
||||
4. 发布面板显示当前阻断项;没有阻断项时允许执行发布。
|
||||
5. 发布面板显示封面预览与封面状态,并提供“设置封面”入口。
|
||||
6. 封面生成、封面上传与封面预览从世界档案页迁移到发布面板;世界档案页不再展示作品封面模块。
|
||||
7. 移动端仍使用底部弹层式面板,PC 端使用居中 modal。
|
||||
|
||||
## 发布后行为
|
||||
|
||||
发布成功后刷新本地结果档案,并进入正式世界;作品由既有 `publish_world` 流程同步到作品库 / 广场。
|
||||
@@ -0,0 +1,346 @@
|
||||
# 方向 13 软件智能化提升奖励材料整理(2026-04-14)
|
||||
|
||||
## 1. 方向判断
|
||||
|
||||
### 1.1 与当前项目的匹配点
|
||||
|
||||
当前项目与附件 13 的匹配点主要有:
|
||||
|
||||
1. 项目本质上是 `游戏软件` 的智能化提升。
|
||||
2. AI 能力不是外挂聊天,而是深入到剧情、世界生成、任务、NPC 关系、运行时内容编排等核心软件功能。
|
||||
3. 当前项目具有完整软件工程形态:
|
||||
- 前端应用
|
||||
- `Express` 后端
|
||||
- 数据存储
|
||||
- AI 服务编排
|
||||
- 编辑器与内容工具链
|
||||
|
||||
### 1.2 当前方向的主要风险
|
||||
|
||||
附件 13 的门槛并不低,当前必须优先核验以下事项:
|
||||
|
||||
1. 项目纳入奖励范围的总投资额是否 `>= 500 万元`
|
||||
2. 项目是否已经 `竣工并投入运行`
|
||||
3. 项目建设周期是否 `<= 2 年`
|
||||
4. 是否具备 `2 项软著` 或 `1 项发明专利`
|
||||
5. 是否已接入 `已备案国产主流大模型`
|
||||
6. 是否有 `日均 Token >= 500 万`
|
||||
7. 是否能满足 `5 个不同客户案例` 或 `5 万 DAU`
|
||||
8. 是否能取得 `CNAS/CMA` 机构出具的软件智能化成熟度测评报告
|
||||
|
||||
如果以上条件中有 3 项以上暂无依据,建议把方向 13 视为“高潜力但高补件强度”的主申报方向,而不是“马上能提报”的方向。
|
||||
|
||||
## 2. 官方要求拆解
|
||||
|
||||
### 2.1 申报条件
|
||||
|
||||
1. 在北京市登记注册,具有独立法人资格的信息软件企业
|
||||
2. 项目纳入奖励范围的总投资额超过 `500 万元(含)`
|
||||
3. 截至申报日项目已竣工并投入运行,竣工时间在 `2025 年 1 月 1 日` 及以后
|
||||
4. 项目形成的智能软件产品具备自主知识产权,取得不少于 `2 项软著` 或 `1 项发明专利`
|
||||
5. 项目建设周期不超过 `2 年`
|
||||
|
||||
### 2.2 绩效要求
|
||||
|
||||
项目需同时满足以下条件:
|
||||
|
||||
1. 形成智能化软件开发能力
|
||||
- 代码生成占比 `>= 35%`,或代码行采纳率 `>= 30%`
|
||||
|
||||
2. 形成智能化软件产品
|
||||
- 接入已备案国产主流大模型
|
||||
- 具备自然语言或多模态交互
|
||||
- 日均 Token 消耗量不少于 `500 万`
|
||||
- 软件智能化成熟度至少达到 `部分智能化`
|
||||
|
||||
3. 具备行业应用效果
|
||||
- 面向企业端:至少 `5 个不同客户`
|
||||
- 面向消费者端:`DAU > 5 万`
|
||||
|
||||
## 3. 申报材料总清单
|
||||
|
||||
### 3.1 必交材料
|
||||
|
||||
1. 《北京市软件智能化提升项目绩效要求》对应证明材料
|
||||
2. 《智能化提升项目纳入奖励范围的总投资要求》对应专项审计与明细
|
||||
3. 《智能化提升奖励申报表》
|
||||
4. 《智能化提升项目实施总结报告》及证明材料
|
||||
5. 《北京市高精尖产业发展项目资金承诺书》
|
||||
6. 企业最新版营业执照复印件
|
||||
7. 其他与项目有关的补充资料
|
||||
|
||||
### 3.2 材料与项目事实的对应关系
|
||||
|
||||
| 官方材料 | 需要表达什么 | 当前项目可复用内容 | 当前待补件 |
|
||||
| --- | --- | --- | --- |
|
||||
| 申报表 | 项目基本信息、投资、创新点、成效、推广性 | `README.md`、`docs/prd/`、`docs/technical/` | 企业信息、投资额、建设时间、客户/DAU、资金支持情况 |
|
||||
| 实施总结报告 | 项目背景、建设方案、关键技术、投资、绩效、效益 | `README.md`、剧情引擎/自定义世界/技术文档 | 立项/结项文件、专项审计、成熟度测评、日志证明 |
|
||||
| 技术设备与投资明细 | 硬件、软件、材料、研发人员投入 | 可从采购、云资源、模型调用、开发工具里整理 | 发票、合同、付款凭证、记账凭证、审计报告 |
|
||||
| 知识产权证明 | 项目形成软件的自主知识产权 | 仓库结构、架构、功能模块可支撑匹配说明 | 软著/专利证书本体 |
|
||||
| 绩效证明 | AI 编码、模型接入、Token、成熟度、应用效果 | 代码仓库、运行日志、接口能力说明 | 第三方编码平台证明、Token 数据、测评报告、客户合同或 DAU |
|
||||
|
||||
## 4. 建议的申报项目命名
|
||||
|
||||
建议在以下 3 个口径中选一个:
|
||||
|
||||
1. `AI 原生剧情引擎与游戏软件智能化提升项目`
|
||||
2. `面向互动叙事游戏的 AI 原生剧情引擎智能化提升项目`
|
||||
3. `跨题材 AI 原生叙事游戏软件智能化改造项目`
|
||||
|
||||
推荐优先使用:
|
||||
|
||||
`AI 原生剧情引擎与游戏软件智能化提升项目`
|
||||
|
||||
原因:
|
||||
|
||||
- 兼顾 `游戏软件` 与 `智能化提升`
|
||||
- 不把自己限制成单一玩法
|
||||
- 后续客户案例或平台化能力也更好挂靠
|
||||
|
||||
## 5. 申报表字段建议底稿
|
||||
|
||||
### 5.1 项目所属领域
|
||||
|
||||
建议填写:
|
||||
|
||||
- `游戏软件`
|
||||
|
||||
### 5.2 项目主要内容(1000 字内,可作为首稿)
|
||||
|
||||
建议首稿:
|
||||
|
||||
> 本项目围绕 AI 原生视觉 RPG 产品开展智能化提升,建设内容覆盖 AI 原生剧情引擎、自定义世界生成、角色关系与任务生成、运行时物品叙事编排、流式交互式对话以及后端持久化与内容工具链等核心模块。项目以“AI 负责叙事表达、本地规则负责状态裁决”为总体技术路线,通过接入大模型能力和本地规则编排机制,完成传统游戏内容生产和运行时交互链路的智能化改造,使游戏软件从固定脚本驱动升级为可结构化生成、可状态约束、可持续演进的 AI 原生软件产品。
|
||||
|
||||
### 5.3 项目关键技术和创新点(1000 字内,可作为首稿)
|
||||
|
||||
建议首稿要点:
|
||||
|
||||
1. `剧情引擎结构化`
|
||||
- 通过 `themePack / storyGraph / narrativeProfile / knowledgeFacts / threadContracts` 等结构,把大模型输出从松散文本升级为可控的剧情引擎语义层。
|
||||
|
||||
2. `AI 与本地规则分工`
|
||||
- AI 负责叙事表达、关系生成、世界扩展,本地规则负责数值、状态、任务推进、背包、招募、持久化等核心逻辑,提升软件稳定性与可验证性。
|
||||
|
||||
3. `跨题材自定义世界生成`
|
||||
- 支持从用户输入的世界锚点出发,生成世界框架、场景、角色、剧情线程和运行时资料,提升内容生产效率与可扩展性。
|
||||
|
||||
4. `运行时智能交互`
|
||||
- 在实际游玩过程中,支持流式剧情推进、NPC 对话、关系推进、任务生成和物品叙事编排,实现游戏软件运行态的智能化。
|
||||
|
||||
5. `前后端协同架构`
|
||||
- 以 `Express + PostgreSQL` 为服务端核心,实现运行时 AI 接口、持久化、资产接口、编辑器写盘与开发联调支撑,形成可持续迭代的软件产品工程体系。
|
||||
|
||||
### 5.4 项目智能化改造成效(1000 字内,建议结构)
|
||||
|
||||
建议分 4 段写:
|
||||
|
||||
1. `技术重构内容`
|
||||
- 从静态内容和单轮生成升级为结构化世界生成、角色叙事档案、线程驱动任务和运行时记忆回写。
|
||||
|
||||
2. `智能化改造重点`
|
||||
- 大模型接入、自然语言交互、智能生成剧情、智能生成任务、智能物品叙事、多阶段世界生成。
|
||||
|
||||
3. `效益量化评估`
|
||||
- 内容生产效率提升、生成链路自动化率提升、编辑器与运行时联动效率提升、研发智能辅助能力增强。
|
||||
|
||||
4. `生态适配能力和社会经济效益`
|
||||
- 面向互动叙事、游戏软件、数字内容、IP 衍生、文化科技融合场景具备复制潜力。
|
||||
|
||||
### 5.5 项目可推广性(1000 字内,建议结构)
|
||||
|
||||
建议强调:
|
||||
|
||||
1. 可从单款产品复用为 `AI 互动叙事引擎`
|
||||
2. 可扩展到多题材、多世界观、多角色规模
|
||||
3. 可服务于游戏、互动内容、数字文化产品
|
||||
4. 后续具备平台化、SaaS 化或中台化演化空间
|
||||
|
||||
## 6. 实施总结报告建议写法
|
||||
|
||||
### 6.1 报告结构
|
||||
|
||||
按附件 13-5 的模板,建议直接写成以下章节:
|
||||
|
||||
1. 企业基本情况介绍
|
||||
2. 项目建设方案
|
||||
3. 项目建设情况
|
||||
4. 相关证明材料
|
||||
5. 其他需说明事项
|
||||
|
||||
### 6.2 可直接落稿的章节框架
|
||||
|
||||
#### 一、企业基本情况介绍
|
||||
|
||||
建议覆盖:
|
||||
|
||||
- 企业基本信息
|
||||
- 发展阶段
|
||||
- 核心软件产品
|
||||
- 近 3 年经营情况或成立以来经营情况
|
||||
- 当前研发团队与技术方向
|
||||
|
||||
#### 二、项目建设方案
|
||||
|
||||
`2.1 项目主要内容`
|
||||
|
||||
- 从“传统脚本化内容生产和运行时交互效率低、扩展成本高”切入
|
||||
- 强调项目要解决的核心问题:
|
||||
- 内容生成成本高
|
||||
- 叙事扩展难
|
||||
- 互动体验不连续
|
||||
- 游戏软件的智能化程度不足
|
||||
|
||||
`2.2 项目建设方案`
|
||||
|
||||
建议写成 5 个子模块:
|
||||
|
||||
1. AI 原生剧情引擎模块
|
||||
2. 自定义世界生成模块
|
||||
3. 角色关系与任务智能生成模块
|
||||
4. 运行时交互与持久化模块
|
||||
5. 编辑器与资产工具链模块
|
||||
|
||||
`2.3 项目关键技术和创新`
|
||||
|
||||
建议围绕以下关键词展开:
|
||||
|
||||
- 大模型接入与多阶段编排
|
||||
- 结构化剧情引擎语义层
|
||||
- AI 叙事与本地规则协同
|
||||
- 游戏软件运行态智能化
|
||||
- 自定义世界生成和叙事图谱构建
|
||||
|
||||
`2.4 项目预期实现的经济社会效益`
|
||||
|
||||
建议从 3 个角度写:
|
||||
|
||||
1. 提升游戏软件研发和内容生产效率
|
||||
2. 形成 AI 原生互动叙事软件产品能力
|
||||
3. 为数字内容、文化科技融合和互动娱乐软件提供可复制技术路径
|
||||
|
||||
#### 三、项目建设情况
|
||||
|
||||
`3.1 项目概况`
|
||||
|
||||
- 项目建设地点
|
||||
- 起止时间
|
||||
- 版本迭代时间点
|
||||
- 上线 / 投运节点
|
||||
|
||||
`3.2 项目建设内容完成情况`
|
||||
|
||||
建议按“计划模块 -> 已完成内容 -> 当前状态”写。
|
||||
|
||||
`3.3 项目投资完成情况`
|
||||
|
||||
- 技术设备费
|
||||
- 材料费
|
||||
- 研发人员费用
|
||||
- 资金到位与使用情况
|
||||
- 专项审计情况
|
||||
|
||||
`3.4 项目绩效完成情况`
|
||||
|
||||
必须逐项回应:
|
||||
|
||||
1. 代码生成占比 / 采纳率
|
||||
2. 国产主流大模型接入
|
||||
3. 日均 Token 量
|
||||
4. 软件智能化成熟度等级
|
||||
5. 行业应用效果或 DAU
|
||||
|
||||
`3.5 项目其他实施效果`
|
||||
|
||||
- 工程效率提升
|
||||
- 研发流程优化
|
||||
- 内容产能提升
|
||||
- 交互质量提升
|
||||
- 可扩展性提升
|
||||
|
||||
## 7. 证据材料采集清单
|
||||
|
||||
### 7.1 基础证明
|
||||
|
||||
- 营业执照
|
||||
- 立项决议 / 项目启动文件
|
||||
- 项目竣工 / 版本上线证明
|
||||
- 项目建设周期证明
|
||||
|
||||
### 7.2 投资与审计证明
|
||||
|
||||
- 设备清单
|
||||
- 投资支出明细表
|
||||
- 发票
|
||||
- 付款凭证
|
||||
- 记账凭证
|
||||
- 银行流水
|
||||
- 采购合同
|
||||
- 专项审计报告
|
||||
- 研发人员清单、工资、社保材料
|
||||
|
||||
### 7.3 技术与知识产权证明
|
||||
|
||||
- 软著
|
||||
- 发明专利
|
||||
- 知识产权与申报产品对应关系说明
|
||||
- 架构图
|
||||
- 关键模块说明
|
||||
|
||||
### 7.4 智能化绩效证明
|
||||
|
||||
- 第三方辅助编码平台导出的代码生成占比 / 采纳率
|
||||
- 项目周期内 1 个月辅助编码平台日志
|
||||
- 大模型接入截图
|
||||
- 网信办备案截图
|
||||
- 日均 Token 量后台证明
|
||||
- 第三方智能化成熟度测评报告
|
||||
|
||||
### 7.5 应用效果证明
|
||||
|
||||
二选一准备:
|
||||
|
||||
1. `B 端路径`
|
||||
- 5 个不同客户销售合同
|
||||
- 上线或验收证明
|
||||
- 非关联关系证明
|
||||
|
||||
2. `C 端路径`
|
||||
- 后台 DAU 日志
|
||||
- 统计口径说明
|
||||
- 关键时间段截图
|
||||
|
||||
## 8. 当前项目的红黄绿核验表
|
||||
|
||||
| 核验项 | 当前判断 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 北京市信息软件企业主体 | `待核验` | 仓库无法证明,需企业基础材料确认 |
|
||||
| 项目总投资 >= 500 万 | `待核验` | 需按附件 13-3 口径做专项审计测算 |
|
||||
| 项目竣工并投运 | `待核验` | 需形成明确版本竣工和运行证明 |
|
||||
| 建设周期 <= 2 年 | `大概率可满足` | 需立项与竣工时间文件确认 |
|
||||
| 2 项软著或 1 项发明专利 | `待核验` | 当前仓库未见证书信息 |
|
||||
| 国产主流备案模型接入 | `待核验` | 需提供模型名称、备案号和接入截图 |
|
||||
| 日均 Token >= 500 万 | `高风险` | 需要真实运行数据支撑 |
|
||||
| 智能化成熟度测评 | `待补` | 需第三方机构报告 |
|
||||
| 5 客户或 5 万 DAU | `高风险` | 需选定 B 端或 C 端路径并集中准备 |
|
||||
|
||||
## 9. 推荐的实际推进动作
|
||||
|
||||
1. 立刻建立 `方向 13 数据底表`
|
||||
- 建设周期
|
||||
- 投资金额
|
||||
- 研发人员
|
||||
- 模型调用量
|
||||
- 客户 / DAU
|
||||
- 软著 / 专利
|
||||
|
||||
2. 先做一版 `项目实施总结报告` Word 初稿
|
||||
- 文字先成型
|
||||
- 数字和证明后补
|
||||
|
||||
3. 同步预约或筛选 `智能化成熟度测评机构`
|
||||
|
||||
4. 立刻判断应用效果走哪条路径
|
||||
- `C 端 DAU`
|
||||
- `B 端 5 个客户`
|
||||
|
||||
5. 如果当前达不到 `5 万 DAU`,且已经有引擎化输出可能,建议考虑把申报产品口径从“单款游戏”适度提升为“AI 原生剧情引擎及其游戏软件应用”,以增强 B 端案例组织空间。
|
||||
@@ -0,0 +1,349 @@
|
||||
# 方向 21 “创赢未来”成长计划材料整理(2026-04-14)
|
||||
|
||||
## 1. 方向判断
|
||||
|
||||
### 1.1 与当前项目的匹配点
|
||||
|
||||
当前项目与方向 21 的匹配度较高,原因如下:
|
||||
|
||||
1. 方向 21 明确支持 `未来信息` 领域。
|
||||
2. 当前项目更适合归入 `未来信息 -> 通用人工智能`。
|
||||
3. 项目同时具备 `沉浸式互动内容`、`世界生成`、`角色智能体化`、`多轮交互式叙事` 等特征,可作为 `元宇宙` 叙事补充语义,但不建议作为首选归类。
|
||||
4. 从仓库状态看,项目已具备完整产品原型、明确技术路线和多阶段演进文档,适合做早期高潜企业 / 团队的路演材料。
|
||||
|
||||
### 1.2 推荐申报口径
|
||||
|
||||
建议主口径:
|
||||
|
||||
- `未来信息 -> 通用人工智能`
|
||||
|
||||
备选口径:
|
||||
|
||||
- `未来信息 -> 元宇宙`
|
||||
|
||||
推荐理由:
|
||||
|
||||
- 当前项目的核心竞争力在于 AI 原生剧情引擎、结构化世界生成与运行时智能交互,而不是纯 3D 场景或虚拟空间平台。
|
||||
|
||||
### 1.3 时间节点
|
||||
|
||||
附件 21 明确写明:
|
||||
|
||||
- `2026 年 6 月` 路演对应申报截止时间:`2026 年 5 月 15 日`
|
||||
|
||||
## 2. 官方材料要求
|
||||
|
||||
### 2.1 必交材料
|
||||
|
||||
1. “创赢未来”成长计划报名表
|
||||
2. 承诺书
|
||||
3. 商业计划书
|
||||
4. 产品或技术演示材料
|
||||
5. 其他补充材料
|
||||
|
||||
### 2.2 与当前项目的适配判断
|
||||
|
||||
| 材料 | 主要看点 | 当前项目优势 | 待补信息 |
|
||||
| --- | --- | --- | --- |
|
||||
| 报名表 | 团队、技术、行业归类、融资规划 | 技术方向清晰,产品结构完整 | 企业基本信息、财务、股权、融资、估值 |
|
||||
| 承诺书 | 基础合规 | 只需走公章和法人签字流程 | 公司主体信息 |
|
||||
| 商业计划书 | 行业空间、技术壁垒、商业化路径、融资用途 | 文档体系完整,路线图和产品能力明确 | 市场数据、营收、客户、融资规划 |
|
||||
| 产品/技术演示 | 路演说服力 | 项目演示性很强,适合做 Demo | 需组织脚本、录屏和讲解 |
|
||||
| 补充材料 | 荣誉、知识产权、合作 | 可补架构、PRD、测试、软著等 | 荣誉、融资、客户证明 |
|
||||
|
||||
## 3. 报名表逐项整理建议
|
||||
|
||||
### 3.1 一、申报主体基本情况
|
||||
|
||||
#### 推荐准备字段
|
||||
|
||||
- 申报主体名称
|
||||
- 统一社会信用代码
|
||||
- 注册资本
|
||||
- 注册地址 / 通讯地址
|
||||
- 企业性质
|
||||
- 法定代表人
|
||||
- 申报负责人 / 联系人
|
||||
- 申报主体人数
|
||||
- 研发人员人数与占比
|
||||
|
||||
#### 企业或创新团队简介建议口径
|
||||
|
||||
建议首稿:
|
||||
|
||||
> 团队围绕 AI 原生互动叙事软件开展研发,核心方向是构建可支撑跨题材互动内容生成、角色关系演化、运行时剧情推进和自定义世界创建的 AI 原生剧情引擎。当前已完成以视觉 RPG 为主要产品形态的原型验证,形成了前后端一体的软件产品框架,并围绕剧情引擎结构化、世界生成、任务编排、角色关系和运行时状态持久化建立了较完整的技术路线和产品文档体系。
|
||||
|
||||
#### 核心团队信息建议准备
|
||||
|
||||
每位核心成员建议统一整理以下字段:
|
||||
|
||||
- 姓名
|
||||
- 角色定位
|
||||
- 负责模块
|
||||
- 学历 / 过往经历
|
||||
- 擅长方向
|
||||
- 与项目的适配性
|
||||
- 奖项 / 荣誉 / 代表成果
|
||||
|
||||
### 3.2 二、核心技术与产品 / 服务
|
||||
|
||||
#### 核心技术基础
|
||||
|
||||
建议围绕以下 5 点展开:
|
||||
|
||||
1. 大模型驱动的剧情生成与世界生成
|
||||
2. 结构化剧情引擎语义层
|
||||
3. AI 叙事与本地规则协同架构
|
||||
4. 自定义世界分阶段生成技术
|
||||
5. 运行时智能交互与持久化技术
|
||||
|
||||
#### 技术 / 产品定位(不超过 300 字)
|
||||
|
||||
建议首稿:
|
||||
|
||||
> 项目聚焦 AI 原生互动叙事软件,面向游戏、数字内容与沉浸式互动场景,提供从世界构建、角色关系、任务生成到运行时剧情推进的一体化智能引擎能力。产品核心解决传统互动内容生产成本高、扩展慢、剧情可玩性不足的问题,支持在统一规则约束下实现多轮对话、动态剧情、角色状态演化与自定义世界生成。
|
||||
|
||||
#### 差异化优势与壁垒(不超过 300 字)
|
||||
|
||||
建议首稿:
|
||||
|
||||
> 项目的差异化不在于简单接入大模型,而在于构建了“AI 负责叙事表达、本地规则负责状态裁决”的分层架构,并将大模型能力进一步沉淀为结构化剧情引擎语义层。相比纯聊天式互动产品,本项目在世界生成、角色关系、任务推进、内容持久化和运行时控制方面具备更强的可控性、可扩展性和软件产品化能力。
|
||||
|
||||
#### 知识产权情况
|
||||
|
||||
当前建议填写方式:
|
||||
|
||||
- 已授权专利:`[待补]`
|
||||
- 发明专利:`[待补]`
|
||||
- 软件著作权:`[待补]`
|
||||
- 其他知识产权:`[待补]`
|
||||
|
||||
#### 技术 / 产品成熟度
|
||||
|
||||
如果当前还未形成稳定商业化收入,建议优先选择:
|
||||
|
||||
- `中试 / 测试`
|
||||
|
||||
如果已经存在真实付费客户或稳定运营数据,再考虑:
|
||||
|
||||
- `已完成商业化`
|
||||
|
||||
#### 商业化进展
|
||||
|
||||
建议按真实情况二选一:
|
||||
|
||||
1. 如果已有收入
|
||||
- 填历史收入、当前客户和代表性案例
|
||||
|
||||
2. 如果尚在测试阶段
|
||||
- 建议如实填写:
|
||||
- 已完成核心原型验证
|
||||
- 已形成可演示产品
|
||||
- 正在推进测试验证 / 合作接洽 / 商业化探索
|
||||
|
||||
### 3.3 三、核心产业领域
|
||||
|
||||
建议勾选:
|
||||
|
||||
- `未来信息 -> 通用人工智能`
|
||||
|
||||
如需辅助说明,可在备注中补一句:
|
||||
|
||||
> 项目兼具沉浸式互动内容和数字世界生成特征,但核心技术驱动仍以通用人工智能能力为主。
|
||||
|
||||
### 3.4 四、融资历史与资本结构
|
||||
|
||||
需要准备:
|
||||
|
||||
- 历史融资时间、轮次、金额、投资方、估值
|
||||
- 当前股权结构
|
||||
- 当前估值
|
||||
- 现有资金储备与可持续运营时间
|
||||
|
||||
如果暂无外部融资,建议如实写:
|
||||
|
||||
- 历史融资:暂无
|
||||
- 当前股权结构:创始团队持股 `100%` 或按真实结构填写
|
||||
- 当前估值:按拟融资口径测算
|
||||
|
||||
### 3.5 五、历史财务信息
|
||||
|
||||
如果已注册公司,需要补齐:
|
||||
|
||||
- `2024`
|
||||
- `2025`
|
||||
- 最近一期
|
||||
|
||||
指标包括:
|
||||
|
||||
- 营业收入
|
||||
- 利润总额
|
||||
- 净利润
|
||||
- 研发投入
|
||||
- 总资产
|
||||
- 净资产
|
||||
- 经营活动现金流净额
|
||||
|
||||
### 3.6 六、融资规划与发展战略
|
||||
|
||||
#### 未来 12-18 个月资金用途建议分类
|
||||
|
||||
建议按以下 5 类填:
|
||||
|
||||
1. 产品研发与迭代
|
||||
2. 核心技术团队扩建
|
||||
3. 市场推广与业务拓展
|
||||
4. 基础设施与模型调用投入
|
||||
5. 补充运营流动资金
|
||||
|
||||
#### 关键发展里程碑建议
|
||||
|
||||
建议先按以下 5 条拟定:
|
||||
|
||||
1. 完成 AI 原生剧情引擎核心能力升级,并形成可对外展示的稳定版本
|
||||
2. 完成自定义世界生成与角色叙事系统的产品化闭环
|
||||
3. 完成首批种子用户测试与关键使用数据沉淀
|
||||
4. 完成核心知识产权申请 / 获取
|
||||
5. 完成下一轮融资所需的数据验证、客户验证或平台验证
|
||||
|
||||
#### 是否接受“拨改投”
|
||||
|
||||
建议先与公司决策层确认再填。
|
||||
|
||||
如果当前阶段确实需要政府快投和后续基金跟投支持,通常建议倾向:
|
||||
|
||||
- `是`
|
||||
|
||||
但这属于有实际融资后果的选择,必须由公司确认。
|
||||
|
||||
### 3.7 七、财务预测与要素需求
|
||||
|
||||
需要形成 `2026-2028` 三年预测:
|
||||
|
||||
- 营业收入
|
||||
- 净利润
|
||||
- 研发投入
|
||||
- 团队规模
|
||||
- 累计知识产权数量
|
||||
|
||||
建议同步准备:
|
||||
|
||||
- 增长驱动因素
|
||||
- 风险与应对
|
||||
- 希望获得的非资金支持
|
||||
|
||||
## 4. 商业计划书建议结构
|
||||
|
||||
附件 21-3 已给出 8 个章节,建议直接写成 15-18 页 BP:
|
||||
|
||||
1. 封面
|
||||
2. 一句话定义项目
|
||||
3. 行业痛点与机会
|
||||
4. 产品形态与演示截图
|
||||
5. 核心技术与架构
|
||||
6. 差异化与壁垒
|
||||
7. 当前进展与验证情况
|
||||
8. 商业化路径
|
||||
9. 市场空间
|
||||
10. 团队介绍
|
||||
11. 融资历史与当前结构
|
||||
12. 本轮融资需求与用途
|
||||
13. 未来 12-18 个月里程碑
|
||||
14. 三年财务预测
|
||||
15. 政府支持与生态协同需求
|
||||
|
||||
## 5. BP 各章节可直接复用的项目内容
|
||||
|
||||
### 5.1 公司 / 团队基本情况
|
||||
|
||||
可复用来源:
|
||||
|
||||
- `README.md`
|
||||
- `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
- `docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||||
|
||||
### 5.2 技术研发情况
|
||||
|
||||
重点引用:
|
||||
|
||||
- `docs/prd/AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_CLASSIC_RPG_EXPERIENCE_BENCHMARK_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_NARRATIVE_THREAD_ITEM_AND_WORLD_NPC_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_STORY_ENGINE_PHASE1_IMPLEMENTATION_PLAN_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_STORY_ENGINE_PHASE2_IMPLEMENTATION_PLAN_2026-04-06.md`
|
||||
|
||||
### 5.3 产品 / 服务
|
||||
|
||||
可突出以下模块:
|
||||
|
||||
1. AI 原生剧情引擎
|
||||
2. 自定义世界生成
|
||||
3. 角色关系与对话系统
|
||||
4. 任务生成与推进
|
||||
5. 运行时智能交互
|
||||
6. 编辑器与内容工作台
|
||||
|
||||
### 5.4 行业及市场
|
||||
|
||||
虽然仓库里没有市场数据,但可以先定义分析框架:
|
||||
|
||||
1. 游戏与互动内容的 AI 生产工具市场
|
||||
2. 互动叙事软件市场
|
||||
3. 数字文化和沉浸式内容市场
|
||||
4. 可扩展到教育、文旅、IP 互动内容的潜在空间
|
||||
|
||||
这一部分需要外部市场数据支持,不能只靠仓库文档。
|
||||
|
||||
### 5.5 发展战略与商业规划
|
||||
|
||||
建议路线:
|
||||
|
||||
1. 先做自有标杆产品验证引擎能力
|
||||
2. 再沉淀可复用的剧情引擎与世界生成能力
|
||||
3. 再探索平台化 / 工具化 / B 端合作 / 内容生态输出
|
||||
|
||||
## 6. 产品 / 技术演示材料建议
|
||||
|
||||
### 6.1 推荐演示结构
|
||||
|
||||
建议控制在 `5-8 分钟`:
|
||||
|
||||
1. 项目定位
|
||||
2. 进入世界或创建自定义世界
|
||||
3. 展示 AI 剧情推进
|
||||
4. 展示 NPC 对话 / 关系 / 任务生成
|
||||
5. 展示运行时状态与本地规则约束
|
||||
6. 展示编辑器或后台架构,证明不是单点 Demo
|
||||
|
||||
### 6.2 建议准备的演示附件
|
||||
|
||||
- 1 个主演示视频
|
||||
- 1 份产品截图包
|
||||
- 1 页系统架构图
|
||||
- 1 页技术路线图
|
||||
- 1 页未来里程碑图
|
||||
|
||||
## 7. 当前项目的材料缺口
|
||||
|
||||
| 类别 | 当前状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 企业基本信息 | `待补` | 需公司或团队真实资料 |
|
||||
| 财务数据 | `待补` | 报名表和 BP 都需要 |
|
||||
| 股权结构与融资历史 | `待补` | 仓库无此信息 |
|
||||
| 市场验证与客户信息 | `待补` | 需真实商业化数据 |
|
||||
| 知识产权 | `待核验` | 建议同步整理软著 / 专利 |
|
||||
| Demo 材料 | `可快速形成` | 项目演示性较强 |
|
||||
| 技术路线与产品逻辑 | `优势明显` | 仓库文档充足,可直接转写 |
|
||||
|
||||
## 8. 推荐的实际推进动作
|
||||
|
||||
1. 先把报名表做成一版可填写底稿。
|
||||
2. 同时做一版 `15 页` 左右的 BP 目录和每页一句话。
|
||||
3. 与创始团队确认:
|
||||
- 轮次
|
||||
- 估值
|
||||
- 拟融资金额
|
||||
- 资金用途
|
||||
- 是否接受拨改投
|
||||
4. 录制第一版产品演示视频。
|
||||
5. 把未来 12-18 个月里程碑先量化成数字。
|
||||
@@ -0,0 +1,184 @@
|
||||
# 方向 24 北京市中小企业服务券材料整理(2026-04-14)
|
||||
|
||||
## 1. 先说判断
|
||||
|
||||
方向 24 不能直接按“和 13、21 一样的项目申报”理解。
|
||||
|
||||
它至少有两条完全不同的路径:
|
||||
|
||||
1. `路径 A:服务机构申报配券产品`
|
||||
2. `路径 B:中小微企业领券用券`
|
||||
|
||||
对当前项目来说,必须先明确你想走哪条路径。
|
||||
|
||||
## 2. 当前项目与方向 24 的适配结论
|
||||
|
||||
### 2.1 如果你想走“服务机构申报配券产品”
|
||||
|
||||
当前项目不建议直接以现有形态冲这一路径,原因如下:
|
||||
|
||||
1. 当前项目核心是 `AI 原生视觉 RPG / 互动叙事产品`,不是天然面向北京市中小微企业销售的标准化企业服务产品。
|
||||
2. 附件 24 要求服务机构上年度与北京市中小企业签约合同不少于 `15 份`,营业收入不低于 `800 万元`。
|
||||
3. 还要求产品有明确服务内容、收费标准、知识产权、销售体系和售后服务。
|
||||
4. 当前批次配券产品征集时间截至 `2026 年 3 月 9 日`,本轮窗口已经结束。
|
||||
|
||||
结论:
|
||||
|
||||
- `不建议把当前轮 24 作为主申报方向。`
|
||||
|
||||
### 2.2 如果你想走“企业领券用券”
|
||||
|
||||
这条路径是可行的,但它不是重材料申报,而是:
|
||||
|
||||
1. 企业身份认证
|
||||
2. 查找上线服务产品
|
||||
3. 下单领券
|
||||
4. 线下签约
|
||||
5. 服务交付与留痕
|
||||
|
||||
这条路径更适合作为:
|
||||
|
||||
- 为 `方向 13` 配套采购第三方大模型、数据治理、智能研发工具、数智转型服务时的降本手段
|
||||
|
||||
## 3. 路径 A:服务机构申报配券产品
|
||||
|
||||
## 3.1 官方硬门槛
|
||||
|
||||
服务机构需满足:
|
||||
|
||||
1. 依法注册,有固定经营场所,成立 `1 年(含)以上`
|
||||
2. 拥有开展专业服务所需设备、许可、认证、资质、资格
|
||||
3. 近 `3 年` 经营、环保、纳税、诚信等方面无严重失信记录
|
||||
4. 上年度与北京市中小企业签订合同量不少于 `15 份`
|
||||
5. 营业收入不低于 `800 万元`
|
||||
6. 产品具有完整知识产权、销售体系及售后服务
|
||||
7. 产品需有明确服务内容和收费标准
|
||||
|
||||
## 3.2 申报材料清单
|
||||
|
||||
### 3.2.1 服务机构申请材料
|
||||
|
||||
1. 服务机构详细介绍(不少于 `2000` 字)
|
||||
2. 营业执照
|
||||
3. 运营所在地证明文件
|
||||
4. `2025` 年度财务审计报告 / 专审报告 / 财务报表
|
||||
5. 至少 `15` 份北京市中小企业合同扫描件或等效证明
|
||||
6. 申请方向相关专业资质证明
|
||||
7. 其他优势特色证明材料
|
||||
|
||||
### 3.2.2 配券服务产品申请材料
|
||||
|
||||
每个产品单独成一个文件夹,需提交:
|
||||
|
||||
1. 配券产品申请表
|
||||
2. 产品价格证明
|
||||
- 报价明细表
|
||||
- 近 `12` 个月 `5 套` 合同 + 发票 + 转账凭证
|
||||
3. 知识产权或销售 / 售后体系证明
|
||||
4. 近两年服务北京地区专精特新、小巨人、上市高成长企业名单(如无可不提供)
|
||||
|
||||
## 3.3 当前项目如果一定要做 24,需要怎么改口径
|
||||
|
||||
如果未来还想走路径 A,建议不要再以“游戏项目”名义申报,而是重构成面向中小企业的标准化服务产品,例如:
|
||||
|
||||
1. `AIGC 互动内容生成与叙事工作台`
|
||||
2. `AI 角色对话与剧情内容生产系统`
|
||||
3. `中小内容团队智能叙事创作平台`
|
||||
|
||||
更适合申报的类别:
|
||||
|
||||
- `方向 1 大模型应用`
|
||||
- 或 `方向 2 数智转型系统`
|
||||
|
||||
但即便如此,仍需补齐:
|
||||
|
||||
1. 北京地区 `15` 份中小企业合同
|
||||
2. `800 万元` 营收
|
||||
3. 标准化产品定价体系
|
||||
4. 售后和交付体系
|
||||
5. 如果按大模型产品报,还需网信办备案信息
|
||||
|
||||
## 3.4 当前路径 A 的建议结论
|
||||
|
||||
建议标记为:
|
||||
|
||||
- `本轮不主攻`
|
||||
- `仅保留备查清单`
|
||||
|
||||
## 4. 路径 B:企业领券用券
|
||||
|
||||
## 4.1 这条路径需要做什么
|
||||
|
||||
1. 在北京市统一身份认证平台完成企业认证
|
||||
2. 登录北京通企服版 APP
|
||||
3. 在服务券专区查找适合的产品
|
||||
4. 领券并下单
|
||||
5. 与服务机构线下签约
|
||||
6. 履约、付款并保留全套材料
|
||||
|
||||
## 4.2 对当前项目最有价值的用券方向
|
||||
|
||||
如果你们作为企业用券,最值得关注的通常是:
|
||||
|
||||
1. `大模型应用`
|
||||
- 模型部署
|
||||
- 模型调用
|
||||
- 大模型精调
|
||||
- 数据治理
|
||||
|
||||
2. `数智转型系统`
|
||||
- 智能研发工具
|
||||
- AI 辅助编程系统
|
||||
- 研发设计 / 经营管理 / 软件系统集成服务
|
||||
|
||||
## 4.3 用券侧建议留存的材料
|
||||
|
||||
虽然企业侧不一定需要像服务机构一样重申报,但仍建议留痕:
|
||||
|
||||
1. 企业认证截图
|
||||
2. 下单截图
|
||||
3. 订单编号与下单时间
|
||||
4. 服务合同
|
||||
5. 发票
|
||||
6. 付款凭证
|
||||
7. 服务交付说明
|
||||
8. 服务完成确认截图
|
||||
|
||||
这些材料后续也可能反过来支持 `方向 13` 的投资和智能化建设证明。
|
||||
|
||||
## 5. 当前项目的实际建议
|
||||
|
||||
### 5.1 不建议做的事
|
||||
|
||||
1. 不建议把当前 AI 游戏项目直接包装成 24 配券产品就立刻申报。
|
||||
2. 不建议在本轮窗口已过的情况下继续花大量时间准备服务机构征集材料。
|
||||
|
||||
### 5.2 建议做的事
|
||||
|
||||
1. 如果你们是 `用券企业`,优先研究可采购的 AI 服务产品。
|
||||
2. 如果你们未来想做 `配券服务机构`,把这份文档当成下一轮准备清单。
|
||||
3. 现阶段把主要精力放在 `方向 13` 和 `方向 21`。
|
||||
|
||||
## 6. 备查清单
|
||||
|
||||
### 6.1 路径 A:未来如要做服务机构征集
|
||||
|
||||
- 服务机构介绍
|
||||
- 营业执照
|
||||
- 场地证明
|
||||
- 审计报告 / 财务报表
|
||||
- `15` 份北京中小企业合同
|
||||
- 资质证明
|
||||
- 产品报价体系
|
||||
- `5` 套合同 + 发票 + 转账凭证
|
||||
- 知识产权 / 销售 / 售后体系
|
||||
- 高成长客户清单
|
||||
|
||||
### 6.2 路径 B:当前如要用券
|
||||
|
||||
- 企业认证
|
||||
- 下单记录
|
||||
- 合同
|
||||
- 发票
|
||||
- 付款记录
|
||||
- 服务交付留痕
|
||||
@@ -0,0 +1,233 @@
|
||||
# 北京市方向 13 / 21 / 24 申报总览(2026-04-14)
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
这份文档用于把当前项目与以下 3 个方向的申报要求对齐,并给出统一的材料准备框架:
|
||||
|
||||
- 方向 `13`:软件智能化提升奖励
|
||||
- 方向 `21`:“创赢未来”成长计划
|
||||
- 方向 `24`:北京市中小企业服务券
|
||||
|
||||
本文档基于以下官方附件整理:
|
||||
|
||||
- `C:\Users\windows\Downloads\W020260225601546780336.docx`
|
||||
- `C:\Users\windows\Downloads\W020260225601548312243.doc`
|
||||
- `C:\Users\windows\Downloads\W020260225601549271520.docx`
|
||||
|
||||
## 2. 先说结论
|
||||
|
||||
### 2.1 当前项目与三个方向的匹配判断
|
||||
|
||||
1. `方向 13` 是当前最值得主攻的申报方向。
|
||||
- 当前项目本质上是“AI 原生剧情引擎 + 本地规则裁决 + 游戏软件产品”的智能化软件项目,且附件 13 明确包含 `游戏软件`。
|
||||
- 但这一方向材料最重、硬门槛最多,必须优先核验 `总投资 >= 500 万元`、`项目已竣工投运`、`知识产权数量`、`国产模型接入`、`Token 量`、`5 个客户案例或 5 万 DAU`、`智能化成熟度测评` 等要求。
|
||||
|
||||
2. `方向 21` 与当前项目方向高度匹配,建议并行准备。
|
||||
- 当前项目适合归入 `未来信息 -> 通用人工智能`,`元宇宙` 可作为备选描述维度,不建议作为首选。
|
||||
- 这一方向更看重技术潜力、团队能力、融资规划和未来产业前景,比较适合当前这种“技术路线清晰、产品原型已成型、后续仍处于快速演化阶段”的项目。
|
||||
- 附件 21 明确写明 `2026 年 6 月` 路演对应申报截止时间为 `2026 年 5 月 15 日`。
|
||||
|
||||
3. `方向 24` 需要先区分申报身份,再决定是否投入材料准备。
|
||||
- 如果你想申报的是 `服务机构配券产品征集`,那当前项目并不天然匹配,因为现有仓库核心是 AI 游戏产品,不是面向北京市中小微企业销售的标准化企业服务产品。
|
||||
- 如果你想用的是 `中小企业服务券`,那不是一套重申报材料,而是企业认证、下单、签约、付款、留痕流程。
|
||||
- 附件 24 写明本轮 `配券产品征集` 截止至 `2026 年 3 月 9 日`,按当前日期 `2026 年 4 月 14 日`,这一轮服务机构征集窗口已经结束。
|
||||
|
||||
### 2.2 建议的投入顺序
|
||||
|
||||
1. 先完成 `方向 13` 的硬条件核验和主材料框架。
|
||||
2. 并行完成 `方向 21` 的报名表底稿、BP 结构和演示材料提纲。
|
||||
3. 对 `方向 24` 只做判断和备查,不建议当前把主要时间投入到“配券产品征集”上。
|
||||
|
||||
## 3. 当前项目可复用的共用事实
|
||||
|
||||
以下内容可以作为 `13` 和 `21` 的共用项目底稿基础:
|
||||
|
||||
### 3.1 项目定位
|
||||
|
||||
- 项目名称:`AI Native Visual RPG`
|
||||
- 核心定位:以 `AI 叙事 + 本地规则 + 像素演出` 为核心的 AI 原生视觉 RPG 原型
|
||||
- 产品形态:前端表现层 + `Express` 后端 + `PostgreSQL` 持久化 + AI 接口编排
|
||||
- 核心能力:
|
||||
- 世界与角色选择
|
||||
- AI 剧情推进与流式对话
|
||||
- 战斗演出、NPC 战斗、切磋
|
||||
- NPC 交易、送礼、求助、招募
|
||||
- 宝藏交互
|
||||
- 同伴跟随与战斗
|
||||
- 预设编辑器 / NPC 视觉编辑器 / 行为编辑器
|
||||
- 自动存档与继续游戏
|
||||
|
||||
### 3.2 技术架构
|
||||
|
||||
- 前端:`React 19` + `TypeScript` + `Vite`
|
||||
- 后端:`Express` + `TypeScript`
|
||||
- 数据层:`PostgreSQL`
|
||||
- AI 能力接入:
|
||||
- 流式剧情生成
|
||||
- 自定义世界多阶段生成
|
||||
- NPC 对话 / 招募 /关系总结
|
||||
- 任务生成
|
||||
- 角色视觉与动画资产生成接口
|
||||
- 工程门禁:
|
||||
- `npm run lint`
|
||||
- `npm run check:encoding`
|
||||
- `npm run check:content`
|
||||
- `npm run build`
|
||||
- `vitest`
|
||||
|
||||
### 3.3 当前可支撑的创新点
|
||||
|
||||
1. `AI 负责叙事表达,本地规则负责状态裁决`
|
||||
- 把剧情生成与关键规则分离,降低纯模型驱动的不稳定性。
|
||||
|
||||
2. `AI 原生剧情引擎`
|
||||
- 当前文档已经形成 `themePack -> storyGraph -> narrativeProfile -> knowledgeFacts / threadContracts` 的结构化设计。
|
||||
|
||||
3. `跨题材自定义世界生成`
|
||||
- 支持从世界锚点出发生成世界框架、角色、地点、叙事图谱与运行时编译结构。
|
||||
|
||||
4. `游戏软件的智能化改造方向明确`
|
||||
- 不是简单在游戏里接聊天,而是围绕剧情推进、任务、角色关系、物品叙事、世界生成做系统级 AI 注入。
|
||||
|
||||
5. `前后端职责边界清晰`
|
||||
- 遵循“前端只做表现,逻辑和数据放后端”的工程约束,便于形成可持续演进的软件产品能力。
|
||||
|
||||
## 4. 仓库内建议重点引用的项目依据
|
||||
|
||||
- `README.md`
|
||||
- `docs/prd/AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_CLASSIC_RPG_EXPERIENCE_BENCHMARK_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_NARRATIVE_THREAD_ITEM_AND_WORLD_NPC_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_CUSTOM_WORLD_CREATION_FLOW_OPTIMIZATION_PRD_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_STORY_ENGINE_PHASE1_IMPLEMENTATION_PLAN_2026-04-06.md`
|
||||
- `docs/prd/AI_NATIVE_STORY_ENGINE_PHASE2_IMPLEMENTATION_PLAN_2026-04-06.md`
|
||||
- `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
- `docs/audits/engineering/README.md`
|
||||
- `docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||||
|
||||
## 5. 三个方向的共用材料包
|
||||
|
||||
以下材料建议先做成一个统一总包,再按方向拆分:
|
||||
|
||||
### 5.1 企业基础件
|
||||
|
||||
- 营业执照扫描件
|
||||
- 法定代表人信息
|
||||
- 联系人信息
|
||||
- 公司简介
|
||||
- 统一社会信用代码
|
||||
- 注册地址 / 办公地址 / 经营场所证明
|
||||
- 企业近 2 年到 3 年财务数据
|
||||
- 2025 年审计报告 / 专审报告 / 财务报表
|
||||
|
||||
### 5.2 项目基础件
|
||||
|
||||
- 项目命名口径
|
||||
- 项目建设周期
|
||||
- 项目立项文件 / 决策文件
|
||||
- 项目结项 / 版本竣工 / 上线证明
|
||||
- 项目建设地点
|
||||
- 项目实施团队名单
|
||||
- 项目总投资和构成明细
|
||||
|
||||
### 5.3 技术与知识产权件
|
||||
|
||||
- 软件著作权证书
|
||||
- 发明专利证书或申请进展材料
|
||||
- 产品版本说明
|
||||
- 系统架构图
|
||||
- 关键技术说明
|
||||
- 模型接入说明
|
||||
- 技术创新点说明
|
||||
|
||||
### 5.4 市场与应用件
|
||||
|
||||
- 客户合同 / 订单 / 上线验收证明
|
||||
- 用户数据后台截图
|
||||
- 日活 / 调用量 / Token 日志
|
||||
- 合作伙伴名单
|
||||
- 试点案例
|
||||
- 演示视频 / 产品截图
|
||||
|
||||
### 5.5 融资与团队件
|
||||
|
||||
- 核心团队简历
|
||||
- 股权结构
|
||||
- 历史融资情况
|
||||
- 当前估值与资金储备
|
||||
- 未来 12-18 个月资金需求与用途
|
||||
- 未来 3 年财务预测
|
||||
|
||||
## 6. 建议的材料目录结构
|
||||
|
||||
建议在仓库外或公司申报盘中采用以下目录:
|
||||
|
||||
```text
|
||||
申报材料/
|
||||
├─ 00_共用基础材料/
|
||||
│ ├─ 00_营业执照与资质/
|
||||
│ ├─ 01_财务与审计/
|
||||
│ ├─ 02_团队与融资/
|
||||
│ ├─ 03_知识产权/
|
||||
│ ├─ 04_项目立项与结项/
|
||||
│ ├─ 05_产品截图与演示/
|
||||
│ └─ 06_客户与应用证明/
|
||||
├─ 13_软件智能化提升奖励/
|
||||
│ ├─ 01_申报表/
|
||||
│ ├─ 02_实施总结报告/
|
||||
│ ├─ 03_绩效与测评/
|
||||
│ ├─ 04_投资明细与专项审计/
|
||||
│ └─ 05_补充证明/
|
||||
├─ 21_创赢未来成长计划/
|
||||
│ ├─ 01_报名表/
|
||||
│ ├─ 02_承诺书/
|
||||
│ ├─ 03_商业计划书/
|
||||
│ ├─ 04_产品技术演示/
|
||||
│ └─ 05_补充证明/
|
||||
└─ 24_中小企业服务券/
|
||||
├─ A_配券产品征集_如后续开放/
|
||||
└─ B_企业用券留痕/
|
||||
```
|
||||
|
||||
## 7. 当前最需要立即核验的硬条件
|
||||
|
||||
### 7.1 方向 13
|
||||
|
||||
- 是否已经形成一个可定义为“已竣工并投入运行”的软件版本
|
||||
- 是否能确认项目建设开始时间和竣工时间,且周期不超过 2 年
|
||||
- 是否有 `2 项软著` 或 `1 项发明专利`
|
||||
- 是否能拿到 `>= 500 万元` 的专项审计口径总投资
|
||||
- 是否能提供 `第三方辅助编码平台` 的代码生成占比 / 采纳率证明
|
||||
- 是否已接入 `已备案的国产主流大模型`
|
||||
- 是否有 `日均 Token >= 500 万`
|
||||
- 是否能拿到 `智能化成熟度测评报告`
|
||||
- 是否能满足 `5 个不同客户案例` 或 `5 万 DAU`
|
||||
|
||||
### 7.2 方向 21
|
||||
|
||||
- 当前申报主体是已注册公司还是创新团队
|
||||
- 是否已有历史融资、估值和股权结构
|
||||
- 是否已有最小商业化验证
|
||||
- 未来 12-18 个月的融资金额和用途是否可量化
|
||||
- 未来 3 年收入、利润、研发投入预测是否能由财务或管理层确认
|
||||
|
||||
### 7.3 方向 24
|
||||
|
||||
- 如果按 `服务机构配券产品征集` 走,是否满足:
|
||||
- 上年度与北京市中小企业签约合同不少于 `15 份`
|
||||
- 营业收入不低于 `800 万元`
|
||||
- 存在标准化、可售卖、可售后、可定价的企业服务产品
|
||||
- 如果不满足,是否转为 `企业用券` 路径,而不是继续准备配券申报材料
|
||||
|
||||
## 8. 推荐的本周推进顺序
|
||||
|
||||
1. 先把 `方向 13` 的硬条件做一次红黄绿核验。
|
||||
2. 同步准备 `方向 21` 的报名表底稿和 BP 第一版。
|
||||
3. 只保留 `方向 24` 的判断文档与备查清单,不建议本周作为主线。
|
||||
4. 所有数字类信息统一建一个 `数据底表`,避免三个方向口径不一致。
|
||||
|
||||
## 9. 关联文档
|
||||
|
||||
- [BEIJING_DIRECTION13_APPLICATION_MATERIALS_2026-04-14.md](./BEIJING_DIRECTION13_APPLICATION_MATERIALS_2026-04-14.md)
|
||||
- [BEIJING_DIRECTION21_APPLICATION_MATERIALS_2026-04-14.md](./BEIJING_DIRECTION21_APPLICATION_MATERIALS_2026-04-14.md)
|
||||
- [BEIJING_DIRECTION24_APPLICATION_MATERIALS_2026-04-14.md](./BEIJING_DIRECTION24_APPLICATION_MATERIALS_2026-04-14.md)
|
||||
@@ -0,0 +1,435 @@
|
||||
# 当前 Agent 创作流程优化执行规划(大白话版)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 先把话说死
|
||||
|
||||
这轮不再加新流程。
|
||||
|
||||
不再新增一套创作动线。
|
||||
不再为了“更完整”继续把 PRD 里没落完的所有阶段、面板、动作全补出来。
|
||||
不再把前端创作工具改成另一套长得不一样的新系统。
|
||||
|
||||
这轮只做一件事:
|
||||
|
||||
**把现在这条你已经满意的前端创作流程,收紧、理顺、删重、补通,让它从“能跑”变成“稳、顺、好维护、不会自己打自己”。**
|
||||
|
||||
这份规划就是基于 [AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md](../audits/AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md) 里已经确认的问题,重新收束出来的一版执行方案。
|
||||
|
||||
## 0.1 当前正式执行基线
|
||||
|
||||
从 `2026-04-21` 起,当前仓库里和这条创作主链直接对应的文件级拆分、阶段验收、工作包进度,统一以以下文档为准:
|
||||
|
||||
1. [../technical/CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md](../technical/CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md)
|
||||
2. `docs/technical/CREATION_FLOW_CHAIN_REFACTOR_WORK_PACKAGE_*_PROGRESS_2026-04-21.md`
|
||||
3. [../technical/CURRENT_AGENT_CREATION_FLOW_STAGE4_CLEANUP_CHECK_2026-04-21.md](../technical/CURRENT_AGENT_CREATION_FLOW_STAGE4_CLEANUP_CHECK_2026-04-21.md)
|
||||
|
||||
本文件继续承担的职责只剩 3 件事:
|
||||
|
||||
1. 解释为什么当前版本只收口现有 Agent 创作动线,不再扩一套新流程
|
||||
2. 冻结这轮明确不做的能力边界
|
||||
3. 给出高层执行顺序与判断标准
|
||||
|
||||
凡是涉及目录落位、命名规范、前后端真相源边界、阶段完成度和工作包状态,统一以后面的技术执行文档为准。
|
||||
|
||||
---
|
||||
|
||||
## 1. 现在最大的问题,用大白话讲是什么
|
||||
|
||||
不是界面丑。
|
||||
不是步骤不够多。
|
||||
不是入口不够花。
|
||||
|
||||
而是现在这条链里,很多地方在“一个流程里混着好几套脑子”。
|
||||
|
||||
具体就是:
|
||||
|
||||
1. 用户明明在走 Agent 创作,但走到一半,很多关键数据又偷偷变成了 old profile 流程在接手。
|
||||
2. 明明已经有 Agent session 这条主线,但结果页、作品库、旧生成接口、旧编辑器能力还都在同时干活。
|
||||
3. 明明有“发布世界”这个概念,但现在实际上“不发布也能直接进入世界”。
|
||||
4. 明明有一些 session 内的数据,比如建议动作、草稿卡、澄清项、质量检查,结果走到结果页之后就像断电了一样,后面没人接着用。
|
||||
5. 明明有些功能已经决定这轮不做,但代码里和文档里还留着很多“半做不做”的说法,会持续误导后续开发。
|
||||
|
||||
所以这轮优化的目标不是“让系统更大”,而是:
|
||||
|
||||
**让整条现有流程只认一条主线,别再一会儿 Agent、一会儿 legacy、一会儿旧 session、一会儿作品库各管各的。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 这轮优化后的目标状态
|
||||
|
||||
我们要收敛到下面这个状态:
|
||||
|
||||
```text
|
||||
用户进入 Agent 创作
|
||||
-> 在现有工作区里聊天和生成草稿
|
||||
-> 草稿整理完成后进入现有结果页
|
||||
-> 结果页只做预览、少量必要确认、进入世界
|
||||
-> 进入世界时走一条明确、统一、可解释的数据链
|
||||
-> 平台“我的创作”能稳定找回这份草稿或这份作品
|
||||
```
|
||||
|
||||
注意,这里有两个关键词:
|
||||
|
||||
1. **还是现有动线**
|
||||
2. **但背后的数据链要统一**
|
||||
|
||||
也就是说:
|
||||
|
||||
前端看上去可以几乎不换流程。
|
||||
但后面谁是真相源、谁负责编译、谁负责保存、谁负责恢复、哪些能力要删掉,必须彻底讲清楚。
|
||||
|
||||
---
|
||||
|
||||
## 3. 这轮不做什么
|
||||
|
||||
为了避免后面又做散,先把“不做什么”写清楚。
|
||||
|
||||
### 3.1 不新增新的大流程
|
||||
|
||||
不做这些:
|
||||
|
||||
1. 不再新增“另一个 Agent 创作工作台”
|
||||
2. 不再新增“另一套草稿结果页”
|
||||
3. 不再新增“另一条作品发布流程”
|
||||
4. 不再新增“另一套创作中心入口”
|
||||
|
||||
### 3.2 不为了补 PRD 而硬补所有未完成能力
|
||||
|
||||
不做这些:
|
||||
|
||||
1. 不把所有 `lock / unlock / regenerate_scope / expand_long_tail / scene asset pipeline` 一次性全打完
|
||||
2. 不为了“文档里写过”就把所有没接线面板都接进来
|
||||
3. 不把当前工作区重新改造成一个更复杂的大后台
|
||||
|
||||
补充更新(`2026-04-21`):
|
||||
|
||||
上一轮审计里提到的一组旧 Agent 副面板,已经在工程清理中被明确判定为退出当前版本主链并物理删除,包括:
|
||||
|
||||
1. `CustomWorldAgentLockBar.tsx`
|
||||
2. `CustomWorldAgentQuickActions.tsx`
|
||||
3. `CustomWorldAgentSummaryPanel.tsx`
|
||||
4. `CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
5. `CustomWorldAgentClarificationPanel.tsx`
|
||||
6. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
7. `CustomWorldDraftCardDetailModal.tsx`
|
||||
8. `CustomWorldDraftEditPanel.tsx`
|
||||
9. `CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
所以这里的“不为了文档里写过就全接进来”,现在不只是态度提醒,而是已经执行过的现实边界。
|
||||
|
||||
### 3.3 不把结果页继续当旧编辑器扩写
|
||||
|
||||
这轮明确不再鼓励:
|
||||
|
||||
1. 在结果页继续加更多直接生成角色 / 地点的按钮
|
||||
2. 在结果页继续加更多直接改 legacy profile 的编辑能力
|
||||
3. 让结果页承担越来越重的“补世界”职责
|
||||
|
||||
一句话:
|
||||
|
||||
**结果页要收口,不要继续发散。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 接下来真正要做的 5 件事
|
||||
|
||||
## 4.1 第一件事:先定一条唯一主链,别再多套数据同时接力
|
||||
|
||||
这是第一优先级,也是最重要的一件事。
|
||||
|
||||
现在的问题不是“没东西可用”,而是“能用的东西太多了,而且互相抢活”。
|
||||
|
||||
接下来要明确:
|
||||
|
||||
1. 当前 Agent 创作流程里,`Agent session` 才是草稿阶段的真相源。
|
||||
2. 结果页只是这份草稿的展示和收口,不应该变成另一套独立编辑器。
|
||||
3. 进入世界时,只能走一条明确的编译出口,不能这里转一次、那里改一次、最后谁改得晚听谁的。
|
||||
|
||||
用大白话讲,就是:
|
||||
|
||||
**从聊天开始到点“进入世界”为止,中间只能有一条主水管。**
|
||||
|
||||
不能再出现:
|
||||
|
||||
1. Agent session 里一份数据
|
||||
2. 前端桥接后又一份 profile
|
||||
3. 结果页本地改完又一份 profile
|
||||
4. 自动保存到作品库后再来一份 profile
|
||||
|
||||
这样下去,后面谁出 bug 都说不清到底是哪一层改坏的。
|
||||
|
||||
所以这一阶段的目标不是改 UI,而是先把话语权统一:
|
||||
|
||||
1. 草稿阶段谁说了算
|
||||
2. 进入世界前谁负责最终编译
|
||||
3. 作品库里保存的到底是“正式世界”还是“当前草稿快照”
|
||||
|
||||
这件事不解决,后面所有优化都会继续打架。
|
||||
|
||||
---
|
||||
|
||||
## 4.2 第二件事:把结果页收口,只保留当前流程真正需要的事
|
||||
|
||||
现在结果页的问题很简单:
|
||||
|
||||
它干的活太多了。
|
||||
|
||||
它现在既像:
|
||||
|
||||
1. 草稿预览页
|
||||
2. 旧自定义世界编辑器
|
||||
3. AI 补角色/补地点的入口
|
||||
4. 自动保存中转页
|
||||
5. 进入世界前的最后一跳
|
||||
|
||||
这就是为什么它会越来越乱。
|
||||
|
||||
这轮要做的不是重做结果页,而是收口结果页。
|
||||
|
||||
收口方向很明确:
|
||||
|
||||
1. 结果页继续保留现在你满意的浏览和进入世界体验
|
||||
2. 但要逐步去掉“它自己偷偷改世界结构”的能力
|
||||
3. 让它更像“当前草稿的总览页”,而不是“另一套世界编辑器”
|
||||
|
||||
用大白话讲:
|
||||
|
||||
**结果页负责看,不负责偷偷再造一遍世界。**
|
||||
|
||||
所以这里建议后续逐步处理:
|
||||
|
||||
1. 把结果页里那些直接生成 playable/story/landmark 的旧能力下掉
|
||||
2. 把直接改 legacy profile 的重编辑能力从结果页移走或收紧
|
||||
3. 让“去 Agent 调整设定”真的是回主流程调,而不是结果页自己补完半套流程
|
||||
|
||||
这一步做完的好处很直接:
|
||||
|
||||
1. 结果页职责会清楚很多
|
||||
2. 进入世界前的状态会更稳定
|
||||
3. 不会再出现“用户以为还在 Agent 流里,实际上已经走到 legacy 编辑器里了”
|
||||
|
||||
---
|
||||
|
||||
## 4.3 第三件事:平台入口统一,不让草稿恢复和作品查看继续割裂
|
||||
|
||||
现在还有一个体验问题不是流程长短的问题,而是入口不统一。
|
||||
|
||||
简单说就是:
|
||||
|
||||
1. 后端已经能区分“草稿”和“已发布作品”
|
||||
2. 但平台页里“我的创作”主要还在看 `myEntries`
|
||||
3. Agent 草稿并不能自然地稳定出现在同一个主入口里
|
||||
|
||||
这会带来两个问题:
|
||||
|
||||
1. 用户做了一半的草稿,不容易稳定找回来
|
||||
2. 系统里其实已经有创作中心能力,但主入口没认它
|
||||
|
||||
所以接下来要做的不是新做一个创作中心,而是:
|
||||
|
||||
**把已经存在的聚合能力真正接回现在的平台入口。**
|
||||
|
||||
用户看到的应该是:
|
||||
|
||||
1. 还没进世界的草稿,可以继续创作
|
||||
2. 已经成型的作品,可以查看或进入世界
|
||||
|
||||
而不是:
|
||||
|
||||
1. 草稿在一套地方
|
||||
2. 已保存作品在另一套地方
|
||||
3. 恢复创作还得靠 sessionId 或隐藏状态兜底
|
||||
|
||||
这一步的核心价值不是“新功能”,而是“东西别丢、入口别分裂、用户心智别断”。
|
||||
|
||||
---
|
||||
|
||||
## 4.4 第四件事:删掉重复 pipeline,不再同时养两三套创作生成链
|
||||
|
||||
这一步很关键,而且一定要明确态度:
|
||||
|
||||
**既然你已经决定当前前端创作流程满意,那就不能继续默认保留那么多并行旧链。**
|
||||
|
||||
现在最典型的重复链有:
|
||||
|
||||
1. Agent 创作链
|
||||
2. 旧 `custom-world/sessions` 世界生成链
|
||||
3. 结果页 legacy profile 直改链
|
||||
|
||||
它们的共同问题是:
|
||||
|
||||
1. 都能生成世界
|
||||
2. 都能改世界
|
||||
3. 但不是同一套状态模型
|
||||
4. 后期维护会越来越痛苦
|
||||
|
||||
所以这一步不是说要立刻把所有旧东西物理删除,而是要明确分层:
|
||||
|
||||
1. 哪条是当前正式主链
|
||||
2. 哪条是兼容链
|
||||
3. 哪条只是暂时留着,但不能再往上继续加功能
|
||||
|
||||
用大白话讲,就是:
|
||||
|
||||
**该扶正的扶正,该降级的降级,该冻结的冻结。**
|
||||
|
||||
尤其是旧 `custom-world/sessions` 这条链,如果还要保留,也只能是兼容入口,不能再和 Agent 主链平起平坐。
|
||||
|
||||
补充更新(`2026-04-21`):
|
||||
|
||||
这条旧 `custom-world/sessions` 世界生成链已经完成物理删除。
|
||||
|
||||
因此阶段三在当前仓库里的剩余任务,不再是“决定要不要保留这条旧链”,而是:
|
||||
|
||||
1. 继续收掉结果页 legacy profile 直改能力的误导性职责
|
||||
2. 继续清理文档里把旧链当成现行选项的表述
|
||||
|
||||
---
|
||||
|
||||
## 4.5 第五件事:把文稿里那些“这轮不做”的未完成项从主叙事里移掉
|
||||
|
||||
这是你这次特别强调的点,我完全同意,而且它很重要。
|
||||
|
||||
现在很多文稿的问题不是“写错了”,而是:
|
||||
|
||||
1. 写了很多理论上该有的能力
|
||||
2. 但当前版本并不准备继续往那个方向扩
|
||||
3. 结果文档会不断把团队拉回“是不是还要把这些补完”的思路里
|
||||
|
||||
这会直接制造两种问题:
|
||||
|
||||
1. 开发判断会飘
|
||||
2. 后续审计会永远得到“未完成项很多”的结论
|
||||
|
||||
所以这轮文档治理要做的,不是把文稿全删空,而是分清三类内容:
|
||||
|
||||
1. **当前版本要继续优化的**
|
||||
2. **当前版本明确不做、先冻结的**
|
||||
3. **未来可以再看,但这轮不纳入执行规划的**
|
||||
|
||||
用大白话讲:
|
||||
|
||||
**文档也要学会闭嘴。**
|
||||
|
||||
不是所有想过的东西,都要继续挂在当前版本的主任务里。
|
||||
|
||||
---
|
||||
|
||||
## 5. 推荐执行顺序
|
||||
|
||||
这轮建议按下面顺序推进,不建议乱穿插。
|
||||
|
||||
## 第一阶段:先收主链
|
||||
|
||||
先做:
|
||||
|
||||
1. 定义当前正式主链
|
||||
2. 明确 Agent session、结果页、作品库、进入世界之间谁负责什么
|
||||
3. 停止继续增强结果页里的 legacy 编辑能力
|
||||
|
||||
这一阶段的目标是:
|
||||
|
||||
**先让水管只有一根。**
|
||||
|
||||
## 第二阶段:再收结果页和平台入口
|
||||
|
||||
再做:
|
||||
|
||||
1. 结果页职责收口
|
||||
2. 平台“我的创作”入口统一
|
||||
3. 草稿恢复和作品查看走同一套入口认知
|
||||
|
||||
这一阶段的目标是:
|
||||
|
||||
**让用户走起来更顺,让系统找回内容更稳定。**
|
||||
|
||||
## 第三阶段:清理旧链残留表述与剩余兼容误导
|
||||
|
||||
再做:
|
||||
|
||||
1. 清理旧 `custom-world/sessions` 已删除链路在文档、索引、任务清单里的残留表述
|
||||
2. 结果页直改 profile 的旧能力继续收紧
|
||||
3. 把仍保留的兼容 façade / 兼容字段边界写清楚
|
||||
|
||||
这一阶段的目标是:
|
||||
|
||||
**减少旧链文档误导和兼容边界漂移。**
|
||||
|
||||
## 第四阶段:最后做文档清理
|
||||
|
||||
最后做:
|
||||
|
||||
1. 把当前版本不再追的未完成项,从主规划文稿里移出去
|
||||
2. 把“未来也许做”从“这轮要做”里拆开
|
||||
3. 让所有当前规划只服务当前版本
|
||||
|
||||
就当前状态补一句最重要的执行口径:
|
||||
|
||||
1. 已经物理删除的旧链和旧副面板,不再作为“本轮待落地项”
|
||||
2. 历史 PRD 可以保留实现设想,但必须和“当前版本执行规划”分开
|
||||
3. 当前版本规划只保留仍对正式主链有现实约束的事项
|
||||
|
||||
这一阶段的目标是:
|
||||
|
||||
**让接下来所有开发都围绕同一套现实目标执行。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 每个阶段做完以后,应该看到什么效果
|
||||
|
||||
## 阶段一做完
|
||||
|
||||
应该看到:
|
||||
|
||||
1. 代码里谁是主链一眼能看明白
|
||||
2. 不会再出现一会儿 Agent、一会儿 legacy profile 接管全局的情况
|
||||
3. 进入世界时的数据来源更清楚
|
||||
|
||||
## 阶段二做完
|
||||
|
||||
应该看到:
|
||||
|
||||
1. 结果页更干净
|
||||
2. 平台页更容易找回自己的创作
|
||||
3. 用户对“草稿”“作品”“进入世界”这三个概念不会混
|
||||
|
||||
## 阶段三做完
|
||||
|
||||
应该看到:
|
||||
|
||||
1. 已删除旧链不再继续出现在当前执行清单里
|
||||
2. 剩余兼容层的保留边界更清楚
|
||||
3. 后续开发不会再不知道该往哪条链上接
|
||||
|
||||
## 阶段四做完
|
||||
|
||||
应该看到:
|
||||
|
||||
1. 文档和代码目标一致
|
||||
2. 团队不会再被一堆“理论上应该补”的项拉偏
|
||||
3. 后续迭代能真正围绕“优化已有流程”推进
|
||||
|
||||
---
|
||||
|
||||
## 7. 这轮最重要的判断标准
|
||||
|
||||
这轮不是看我们补了多少功能。
|
||||
|
||||
这轮的判断标准应该是下面 5 条:
|
||||
|
||||
1. 用户现在这条创作流程有没有被打断
|
||||
2. 同一个世界的数据是不是只走一条清楚的主链
|
||||
3. 结果页是不是还在偷偷承担旧编辑器职责
|
||||
4. 平台入口能不能稳定找回草稿和作品
|
||||
5. 文档是不是已经不再推动大家去补这轮明确不做的东西
|
||||
|
||||
如果这 5 条做好了,就说明这轮方向是对的。
|
||||
|
||||
---
|
||||
|
||||
## 8. 一句话总结
|
||||
|
||||
接下来的优化,不是再发明一套更复杂的创作流程,而是把当前你已经满意的这条前端动线背后的数据链、入口、职责和文档全部收紧到同一个方向上:
|
||||
|
||||
**少一点并行、少一点桥接、少一点重复、少一点“半做半留”,把现有流程真正打磨成一条稳定主链。**
|
||||
@@ -0,0 +1,608 @@
|
||||
# 世界 Profile 映射优化方案(2026-04-18)
|
||||
|
||||
更新时间:`2026-04-18`
|
||||
|
||||
## 0. 文档目标
|
||||
|
||||
这份文档基于以下结论继续推进:
|
||||
|
||||
- `docs/audits/CUSTOM_WORLD_PROFILE_MAPPING_AUDIT_2026-04-18.md` 已确认,当前世界 `profile` 已打通主干映射,但还没有成为“所有预设内容与实时生成规则共同优先读取的单一真相源”。
|
||||
- 当前最主要的缺口不是“没有世界设定”,而是“世界设定没有被所有运行时链路以同等强度消费”。
|
||||
- 优化重点应优先放在后端运行时消费链、跨题材兼容链、世界级内容对象化三条主线上,而不是继续堆新预设内容。
|
||||
|
||||
本文目标不是重复审计结论,而是把问题整理成:
|
||||
|
||||
1. 分优先级的落地改造项
|
||||
2. 每一项的目标状态
|
||||
3. 需要修改的关键模块
|
||||
4. 具体实施步骤
|
||||
5. 验收标准
|
||||
6. 风险与回滚策略
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标状态
|
||||
|
||||
本轮优化完成后,系统应达到以下状态:
|
||||
|
||||
1. `CustomWorldProfile` 成为预设内容和实时生成规则的统一主数据源。
|
||||
2. 前端剧情链、后端任务链、后端物品链消费的是同一套世界语义,而不是“前端懂世界、后端只懂摘要”。
|
||||
3. `templateWorldType` 只承担兼容字段职责,不再主导跨题材世界的角色、场景、怪物和视觉映射。
|
||||
4. `items / factions / conflicts / threads` 不再只是文本种子,而是能驱动运行时行为的结构对象。
|
||||
5. landmark、场景、怪物、掉落、任务、奖励之间的对应关系优先由世界 profile 决定,模板补位只在缺口场景下触发。
|
||||
|
||||
---
|
||||
|
||||
## 2. 优先级总览
|
||||
|
||||
## P0:先补“真实消费不完整”的运行时主链
|
||||
|
||||
- 让后端 `runtimeItemModule` / `runtimeQuestModule` 接入完整可控的世界 profile 子集。
|
||||
- 去掉后端运行时里“伪线程 id 冒充真实线程”的弱映射。
|
||||
- 建立后端世界消费 contract,统一前后端字段裁剪方式。
|
||||
|
||||
## P1:再补“世界设定被模板压扁”的兼容链与物品链
|
||||
|
||||
- 把 `templateWorldType` 退回兼容层,不再主导真实映射。
|
||||
- 为世界级 `items` 建立 seed 与引用链,补齐“世界物件图谱”。
|
||||
- 让任务奖励、场景宝藏、运行时物品生成优先读取世界物品种子。
|
||||
|
||||
## P2:把文本种子升级为游戏对象
|
||||
|
||||
- 把 `majorFactions / coreConflicts` 升级成可索引、可关联、可推进的结构对象。
|
||||
- 调整 landmark 场景怪物注入逻辑,停止“模板怪物硬补丁”主导场景内容。
|
||||
- 让世界冲突、势力归属真正影响任务、场景压力、敌对关系。
|
||||
|
||||
## P3:补齐长尾映射与创作层沉淀
|
||||
|
||||
- 扩展 `referenceProfile.roleArchetypes` 的来源覆盖,补上 `storyNpcs` 长尾 archetype。
|
||||
- 重新定义 `creatorIntent / anchorPack / lockState / anchorContent` 中哪些字段需要进入运行时。
|
||||
- 为后续第四阶段的世界编辑器、运行时回写和世界演化能力预留稳定接口。
|
||||
|
||||
---
|
||||
|
||||
## 3. 设计原则
|
||||
|
||||
1. 前端只做表现与编排,世界规则解释、任务生成、物品生成、状态持久化都在 Express 后端完成。
|
||||
2. 优先改造现有链路与现有类型,不新造平行系统。
|
||||
3. 兼容字段只做 fallback,不反向主导真实世界内容。
|
||||
4. 所有新增结构都必须能同时服务“预设内容生成”和“运行时规则生成”,避免再次分叉。
|
||||
5. 每一个优化项都必须带测试入口、验收口径和回滚开关。
|
||||
|
||||
---
|
||||
|
||||
## 4. P0 优化方案:补齐后端真实世界消费链
|
||||
|
||||
## P0-1:建立统一的运行时世界消费 Contract
|
||||
|
||||
### 问题定义
|
||||
|
||||
当前前端剧情主链可以拿到较完整的 `customWorldProfile`,但后端任务与物品模块只消费 `{ name, summary }` 这类瘦身字段,导致同一个世界在不同链路里语义强度不一致。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 后端所有运行时生成模块统一读取 `RuntimeWorldContext`。
|
||||
- `RuntimeWorldContext` 来源于 `CustomWorldProfile` 的受控裁剪,而不是各模块各自手写轻量字段。
|
||||
- 前后端消费世界信息时,共享同一套字段分层。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\ai\customWorldOrchestrator.ts`
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\runtime-item\runtimeItemModule.ts`
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\quest\runtimeQuestModule.ts`
|
||||
- `E:\Repos\Genarrative\src\types\customWorld.ts`
|
||||
- `E:\Repos\Genarrative\src\hooks\story\storyContextBuilder.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 在后端新增统一的 `RuntimeWorldContext` 类型与构建函数。
|
||||
2. 首批纳入字段:
|
||||
- `name`
|
||||
- `summary`
|
||||
- `themePack`
|
||||
- `storyGraph`
|
||||
- `knowledgeFacts`
|
||||
- `threadContracts`
|
||||
- `majorFactions`
|
||||
- `coreConflicts`
|
||||
- `ownedSettingLayers.ruleProfile`
|
||||
- `referenceProfile`
|
||||
3. 在 orchestrator 层完成一次裁剪与归一化,禁止 `runtimeItemModule`、`runtimeQuestModule` 自己拼 world summary。
|
||||
4. 为后端 prompt 构造器增加“世界上下文来源检查”,缺字段时直接走 fallback 分支并记录日志。
|
||||
5. 将前端剧情链现有世界裁剪逻辑与后端世界裁剪逻辑对齐,避免出现同字段两套解释。
|
||||
|
||||
### 前后端职责
|
||||
|
||||
- 前端:只传递当前线程、当前场景、当前 encounter、当前角色状态等调用上下文。
|
||||
- 后端:解释世界 profile、构造任务 prompt、构造物品 prompt、产出最终结构化结果。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 后端任务和物品生成日志中可看到相同世界的 `themePack / activeThreads / ruleProfile` 已进入 prompt 上下文。
|
||||
- 同一世界下,前端剧情 prompt 与后端任务/物品 prompt 的核心势力、冲突、世界基调不再明显割裂。
|
||||
- 缺失字段时有稳定 fallback,不会因为世界 profile 某块为空直接报错。
|
||||
|
||||
### 风险与回滚
|
||||
|
||||
- 风险:一次性带入字段过多,可能导致 prompt 膨胀。
|
||||
- 回滚策略:保留 `RuntimeWorldContextLite` 开关,出现 token 或稳定性问题时,可按模块退回精简字段集。
|
||||
|
||||
---
|
||||
|
||||
## P0-2:让后端 active threads 读取真实故事线程
|
||||
|
||||
### 问题定义
|
||||
|
||||
当前后端运行时物品模块里的 `activeThreadIds` 只是 `thread:${encounter.id}` 或 `thread:${scene.id}` 这类伪 id,不是真正来自 `storyGraph` 的线程对象。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 后端运行时统一读取真实 `storyGraph` 线程。
|
||||
- 若当前 scene / encounter 未命中真实线程,再进入显式 fallback。
|
||||
- 运行时物品、任务奖励、事件物件都能解释“为什么此刻出现”。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\runtime-item\runtimeItemModule.ts`
|
||||
- `E:\Repos\Genarrative\src\services\storyEngine\worldStoryGraph.ts`
|
||||
- `E:\Repos\Genarrative\src\services\storyEngine\threadContract.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 在后端新增 `resolveActiveWorldThreads(...)`,输入 scene、encounter、knowledge facts、runtime memory。
|
||||
2. 线程命中优先顺序:
|
||||
- 当前 scene 关联线程
|
||||
- 当前 encounter / npc 关联线程
|
||||
- 当前已激活 `threadContracts`
|
||||
- 当前 `knowledgeFacts` 所属线程
|
||||
- fallback synthetic thread
|
||||
3. synthetic thread 必须显式标记 `source: fallback`,防止伪装成真实世界线程。
|
||||
4. 物品与任务模块统一消费 `ResolvedThreadRef[]`,不再直接消费裸字符串 id。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 后端日志中可区分真实线程与 fallback 线程。
|
||||
- 运行时物品说明、任务目标和世界冲突有明确对应,不再只围绕当前场景 id 即时拼接。
|
||||
|
||||
### 风险与回滚
|
||||
|
||||
- 风险:现有 scene / encounter 到 thread 的映射不完整,可能导致命中率不高。
|
||||
- 回滚策略:保留 synthetic fallback,但必须在日志和结构体中显式标识来源。
|
||||
|
||||
---
|
||||
|
||||
## P0-3:先补基础验证链,避免后端世界消费升级后失控
|
||||
|
||||
### 问题定义
|
||||
|
||||
世界上下文一旦进入后端主链,后续所有任务和物品生成都将更依赖字段质量;若没有结构化校验,很容易引入“字段有了但解释不一致”的新问题。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 为 `RuntimeWorldContext` 建立结构校验与测试样例。
|
||||
- 世界映射升级后可以快速回归。
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 为 `RuntimeWorldContext` 增加 schema 校验或最小断言层。
|
||||
2. 建立 3 组回归世界:
|
||||
- 武侠
|
||||
- 现代都市
|
||||
- 科幻/魔法混合
|
||||
3. 增加任务模块、物品模块的世界消费快照测试。
|
||||
4. 对“缺 `storyGraph`、缺 `items`、缺 `factions`”的情况补边界测试。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 世界消费链新增测试可稳定通过。
|
||||
- 新增字段不会让现有预设世界直接失效。
|
||||
|
||||
---
|
||||
|
||||
## 5. P1 优化方案:弱化模板主导,补齐世界物件图谱
|
||||
|
||||
## P1-1:把 `templateWorldType` 退回兼容层
|
||||
|
||||
### 问题定义
|
||||
|
||||
当前 `templateWorldType / compatibilityTemplateWorldType` 仍然过度参与角色模板、场景视觉、怪物池、fallback 映射,导致跨题材世界被粗暴压回 `WUXIA/XIANXIA`。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- `templateWorldType` 仅用于兼容旧模板与最低保底 fallback。
|
||||
- 真实映射优先读取 `ownedSettingLayers`、`themePack`、`referenceProfile`、世界表达层信号。
|
||||
- 新世界生成不再被强制压成二元题材。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\ai\customWorldOrchestrator.ts`
|
||||
- `E:\Repos\Genarrative\src\services\customWorldTheme.ts`
|
||||
- `E:\Repos\Genarrative\src\data\customWorldVisuals.ts`
|
||||
- `E:\Repos\Genarrative\src\data\customWorldNpcMonsters.ts`
|
||||
- `E:\Repos\Genarrative\src\data\characterPresets.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 梳理所有直接读取 `templateWorldType` 的模块,按用途拆成:
|
||||
- 必须兼容旧内容
|
||||
- 实际主导内容生成
|
||||
2. 新增 `worldFlavorProfile` 或等价归一层,从以下信号综合得出世界风味:
|
||||
- 世界主题摘要
|
||||
- `themePack`
|
||||
- `expressionProfile`
|
||||
- `ownedSettingLayers`
|
||||
- `referenceProfile.sceneBuckets`
|
||||
- `referenceProfile.creatureArchetypes`
|
||||
3. 将视觉、怪物、角色模板选择改为优先读取 `worldFlavorProfile`。
|
||||
4. `templateWorldType` 只在真实信号不足时参与兜底。
|
||||
5. 补 5 类题材测试样本:
|
||||
- 现代金融
|
||||
- 赛博 AI 战争
|
||||
- 校园悬疑
|
||||
- 海洋奇幻
|
||||
- 仙侠科技混合
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 非武侠/仙侠世界不再默认掉进 `WUXIA/XIANXIA` preset 池。
|
||||
- 视觉、怪物、角色原型对同一世界的选择结果更加一致。
|
||||
- 旧世界内容仍能被兼容字段兜住。
|
||||
|
||||
### 风险与回滚
|
||||
|
||||
- 风险:移除模板主导后,部分老世界可能暂时失去稳定视觉锚点。
|
||||
- 回滚策略:保留兼容开关,允许单模块临时回退到旧模板选择逻辑。
|
||||
|
||||
---
|
||||
|
||||
## P1-2:建立世界级 Item Seed 与 World Item Graph
|
||||
|
||||
### 问题定义
|
||||
|
||||
`CustomWorldProfile.items` 虽然在类型层存在,但主链会主动清空,导致世界级物品图谱缺席,任务奖励、宝藏、掉落、交易更依赖运行时临时生成。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 世界生成阶段可产出一批结构化 `item seeds`。
|
||||
- `item seeds` 能挂接到 `knowledgeFacts`、`landmarks`、`factions`、`threads`、`treasure hints`。
|
||||
- 运行时物品生成优先从世界级物件图谱中取材,而不是完全现场即兴。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\ai\customWorldOrchestrator.ts`
|
||||
- `E:\Repos\Genarrative\src\services\customWorldBuilder.ts`
|
||||
- `E:\Repos\Genarrative\src\data\customWorldRuntime.ts`
|
||||
- `E:\Repos\Genarrative\src\services\storyEngine\knowledgeGraph.ts`
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\runtime-item\runtimeItemModule.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 停止在主链里无条件把 `items` 压空。
|
||||
2. 新增 `WorldItemSeed` 结构,最少包含:
|
||||
- `id`
|
||||
- `name`
|
||||
- `category`
|
||||
- `rarity`
|
||||
- `originType`
|
||||
- `relatedFactionIds`
|
||||
- `relatedThreadIds`
|
||||
- `relatedLandmarkIds`
|
||||
- `knowledgeSummary`
|
||||
3. 世界生成阶段只产出“有限世界物件 seed”,不预生成全量成品装备。
|
||||
4. 运行时物品模块新增两段式生成:
|
||||
- 先从 `WorldItemSeed` 中挑选相关 seed
|
||||
- 再根据当前场景和奖励语境编译成最终 runtime item
|
||||
5. 任务奖励、宝藏提示、交易货单优先引用世界 item seed。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 同一世界内的物品来源能够被追溯到特定势力、地标或线程。
|
||||
- 宝藏、任务奖励和偶发掉落之间开始出现统一世界物件语义。
|
||||
- 即使不预生成大量装备,系统也已具备稳定的世界物件骨架。
|
||||
|
||||
### 风险与回滚
|
||||
|
||||
- 风险:若 seed 太多,会拖慢世界生成与存档体积。
|
||||
- 回滚策略:限制每个世界的 seed 上限,只保留高价值世界物件骨架。
|
||||
|
||||
---
|
||||
|
||||
## P1-3:统一“任务奖励 / 宝藏 / 掉落 / 交易”的物品取材顺序
|
||||
|
||||
### 问题定义
|
||||
|
||||
即使补上世界 `items`,如果各入口仍各自即时生成,世界物件图谱仍然无法变成真实运行时约束。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 物品相关入口统一读取同一套 world-first 取材顺序。
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 制定统一物品取材优先级:
|
||||
- 世界线程相关 seed
|
||||
- 当前场景相关 seed
|
||||
- 当前势力相关 seed
|
||||
- 当前角色 build / 属性补位型 seed
|
||||
- 程序化 fallback
|
||||
2. 将该顺序接入:
|
||||
- runtime item
|
||||
- quest reward
|
||||
- treasure hint
|
||||
- shop inventory
|
||||
3. 为每种入口记录 `itemSourceType`,便于后续审计。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 不同入口产出的物品不再像来自多个无关池子。
|
||||
- 同一阶段的奖励和世界冲突、场景语境具有明显一致性。
|
||||
|
||||
---
|
||||
|
||||
## 6. P2 优化方案:把文本世界升级成可操作对象世界
|
||||
|
||||
## P2-1:把 `majorFactions / coreConflicts` 升级成结构对象
|
||||
|
||||
### 问题定义
|
||||
|
||||
当前势力与冲突已能进入 `ThemePack`、`StoryGraph`、`FactionTensionState`,但本质仍偏文本语义层,尚未形成可索引、可归属、可推进的游戏对象。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- faction 成为正式实体。
|
||||
- conflict 成为正式实体。
|
||||
- NPC、scene、shop、quest、thread 可以明确挂接到 faction/conflict。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\src\services\storyEngine\themePack.ts`
|
||||
- `E:\Repos\Genarrative\src\services\storyEngine\worldStoryGraph.ts`
|
||||
- `E:\Repos\Genarrative\src\services\storyEngine\factionTensionState.ts`
|
||||
- `E:\Repos\Genarrative\server-node\src\modules\quest\runtimeQuestModule.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 新增 `WorldFaction`、`WorldConflict` 结构类型。
|
||||
2. `majorFactions` 进入标准化流程,最少补:
|
||||
- `id`
|
||||
- `name`
|
||||
- `publicImage`
|
||||
- `stanceTags`
|
||||
- `homeLandmarkIds`
|
||||
- `relatedNpcIds`
|
||||
3. `coreConflicts` 进入标准化流程,最少补:
|
||||
- `id`
|
||||
- `title`
|
||||
- `parties`
|
||||
- `stakes`
|
||||
- `relatedThreadIds`
|
||||
- `pressureLevel`
|
||||
4. 任务模块改为先选 conflict,再派生 quest intent。
|
||||
5. scene / npc / 商店 / 敌对阵营状态优先读取 faction 归属。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 任一任务都可追溯到某个 faction 或 conflict,而不只是笼统“世界 tension”。
|
||||
- NPC 与场景可以明确展示势力归属或冲突立场。
|
||||
|
||||
### 风险与回滚
|
||||
|
||||
- 风险:结构化后,旧世界数据可能缺字段。
|
||||
- 回滚策略:保留旧字符串字段作为输入源,通过标准化编译器补齐对象字段。
|
||||
|
||||
---
|
||||
|
||||
## P2-2:修正 landmark 场景中的模板怪物硬注入
|
||||
|
||||
### 问题定义
|
||||
|
||||
当前 landmark scene 在放入 `landmark.sceneNpcIds` 对应实体之外,还会从模板怪物池额外拼入敌对实体,导致地标设定与实际战斗实体池出现偏移。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- landmark 场景内容优先由 `landmark + storyNpcs + factions + conflicts` 决定。
|
||||
- 模板怪物仅在内容缺口时补位。
|
||||
- 补位结果也必须受世界题材和当前线程约束。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\src\data\scenePresets.ts`
|
||||
- `E:\Repos\Genarrative\src\data\customWorldNpcMonsters.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 将场景实体池拆成三层:
|
||||
- 显式指定实体
|
||||
- 世界关系推导实体
|
||||
- 模板补位实体
|
||||
2. 补位触发条件必须显式化,例如:
|
||||
- 当前场景无敌对实体
|
||||
- 当前任务需要战斗对象
|
||||
- 当前地标存在压力标签但无实体承载
|
||||
3. 模板补位时必须额外经过:
|
||||
- 世界风味过滤
|
||||
- faction/conflict 过滤
|
||||
- landmark 标签过滤
|
||||
4. 记录实体来源,供后续审计。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- landmark 场景中的实体构成更忠于世界原始设定。
|
||||
- 非武侠/仙侠世界不再被模板怪物池轻易拖偏。
|
||||
|
||||
---
|
||||
|
||||
## P2-3:让冲突与势力真实进入任务和场景状态推进
|
||||
|
||||
### 问题定义
|
||||
|
||||
即使 faction/conflict 对象化,如果任务与场景状态推进仍然只吃文本 tension,总体改善也会有限。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 冲突和势力状态能驱动任务来源、场景压力、敌我关系和奖励语境。
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 任务生成先选 conflict,再根据 `pressureLevel`、`party`、`stakes` 生成目标和阶段。
|
||||
2. 场景压力读取当前 `conflict` 和 `faction tension`,决定:
|
||||
- 敌对出现概率
|
||||
- 商店风格
|
||||
- 场景描述张力
|
||||
3. 奖励语义优先与 conflict/faction 绑定。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 同一冲突升温后,任务、场景、物品奖励能出现同步变化。
|
||||
|
||||
---
|
||||
|
||||
## 7. P3 优化方案:补齐长尾 archetype 与创作层沉淀
|
||||
|
||||
## P3-1:扩展 `referenceProfile.roleArchetypes` 来源
|
||||
|
||||
### 问题定义
|
||||
|
||||
当前 `roleArchetypes` 主要从 `playableNpcs.slice(0, 6)` 派生,导致可玩角色映射稳定,但长尾 `storyNpcs`、平民、敌对成员、怪物的 archetype 覆盖不足。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- `roleArchetypes` 来源覆盖 `playableNpcs + storyNpcs`。
|
||||
- 长尾角色也能沉淀为稳定 archetype。
|
||||
|
||||
### 关键文件
|
||||
|
||||
- `E:\Repos\Genarrative\src\services\customWorldOwnedSettingLayers.ts`
|
||||
- `E:\Repos\Genarrative\src\services\customWorldReferenceSignals.ts`
|
||||
- `E:\Repos\Genarrative\src\data\characterPresets.ts`
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 调整 archetype 编译输入,加入 `storyNpcs`。
|
||||
2. 按角色用途拆 archetype 桶:
|
||||
- playable
|
||||
- civilian
|
||||
- hostile
|
||||
- monster
|
||||
- faction member
|
||||
3. 为长尾 archetype 增加抽样上限与去重规则,避免噪声过大。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 非主角型角色在模板选择时命中率更高。
|
||||
- 长尾场景角色的表现更稳定,不再过度依赖 heuristics fallback。
|
||||
|
||||
---
|
||||
|
||||
## P3-2:重新定义哪些创作层元数据需要进入运行时
|
||||
|
||||
### 问题定义
|
||||
|
||||
`creatorIntent / anchorPack / lockState / anchorContent` 当前主要停留在创作与编辑器链路,对正式运行时作用较弱。
|
||||
|
||||
### 目标状态
|
||||
|
||||
- 明确区分“只服务创作编辑”的元数据和“应进入运行时约束”的元数据。
|
||||
- 防止未来编辑器功能越做越多,但运行时仍读不到关键锚点。
|
||||
|
||||
### 实施步骤
|
||||
|
||||
1. 对四类元数据逐项分层:
|
||||
- 创作态专用
|
||||
- 编译态可消费
|
||||
- 运行时必须消费
|
||||
2. 首批建议进入运行时的内容:
|
||||
- 不可违背的世界禁令
|
||||
- 必须保留的主势力/主线锚点
|
||||
- 必须保留的世界表达边界
|
||||
3. 将运行时需要消费的部分编译进 `ownedSettingLayers` 或 `RuntimeWorldContext`,不要让运行时直接读取编辑器原始字段。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 世界编辑器中被锁定的高优先级设定,能在任务、剧情、物品和场景中持续生效。
|
||||
- 创作层字段不会原样泄漏进运行时,仍保持清晰编译边界。
|
||||
|
||||
---
|
||||
|
||||
## 8. 推荐实施顺序
|
||||
|
||||
## 第一阶段:先打通后端世界消费主链
|
||||
|
||||
1. `P0-1` 统一 `RuntimeWorldContext`
|
||||
2. `P0-2` 接入真实线程解析
|
||||
3. `P0-3` 补回归验证链
|
||||
|
||||
## 第二阶段:弱化模板主导,补齐世界物件骨架
|
||||
|
||||
1. `P1-1` 模板退回兼容层
|
||||
2. `P1-2` 建立世界 item seed
|
||||
3. `P1-3` 统一物品入口取材顺序
|
||||
|
||||
## 第三阶段:把世界对象化
|
||||
|
||||
1. `P2-1` faction/conflict 对象化
|
||||
2. `P2-2` 修正 landmark 怪物注入
|
||||
3. `P2-3` 接入任务与场景状态推进
|
||||
|
||||
## 第四阶段:补齐长尾映射与创作层沉淀
|
||||
|
||||
1. `P3-1` 扩展 archetype 来源
|
||||
2. `P3-2` 明确创作层入运行时边界
|
||||
|
||||
---
|
||||
|
||||
## 9. 里程碑拆分建议
|
||||
|
||||
## M1:世界消费对齐
|
||||
|
||||
- 输出物:`RuntimeWorldContext`、后端任务/物品世界消费升级、真实线程解析
|
||||
- 结果判定:前后端都能围绕同一世界线程与规则说话
|
||||
|
||||
## M2:跨题材映射纠偏
|
||||
|
||||
- 输出物:`worldFlavorProfile`、模板兼容层瘦身、跨题材测试集
|
||||
- 结果判定:现代/科幻/混合题材不再被压回武侠/仙侠
|
||||
|
||||
## M3:世界物件与势力冲突对象化
|
||||
|
||||
- 输出物:`WorldItemSeed`、`WorldFaction`、`WorldConflict`
|
||||
- 结果判定:任务、场景、物品奖励开始围绕世界对象图谱运转
|
||||
|
||||
## M4:长尾稳定化
|
||||
|
||||
- 输出物:扩展 archetype、运行时锚点编译边界
|
||||
- 结果判定:长尾 NPC 与世界编辑器高优先级设定都能稳定进入运行时
|
||||
|
||||
---
|
||||
|
||||
## 10. 验收口径
|
||||
|
||||
本轮优化建议至少按以下 8 条验收:
|
||||
|
||||
1. 后端任务与物品模块都已消费统一 `RuntimeWorldContext`。
|
||||
2. 后端 `activeThreadIds` 已能区分真实线程与 fallback 线程。
|
||||
3. 非武侠/仙侠世界的视觉、怪物、角色模板选择明显更加合理。
|
||||
4. 世界 profile 中的 `items` 已形成有限但真实可用的 `item seed` 图谱。
|
||||
5. faction/conflict 已可被任务、场景、物品奖励直接引用。
|
||||
6. landmark 场景的实体池优先由地标与世界对象决定,不再被模板怪物硬主导。
|
||||
7. `storyNpcs` 已进入 archetype 编译链。
|
||||
8. 高优先级创作锚点已通过编译层进入运行时,而不是停留在编辑器态。
|
||||
|
||||
---
|
||||
|
||||
## 11. 本轮不建议优先做的事
|
||||
|
||||
- 不建议先扩充更多世界 preset、怪物 preset、场景 preset。
|
||||
- 不建议先美化编辑器文案或增加说明性 UI 文本。
|
||||
- 不建议在前端直接补更多规则判断,避免继续把世界逻辑留在表现层。
|
||||
- 不建议在没有统一后端世界 contract 之前分别微调 quest prompt 和 item prompt。
|
||||
|
||||
原因很明确:
|
||||
|
||||
**当前最缺的不是内容数量,而是“世界设定是否真的被一致消费”。在这一层没补齐前,继续加内容只会把映射偏差放大。**
|
||||
|
||||
---
|
||||
|
||||
## 12. 一句话结论
|
||||
|
||||
这轮优化最应该优先做的,不是继续往世界编辑器里加更多设定项,而是先把 `CustomWorldProfile -> 后端运行时任务/物品 -> 场景/NPC/奖励` 这条真实消费主链补齐;只有先把世界 profile 收束成单一真相源,后续跨题材世界、世界级物件、势力冲突和长尾 NPC 映射才会越做越稳。
|
||||
@@ -0,0 +1,579 @@
|
||||
# 工程无用分支、历史代码与隐形多链路大清洗执行计划(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 文档目标
|
||||
|
||||
这份文档只解决一件事:
|
||||
|
||||
**对当前工程发起一轮“不是继续加功能,而是系统性减负、删重、收口、归档”的大清洗。**
|
||||
|
||||
这轮重点不是做表面上的“代码变少”,而是把下面 3 类长期拉低可读性和可维护性的东西真正处理掉:
|
||||
|
||||
1. 无用历史代码
|
||||
2. 隐形的多数据链路 / 多真相链路乱代码
|
||||
3. 实现到一半但长期挂在主工程里的半成品代码
|
||||
|
||||
本文目标不是重复现有审计,而是把已有结论整理成:
|
||||
|
||||
1. 可执行的清洗范围
|
||||
2. 明确的判定标准
|
||||
3. 分阶段的推进顺序
|
||||
4. 每阶段的交付物
|
||||
5. 可以落地的验收与回滚口径
|
||||
|
||||
---
|
||||
|
||||
## 1. 先把“清什么”说清楚
|
||||
|
||||
这次文档里说的“无用分支”,优先指的是:
|
||||
|
||||
1. 代码逻辑分支
|
||||
2. 数据链路分支
|
||||
3. 兼容实现分支
|
||||
4. 遗留入口分支
|
||||
|
||||
**不是先把 Git 分支清空。**
|
||||
|
||||
Git 分支治理可以后置做,但不能和首轮工程清洗混在一起,否则很容易把“代码归因”“入口归因”“历史责任归因”一起搅乱。
|
||||
|
||||
---
|
||||
|
||||
## 2. 三类清洗对象的定义
|
||||
|
||||
## 2.1 无用历史代码
|
||||
|
||||
满足以下任一特征,即进入“无用历史代码候选”:
|
||||
|
||||
1. 没有正式运行时入口,也没有当前规划要接回入口
|
||||
2. 只被测试或历史兼容层引用,但主流程已经不再依赖
|
||||
3. 与当前正式实现功能重复,但不是唯一真相源
|
||||
4. 只剩 stub、占位、迁移残骸、旧 prompt 壳子、旧 helper 壳子
|
||||
5. 生成产物仍留在主仓库,但已不再被正式流程消费
|
||||
|
||||
这类代码的处理目标是:
|
||||
|
||||
**删除、归档、降级标记三选一,不再长期以“也许以后要用”为理由挂在主路径里。**
|
||||
|
||||
## 2.2 隐形多数据链路乱代码
|
||||
|
||||
满足以下任一特征,即进入“隐形多链路问题候选”:
|
||||
|
||||
1. 同一份运行时状态同时由前端本地镜像和后端会话共同解释
|
||||
2. 同一类任务、物品、剧情、鉴权逻辑在前后端或多模块里各维护一份
|
||||
3. 同一份数据在“提交前本地写一份、提交后服务端再回填一份”
|
||||
4. 同一功能表面只有一个按钮,背后却有两到三条实现路径
|
||||
5. 正式链路和 fallback 链路长期并存,且没有退场时间
|
||||
|
||||
这类问题的处理目标是:
|
||||
|
||||
**把每条正式能力收敛成单一主链、单一真相源、单一编排出口。**
|
||||
|
||||
## 2.3 实现到一半的半成品代码
|
||||
|
||||
满足以下任一特征,即进入“半成品候选”:
|
||||
|
||||
1. UI、Hook、Service 已存在,但没有正式入口
|
||||
2. 文档写了概念,代码只落了一半,后续也没有继续接完
|
||||
3. 只有局部测试或局部 mock 在用,真实流程不用
|
||||
4. 仍保留 TODO / stub / draft / launcher / modal,但未纳入当前主线
|
||||
5. 用户看不到、主流程不调用、团队也没有当前阶段交付计划
|
||||
|
||||
这类代码的处理目标是:
|
||||
|
||||
**要么纳入当前主线尽快补完,要么明确归档,不允许继续以“半活状态”污染主工程。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 这轮清洗后的目标状态
|
||||
|
||||
本轮完成后,工程应至少达到下面 7 个状态:
|
||||
|
||||
1. 同一领域只保留一条正式主链,不再出现前后端双真相或多桥接链路并存
|
||||
2. 无入口孤岛、旧兼容壳子、旧 prompt 壳子、旧 stub 文件有明确去留结果
|
||||
3. “实现到一半”的模块不再伪装成正式能力挂在主工程中
|
||||
4. 前端继续回到“表现层”,正式运行时逻辑、鉴权真相、任务物品编排继续向后端收口
|
||||
5. 热点大文件不再同时背负历史残留、兼容残留和新逻辑堆叠
|
||||
6. 文档与代码状态一致,不再让旧规划长期误导当前执行方向
|
||||
7. `lint + typecheck + test + build + check:content` 重新成为可信基线
|
||||
|
||||
---
|
||||
|
||||
## 4. 执行原则
|
||||
|
||||
## 4.1 不做大爆炸整仓改写
|
||||
|
||||
本轮只允许“小批次、可回归、可解释”的连续清洗,不做一次性整仓推翻。
|
||||
|
||||
## 4.2 先建台账,再动删除
|
||||
|
||||
任何删除、归档、重定向动作前,必须先确认:
|
||||
|
||||
1. 当前入口关系
|
||||
2. 当前依赖关系
|
||||
3. 当前替代路径
|
||||
4. 删除后的验收路径
|
||||
|
||||
没有台账,不做大规模删改。
|
||||
|
||||
## 4.3 先收真相源,再谈瘦身
|
||||
|
||||
如果同一领域仍有多条真相链路并存,优先收口真相源,而不是只删表面代码量。
|
||||
|
||||
## 4.4 文档和代码同步收口
|
||||
|
||||
只要本轮确认某条旧链降级、冻结、归档,相关文档必须同步更新,不能让旧文档继续把团队往废链路上拉。
|
||||
|
||||
## 4.5 每批清洗必须可回归
|
||||
|
||||
每一批完成后至少要求:
|
||||
|
||||
1. 入口可解释
|
||||
2. 回归路径明确
|
||||
3. 门禁可跑
|
||||
4. 回滚点存在
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前已知问题基础
|
||||
|
||||
本计划基于现有文档已经确认的结论推进,重点参考:
|
||||
|
||||
1. `docs/audits/engineering/README.md`
|
||||
2. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`
|
||||
3. `docs/audits/engineering/CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`
|
||||
4. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
5. `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
|
||||
按当前审计结果,首轮就应重点关注下面 3 组对象。
|
||||
|
||||
## 5.1 当前高置信度“无入口 / 孤岛 / 残留”候选
|
||||
|
||||
以下对象已经在最近审计中被点名,默认进入首轮复核台账:
|
||||
|
||||
1. `src/components/GameShell.tsx`
|
||||
2. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
3. `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx`
|
||||
4. `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx`
|
||||
5. `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
6. `src/hooks/story/storyBootstrap.ts`
|
||||
7. `src/hooks/useEquipmentFlow.ts`
|
||||
8. `src/hooks/useForgeFlow.ts`
|
||||
9. `src/hooks/useInventoryFlow.ts`
|
||||
10. `src/services/customWorldPresentation.stub.ts`
|
||||
11. `src/services/typewriter.ts`
|
||||
12. `src/prompts/customWorldOrchestratorPrompts.ts`
|
||||
13. `src/prompts/storyOrchestratorPrompts.ts`
|
||||
14. `src/data/buildTagSimilarity.generated.ts`(已在后续清理批次中删除)
|
||||
|
||||
这些文件不能直接判死刑,但必须进入“保留 / 接回 / 归档 / 删除”四选一清单。
|
||||
|
||||
## 5.2 当前高置信度“隐形多链路 / 双真相”候选
|
||||
|
||||
以下对象应进入首轮主链收口清单:
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
2. `src/services/runtimeStoryService.ts`
|
||||
3. `src/services/apiClient.ts`
|
||||
4. `src/hooks/story/npcEncounterActions.ts`
|
||||
5. `src/services/questDirector.ts`
|
||||
6. `src/services/runtimeItemAiDirector.ts`
|
||||
7. `src/services/ai.ts`
|
||||
|
||||
当前这批问题的共同特征是:
|
||||
|
||||
1. 前端仍保留本地镜像、自动登录凭证或双环境编排残留
|
||||
2. NPC 任务换单、任务生成、运行时物品生成仍有前端发起和混合执行痕迹
|
||||
3. 浏览器侧大型 AI orchestration 仍未完全退出主工程
|
||||
|
||||
## 5.3 当前“新热点继续吸纳历史复杂度”候选
|
||||
|
||||
以下对象不一定是垃圾代码,但很容易继续成为历史残留的新容器:
|
||||
|
||||
1. `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
2. `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
3. `src/prompts/storyPromptBuilders.ts`
|
||||
4. `server-node/src/modules/custom-world/runtimeProfile.ts`
|
||||
5. `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
6. `src/components/game-shell/PlatformHomeView.tsx`
|
||||
|
||||
这批文件必须在本轮中被视为“禁止继续裸堆新逻辑”的重点区域。
|
||||
|
||||
---
|
||||
|
||||
## 6. 清洗判定表
|
||||
|
||||
每个候选对象进入清理台账后,只允许落到下面 4 类结果之一:
|
||||
|
||||
| 结果类型 | 适用场景 | 处理动作 |
|
||||
| --- | --- | --- |
|
||||
| 删除 | 无入口、无当前规划、无兼容价值 | 直接删文件、删引用、补回归 |
|
||||
| 归档 | 暂不继续,但保留历史价值 | 移出主路径、在文档中标明冻结状态 |
|
||||
| 扶正 | 当前主线确实需要,只是入口丢失或命名混乱 | 接回正式入口、补测试、补文档 |
|
||||
| 拆分收口 | 不是废代码,但混合了历史残留和正式逻辑 | 先拆职责,再删除残留分支 |
|
||||
|
||||
禁止出现第 5 种状态:
|
||||
|
||||
**“先留着,以后再说,但继续挂在主工程里。”**
|
||||
|
||||
---
|
||||
|
||||
## 7. 分阶段执行计划
|
||||
|
||||
## P0:冻结新增污染,先建立清洗台账
|
||||
|
||||
### 目标
|
||||
|
||||
先把“哪些东西要清、为什么清、怎么判定是否能清”讲清楚,停止继续往旧热点和疑似废链上加逻辑。
|
||||
|
||||
### 主要动作
|
||||
|
||||
1. 建立 3 份清单:
|
||||
- 无入口孤岛清单
|
||||
- 多真相链路清单
|
||||
- 半成品能力清单
|
||||
2. 为每个对象补 5 个字段:
|
||||
- 当前入口
|
||||
- 当前调用方
|
||||
- 当前替代路径
|
||||
- 建议结论
|
||||
- 回归验证点
|
||||
3. 约束新增开发:
|
||||
- 不再向疑似废链补功能
|
||||
- 不再向热点大文件直接叠逻辑
|
||||
- 新需求优先接到当前正式主链
|
||||
4. 明确本轮清洗后的唯一方向:
|
||||
- 前端只做表现
|
||||
- 后端持有正式运行时真相
|
||||
- 旧兼容链不能继续膨胀
|
||||
|
||||
### 交付物
|
||||
|
||||
1. 清洗对象总台账
|
||||
2. 首轮批次拆分表
|
||||
3. 每批回归清单
|
||||
|
||||
### 完成标准
|
||||
|
||||
不是“开始删文件”才算开始。
|
||||
|
||||
只要台账、批次、判定口径和冻结规则明确,这一阶段就算完成。
|
||||
|
||||
---
|
||||
|
||||
## P1:先清无入口孤岛和明显历史残留
|
||||
|
||||
### 目标
|
||||
|
||||
先把最容易污染阅读体验、又不需要大规模业务改造的对象清掉,快速降低仓库噪音。
|
||||
|
||||
### 优先清理对象
|
||||
|
||||
1. 无运行时入口组件
|
||||
2. 只被测试引用的旧壳层
|
||||
3. 已迁移后留下的 stub / prompt 壳 / helper 壳
|
||||
4. 已不进入正式链路的 generated 文件
|
||||
5. 旧 launcher / draft / modal 壳层
|
||||
|
||||
### 处理顺序建议
|
||||
|
||||
1. 先处理 `prompt / stub / helper / launcher` 级别的小残留
|
||||
2. 再处理 `旧 hook / 旧 flow / 旧 shell` 级别的流程残留
|
||||
3. 最后处理“可能有历史价值但暂不接回”的 UI 大块头
|
||||
|
||||
### 本阶段输出结果
|
||||
|
||||
每个对象必须给出明确结果:
|
||||
|
||||
1. 删除
|
||||
2. 归档
|
||||
3. 扶正接回
|
||||
|
||||
### 验收标准
|
||||
|
||||
1. 主工程中“没有正式入口的文件”显著减少
|
||||
2. 新人看目录时,不再大量遇到真假难辨的旧入口
|
||||
3. 相关引用、测试、文档同步更新
|
||||
|
||||
---
|
||||
|
||||
## P2:收单一真相源,清掉隐形多数据链路
|
||||
|
||||
### 目标
|
||||
|
||||
这阶段不以“删多少文件”为核心,而是以“同一件事最终只走一条正式链”作为核心。
|
||||
|
||||
### 第一优先级链路
|
||||
|
||||
1. 运行时快照链
|
||||
2. 鉴权与自动登录链
|
||||
3. NPC 任务生成 / 换单链
|
||||
4. 运行时物品生成链
|
||||
5. 浏览器端 AI orchestration 链
|
||||
|
||||
### 重点动作
|
||||
|
||||
1. 收掉前端“提交前先写本地真相,再等服务端回填”的链路
|
||||
2. 收掉本地存储中的自动登录用户名 / 密码真相
|
||||
3. 把 NPC 委托换单动作继续迁回后端运行时主链
|
||||
4. 将 `questDirector`、`runtimeItemAiDirector` 拆成:
|
||||
- 前端 SDK 层
|
||||
- 后端正式执行层
|
||||
5. 继续压缩浏览器端 `src/services/ai.ts` 的正式职责
|
||||
|
||||
### 这阶段最重要的判断标准
|
||||
|
||||
不是“文件还在不在”,而是下面 4 条是否成立:
|
||||
|
||||
1. 玩家一次动作只提交一个正式 action,而不是两边各写一遍状态
|
||||
2. 前端不再持有正式运行时镜像真相
|
||||
3. 前端不再长期持有自动登录账号密码
|
||||
4. 同一类生成能力不再同时存在“浏览器正式版”和“后端正式版”
|
||||
|
||||
### 验收标准
|
||||
|
||||
1. 正式运行时状态解释权明确以后端为准
|
||||
2. 鉴权边界不再依赖浏览器保存高风险凭证
|
||||
3. NPC 任务、物品、剧情编排链路的职责边界清楚
|
||||
|
||||
---
|
||||
|
||||
## P3:集中处理实现到一半的半成品能力
|
||||
|
||||
### 目标
|
||||
|
||||
把“看起来像功能、实际上不是当前正式能力”的对象清出主路径。
|
||||
|
||||
### 清理规则
|
||||
|
||||
半成品对象统一按下面规则处理:
|
||||
|
||||
1. 30 天内明确要接回主线的,进入补完批次
|
||||
2. 当前阶段不做的,降级为归档或实验稿
|
||||
3. 没有继续计划、也没有正式入口价值的,直接删除
|
||||
|
||||
### 本阶段重点对象
|
||||
|
||||
1. 只有 modal / launcher / draft 壳层,但没有正式调用链的 UI
|
||||
2. 只有部分 hook / service 实现,但没有主链消费的流程模块
|
||||
3. 只剩“概念占位”的 prompt、adapter、presentation、stub 文件
|
||||
4. 文档里反复提到、代码里却长期不接线的能力块
|
||||
|
||||
### 必须同步做的事
|
||||
|
||||
1. 更新对应规划文档
|
||||
2. 从当前主叙事中移除本轮明确不做的项
|
||||
3. 给保留实验稿加清晰标签,避免被误读成正式能力
|
||||
|
||||
### 验收标准
|
||||
|
||||
1. 主工程里不再混着大量“像功能但不是正式功能”的对象
|
||||
2. 文档不再持续推动团队回头补本轮已冻结能力
|
||||
3. 目录层级和入口关系显著更清楚
|
||||
|
||||
---
|
||||
|
||||
## P4:在减负后的基础上拆热点,恢复可读性
|
||||
|
||||
### 目标
|
||||
|
||||
前 3 阶段做完后,再进入“真正让工程重新好读”的结构优化。
|
||||
|
||||
### 重点对象
|
||||
|
||||
1. `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
2. `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
3. `src/prompts/storyPromptBuilders.ts`
|
||||
4. `server-node/src/modules/custom-world/runtimeProfile.ts`
|
||||
5. `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
6. `src/components/game-shell/PlatformHomeView.tsx`
|
||||
|
||||
### 拆分原则
|
||||
|
||||
1. 先按职责拆,不按文件长度拆
|
||||
2. 先把历史残留和兼容分支移走,再做正式模块化
|
||||
3. 拆完之后必须更清晰地回答:
|
||||
- 谁负责 UI
|
||||
- 谁负责数据准备
|
||||
- 谁负责正式规则
|
||||
- 谁负责调用后端
|
||||
|
||||
### 验收标准
|
||||
|
||||
1. 热点文件不再同时吞 UI、规则、编排、兼容残留
|
||||
2. 新功能不需要再跨四五层历史壳子一起改
|
||||
3. 后续 review 能更快定位责任边界
|
||||
|
||||
---
|
||||
|
||||
## 8. 批次拆分建议
|
||||
|
||||
为了避免清理动作过大失控,建议按下面粒度推进:
|
||||
|
||||
## 批次 A:小型孤岛与残留壳子
|
||||
|
||||
处理对象:
|
||||
|
||||
1. stub
|
||||
2. prompt 壳
|
||||
3. 无入口 helper
|
||||
4. 无入口 launcher / modal
|
||||
|
||||
目标:
|
||||
|
||||
快速去噪,降低目录误导性。
|
||||
|
||||
## 批次 B:旧 flow / 旧 shell / 旧 hook
|
||||
|
||||
处理对象:
|
||||
|
||||
1. `GameShell`
|
||||
2. `storyBootstrap`
|
||||
3. `useEquipmentFlow`
|
||||
4. `useForgeFlow`
|
||||
5. `useInventoryFlow`
|
||||
|
||||
目标:
|
||||
|
||||
清旧主流程壳层和旧流程残留。
|
||||
|
||||
## 批次 C:运行时真相收口
|
||||
|
||||
处理对象:
|
||||
|
||||
1. `runtimeStoryCoordinator`
|
||||
2. `runtimeStoryService`
|
||||
3. `apiClient`
|
||||
|
||||
目标:
|
||||
|
||||
去掉本地镜像真相与本地鉴权真相。
|
||||
|
||||
## 批次 D:任务 / 物品 / AI 混合执行层收口
|
||||
|
||||
处理对象:
|
||||
|
||||
1. `npcEncounterActions`
|
||||
2. `questDirector`
|
||||
3. `runtimeItemAiDirector`
|
||||
4. `ai.ts`
|
||||
|
||||
目标:
|
||||
|
||||
消灭混合执行和双环境正式链。
|
||||
|
||||
## 批次 E:热点大文件拆分
|
||||
|
||||
处理对象:
|
||||
|
||||
1. custom world
|
||||
2. assets
|
||||
3. game shell platform
|
||||
4. prompt builder
|
||||
5. runtime profile
|
||||
|
||||
目标:
|
||||
|
||||
在主链已收口后恢复可读性。
|
||||
|
||||
---
|
||||
|
||||
## 9. 每批必须产出的内容
|
||||
|
||||
每一批都必须带着下面 5 类产出结束:
|
||||
|
||||
1. 代码改动
|
||||
2. 文档回填
|
||||
3. 去留说明
|
||||
4. 验收记录
|
||||
5. 回滚点说明
|
||||
|
||||
如果一个批次只能产出“删了几个文件”,但说不清:
|
||||
|
||||
1. 删除后谁接手
|
||||
2. 主链是否更清楚
|
||||
3. 文档是否同步
|
||||
|
||||
那么这个批次不算完成。
|
||||
|
||||
---
|
||||
|
||||
## 10. 统一验收口径
|
||||
|
||||
本轮建议至少用下面 10 条作为统一验收口径:
|
||||
|
||||
1. `npm run lint`
|
||||
2. `npm run test`
|
||||
3. `npm run build`
|
||||
4. `npm run check:content`
|
||||
5. 目录中高置信度孤岛数量下降
|
||||
6. 旧兼容链不再继续接收新逻辑
|
||||
7. 前端不再保存自动登录用户名 / 密码
|
||||
8. 运行时主状态不再由前端本地镜像优先解释
|
||||
9. 当前正式能力的入口关系能在文档中说清楚
|
||||
10. 新人阅读主目录和主流程文件时,不再频繁遇到真假并存入口
|
||||
|
||||
---
|
||||
|
||||
## 11. 风险与控制点
|
||||
|
||||
## 11.1 最大风险不是“删多了”,而是“边删边继续加废链”
|
||||
|
||||
如果没有冻结规则,这轮会一边清旧,一边又把新逻辑接回旧壳子里,最后只会重复劳动。
|
||||
|
||||
## 11.2 不能把“兼容”当永久借口
|
||||
|
||||
兼容链可以短期存在,但必须写清:
|
||||
|
||||
1. 为什么保留
|
||||
2. 保留到什么时候
|
||||
3. 谁负责后续移除
|
||||
|
||||
## 11.3 不能只删代码,不收文档
|
||||
|
||||
如果代码删了,旧文档不改,团队还是会持续把需求往旧链上接。
|
||||
|
||||
## 11.4 不能只盯文件大小,不盯真相链
|
||||
|
||||
有些文件很大但确实是正式主链。
|
||||
有些文件很小,却是双真相和多链路的根源。
|
||||
|
||||
本轮必须优先盯后者。
|
||||
|
||||
---
|
||||
|
||||
## 12. 当前不建议优先做的事
|
||||
|
||||
1. 不建议在清洗期间继续横向扩功能
|
||||
2. 不建议直接对热点文件做“纯格式化式拆分”
|
||||
3. 不建议在未确认入口关系前整片删除可疑模块
|
||||
4. 不建议让前端继续补正式运行时逻辑作为短期兜底
|
||||
5. 不建议保留“也许以后有用”的主工程残留
|
||||
|
||||
原因很简单:
|
||||
|
||||
**当前最需要恢复的不是功能宽度,而是工程的干净边界、单一主链和可读体验。**
|
||||
|
||||
---
|
||||
|
||||
## 13. 推荐推进顺序
|
||||
|
||||
建议严格按下面顺序推进:
|
||||
|
||||
1. 先做 P0:建台账、冻结污染
|
||||
2. 再做 P1:清无入口孤岛和小残留
|
||||
3. 再做 P2:收运行时、鉴权、任务物品的单一主链
|
||||
4. 再做 P3:处理半成品能力与文档冻结项
|
||||
5. 最后做 P4:拆热点、补结构可读性
|
||||
|
||||
不建议倒过来先拆热点。
|
||||
|
||||
因为如果历史残留和双真相还在,大文件拆完以后,复杂度只是换地方继续长。
|
||||
|
||||
---
|
||||
|
||||
## 14. 一句话结论
|
||||
|
||||
这轮工程大清洗的核心,不是“删旧代码看起来更清爽”,而是:
|
||||
|
||||
**用一轮有台账、有判定、有阶段、有验收的大清理,把无用历史代码、隐形多链路乱代码和半成品能力从主工程里真正清出去,让项目重新回到单一主链、单一真相源、目录可读、职责清楚的健康状态。**
|
||||
20
docs/planning/README.md
Normal file
20
docs/planning/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# 规划与优先级
|
||||
|
||||
## 当前入口
|
||||
|
||||
- [ENGINEERING_DEAD_CODE_AND_HIDDEN_BRANCH_CLEANUP_PLAN_2026-04-21.md](./ENGINEERING_DEAD_CODE_AND_HIDDEN_BRANCH_CLEANUP_PLAN_2026-04-21.md):面向无用历史代码、隐形多数据链路和半成品实现的一轮工程大清洗执行计划,强调先建台账、再删重收口、最后恢复主工程可读性。
|
||||
- [../technical/CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md](../technical/CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md):当前创作入口、Agent session、结果页自动保存、作品库与进入世界主链的正式文件级重构基线;涉及目录落位、命名规范、阶段验收与工作包拆分时优先看这一份。
|
||||
- [../technical/RPG_ENTRY_RUNTIME_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md](../technical/RPG_ENTRY_RUNTIME_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md):当前平台入口、继续游戏、角色选择、RPG runtime 与 runtime story 主链的正式文件级重构基线;涉及入口壳层、session、runtime、story、route/service/repository 拆分时优先看这一份。
|
||||
- [CURRENT_AGENT_CREATION_FLOW_OPTIMIZATION_PLAN_2026-04-20.md](./CURRENT_AGENT_CREATION_FLOW_OPTIMIZATION_PLAN_2026-04-20.md):创作链高层目标、冻结边界与执行顺序说明;文件级拆分与阶段验收以创作链重构执行方案为准。
|
||||
- [../technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md](../technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md):当前后端唯一落地口径,后续排期涉及服务端、数据真相或 SpacetimeDB 时优先按这一份判断方向。
|
||||
- [BEIJING_POLICY_APPLICATION_OVERVIEW_13_21_24_2026-04-14.md](./BEIJING_POLICY_APPLICATION_OVERVIEW_13_21_24_2026-04-14.md):北京市方向 13 / 21 / 24 的统一判断、共用材料框架和准备顺序。
|
||||
- [BEIJING_DIRECTION13_APPLICATION_MATERIALS_2026-04-14.md](./BEIJING_DIRECTION13_APPLICATION_MATERIALS_2026-04-14.md):方向 13 软件智能化提升奖励的硬门槛、必交材料、底稿建议和证据清单。
|
||||
- [BEIJING_DIRECTION21_APPLICATION_MATERIALS_2026-04-14.md](./BEIJING_DIRECTION21_APPLICATION_MATERIALS_2026-04-14.md):方向 21 “创赢未来”成长计划的报名表、BP、Demo 和融资规划整理。
|
||||
- [BEIJING_DIRECTION24_APPLICATION_MATERIALS_2026-04-14.md](./BEIJING_DIRECTION24_APPLICATION_MATERIALS_2026-04-14.md):方向 24 服务机构配券产品与企业用券两条路径的判断和材料备查。
|
||||
|
||||
## 使用建议
|
||||
|
||||
- 需要排期、拆阶段、判断先修基线还是先加功能时,先看这份。
|
||||
- 当前如果要推进创作链或 RPG 运行时主链重构,先看上面的两份 `2026-04-21` 执行方案,再回来看高层优先级和冻结边界。
|
||||
- 涉及后端方案时,不再参考已删除的 Express / Node 规划文档,统一回到 Rust / SpacetimeDB 当前基线。
|
||||
- 这份文档大量引用了经验文档、工程审查和 PRD,适合作为跨文档导航页使用。
|
||||
1011
docs/prd/ACCOUNT_SYSTEM_AND_LOGIN_ENTRY_PRD_2026-04-09.md
Normal file
1011
docs/prd/ACCOUNT_SYSTEM_AND_LOGIN_ENTRY_PRD_2026-04-09.md
Normal file
File diff suppressed because it is too large
Load Diff
635
docs/prd/AI_CHARACTER_VISUAL_ANIMATION_MVP_PRD_2026-04-04.md
Normal file
635
docs/prd/AI_CHARACTER_VISUAL_ANIMATION_MVP_PRD_2026-04-04.md
Normal file
@@ -0,0 +1,635 @@
|
||||
# AI 角色形象与角色动画 MVP PRD
|
||||
|
||||
更新时间:`2026-04-19`
|
||||
|
||||
## 0. 一句话结论
|
||||
|
||||
本次 MVP 要做的不是一个泛化的“AI 动画平台”,而是一个能直接服务当前项目角色资产生产的最小闭环:
|
||||
|
||||
1. 用户先输入角色形象设定并上传参考图,或直接上传现成角色素材
|
||||
2. 系统生成或规范化出一张**符合当前游戏侧视角色素材视角**的主形象图
|
||||
3. 用户确认主形象后,再为该角色生成与当前项目可扮演角色动作槽位匹配的基础动作集
|
||||
4. 用户可预览、重新生成,并最终发布为当前仓库可直接读取的角色资产
|
||||
|
||||
一句话说:
|
||||
|
||||
**MVP 先解决“怎么稳定产出能进游戏的角色主形象和基础动作”,而不是先追求所有技能动作和复杂演出。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景
|
||||
|
||||
当前仓库已经有:
|
||||
|
||||
- 可扮演角色与角色型 NPC
|
||||
- `CharacterAnimator` 运行时播放链路
|
||||
- 角色预设与 override 机制
|
||||
- 本地 API 插件机制
|
||||
- NPC 静态形象编辑器
|
||||
|
||||
但当前缺少一条可用的角色资产生产链:
|
||||
|
||||
1. 角色主形象仍依赖手工素材整理
|
||||
2. 动作资产缺少“从角色设定到可播放动作集”的编辑器闭环
|
||||
3. 没有把“AI 生成结果”稳定沉淀为当前项目的标准角色资源
|
||||
|
||||
因此本期 MVP 的目标不是重做运行时战斗系统,而是补齐:
|
||||
|
||||
- 主形象生产
|
||||
- 基础动作生产
|
||||
- 预览与重新生成
|
||||
- 发布到现有角色资源体系
|
||||
|
||||
---
|
||||
|
||||
## 2. MVP 要解决的问题
|
||||
|
||||
## 2.1 用户侧问题
|
||||
|
||||
当前如果想给项目新增一个角色,成本很高:
|
||||
|
||||
- 要先准备适合当前游戏视角的主形象
|
||||
- 再补动作资源
|
||||
- 还要手工整理资源目录和配置
|
||||
|
||||
MVP 要把这件事改成一个编辑器工作流。
|
||||
|
||||
## 2.2 项目侧问题
|
||||
|
||||
当前项目并不适合把 AI 直接放进运行时实时生成动作,因为:
|
||||
|
||||
- 运行时需要稳定、可回放、可测试的资源
|
||||
- 战斗和剧情都依赖固定动作槽位
|
||||
- 生成结果如果不资产化,会让维护成本失控
|
||||
|
||||
所以 MVP 的正确方向是:
|
||||
|
||||
**把 AI 用在编辑器里的资产生产链,而不是运行时即时生成。**
|
||||
|
||||
---
|
||||
|
||||
## 3. MVP 目标
|
||||
|
||||
## 3.1 产品目标
|
||||
|
||||
提供一个最小可用的“角色资产工坊”,满足以下闭环:
|
||||
|
||||
1. 生成或上传角色主形象
|
||||
2. 预览并重选角色主形象
|
||||
3. 基于主形象生成基础动作
|
||||
4. 预览并重选动作结果
|
||||
5. 发布为当前项目可直接使用的角色资源
|
||||
|
||||
## 3.2 技术目标
|
||||
|
||||
MVP 必须满足:
|
||||
|
||||
1. 只依赖国内可用模型与服务
|
||||
2. 只生成当前项目能消费的标准资产
|
||||
3. 不改动现有战斗规则与剧情规则
|
||||
4. 生成结果必须走本地后处理与发布流程
|
||||
5. 运行时只读本地标准化资产
|
||||
|
||||
## 3.3 成功标准
|
||||
|
||||
当以下条件同时成立时,视为 MVP 成功:
|
||||
|
||||
1. 编辑器里可以完成“主形象 -> 基础动作 -> 发布”闭环
|
||||
2. 发布后的角色能被当前 `CharacterAnimator` 播放
|
||||
3. 基础动作槽位不存在空映射
|
||||
4. 用户可以对主形象和动作分别进行重新生成
|
||||
|
||||
---
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
本期不做:
|
||||
|
||||
1. 不做运行时实时动画生成
|
||||
2. 不做怪物动画生成链路
|
||||
3. 不做通用 NPC 群像流水线
|
||||
4. 不做技能动作全自动补齐
|
||||
5. 不做批量生产多个角色的自动流水线
|
||||
6. 不做多供应商路由调度
|
||||
|
||||
说明:
|
||||
|
||||
- 本期只先做好**单角色、单次编辑器操作**的最小闭环
|
||||
- 技能动作可后续补,但**基础动作槽位不能为空**
|
||||
|
||||
---
|
||||
|
||||
## 5. 目标用户与使用场景
|
||||
|
||||
## 5.1 目标用户
|
||||
|
||||
- 项目策划
|
||||
- 项目美术 / 技术美术
|
||||
- 负责角色内容生产的开发者
|
||||
|
||||
## 5.2 核心使用场景
|
||||
|
||||
### 场景 A:新建角色
|
||||
|
||||
用户输入角色设定词、参考图,生成当前项目风格可用的主形象和基础动作。
|
||||
|
||||
### 场景 B:已有角色素材导入
|
||||
|
||||
用户已有一张角色图,希望快速裁切、规范化,并继续生成基础动作。
|
||||
|
||||
### 场景 C:已有角色动作质量不满意
|
||||
|
||||
用户不改主形象,只重新生成单个或多个动作槽位。
|
||||
|
||||
---
|
||||
|
||||
## 6. MVP 用户流程
|
||||
|
||||
## 6.1 阶段 A:主形象生成 / 导入
|
||||
|
||||
1. 用户选择角色
|
||||
2. 输入角色形象设定文本
|
||||
3. 上传角色参考图,或直接上传现成角色素材
|
||||
4. 系统做尺寸、裁剪、构图校验
|
||||
5. 提交生成或规范化任务
|
||||
6. 返回多个候选预览图
|
||||
7. 用户可:
|
||||
- 预览
|
||||
- 重新生成
|
||||
- 设为当前主形象
|
||||
|
||||
## 6.2 阶段 B:基础动作生成
|
||||
|
||||
1. 用户基于已确认主形象进入动作页
|
||||
2. 系统展示当前基础动作槽位状态
|
||||
3. 用户选择:
|
||||
- 直接使用动作模板
|
||||
- 上传参考动作视频
|
||||
4. 提交动作生成任务
|
||||
5. 生成完成后进入动作预览
|
||||
6. 用户可:
|
||||
- 保留结果
|
||||
- 重新生成单动作
|
||||
- 替换当前动作
|
||||
|
||||
## 6.3 阶段 C:发布
|
||||
|
||||
只有在基础动作槽位全部有有效资源时,才允许发布。
|
||||
|
||||
发布后:
|
||||
|
||||
1. 写入主形象资源
|
||||
2. 写入动画资源
|
||||
3. 生成 manifest
|
||||
4. 更新角色 override / 映射关系
|
||||
|
||||
---
|
||||
|
||||
## 7. 主形象阶段需求
|
||||
|
||||
## 7.1 输入方式
|
||||
|
||||
MVP 支持三种主形象输入方式:
|
||||
|
||||
1. 文生图
|
||||
- 用户输入形象设定
|
||||
2. 图生图
|
||||
- 用户输入形象设定并上传参考图
|
||||
3. 直接上传素材
|
||||
- 用户上传已有角色图,不强制重新生成
|
||||
|
||||
## 7.2 视角要求
|
||||
|
||||
主形象必须贴近当前项目现有角色素材体系:
|
||||
|
||||
- 2D 侧视动作素材视角
|
||||
- 单人全身
|
||||
- 人物朝向右侧
|
||||
- 脚底完整可见
|
||||
- 武器和关键轮廓完整
|
||||
- 不做正面立绘
|
||||
- 不做强透视镜头
|
||||
|
||||
这是硬约束,不是美术建议。
|
||||
|
||||
原因:
|
||||
|
||||
- 当前项目运行时通过镜像处理左右朝向
|
||||
- 如果主形象不是侧视动作素材视角,后续动作生成和运行时挂接都会失真
|
||||
|
||||
## 7.3 尺寸与裁剪要求
|
||||
|
||||
推荐规格:
|
||||
|
||||
- 推荐输入:`1024x1536`
|
||||
- 可接受比例:`2:3` 或 `3:4`
|
||||
- 最低建议:短边 `>= 768`
|
||||
- 统一输出标准图:`1024x1536`
|
||||
|
||||
构图要求:
|
||||
|
||||
- 角色主体占画面高度约 `70% ~ 85%`
|
||||
- 头顶保留少量留白
|
||||
- 脚底必须完整露出
|
||||
- 背景尽量简单
|
||||
- 只允许单角色
|
||||
|
||||
## 7.4 主形象阶段交互要求
|
||||
|
||||
用户必须可以:
|
||||
|
||||
- 查看候选结果
|
||||
- 放大预览
|
||||
- 丢弃某个候选
|
||||
- 基于同样输入重新生成
|
||||
- 选择一个候选作为主形象
|
||||
|
||||
用户不能直接跳过主形象确认进入动作阶段,除非已经锁定主形象。
|
||||
|
||||
---
|
||||
|
||||
## 8. 动作阶段需求
|
||||
|
||||
## 8.1 基础动作槽位要求
|
||||
|
||||
MVP 必须与当前项目可扮演角色动作槽位对齐。
|
||||
|
||||
当前落地实现补充约束(`2026-04-20`):
|
||||
|
||||
- 角色资产工坊固定生成入口仍为 `idle / run / attack / die`
|
||||
- `run / attack` 是固定基础必生成动作
|
||||
- `idle / die` 改为固定可选动作,不再作为发布硬门槛
|
||||
- `idle` 未生成时默认直接使用主图静止显示
|
||||
- `die` 未生成时默认播放一段基于主图的向后倒地过渡动画,并最终停在翻转倒地姿态
|
||||
- 角色已配置的每个技能,都必须在技能编辑面板里补出对应动作预览
|
||||
- 图生视频默认走火山方舟 `Seedance` 首尾帧方案
|
||||
- 接口请求体中的两张参考图分别固定为 `first_frame / last_frame`
|
||||
- 固定参数为 `1:1`、`480p`、`4 秒`、单次 `1` 个视频
|
||||
- 提示词中的动作名统一传英文动作名
|
||||
|
||||
第一版动作生成按下面两层规则落地:
|
||||
|
||||
| 类别 | 动作槽位 | 是否必填 | 备注 |
|
||||
| -------- | ------------------------------- | -------- | -------------------------------------------------- |
|
||||
| 基础动作 | `run` | 必填 | 角色移动主循环动作 |
|
||||
| 基础动作 | `attack` | 必填 | 角色普通攻击主动作 |
|
||||
| 技能动作 | `skills[*].actionPreviewConfig` | 必填 | 当前角色每个已配置技能都要有独立动作资源 |
|
||||
| 可选动作 | `idle` | 可选 | 缺失时默认走主图静止待机 |
|
||||
| 可选动作 | `die` | 可选 | 缺失时默认走主图向后倒地过渡动画,最终停在翻转倒地姿态 |
|
||||
|
||||
这里“必生成”指的是:
|
||||
|
||||
- `run / attack` 必须最终指向可播放资源
|
||||
- 每个已配置技能都必须带独立 `actionPreviewConfig`
|
||||
- 发布判定不再要求 `idle / die` 一定存在动画映射
|
||||
- 运行时仍然不能出现无可用表现;`idle / die` 的缺口由默认兜底承担
|
||||
|
||||
## 8.2 技能动作要求
|
||||
|
||||
本期不再要求把整套固定技能枚举一次性自动补齐,但对“角色当前实际配置的技能”改为必做:
|
||||
|
||||
- 不要求预先把 `skill1 / skill2 / skill3 / skill4` 这套历史枚举全部补满
|
||||
- 只要求当前角色 `skills` 数组里的每个技能都生成独立动作预览
|
||||
- 技能动作生成入口继续放在技能编辑面板逐个处理,不塞进固定四按钮里
|
||||
|
||||
结论:
|
||||
|
||||
- 技能动作从“固定枚举可选”调整为“按角色已配技能必做”
|
||||
- 固定基础动作收敛为 `run / attack`
|
||||
- `idle / die` 保留为可选增强动作
|
||||
|
||||
## 8.3 动作生成方式
|
||||
|
||||
MVP 支持两种方式:
|
||||
|
||||
1. 模板动作生成
|
||||
- 用户选择动作模板
|
||||
2. 参考视频驱动
|
||||
- 用户上传参考动作视频
|
||||
|
||||
优先级:
|
||||
|
||||
- 基础动作优先走模板
|
||||
- 个性化动作再用参考视频驱动
|
||||
|
||||
## 8.4 动作阶段交互要求
|
||||
|
||||
用户必须可以:
|
||||
|
||||
- 查看每个动作槽位当前状态
|
||||
- 单独预览某个动作
|
||||
- 单独重新生成某个动作
|
||||
- 保留某些已满意动作,只重生其余动作
|
||||
- 在所有基础动作齐全后再发布
|
||||
|
||||
---
|
||||
|
||||
## 9. 生成策略约束
|
||||
|
||||
## 9.1 角色一致性优先
|
||||
|
||||
动作生成阶段只能使用已锁定的主形象,不允许每个动作重新随机生成角色外观。
|
||||
|
||||
## 9.2 首尾帧控制
|
||||
|
||||
参考用户提供的视频方向,MVP 固化以下策略:
|
||||
|
||||
### 循环动作
|
||||
|
||||
- `idle`
|
||||
- `run`
|
||||
|
||||
要求首尾姿态尽量接近,便于循环。
|
||||
|
||||
### 一次性动作
|
||||
|
||||
- `attack`
|
||||
- `jump_attack`
|
||||
- `die`
|
||||
|
||||
要求末帧清晰,不与下一动作切换冲突。
|
||||
|
||||
## 9.3 高分辨率生成,低分辨率落地
|
||||
|
||||
MVP 不要求模型直接输出最终像素逐帧。
|
||||
|
||||
正确流程是:
|
||||
|
||||
1. 生成较稳定的高分辨率动作视频
|
||||
2. 本地解帧、对齐、清理
|
||||
3. 再转成当前项目可用的像素化资产
|
||||
|
||||
---
|
||||
|
||||
## 10. 技术方案边界
|
||||
|
||||
## 10.1 模型选择
|
||||
|
||||
MVP 统一采用国内可用的阿里云百炼方案:
|
||||
|
||||
- 主形象生成:`wan2.7-image-pro` / `wan2.7-image`
|
||||
- 动作生成:`wan2.2-animate-move`
|
||||
- 高质量换角动作:`wan2.2-animate-mix`
|
||||
|
||||
选择理由:
|
||||
|
||||
1. 国内可用
|
||||
2. 图像和动作链路在同一平台
|
||||
3. 便于 MVP 先收敛到单平台实现
|
||||
|
||||
## 10.2 本地后处理
|
||||
|
||||
MVP 必须包含本地后处理:
|
||||
|
||||
1. 解帧
|
||||
2. 主体裁切
|
||||
3. 背景清理
|
||||
4. 稳帧
|
||||
5. 像素化
|
||||
6. 打包 Sprite Sheet
|
||||
7. 输出 manifest
|
||||
|
||||
## 10.3 运行时边界
|
||||
|
||||
运行时不直接请求第三方模型接口。
|
||||
|
||||
运行时只读取:
|
||||
|
||||
- 主形象标准资源
|
||||
- 动画标准资源
|
||||
- override / manifest 配置
|
||||
|
||||
---
|
||||
|
||||
## 11. MVP 数据与接口
|
||||
|
||||
## 11.1 角色主形象资源
|
||||
|
||||
建议最小结构:
|
||||
|
||||
```ts
|
||||
type GeneratedCharacterVisualAsset = {
|
||||
id: string;
|
||||
characterId: string;
|
||||
sourceMode: 'text-to-image' | 'image-to-image' | 'upload';
|
||||
masterImagePath: string;
|
||||
previewImagePaths: string[];
|
||||
width: number;
|
||||
height: number;
|
||||
facing: 'right';
|
||||
locked: boolean;
|
||||
};
|
||||
```
|
||||
|
||||
## 11.2 角色动画资源
|
||||
|
||||
```ts
|
||||
type GeneratedCharacterAnimationAsset = {
|
||||
id: string;
|
||||
characterId: string;
|
||||
visualAssetId: string;
|
||||
action: string;
|
||||
frameCount: number;
|
||||
fps: number;
|
||||
loop: boolean;
|
||||
spriteSheetPath: string;
|
||||
framePaths: string[];
|
||||
previewVideoPath: string;
|
||||
};
|
||||
```
|
||||
|
||||
## 11.3 最小接口
|
||||
|
||||
建议新增:
|
||||
|
||||
- `POST /api/character-visual/jobs`
|
||||
- `GET /api/character-visual/jobs/:id`
|
||||
- `POST /api/character-visual/publish`
|
||||
- `POST /api/animation/jobs`
|
||||
- `GET /api/animation/jobs/:id`
|
||||
- `GET /api/animation/templates`
|
||||
- `POST /api/animation/publish`
|
||||
|
||||
职责:
|
||||
|
||||
### `POST /api/character-visual/jobs`
|
||||
|
||||
- 创建主形象生成或规范化任务
|
||||
|
||||
### `GET /api/character-visual/jobs/:id`
|
||||
|
||||
- 查询主形象任务状态与结果
|
||||
|
||||
### `POST /api/character-visual/publish`
|
||||
|
||||
- 锁定主形象并写入主形象 manifest
|
||||
|
||||
### `POST /api/animation/jobs`
|
||||
|
||||
- 创建动作生成任务
|
||||
|
||||
### `GET /api/animation/jobs/:id`
|
||||
|
||||
- 查询动作任务状态与结果
|
||||
|
||||
### `GET /api/animation/templates`
|
||||
|
||||
- 返回动作模板列表
|
||||
|
||||
### `POST /api/animation/publish`
|
||||
|
||||
- 发布动作资源并更新动画映射
|
||||
|
||||
---
|
||||
|
||||
## 12. 与当前仓库的接入点
|
||||
|
||||
第一批建议接入:
|
||||
|
||||
- `src/components/CharacterAnimator.tsx`
|
||||
- `src/types/characters.ts`
|
||||
- `src/data/characterOverrides.json`
|
||||
- `server-node/src/modules/assets/**`
|
||||
|
||||
建议新增:
|
||||
|
||||
- `src/components/CharacterAssetStudio.tsx`
|
||||
- `src/data/characterAnimationOverrides.json`
|
||||
- 角色主形象 manifest 读取逻辑
|
||||
- 动画 manifest 读取逻辑
|
||||
|
||||
运行时优先级建议:
|
||||
|
||||
1. 角色 AI 生成动画 override
|
||||
2. 角色原始 `animationMap`
|
||||
3. 默认回退动画
|
||||
|
||||
---
|
||||
|
||||
## 13. 验收标准
|
||||
|
||||
## 13.1 主形象验收
|
||||
|
||||
1. 用户可以通过文生图 / 图生图 / 直接上传素材三种方式得到主形象
|
||||
2. 主形象视角符合当前项目侧视角色素材要求
|
||||
3. 主形象可预览、可重新生成、可锁定
|
||||
|
||||
## 13.2 动作验收
|
||||
|
||||
1. 所有基础动作槽位均有有效资源
|
||||
2. 用户可以单独预览和重新生成某个动作
|
||||
3. 发布后动作能被当前 `CharacterAnimator` 播放
|
||||
|
||||
## 13.3 资产验收
|
||||
|
||||
1. 发布后可生成主形象资源目录
|
||||
2. 发布后可生成动画资源目录
|
||||
3. 可生成对应 manifest / override 映射
|
||||
|
||||
## 13.4 体验验收
|
||||
|
||||
1. 用户不需要手工整理最终资源目录
|
||||
2. 用户不需要每次都从头重做全部动作
|
||||
3. 主形象和动作两阶段都可回看和重生
|
||||
|
||||
---
|
||||
|
||||
## 14. 风险与对策
|
||||
|
||||
## 14.1 风险:主形象视角不稳定
|
||||
|
||||
对策:
|
||||
|
||||
- 把“侧视、朝右、全身、脚底完整”作为硬校验
|
||||
- 不合格结果不允许直接进入动作阶段
|
||||
|
||||
## 14.2 风险:动作循环不自然
|
||||
|
||||
对策:
|
||||
|
||||
- `idle`、`run` 强制使用循环模板优先
|
||||
- 引入首尾帧接近度校验
|
||||
|
||||
## 14.3 风险:基础动作槽位过多,MVP 开发压力大
|
||||
|
||||
对策:
|
||||
|
||||
- 允许 `acquire`、`double_jump`、`wall_slide` 等少数槽位由近似动作衍生
|
||||
- 但运行时最终槽位仍必须非空
|
||||
|
||||
## 14.4 风险:生成成本过高
|
||||
|
||||
对策:
|
||||
|
||||
- 先只支持单角色编辑
|
||||
- 基础动作优先模板化
|
||||
- 仅对不满意动作单独重生
|
||||
|
||||
---
|
||||
|
||||
## 15. MVP 开发顺序
|
||||
|
||||
## 阶段 1:主形象闭环
|
||||
|
||||
目标:
|
||||
|
||||
- 跑通主形象生成 / 上传 / 预览 / 锁定
|
||||
|
||||
产出:
|
||||
|
||||
- `CharacterAssetStudio` 的主形象页
|
||||
- 主形象任务 API
|
||||
- 主形象 manifest
|
||||
|
||||
## 阶段 2:基础动作闭环
|
||||
|
||||
目标:
|
||||
|
||||
- 跑通单动作生成、预览与替换
|
||||
|
||||
产出:
|
||||
|
||||
- 动作任务 API
|
||||
- 动作模板列表
|
||||
- 预览与重新生成流程
|
||||
|
||||
## 阶段 3:基础动作补齐与发布
|
||||
|
||||
目标:
|
||||
|
||||
- 让必生成动作全部就绪,并为 `idle / die` 提供明确默认兜底
|
||||
|
||||
产出:
|
||||
|
||||
- 动作状态面板
|
||||
- 发布逻辑
|
||||
- override / manifest 写入
|
||||
|
||||
## 阶段 4:运行时接入
|
||||
|
||||
目标:
|
||||
|
||||
- 让发布后的角色直接在现有运行时播放
|
||||
|
||||
产出:
|
||||
|
||||
- `CharacterAnimator` 读取生成动画能力
|
||||
- 角色 override 映射接入
|
||||
|
||||
---
|
||||
|
||||
## 16. 最终结论
|
||||
|
||||
对当前仓库来说,最可落地的 MVP 不是“先做一个很强的 AI 动画系统”,而是:
|
||||
|
||||
1. 先固定角色主形象生产流程
|
||||
2. 再固定基础动作生产流程
|
||||
3. 只补能进当前项目运行时的最小动作集
|
||||
4. 把预览、重新生成和发布做完整
|
||||
|
||||
这样做的价值在于:
|
||||
|
||||
- 范围可控
|
||||
- 路径清晰
|
||||
- 能真正进入当前仓库
|
||||
- 后续可以在此基础上再加技能动作、剧情演出和多供应商增强路线
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,796 @@
|
||||
# AI 原生 Agent-First 自定义世界创作工具第二阶段技术落地方案
|
||||
|
||||
更新时间:`2026-04-13`
|
||||
|
||||
## 0.1 当前状态说明(2026-04-21)
|
||||
|
||||
这份文档保留为第二阶段历史落地方案。
|
||||
|
||||
补充边界:
|
||||
|
||||
1. 文中提到的 `CustomWorldAgentIntentSummaryPanel`、`CustomWorldAgentClarificationPanel`、`CustomWorldAgentLockBar`、`CustomWorldAgentQuickActions` 等旧副面板,已经在当前版本收口判断中退出主链并物理删除
|
||||
2. 这些内容现在只能作为历史设计参考,不再作为当前版本默认待接线项
|
||||
3. 当前如果要重新设计这些能力的消费方式,应基于现行主链重新定义
|
||||
## 0. 文档目的
|
||||
|
||||
这份文档用于把以下两份文档进一步收束成第二阶段实现方案:
|
||||
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md)
|
||||
|
||||
如果说第一阶段的目标是:
|
||||
|
||||
**先把创作页面和 Agent 工作区的外壳搭起来**
|
||||
|
||||
那么第二阶段的目标就是:
|
||||
|
||||
**让 Agent 会话真正开始理解创作者输入,并把自然语言聊天沉淀成结构化创作锚点。**
|
||||
|
||||
一句话定义:
|
||||
|
||||
**第二阶段先把“收集最小锚点、追问缺口、更新创作意图、同步草稿摘要”这条主链打通,而不是先急着生成完整世界。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 阶段衔接关系
|
||||
|
||||
## 1.1 第一阶段已经完成什么
|
||||
|
||||
第二阶段默认建立在第一阶段已经完成的能力之上:
|
||||
|
||||
1. 从世界选择页可以进入创作页面
|
||||
2. 创作页面可以展示草稿和已发布作品
|
||||
3. 新建作品可以创建 Agent session
|
||||
4. 可以进入 Agent 工作区
|
||||
5. 用户发送消息后,服务端会写入 user / assistant 消息
|
||||
6. session snapshot 和 operation 可以持久化与恢复
|
||||
|
||||
## 1.2 第二阶段不再重做什么
|
||||
|
||||
以下内容第二阶段不重做:
|
||||
|
||||
1. 不重做创作页面整体布局
|
||||
2. 不重做 session 基础持久化
|
||||
3. 不重做 operation 轮询主链
|
||||
4. 不重做 workspace 基础壳层
|
||||
|
||||
第二阶段只在第一阶段骨架上继续补:
|
||||
|
||||
1. 意图提取
|
||||
2. 最小锚点判断
|
||||
3. 澄清问题生成
|
||||
4. `creatorIntent` 持续更新
|
||||
5. 创作页面草稿摘要变得更像“作品”
|
||||
|
||||
---
|
||||
|
||||
## 2. 第二阶段在八阶段中的位置
|
||||
|
||||
八阶段拆分如下:
|
||||
|
||||
1. 阶段 1:创作页面入口、Agent 会话主链与工作区骨架
|
||||
2. 阶段 2:最小锚点收集与澄清流程
|
||||
3. 阶段 3:世界底稿生成与草稿卡编译
|
||||
4. 阶段 4:草稿设定编辑与 AI 新增角色/场景生成
|
||||
5. 阶段 5:角色主图与动作资产工坊接入
|
||||
6. 阶段 6:场景背景图工坊接入
|
||||
7. 阶段 7:长尾内容扩展与自动补齐
|
||||
8. 阶段 8:发布、世界库接入与继续创作恢复
|
||||
|
||||
本文件只覆盖:
|
||||
|
||||
**阶段 2:最小锚点收集与澄清流程**
|
||||
|
||||
---
|
||||
|
||||
## 3. 第二阶段目标
|
||||
|
||||
第二阶段只做 6 件必须一起成立的事:
|
||||
|
||||
1. 把用户自然语言输入持续抽取为结构化 `creatorIntent`
|
||||
2. 明确最小锚点是否齐备
|
||||
3. 当锚点不足时,生成 `1~3` 个高杠杆澄清问题
|
||||
4. 在 Agent 工作区中展示“已收集锚点摘要”和“待补充问题”
|
||||
5. 把 `creatorIntent` 的变化同步反映到创作页面草稿卡片摘要里
|
||||
6. 当最小锚点齐备时,把 session 阶段推进到 `foundation_review`
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让第二阶段结束时,Agent 不再只是会回话,而是真正开始把“聊天内容”沉淀成“世界锚点”。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 第二阶段完成定义
|
||||
|
||||
第二阶段完成后,必须同时满足以下结果:
|
||||
|
||||
1. 用户连续输入多轮自然语言后,`creatorIntent` 会被持续更新。
|
||||
2. `creatorIntent` 中至少这些字段会真实变化:
|
||||
- `worldHook`
|
||||
- `themeKeywords`
|
||||
- `toneDirectives`
|
||||
- `playerPremise`
|
||||
- `openingSituation`
|
||||
- `coreConflicts`
|
||||
- `keyCharacters`
|
||||
- `iconicElements`
|
||||
- `forbiddenDirectives`
|
||||
3. 当最小锚点不完整时,workspace 右侧会显示待澄清问题。
|
||||
4. Agent 的回复不再只做“复述”,而会围绕缺失锚点主动追问。
|
||||
5. 当最小锚点齐备时,session 会进入 `foundation_review`,并明确告知“已可以进入下一阶段生成世界底稿”。
|
||||
6. 创作页面里的草稿作品标题和摘要会随着 `creatorIntent` 更新而变得更准确,不再只是空壳草稿。
|
||||
7. 第二阶段仍然不要求真正生成世界底稿,也不要求编出角色卡和地点卡。
|
||||
|
||||
---
|
||||
|
||||
## 5. 范围控制
|
||||
|
||||
## 5.1 第二阶段纳入范围
|
||||
|
||||
纳入范围的模块:
|
||||
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- `src/services/customWorldCreatorIntent.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
- `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
- `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
- `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
|
||||
新增前端模块:
|
||||
|
||||
- `src/components/custom-world-agent/CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentClarificationPanel.tsx`
|
||||
|
||||
新增服务端模块:
|
||||
|
||||
- `server-node/src/services/customWorldAgentIntentExtractionService.ts`
|
||||
- `server-node/src/services/customWorldAgentClarificationService.ts`
|
||||
|
||||
## 5.2 第二阶段明确不做
|
||||
|
||||
以下内容不放进第二阶段:
|
||||
|
||||
1. 不生成世界底稿
|
||||
2. 不生成 draftCards
|
||||
3. 不进入角色、地点、势力、章节的实体卡编译
|
||||
4. 不做锁定逻辑
|
||||
5. 不做角色资产工坊
|
||||
6. 不做场景图工坊
|
||||
7. 不做长尾扩展
|
||||
8. 不做发布
|
||||
|
||||
原因:
|
||||
|
||||
**第二阶段的唯一重点,是把 Agent 会话从“能聊”推进到“能收集创作锚点”。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 第二阶段最小闭环
|
||||
|
||||
建议把第二阶段的最小闭环定义为:
|
||||
|
||||
```text
|
||||
创作页面新建作品
|
||||
-> 进入 Agent 工作区
|
||||
-> 用户输入世界想法
|
||||
-> 服务端提取 creatorIntent patch
|
||||
-> 更新 creatorIntent / anchorPack / pendingClarifications
|
||||
-> Agent 回复补问或确认
|
||||
-> 前端展示已收集锚点摘要
|
||||
-> 用户继续补充
|
||||
-> 最小锚点齐备
|
||||
-> session 进入 foundation_review
|
||||
-> 创作页面草稿摘要同步更新
|
||||
```
|
||||
|
||||
这个闭环里,先只强接两条高价值链路:
|
||||
|
||||
1. 对话 -> creatorIntent
|
||||
2. creatorIntent -> 草稿摘要
|
||||
|
||||
---
|
||||
|
||||
## 7. 第二阶段产品行为定义
|
||||
|
||||
## 7.1 最小锚点定义
|
||||
|
||||
第二阶段必须明确判定“最小锚点是否齐备”。
|
||||
|
||||
建议统一收束成以下 6 组:
|
||||
|
||||
1. 世界一句话与核心幻想
|
||||
- 对应:`worldHook`
|
||||
|
||||
2. 玩家身份与开局困境
|
||||
- 对应:`playerPremise + openingSituation`
|
||||
|
||||
3. 主题气质与禁忌边界
|
||||
- 对应:`themeKeywords + toneDirectives + forbiddenDirectives`
|
||||
|
||||
4. 核心冲突
|
||||
- 对应:`coreConflicts`
|
||||
|
||||
5. 关键关系钩子
|
||||
- 对应:`keyCharacters`
|
||||
- 最低要求:至少有 1 个关键人物种子,且带 `relationToPlayer` 或 `hiddenHook`
|
||||
|
||||
6. 标志性要素
|
||||
- 对应:`iconicElements`
|
||||
|
||||
## 7.2 最小锚点齐备规则
|
||||
|
||||
建议使用 deterministic 规则判断:
|
||||
|
||||
```ts
|
||||
type CreatorIntentReadiness = {
|
||||
isReady: boolean;
|
||||
completedKeys: string[];
|
||||
missingKeys: string[];
|
||||
};
|
||||
```
|
||||
|
||||
### 判定要求
|
||||
|
||||
#### `world_hook`
|
||||
|
||||
满足任一条件即视为完成:
|
||||
|
||||
1. `worldHook.trim().length >= 8`
|
||||
2. `rawSettingText.trim().length >= 24` 且可提取稳定世界命题
|
||||
|
||||
#### `player_premise`
|
||||
|
||||
必须:
|
||||
|
||||
1. `playerPremise` 非空
|
||||
2. `openingSituation` 非空
|
||||
|
||||
#### `theme_and_tone`
|
||||
|
||||
满足:
|
||||
|
||||
1. `themeKeywords.length >= 1`
|
||||
2. `toneDirectives.length >= 1`
|
||||
|
||||
`forbiddenDirectives` 可选,但一旦用户明确提到禁忌,必须写入
|
||||
|
||||
#### `core_conflict`
|
||||
|
||||
满足:
|
||||
|
||||
1. `coreConflicts.length >= 1`
|
||||
|
||||
#### `relationship_seed`
|
||||
|
||||
满足:
|
||||
|
||||
1. `keyCharacters.length >= 1`
|
||||
2. 至少一个条目同时满足:
|
||||
- `name` 非空
|
||||
- 且 `relationToPlayer` 或 `hiddenHook` 非空
|
||||
|
||||
#### `iconic_element`
|
||||
|
||||
满足:
|
||||
|
||||
1. `iconicElements.length >= 1`
|
||||
|
||||
## 7.3 缺口澄清规则
|
||||
|
||||
当 `isReady === false` 时,Agent 必须追问,但必须遵守:
|
||||
|
||||
1. 一次最多追问 `3` 个问题
|
||||
2. 问题必须优先覆盖最高杠杆缺口
|
||||
3. 问题不能像问卷
|
||||
4. 每个问题最好给一个方向提示
|
||||
|
||||
### 优先级顺序
|
||||
|
||||
1. `world_hook`
|
||||
2. `player_premise`
|
||||
3. `core_conflict`
|
||||
4. `theme_and_tone`
|
||||
5. `relationship_seed`
|
||||
6. `iconic_element`
|
||||
|
||||
## 7.4 阶段推进规则
|
||||
|
||||
### 初始
|
||||
|
||||
- `collecting_intent`
|
||||
|
||||
### 缺口存在
|
||||
|
||||
- `clarifying`
|
||||
|
||||
### 最小锚点齐备
|
||||
|
||||
- `foundation_review`
|
||||
|
||||
### 说明
|
||||
|
||||
第二阶段进入 `foundation_review` 后,不代表已经生成底稿;
|
||||
只代表:
|
||||
|
||||
**已经具备进入第三阶段生成世界底稿的输入条件。**
|
||||
|
||||
## 7.5 Agent 回复行为
|
||||
|
||||
第二阶段起,assistant 回复必须升级成 3 段结构:
|
||||
|
||||
1. 已确认内容
|
||||
2. 仍缺内容
|
||||
3. 下一步提问或建议
|
||||
|
||||
### 示例结构
|
||||
|
||||
```text
|
||||
我先把目前已经明确的部分收一下:
|
||||
- ...
|
||||
|
||||
现在还缺两块最关键的信息:
|
||||
- ...
|
||||
- ...
|
||||
|
||||
你可以先告诉我:
|
||||
1. ...
|
||||
2. ...
|
||||
```
|
||||
|
||||
禁止:
|
||||
|
||||
1. 只说“收到”
|
||||
2. 一次问超过 3 个问题
|
||||
3. 明知缺世界核心还继续追问长尾细节
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据结构落地方案
|
||||
|
||||
## 8.1 修改 `CustomWorldCreatorIntent`
|
||||
|
||||
继续复用 `src/services/customWorldCreatorIntent.ts` 的现有结构,不新增第二套意图对象。
|
||||
|
||||
第二阶段要求:
|
||||
|
||||
1. 所有字段都支持增量 patch
|
||||
2. patch 合并必须是“补充 + 覆盖用户明确改写”
|
||||
3. 不允许每次新消息都重置整个 intent
|
||||
|
||||
## 8.2 新增 `CreatorIntentReadiness`
|
||||
|
||||
建议新增到:
|
||||
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
|
||||
```ts
|
||||
export interface CreatorIntentReadiness {
|
||||
isReady: boolean;
|
||||
completedKeys: string[];
|
||||
missingKeys: string[];
|
||||
}
|
||||
```
|
||||
|
||||
## 8.3 扩展 `pendingClarifications`
|
||||
|
||||
当前第一阶段里的澄清结构太轻,第二阶段要扩成:
|
||||
|
||||
```ts
|
||||
export interface CustomWorldPendingClarification {
|
||||
id: string;
|
||||
label: string;
|
||||
question: string;
|
||||
targetKey:
|
||||
| 'world_hook'
|
||||
| 'player_premise'
|
||||
| 'theme_and_tone'
|
||||
| 'core_conflict'
|
||||
| 'relationship_seed'
|
||||
| 'iconic_element';
|
||||
priority: number;
|
||||
answer?: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 8.4 扩展 `CustomWorldAgentSessionSnapshot`
|
||||
|
||||
第二阶段必须新增:
|
||||
|
||||
```ts
|
||||
creatorIntentReadiness: CreatorIntentReadiness;
|
||||
```
|
||||
|
||||
并把:
|
||||
|
||||
```ts
|
||||
pendingClarifications: CustomWorldPendingClarification[];
|
||||
```
|
||||
|
||||
替换掉第一阶段的轻量问题数组。
|
||||
|
||||
## 8.5 扩展 `CustomWorldWorkSummary`
|
||||
|
||||
为了让创作页面草稿卡更像一个“作品”,第二阶段必须要求草稿摘要从 `creatorIntent` 实时编译。
|
||||
|
||||
规则:
|
||||
|
||||
### 标题
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `creatorIntent.worldHook`
|
||||
2. `rawSettingText` 截断
|
||||
3. `未命名草稿`
|
||||
|
||||
### 摘要
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `buildCustomWorldCreatorIntentDisplayText(intent)`
|
||||
2. `rawSettingText` 截断
|
||||
3. 默认空态文案
|
||||
|
||||
### 阶段文案
|
||||
|
||||
按 session.stage 直接映射。
|
||||
|
||||
---
|
||||
|
||||
## 9. 服务端实现方案
|
||||
|
||||
## 9.1 新增 `customWorldAgentIntentExtractionService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentIntentExtractionService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
输入:
|
||||
|
||||
1. 当前 `creatorIntent`
|
||||
2. 最新用户消息
|
||||
3. 最近若干轮对话摘要
|
||||
|
||||
输出:
|
||||
|
||||
```ts
|
||||
type ExtractedCreatorIntentPatch = {
|
||||
worldHook?: string;
|
||||
themeKeywords?: string[];
|
||||
toneDirectives?: string[];
|
||||
playerPremise?: string;
|
||||
openingSituation?: string;
|
||||
coreConflicts?: string[];
|
||||
keyCharacters?: CreatorCharacterSeed[];
|
||||
iconicElements?: string[];
|
||||
forbiddenDirectives?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
### 推荐实现策略
|
||||
|
||||
第一优先:
|
||||
|
||||
1. 使用 deterministic 规则提取明显字段
|
||||
|
||||
第二优先:
|
||||
|
||||
2. 用一个轻量 LLM contract 只提取 patch,不生成世界内容
|
||||
|
||||
### 第一阶段之外、第二阶段之内的硬要求
|
||||
|
||||
这一步的 LLM 输出必须只做“结构提取”,不能夹带世界扩写。
|
||||
|
||||
## 9.2 新增 `customWorldAgentClarificationService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentClarificationService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
1. 根据 `creatorIntent` 计算 readiness
|
||||
2. 生成 `pendingClarifications`
|
||||
3. 按优先级裁剪到 `1~3` 个问题
|
||||
|
||||
### 导出函数建议
|
||||
|
||||
```ts
|
||||
evaluateCreatorIntentReadiness(intent)
|
||||
buildPendingClarifications(intent, readiness)
|
||||
```
|
||||
|
||||
## 9.3 修改 `customWorldAgentOrchestrator.ts`
|
||||
|
||||
第二阶段它要从“写消息 + 回固定话术”升级为:
|
||||
|
||||
1. 写入 user message
|
||||
2. 提取 intent patch
|
||||
3. 合并 intent
|
||||
4. 更新 anchorPack
|
||||
5. 计算 readiness
|
||||
6. 生成 clarifications
|
||||
7. 生成更结构化的 assistant 回复
|
||||
8. 更新 snapshot
|
||||
|
||||
### 关键顺序
|
||||
|
||||
必须严格按下面顺序:
|
||||
|
||||
```text
|
||||
收到用户消息
|
||||
-> 提取 intent patch
|
||||
-> merge creatorIntent
|
||||
-> build anchorPack
|
||||
-> evaluate readiness
|
||||
-> build pendingClarifications
|
||||
-> compose assistant reply
|
||||
-> 写回 snapshot
|
||||
```
|
||||
|
||||
### 第一阶段兼容要求
|
||||
|
||||
如果提取失败:
|
||||
|
||||
1. 不允许清空原有 intent
|
||||
2. assistant 仍要给出可继续的澄清回复
|
||||
|
||||
## 9.4 修改 `customWorldWorkSummaryService.ts`
|
||||
|
||||
第二阶段它必须从 session 中读取:
|
||||
|
||||
1. `creatorIntent`
|
||||
2. `creatorIntentReadiness`
|
||||
3. `stage`
|
||||
|
||||
并生成更准确的:
|
||||
|
||||
1. 草稿标题
|
||||
2. 草稿摘要
|
||||
3. 当前阶段标签
|
||||
|
||||
---
|
||||
|
||||
## 10. 前端实现方案
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
这一节描述的是第二阶段编写当时的右侧副面板方案。
|
||||
|
||||
但当前版本已经明确:
|
||||
|
||||
1. `CustomWorldAgentIntentSummaryPanel`
|
||||
2. `CustomWorldAgentClarificationPanel`
|
||||
3. `CustomWorldAgentLockBar`
|
||||
4. `CustomWorldAgentQuickActions`
|
||||
|
||||
这组旧副面板不再作为当前版本默认待接线方向,其中对应已落地但退出主链的文件也已物理删除。
|
||||
|
||||
因此本节以下内容应视为历史设计稿,不再直接代表当前版本执行方案。
|
||||
|
||||
## 10.1 修改 `CustomWorldAgentWorkspace.tsx`
|
||||
|
||||
第二阶段它不再只是空壳工作区,而要新增:
|
||||
|
||||
1. 意图摘要区
|
||||
2. 澄清问题区
|
||||
|
||||
### 右侧结构建议
|
||||
|
||||
1. `CustomWorldAgentIntentSummaryPanel`
|
||||
2. `CustomWorldAgentClarificationPanel`
|
||||
3. `CustomWorldAgentLockBar`
|
||||
4. `CustomWorldAgentDraftDrawer`
|
||||
5. `CustomWorldAgentQuickActions`
|
||||
|
||||
说明:
|
||||
|
||||
第二阶段虽然还没有真正 `draftCards`,但壳层继续保留。
|
||||
|
||||
## 10.2 新增 `CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
|
||||
### 职责
|
||||
|
||||
展示当前已收集的最小锚点摘要。
|
||||
|
||||
### 展示项
|
||||
|
||||
1. 世界一句话
|
||||
2. 玩家身份
|
||||
3. 开局处境
|
||||
4. 核心冲突
|
||||
5. 主题气质
|
||||
6. 标志性要素
|
||||
|
||||
### 空态
|
||||
|
||||
未收集到时显示:
|
||||
|
||||
- `还在收集你的世界锚点`
|
||||
|
||||
## 10.3 新增 `CustomWorldAgentClarificationPanel.tsx`
|
||||
|
||||
### 职责
|
||||
|
||||
展示当前 `pendingClarifications`
|
||||
|
||||
### 展示规则
|
||||
|
||||
1. 每个问题显示 label + question
|
||||
2. 最多展示 3 个
|
||||
3. 若 `isReady === true`,显示:
|
||||
- `最小锚点已齐备,可以进入下一阶段`
|
||||
|
||||
## 10.4 修改 `CustomWorldCreationHub.tsx`
|
||||
|
||||
第二阶段必须让草稿卡开始体现“已收集锚点”的变化。
|
||||
|
||||
要求:
|
||||
|
||||
1. 草稿卡标题和摘要来自统一 `CustomWorldWorkSummary`
|
||||
2. 列表刷新后可以看到标题变化
|
||||
3. 草稿从“未命名草稿”变成更接近创作主题的标题
|
||||
|
||||
## 10.5 修改 `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
第二阶段只保留轻动作:
|
||||
|
||||
1. `总结当前设定`
|
||||
2. `继续补充锚点`
|
||||
|
||||
不允许展示:
|
||||
|
||||
1. `生成世界底稿`
|
||||
2. `发布世界`
|
||||
|
||||
因为这属于后续阶段。
|
||||
|
||||
---
|
||||
|
||||
## 11. 交互时序
|
||||
|
||||
## 11.1 用户补充锚点
|
||||
|
||||
```text
|
||||
用户发消息
|
||||
-> 前端 POST /messages
|
||||
-> 后端提取 creatorIntent patch
|
||||
-> 更新 creatorIntent
|
||||
-> 更新 readiness 和 pendingClarifications
|
||||
-> 写入 assistant 回复
|
||||
-> 前端刷新 snapshot
|
||||
-> 前端刷新意图摘要和澄清问题
|
||||
```
|
||||
|
||||
## 11.2 锚点齐备
|
||||
|
||||
```text
|
||||
用户最后一轮补齐关键锚点
|
||||
-> 后端 evaluate readiness = true
|
||||
-> session.stage 切到 foundation_review
|
||||
-> assistant 回复“已可进入下一阶段”
|
||||
-> 前端显示完成态
|
||||
-> 创作页面草稿摘要同步更新
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 第一阶段到第二阶段的兼容要求
|
||||
|
||||
第二阶段必须兼容第一阶段已有数据。
|
||||
|
||||
## 12.1 旧 session 兼容
|
||||
|
||||
如果存在第一阶段创建的 session,没有:
|
||||
|
||||
1. `creatorIntentReadiness`
|
||||
2. 新版 `pendingClarifications`
|
||||
|
||||
则读取时要自动补 fallback。
|
||||
|
||||
## 12.2 旧草稿兼容
|
||||
|
||||
如果草稿还没有明确 `worldHook`:
|
||||
|
||||
1. 继续显示 `未命名草稿`
|
||||
2. 不允许报错
|
||||
|
||||
---
|
||||
|
||||
## 13. 落地文件清单
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
本节列的是第二阶段历史文件清单。
|
||||
|
||||
其中涉及旧副面板的部分,现在只保留历史参考价值,不再等同于当前版本待落地项。
|
||||
|
||||
## 13.1 shared
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
|
||||
## 13.2 frontend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldAgentClarificationPanel.tsx`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
4. `src/services/aiService.ts`
|
||||
5. `src/services/customWorldCreatorIntent.ts`
|
||||
|
||||
## 13.3 backend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentIntentExtractionService.ts`
|
||||
2. `server-node/src/services/customWorldAgentClarificationService.ts`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
2. `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
3. `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
|
||||
---
|
||||
|
||||
## 14. 测试要求
|
||||
|
||||
## 14.1 服务端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. 用户消息能提取到 `creatorIntent` patch
|
||||
2. patch 合并不会覆盖无关旧字段
|
||||
3. readiness 能正确判断缺失项
|
||||
4. clarifications 最多只返回 3 个
|
||||
5. readiness 达标后 stage 会切到 `foundation_review`
|
||||
|
||||
## 14.2 前端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. intent summary panel 能展示已收集锚点
|
||||
2. clarification panel 能展示待补充问题
|
||||
3. readiness 达标后显示完成态
|
||||
4. 创作页面草稿卡能随着摘要变化更新
|
||||
|
||||
## 14.3 手工回归
|
||||
|
||||
至少走这 4 条:
|
||||
|
||||
1. 用户输入一段简单世界想法 -> 被正确提取为 worldHook
|
||||
2. 用户补充“玩家是谁” -> summary 更新
|
||||
3. 用户补充核心冲突 -> clarification 继续减少
|
||||
4. 锚点齐备 -> session 进入 foundation_review
|
||||
|
||||
---
|
||||
|
||||
## 15. 第二阶段验收标准
|
||||
|
||||
做到以下几点,才算第二阶段真正完成:
|
||||
|
||||
1. Agent 会话已经可以持续收集并更新 `creatorIntent`。
|
||||
2. 最小锚点不足时,系统会追问真正缺失的高杠杆问题。
|
||||
3. 最小锚点齐备时,session 会进入 `foundation_review`。
|
||||
4. 创作页面中的草稿摘要会明显变得更像一个作品,而不是空壳 session。
|
||||
5. 第二阶段仍然不生成世界底稿,不越权进入第三阶段。
|
||||
|
||||
---
|
||||
|
||||
## 16. 一句话结论
|
||||
|
||||
第二阶段最重要的不是“让 Agent 写得更长”,而是:
|
||||
|
||||
**先让它学会把用户说过的话,稳定地变成创作锚点。**
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,987 @@
|
||||
# AI 原生 Agent-First 自定义世界创作工具第四阶段技术落地方案
|
||||
|
||||
更新时间:`2026-04-14`
|
||||
|
||||
## 0.1 当前状态说明(2026-04-21)
|
||||
|
||||
这份文档保留为第四阶段历史落地方案。
|
||||
|
||||
补充边界:
|
||||
|
||||
1. 文中聚焦的草稿详情编辑链与实体生成弹窗链,在当前版本收口判断中已经退出主链
|
||||
2. 对应的 `CustomWorldAgentDraftDetailPanel`、`CustomWorldDraftEditPanel`、`CustomWorldGenerateEntityModal`、`CustomWorldAgentQuickActions` 等文件已物理删除
|
||||
3. 当前版本不再把这套旧副面板链作为默认待接线方向
|
||||
## 0. 文档目的
|
||||
|
||||
这份文档用于把以下几份文档进一步收束成第四阶段实现方案:
|
||||
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE2_IMPLEMENTATION_PLAN_2026-04-13.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE2_IMPLEMENTATION_PLAN_2026-04-13.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md)
|
||||
|
||||
如果说第三阶段的目标是:
|
||||
|
||||
**把已经收集好的创作锚点编译成第一版世界底稿**
|
||||
|
||||
那么第四阶段的目标就是:
|
||||
|
||||
**让创作者直接修改这版草稿设定,并且继续用 AI 为这版草稿扩出新的角色和场景。**
|
||||
|
||||
一句话定义:
|
||||
|
||||
**第四阶段把“世界已经长出来”升级成“世界开始可编辑、可继续长新内容”。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 阶段衔接关系
|
||||
|
||||
## 1.1 第三阶段已经完成什么
|
||||
|
||||
第四阶段默认建立在第三阶段已经完成的能力之上:
|
||||
|
||||
1. session 已进入 `object_refining`
|
||||
2. `draftProfile` 已经非空
|
||||
3. `draftCards` 已经非空
|
||||
4. 工作区可以展示世界、势力、角色、地点、线程和第一幕卡片
|
||||
5. 用户可以查看卡片详情
|
||||
6. 创作页面草稿卡已经能显示更像作品的标题、摘要与对象数量
|
||||
|
||||
## 1.2 第四阶段不再重做什么
|
||||
|
||||
以下内容第四阶段不重做:
|
||||
|
||||
1. 不重做最小锚点收集
|
||||
2. 不重做 foundation draft 生成主链
|
||||
3. 不重做基础 draftCards 编译
|
||||
4. 不重做创作页面和工作区壳层
|
||||
|
||||
第四阶段只继续补:
|
||||
|
||||
1. 草稿设定编辑
|
||||
2. 编辑后的草稿对象写回
|
||||
3. 新增角色的 AI 生成
|
||||
4. 新增场景的 AI 生成
|
||||
5. 新卡片插入与摘要重编译
|
||||
6. assistant 变更总结与 checkpoint
|
||||
|
||||
---
|
||||
|
||||
## 2. 第四阶段在八阶段中的位置
|
||||
|
||||
八阶段拆分如下:
|
||||
|
||||
1. 阶段 1:创作页面入口、Agent 会话主链与工作区骨架
|
||||
2. 阶段 2:最小锚点收集与澄清流程
|
||||
3. 阶段 3:世界底稿生成与草稿卡编译
|
||||
4. 阶段 4:草稿设定编辑与 AI 新增角色/场景生成
|
||||
5. 阶段 5:角色主图与动作资产工坊接入
|
||||
6. 阶段 6:场景背景图工坊接入
|
||||
7. 阶段 7:长尾内容扩展与自动补齐
|
||||
8. 阶段 8:发布、世界库接入与继续创作恢复
|
||||
|
||||
本文件只覆盖:
|
||||
|
||||
**阶段 4:草稿设定编辑与 AI 新增角色/场景生成**
|
||||
|
||||
---
|
||||
|
||||
## 3. 第四阶段目标
|
||||
|
||||
第四阶段只做 7 件必须一起成立的事:
|
||||
|
||||
1. 用户可以直接修改 draft card 中的可编辑设定字段
|
||||
2. 编辑后的内容会稳定写回 `draftProfile`
|
||||
3. 写回后 `draftCards` 摘要会同步更新
|
||||
4. 用户可以让 AI 新增角色
|
||||
5. 用户可以让 AI 新增场景
|
||||
6. 新生成的角色和场景会插入 `draftProfile` 并出现为新的 `draftCards`
|
||||
7. 每次编辑或新增后,系统都要写入 assistant 变更摘要和 checkpoint
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让第四阶段结束时,创作者第一次能像在真正做作品一样修改草稿、继续长出新对象。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 第四阶段完成定义
|
||||
|
||||
第四阶段完成后,必须同时满足以下结果:
|
||||
|
||||
1. 用户可以在 world / faction / character / landmark / thread / chapter 卡详情中进入编辑模式。
|
||||
2. 用户保存编辑后,`draftProfile` 会真实变化,而不是只改前端显示。
|
||||
3. 保存后,对应 `draftCards` 的标题、副标题、摘要会更新。
|
||||
4. 用户可以通过 AI 生成 `1~3` 个新角色卡。
|
||||
5. 用户可以通过 AI 生成 `1~3` 个新场景卡。
|
||||
6. 新角色卡和新场景卡插入后,draft drawer 能立即看到新增对象。
|
||||
7. 创作页面里的草稿作品卡数量统计会同步增加。
|
||||
8. 第四阶段仍然不要求做视觉资产工坊、长尾扩展和发布。
|
||||
|
||||
---
|
||||
|
||||
## 5. 范围控制
|
||||
|
||||
## 5.1 第四阶段纳入范围
|
||||
|
||||
纳入范围的模块:
|
||||
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
- `src/services/aiService.ts`
|
||||
- `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
- `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
- `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
- `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
|
||||
新增前端模块:
|
||||
|
||||
- `src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
新增服务端模块:
|
||||
|
||||
- `server-node/src/services/customWorldAgentDraftEditService.ts`
|
||||
- `server-node/src/services/customWorldAgentEntityGenerationService.ts`
|
||||
- `server-node/src/services/customWorldAgentChangeSummaryService.ts`
|
||||
|
||||
## 5.2 第四阶段明确不做
|
||||
|
||||
以下内容不放进第四阶段:
|
||||
|
||||
1. 不做锁定
|
||||
2. 不做局部重生成
|
||||
3. 不做角色主图与动作资产工坊接入
|
||||
4. 不做场景图工坊接入
|
||||
5. 不做长尾内容自动补齐
|
||||
6. 不做发布
|
||||
|
||||
原因:
|
||||
|
||||
**第四阶段只解决“这版底稿怎么继续被编辑和扩展”的问题。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 第四阶段最小闭环
|
||||
|
||||
建议把第四阶段的最小闭环定义为:
|
||||
|
||||
```text
|
||||
第三阶段已有 foundation draft
|
||||
-> 用户打开某张角色卡
|
||||
-> 修改角色压力与关系描述
|
||||
-> 保存
|
||||
-> draftProfile 更新
|
||||
-> 对应 draftCard 摘要更新
|
||||
-> 用户点击“新增角色”
|
||||
-> AI 生成 2 个新角色
|
||||
-> draftProfile.storyNpcs 增加
|
||||
-> 新角色卡出现在 drawer
|
||||
-> 创作页面草稿卡数量同步增加
|
||||
```
|
||||
|
||||
这个闭环里,先只强接两条高价值链路:
|
||||
|
||||
1. `draftCard -> draftProfile 编辑`
|
||||
2. `AI 新增对象 -> draftProfile 扩展`
|
||||
|
||||
---
|
||||
|
||||
## 7. 第四阶段产品行为定义
|
||||
|
||||
## 7.1 可编辑的卡片类型
|
||||
|
||||
第四阶段允许直接编辑这些卡片:
|
||||
|
||||
1. `world`
|
||||
2. `faction`
|
||||
3. `character`
|
||||
4. `landmark`
|
||||
5. `thread`
|
||||
6. `chapter`
|
||||
7. `camp`
|
||||
|
||||
## 7.2 编辑模式规则
|
||||
|
||||
第四阶段采用:
|
||||
|
||||
**卡片详情内编辑**
|
||||
|
||||
不采用:
|
||||
|
||||
1. 大型全局表单
|
||||
2. 多卡同时编辑
|
||||
3. 独立复杂后台编辑器
|
||||
|
||||
### 编辑流程
|
||||
|
||||
```text
|
||||
打开卡片详情
|
||||
-> 点击“编辑设定”
|
||||
-> 进入编辑模式
|
||||
-> 修改字段
|
||||
-> 点击保存
|
||||
-> 写回 draftProfile
|
||||
-> 重编译 draftCards
|
||||
-> 写入 assistant action_result
|
||||
```
|
||||
|
||||
### 取消规则
|
||||
|
||||
用户点击取消后:
|
||||
|
||||
1. 丢弃本次未保存草稿
|
||||
2. 回到只读详情模式
|
||||
|
||||
## 7.3 各卡片可编辑字段
|
||||
|
||||
为了避免实现漂移,第四阶段明确限定每种卡的可编辑字段。
|
||||
|
||||
### `world`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `title`
|
||||
2. `subtitle`
|
||||
3. `summary`
|
||||
4. `playerGoal`
|
||||
5. `tone`
|
||||
6. `coreConflicts`
|
||||
|
||||
### `faction`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `title`
|
||||
2. `subtitle`
|
||||
3. `summary`
|
||||
4. `publicGoal`
|
||||
5. `tension`
|
||||
|
||||
### `character`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `name`
|
||||
2. `role`
|
||||
3. `publicMask`
|
||||
4. `hiddenHook`
|
||||
5. `relationToPlayer`
|
||||
6. `summary`
|
||||
|
||||
### `landmark`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `name`
|
||||
2. `purpose`
|
||||
3. `mood`
|
||||
4. `secret`
|
||||
5. `summary`
|
||||
|
||||
### `thread`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `title`
|
||||
2. `summary`
|
||||
3. `conflictType`
|
||||
4. `stakes`
|
||||
|
||||
### `chapter`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `title`
|
||||
2. `summary`
|
||||
3. `openingEvent`
|
||||
4. `playerGoal`
|
||||
5. `understandingShift`
|
||||
|
||||
### `camp`
|
||||
|
||||
允许编辑:
|
||||
|
||||
1. `name`
|
||||
2. `description`
|
||||
|
||||
## 7.4 第四阶段不允许编辑的内容
|
||||
|
||||
为控制范围,以下内容第四阶段不开放:
|
||||
|
||||
1. 技能
|
||||
2. 初始物品
|
||||
3. 场景连接网络
|
||||
4. sceneNpcIds
|
||||
5. 背景章节分段
|
||||
6. 视觉资产引用
|
||||
|
||||
这些内容留给后续阶段。
|
||||
|
||||
## 7.5 AI 新增角色
|
||||
|
||||
第四阶段要支持:
|
||||
|
||||
```text
|
||||
新增角色
|
||||
```
|
||||
|
||||
### 目标对象
|
||||
|
||||
默认新增:
|
||||
|
||||
1. `storyNpcs`
|
||||
|
||||
说明:
|
||||
|
||||
第四阶段不默认新增 `playableNpcs`,避免过早引入玩家入口角色平衡问题。
|
||||
|
||||
### 输入
|
||||
|
||||
用户可以提供:
|
||||
|
||||
1. 一句话要求
|
||||
2. 角色数量
|
||||
3. 可选参考卡片
|
||||
|
||||
### 数量限制
|
||||
|
||||
每次允许:
|
||||
|
||||
1. `1~3` 个角色
|
||||
|
||||
### 必须生成的字段
|
||||
|
||||
每个新角色至少要带:
|
||||
|
||||
1. `id`
|
||||
2. `name`
|
||||
3. `role`
|
||||
4. `description`
|
||||
5. `visualDescription`
|
||||
6. `actionDescription`
|
||||
7. `sceneVisualDescription`
|
||||
8. `publicMask`
|
||||
9. `hiddenHook`
|
||||
10. `relationToPlayer`
|
||||
11. `summary`
|
||||
|
||||
### 角色资产工坊默认文本来源
|
||||
|
||||
`visualDescription` 是角色主形象生成入口的默认形象描述主源,必须在可扮演角色 / 场景角色的草稿生成步骤中跟随角色一并生成,不允许在资产工坊打开时再用本地规则把 `description`、`role`、`tags` 拼成默认文案。
|
||||
|
||||
生成要求:
|
||||
|
||||
1. `description` 只写角色定位,控制在 8 到 18 个汉字内,用于角色卡摘要。
|
||||
2. `visualDescription` 专门写角色外观,包含轮廓、服饰 / 身体特征、携带物或材质气质,不写性格规则和玩法说明。
|
||||
3. `actionDescription` 专门写动作气质,用于动作生成默认文本。
|
||||
4. `sceneVisualDescription` 专门写角色常出现的场景氛围,用于场景图或角色场景联动默认文本。
|
||||
5. 资产工坊默认值优先读取 `visualDescription`,只有历史草稿缺失该字段时才允许回退到 `description`。
|
||||
|
||||
### 插入规则
|
||||
|
||||
生成后:
|
||||
|
||||
1. 写入 `draftProfile.storyNpcs`
|
||||
2. 重新编译 `character` 类 draftCards
|
||||
3. 在 drawer 中显示
|
||||
|
||||
## 7.6 AI 新增场景
|
||||
|
||||
第四阶段要支持:
|
||||
|
||||
```text
|
||||
新增场景
|
||||
```
|
||||
|
||||
### 目标对象
|
||||
|
||||
默认新增:
|
||||
|
||||
1. `landmarks`
|
||||
|
||||
### 输入
|
||||
|
||||
用户可以提供:
|
||||
|
||||
1. 一句话要求
|
||||
2. 场景数量
|
||||
3. 可选参考线程 / 角色 / 势力
|
||||
|
||||
### 数量限制
|
||||
|
||||
每次允许:
|
||||
|
||||
1. `1~3` 个场景
|
||||
|
||||
### 必须生成的字段
|
||||
|
||||
每个新场景至少要带:
|
||||
|
||||
1. `id`
|
||||
2. `name`
|
||||
3. `description` 或 `summary`
|
||||
5. `purpose`
|
||||
6. `mood`
|
||||
|
||||
### 插入规则
|
||||
|
||||
生成后:
|
||||
|
||||
1. 写入 `draftProfile.landmarks`
|
||||
2. 重新编译 `landmark` 类 draftCards
|
||||
3. 在 drawer 中显示
|
||||
|
||||
## 7.7 新增对象的归类规则
|
||||
|
||||
为了避免新增对象漂移,第四阶段新增对象必须绑定至少一个已有语义锚点:
|
||||
|
||||
### 新角色至少要绑定一个:
|
||||
|
||||
1. 线程
|
||||
2. 势力
|
||||
3. 玩家关系
|
||||
|
||||
### 新场景至少要绑定一个:
|
||||
|
||||
1. 线程
|
||||
2. 角色
|
||||
3. 势力
|
||||
|
||||
如果 AI 生成结果无法绑定任何现有锚点,则:
|
||||
|
||||
1. 允许生成
|
||||
2. 但卡片标记为 `warning`
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据结构落地方案
|
||||
|
||||
## 8.1 扩展 `CustomWorldAgentActionRequest`
|
||||
|
||||
第四阶段必须正式启用以下 action:
|
||||
|
||||
```ts
|
||||
| {
|
||||
action: 'update_draft_card';
|
||||
cardId: string;
|
||||
sections: Array<{
|
||||
sectionId: string;
|
||||
value: string;
|
||||
}>;
|
||||
}
|
||||
| {
|
||||
action: 'generate_characters';
|
||||
count: number;
|
||||
promptText?: string | null;
|
||||
anchorCardIds?: string[];
|
||||
}
|
||||
| {
|
||||
action: 'generate_landmarks';
|
||||
count: number;
|
||||
promptText?: string | null;
|
||||
anchorCardIds?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
### 第一版限制
|
||||
|
||||
1. `count` 只能是 `1~3`
|
||||
2. `anchorCardIds` 可选
|
||||
3. `sections` 不能为空
|
||||
|
||||
## 8.2 扩展 `CustomWorldAgentOperationType`
|
||||
|
||||
第四阶段新增:
|
||||
|
||||
```ts
|
||||
| 'update_draft_card'
|
||||
| 'generate_characters'
|
||||
| 'generate_landmarks'
|
||||
```
|
||||
|
||||
## 8.3 扩展 `CustomWorldDraftCardDetail`
|
||||
|
||||
第四阶段开始,detail 里需要返回:
|
||||
|
||||
```ts
|
||||
editable: boolean;
|
||||
editableSectionIds: string[];
|
||||
```
|
||||
|
||||
### 规则
|
||||
|
||||
1. 第四阶段所有可编辑卡返回 `editable = true`
|
||||
2. 非可编辑卡返回 `editable = false`
|
||||
|
||||
## 8.4 `draftProfile` 写回规则
|
||||
|
||||
第四阶段的所有保存动作都必须最终落到 `draftProfile` 对应对象上。
|
||||
|
||||
不得:
|
||||
|
||||
1. 只改 `draftCards`
|
||||
2. 只改前端详情临时数据
|
||||
|
||||
顺序必须是:
|
||||
|
||||
```text
|
||||
update draftProfile
|
||||
-> recompile draftCards
|
||||
-> return snapshot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 服务端实现方案
|
||||
|
||||
## 9.1 新增 `customWorldAgentDraftEditService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentDraftEditService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
1. 校验 card 是否存在
|
||||
2. 校验 card 是否可编辑
|
||||
3. 校验 sectionId 是否允许编辑
|
||||
4. 把 section patch 写回对应对象
|
||||
5. 返回新的 `draftProfile`
|
||||
|
||||
### 导出函数建议
|
||||
|
||||
```ts
|
||||
updateDraftCardSections(params)
|
||||
```
|
||||
|
||||
### 输入
|
||||
|
||||
```ts
|
||||
type UpdateDraftCardSectionsParams = {
|
||||
draftProfile: Record<string, unknown>;
|
||||
cardId: string;
|
||||
sections: Array<{
|
||||
sectionId: string;
|
||||
value: string;
|
||||
}>;
|
||||
};
|
||||
```
|
||||
|
||||
## 9.2 新增 `customWorldAgentEntityGenerationService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentEntityGenerationService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
1. 生成新增角色
|
||||
2. 生成新增场景
|
||||
3. 把新增对象插入 `draftProfile`
|
||||
|
||||
### 导出函数建议
|
||||
|
||||
```ts
|
||||
generateAdditionalCharacters(params)
|
||||
generateAdditionalLandmarks(params)
|
||||
```
|
||||
|
||||
### 输入
|
||||
|
||||
必须包含:
|
||||
|
||||
1. `creatorIntent`
|
||||
2. `anchorPack`
|
||||
3. `draftProfile`
|
||||
4. `count`
|
||||
5. `promptText`
|
||||
6. `anchorCardIds`
|
||||
|
||||
### 生成原则
|
||||
|
||||
1. 只围绕当前已生成的 foundation draft 扩展
|
||||
2. 不能重做已有对象
|
||||
3. 不能直接扩成完整长尾
|
||||
|
||||
## 9.3 新增 `customWorldAgentChangeSummaryService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
每次编辑或新增对象后,生成一段简短变更摘要。
|
||||
|
||||
要求至少包含:
|
||||
|
||||
1. 改了什么卡 / 新增了什么对象
|
||||
2. 影响到哪些对象数量
|
||||
3. 下一步建议
|
||||
|
||||
## 9.4 修改 `customWorldAgentOrchestrator.ts`
|
||||
|
||||
第四阶段必须启用以下 action:
|
||||
|
||||
1. `update_draft_card`
|
||||
2. `generate_characters`
|
||||
3. `generate_landmarks`
|
||||
|
||||
### `update_draft_card` 流程
|
||||
|
||||
```text
|
||||
收到 update_draft_card
|
||||
-> 校验 cardId
|
||||
-> 调用 DraftEditService
|
||||
-> 更新 draftProfile
|
||||
-> 调用 DraftCompiler
|
||||
-> 更新 draftCards
|
||||
-> 写入 assistant action_result
|
||||
-> 写入 checkpoint
|
||||
-> operation completed
|
||||
```
|
||||
|
||||
### `generate_characters` 流程
|
||||
|
||||
```text
|
||||
收到 generate_characters
|
||||
-> 校验 count
|
||||
-> 调用 EntityGenerationService
|
||||
-> 更新 draftProfile.storyNpcs
|
||||
-> 调用 DraftCompiler
|
||||
-> 更新 draftCards
|
||||
-> 写入 assistant action_result
|
||||
-> 写入 checkpoint
|
||||
-> operation completed
|
||||
```
|
||||
|
||||
### `generate_landmarks` 流程
|
||||
|
||||
```text
|
||||
收到 generate_landmarks
|
||||
-> 校验 count
|
||||
-> 调用 EntityGenerationService
|
||||
-> 更新 draftProfile.landmarks
|
||||
-> 调用 DraftCompiler
|
||||
-> 更新 draftCards
|
||||
-> 写入 assistant action_result
|
||||
-> 写入 checkpoint
|
||||
-> operation completed
|
||||
```
|
||||
|
||||
## 9.5 修改 `customWorldAgentDraftCompiler.ts`
|
||||
|
||||
第四阶段它必须继续承担:
|
||||
|
||||
1. 根据新的 `draftProfile` 重编译摘要
|
||||
2. 对新增角色生成新的 character 卡
|
||||
3. 对新增场景生成新的 landmark 卡
|
||||
|
||||
### 第四阶段新增要求
|
||||
|
||||
对 detail 详情返回:
|
||||
|
||||
1. `editable`
|
||||
2. `editableSectionIds`
|
||||
|
||||
---
|
||||
|
||||
## 10. 前端实现方案
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
这一节描述的是第四阶段编写当时的草稿详情编辑链与实体生成弹窗链。
|
||||
|
||||
但当前版本已经明确:
|
||||
|
||||
1. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
2. `CustomWorldDraftEditPanel.tsx`
|
||||
3. `CustomWorldGenerateEntityModal.tsx`
|
||||
4. `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
已在当前版本收口判断中退出主链并物理删除。
|
||||
|
||||
因此本节以下内容只保留历史设计参考价值,不再直接代表当前版本执行方向。
|
||||
|
||||
## 10.1 修改 `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
|
||||
第四阶段它要从只读详情升级成:
|
||||
|
||||
1. 只读模式
|
||||
2. 编辑模式
|
||||
|
||||
### 新增动作
|
||||
|
||||
1. `编辑设定`
|
||||
2. `保存`
|
||||
3. `取消`
|
||||
4. `新增角色`
|
||||
5. `新增场景`
|
||||
|
||||
### 模式规则
|
||||
|
||||
#### 只读模式
|
||||
|
||||
显示:
|
||||
|
||||
1. sections
|
||||
2. 编辑设定按钮
|
||||
|
||||
#### 编辑模式
|
||||
|
||||
对 `editableSectionIds` 对应的 section 渲染输入框:
|
||||
|
||||
1. 短字段用 `input`
|
||||
2. 长字段用 `textarea`
|
||||
|
||||
## 10.2 新增 `CustomWorldDraftEditPanel.tsx`
|
||||
|
||||
### 职责
|
||||
|
||||
承接 detail panel 的编辑表单。
|
||||
|
||||
### props
|
||||
|
||||
```ts
|
||||
{
|
||||
detail: CustomWorldDraftCardDetail;
|
||||
onSave: (sections) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
## 10.3 新增 `CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
### 职责
|
||||
|
||||
统一承接:
|
||||
|
||||
1. AI 新增角色
|
||||
2. AI 新增场景
|
||||
|
||||
### 模式
|
||||
|
||||
```ts
|
||||
mode: 'character' | 'landmark'
|
||||
```
|
||||
|
||||
### 字段
|
||||
|
||||
1. `count`
|
||||
2. `promptText`
|
||||
3. 当前参考卡提示
|
||||
|
||||
### 第一版限制
|
||||
|
||||
1. 不做复杂多选引用 UI
|
||||
2. `anchorCardIds` 可先默认使用当前焦点卡
|
||||
|
||||
## 10.4 修改 `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
第四阶段开始可以根据 session.stage 显示:
|
||||
|
||||
1. `新增角色`
|
||||
2. `新增场景`
|
||||
|
||||
说明:
|
||||
|
||||
这些只是快捷入口,本质仍然打开 modal 并走 action route。
|
||||
|
||||
## 10.5 修改 `CustomWorldAgentWorkspace.tsx`
|
||||
|
||||
第四阶段它要新增:
|
||||
|
||||
1. `editMode`
|
||||
2. `showGenerateEntityModal`
|
||||
3. `generateEntityMode`
|
||||
|
||||
同时要支持:
|
||||
|
||||
1. 打开详情并进入编辑
|
||||
2. 保存编辑
|
||||
3. 打开新增角色 modal
|
||||
4. 打开新增场景 modal
|
||||
|
||||
## 10.6 修改 `CustomWorldCreationHub.tsx`
|
||||
|
||||
第四阶段它必须支持作品摘要继续升级:
|
||||
|
||||
1. 新增角色后,数量变化
|
||||
2. 新增场景后,数量变化
|
||||
3. 编辑世界卡后,标题或摘要变化
|
||||
|
||||
---
|
||||
|
||||
## 11. 交互时序
|
||||
|
||||
## 11.1 编辑草稿设定
|
||||
|
||||
```text
|
||||
用户打开角色卡详情
|
||||
-> 点击编辑设定
|
||||
-> 修改字段
|
||||
-> 点击保存
|
||||
-> 前端 POST /actions { action: update_draft_card }
|
||||
-> 服务端更新 draftProfile
|
||||
-> 服务端重编译 draftCards
|
||||
-> 服务端写入变更摘要
|
||||
-> 前端刷新 snapshot
|
||||
```
|
||||
|
||||
## 11.2 AI 新增角色
|
||||
|
||||
```text
|
||||
用户点击新增角色
|
||||
-> 打开 generate modal
|
||||
-> 输入数量和补充描述
|
||||
-> 前端 POST /actions { action: generate_characters }
|
||||
-> 服务端新增角色
|
||||
-> 服务端更新 draftProfile.storyNpcs
|
||||
-> 服务端重编译 draftCards
|
||||
-> 前端刷新 snapshot
|
||||
```
|
||||
|
||||
## 11.3 AI 新增场景
|
||||
|
||||
```text
|
||||
用户点击新增场景
|
||||
-> 打开 generate modal
|
||||
-> 输入数量和补充描述
|
||||
-> 前端 POST /actions { action: generate_landmarks }
|
||||
-> 服务端新增场景
|
||||
-> 服务端更新 draftProfile.landmarks
|
||||
-> 服务端重编译 draftCards
|
||||
-> 前端刷新 snapshot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 与第三阶段的兼容要求
|
||||
|
||||
## 12.1 旧 draftCards 兼容
|
||||
|
||||
第三阶段生成的 card detail 如果没有:
|
||||
|
||||
```ts
|
||||
editable
|
||||
editableSectionIds
|
||||
```
|
||||
|
||||
服务端读取时应自动补:
|
||||
|
||||
```ts
|
||||
editable: true/false
|
||||
editableSectionIds: []
|
||||
```
|
||||
|
||||
## 12.2 旧 draftProfile 兼容
|
||||
|
||||
如果旧 draftProfile 缺少某些新增字段:
|
||||
|
||||
1. 编辑时允许 fallback
|
||||
2. 不允许因为字段缺失直接报错
|
||||
|
||||
## 12.3 新增角色/场景 ID 规则
|
||||
|
||||
新增对象时,必须使用稳定 id 生成规则,不能临时用数组下标。
|
||||
|
||||
---
|
||||
|
||||
## 13. 落地文件清单
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
本节列的是第四阶段历史文件清单。
|
||||
|
||||
其中涉及草稿详情编辑链与实体生成弹窗链的部分,不再等同于当前版本待落地清单。
|
||||
|
||||
## 13.1 shared
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
|
||||
## 13.2 frontend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
|
||||
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
4. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
5. `src/services/aiService.ts`
|
||||
|
||||
## 13.3 backend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentDraftEditService.ts`
|
||||
2. `server-node/src/services/customWorldAgentEntityGenerationService.ts`
|
||||
3. `server-node/src/services/customWorldAgentChangeSummaryService.ts`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
3. `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
4. `server-node/src/routes/customWorldAgent.ts`
|
||||
|
||||
---
|
||||
|
||||
## 14. 测试要求
|
||||
|
||||
## 14.1 服务端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. `update_draft_card` 能正确写回 draftProfile
|
||||
2. 写回后 draftCards 摘要会更新
|
||||
3. `generate_characters` 会新增 `storyNpcs` 并生成新的 character 卡
|
||||
4. `generate_landmarks` 会新增 `landmarks` 并生成新的 landmark 卡
|
||||
5. 每次编辑或新增后会写入 checkpoint
|
||||
|
||||
## 14.2 前端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. detail panel 可以进入编辑模式
|
||||
2. 保存编辑会调用 action route
|
||||
3. 可以打开新增角色 modal
|
||||
4. 可以打开新增场景 modal
|
||||
5. 操作完成后 drawer 与创作页面摘要会更新
|
||||
|
||||
## 14.3 手工回归
|
||||
|
||||
至少走这 5 条:
|
||||
|
||||
1. 编辑世界总卡标题和摘要
|
||||
2. 编辑一张角色卡的压力与关系
|
||||
3. 新增 2 个角色
|
||||
4. 新增 2 个场景
|
||||
5. 返回创作页面确认数量与摘要变化
|
||||
|
||||
---
|
||||
|
||||
## 15. 第四阶段验收标准
|
||||
|
||||
做到以下几点,才算第四阶段真正完成:
|
||||
|
||||
1. 用户可以直接修改草稿中的设定。
|
||||
2. 修改后的内容会真正写回 draftProfile,而不是只改前端展示。
|
||||
3. 用户可以继续用 AI 新增角色和场景。
|
||||
4. 新增角色和场景会成为新的草稿卡。
|
||||
5. 创作页面草稿作品卡会同步反映这些变化。
|
||||
6. 第四阶段仍然不越界去做资产工坊、长尾扩展和发布。
|
||||
|
||||
---
|
||||
|
||||
## 16. 一句话结论
|
||||
|
||||
第四阶段最重要的不是“继续控制已有结果不动”,而是:
|
||||
|
||||
**让这版世界草稿开始具备真正的可编辑性和可扩展性。**
|
||||
@@ -0,0 +1,818 @@
|
||||
# AI 原生 Agent-First 自定义世界创作工具第五阶段技术落地方案
|
||||
|
||||
更新时间:`2026-04-14`
|
||||
|
||||
## 0.1 当前状态说明(2026-04-21)
|
||||
|
||||
这份文档保留为第五阶段历史落地方案。
|
||||
|
||||
补充边界:
|
||||
|
||||
1. 文中继续沿用的 `CustomWorldAgentDraftDetailPanel`、`CustomWorldAgentQuickActions` 等旧副面板,在当前版本已经退出主链并物理删除
|
||||
2. 因此这份文档里的实现安排,不应再被直接视为当前版本执行清单
|
||||
3. 当前版本是否重引入相关能力,必须基于新的主链设计重新判断
|
||||
## 0. 文档目的
|
||||
|
||||
这份文档用于把以下几份文档进一步收束成第五阶段实现方案:
|
||||
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md)
|
||||
- [AI_CHARACTER_VISUAL_ANIMATION_MVP_PRD_2026-04-04.md](./AI_CHARACTER_VISUAL_ANIMATION_MVP_PRD_2026-04-04.md)
|
||||
|
||||
如果说第四阶段的目标是:
|
||||
|
||||
**让草稿世界变得可编辑、可继续长出新角色和新场景**
|
||||
|
||||
那么第五阶段的目标就是:
|
||||
|
||||
**把草稿里的角色第一次接上正式的主图与核心动作资产工坊。**
|
||||
|
||||
一句话定义:
|
||||
|
||||
**第五阶段把“角色只是文字卡”升级成“角色开始有可预览、可应用的主形象和动作资产”。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 阶段衔接关系
|
||||
|
||||
## 1.1 第四阶段已经完成什么
|
||||
|
||||
第五阶段默认建立在第四阶段已经完成的能力之上:
|
||||
|
||||
1. `draftProfile` 已经可编辑
|
||||
2. 用户可以新增角色
|
||||
3. `draftCards` 中已经有稳定的 `character` 卡
|
||||
4. `CustomWorldAgentDraftDetailPanel` 已经存在
|
||||
5. 用户可以从工作区聚焦到某个具体角色
|
||||
|
||||
## 1.2 第五阶段不再重做什么
|
||||
|
||||
以下内容第五阶段不重做:
|
||||
|
||||
1. 不重做 foundation draft 生成
|
||||
2. 不重做 draftCards 主链
|
||||
3. 不重做草稿设定编辑
|
||||
4. 不重做 AI 新增角色 / 场景
|
||||
|
||||
第五阶段只继续补:
|
||||
|
||||
1. 角色主图候选生成
|
||||
2. 角色主图发布
|
||||
3. 角色核心动作生成
|
||||
4. 角色核心动作发布
|
||||
5. 资产状态写回 session 与 draftProfile
|
||||
6. 角色卡资产状态展示
|
||||
|
||||
---
|
||||
|
||||
## 2. 第五阶段在八阶段中的位置
|
||||
|
||||
八阶段拆分如下:
|
||||
|
||||
1. 阶段 1:创作页面入口、Agent 会话主链与工作区骨架
|
||||
2. 阶段 2:最小锚点收集与澄清流程
|
||||
3. 阶段 3:世界底稿生成与草稿卡编译
|
||||
4. 阶段 4:草稿设定编辑与 AI 新增角色/场景生成
|
||||
5. 阶段 5:角色主图与动作资产工坊接入
|
||||
6. 阶段 6:场景背景图工坊接入
|
||||
7. 阶段 7:长尾内容扩展与自动补齐
|
||||
8. 阶段 8:发布、世界库接入与继续创作恢复
|
||||
|
||||
本文件只覆盖:
|
||||
|
||||
**阶段 5:角色主图与动作资产工坊接入**
|
||||
|
||||
---
|
||||
|
||||
## 3. 第五阶段目标
|
||||
|
||||
第五阶段只做 7 件必须一起成立的事:
|
||||
|
||||
1. 用户可以从角色卡打开资产工坊
|
||||
2. 用户可以为角色生成主图候选
|
||||
3. 用户可以选择主图候选并发布为角色主图
|
||||
4. 用户可以基于已发布主图生成核心动作
|
||||
5. 用户可以发布核心动作资产
|
||||
6. 发布成功后,角色对象会写回 `imageSrc / generatedVisualAssetId / generatedAnimationSetId / animationMap`
|
||||
7. 工作区和创作页面能感知角色资产状态变化
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让第五阶段结束时,至少部分关键角色已经不只是“设定存在”,而是“能动起来”。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 第五阶段完成定义
|
||||
|
||||
第五阶段完成后,必须同时满足以下结果:
|
||||
|
||||
1. 用户从某张 `character` 卡进入详情后,可以点击“角色资产”打开 `CustomWorldRoleAssetStudioModal`。
|
||||
2. 用户可以生成主图候选,并能预览多个候选。
|
||||
3. 用户选择候选并发布后,对应角色会得到:
|
||||
- `imageSrc`
|
||||
- `generatedVisualAssetId`
|
||||
4. 用户可以基于主图继续生成核心动作草稿。
|
||||
5. 用户发布动作后,对应角色会得到:
|
||||
- `generatedAnimationSetId`
|
||||
- `animationMap`
|
||||
6. assetCoverage 中对应角色状态会更新。
|
||||
7. 工作区中的角色卡会显示主图 / 动作状态变化。
|
||||
8. 第五阶段仍然不要求场景背景图接入,也不要求所有角色都必须完成资产生成。
|
||||
|
||||
---
|
||||
|
||||
## 5. 范围控制
|
||||
|
||||
## 5.1 第五阶段纳入范围
|
||||
|
||||
纳入范围的模块:
|
||||
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
- `src/components/CustomWorldRoleAssetStudioModal.tsx`
|
||||
- `src/components/asset-studio/characterAssetWorkflowPersistence.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
- `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
- `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
- `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
|
||||
新增服务端模块:
|
||||
|
||||
- `server-node/src/services/customWorldAgentAssetBridgeService.ts`
|
||||
- `server-node/src/services/customWorldAgentRoleAssetStateService.ts`
|
||||
|
||||
## 5.2 第五阶段明确不做
|
||||
|
||||
以下内容不放进第五阶段:
|
||||
|
||||
1. 不做场景背景图工坊接入
|
||||
2. 不做长尾角色批量自动出图
|
||||
3. 不做所有角色的自动动作补齐
|
||||
4. 不做发布时强制所有角色资产齐全
|
||||
5. 不做视频导入高级编辑链
|
||||
6. 不做口型 / 对话特写
|
||||
|
||||
原因:
|
||||
|
||||
**第五阶段只解决“选中的角色如何进入资产工坊并成功把结果写回草稿世界”。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 第五阶段最小闭环
|
||||
|
||||
建议把第五阶段的最小闭环定义为:
|
||||
|
||||
```text
|
||||
第四阶段已有角色卡
|
||||
-> 用户打开某张角色卡详情
|
||||
-> 点击“角色资产”
|
||||
-> 打开角色资产工坊
|
||||
-> 生成主图候选
|
||||
-> 选择并发布主图
|
||||
-> 生成核心动作
|
||||
-> 发布动作
|
||||
-> sync_role_assets
|
||||
-> role card / assetCoverage / 创作页面摘要同步更新
|
||||
```
|
||||
|
||||
这个闭环里,先只强接两条高价值链路:
|
||||
|
||||
1. `character card -> asset studio`
|
||||
2. `asset studio publish -> session sync`
|
||||
|
||||
---
|
||||
|
||||
## 7. 第五阶段产品行为定义
|
||||
|
||||
## 7.1 哪些角色可以进入资产工坊
|
||||
|
||||
第五阶段允许以下角色进入资产工坊:
|
||||
|
||||
1. `playableNpcs`
|
||||
2. `storyNpcs`
|
||||
|
||||
但默认推荐优先处理:
|
||||
|
||||
1. 主线关键角色
|
||||
2. 可扮演角色
|
||||
3. 创作者重点想看的角色
|
||||
|
||||
## 7.2 入口位置
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
这一节以下描述依赖当时仍被视为现行方案的旧详情面板链与旧快捷动作链。
|
||||
|
||||
但当前版本已经明确:
|
||||
|
||||
1. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
2. `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
已退出主链并物理删除。
|
||||
|
||||
因此这里关于入口位置的说明,现在只能作为历史资产工坊设计参考,不再代表当前版本 UI 入口。
|
||||
|
||||
### 角色卡详情入口
|
||||
|
||||
在 `CustomWorldAgentDraftDetailPanel` 中,当当前卡类型为:
|
||||
|
||||
```ts
|
||||
kind === 'character';
|
||||
```
|
||||
|
||||
显示按钮:
|
||||
|
||||
- `角色资产`
|
||||
|
||||
### 快捷动作入口
|
||||
|
||||
当当前 focus card 为角色卡时,`CustomWorldAgentQuickActions` 可显示:
|
||||
|
||||
- `生成角色主图与动作`
|
||||
|
||||
说明:
|
||||
|
||||
快捷动作与详情按钮最终都打开同一个 modal。
|
||||
|
||||
## 7.3 第五阶段支持的资产流程
|
||||
|
||||
### 阶段 A:主图候选
|
||||
|
||||
允许:
|
||||
|
||||
1. `text-to-image`
|
||||
2. `image-to-image`
|
||||
|
||||
不做:
|
||||
|
||||
1. 批量上传模式
|
||||
2. 一次性批量生成多个角色主图
|
||||
|
||||
### 阶段 B:主图发布
|
||||
|
||||
用户在候选中选择一个结果后,发布主图。
|
||||
|
||||
### 阶段 C:核心动作草稿
|
||||
|
||||
基于主图生成当前工坊支持的核心动作:
|
||||
|
||||
1. `run`
|
||||
2. `attack`
|
||||
|
||||
可选增强动作:
|
||||
|
||||
1. `idle`
|
||||
2. `die`
|
||||
|
||||
补充约束:
|
||||
|
||||
1. `run / attack` 为固定必生成动作
|
||||
2. 角色已配置技能时,对应技能动作也属于必生成动作
|
||||
3. `idle / die` 只作为可选增强,缺失时分别走主图静止 / 主图向后倒地过渡动画兜底,死亡动画带轻微过冲回落,最终停在翻转倒地姿态
|
||||
|
||||
### 阶段 D:动作发布
|
||||
|
||||
将动作草稿发布为正式动画资产,并写回角色。
|
||||
|
||||
## 7.4 第五阶段不强制的事情
|
||||
|
||||
第五阶段明确不强制:
|
||||
|
||||
1. 每个角色都必须立刻生成主图
|
||||
2. 每个角色都必须立刻生成动作
|
||||
3. 没有资产的角色不能继续文本创作
|
||||
|
||||
说明:
|
||||
|
||||
这一步是“角色开始接资产”,不是“所有角色必须立刻完工”。
|
||||
|
||||
## 7.5 积分消耗提示规则
|
||||
|
||||
当前项目已经明确:
|
||||
|
||||
**不做预算限制,但高成本生成前必须明确提示积分消耗。**
|
||||
|
||||
因此第五阶段必须遵守:
|
||||
|
||||
### 主图候选生成前
|
||||
|
||||
必须提示:
|
||||
|
||||
1. 本次会消耗多少积分
|
||||
2. 这是候选抽卡,不是最终发布
|
||||
|
||||
### 动作草稿生成前
|
||||
|
||||
必须提示:
|
||||
|
||||
1. 本次会消耗多少积分
|
||||
2. 这是动作草稿,不是最终发布
|
||||
|
||||
### 发布前
|
||||
|
||||
发布动作或主图本身不应再次重复收积分,除非现有资产接口明确要求。
|
||||
|
||||
---
|
||||
|
||||
## 8. 角色资产状态定义
|
||||
|
||||
## 8.1 `assetCoverage.roleAssets`
|
||||
|
||||
第五阶段必须开始真正使用它。
|
||||
|
||||
建议状态:
|
||||
|
||||
```ts
|
||||
type CustomWorldRoleAssetStatus =
|
||||
| 'missing'
|
||||
| 'visual_ready'
|
||||
| 'animations_ready'
|
||||
| 'complete';
|
||||
```
|
||||
|
||||
### 含义
|
||||
|
||||
#### `missing`
|
||||
|
||||
角色还没有正式主图
|
||||
|
||||
#### `visual_ready`
|
||||
|
||||
角色已经有:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedVisualAssetId`
|
||||
|
||||
但没有完整动作
|
||||
|
||||
#### `animations_ready`
|
||||
|
||||
角色已经有:
|
||||
|
||||
1. `generatedAnimationSetId`
|
||||
2. 至少一组核心动作映射
|
||||
|
||||
但若需要更严格区分,也允许继续映射到 `complete`
|
||||
|
||||
#### `complete`
|
||||
|
||||
角色有:
|
||||
|
||||
1. 主图
|
||||
2. 核心动作
|
||||
|
||||
### 第五阶段建议判定
|
||||
|
||||
为了避免漂移,直接使用:
|
||||
|
||||
1. 只有主图:`visual_ready`
|
||||
2. 主图 + 五组核心动作都齐:`complete`
|
||||
|
||||
第五阶段不强制使用 `animations_ready` 作为单独过渡,可选保留。
|
||||
|
||||
## 8.2 角色对象写回字段
|
||||
|
||||
发布主图成功后,必须写回:
|
||||
|
||||
```ts
|
||||
imageSrc;
|
||||
generatedVisualAssetId;
|
||||
```
|
||||
|
||||
发布动作成功后,必须写回:
|
||||
|
||||
```ts
|
||||
generatedAnimationSetId;
|
||||
animationMap;
|
||||
```
|
||||
|
||||
### 明确要求
|
||||
|
||||
第五阶段不允许只更新 `assetCoverage`,不更新角色对象本身。
|
||||
|
||||
---
|
||||
|
||||
## 9. 数据结构落地方案
|
||||
|
||||
## 9.1 扩展 `CustomWorldAgentActionRequest`
|
||||
|
||||
第五阶段正式启用:
|
||||
|
||||
```ts
|
||||
| { action: 'generate_role_assets'; roleIds: string[] }
|
||||
| {
|
||||
action: 'sync_role_assets';
|
||||
roleId: string;
|
||||
portraitPath: string;
|
||||
generatedVisualAssetId: string;
|
||||
generatedAnimationSetId?: string | null;
|
||||
animationMap?: JsonObject | null;
|
||||
}
|
||||
```
|
||||
|
||||
### 第五阶段限制
|
||||
|
||||
1. `generate_role_assets` 第一版只允许单角色:
|
||||
- `roleIds.length === 1`
|
||||
2. 批量角色资产生成留到后续阶段
|
||||
|
||||
## 9.2 扩展 `CustomWorldRoleAssetSummary`
|
||||
|
||||
第五阶段开始必须真正填:
|
||||
|
||||
1. `portraitPath`
|
||||
2. `generatedVisualAssetId`
|
||||
3. `generatedAnimationSetId`
|
||||
4. `status`
|
||||
5. `missingAnimations`
|
||||
6. `nextPointCost`
|
||||
|
||||
## 9.3 新增角色资产同步结果结构
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
type SyncRoleAssetsResult = {
|
||||
roleId: string;
|
||||
updatedRole: Record<string, unknown>;
|
||||
updatedAssetSummary: CustomWorldRoleAssetSummary;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 服务端实现方案
|
||||
|
||||
## 10.1 新增 `customWorldAgentAssetBridgeService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentAssetBridgeService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
负责连接:
|
||||
|
||||
1. Agent session
|
||||
2. 现有角色资产路由与持久化能力
|
||||
|
||||
### 第一版职责
|
||||
|
||||
1. 将角色卡编译成资产工坊启动参数
|
||||
2. 接收工坊发布结果
|
||||
3. 转换为 session 可写回的标准结果
|
||||
|
||||
### 输入
|
||||
|
||||
```ts
|
||||
buildRoleAssetStudioContext(snapshot, roleId);
|
||||
applyRoleAssetPublishResult(snapshot, payload);
|
||||
```
|
||||
|
||||
### 说明
|
||||
|
||||
它不自己生成图片或动作,仍然复用现有资产链。
|
||||
|
||||
## 10.2 新增 `customWorldAgentRoleAssetStateService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentRoleAssetStateService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
根据角色对象真实字段,更新:
|
||||
|
||||
1. `assetCoverage.roleAssets`
|
||||
2. `draftCards` 中角色卡的副摘要
|
||||
3. 创作页面作品卡统计
|
||||
|
||||
### 导出函数建议
|
||||
|
||||
```ts
|
||||
rebuildRoleAssetCoverage(draftProfile);
|
||||
mergeRoleAssetIntoDraftProfile(draftProfile, payload);
|
||||
```
|
||||
|
||||
## 10.3 修改 `customWorldAgentOrchestrator.ts`
|
||||
|
||||
第五阶段必须启用:
|
||||
|
||||
1. `generate_role_assets`
|
||||
2. `sync_role_assets`
|
||||
|
||||
### `generate_role_assets` 流程
|
||||
|
||||
```text
|
||||
收到 generate_role_assets
|
||||
-> 校验 roleIds
|
||||
-> 构建 role asset studio context
|
||||
-> 返回 operation completed
|
||||
-> 前端打开资产工坊
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
这里的 operation 不是生成图片,而是准备进入工坊。
|
||||
|
||||
### `sync_role_assets` 流程
|
||||
|
||||
```text
|
||||
收到 sync_role_assets
|
||||
-> 校验 roleId
|
||||
-> 写回 draftProfile 中的角色字段
|
||||
-> 重建 assetCoverage.roleAssets
|
||||
-> 重新编译角色卡摘要
|
||||
-> 写入 assistant action_result
|
||||
-> 写入 checkpoint
|
||||
-> operation completed
|
||||
```
|
||||
|
||||
## 10.4 修改 `customWorldAgentDraftCompiler.ts`
|
||||
|
||||
第五阶段它必须让 `character` 卡摘要带出资产状态。
|
||||
|
||||
### 角色卡摘要新增要求
|
||||
|
||||
在 `subtitle` 或 `summary` 中追加:
|
||||
|
||||
1. `主图已就绪`
|
||||
2. `动作已就绪`
|
||||
3. `待生成主图`
|
||||
|
||||
但不要让卡片默认变成技术清单。
|
||||
|
||||
推荐形式:
|
||||
|
||||
- `外显身份 / 主图已就绪`
|
||||
|
||||
或:
|
||||
|
||||
- `当前压力……(动作待补)`
|
||||
|
||||
## 10.5 修改 `customWorldWorkSummaryService.ts`
|
||||
|
||||
第五阶段创作页面草稿卡应支持展示:
|
||||
|
||||
1. 已有多少角色具备主图
|
||||
2. 已有多少角色具备动作
|
||||
|
||||
第一版如果不想上具体数字,也至少要能在草稿卡上体现:
|
||||
|
||||
- `角色资产进行中`
|
||||
|
||||
---
|
||||
|
||||
## 11. 前端实现方案
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
本节以下内容依赖旧详情面板链与旧快捷动作面板。
|
||||
|
||||
这些文件当前已经退出主链并删除,所以这里不再是当前版本的直接执行清单。
|
||||
|
||||
## 11.1 修改 `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
|
||||
当卡片类型为 `character` 时,新增:
|
||||
|
||||
1. `角色资产` 按钮
|
||||
2. 资产状态 badge
|
||||
|
||||
### 状态显示建议
|
||||
|
||||
1. `待生成主图`
|
||||
2. `主图已就绪`
|
||||
3. `动作已就绪`
|
||||
|
||||
## 11.2 修改 `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
当当前 focus 为角色卡时,可显示:
|
||||
|
||||
1. `生成角色主图与动作`
|
||||
|
||||
点击后:
|
||||
|
||||
1. 调用 `generate_role_assets`
|
||||
2. 成功后打开 `CustomWorldRoleAssetStudioModal`
|
||||
|
||||
## 11.3 修改 `CustomWorldAgentWorkspace.tsx`
|
||||
|
||||
新增状态:
|
||||
|
||||
```ts
|
||||
activeRoleAssetTargetId?: string | null;
|
||||
showRoleAssetStudio: boolean;
|
||||
```
|
||||
|
||||
### 打开逻辑
|
||||
|
||||
1. 来自 detail panel
|
||||
2. 来自 quick actions
|
||||
|
||||
### 关闭逻辑
|
||||
|
||||
关闭后不代表写回成功。
|
||||
|
||||
必须等:
|
||||
|
||||
1. 工坊发布成功
|
||||
2. `sync_role_assets` 成功
|
||||
|
||||
之后才刷新角色资产状态。
|
||||
|
||||
## 11.4 修改 `CustomWorldRoleAssetStudioModal.tsx`
|
||||
|
||||
第五阶段不重做这个组件,但必须调整为:
|
||||
|
||||
1. 接收来自 Agent 工作区的角色对象
|
||||
2. 发布成功后,不直接改本地 profile
|
||||
3. 统一回调:
|
||||
|
||||
```ts
|
||||
onPublishSuccess(payload);
|
||||
```
|
||||
|
||||
### `onPublishSuccess` 最小字段
|
||||
|
||||
```ts
|
||||
{
|
||||
roleId: string;
|
||||
portraitPath: string;
|
||||
generatedVisualAssetId: string;
|
||||
generatedAnimationSetId?: string | null;
|
||||
animationMap?: Record<string, unknown> | null;
|
||||
}
|
||||
```
|
||||
|
||||
## 11.5 修改 `CustomWorldCreationHub.tsx`
|
||||
|
||||
第五阶段它必须支持草稿作品卡的“资产进度感”。
|
||||
|
||||
第一版至少做到:
|
||||
|
||||
1. 草稿卡可展示:
|
||||
- 角色资产进行中
|
||||
- 或若数量可得,则展示主图 / 动作完成数
|
||||
|
||||
不要求这一版做得很重。
|
||||
|
||||
---
|
||||
|
||||
## 12. 交互时序
|
||||
|
||||
## 12.1 打开角色资产工坊
|
||||
|
||||
```text
|
||||
用户点击角色卡
|
||||
-> 打开 detail panel
|
||||
-> 点击“角色资产”
|
||||
-> 前端 POST /actions { action: generate_role_assets }
|
||||
-> 服务端校验角色
|
||||
-> 服务端返回可进入工坊
|
||||
-> 前端打开 CustomWorldRoleAssetStudioModal
|
||||
```
|
||||
|
||||
## 12.2 发布主图
|
||||
|
||||
```text
|
||||
用户在工坊中选择主图候选
|
||||
-> 发布主图
|
||||
-> 工坊获得 portraitPath + generatedVisualAssetId
|
||||
-> 暂不关闭会话
|
||||
-> 可继续生成动作
|
||||
```
|
||||
|
||||
## 12.3 发布动作并同步
|
||||
|
||||
```text
|
||||
用户发布动作
|
||||
-> 工坊获得 generatedAnimationSetId + animationMap
|
||||
-> 前端调用 sync_role_assets
|
||||
-> 服务端写回 draftProfile.character
|
||||
-> 服务端重建 assetCoverage.roleAssets
|
||||
-> 服务端重编译角色卡摘要
|
||||
-> 前端刷新 snapshot
|
||||
-> 工坊关闭
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 与第四阶段的兼容要求
|
||||
|
||||
## 13.1 兼容新增角色
|
||||
|
||||
第四阶段新增的角色对象只要已经在 `draftProfile.storyNpcs` 或 `playableNpcs` 中,均允许进入资产工坊。
|
||||
|
||||
不要求:
|
||||
|
||||
1. 该角色必须有完整长背景
|
||||
2. 该角色必须已进入后续发布阶段
|
||||
|
||||
## 13.2 兼容无主图角色
|
||||
|
||||
如果某角色完全无:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedVisualAssetId`
|
||||
|
||||
也允许打开工坊,从零开始生成。
|
||||
|
||||
## 13.3 兼容有主图无动作角色
|
||||
|
||||
如果角色已经有:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedVisualAssetId`
|
||||
|
||||
但没有:
|
||||
|
||||
1. `generatedAnimationSetId`
|
||||
|
||||
则工坊默认直接进入动作阶段。
|
||||
|
||||
---
|
||||
|
||||
## 14. 落地文件清单
|
||||
|
||||
## 14.1 frontend
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
|
||||
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
4. `src/components/CustomWorldRoleAssetStudioModal.tsx`
|
||||
5. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
6. `src/services/aiService.ts`
|
||||
|
||||
## 14.2 backend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentAssetBridgeService.ts`
|
||||
2. `server-node/src/services/customWorldAgentRoleAssetStateService.ts`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
3. `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
4. `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
|
||||
---
|
||||
|
||||
## 15. 测试要求
|
||||
|
||||
## 15.1 服务端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. `generate_role_assets` 仅允许单角色
|
||||
2. `sync_role_assets` 能正确写回角色字段
|
||||
3. 写回后 `assetCoverage.roleAssets` 状态更新
|
||||
4. 写回后角色卡摘要更新
|
||||
5. 写回后 checkpoint 存在
|
||||
|
||||
## 15.2 前端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. character 卡详情可显示角色资产入口
|
||||
2. quick actions 可打开角色资产工坊
|
||||
3. 工坊发布成功后会触发 `sync_role_assets`
|
||||
4. snapshot 刷新后角色卡显示新状态
|
||||
|
||||
## 15.3 手工回归
|
||||
|
||||
至少走这 4 条:
|
||||
|
||||
1. 为一个无主图角色生成主图
|
||||
2. 为该角色继续生成并发布核心动作
|
||||
3. 返回 workspace 确认角色卡状态变化
|
||||
4. 返回创作页面确认草稿卡摘要变化
|
||||
|
||||
---
|
||||
|
||||
## 16. 第五阶段验收标准
|
||||
|
||||
做到以下几点,才算第五阶段真正完成:
|
||||
|
||||
1. 角色卡已经可以接入并打开角色资产工坊。
|
||||
2. 主图发布成功后,角色对象会写回 `imageSrc / generatedVisualAssetId`。
|
||||
3. 动作发布成功后,角色对象会写回 `generatedAnimationSetId / animationMap`。
|
||||
4. 角色资产状态会同步反映到 session snapshot 和角色卡摘要。
|
||||
5. 角色资产接入不会阻塞继续文本创作。
|
||||
6. 第五阶段仍然不越界去做场景背景图、长尾扩展和发布逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 17. 一句话结论
|
||||
|
||||
第五阶段最重要的不是“让所有角色都立刻变成完整资产”,而是:
|
||||
|
||||
**先把草稿世界里的角色,真正接到一条可预览、可发布、可写回的资产工坊链路上。**
|
||||
@@ -0,0 +1,721 @@
|
||||
# AI 原生 Agent-First 自定义世界创作工具第六阶段技术落地方案
|
||||
|
||||
更新时间:`2026-04-14`
|
||||
|
||||
## 0.1 当前状态说明(2026-04-21)
|
||||
|
||||
这份文档保留为第六阶段历史落地方案。
|
||||
|
||||
补充边界:
|
||||
|
||||
1. 文中继续引用的 `CustomWorldAgentDraftDetailPanel`、`CustomWorldAgentQuickActions` 等旧副面板,在当前版本已经退出主链并物理删除
|
||||
2. 这份文档可用于回看当时的资产工坊设想,但不代表当前版本仍按这里逐项补齐
|
||||
3. 当前执行边界以最新优化规划和阶段四清理边界文档为准
|
||||
## 0. 文档目的
|
||||
|
||||
这份文档用于把以下几份文档进一步收束成第六阶段实现方案:
|
||||
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md)
|
||||
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE5_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE5_IMPLEMENTATION_PLAN_2026-04-14.md)
|
||||
|
||||
如果说第五阶段的目标是:
|
||||
|
||||
**把草稿世界里的角色第一次接上正式的主图与核心动作资产工坊**
|
||||
|
||||
那么第六阶段的目标就是:
|
||||
|
||||
**把草稿世界里的营地和关键场景第一次接上正式的背景图工坊。**
|
||||
|
||||
一句话定义:
|
||||
|
||||
**第六阶段把“场景只是文字卡”升级成“场景开始有可预览、可应用的背景图资产”。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 阶段衔接关系
|
||||
|
||||
## 1.1 第五阶段已经完成什么
|
||||
|
||||
第六阶段默认建立在第五阶段已经完成的能力之上:
|
||||
|
||||
1. 角色卡已经可以接入资产工坊
|
||||
2. 角色主图与动作可以写回 `draftProfile`
|
||||
3. `assetCoverage.roleAssets` 已开始发挥作用
|
||||
4. 工作区已具备“卡片详情 -> 资产工坊 -> session 同步”的基本模式
|
||||
|
||||
## 1.2 第六阶段不再重做什么
|
||||
|
||||
以下内容第六阶段不重做:
|
||||
|
||||
1. 不重做 foundation draft 生成
|
||||
2. 不重做草稿设定编辑
|
||||
3. 不重做 AI 新增角色 / 场景
|
||||
4. 不重做角色主图与动作资产工坊接入
|
||||
|
||||
第六阶段只继续补:
|
||||
|
||||
1. 营地背景图资产工坊
|
||||
2. 场景背景图资产工坊
|
||||
3. 场景图状态写回 session 与 draftProfile
|
||||
4. 场景卡资产状态展示
|
||||
|
||||
---
|
||||
|
||||
## 2. 第六阶段在八阶段中的位置
|
||||
|
||||
八阶段拆分如下:
|
||||
|
||||
1. 阶段 1:创作页面入口、Agent 会话主链与工作区骨架
|
||||
2. 阶段 2:最小锚点收集与澄清流程
|
||||
3. 阶段 3:世界底稿生成与草稿卡编译
|
||||
4. 阶段 4:草稿设定编辑与 AI 新增角色/场景生成
|
||||
5. 阶段 5:角色主图与动作资产工坊接入
|
||||
6. 阶段 6:场景背景图工坊接入
|
||||
7. 阶段 7:长尾内容扩展与自动补齐
|
||||
8. 阶段 8:发布、世界库接入与继续创作恢复
|
||||
|
||||
本文件只覆盖:
|
||||
|
||||
**阶段 6:场景背景图工坊接入**
|
||||
|
||||
---
|
||||
|
||||
## 3. 第六阶段目标
|
||||
|
||||
第六阶段只做 7 件必须一起成立的事:
|
||||
|
||||
1. 用户可以从 `landmark` 卡和 `camp` 卡打开场景图工坊
|
||||
2. 用户可以为场景生成背景图候选
|
||||
3. 用户可以预览生成结果
|
||||
4. 用户可以选择结果并保存为正式场景图
|
||||
5. 保存成功后,场景对象会写回 `imageSrc / generatedSceneAssetId / generatedScenePrompt / generatedSceneModel`
|
||||
6. `assetCoverage.sceneAssets` 状态会更新
|
||||
7. 工作区和创作页面能感知场景资产状态变化
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让第六阶段结束时,至少部分关键场景已经不只是“设定存在”,而是“有可用背景图”。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 第六阶段完成定义
|
||||
|
||||
第六阶段完成后,必须同时满足以下结果:
|
||||
|
||||
1. 用户从某张 `landmark` 或 `camp` 卡进入详情后,可以点击“场景背景图”打开场景图工坊。
|
||||
2. 用户可以输入 prompt 并生成场景背景图结果。
|
||||
3. 用户可以预览生成结果,并在保存前决定是否继续重试。
|
||||
4. 用户保存成功后,对应场景对象会得到:
|
||||
- `imageSrc`
|
||||
- `generatedSceneAssetId`
|
||||
- `generatedScenePrompt`
|
||||
- `generatedSceneModel`
|
||||
5. `assetCoverage.sceneAssets` 中对应场景状态会更新。
|
||||
6. 工作区中的地点卡 / 营地卡会显示背景图状态变化。
|
||||
7. 第六阶段仍然不要求所有场景都立刻完成背景图,也不要求进入发布。
|
||||
|
||||
---
|
||||
|
||||
## 5. 范围控制
|
||||
|
||||
## 5.1 第六阶段纳入范围
|
||||
|
||||
纳入范围的模块:
|
||||
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
|
||||
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
- `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
- `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
- `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
- `server-node/src/services/sceneImageService.ts`
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
|
||||
新增前端模块:
|
||||
|
||||
- `src/components/custom-world-agent/CustomWorldSceneAssetStudioModal.tsx`
|
||||
|
||||
新增服务端模块:
|
||||
|
||||
- `server-node/src/services/customWorldAgentSceneAssetStateService.ts`
|
||||
|
||||
## 5.2 第六阶段明确不做
|
||||
|
||||
以下内容不放进第六阶段:
|
||||
|
||||
1. 不做角色资产工坊改造
|
||||
2. 不做长尾场景批量自动出图
|
||||
3. 不做场景图批量预生成
|
||||
4. 不做发布时强制所有场景图齐全
|
||||
5. 不做场景图精修工作流
|
||||
6. 不做地图连接与场景图自动同步生成
|
||||
|
||||
原因:
|
||||
|
||||
**第六阶段只解决“选中的营地或场景如何进入背景图工坊并成功把结果写回草稿世界”。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 第六阶段最小闭环
|
||||
|
||||
建议把第六阶段的最小闭环定义为:
|
||||
|
||||
```text
|
||||
第五阶段已有 landmark/camp 卡
|
||||
-> 用户打开某张地点卡详情
|
||||
-> 点击“场景背景图”
|
||||
-> 打开场景图工坊
|
||||
-> 输入 prompt 并开始生成
|
||||
-> 预览结果
|
||||
-> 保存
|
||||
-> sync_scene_assets
|
||||
-> landmark/camp card / assetCoverage / 创作页面摘要同步更新
|
||||
```
|
||||
|
||||
这个闭环里,先只强接两条高价值链路:
|
||||
|
||||
1. `landmark/camp card -> scene asset studio`
|
||||
2. `scene asset studio save -> session sync`
|
||||
|
||||
---
|
||||
|
||||
## 7. 第六阶段产品行为定义
|
||||
|
||||
## 7.1 哪些对象可以进入场景图工坊
|
||||
|
||||
第六阶段允许以下对象进入场景图工坊:
|
||||
|
||||
1. `camp`
|
||||
2. `landmark`
|
||||
|
||||
不处理:
|
||||
|
||||
1. 其他卡片类型
|
||||
|
||||
## 7.2 入口位置
|
||||
|
||||
### 当前状态补充(2026-04-21)
|
||||
|
||||
这一节以下描述依赖当时仍被视为现行方案的旧详情面板链与旧快捷动作链。
|
||||
|
||||
但当前版本已经明确:
|
||||
|
||||
1. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
2. `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
已退出主链并物理删除。
|
||||
|
||||
因此这里关于入口位置的说明,现在只保留历史场景资产工坊设计参考价值。
|
||||
|
||||
### 地点卡详情入口
|
||||
|
||||
在 `CustomWorldAgentDraftDetailPanel` 中,当当前卡类型为:
|
||||
|
||||
```ts
|
||||
kind === 'landmark' || kind === 'camp'
|
||||
```
|
||||
|
||||
显示按钮:
|
||||
|
||||
- `场景背景图`
|
||||
|
||||
### 快捷动作入口
|
||||
|
||||
当当前 focus card 为 `landmark` 或 `camp` 时,`CustomWorldAgentQuickActions` 可显示:
|
||||
|
||||
- `生成场景背景图`
|
||||
|
||||
说明:
|
||||
|
||||
快捷动作与详情按钮最终都打开同一个 modal。
|
||||
|
||||
## 7.3 第六阶段支持的场景图流程
|
||||
|
||||
### 阶段 A:场景图生成
|
||||
|
||||
允许:
|
||||
|
||||
1. 输入场景内容描述
|
||||
2. 上传一张可选参考图
|
||||
3. 基于当前场景语义生成背景图
|
||||
|
||||
### 阶段 B:场景图预览
|
||||
|
||||
用户必须可以:
|
||||
|
||||
1. 看到新生成图片
|
||||
2. 对比当前图片
|
||||
3. 决定是否保存
|
||||
|
||||
### 阶段 C:场景图保存
|
||||
|
||||
保存后把结果写回:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedSceneAssetId`
|
||||
3. `generatedScenePrompt`
|
||||
4. `generatedSceneModel`
|
||||
|
||||
## 7.4 第六阶段不强制的事情
|
||||
|
||||
第六阶段明确不强制:
|
||||
|
||||
1. 每个场景都必须立刻生成背景图
|
||||
2. 每个背景图都必须一次满意
|
||||
3. 没有背景图的场景不能继续文本创作
|
||||
|
||||
说明:
|
||||
|
||||
这一步是“场景开始接资产”,不是“所有场景必须立刻完工”。**
|
||||
|
||||
## 7.5 积分消耗提示规则
|
||||
|
||||
和第五阶段保持一致:
|
||||
|
||||
**不做预算限制,但高成本生成前必须明确提示积分消耗。**
|
||||
|
||||
因此第六阶段必须遵守:
|
||||
|
||||
### 生成前
|
||||
|
||||
必须提示:
|
||||
|
||||
1. 本次会消耗多少积分
|
||||
2. 这是候选生成,不是最终发布
|
||||
|
||||
### 保存前
|
||||
|
||||
保存本身不应再次重复收积分,除非现有场景图服务明确要求。
|
||||
|
||||
---
|
||||
|
||||
## 8. 场景资产状态定义
|
||||
|
||||
## 8.1 `assetCoverage.sceneAssets`
|
||||
|
||||
第六阶段必须开始真正使用它。
|
||||
|
||||
建议状态:
|
||||
|
||||
```ts
|
||||
type CustomWorldSceneAssetStatus = 'missing' | 'ready';
|
||||
```
|
||||
|
||||
### 含义
|
||||
|
||||
#### `missing`
|
||||
|
||||
场景还没有正式背景图
|
||||
|
||||
#### `ready`
|
||||
|
||||
场景已经有:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedSceneAssetId`
|
||||
|
||||
## 8.2 场景对象写回字段
|
||||
|
||||
保存成功后,必须写回:
|
||||
|
||||
```ts
|
||||
imageSrc
|
||||
generatedSceneAssetId
|
||||
generatedScenePrompt
|
||||
generatedSceneModel
|
||||
```
|
||||
|
||||
### 明确要求
|
||||
|
||||
第六阶段不允许只更新 `assetCoverage`,不更新场景对象本身。
|
||||
|
||||
---
|
||||
|
||||
## 9. 数据结构落地方案
|
||||
|
||||
## 9.1 启用 `CustomWorldAgentActionRequest`
|
||||
|
||||
第六阶段正式启用:
|
||||
|
||||
```ts
|
||||
| {
|
||||
action: 'sync_scene_assets';
|
||||
sceneId: string;
|
||||
sceneKind: 'camp' | 'landmark';
|
||||
imageSrc: string;
|
||||
generatedSceneAssetId: string;
|
||||
generatedScenePrompt?: string | null;
|
||||
generatedSceneModel?: string | null;
|
||||
}
|
||||
```
|
||||
|
||||
### 第六阶段说明
|
||||
|
||||
不新增新的 `generate_scene_assets` 前置准备 action。
|
||||
|
||||
原因:
|
||||
|
||||
当前场景图生成链已经由 `generateCustomWorldSceneImage(...)` 直接承接,
|
||||
因此第六阶段只需要在保存成功后做 session 同步。
|
||||
|
||||
## 9.2 扩展 `CustomWorldSceneAssetSummary`
|
||||
|
||||
第六阶段开始必须真正填:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedSceneAssetId`
|
||||
3. `status`
|
||||
4. `nextPointCost`
|
||||
|
||||
## 9.3 新增场景资产同步结果结构
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
type SyncSceneAssetsResult = {
|
||||
sceneId: string;
|
||||
sceneKind: 'camp' | 'landmark';
|
||||
updatedScene: Record<string, unknown>;
|
||||
updatedAssetSummary: CustomWorldSceneAssetSummary;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 服务端实现方案
|
||||
|
||||
## 10.1 新增 `customWorldAgentSceneAssetStateService.ts`
|
||||
|
||||
### 文件
|
||||
|
||||
`server-node/src/services/customWorldAgentSceneAssetStateService.ts`
|
||||
|
||||
### 职责
|
||||
|
||||
根据营地或场景对象真实字段,更新:
|
||||
|
||||
1. `assetCoverage.sceneAssets`
|
||||
2. `draftCards` 中地点卡 / 营地卡的副摘要
|
||||
3. 创作页面作品卡统计
|
||||
|
||||
### 导出函数建议
|
||||
|
||||
```ts
|
||||
rebuildSceneAssetCoverage(draftProfile)
|
||||
mergeSceneAssetIntoDraftProfile(draftProfile, payload)
|
||||
```
|
||||
|
||||
## 10.2 修改 `customWorldAgentOrchestrator.ts`
|
||||
|
||||
第六阶段必须启用:
|
||||
|
||||
1. `sync_scene_assets`
|
||||
|
||||
### `sync_scene_assets` 流程
|
||||
|
||||
```text
|
||||
收到 sync_scene_assets
|
||||
-> 校验 sceneId
|
||||
-> 校验 sceneKind
|
||||
-> 写回 draftProfile.camp 或 draftProfile.landmarks
|
||||
-> 重建 assetCoverage.sceneAssets
|
||||
-> 重新编译地点卡 / 营地卡摘要
|
||||
-> 写入 assistant action_result
|
||||
-> 写入 checkpoint
|
||||
-> operation completed
|
||||
```
|
||||
|
||||
### camp 写回规则
|
||||
|
||||
当:
|
||||
|
||||
```ts
|
||||
sceneKind === 'camp'
|
||||
```
|
||||
|
||||
写回:
|
||||
|
||||
```ts
|
||||
draftProfile.camp
|
||||
```
|
||||
|
||||
### landmark 写回规则
|
||||
|
||||
当:
|
||||
|
||||
```ts
|
||||
sceneKind === 'landmark'
|
||||
```
|
||||
|
||||
写回:
|
||||
|
||||
```ts
|
||||
draftProfile.landmarks.find(...)
|
||||
```
|
||||
|
||||
## 10.3 修改 `customWorldAgentDraftCompiler.ts`
|
||||
|
||||
第六阶段它必须让:
|
||||
|
||||
1. `landmark` 卡摘要带出场景图状态
|
||||
2. `camp` 卡摘要带出场景图状态
|
||||
|
||||
### 推荐展示方式
|
||||
|
||||
在 `subtitle` 或 `summary` 中追加:
|
||||
|
||||
1. `背景图已就绪`
|
||||
2. `待生成背景图`
|
||||
|
||||
但不要把卡片变成技术表。
|
||||
|
||||
## 10.4 修改 `customWorldWorkSummaryService.ts`
|
||||
|
||||
第六阶段创作页面草稿卡应支持展示:
|
||||
|
||||
1. 已有多少场景具备背景图
|
||||
|
||||
第一版如果不想上具体数字,也至少要能体现:
|
||||
|
||||
- `场景资产进行中`
|
||||
|
||||
---
|
||||
|
||||
## 11. 前端实现方案
|
||||
|
||||
## 11.1 新增 `CustomWorldSceneAssetStudioModal.tsx`
|
||||
|
||||
### 来源
|
||||
|
||||
从当前 `CustomWorldEntityEditorModal.tsx` 中的 `SceneImageGenerationModal` 思路抽出,
|
||||
但改成可被 Agent 工作区调用的版本。
|
||||
|
||||
### props
|
||||
|
||||
```ts
|
||||
{
|
||||
profile: Pick<CustomWorldProfile, 'id' | 'name' | 'summary' | 'tone' | 'playerGoal' | 'settingText'>;
|
||||
scene: {
|
||||
id: string;
|
||||
kind: 'camp' | 'landmark';
|
||||
name: string;
|
||||
description: string;
|
||||
imageSrc?: string;
|
||||
};
|
||||
onPublishSuccess: (payload) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
### 功能
|
||||
|
||||
1. 输入场景 prompt
|
||||
2. 上传可选参考图
|
||||
3. 调用 `generateCustomWorldSceneImage(...)`
|
||||
4. 展示预览
|
||||
5. 保存并回调 `onPublishSuccess`
|
||||
|
||||
## 11.2 修改 `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
|
||||
当卡片类型为 `landmark` 或 `camp` 时,新增:
|
||||
|
||||
1. `场景背景图` 按钮
|
||||
2. 资产状态 badge
|
||||
|
||||
### 状态显示建议
|
||||
|
||||
1. `待生成背景图`
|
||||
2. `背景图已就绪`
|
||||
|
||||
## 11.3 修改 `CustomWorldAgentQuickActions.tsx`
|
||||
|
||||
当当前 focus card 为 `landmark` 或 `camp` 时,可显示:
|
||||
|
||||
- `生成场景背景图`
|
||||
|
||||
点击后:
|
||||
|
||||
1. 直接打开 `CustomWorldSceneAssetStudioModal`
|
||||
|
||||
## 11.4 修改 `CustomWorldAgentWorkspace.tsx`
|
||||
|
||||
新增状态:
|
||||
|
||||
```ts
|
||||
activeSceneAssetTarget?: {
|
||||
sceneId: string;
|
||||
sceneKind: 'camp' | 'landmark';
|
||||
} | null;
|
||||
showSceneAssetStudio: boolean;
|
||||
```
|
||||
|
||||
### 打开逻辑
|
||||
|
||||
1. 来自 detail panel
|
||||
2. 来自 quick actions
|
||||
|
||||
### 关闭逻辑
|
||||
|
||||
关闭不代表写回成功。
|
||||
|
||||
必须等:
|
||||
|
||||
1. 场景图生成完成并保存
|
||||
2. `sync_scene_assets` 成功
|
||||
|
||||
之后才刷新场景资产状态。
|
||||
|
||||
## 11.5 修改 `CustomWorldCreationHub.tsx`
|
||||
|
||||
第六阶段它必须支持草稿作品卡的“场景资产进度感”。
|
||||
|
||||
第一版至少做到:
|
||||
|
||||
1. 草稿卡可展示:
|
||||
- 场景资产进行中
|
||||
- 或若数量可得,则展示场景背景图完成数
|
||||
|
||||
---
|
||||
|
||||
## 12. 交互时序
|
||||
|
||||
## 12.1 打开场景图工坊
|
||||
|
||||
```text
|
||||
用户点击地点卡
|
||||
-> 打开 detail panel
|
||||
-> 点击“场景背景图”
|
||||
-> 前端打开 CustomWorldSceneAssetStudioModal
|
||||
```
|
||||
|
||||
## 12.2 保存场景图
|
||||
|
||||
```text
|
||||
用户在工坊中生成场景图
|
||||
-> 预览结果
|
||||
-> 点击保存
|
||||
-> 工坊得到 imageSrc + generatedSceneAssetId + prompt + model
|
||||
-> 前端调用 sync_scene_assets
|
||||
-> 服务端写回 draftProfile.camp 或 landmark
|
||||
-> 服务端重建 assetCoverage.sceneAssets
|
||||
-> 服务端重编译地点卡摘要
|
||||
-> 前端刷新 snapshot
|
||||
-> 工坊关闭
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 与第五阶段的兼容要求
|
||||
|
||||
## 13.1 兼容有图场景
|
||||
|
||||
如果某场景已经有:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedSceneAssetId`
|
||||
|
||||
仍允许继续打开工坊重新生成,再保存覆盖。
|
||||
|
||||
## 13.2 兼容无图场景
|
||||
|
||||
如果某场景完全无:
|
||||
|
||||
1. `imageSrc`
|
||||
2. `generatedSceneAssetId`
|
||||
|
||||
也允许打开工坊从零生成。
|
||||
|
||||
## 13.3 兼容新增场景
|
||||
|
||||
第四阶段新增的 `landmark` 一旦存在于 `draftProfile.landmarks` 中,立即允许进入场景图工坊。
|
||||
|
||||
---
|
||||
|
||||
## 14. 落地文件清单
|
||||
|
||||
## 14.1 frontend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldSceneAssetStudioModal.tsx`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
|
||||
2. `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
|
||||
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
|
||||
4. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
5. `src/services/ai.ts`
|
||||
6. `src/services/aiService.ts`
|
||||
|
||||
## 14.2 backend
|
||||
|
||||
必须新增:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentSceneAssetStateService.ts`
|
||||
|
||||
必须修改:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
|
||||
3. `server-node/src/services/customWorldAgentSessionStore.ts`
|
||||
4. `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
5. `server-node/src/services/sceneImageService.ts`
|
||||
6. `server-node/src/routes/runtimeRoutes.ts`
|
||||
|
||||
---
|
||||
|
||||
## 15. 测试要求
|
||||
|
||||
## 15.1 服务端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. `sync_scene_assets` 能正确写回 `camp`
|
||||
2. `sync_scene_assets` 能正确写回 `landmark`
|
||||
3. 写回后 `assetCoverage.sceneAssets` 状态更新
|
||||
4. 写回后地点卡 / 营地卡摘要更新
|
||||
5. 写回后 checkpoint 存在
|
||||
|
||||
## 15.2 前端测试
|
||||
|
||||
至少要补:
|
||||
|
||||
1. landmark/camp 卡详情可显示背景图入口
|
||||
2. quick actions 可打开场景图工坊
|
||||
3. 工坊保存成功后会触发 `sync_scene_assets`
|
||||
4. snapshot 刷新后场景卡显示新状态
|
||||
|
||||
## 15.3 手工回归
|
||||
|
||||
至少走这 4 条:
|
||||
|
||||
1. 为一个无图场景生成背景图
|
||||
2. 为营地生成背景图
|
||||
3. 返回 workspace 确认场景卡状态变化
|
||||
4. 返回创作页面确认草稿卡摘要变化
|
||||
|
||||
---
|
||||
|
||||
## 16. 第六阶段验收标准
|
||||
|
||||
做到以下几点,才算第六阶段真正完成:
|
||||
|
||||
1. 场景卡和营地卡已经可以接入并打开背景图工坊。
|
||||
2. 保存成功后,场景对象会写回 `imageSrc / generatedSceneAssetId / generatedScenePrompt / generatedSceneModel`。
|
||||
3. 场景资产状态会同步反映到 session snapshot 和场景卡摘要。
|
||||
4. 场景图接入不会阻塞继续文本创作。
|
||||
5. 第六阶段仍然不越界去做长尾自动补齐和发布逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 17. 一句话结论
|
||||
|
||||
第六阶段最重要的不是“让所有场景都立刻有图”,而是:
|
||||
|
||||
**先把草稿世界里的营地和关键场景,真正接到一条可预览、可保存、可写回的背景图工坊链路上。**
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,233 @@
|
||||
# AI Native 战斗单行为 Function PRD(2026-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 回合感保留
|
||||
|
||||
虽然不再做连续多轮击打,但每个战斗动作仍然视为消耗了一个战斗回合,因此:
|
||||
|
||||
- 技能冷却要按“本次动作结束后”推进
|
||||
- 恢复类动作可额外提供冷却推进收益
|
||||
- 物品动作在战斗态下也算一次战斗回合
|
||||
- 战斗中使用物品要先结算物品恢复 / buff / 额外冷却收益,再结算这一回合是否承受敌方单次反击
|
||||
|
||||
### 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. 文档、测试同步更新
|
||||
|
||||
补充落地备注(2026-04-20):
|
||||
|
||||
- `inventory_use` 在战斗中按战斗动作结算,而不是按非战斗库存动作直接短路返回
|
||||
- 战斗态 `inventory_use` 使用后要消费物品、累计 `itemsUsed`、推进 1 回合基础冷却,再叠加物品自带的 `cooldownReduction`
|
||||
- 若物品动作结算后战斗仍在继续,`storyText` 直接等于本次战斗结果文本,不触发 AI 续写
|
||||
|
||||
本期不做:
|
||||
|
||||
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 不识别而报错。
|
||||
@@ -0,0 +1,498 @@
|
||||
# AI 原生经典 RPG 体验对标引擎 PRD
|
||||
|
||||
更新时间:`2026-04-06`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份 PRD 建立在已有的:
|
||||
|
||||
- `AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md`
|
||||
- `AI_NATIVE_NARRATIVE_THREAD_ITEM_AND_WORLD_NPC_PRD_2026-04-06.md`
|
||||
|
||||
之上,进一步回答一个更明确的问题:
|
||||
|
||||
**如何让当前仓库里的 AI 原生剧情引擎,不只是“会生成剧情”,而是能在现有游戏框架中,驱动出对标《仙剑》《轩辕剑》《古剑》《黑神话:悟空》《博德之门》这类经典作品的角色扮演体验。**
|
||||
|
||||
这里的“对标”不是复制题材、桥段或美术风格,而是抽取这些作品背后的体验能力:
|
||||
|
||||
1. 让玩家记住角色,而不只是记住设定。
|
||||
2. 让世界里的地点、旧物、传闻、队友、任务彼此互相讲同一件事。
|
||||
3. 让玩家的选择、立场、关系、误判、探索真正改变后续体验。
|
||||
4. 让剧情推进同时拥有“作者性”和“系统性”。
|
||||
|
||||
一句话目标:
|
||||
|
||||
**把当前项目的 AI 原生叙事,升级成一种能稳定产出“经典单机 RPG 体验质感”的剧情引擎。**
|
||||
|
||||
## 1. 研究结论先说
|
||||
|
||||
综合参考对象后,可以把这几类经典体验抽象成 5 个核心方向:
|
||||
|
||||
1. `仙剑` 型体验
|
||||
- 强角色记忆点
|
||||
- “人”和“情”优先
|
||||
- 主线、支线、传记、碎片化叙事共同塑造角色
|
||||
|
||||
2. `轩辕剑` 型体验
|
||||
- 历史 / 神话 /文化意象共同构成宏大冲突
|
||||
- 大时代与个人成长同时成立
|
||||
- 系统玩法本身带文化与世界观意味
|
||||
|
||||
3. `古剑` 型体验
|
||||
- 世界观先行
|
||||
- 主题先行
|
||||
- 角色命题、支线补完、衍生叙事共同构成厚世界
|
||||
|
||||
4. `黑神话` 型体验
|
||||
- 空间本身讲故事
|
||||
- 物件、残痕、命名、演出都带文化锚点
|
||||
- 旅程像一次带试炼感的穿行,而不是纯任务导航
|
||||
|
||||
5. `博德之门` 型体验
|
||||
- 队友强反应
|
||||
- 选择有代价
|
||||
- 关系状态、立场差异、任务分支和系统规则一起驱动叙事
|
||||
|
||||
对当前项目来说,这意味着剧情引擎必须补的,不是更多文案,而是下面 10 项能力:
|
||||
|
||||
1. 世界线程图谱
|
||||
2. 题材适配层
|
||||
3. 角色命题与秘密档案
|
||||
4. 队友反应与关系矩阵
|
||||
5. 信息可见性裁剪
|
||||
6. 地点 / 物件 / 文书 / 残痕的叙事编译
|
||||
7. 情境导演与节奏控制
|
||||
8. 线程 -> 合约 -> 信号推进
|
||||
9. 回响与长期记忆
|
||||
10. 当前框架可落地的 orchestration 主链
|
||||
|
||||
## 2. 经典作品拆解
|
||||
|
||||
## 2.1 从《仙剑》系列提炼什么
|
||||
|
||||
《仙剑》最值得提炼的,不是仙侠题材,而是:
|
||||
|
||||
1. 角色与情感先于设定说明
|
||||
2. 玩家会因为“人”和“情”记住剧情
|
||||
3. 主线之外的角色剧情、人物传记、碎片信息都在持续加深理解
|
||||
4. 角色魅力是分阶段投放,不是一口气灌输
|
||||
|
||||
对引擎的要求就是:
|
||||
|
||||
1. 每个重点角色都必须有“高光入口”
|
||||
2. 角色认知要通过多载体逐步加深
|
||||
3. 情感关系不能只挂在恋爱线,要覆盖友情、亲情、师承、旧债、牺牲、错过
|
||||
4. 碎片化叙事必须和主线、支线互文,而不是散落设定
|
||||
|
||||
## 2.2 从《轩辕剑》系列提炼什么
|
||||
|
||||
《轩辕剑》最值得提炼的,不是具体朝代,而是:
|
||||
|
||||
1. 历史与神话共存
|
||||
2. 宏观时代与个人命运互相牵引
|
||||
3. 每一代往往有明确中心主题
|
||||
4. 世界里的神器、法宝、炼妖壶、符鬼等系统并不是纯玩法道具,而是世界观的一部分
|
||||
|
||||
对引擎的要求就是:
|
||||
|
||||
1. 每个世界必须有明确的大时代冲突
|
||||
2. 每段主线必须能同时看到“苍生线”和“个人线”
|
||||
3. 每一轮内容生成都要知道自己服务的是哪条主题轴
|
||||
4. 系统物件、战斗能力、资源名称、任务机制都要与世界观绑定
|
||||
|
||||
## 2.3 从《古剑》系列提炼什么
|
||||
|
||||
《古剑》最值得提炼的,不是台词风格,而是:
|
||||
|
||||
1. 世界观不是背景板,而是叙事发动机
|
||||
2. 主题是预先确定的,比如“重生”“问道”
|
||||
3. 游戏中只展示世界的一角,但能感到背后有更大的历史层
|
||||
4. 支线、小说、传记、远古设定共同构成世界厚度
|
||||
|
||||
对引擎的要求就是:
|
||||
|
||||
1. 先生成“世界故事图谱”,再生成角色和剧情
|
||||
2. 每个世界必须有自己的主题母题
|
||||
3. 重点角色都要有“命题”
|
||||
4. 支线不能只是奖励入口,而要承担世界观展开和人物补完
|
||||
|
||||
## 2.4 从《黑神话:悟空》提炼什么
|
||||
|
||||
《黑神话:悟空》最值得提炼的,不是神话题材本身,而是:
|
||||
|
||||
1. 空间叙事强
|
||||
2. 旅程感强
|
||||
3. 文化意象直接进入地点、敌人、物件、建筑和命名
|
||||
4. 玩家不是靠大段讲解理解世界,而是靠穿行、观察、搏斗和残痕去感受
|
||||
|
||||
对引擎的要求就是:
|
||||
|
||||
1. 场景必须有“故事残痕层”
|
||||
2. 路线推进要像试炼 / 朝圣 / 追索 / 深入禁地,而不是只弹任务文本
|
||||
3. 重点物件必须是文化锚点和旧事证人
|
||||
4. 敌人与地标也应属于叙事载体,而不只是战斗内容
|
||||
|
||||
## 2.5 从《博德之门》提炼什么
|
||||
|
||||
《博德之门》最值得提炼的,不是西式奇幻题材,而是:
|
||||
|
||||
1. 队友是强叙事引擎
|
||||
2. 不同角色对同一行为会有不同立场反应
|
||||
3. 关系推进有信任门槛
|
||||
4. 玩家选择会改变关系、任务理解和队伍结构
|
||||
5. 系统层会用可控的“认可 / 不认可”“信任 / 不信任”来表达复杂反应,而不是无限写分支
|
||||
|
||||
对引擎的要求就是:
|
||||
|
||||
1. 每个重点队友都要有可追踪的立场轴和信任轴
|
||||
2. 对同一选择,队友必须出现差异化反应
|
||||
3. 关系状态要进入后续任务、聊天、协战、赠礼、剧情揭示
|
||||
4. 系统必须允许“有限分支 + 强反馈”,而不是追求不可控的全分支写作
|
||||
|
||||
## 3. 对标能力矩阵
|
||||
|
||||
## 3.1 引擎必须支持的体验支柱
|
||||
|
||||
建议把“经典 RPG 体验”拆成下面 8 根支柱:
|
||||
|
||||
1. 角色羁绊支柱
|
||||
2. 主题表达支柱
|
||||
3. 世界厚度支柱
|
||||
4. 路线试炼支柱
|
||||
5. 选择后果支柱
|
||||
6. 队友反应支柱
|
||||
7. 叙事载体支柱
|
||||
8. 回响记忆支柱
|
||||
|
||||
## 3.2 支柱与经典作品的对照
|
||||
|
||||
| 支柱 | 仙剑 | 轩辕剑 | 古剑 | 黑神话 | 博德之门 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 角色羁绊 | 强 | 中 | 强 | 中 | 强 |
|
||||
| 主题表达 | 强 | 强 | 强 | 中到强 | 强 |
|
||||
| 世界厚度 | 中到强 | 强 | 强 | 强 | 强 |
|
||||
| 路线试炼 | 中 | 中 | 中 | 强 | 中 |
|
||||
| 选择后果 | 中 | 中 | 中 | 轻 | 强 |
|
||||
| 队友反应 | 中 | 中 | 中 | 轻 | 强 |
|
||||
| 叙事载体 | 中 | 强 | 强 | 强 | 强 |
|
||||
| 回响记忆 | 中 | 强 | 强 | 中 | 强 |
|
||||
|
||||
结论不是“每个游戏都做一样多”,而是:
|
||||
|
||||
**要想对标这些经典作品的总和体验,引擎不能只强其中一项。**
|
||||
|
||||
## 4. 面向当前项目的引擎能力设计
|
||||
|
||||
## 4.1 世界线程图谱
|
||||
|
||||
用于承载:
|
||||
|
||||
- 《轩辕剑》式的大时代冲突
|
||||
- 《古剑》式的远古 / 旧史 / 深层设定
|
||||
- 《仙剑》式的主线与碎片化叙事互文
|
||||
|
||||
最低要求:
|
||||
|
||||
1. 每个世界有 `明线线程`
|
||||
2. 每个世界有 `暗线线程`
|
||||
3. 每个世界有 `旧事伤痕`
|
||||
4. 每个世界有 `主题母题`
|
||||
|
||||
## 4.2 角色命题与秘密档案
|
||||
|
||||
用于承载:
|
||||
|
||||
- 《仙剑》式角色高光与感情曲线
|
||||
- 《古剑》式角色命题与主题性成长
|
||||
- 《博德之门》式角色秘密与立场差异
|
||||
|
||||
每个重点角色必须有:
|
||||
|
||||
1. 外显身份
|
||||
2. 当前压力
|
||||
3. 表面目标
|
||||
4. 真实目标
|
||||
5. 已付代价
|
||||
6. 关系负债
|
||||
7. 禁区
|
||||
8. 可触发反应的关键词
|
||||
|
||||
## 4.3 队友反应与关系矩阵
|
||||
|
||||
这是当前项目对标《博德之门》最需要补的一块。
|
||||
|
||||
建议每个重点队友都至少维护:
|
||||
|
||||
```ts
|
||||
interface CompanionStanceProfile {
|
||||
trust: number;
|
||||
warmth: number;
|
||||
ideologicalFit: number;
|
||||
fearOrGuard: number;
|
||||
loyalty: number;
|
||||
currentConflictTag?: string | null;
|
||||
recentApprovals: string[];
|
||||
recentDisapprovals: string[];
|
||||
}
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
1. `trust`
|
||||
- 决定是否愿意跟随你深入风险。
|
||||
|
||||
2. `warmth`
|
||||
- 决定情感表达密度。
|
||||
|
||||
3. `ideologicalFit`
|
||||
- 决定在价值观选择上的反应强度。
|
||||
|
||||
4. `fearOrGuard`
|
||||
- 决定低关系阶段是不是更容易误会、回避、抗拒。
|
||||
|
||||
5. `loyalty`
|
||||
- 决定关键节点是否站队。
|
||||
|
||||
## 4.4 信息可见性层
|
||||
|
||||
这是对标《古剑》的世界层深度、对标《仙剑》的分段投放、对标《博德之门》的可控分支,以及修复当前自定义世界 prompt 泄露问题的共同底座。
|
||||
|
||||
核心要求:
|
||||
|
||||
1. 角色知道什么
|
||||
2. 玩家知道什么
|
||||
3. 角色此刻愿意说什么
|
||||
4. 当前场景允许模型看到什么
|
||||
|
||||
必须分开建模。
|
||||
|
||||
## 4.5 叙事载体编译层
|
||||
|
||||
这是对标《黑神话》《轩辕剑》《古剑》最关键的一层。
|
||||
|
||||
载体不能只限于装备物品,应统一抽象为:
|
||||
|
||||
1. 遗物
|
||||
2. 证物
|
||||
3. 文书
|
||||
4. 材料
|
||||
5. 禁物
|
||||
6. 装置
|
||||
7. 记忆碎片
|
||||
8. 残痕场景
|
||||
|
||||
每个载体都要有:
|
||||
|
||||
1. 可见线索
|
||||
2. 见证痕
|
||||
3. 未完成问题
|
||||
4. 当前出现理由
|
||||
5. 后续反应钩子
|
||||
|
||||
## 4.6 情境导演与节奏层
|
||||
|
||||
这是对标《仙剑》的情感推进、《黑神话》的旅程压迫、《博德之门》的分支张力时最重要的“节奏控制器”。
|
||||
|
||||
导演层要先判断:
|
||||
|
||||
1. 当前是情感深化回合,还是冲突升级回合
|
||||
2. 当前应推进明线、暗线、关系线、还是主题线
|
||||
3. 当前需要推前台的是角色、地点、还是物件
|
||||
4. 当前披露预算应该是低、中还是高
|
||||
|
||||
没有导演层,AI 文本会持续飘散。
|
||||
|
||||
## 4.7 线程 -> 合约 -> 信号推进
|
||||
|
||||
这是把经典单机 RPG 的作者性故事,转成 AI 原生可持续运行结构的关键。
|
||||
|
||||
统一抽象如下:
|
||||
|
||||
1. 线程
|
||||
- 这段故事在讲哪条线。
|
||||
|
||||
2. 合约
|
||||
- 当前线的阶段目标、参与者、条件、失败态与回报。
|
||||
|
||||
3. 信号
|
||||
- 玩家做了什么,导致哪个关系、地点、物件、真相片段发生变化。
|
||||
|
||||
## 4.8 回响与长期记忆
|
||||
|
||||
这是决定剧情是否像“经典作品”的最后一层。
|
||||
|
||||
玩家之所以会觉得这些作品有余味,不是因为文本多,而是因为:
|
||||
|
||||
1. 旧事会回来
|
||||
2. 旧物会再被提起
|
||||
3. 旧误解会被翻案
|
||||
4. 旧角色会因为你做过的事改变口风
|
||||
|
||||
因此系统必须维护:
|
||||
|
||||
1. 事件记忆
|
||||
2. 关系记忆
|
||||
3. 线索记忆
|
||||
4. 误解记忆
|
||||
5. 已揭示真相记忆
|
||||
|
||||
## 5. 当前框架接入方案
|
||||
|
||||
## 5.1 `src/services/customWorld.ts`
|
||||
|
||||
从“批量生成 NPC 和地标”升级为:
|
||||
|
||||
1. 先生成 `ThemePack`
|
||||
2. 再生成 `WorldStoryGraph`
|
||||
3. 再生成 `ActorNarrativeProfile`
|
||||
4. 最后补 `backstoryReveal / skills / initialItems`
|
||||
|
||||
它将成为当前项目里最接近“古剑式世界观先行 + 轩辕剑式宏大主题”的入口。
|
||||
|
||||
## 5.2 `src/services/prompt.ts`
|
||||
|
||||
从“组装上下文”升级为:
|
||||
|
||||
1. 读取 `VisibilitySlice`
|
||||
2. 读取 `SceneNarrativeDirective`
|
||||
3. 只注入当前阶段可见、可说、可推的最小剧情上下文
|
||||
|
||||
它将成为:
|
||||
|
||||
- 对标《博德之门》强反应又可控
|
||||
- 对标《仙剑》分阶段角色理解
|
||||
- 修复当前全知视角泄露
|
||||
|
||||
的核心模块。
|
||||
|
||||
## 5.3 `src/data/npcInteractions.ts`
|
||||
|
||||
从“关系规则函数集合”升级为:
|
||||
|
||||
1. 首遇状态机
|
||||
2. 队友立场矩阵
|
||||
3. 认可 / 不认可反馈
|
||||
4. 关系冲突 tag
|
||||
5. 私聊 / 队伍 / 营地事件触发
|
||||
|
||||
它将承担当前项目里最接近《博德之门》队友系统和《仙剑》角色关系成长的部分。
|
||||
|
||||
## 5.4 `src/services/questDirector.ts`
|
||||
|
||||
从“任务导演”升级为:
|
||||
|
||||
1. 剧情线程导演
|
||||
2. 合约生成器
|
||||
3. 信号推进器
|
||||
4. 阶段揭示器
|
||||
|
||||
它将承担对标《轩辕剑》宏观主线推进和《博德之门》分支任务反馈的主链。
|
||||
|
||||
## 5.5 `src/data/runtimeItemDirector.ts` / `src/data/runtimeItemNarrative.ts`
|
||||
|
||||
从“运行时奖励导演”升级为:
|
||||
|
||||
1. 通用叙事载体编译器
|
||||
2. 重点物件故事指纹生成器
|
||||
3. 角色 / 场景 / 势力 / 旧事的回响载体
|
||||
|
||||
它将承担对标《黑神话》物件文化锚点、对标《轩辕剑》器物世界观、对标《古剑》旧史残痕的能力。
|
||||
|
||||
## 5.6 `src/hooks/useStoryGeneration.ts`
|
||||
|
||||
从“剧情总 orchestrator”收束为:
|
||||
|
||||
1. 读取导演结果
|
||||
2. 发起对应 contract
|
||||
3. 驱动生成
|
||||
4. 回写记忆与信号
|
||||
|
||||
不要继续把越来越多叙事细节直接塞进这个 hook,而是让它只做总线协调。
|
||||
|
||||
## 6. 体验验收标准
|
||||
|
||||
如果要说“能对标经典单机 RPG 体验”,至少要达到下面这些结果。
|
||||
|
||||
## 6.1 角色体验
|
||||
|
||||
1. 玩家在一次完整体验后,能明确记住至少 `3~5` 个队友 / 核心角色的个性、矛盾和关键旧事。
|
||||
2. 低好感角色不会只是“冷淡”,而是会带明确压力、错位说辞和暗线钩子。
|
||||
3. 高关系角色会在聊天、任务、协战、赠礼、事件节点中显著改变表达与立场。
|
||||
|
||||
## 6.2 世界体验
|
||||
|
||||
1. 玩家能感到世界背后有更深层的旧史与暗线,而不是所有信息都在主线上直接交代。
|
||||
2. 场景、地点、支线、人物传记、物件描述之间会互相印证。
|
||||
3. 世界主题在命名、系统、任务、人物冲突上持续一致。
|
||||
|
||||
## 6.3 选择体验
|
||||
|
||||
1. 玩家选择能被至少一名队友明确认可或反对。
|
||||
2. 至少一部分选择会影响后续任务理解、关系推进、额外剧情或可见信息。
|
||||
3. 系统既要让选择有重量,又不能因为分支爆炸而失控。
|
||||
|
||||
## 6.4 旅程体验
|
||||
|
||||
1. 场景推进要有“试炼 / 追索 / 深入 / 回望”的旅程感。
|
||||
2. 不是所有叙事都靠对话框完成,空间和载体也必须承担讲故事的职责。
|
||||
3. 玩家会因为一个地标、一个旧物、一次反应,主动去拼出暗线。
|
||||
|
||||
## 7. 推荐落地顺序
|
||||
|
||||
## 阶段 A:先补对标经典作品的共同底座
|
||||
|
||||
优先做:
|
||||
|
||||
1. `ThemePack`
|
||||
2. `WorldStoryGraph`
|
||||
3. `ActorNarrativeProfile`
|
||||
4. `VisibilitySlice`
|
||||
|
||||
## 阶段 B:优先把当前项目最能出效果的两条链做强
|
||||
|
||||
1. 队友 / NPC 关系反应链
|
||||
2. 运行时物件 / 场景残痕叙事链
|
||||
|
||||
这是当前最容易直接提升“像经典 RPG”的地方。
|
||||
|
||||
## 阶段 C:把任务和主线推进改成线程化
|
||||
|
||||
重点补:
|
||||
|
||||
1. 线程
|
||||
2. 合约
|
||||
3. 信号
|
||||
4. 阶段揭示
|
||||
|
||||
## 阶段 D:补营地 / 旅途中队友事件
|
||||
|
||||
这是当前项目对标《仙剑》与《博德之门》体验非常关键的一步。
|
||||
|
||||
建议新增:
|
||||
|
||||
1. 营地对话
|
||||
2. 旅途中短反应
|
||||
3. 关键选择后的队友插话
|
||||
4. 队友之间的互相评价
|
||||
|
||||
## 阶段 E:做经典体验压力测试
|
||||
|
||||
至少要用 5 类体验场景去压测引擎:
|
||||
|
||||
1. 情感型主线
|
||||
2. 历史 / 神话型大事件
|
||||
3. 世界观层层揭示型流程
|
||||
4. 旅程试炼型场景链
|
||||
5. 队友强反应分支型流程
|
||||
|
||||
## 8. 一句话结论
|
||||
|
||||
要让当前项目的 AI 原生剧情引擎真正对标《仙剑》《轩辕剑》《古剑》《黑神话》《博德之门》这些经典作品,关键不是去模仿哪一种题材,而是让引擎同时具备:
|
||||
|
||||
- 让人记住角色的能力
|
||||
- 让世界互相说话的能力
|
||||
- 让选择产生后果的能力
|
||||
- 让地点与物件承担叙事的能力
|
||||
- 让长线回响沉淀下来的能力
|
||||
|
||||
只有这些能力一起成立,当前框架里跑出来的体验,才会从“AI 会写剧情”,真正跨到“AI 能驱动经典 RPG 质感”。
|
||||
554
docs/prd/AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md
Normal file
554
docs/prd/AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md
Normal file
@@ -0,0 +1,554 @@
|
||||
# AI 原生跨题材剧情引擎 PRD
|
||||
|
||||
更新时间:`2026-04-06`
|
||||
|
||||
## 0. 定位
|
||||
|
||||
这份 PRD 的目标不是为某一种题材写一套“更会编故事的文案系统”,而是设计一套:
|
||||
|
||||
**可适配奇幻、武侠、仙侠、科幻、悬疑、恐怖、末世、都市、校园、神话等多种题材的 AI 原生游戏剧情引擎。**
|
||||
|
||||
它应该解决的不是单一题材里的句子风格,而是更底层的问题:
|
||||
|
||||
1. 世界的明线、暗线如何被系统化组织。
|
||||
2. 角色、地点、物件、文书、怪物、装置、尸体、遗迹这些叙事载体如何共同讲故事。
|
||||
3. 玩家当前能知道什么、误以为知道什么、还不能知道什么,如何被稳定控制。
|
||||
4. AI 如何负责叙事生成,本地规则如何负责边界、状态、可见性、推进信号与玩法编译。
|
||||
|
||||
一句话定位:
|
||||
|
||||
**它是一个“剧情引擎层”,不是一个“某题材内容包”。**
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
这套引擎要同时满足 6 个目标:
|
||||
|
||||
1. 跨题材
|
||||
- 核心语义不写死在武侠、奇幻、修仙、蒸汽朋克等具体题材上。
|
||||
|
||||
2. AI 原生
|
||||
- 剧情文本、现场张力、角色表述、线索回响由 AI 参与生成,而不是只做静态模板替换。
|
||||
|
||||
3. 规则可控
|
||||
- 世界状态、信息泄露边界、关系推进、任务推进、奖励发放仍由本地规则约束。
|
||||
|
||||
4. 叙事网状化
|
||||
- 故事不只存在于主线任务里,而是分布在角色、物件、地点、事件余波与传闻中。
|
||||
|
||||
5. 可扩展
|
||||
- 新增题材时,优先新增“题材适配层”,而不是推翻剧情引擎本体。
|
||||
|
||||
6. 可验证
|
||||
- 能明确验收“是否有故事感”“是否埋得住暗线”“是否越权泄露”“是否跨题材仍成立”。
|
||||
|
||||
## 2. 参考方法抽象
|
||||
|
||||
本次设计参考的是成熟叙事游戏的方法,不是照搬具体剧情。
|
||||
|
||||
## 2.1 可借鉴的方法来源
|
||||
|
||||
1. CRPG 方法
|
||||
- 代表思路:角色秘密、阵营立场、任务分支、物件与角色的反应联动。
|
||||
- 可借鉴点:角色不是独立设定卡,而是世界冲突中的活节点。
|
||||
|
||||
2. 沉浸式侦查 / 推理方法
|
||||
- 代表思路:线索不是一次性交代,而是靠地点、证物、口供、误导与缺失共同成立。
|
||||
- 可借鉴点:信息差、误判、再解释,是故事感的重要来源。
|
||||
|
||||
3. 系统叙事方法
|
||||
- 代表思路:事件、状态、关系、资源变化会自然生成“像故事”的结果。
|
||||
- 可借鉴点:引擎应先保证状态与因果,再让 AI 把它叙事化。
|
||||
|
||||
4. Roguelike / 重复游玩叙事方法
|
||||
- 代表思路:角色关系、旧伤、遗物、失败记录、阶段揭示会在多轮体验中叠加意义。
|
||||
- 可借鉴点:故事不是一次性讲完,而是通过回响与累积形成。
|
||||
|
||||
5. 强氛围题材方法
|
||||
- 代表思路:名字、物件、俗称、禁忌称呼、残损意象本身就携带故事。
|
||||
- 可借鉴点:叙事载体不只靠大段说明,也能靠命名与残痕表达。
|
||||
|
||||
## 2.2 抽象结论
|
||||
|
||||
综合这些方法后,这套引擎应固定采用下面这 5 个叙事原则:
|
||||
|
||||
1. 故事必须网状分布,不能只挂在主线任务上。
|
||||
2. 信息披露必须分层,不能让模型默认全知。
|
||||
3. 低关系、低信任、低理解阶段,不能减少故事密度,只能减少披露深度。
|
||||
4. 物件与地点必须是故事证人,而不只是功能容器。
|
||||
5. 题材差异应该主要落在“词汇、意象、制度、冲突形式”上,而不是改变剧情引擎基本语法。
|
||||
|
||||
## 3. 引擎核心原则
|
||||
|
||||
1. AI 负责叙事表达,本地负责规则裁决。
|
||||
2. 世界先于角色,角色先于对白,状态先于文案。
|
||||
3. 所有剧情都必须能回到“谁知道什么、谁想隐藏什么、谁正在承受什么”。
|
||||
4. 明线、暗线、代价线、回响线是所有题材共通的最小叙事单元。
|
||||
5. 信息可见性必须被数据化,而不能只靠 prompt 口头提醒。
|
||||
6. 引擎关注“剧情语法”,题材包只负责“表现词汇”。
|
||||
|
||||
## 4. 引擎总架构
|
||||
|
||||
建议把 AI 原生剧情引擎拆成 8 个层:
|
||||
|
||||
1. 世界语义层
|
||||
2. 题材适配层
|
||||
3. 角色与阵营层
|
||||
4. 信息可见性层
|
||||
5. 情境导演层
|
||||
6. 合约与信号推进层
|
||||
7. 叙事载体编译层
|
||||
8. 记忆与回响层
|
||||
|
||||
关系如下:
|
||||
|
||||
```text
|
||||
世界语义层
|
||||
-> 题材适配层
|
||||
-> 角色与阵营层
|
||||
-> 信息可见性层
|
||||
-> 情境导演层
|
||||
-> 合约与信号推进层
|
||||
-> 叙事载体编译层
|
||||
-> 记忆与回响层
|
||||
```
|
||||
|
||||
## 5. 世界语义层
|
||||
|
||||
## 5.1 目标
|
||||
|
||||
让所有题材都先被翻译成一套统一的世界叙事骨架,而不是直接开始生成角色和对白。
|
||||
|
||||
## 5.2 建议的数据结构
|
||||
|
||||
```ts
|
||||
interface StoryThread {
|
||||
id: string;
|
||||
title: string;
|
||||
visibility: 'visible' | 'hidden';
|
||||
summary: string;
|
||||
conflictType: string;
|
||||
stakes: string;
|
||||
involvedFactionIds: string[];
|
||||
involvedActorIds: string[];
|
||||
relatedLocationIds: string[];
|
||||
}
|
||||
|
||||
interface StoryScar {
|
||||
id: string;
|
||||
title: string;
|
||||
pastEvent: string;
|
||||
publicResidue: string;
|
||||
hiddenTruth: string;
|
||||
relatedActorIds: string[];
|
||||
relatedLocationIds: string[];
|
||||
}
|
||||
|
||||
interface StoryMotif {
|
||||
id: string;
|
||||
label: string;
|
||||
semanticRole: 'institution' | 'ritual' | 'technology' | 'taboo' | 'ruin' | 'memory' | 'resource' | 'creature';
|
||||
lexicalHints: string[];
|
||||
}
|
||||
|
||||
interface WorldStoryGraph {
|
||||
visibleThreads: StoryThread[];
|
||||
hiddenThreads: StoryThread[];
|
||||
scars: StoryScar[];
|
||||
motifs: StoryMotif[];
|
||||
}
|
||||
```
|
||||
|
||||
## 5.3 为什么它必须在最前面
|
||||
|
||||
没有这层图谱,就会出现这类问题:
|
||||
|
||||
1. 角色各自有设定,但彼此没有共享暗线。
|
||||
2. 物件命名很酷,但和世界冲突没有关系。
|
||||
3. 场景有氛围,但和主要矛盾不互相印证。
|
||||
4. 每次 AI 输出都像重新发明一个宇宙。
|
||||
|
||||
## 6. 题材适配层
|
||||
|
||||
## 6.1 目标
|
||||
|
||||
让题材差异变成一个可替换的“表现层”,而不是把剧情引擎本体写死成某一类世界观。
|
||||
|
||||
## 6.2 建议的数据结构
|
||||
|
||||
```ts
|
||||
interface ThemePack {
|
||||
id: string;
|
||||
displayName: string;
|
||||
toneRange: string[];
|
||||
institutionLexicon: string[];
|
||||
tabooLexicon: string[];
|
||||
artifactClasses: string[];
|
||||
actorArchetypes: string[];
|
||||
conflictForms: string[];
|
||||
clueForms: string[];
|
||||
namingPatterns: string[];
|
||||
revealStyles: string[];
|
||||
}
|
||||
```
|
||||
|
||||
## 6.3 题材适配层负责什么
|
||||
|
||||
它只负责:
|
||||
|
||||
1. 把“机构”翻译成宗门、财团、学会、调查局、帮派、舰队、公司、教团等。
|
||||
2. 把“禁忌”翻译成邪术、封印、机密协议、校园旧规、污染区准则等。
|
||||
3. 把“叙事载体”翻译成遗物、枪械、芯片、病例、证物、祭器、录像带、样本、航图等。
|
||||
4. 把“冲突形式”翻译成宫廷斗争、公司内斗、调查失踪、阵营战争、神话追索、生存竞争等。
|
||||
|
||||
它不负责:
|
||||
|
||||
1. 决定角色到底知道什么。
|
||||
2. 决定剧情推进是否合法。
|
||||
3. 决定哪些信息此刻允许披露。
|
||||
|
||||
## 7. 角色与阵营层
|
||||
|
||||
## 7.1 角色不是“背景文本”,而是“叙事立场体”
|
||||
|
||||
每个角色都必须被拆成下面几个面向:
|
||||
|
||||
1. 外显身份
|
||||
2. 当前处境
|
||||
3. 表面目标
|
||||
4. 真实目标
|
||||
5. 隐藏关系
|
||||
6. 已付代价
|
||||
7. 不愿被碰的禁区
|
||||
8. 会触发反应的关键词
|
||||
|
||||
## 7.2 建议的数据结构
|
||||
|
||||
```ts
|
||||
interface ActorNarrativeProfile {
|
||||
publicMask: string;
|
||||
firstContactMask: string;
|
||||
visibleLine: string;
|
||||
hiddenLine: string;
|
||||
contradiction: string;
|
||||
debtOrBurden: string;
|
||||
taboo: string;
|
||||
immediatePressure: string;
|
||||
relatedThreadIds: string[];
|
||||
relatedScarIds: string[];
|
||||
reactionHooks: string[];
|
||||
}
|
||||
```
|
||||
|
||||
## 7.3 低关系角色的引擎规则
|
||||
|
||||
低关系、低好感、低信任角色必须满足:
|
||||
|
||||
1. 有压力
|
||||
2. 有保留
|
||||
3. 有错位
|
||||
4. 有反应钩子
|
||||
|
||||
不能只是:
|
||||
|
||||
1. 说得少
|
||||
2. 更冷淡
|
||||
3. 更短句
|
||||
|
||||
正确做法应该是:
|
||||
|
||||
- 披露深度更低
|
||||
- 戏剧张力更高
|
||||
- 错误说辞更多
|
||||
- 观察与试探更明显
|
||||
|
||||
## 8. 信息可见性层
|
||||
|
||||
## 8.1 这是 AI 原生剧情引擎的核心
|
||||
|
||||
如果不把“可见性”数据化,AI 叙事会天然滑向全知视角。
|
||||
|
||||
因此必须明确区分:
|
||||
|
||||
1. 事实是否存在
|
||||
2. 玩家是否知道
|
||||
3. 当前角色是否愿意说
|
||||
4. 当前 prompt 是否允许注入
|
||||
5. 玩家是否只是误以为知道
|
||||
|
||||
## 8.2 建议的数据结构
|
||||
|
||||
```ts
|
||||
interface KnowledgeFact {
|
||||
id: string;
|
||||
content: string;
|
||||
ownerActorIds: string[];
|
||||
relatedThreadIds: string[];
|
||||
visibility: 'public' | 'discoverable' | 'private' | 'forbidden';
|
||||
}
|
||||
|
||||
interface VisibilitySlice {
|
||||
factIds: string[];
|
||||
sayableFactIds: string[];
|
||||
inferredFactIds: string[];
|
||||
forbiddenFactIds: string[];
|
||||
misdirectionHints: string[];
|
||||
}
|
||||
```
|
||||
|
||||
## 8.3 运行时规则
|
||||
|
||||
1. prompt 只吃 `VisibilitySlice`
|
||||
2. 未解锁章节不等于不存在,但不能进当前 prompt
|
||||
3. 角色知道某事,不等于此刻愿意承认
|
||||
4. 玩家接触到线索,不等于系统要直接盖章真相
|
||||
|
||||
## 9. 情境导演层
|
||||
|
||||
## 9.1 目标
|
||||
|
||||
每一轮剧情生成都不是“让 AI 自由写”,而是先由导演层判断:
|
||||
|
||||
1. 此刻最重要的压力是什么
|
||||
2. 谁在主导场面
|
||||
3. 当前最适合推进的是明线、暗线还是关系线
|
||||
4. 哪些叙事载体应该被推到前台
|
||||
|
||||
## 9.2 导演层输入
|
||||
|
||||
- 当前场景
|
||||
- 当前实体
|
||||
- 当前关系状态
|
||||
- 当前可见信息
|
||||
- 最近信号变化
|
||||
- 玩家上一步行动
|
||||
- 尚未回响的故事线程
|
||||
|
||||
## 9.3 导演层输出
|
||||
|
||||
```ts
|
||||
interface SceneNarrativeDirective {
|
||||
primaryPressure: string;
|
||||
activeThreadIds: string[];
|
||||
foregroundActorIds: string[];
|
||||
foregroundCarrierIds: string[];
|
||||
revealBudget: 'low' | 'medium' | 'high';
|
||||
emotionalCadence: 'tense' | 'curious' | 'hostile' | 'intimate' | 'tragic' | 'mysterious';
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 合约与信号推进层
|
||||
|
||||
## 10.1 目标
|
||||
|
||||
让剧情推进不依赖纯脚本,而是依赖“意图 -> 合约 -> 信号”。
|
||||
|
||||
## 10.2 统一抽象
|
||||
|
||||
1. 意图
|
||||
- 当前想推动什么关系、冲突、调查或获取。
|
||||
|
||||
2. 合约
|
||||
- 把意图翻译成可追踪的步骤、条件、参与者与回报。
|
||||
|
||||
3. 信号
|
||||
- 玩家行动、地点变化、物件获取、关系变化、战斗结果、情报拼接后触发推进。
|
||||
|
||||
## 10.3 为什么这层跨题材都成立
|
||||
|
||||
因为不管是:
|
||||
|
||||
- 武侠寻仇
|
||||
- 科幻调查
|
||||
- 校园秘密
|
||||
- 末世生存
|
||||
- 神话追索
|
||||
|
||||
它们最终都能抽象成:
|
||||
|
||||
- 某种线索被拿到
|
||||
- 某个误会被确认或打破
|
||||
- 某种关系被推进或撕裂
|
||||
- 某个真相片段被解锁
|
||||
|
||||
## 11. 叙事载体编译层
|
||||
|
||||
## 11.1 不要只把“物品”当成装备
|
||||
|
||||
跨题材剧情引擎里,叙事载体不应仅仅是“装备 / 道具”,而应统一抽象成:
|
||||
|
||||
```ts
|
||||
type NarrativeCarrierType =
|
||||
| 'artifact'
|
||||
| 'document'
|
||||
| 'evidence'
|
||||
| 'device'
|
||||
| 'resource'
|
||||
| 'corpse'
|
||||
| 'sample'
|
||||
| 'relic'
|
||||
| 'ritual_object'
|
||||
| 'memory_fragment';
|
||||
```
|
||||
|
||||
## 11.2 每个载体必须包含的叙事指纹
|
||||
|
||||
```ts
|
||||
interface CarrierStoryFingerprint {
|
||||
visibleClue: string;
|
||||
witnessMark: string;
|
||||
unresolvedQuestion: string;
|
||||
currentAppearanceReason: string;
|
||||
relatedThreadIds: string[];
|
||||
relatedScarIds: string[];
|
||||
reactionHooks: string[];
|
||||
}
|
||||
```
|
||||
|
||||
## 11.3 编译规则
|
||||
|
||||
每个叙事载体都至少要能回答:
|
||||
|
||||
1. 它是谁、哪处、哪次事留下的痕迹?
|
||||
2. 它为什么现在出现?
|
||||
3. 它之后能让谁产生反应?
|
||||
4. 它和哪条线程有关系?
|
||||
|
||||
这层的作用,是让:
|
||||
|
||||
- 奇幻里的遗物
|
||||
- 武侠里的旧兵器
|
||||
- 科幻里的芯片
|
||||
- 悬疑里的口供
|
||||
- 恐怖里的录像带
|
||||
- 校园题材里的匿名纸条
|
||||
|
||||
都能进入同一套剧情引擎。
|
||||
|
||||
## 12. 记忆与回响层
|
||||
|
||||
## 12.1 目标
|
||||
|
||||
让世界对玩家行动和已获取的叙事载体产生长期回响,而不是每轮都像第一次发生。
|
||||
|
||||
## 12.2 记忆分层
|
||||
|
||||
建议至少拆成:
|
||||
|
||||
1. 事件记忆
|
||||
2. 关系记忆
|
||||
3. 线索记忆
|
||||
4. 误解记忆
|
||||
5. 已揭示真相记忆
|
||||
|
||||
## 12.3 回响规则
|
||||
|
||||
一个故事线程真正成立,不是因为它被写过一次,而是因为它能在后续这些地方重新出现:
|
||||
|
||||
1. 别的角色说法里
|
||||
2. 新地点残痕里
|
||||
3. 新载体命名里
|
||||
4. 新任务前提里
|
||||
5. 关系变化反应里
|
||||
|
||||
## 13. Prompt Contract 设计
|
||||
|
||||
## 13.1 建议拆成 6 类 contract
|
||||
|
||||
1. 世界图谱 contract
|
||||
2. 角色叙事档案 contract
|
||||
3. 章节解锁 contract
|
||||
4. 场景导演 contract
|
||||
5. 叙事载体意图 contract
|
||||
6. 回响总结 contract
|
||||
|
||||
## 13.2 contract 总原则
|
||||
|
||||
1. AI 只拿当前阶段需要的最小上下文
|
||||
2. AI 不直接决定数值、库存、状态迁移、任务合法性
|
||||
3. AI 输出优先是“意图 / 钩子 / 视角 / 叙事指纹”,不是庞大成品对象
|
||||
4. 所有未解锁信息都不能被默认注入
|
||||
|
||||
## 14. 与当前仓库的接入方式
|
||||
|
||||
这套引擎并不是脱离当前项目另起炉灶,而是可以沿着已有骨架往前升级。
|
||||
|
||||
## 14.1 可直接复用的现有基础
|
||||
|
||||
1. `customWorld.ts`
|
||||
- 已有世界生成骨架,可升级成“世界图谱 + 角色叙事档案”生成入口。
|
||||
|
||||
2. `prompt.ts`
|
||||
- 已有上下文组织能力,可升级成“基于可见性切片”的 prompt 裁剪器。
|
||||
|
||||
3. `questDirector.ts`
|
||||
- 已有任务导演方向,可升级成“线程 -> 合约 -> 信号”的推进器。
|
||||
|
||||
4. `runtimeItemDirector.ts` / `runtimeItemNarrative.ts`
|
||||
- 已有运行时奖励与叙事包装能力,可升级成“叙事载体编译器”。
|
||||
|
||||
5. `npcInteractions.ts`
|
||||
- 已有关系状态和首遇逻辑,可升级成“关系与披露双轴控制器”。
|
||||
|
||||
## 14.2 建议新增的模块
|
||||
|
||||
- `src/services/storyEngine/themePack.ts`
|
||||
- `src/services/storyEngine/worldStoryGraph.ts`
|
||||
- `src/services/storyEngine/visibilityEngine.ts`
|
||||
- `src/services/storyEngine/actorNarrativeDossier.ts`
|
||||
- `src/services/storyEngine/sceneNarrativeDirector.ts`
|
||||
- `src/services/storyEngine/carrierNarrativeCompiler.ts`
|
||||
- `src/services/storyEngine/echoMemory.ts`
|
||||
|
||||
## 15. 验收标准
|
||||
|
||||
这套引擎至少要满足下面这些标准,才能算“跨题材 AI 原生剧情引擎”而不是“某一类题材文案增强器”。
|
||||
|
||||
1. 同一套引擎在至少 3 种明显不同的题材包里都能产出结构稳定的世界线程、角色秘密与叙事载体。
|
||||
2. 低关系角色在不同题材下都能做到“有压力、有错位、有暗线钩子”,而不是只会变冷淡。
|
||||
3. 未解锁信息不会在首遇、低披露或无关场景中提前进入 prompt。
|
||||
4. 至少 `80%` 的重点叙事载体都能被玩家看出与某条故事线程、某个旧伤或某个角色关系有关。
|
||||
5. 玩家在不看后台数据的情况下,仍能通过角色、物件、地点、任务描述拼出世界里的明线与暗线。
|
||||
6. 新增一个题材时,主要工作量集中在 `ThemePack` 与词汇适配,而不是重写剧情主逻辑。
|
||||
|
||||
## 16. 推荐落地顺序
|
||||
|
||||
## 阶段 A:先做引擎底层,不先卷文案
|
||||
|
||||
先补:
|
||||
|
||||
- 世界图谱
|
||||
- 可见性切片
|
||||
- 角色叙事档案
|
||||
|
||||
## 阶段 B:再接当前项目最需要的两个落点
|
||||
|
||||
1. 大世界 NPC 背景与首遇表达
|
||||
2. 运行时物件名称、描述与回响
|
||||
|
||||
## 阶段 C:再把任务、地点、关系、载体接成一张网
|
||||
|
||||
重点做:
|
||||
|
||||
- 线程推进
|
||||
- 合约生成
|
||||
- 信号触发
|
||||
- 回响回写
|
||||
|
||||
## 阶段 D:最后做多题材验证
|
||||
|
||||
至少选 3 种差异足够大的题材做压力测试:
|
||||
|
||||
1. 高奇幻 / 武侠神话类
|
||||
2. 科幻 / 调查类
|
||||
3. 悬疑 / 恐怖 / 校园 / 现代类
|
||||
|
||||
## 17. 最后结论
|
||||
|
||||
真正可复用的 AI 原生剧情引擎,不应该先问“这句像不像某个题材”,而应该先问:
|
||||
|
||||
1. 世界有哪些正在运行的明线和暗线?
|
||||
2. 谁知道什么?谁不肯说什么?谁在承受什么?
|
||||
3. 哪些角色、地点、物件、证物正在共同讲同一件事?
|
||||
4. 当前这一轮,玩家应该感到的是压力、怀疑、诱惑、误导,还是揭示?
|
||||
|
||||
只有当这些问题被引擎层回答清楚之后,不同题材的外观、词汇和风格,才会真正长在同一套 AI 原生剧情框架之上。
|
||||
@@ -0,0 +1,724 @@
|
||||
# AI 原生自定义世界生成流程优化 PRD
|
||||
|
||||
更新时间:`2026-04-06`
|
||||
|
||||
## 0. 文档目的
|
||||
|
||||
这份 PRD 用于基于 [CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md](../design/CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md) 的分工结论,系统优化当前自定义世界生成流程。
|
||||
|
||||
目标不是推翻当前已经存在的多阶段生成链,而是解决下面这个核心错位:
|
||||
|
||||
**当前仓库已经开始把世界生成拆成 `framework -> themePack -> storyGraph -> role outline -> dossier -> narrativeProfile` 的分阶段 AI 编译流程,但创作者入口仍然是“一段大文本”,结果页又把大量低杠杆字段重新扔回给创作者人工兜底。**
|
||||
|
||||
一句话定义本次优化:
|
||||
|
||||
**让创作者先定义世界灵魂锚点,再让 AI / 系统围绕锚点分层生成、分层展开、分层可控地完成长尾内容。**
|
||||
|
||||
## 1. 当前流程现状
|
||||
|
||||
## 1.1 当前用户流程
|
||||
|
||||
当前自定义世界的实际产品链路大致是:
|
||||
|
||||
1. 世界选择页点击“创建自定义世界”
|
||||
2. 弹出创建弹窗,只输入一段 `世界设定文本`
|
||||
3. 调用 `generateCustomWorldProfile(...)`
|
||||
4. 进入分阶段生成页,依次跑:
|
||||
- 世界框架
|
||||
- 题材适配层
|
||||
- 世界线程图谱
|
||||
- 可扮演角色骨架
|
||||
- 场景角色骨架
|
||||
- 场景骨架
|
||||
- 场景连接
|
||||
- 角色叙事补全
|
||||
- 角色档案补全
|
||||
- 角色叙事档案补全
|
||||
- 最终归档
|
||||
5. 生成完成后进入结果页
|
||||
6. 在结果页里按 `世界 / 可扮演角色 / 场景角色 / 场景` 四个页签逐项编辑
|
||||
7. 保存并进入世界
|
||||
|
||||
对应当前仓库的主要模块:
|
||||
|
||||
- 输入入口:`src/components/SelectionCustomizationModals.tsx`
|
||||
- 预开局流程:`src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- 分阶段生成:`src/services/ai.ts`
|
||||
- prompt 与结构归一:`src/services/customWorld.ts`
|
||||
- 扩展与编译:`src/services/customWorldBuilder.ts`
|
||||
- 结果页:`src/components/CustomWorldResultView.tsx`
|
||||
- 结果目录:`src/components/CustomWorldEntityCatalog.tsx`
|
||||
- 实体编辑器:`src/components/CustomWorldEntityEditorModal.tsx`
|
||||
|
||||
## 1.2 当前流程已经做对了什么
|
||||
|
||||
当前流程并不是“完全错误”,它已经有几个很值得保留的基础:
|
||||
|
||||
1. 生成链已经不是单次大 JSON 直出,而是分阶段生成。
|
||||
2. 已经存在 `themePack / storyGraph / narrativeProfile / knowledgeFacts / threadContracts` 这类更接近 AI 原生剧情引擎的结构。
|
||||
3. 已经有阶段进度反馈,而不是黑盒等待。
|
||||
4. 已经有结果页与人工编辑能力,可以作为后续工作台的基础。
|
||||
5. 已经有 normalize / fallback / repair prompt 机制,说明链路具备继续工程化的基础。
|
||||
|
||||
本次优化应尽量复用这些已有能力,而不是回到“单次 prompt 直接生世界”的旧思路。
|
||||
|
||||
## 1.3 当前流程的核心问题
|
||||
|
||||
## 1.3.1 创作者入口过于粗糙
|
||||
|
||||
当前创建入口只有一块大文本输入框。
|
||||
|
||||
这会直接导致:
|
||||
|
||||
1. 不会写长描述的用户很难开局。
|
||||
2. 愿意精细创作的用户没有结构化落点。
|
||||
3. 系统无法明确分辨“哪些是创作者真正想锁定的锚点,哪些只是随口补充的描述”。
|
||||
|
||||
结果就是:
|
||||
|
||||
**输入端自由,但信息信号不稳定;AI 虽然能生成很多内容,却不一定生成的是创作者真正关心的内容。**
|
||||
|
||||
## 1.3.2 创作者与 AI 的职责发生倒置
|
||||
|
||||
当前流程实际上是:
|
||||
|
||||
- 创作者先写一段泛化设定
|
||||
- AI 再把整个世界铺满
|
||||
- 创作者最后回到结果页,人工修改大量角色、章节、技能、初始物品、场景连接等细节
|
||||
|
||||
这与“低创作门槛、高创作自由度”的目标相反。
|
||||
|
||||
因为真正应该由创作者控制的,是:
|
||||
|
||||
- 世界核心命题
|
||||
- 主题与气质
|
||||
- 玩家视角
|
||||
- 核心冲突
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性物件 / 怪物 / 禁忌
|
||||
|
||||
而不是让创作者在结果页里逐个补:
|
||||
|
||||
- `backstoryReveal.chapters`
|
||||
- `skills`
|
||||
- `initialItems`
|
||||
- `sceneNpcIds`
|
||||
- `connections`
|
||||
- 各类长尾角色与场景的细枝末节
|
||||
|
||||
## 1.3.3 关键内容与长尾内容没有分层
|
||||
|
||||
当前流程会稳定生成:
|
||||
|
||||
- `5` 个可扮演角色
|
||||
- `25+` 个场景角色
|
||||
- `10+` 个场景
|
||||
|
||||
问题不在数量本身,而在于系统并没有明确区分:
|
||||
|
||||
1. 哪些是创作者应重点塑造的关键对象
|
||||
2. 哪些只是 AI 应自动展开的长尾铺量
|
||||
|
||||
这会导致两个问题:
|
||||
|
||||
1. AI 在早期就花大量成本生成长尾内容,等待时间长。
|
||||
2. 创作者在结果页里面对的是一整套“全部都生成了”的世界,而不是“先抓关键锚点,再决定是否继续铺开”。
|
||||
|
||||
## 1.3.4 当前结果页暴露了过多低杠杆字段
|
||||
|
||||
当前结果页和实体编辑器允许编辑的字段过多,而且很多是低创作价值、系统结构化字段:
|
||||
|
||||
- 背景章节的标题、阈值、teaser、content、contextSnippet
|
||||
- 角色技能与初始物品
|
||||
- 场景 NPC 分配
|
||||
- 场景连接网络
|
||||
|
||||
这对“专业创作者”当然有帮助,但对目标用户来说,容易把工具变成:
|
||||
|
||||
**看起来自由度很高,实际上需要承担很多系统编辑工作。**
|
||||
|
||||
## 1.3.5 当前重新生成是“整世界覆盖式”的
|
||||
|
||||
当前结果页的“重新生成”会清空并重做当前世界的所有信息。
|
||||
|
||||
这意味着:
|
||||
|
||||
1. 创作者一旦修改过内容,就会担心被覆盖。
|
||||
2. 没有“锁定关键内容,只重生成长尾部分”的机制。
|
||||
3. AI 无法真正成为创作搭档,只像一次性大批量生成器。
|
||||
|
||||
## 1.3.6 当前生成阶段是“模型视角”,不是“创作者视角”
|
||||
|
||||
当前生成页展示的是系统批次和阶段进度,这很好,但它主要回答的是:
|
||||
|
||||
- 现在模型在跑哪一步
|
||||
|
||||
没有回答的是:
|
||||
|
||||
- 创作者最关心的关键角色是否已经成型
|
||||
- 世界冲突是否已经稳定
|
||||
- 当前这轮已经锁定了哪些核心创意
|
||||
- 接下来生成的是关键锚点,还是长尾内容
|
||||
|
||||
也就是说:
|
||||
|
||||
**当前链路的进度可见了,但创作过程仍然没有真正可见。**
|
||||
|
||||
## 2. 本次优化的设计目标
|
||||
|
||||
这次优化要同时满足 6 个目标:
|
||||
|
||||
1. 降低输入门槛
|
||||
- 不要求创作者一上来写长文,不要求理解系统字段。
|
||||
|
||||
2. 提高高杠杆创作自由度
|
||||
- 让创作者直接控制世界灵魂锚点,而不是低价值细节。
|
||||
|
||||
3. 明确创作者与 AI 的职责边界
|
||||
- 创作者负责“决定什么值得创作”,AI 负责“把它展开并跑起来”。
|
||||
|
||||
4. 保留现有分阶段生成骨架
|
||||
- 不推翻 `framework -> themePack -> storyGraph -> role/landmark` 的已有结构。
|
||||
|
||||
5. 引入锁定与局部重生成
|
||||
- 让创作者能保住自己在乎的内容,只重做其余部分。
|
||||
|
||||
6. 把结果页从“数据总表”升级成“创作工作台”
|
||||
- 让编辑界面按创作价值组织,而不是按底层对象堆字段。
|
||||
|
||||
## 3. 核心产品结论
|
||||
|
||||
优化后的自定义世界流程应该改为:
|
||||
|
||||
```text
|
||||
创作者输入世界锚点
|
||||
-> AI 编译创作者意图摘要
|
||||
-> 创作者确认 / 锁定关键锚点
|
||||
-> AI 先生成关键角色与关键地点
|
||||
-> 创作者可局部修改 / 局部重生成
|
||||
-> AI 再展开长尾 NPC、长尾场景与运行时编译结构
|
||||
-> 结果页以“锚点 / 关键对象 / 扩展内容 / 运行时摘要”方式组织
|
||||
-> 保存并进入世界
|
||||
```
|
||||
|
||||
一句话:
|
||||
|
||||
**先做创作决策,再做内容展开;先做关键对象,再做长尾铺量;先让创作者锁定灵魂,再让 AI 扩散世界。**
|
||||
|
||||
## 4. 输入层优化方案
|
||||
|
||||
## 4.1 把“单一大文本”升级为“创作卡片”
|
||||
|
||||
新的输入层不应只有一块大 textarea,而应拆成卡片式输入。
|
||||
|
||||
建议至少包含 9 张卡:
|
||||
|
||||
1. 世界一句话
|
||||
2. 主题与气质
|
||||
3. 玩家是谁
|
||||
4. 核心冲突
|
||||
5. 关键势力
|
||||
6. 关键角色
|
||||
7. 关键地点
|
||||
8. 标志性要素
|
||||
9. 禁止事项
|
||||
|
||||
每张卡都支持:
|
||||
|
||||
1. 一句话输入
|
||||
2. 标签 / 选项辅助
|
||||
3. 高级补充展开
|
||||
|
||||
这样做的目的不是让用户填更多,而是让:
|
||||
|
||||
- 不会写长文的人,也能靠卡片完成创作输入
|
||||
- 愿意深挖的人,也有明确位置继续提升质量
|
||||
|
||||
## 4.2 保留“自由输入模式”,但不再只靠它
|
||||
|
||||
当前的 `settingText` 不应被废弃,而应保留为:
|
||||
|
||||
1. 快速模式
|
||||
2. 导入模式
|
||||
3. 兜底模式
|
||||
|
||||
系统应支持两种输入入口:
|
||||
|
||||
1. 快速文本模式
|
||||
- 用户只写一段设定,系统自动拆分成创作卡片建议
|
||||
|
||||
2. 卡片模式
|
||||
- 用户直接按结构化方式输入世界锚点
|
||||
|
||||
两种模式最终都编译成统一的创作者意图对象。
|
||||
|
||||
## 4.3 必填与选填要分开
|
||||
|
||||
不应要求用户每一张卡都填完。
|
||||
|
||||
建议:
|
||||
|
||||
- 必填:
|
||||
- 世界一句话
|
||||
- 主题与气质
|
||||
- 玩家是谁
|
||||
- 核心冲突
|
||||
|
||||
- 选填:
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 禁止事项
|
||||
|
||||
这样既能保证世界最小成型,又不会把创作者门槛抬高。
|
||||
|
||||
## 4.3.1 抽象统一“聊天补充设定”能力
|
||||
|
||||
RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都应走同一套“聊天补充设定”能力,而不是各自维护按钮、提交 payload 和自动补全规则。
|
||||
|
||||
统一能力需要覆盖:
|
||||
|
||||
1. 普通聊天提交:只携带用户输入文本与统一生成的 `clientMessageId`。
|
||||
2. 总结当前设定:快捷动作统一展示为“总结当前设定”,但总结消息允许各玩法保留领域文案。
|
||||
3. 补充剩余设定:快捷动作统一展示为“补充剩余设定”,并统一进入自动补全模式。
|
||||
|
||||
用户完成至少两轮对话后,工作台展示“补充剩余设定”快捷操作。点击后前端只发送一次聊天消息,不再弹出额外表单或追问面板:
|
||||
|
||||
- 消息文本固定为 `请补充剩余设定。`
|
||||
- 请求必须携带 `quickFillRequested: true`
|
||||
- `focusCardId` 固定为空,`selectedCardIds` 固定为空数组
|
||||
|
||||
后端各玩法 Agent 收到 `quickFillRequested: true` 后必须进入强制补全模式,并复用统一公共规则:
|
||||
|
||||
1. 不再继续向用户追问缺失设定。
|
||||
2. 基于已有对话与已推断卡片自行补齐剩余关键字。
|
||||
3. 输出可进入对应生成结果的完整结构。
|
||||
4. 将进度推进到可提交状态,避免用户点击后仍停留在问答循环。
|
||||
|
||||
三入口只允许保留领域差异:聊天消息 ID 前缀、总结文案、最终生成按钮名称、领域 payload 额外字段、领域 prompt 对“缺失内容范围”的补充说明。除此之外,聊天动作的展示、触发语义与自动补全硬规则必须统一维护。
|
||||
|
||||
## 4.4 明确支持“锁定”
|
||||
|
||||
每张卡片、每个关键角色、每个关键地点都应支持锁定。
|
||||
|
||||
锁定后:
|
||||
|
||||
1. AI 不得在重生成时覆盖该内容
|
||||
2. 长尾内容只能围绕它展开
|
||||
3. 结果页里应明确显示其为“创作者锚点”
|
||||
|
||||
## 5. 生成链路优化方案
|
||||
|
||||
## 5.1 新增“创作者意图编译层”
|
||||
|
||||
在真正开始世界生成前,先新增一个轻量阶段:
|
||||
|
||||
**Creator Intent Compile**
|
||||
|
||||
输入:
|
||||
|
||||
- 文本模式输入
|
||||
- 或卡片模式输入
|
||||
|
||||
输出:
|
||||
|
||||
- 创作者意图摘要
|
||||
- 世界锚点摘要
|
||||
- 系统识别出的关键角色 / 冲突 / 地点 / 禁忌
|
||||
|
||||
这一步的作用不是生成世界,而是先回答:
|
||||
|
||||
1. 系统理解到的世界核心是什么
|
||||
2. 哪些内容将被视为创作者强锚点
|
||||
3. 哪些内容将交给 AI 扩展
|
||||
|
||||
## 5.2 把当前生成链改成“关键先行、长尾后补”
|
||||
|
||||
当前 `generateCustomWorldProfile(...)` 的分阶段结构可以保留,但生成顺序需要更创作者化。
|
||||
|
||||
建议改成 5 层:
|
||||
|
||||
### 第一层:世界锚点层
|
||||
|
||||
先生成:
|
||||
|
||||
- 世界框架
|
||||
- ThemePack
|
||||
- StoryGraph 的基础版
|
||||
- 创作者锚点摘要
|
||||
|
||||
这一层完成后,系统应能让创作者看到:
|
||||
|
||||
- 世界现在到底被理解成了什么
|
||||
- 哪些冲突 / 势力 / 意象被识别出来了
|
||||
|
||||
### 第二层:关键对象层
|
||||
|
||||
优先生成:
|
||||
|
||||
- 关键可扮演角色
|
||||
- 关键场景角色
|
||||
- 关键地点
|
||||
|
||||
这一层优先围绕创作者明确输入的角色和地点,而不是先铺满全部数量。
|
||||
|
||||
### 第三层:创作者校对层
|
||||
|
||||
在继续展开长尾内容前,应允许创作者做一次轻量校对:
|
||||
|
||||
- 确认关键角色是否对
|
||||
- 确认关键地点是否对
|
||||
- 锁定已经满意的内容
|
||||
- 对不满意的关键对象做局部重生成
|
||||
|
||||
### 第四层:长尾展开层
|
||||
|
||||
在关键层稳定后,再生成:
|
||||
|
||||
- 普通场景角色
|
||||
- 路人 / 杂兵 / 补位 NPC
|
||||
- 次级地点
|
||||
- 扩展连接关系
|
||||
- 长尾命名和描述
|
||||
|
||||
### 第五层:运行时编译层
|
||||
|
||||
最后再编译:
|
||||
|
||||
- `themePack`
|
||||
- `storyGraph`
|
||||
- `knowledgeFacts`
|
||||
- `threadContracts`
|
||||
- `narrativeProfile`
|
||||
- 各类运行时支持结构
|
||||
|
||||
## 5.3 支持“快速开局生成”和“完整展开生成”
|
||||
|
||||
建议提供两种生成策略:
|
||||
|
||||
1. 快速开局
|
||||
- 先完成世界锚点 + 关键对象 + 最小可玩档案
|
||||
- 用户可以更快看到世界雏形
|
||||
|
||||
2. 完整展开
|
||||
- 一次性继续补齐长尾场景角色、地标和完整世界网络
|
||||
|
||||
这样做的价值很高:
|
||||
|
||||
1. 降低首次等待焦虑
|
||||
2. 让创作者更早介入关键对象校正
|
||||
3. 避免系统在创作方向还没稳定前,先铺满大量长尾内容
|
||||
|
||||
## 5.4 角色与场景生成要改成“锚点优先 + 长尾补位”
|
||||
|
||||
当前角色与场景的生成方式更像“按配额批量产出”。
|
||||
|
||||
优化后应改为:
|
||||
|
||||
1. 先生成创作者明确指定的关键角色 / 地点
|
||||
2. 再根据世界冲突自动补位缺失的角色原型和场景功能位
|
||||
3. 最后再铺长尾
|
||||
|
||||
这样生成出来的世界会更像“围绕创作者意图长出来”,而不是“先生成了一个完整世界,再让创作者去认领”
|
||||
|
||||
## 6. 结果页与编辑工作台优化方案
|
||||
|
||||
## 6.1 结果页不应再按“底层对象目录”组织为主
|
||||
|
||||
当前结果页主要按:
|
||||
|
||||
- 世界
|
||||
- 可扮演角色
|
||||
- 场景角色
|
||||
- 场景
|
||||
|
||||
来组织。
|
||||
|
||||
优化后建议改成 4 层工作台:
|
||||
|
||||
1. 创作锚点
|
||||
- 展示创作者输入和锁定内容
|
||||
|
||||
2. 关键对象
|
||||
- 关键角色、关键地点、关键冲突对象
|
||||
|
||||
3. 扩展内容
|
||||
- AI 自动展开的长尾角色、长尾地点、补位内容
|
||||
|
||||
4. 世界编译摘要
|
||||
- 展示世界线程、题材包、运行时摘要,但默认不要求创作者编辑
|
||||
|
||||
## 6.2 编辑界面应遵守“高价值字段前置,低价值字段折叠”
|
||||
|
||||
对创作者默认暴露的应是:
|
||||
|
||||
- 角色一句话定位
|
||||
- 角色表面面貌
|
||||
- 角色真正想要什么
|
||||
- 角色与谁有关
|
||||
- 地点为什么重要
|
||||
- 地点承载什么冲突
|
||||
- 世界哪些规则不能动
|
||||
|
||||
不应默认把下面这些字段摆在第一屏:
|
||||
|
||||
- `backstoryReveal.chapters`
|
||||
- `skills`
|
||||
- `initialItems`
|
||||
- `contextSnippet`
|
||||
- `sceneNpcIds`
|
||||
- `connections`
|
||||
|
||||
这些应被系统下沉到:
|
||||
|
||||
- 自动生成
|
||||
- 高级模式
|
||||
- 或局部展开区域
|
||||
|
||||
## 6.3 新增局部重生成
|
||||
|
||||
结果页必须支持至少 4 种局部重生成:
|
||||
|
||||
1. 仅重生成某个关键角色
|
||||
2. 仅重生成某个关键地点
|
||||
3. 仅重生成长尾场景角色
|
||||
4. 仅重生成场景网络 / 长尾连接
|
||||
|
||||
并且所有局部重生成都必须:
|
||||
|
||||
- 尊重锁定内容
|
||||
- 显示影响范围
|
||||
- 避免全局覆盖
|
||||
|
||||
## 6.4 新增“AI 建议修订”而非“只允许手改”
|
||||
|
||||
结果页不应只提供人工编辑,还应提供:
|
||||
|
||||
- 让 AI 重写一句话定位
|
||||
- 让 AI 补强冲突张力
|
||||
- 让 AI 改得更克制 / 更黑暗 / 更传奇 / 更现实
|
||||
- 让 AI 只围绕已锁定内容变体
|
||||
|
||||
这样才能真正体现“AI 是创作辅助,而不是一次性生成器”。
|
||||
|
||||
## 7. 数据结构建议
|
||||
|
||||
## 7.1 新增 `CustomWorldCreatorIntent`
|
||||
|
||||
建议新增创作者输入的统一结构:
|
||||
|
||||
```ts
|
||||
interface CustomWorldCreatorIntent {
|
||||
sourceMode: 'freeform' | 'card';
|
||||
rawSettingText: string;
|
||||
worldHook: string;
|
||||
themeKeywords: string[];
|
||||
toneDirectives: string[];
|
||||
playerPremise: string;
|
||||
openingSituation: string;
|
||||
coreConflicts: string[];
|
||||
keyFactions: CreatorFactionSeed[];
|
||||
keyCharacters: CreatorCharacterSeed[];
|
||||
keyLandmarks: CreatorLandmarkSeed[];
|
||||
iconicElements: string[];
|
||||
forbiddenDirectives: string[];
|
||||
}
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
- 把“创作者真正输入了什么”从最终 `CustomWorldProfile` 中分离出来
|
||||
|
||||
## 7.2 新增 `CustomWorldAnchorPack`
|
||||
|
||||
建议新增系统编译后的锚点包:
|
||||
|
||||
```ts
|
||||
interface CustomWorldAnchorPack {
|
||||
worldSummary: string;
|
||||
creatorIntentSummary: string;
|
||||
lockedAnchorIds: string[];
|
||||
keyConflictSummaries: string[];
|
||||
keyFactionSummaries: string[];
|
||||
keyCharacterAnchors: ActorAnchor[];
|
||||
keyLandmarkAnchors: LandmarkAnchor[];
|
||||
motifDirectives: string[];
|
||||
}
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
- 让后续长尾扩展、局部重生成、结果页工作台都围绕同一套“创作锚点”工作
|
||||
|
||||
## 7.3 新增 `CustomWorldLockState`
|
||||
|
||||
```ts
|
||||
interface CustomWorldLockState {
|
||||
worldLockedFields: string[];
|
||||
lockedCharacterIds: string[];
|
||||
lockedLandmarkIds: string[];
|
||||
lockedConflictIds: string[];
|
||||
lockedFactionIds: string[];
|
||||
}
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
- 明确哪些内容 AI 不能重写
|
||||
|
||||
## 7.4 新增 `CustomWorldGenerationDraft`
|
||||
|
||||
```ts
|
||||
interface CustomWorldGenerationDraft {
|
||||
creatorIntent: CustomWorldCreatorIntent;
|
||||
anchorPack: CustomWorldAnchorPack | null;
|
||||
profile: CustomWorldProfile | null;
|
||||
lockState: CustomWorldLockState;
|
||||
generationMode: 'fast' | 'full';
|
||||
generationStatus: 'idle' | 'compiling' | 'generating_key' | 'generating_long_tail' | 'ready';
|
||||
}
|
||||
```
|
||||
|
||||
作用:
|
||||
|
||||
- 让“创作者输入、AI 编译、结果编辑”成为连续工作流,而不是只有最终成品对象
|
||||
|
||||
## 8. 与当前仓库的接入建议
|
||||
|
||||
## 8.1 输入层
|
||||
|
||||
优先改:
|
||||
|
||||
- `src/components/SelectionCustomizationModals.tsx`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
|
||||
目标:
|
||||
|
||||
- 把单 textarea 升级为“快速模式 + 卡片模式”
|
||||
- 新增创作者意图状态
|
||||
- 新增锁定和局部重生成入口
|
||||
|
||||
## 8.2 prompt 与生成服务层
|
||||
|
||||
优先改:
|
||||
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/ai.ts`
|
||||
|
||||
目标:
|
||||
|
||||
- 新增 Creator Intent Compile prompt
|
||||
- 新增 Anchor Pack compile prompt
|
||||
- 新增局部重生成 prompt
|
||||
- 保留现有 `framework / themePack / storyGraph / role / landmark` 生成骨架
|
||||
|
||||
## 8.3 Builder 与结构层
|
||||
|
||||
优先改:
|
||||
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
- `src/types/customWorld.ts`
|
||||
|
||||
目标:
|
||||
|
||||
- 为 `CustomWorldProfile` 增加创作者意图与锚点相关扩展字段
|
||||
- 保持旧档兼容
|
||||
- 让现有 builder 能同时消费 `creatorIntent + anchorPack + profile seed`
|
||||
|
||||
## 8.4 结果页与编辑器层
|
||||
|
||||
优先改:
|
||||
|
||||
- `src/components/CustomWorldResultView.tsx`
|
||||
- `src/components/CustomWorldEntityCatalog.tsx`
|
||||
- `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
|
||||
目标:
|
||||
|
||||
- 结果页由“数据目录”转为“创作工作台”
|
||||
- 支持局部重生成
|
||||
- 高价值字段前置,低价值字段折叠
|
||||
- 允许 AI 辅助改写,而不只是手工编辑
|
||||
|
||||
## 9. 明确不做什么
|
||||
|
||||
本次优化不做以下事情:
|
||||
|
||||
1. 不推翻当前自定义世界最终输出仍是 `CustomWorldProfile` 的兼容目标
|
||||
2. 不把所有运行时结构都暴露给创作者直接编辑
|
||||
3. 不要求创作者理解 `themePack / storyGraph / knowledgeFacts / threadContracts` 等系统结构
|
||||
4. 不把复杂数值平衡、掉落预算、build 预算转移给创作者
|
||||
5. 不把“高自由度”理解成“所有字段都手工可改”
|
||||
|
||||
## 10. 验收标准
|
||||
|
||||
做到以下几点,才算这次优化真正成立:
|
||||
|
||||
1. 创作者可以不用写长文,只靠卡片输入也能完成自定义世界创建。
|
||||
2. 系统会明确区分“创作者锚点”和“AI 自动展开内容”。
|
||||
3. 创作者不再需要默认手改大量 `skills / initialItems / backstoryReveal / scene connections` 才能得到可用世界。
|
||||
4. 结果页支持锁定关键角色、关键地点、关键冲突,并支持局部重生成。
|
||||
5. 重新生成不再默认覆盖整个世界。
|
||||
6. 当前 `framework -> themePack -> storyGraph -> role/landmark` 生成主链可以继续复用,而不是被废弃。
|
||||
7. 结果页默认展示的是高创作价值对象,而不是系统级低层字段。
|
||||
8. 长尾内容生成明显后置于关键对象生成,创作者能更早看到并修正关键对象。
|
||||
9. 旧的自由文本输入模式仍然可用,但不再是唯一入口。
|
||||
|
||||
## 11. 推荐落地顺序
|
||||
|
||||
## 阶段 A:先加创作者意图层
|
||||
|
||||
先做:
|
||||
|
||||
- `CustomWorldCreatorIntent`
|
||||
- 输入卡片 UI
|
||||
- 快速文本 -> 卡片建议编译
|
||||
|
||||
目标:
|
||||
|
||||
- 先把创作者输入从“单一大文本”升级成“可识别的创作锚点”
|
||||
|
||||
## 阶段 B:再加锚点包与锁定能力
|
||||
|
||||
先做:
|
||||
|
||||
- `CustomWorldAnchorPack`
|
||||
- `CustomWorldLockState`
|
||||
- 锁定 UI
|
||||
|
||||
目标:
|
||||
|
||||
- 让后续生成真正知道“哪些不能动”
|
||||
|
||||
## 阶段 C:再改生成顺序
|
||||
|
||||
先做:
|
||||
|
||||
- 关键对象优先
|
||||
- 长尾内容后置
|
||||
- 快速开局模式
|
||||
|
||||
目标:
|
||||
|
||||
- 缩短“看到关键结果”的等待时间
|
||||
|
||||
## 阶段 D:最后重做结果页工作台
|
||||
|
||||
先做:
|
||||
|
||||
- 锚点页
|
||||
- 关键对象页
|
||||
- 扩展内容页
|
||||
- 局部重生成
|
||||
|
||||
目标:
|
||||
|
||||
- 让结果页真正成为创作工具,而不是人工补表页面
|
||||
|
||||
## 12. 一句话结论
|
||||
|
||||
当前自定义世界流程最需要优化的,不是“让 AI 再多生成一点内容”,而是:
|
||||
|
||||
**把创作者从低价值字段编辑里解放出来,让创作者负责世界灵魂锚点,让 AI 负责围绕这些锚点分层生成、分层展开、分层可控地把世界长出来。**
|
||||
959
docs/prd/AI_NATIVE_CUSTOM_WORLD_CREATION_HUB_PRD_2026-04-13.md
Normal file
959
docs/prd/AI_NATIVE_CUSTOM_WORLD_CREATION_HUB_PRD_2026-04-13.md
Normal file
@@ -0,0 +1,959 @@
|
||||
# AI 原生自定义世界创作页面 PRD
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 文档目的
|
||||
|
||||
这份 PRD 用于定义一个新的、独立的“自定义世界创作页面”。
|
||||
|
||||
目标不是继续沿用当前“世界选择页里弹出创建弹窗”的旧流程,而是把“创作入口”和“历史作品管理”正式从世界选择页中抽出来,形成一个专门承接创作行为的页面。
|
||||
|
||||
这份 PRD 要解决的核心问题是:
|
||||
|
||||
**当用户在世界选择页点击“创建自定义世界”后,不应该立刻被丢进一个弹窗或某个具体工作流,而应该先进入一个专门的创作页面,在这里完成:**
|
||||
|
||||
1. 新建作品
|
||||
2. 继续创作草稿
|
||||
3. 查看历史已发布作品
|
||||
4. 从创作页面进入具体 Agent 创作工作区
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让“创作自定义世界”从一个一次性动作,升级成一个正式的创作入口与作品管理入口。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前问题
|
||||
|
||||
## 1.1 当前创建入口过于直接
|
||||
|
||||
当前链路是:
|
||||
|
||||
```text
|
||||
世界选择页
|
||||
-> 点击创建自定义世界
|
||||
-> 直接打开创建弹窗
|
||||
```
|
||||
|
||||
这会带来几个问题:
|
||||
|
||||
1. 入口太窄
|
||||
- 用户只有“立刻创建”这一个选择,没有“先看看历史作品”“继续草稿”的缓冲页。
|
||||
|
||||
2. 创作与管理没有分层
|
||||
- 新建、继续创作、查看已发布作品都混在世界选择页这个入口层里。
|
||||
|
||||
3. 后续 Agent 工作区不好接
|
||||
- 如果直接从世界选择页跳进 Agent session,用户缺少“这是一个创作空间”的过渡。
|
||||
|
||||
## 1.2 历史作品入口不完整
|
||||
|
||||
当前世界选择页里虽然能展示已保存的自定义世界,但它更像“世界卡片列表”,不是一个真正的创作历史页。
|
||||
|
||||
缺口主要有:
|
||||
|
||||
1. 草稿和已发布作品没有统一视图
|
||||
2. 草稿没有正式“继续创作”入口体系
|
||||
3. 已发布作品只是“世界库内容”,不是“创作成果”
|
||||
4. 用户看不到自己的创作历史全貌
|
||||
|
||||
## 1.3 未来 Agent 工作区缺少前置首页
|
||||
|
||||
后续 Agent-first 创作工具一定会有:
|
||||
|
||||
1. 草稿 session
|
||||
2. 已发布世界
|
||||
3. 继续创作入口
|
||||
4. 发布后的回看入口
|
||||
|
||||
如果没有一个专门的创作页面,这些入口只能继续塞在:
|
||||
|
||||
- 世界选择页
|
||||
- 结果页
|
||||
- 临时 modal
|
||||
|
||||
最终会让流程越来越乱。
|
||||
|
||||
---
|
||||
|
||||
## 2. 产品目标
|
||||
|
||||
这次要做的创作页面,必须同时满足 6 个目标:
|
||||
|
||||
1. 把“新建作品”和“管理作品”放到同一入口里
|
||||
2. 支持同时展示草稿和已发布作品
|
||||
3. 让用户从世界选择页进入后,先感知到“这里是创作空间”
|
||||
4. 为后续 Agent 创作工作区提供稳定前置页
|
||||
5. 保持移动端优先,界面清爽,不堆规则说明
|
||||
6. 前端只负责展示和跳转,数据聚合与状态归类全部交给后端
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心结论
|
||||
|
||||
新的用户主链应该改成:
|
||||
|
||||
```text
|
||||
世界选择页
|
||||
-> 点击“创建自定义世界”
|
||||
-> 进入“创作页面”
|
||||
-> 用户选择:
|
||||
- 新建作品
|
||||
- 继续创作草稿
|
||||
- 查看已发布作品
|
||||
-> 再进入具体 Agent 工作区或正式世界
|
||||
```
|
||||
|
||||
一句话:
|
||||
|
||||
**创作页面是“创作中心”,不是“又一个创建弹窗”。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 页面定位
|
||||
|
||||
## 4.1 页面名称
|
||||
|
||||
建议名称:
|
||||
|
||||
`创作页面`
|
||||
|
||||
UI 主标题建议:
|
||||
|
||||
`自定义世界创作`
|
||||
|
||||
## 4.2 页面职责
|
||||
|
||||
这个页面只负责 4 件事:
|
||||
|
||||
1. 提供“新建作品”入口
|
||||
2. 列出用户历史草稿
|
||||
3. 列出用户已发布作品
|
||||
4. 把用户带到正确的下一步页面
|
||||
|
||||
这个页面不负责:
|
||||
|
||||
1. 直接进行世界锚点编辑
|
||||
2. 直接进行 Agent 长对话创作
|
||||
3. 直接进行结果页细改
|
||||
4. 直接发布作品
|
||||
|
||||
也就是说:
|
||||
|
||||
**它是创作首页,不是创作工作区本体。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 用户流程
|
||||
|
||||
## 5.1 世界选择页进入创作页面
|
||||
|
||||
当前世界选择页里的“创建自定义世界”按钮行为改为:
|
||||
|
||||
```text
|
||||
点击创建自定义世界
|
||||
-> 不再打开旧 modal
|
||||
-> 进入 custom-world-home
|
||||
```
|
||||
|
||||
第一阶段只要求:
|
||||
|
||||
1. 进入专门创作页面
|
||||
2. 能看到新建入口和历史作品
|
||||
|
||||
## 5.2 在创作页面新建作品
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
创作页面
|
||||
-> 点击“新建作品”
|
||||
-> 在首屏新建作品卡片中直接选择游戏创作模板
|
||||
-> 创建新的 Agent session
|
||||
-> 进入 custom-world-agent
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 新建作品依然走 Agent session 主链
|
||||
- 创作页面不自己生成世界
|
||||
- 可创建玩法模板直接露出在首屏卡片中,不再额外弹一次类型 launcher
|
||||
|
||||
## 5.3 在创作页面继续草稿
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
创作页面
|
||||
-> 点击草稿卡片的“继续创作”
|
||||
-> 打开该 session
|
||||
-> 进入 custom-world-agent
|
||||
```
|
||||
|
||||
## 5.4 在创作页面查看已发布作品
|
||||
|
||||
已发布作品卡片支持两种动作:
|
||||
|
||||
1. `进入世界`
|
||||
2. `查看作品`
|
||||
|
||||
说明:
|
||||
|
||||
- `进入世界` 直接进入当前已发布世界
|
||||
- `查看作品` 进入只读详情页或结果总览页
|
||||
|
||||
第一版如果不单独做只读详情页,可先只保留:
|
||||
|
||||
1. `进入世界`
|
||||
|
||||
但卡片展示层必须把“它是已发布作品”表达清楚。
|
||||
|
||||
---
|
||||
|
||||
## 6. 信息架构
|
||||
|
||||
## 6.1 页面整体结构
|
||||
|
||||
创作页面必须包含 4 个区域:
|
||||
|
||||
1. 首屏新建作品区
|
||||
2. 新建作品区
|
||||
3. 历史作品筛选区
|
||||
4. 作品列表区
|
||||
|
||||
## 6.2 首屏新建作品区
|
||||
|
||||
这是页面首屏最高优先级区域,默认不再单独展示返回按钮和“创作中心 / 自定义世界创作”标题,直接把注意力留给可创建模板与作品列表。
|
||||
|
||||
必须包含:
|
||||
|
||||
1. `新建作品` 主标题
|
||||
2. 一段极短说明文案
|
||||
3. 游戏创作模板快捷卡片
|
||||
|
||||
模板卡片要求:
|
||||
|
||||
1. 直接展示当前可创建玩法,如 `角色扮演 RPG`、`大鱼吃小鱼`、`拼图玩法`
|
||||
2. 锁定中的玩法保留占位,但必须显式禁用
|
||||
3. 点击可创建玩法后直接进入对应创作工作台,不再额外弹二次选择面板
|
||||
|
||||
说明文案要求:
|
||||
|
||||
1. 只一两句
|
||||
2. 不要写规则说明
|
||||
3. 不要写长解释
|
||||
|
||||
推荐文案方向:
|
||||
|
||||
- `直接选择游戏创作模板,立刻进入对应的共创工作台。`
|
||||
|
||||
## 6.3 历史作品筛选区
|
||||
|
||||
建议用 3 个 tab:
|
||||
|
||||
1. `全部`
|
||||
2. `草稿`
|
||||
3. `已发布`
|
||||
|
||||
默认:
|
||||
|
||||
- `全部`
|
||||
|
||||
第一版不强制上搜索框,但如果作品数超过 `8` 个,建议补搜索。
|
||||
|
||||
## 6.4 作品列表区
|
||||
|
||||
列表区统一展示作品卡片,但卡片要区分两类:
|
||||
|
||||
1. 草稿卡片
|
||||
2. 已发布卡片
|
||||
|
||||
默认排序:
|
||||
|
||||
- 按 `updatedAt desc`
|
||||
|
||||
---
|
||||
|
||||
## 7. 作品卡片定义
|
||||
|
||||
## 7.1 草稿卡片
|
||||
|
||||
草稿卡片必须展示:
|
||||
|
||||
1. 标题
|
||||
2. 草稿状态标识
|
||||
3. 最近更新时间
|
||||
4. 当前阶段标签
|
||||
5. 简短摘要
|
||||
6. 封面图
|
||||
7. 主要操作按钮
|
||||
|
||||
### 标题规则
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `draftProfile.name`
|
||||
2. `anchorPack.worldSummary`
|
||||
3. `creatorIntent.worldHook`
|
||||
4. `未命名草稿`
|
||||
|
||||
### 摘要规则
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `anchorPack.creatorIntentSummary`
|
||||
2. `creatorIntent.rawSettingText`
|
||||
3. 默认摘要占位文本
|
||||
|
||||
### 封面图规则
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `draftProfile.cover.imageSrc`,当 `sourceType` 为 `uploaded / generated`
|
||||
2. `draftProfile.sceneChapterBlueprints[0].acts[0].backgroundImageSrc` 作为默认封面底图
|
||||
3. 默认封面底图上叠加 `draftProfile.cover.characterRoleIds` 对应的角色主形象
|
||||
4. 若未显式指定角色,则按 `playableNpcs` 顺序取前 `3` 个有主图的角色
|
||||
5. 若开局场景第一幕图片为空,则依次回退到 `draftProfile.camp.imageSrc`、首个 `landmark.imageSrc`、首个角色主图或默认占位图
|
||||
|
||||
### 草稿卡片主操作
|
||||
|
||||
第一版必须有:
|
||||
|
||||
1. `继续创作`
|
||||
|
||||
可选:
|
||||
|
||||
1. `删除草稿`
|
||||
2. `复制草稿`
|
||||
|
||||
第一版如来不及,可不做删除和复制,但接口结构应预留。
|
||||
|
||||
## 7.2 已发布卡片
|
||||
|
||||
已发布卡片必须展示:
|
||||
|
||||
1. 世界名称
|
||||
2. 已发布标识
|
||||
3. 发布时间或更新时间
|
||||
4. 世界摘要
|
||||
5. 封面图
|
||||
6. 主要操作按钮
|
||||
|
||||
### 标题规则
|
||||
|
||||
直接取:
|
||||
|
||||
1. `CustomWorldProfile.name`
|
||||
|
||||
### 摘要规则
|
||||
|
||||
直接取:
|
||||
|
||||
1. `CustomWorldProfile.summary`
|
||||
|
||||
### 封面图规则
|
||||
|
||||
按优先级取:
|
||||
|
||||
1. `CustomWorldProfile.cover.imageSrc`,当 `sourceType` 为 `uploaded / generated`
|
||||
2. 开局场景第一幕图片作为默认封面底图
|
||||
3. 默认封面底图上叠加 `cover.characterRoleIds` 指定的角色主形象
|
||||
4. 若未显式指定角色,则按 `playableNpcs` 顺序取前 `3` 个有主图的角色
|
||||
5. 若默认底图不可用,则依次回退到 `camp.imageSrc`、首个 `landmark.imageSrc`、第一可扮演角色立绘或默认占位图
|
||||
|
||||
## 7.3 作品封面属性
|
||||
|
||||
作品必须新增显式封面属性,作为作者可编辑的作品资产,而不再只靠“卡片展示时临时猜一张图”。
|
||||
|
||||
建议字段:
|
||||
|
||||
```ts
|
||||
type CustomWorldCoverSourceType = 'default' | 'uploaded' | 'generated';
|
||||
|
||||
interface CustomWorldCoverProfile {
|
||||
sourceType: CustomWorldCoverSourceType;
|
||||
imageSrc?: string | null;
|
||||
characterRoleIds?: string[];
|
||||
}
|
||||
```
|
||||
|
||||
字段含义:
|
||||
|
||||
1. `sourceType = default`
|
||||
- 表示继续使用系统默认封面布局
|
||||
- `imageSrc` 不作为最终封面图使用
|
||||
- 底图固定优先取“开局场景第一幕图片”
|
||||
- 前景角色取 `characterRoleIds`
|
||||
|
||||
2. `sourceType = uploaded`
|
||||
- 表示作者直接上传了一张最终封面
|
||||
- 卡片与详情页直接显示 `imageSrc`
|
||||
- 不再叠加默认角色前景
|
||||
|
||||
3. `sourceType = generated`
|
||||
- 表示作者通过 AI 生成了一张最终封面
|
||||
- 卡片与详情页直接显示 `imageSrc`
|
||||
- 不再叠加默认角色前景
|
||||
- 生成时允许作者补一句封面描述,系统会结合世界主题、场景素材、角色素材共同构图
|
||||
|
||||
## 7.4 默认封面布局
|
||||
|
||||
默认封面布局不是单纯“取开局场景图”,而是:
|
||||
|
||||
```text
|
||||
开局场景第一幕图片
|
||||
+ 前景主角色主形象 2~3 个
|
||||
+ 用于列表卡片和作品详情的统一封面预览
|
||||
```
|
||||
|
||||
明确规则:
|
||||
|
||||
1. 默认封面底图固定优先取 `sceneChapterBlueprints[0].acts[0].backgroundImageSrc`
|
||||
2. 若开局场景第一幕图片不存在,则依次回退到 `camp.imageSrc` 与首个 `landmark.imageSrc`
|
||||
3. 默认前景角色固定从 `playableNpcs` 中取前 `3` 个有主图的角色
|
||||
4. 若作者在 `cover.characterRoleIds` 中显式指定角色,则优先按指定顺序展示
|
||||
5. 前端只负责把后端给出的“底图 + 角色主图列表”渲染成封面,不在前端做封面规则推理
|
||||
6. 已上传或已生成的最终封面,直接作为成品图显示,不再做默认布局叠加
|
||||
|
||||
## 7.5 作者操作
|
||||
|
||||
作者在作品编辑态至少支持 4 个动作:
|
||||
|
||||
1. `使用默认封面`
|
||||
2. `上传封面`
|
||||
3. `AI 生成封面`
|
||||
4. `重置为默认`
|
||||
|
||||
约束:
|
||||
|
||||
1. 上传和 AI 生成都必须把最终图片落到后端资产目录,前端不能长期持有 Data URL 作为作品封面
|
||||
2. 重置为默认后,`sourceType` 回到 `default`
|
||||
3. 草稿与已发布作品都读取同一份封面属性,不允许出现“草稿页是一个封面、发布后又自动换另一张”的漂移
|
||||
|
||||
## 7.6 AI 封面生成与上传约束
|
||||
|
||||
### AI 生成输入
|
||||
|
||||
作者点击 `AI 生成封面` 后,面板至少支持 3 类输入:
|
||||
|
||||
1. 一句封面图描述
|
||||
2. 可选参考图
|
||||
3. 角色出镜选择
|
||||
|
||||
系统生成封面时,后端必须自动拼接以下上下文,而不是只吃用户那一句描述:
|
||||
|
||||
1. 世界名、副标题、世界概述、主题基调、玩家目标
|
||||
2. 开局场景第一幕标题、摘要、背景图
|
||||
3. 营地图与关键场景图
|
||||
4. 可扮演角色主形象
|
||||
5. 已选择的封面角色顺序
|
||||
|
||||
结论:
|
||||
|
||||
**封面 AI 生成必须是“用户一句描述 + 系统世界素材拼接”的生成链,而不是裸 prompt。**
|
||||
|
||||
### AI 生成结果要求
|
||||
|
||||
1. 默认生成尺寸固定为 `16:9`
|
||||
2. 第一版统一生成 `1600 × 900`
|
||||
3. 结果图不允许出现标题字、水印、按钮、UI 边框
|
||||
4. 结果图要优先满足移动端卡片裁切后的主体可读性
|
||||
5. 结果图保存后直接写入作品封面资产目录
|
||||
|
||||
### 上传封面要求
|
||||
|
||||
作者点击 `上传封面` 后,不能直接把原图原样落库,必须经过独立裁剪面板处理。
|
||||
|
||||
裁剪链路要求:
|
||||
|
||||
1. 上传后先进入独立裁剪面板
|
||||
2. 裁剪框比例固定为 `16:9`
|
||||
3. 作者只能平移和缩放,不允许自由改比例
|
||||
4. 裁剪完成后,再提交给后端保存
|
||||
|
||||
### 上传大小与格式限制
|
||||
|
||||
第一版约束:
|
||||
|
||||
1. 仅支持 `png / jpg / webp`
|
||||
2. 上传原图大小上限固定为 `10 MB`
|
||||
3. 后端落库前必须统一裁剪并缩放到 `1600 × 900`
|
||||
4. 后端保存时需要做体积压缩,目标成品图不超过 `1.5 MB`
|
||||
5. 若压缩后仍超过限制,返回明确错误,不允许静默保存超标文件
|
||||
|
||||
### 前后端分工
|
||||
|
||||
1. 前端负责提供裁剪交互、预览与提交裁剪框
|
||||
2. 后端负责最终裁剪、缩放、压缩和大小校验
|
||||
3. 前端不能直接把本地裁剪结果当最终事实来源
|
||||
4. 同一张上传封面在草稿页、作品库、详情页必须读取同一后端成品地址
|
||||
|
||||
### 已发布卡片主操作
|
||||
|
||||
第一版必须有:
|
||||
|
||||
1. `进入世界`
|
||||
|
||||
可选:
|
||||
|
||||
1. `查看作品`
|
||||
2. `基于此作品继续创作`
|
||||
|
||||
第一版不强制做“基于已发布作品继续创作”,避免先把发布后再开草稿链带复杂。
|
||||
|
||||
---
|
||||
|
||||
## 8. 作品摘要数据结构
|
||||
|
||||
## 8.1 新增统一作品摘要结构
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
type CustomWorldWorkStatus = 'draft' | 'published';
|
||||
type CustomWorldWorkSource = 'agent_session' | 'published_profile';
|
||||
|
||||
interface CustomWorldWorkSummary {
|
||||
workId: string;
|
||||
sourceType: CustomWorldWorkSource;
|
||||
status: CustomWorldWorkStatus;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
summary: string;
|
||||
coverImageSrc?: string | null;
|
||||
coverRenderMode?: 'image' | 'scene_with_roles';
|
||||
coverCharacterImageSrcs?: string[];
|
||||
updatedAt: string;
|
||||
publishedAt?: string | null;
|
||||
stage?: string | null;
|
||||
stageLabel?: string | null;
|
||||
playableNpcCount: number;
|
||||
landmarkCount: number;
|
||||
sessionId?: string | null;
|
||||
profileId?: string | null;
|
||||
canResume: boolean;
|
||||
canEnterWorld: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## 8.2 字段解释
|
||||
|
||||
### `workId`
|
||||
|
||||
统一主键,用于前端列表渲染。
|
||||
|
||||
建议格式:
|
||||
|
||||
- 草稿:`draft:${sessionId}`
|
||||
- 已发布:`published:${profileId}`
|
||||
|
||||
### `sourceType`
|
||||
|
||||
用于区分:
|
||||
|
||||
1. Agent 草稿 session
|
||||
2. 已发布 profile
|
||||
|
||||
### `status`
|
||||
|
||||
只允许两类:
|
||||
|
||||
1. `draft`
|
||||
2. `published`
|
||||
|
||||
### `stage / stageLabel`
|
||||
|
||||
仅草稿需要。
|
||||
|
||||
已发布作品可为空。
|
||||
|
||||
### `canResume`
|
||||
|
||||
仅草稿为 `true`
|
||||
|
||||
### `canEnterWorld`
|
||||
|
||||
仅已发布作品为 `true`
|
||||
|
||||
### `coverRenderMode / coverCharacterImageSrcs`
|
||||
|
||||
用于支撑默认封面布局。
|
||||
|
||||
规则:
|
||||
|
||||
1. 当作品封面为上传或 AI 生成成图时:
|
||||
- `coverRenderMode = image`
|
||||
- `coverCharacterImageSrcs = []`
|
||||
|
||||
2. 当作品封面为默认布局时:
|
||||
- `coverRenderMode = scene_with_roles`
|
||||
- `coverImageSrc = 开局场景图`
|
||||
- `coverCharacterImageSrcs = 需要叠加的角色主图列表`
|
||||
|
||||
一句话:
|
||||
|
||||
**后端负责告诉前端“这张封面该怎么画”,前端只负责把它画出来。**
|
||||
|
||||
---
|
||||
|
||||
## 9. 后端接口设计
|
||||
|
||||
## 9.1 新增作品列表接口
|
||||
|
||||
必须新增:
|
||||
|
||||
`GET /api/runtime/custom-world/works`
|
||||
|
||||
这是创作页面的核心接口。
|
||||
|
||||
它负责返回:
|
||||
|
||||
1. 当前用户的草稿 session 摘要
|
||||
2. 当前用户的已发布世界摘要
|
||||
3. 按统一结构聚合后的作品列表
|
||||
|
||||
## 9.2 接口返回结构
|
||||
|
||||
```ts
|
||||
interface ListCustomWorldWorksResponse {
|
||||
items: CustomWorldWorkSummary[];
|
||||
}
|
||||
```
|
||||
|
||||
### 第一版要求
|
||||
|
||||
1. 后端一次性返回全量列表
|
||||
2. 前端做 tab 过滤
|
||||
3. 不做服务端分页
|
||||
|
||||
原因:
|
||||
|
||||
- 当前用户作品量预计不大
|
||||
- 先把结构做稳,比先做分页更重要
|
||||
|
||||
### 公开浏览与登录边界
|
||||
|
||||
创作首页与世界选择页必须拆分两类数据:
|
||||
|
||||
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 数据来源
|
||||
|
||||
### 草稿来源
|
||||
|
||||
来自:
|
||||
|
||||
- `customWorldAgentSessionStore`
|
||||
|
||||
筛选规则:
|
||||
|
||||
1. `stage !== published`
|
||||
2. 未被标记为归档 / 删除
|
||||
|
||||
### 已发布来源
|
||||
|
||||
来自:
|
||||
|
||||
- 当前自定义世界库
|
||||
|
||||
即:
|
||||
|
||||
- `runtimeRepository.listCustomWorldProfiles(userId)`
|
||||
|
||||
## 9.4 聚合服务
|
||||
|
||||
建议新增服务:
|
||||
|
||||
`server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
|
||||
职责:
|
||||
|
||||
1. 读取草稿 session
|
||||
2. 读取已发布 profile
|
||||
3. 编译成统一的 `CustomWorldWorkSummary[]`
|
||||
|
||||
### 明确要求
|
||||
|
||||
不允许在 route 里直接拼草稿和已发布数据。
|
||||
|
||||
---
|
||||
|
||||
## 10. 前端页面设计
|
||||
|
||||
## 10.1 页面组件
|
||||
|
||||
建议新增页面组件:
|
||||
|
||||
`src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
|
||||
这是新的创作页面主组件。
|
||||
|
||||
## 10.2 子组件建议
|
||||
|
||||
建议拆成:
|
||||
|
||||
1. `CustomWorldCreationHubHeader.tsx`
|
||||
2. `CustomWorldCreationStartCard.tsx`
|
||||
3. `CustomWorldWorkTabs.tsx`
|
||||
4. `CustomWorldWorkCard.tsx`
|
||||
5. `CustomWorldWorkList.tsx`
|
||||
6. `CustomWorldCreationHubEmptyState.tsx`
|
||||
|
||||
第一版如果不想拆太多,也允许先做成一个主组件加一个作品卡组件。
|
||||
|
||||
## 10.3 页面状态
|
||||
|
||||
页面至少要支持:
|
||||
|
||||
1. `loading`
|
||||
2. `ready`
|
||||
3. `error`
|
||||
4. `empty`
|
||||
|
||||
### `loading`
|
||||
|
||||
展示骨架屏,不展示空白页。
|
||||
|
||||
### `ready`
|
||||
|
||||
正常展示:
|
||||
|
||||
1. 新建作品区
|
||||
2. 筛选 tabs
|
||||
3. 作品列表
|
||||
|
||||
### `error`
|
||||
|
||||
展示:
|
||||
|
||||
1. 错误文案
|
||||
2. `重试` 按钮
|
||||
|
||||
### `empty`
|
||||
|
||||
分两类空态:
|
||||
|
||||
1. `全量空态`
|
||||
- 没有任何草稿,也没有已发布作品
|
||||
|
||||
2. `筛选空态`
|
||||
- 比如只看草稿时为空
|
||||
|
||||
## 10.4 页面交互
|
||||
|
||||
### 新建作品
|
||||
|
||||
点击后:
|
||||
|
||||
1. 打开 Agent launcher
|
||||
2. 创建新 session
|
||||
3. 成功后跳入 Agent workspace
|
||||
|
||||
### 草稿卡片点击
|
||||
|
||||
主按钮:
|
||||
|
||||
1. `继续创作`
|
||||
|
||||
触发:
|
||||
|
||||
1. 进入 `custom-world-agent`
|
||||
2. 带 `sessionId`
|
||||
|
||||
### 已发布卡片点击
|
||||
|
||||
主按钮:
|
||||
|
||||
1. `进入世界`
|
||||
|
||||
触发:
|
||||
|
||||
1. 读取对应 `profile`
|
||||
2. 调用当前进入世界流程
|
||||
|
||||
---
|
||||
|
||||
## 11. 与现有流程的接入方式
|
||||
|
||||
## 11.1 修改 `SelectionStage`
|
||||
|
||||
建议新增:
|
||||
|
||||
```ts
|
||||
type SelectionStage =
|
||||
| 'start'
|
||||
| 'world'
|
||||
| 'custom-world-home'
|
||||
| 'custom-world-agent'
|
||||
| ...
|
||||
```
|
||||
|
||||
## 11.2 世界选择页创建按钮改造
|
||||
|
||||
当前:
|
||||
|
||||
```text
|
||||
点击创建自定义世界
|
||||
-> 打开创建 modal
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```text
|
||||
点击创建自定义世界
|
||||
-> setSelectionStage('custom-world-home')
|
||||
```
|
||||
|
||||
## 11.3 创作页面与 Agent 工作区关系
|
||||
|
||||
关系必须明确:
|
||||
|
||||
1. 创作页面
|
||||
- 管理入口
|
||||
- 新建入口
|
||||
- 历史作品页
|
||||
|
||||
2. Agent 工作区
|
||||
- 具体创作编辑页
|
||||
|
||||
这两个页面不能混成一个组件。
|
||||
|
||||
---
|
||||
|
||||
## 12. UI 与交互约束
|
||||
|
||||
## 12.1 移动端优先
|
||||
|
||||
页面默认以移动端竖屏成立。
|
||||
|
||||
要求:
|
||||
|
||||
1. 新建作品区位于首屏
|
||||
2. tabs 横向可滚
|
||||
3. 平台“创作”页中的“我的创作”列表在移动端至少双列展示,不能继续沿用横向滚动卡片的固定宽度
|
||||
4. 不使用桌面化大表格
|
||||
5. 双列卡片必须采用紧凑栅格布局,标题、状态、时间允许换行或截断,但不能横向溢出或出现参差错位
|
||||
|
||||
## 12.2 页面保持清爽
|
||||
|
||||
遵守当前项目约束:
|
||||
|
||||
1. 不在页面中堆规则说明
|
||||
2. 不默认展示很多系统字段
|
||||
3. 不出现“大型表单式管理后台”感
|
||||
|
||||
## 12.3 作品卡信息密度
|
||||
|
||||
每张卡默认最多展示:
|
||||
|
||||
1. 标题
|
||||
2. 标签
|
||||
3. 更新时间
|
||||
4. 一行摘要
|
||||
5. 一张封面
|
||||
6. 一个主按钮
|
||||
|
||||
不要默认堆:
|
||||
|
||||
1. 大量统计字段
|
||||
2. 多排操作按钮
|
||||
3. 技术字段
|
||||
|
||||
---
|
||||
|
||||
## 13. 明确不做什么
|
||||
|
||||
本次创作页面 PRD 不做:
|
||||
|
||||
1. 不做完整 Agent 工作区
|
||||
2. 不做世界底稿生成
|
||||
3. 不做作品删除确认流
|
||||
4. 不做作品搜索排序高级功能
|
||||
5. 不做发布世界管理后台
|
||||
6. 不做已发布作品的二次派生创作
|
||||
|
||||
这些内容后续可接,但不属于本次页面 PRD 核心闭环。
|
||||
|
||||
---
|
||||
|
||||
## 14. 验收标准
|
||||
|
||||
做到以下几点,才算这个创作页面真正成立:
|
||||
|
||||
1. 世界选择页点击“创建自定义世界”后,进入的是独立创作页面,不再是旧弹窗。
|
||||
2. 创作页面能同时展示草稿和已发布作品。
|
||||
3. 草稿作品可以继续创作。
|
||||
4. 已发布作品可以进入世界。
|
||||
5. 新建作品入口可以正确创建 Agent session 并跳转到创作工作区。
|
||||
6. 页面在移动端首屏可用,信息层级清楚。
|
||||
7. 草稿与已发布作品都通过后端聚合接口返回,前端不自己拼数据来源。
|
||||
|
||||
---
|
||||
|
||||
## 15. 推荐落地顺序
|
||||
|
||||
## 阶段 A:先做后端聚合接口
|
||||
|
||||
先做:
|
||||
|
||||
1. `GET /api/runtime/custom-world/works`
|
||||
2. `customWorldWorkSummaryService`
|
||||
|
||||
验收:
|
||||
|
||||
- 能返回统一的作品摘要数组
|
||||
|
||||
## 阶段 B:再做前端创作页面
|
||||
|
||||
先做:
|
||||
|
||||
1. `custom-world-home` stage
|
||||
2. `CustomWorldCreationHub`
|
||||
3. 作品卡片和 tabs
|
||||
|
||||
验收:
|
||||
|
||||
- 能看到新建入口和历史作品
|
||||
|
||||
## 阶段 C:最后接 Agent workspace 跳转
|
||||
|
||||
先做:
|
||||
|
||||
1. 新建作品 -> 创建 session -> 进入 workspace
|
||||
2. 草稿 -> 恢复 session
|
||||
3. 已发布作品 -> 进入世界
|
||||
|
||||
验收:
|
||||
|
||||
- 三条主路径都通
|
||||
|
||||
---
|
||||
|
||||
## 16. 一句话结论
|
||||
|
||||
“创建自定义世界”不应该继续只是一个弹窗动作,而应该升级成一个正式的创作入口。
|
||||
|
||||
这个创作页面的本质价值,不是多做一个页面,而是把:
|
||||
|
||||
- 新建作品
|
||||
- 继续草稿
|
||||
- 查看已发布作品
|
||||
|
||||
这三类本来分散的行为,正式收口到同一个创作中心里。
|
||||
@@ -0,0 +1,734 @@
|
||||
# AI 原生叙事线索驱动的物品命名与大世界 NPC 背景系统 PRD
|
||||
|
||||
更新时间:`2026-04-06`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份 PRD 面向当前仓库,解决两个直接影响“故事感”的核心问题:
|
||||
|
||||
1. 实时生成的物品名称、描述虽然已经能贴合 build 和来源,但整体仍偏模板拼接,缺少“它背后发生过什么”的故事重量。
|
||||
2. 大世界生成的 NPC 背景目前更像设定摘要,尤其是初始好感度低的角色,容易只剩“冷淡 / 戒备 / 不说”,却没有真正的戏剧张力和暗线钩子。
|
||||
|
||||
本次设计参考《博德之门 3》《黑神话:悟空》这类 RPG 的叙事组织方式,但不照搬具体内容,而是提炼出适合当前项目的 4 个目标:
|
||||
|
||||
1. 每个 NPC 都不仅有“公开设定”,还要有能被逐步识别的明线、暗线、代价线与回响线。
|
||||
2. 每个运行时物品都不仅是“当前 build 的奖励”,还要像某件旧事留下的证物、遗物、债物或禁物。
|
||||
3. 初始好感度低不等于故事薄;低好感角色要更像“有东西不肯说”,而不是“没有东西可说”。
|
||||
4. AI 继续负责叙事表达与意图,本地规则继续负责数值、合法性、状态迁移与编译。
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让角色背景、物品名称、物品描述都成为世界主线与暗线的载体,而不是玩法奖励外面包的一层随机文案。**
|
||||
|
||||
## 1. 当前问题定位
|
||||
|
||||
## 1.1 运行时物品叙事目前仍偏模板拼接
|
||||
|
||||
当前实现已经有 `runtimeItemContext -> runtimeItemDirector -> runtimeItemCompiler -> runtimeItemNarrative` 这条主链,玩法层是成立的,但叙事密度仍然不够。
|
||||
|
||||
主要问题有 3 个:
|
||||
|
||||
1. `src/data/runtimeItemNarrative.ts`
|
||||
- 名称仍然主要依赖 `来源词 + 关系词 + 功能词` 的固定拼接。
|
||||
- 描述仍然主要是“谁留下的什么 + 为什么出现 + 偏向什么 build”的单模板句式。
|
||||
|
||||
2. `src/data/runtimeItemNarrative.ts`
|
||||
- fallback 的 `reasonToAppear` 仍是“与最近局势把它推到了你面前”这一类通用解释。
|
||||
- 这能解释“为什么它不是纯随机”,但解释不了“它到底见证过什么”。
|
||||
|
||||
3. `src/services/runtimeItemAiPrompt.ts`
|
||||
- 当前 AI contract 仍聚焦 `shortNameSeed / sourcePhrase / reasonToAppear / relationHooks / desiredBuildTags`。
|
||||
- 它能产出“贴合当前局势”的轻量意图,但还不够支撑“证物感、传闻感、宿命感、旧债感”。
|
||||
|
||||
结果就是:
|
||||
|
||||
- 物品已经不再是纯随机装备,但还没有成为能埋故事线索的叙事节点。
|
||||
- 玩家会知道“它适合当前 build”,但不一定会对“它从哪段旧事里来”产生兴趣。
|
||||
|
||||
## 1.2 自定义世界 NPC 生成仍偏“字段补齐”,不够像故事角色
|
||||
|
||||
当前 `src/services/customWorld.ts` 的自定义世界生成已经能产出完整的:
|
||||
|
||||
- `backstory`
|
||||
- `personality`
|
||||
- `motivation`
|
||||
- `combatStyle`
|
||||
- `backstoryReveal`
|
||||
- `skills`
|
||||
- `initialItems`
|
||||
|
||||
但问题在于,它更像一份“角色设定卡 JSON”,而不是“能在游玩里逐步显影的故事人物”。
|
||||
|
||||
当前的主要限制有:
|
||||
|
||||
1. 单次生成字段很多,但每个字段长度被压得很短。
|
||||
2. `backstoryReveal` 固定 4 章,但更像摘要切片,而不是围绕世界冲突组织的叙事章节。
|
||||
3. 生成要求强调“不要改定位、不要超字段、字符串尽量简洁”,这对结构稳定有帮助,但会明显牺牲戏剧性。
|
||||
|
||||
结果就是:
|
||||
|
||||
- NPC 有设定,但缺少真正的事件痕迹。
|
||||
- NPC 有动机,但缺少真正的秘密、债务、误认、旧案、禁忌、未完成关系。
|
||||
- NPC 有章节,但章节之间没有足够强的剧情递进与回响。
|
||||
|
||||
## 1.3 自定义世界 NPC 的信息边界仍在越权泄露
|
||||
|
||||
这部分是当前“低好感角色仍然不神秘”的一个关键根因。
|
||||
|
||||
目前在 `src/services/prompt.ts` 中,自定义世界 NPC 遭遇描述仍会注入:
|
||||
|
||||
1. 完整 `backstory`
|
||||
2. 所有 `backstoryReveal.chapters`
|
||||
3. 技能与初始物品细节
|
||||
|
||||
同时 `describeCustomWorldSection(...)` 还会把多名 NPC 的:
|
||||
|
||||
- 公开背景
|
||||
- 完整背景
|
||||
- 动机
|
||||
- 技能
|
||||
- 初始物品
|
||||
- 章节 teaser
|
||||
|
||||
打成“自定义世界补充档案”整体注入。
|
||||
|
||||
这会直接导致两个问题:
|
||||
|
||||
1. 模型在第一次见面、低好感、甚至仅仅“面前遭遇”阶段,就已经站在“全知视角”上写角色。
|
||||
2. 角色表面上虽然还在说得很少,但模型其实已经知道太多,所以写出来的话会天然带着“设定卡背书感”,而不是“此刻只肯露一角”。
|
||||
|
||||
## 1.4 初始低好感角色目前更多是“收口”,不是“施压”
|
||||
|
||||
低好感角色无聊,核心不在于他们说得少,而在于他们缺少下面这些东西:
|
||||
|
||||
1. 面前局势里的压力
|
||||
2. 说辞与真实动机之间的错位
|
||||
3. 对某个旧事件、旧物、旧人、旧地的条件反射
|
||||
4. 让玩家感觉“这人知道点什么,但现在不肯给”的钩子
|
||||
|
||||
也就是说:
|
||||
|
||||
**当前低好感角色更多是信息减少了,但戏剧密度没有同步提高。**
|
||||
|
||||
## 2. 设计参考转译
|
||||
|
||||
本次设计参考的不是具体桥段,而是两类成熟 RPG 的叙事组织方法。
|
||||
|
||||
## 2.1 来自《博德之门 3》的可借鉴点
|
||||
|
||||
1. 角色秘密不是独立文本,而是会影响初见印象、后续关系、任务走向与物品反应。
|
||||
2. 物品、书信、遗物、口供、尸体、地标都在一起构成线索网,而不是各说各话。
|
||||
3. 真正有意思的角色,往往不是“设定很多”,而是“表面、欲望、隐瞒、代价”彼此错位。
|
||||
|
||||
## 2.2 来自《黑神话:悟空》的可借鉴点
|
||||
|
||||
1. 名称本身就带旧事与异感,不只是功能标签。
|
||||
2. 很多信息不是直接说明,而是通过残缺线索、旧痕、俗称、误传、传闻去显影。
|
||||
3. 角色和物件都会带一种“事已经发生过,但后劲还在”的叙事余震。
|
||||
|
||||
## 2.3 对当前项目的转译原则
|
||||
|
||||
转成当前仓库可落地的做法后,所有重点 NPC 与重点物品都必须携带四条线:
|
||||
|
||||
1. 明线
|
||||
- 玩家当前就能感知到的表层目标、来意、用途、冲突位置。
|
||||
|
||||
2. 暗线
|
||||
- 与世界冲突、旧事件、秘密关系、禁忌知识有关,但此刻不完全说透的线。
|
||||
|
||||
3. 代价线
|
||||
- 角色或物品背后已经失去过什么、欠着什么、被谁盯上、为什么不能轻易松口。
|
||||
|
||||
4. 回响线
|
||||
- 能与其他 NPC、场景、任务、物品互相印证的共享线索、意象、事件伤痕或势力痕迹。
|
||||
|
||||
## 3. 设计原则
|
||||
|
||||
1. AI 负责叙事层,本地负责规则层。
|
||||
- 不能让模型直接决定数值、掉落预算、好感变化和状态迁移。
|
||||
|
||||
2. 首次接触只给“可见的一角”,不给“全量设定”。
|
||||
- 低好感阶段更要严格限制 prompt 注入范围。
|
||||
|
||||
3. 低好感降低的是披露深度,不是故事密度。
|
||||
- 对方可以不坦白,但必须有压力、矛盾、误导、观察和反应。
|
||||
|
||||
4. 物品必须先是叙事证物,再是功能容器。
|
||||
- build 倾向依然重要,但需要嵌在“它是谁留下的、为什么出现在这里”之中。
|
||||
|
||||
5. 世界里的 NPC、物品、场景要共享同一套叙事词根与事件节点。
|
||||
- 不允许每次生成都像一个独立小宇宙。
|
||||
|
||||
6. UI 展示保持克制。
|
||||
- 不在面板里默认堆规则说明,只展示结果与线索感,符合项目已有的清爽游戏 UI 要求。
|
||||
|
||||
## 4. 核心系统结论
|
||||
|
||||
建议把当前“物品叙事 + 大世界 NPC 背景”升级为:
|
||||
|
||||
**世界叙事图谱 -> NPC 叙事档案 -> 运行时物品叙事指纹 -> prompt 可见性裁剪 -> 反应与回响回写**
|
||||
|
||||
它不是新起一套独立玩法,而是补在当前这些模块之上:
|
||||
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/data/runtimeItemContext.ts`
|
||||
- `src/data/runtimeItemDirector.ts`
|
||||
- `src/data/runtimeItemNarrative.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
|
||||
## 5. 世界级叙事图谱设计
|
||||
|
||||
## 5.1 目标
|
||||
|
||||
给自定义世界补一层比 `summary / tone / factions / landmarks` 更强的叙事骨架,让 NPC 和物品都不是凭空生出来,而是从同一套世界秘密与旧事件里长出来。
|
||||
|
||||
## 5.2 建议新增的数据结构
|
||||
|
||||
```ts
|
||||
interface WorldNarrativeThread {
|
||||
id: string;
|
||||
title: string;
|
||||
lineType: 'visible' | 'shadow';
|
||||
summary: string;
|
||||
involvedFactions: string[];
|
||||
involvedNpcIds: string[];
|
||||
relatedLandmarkIds: string[];
|
||||
motifIds: string[];
|
||||
}
|
||||
|
||||
interface WorldNarrativeScar {
|
||||
id: string;
|
||||
title: string;
|
||||
pastEvent: string;
|
||||
visibleResidue: string;
|
||||
hiddenTruth: string;
|
||||
relatedNpcIds: string[];
|
||||
relatedLandmarkIds: string[];
|
||||
}
|
||||
|
||||
interface WorldNarrativeMotif {
|
||||
id: string;
|
||||
label: string;
|
||||
usage: 'name' | 'item' | 'dialogue' | 'landmark';
|
||||
examples: string[];
|
||||
}
|
||||
|
||||
interface CustomWorldNarrativeGraph {
|
||||
visibleThreads: WorldNarrativeThread[];
|
||||
shadowThreads: WorldNarrativeThread[];
|
||||
scars: WorldNarrativeScar[];
|
||||
motifs: WorldNarrativeMotif[];
|
||||
}
|
||||
```
|
||||
|
||||
并挂到:
|
||||
|
||||
```ts
|
||||
interface CustomWorldProfile {
|
||||
narrativeGraph?: CustomWorldNarrativeGraph;
|
||||
}
|
||||
```
|
||||
|
||||
## 5.3 叙事图谱最少产出要求
|
||||
|
||||
每个自定义世界最少应生成:
|
||||
|
||||
1. `3` 条明线线程
|
||||
2. `4~6` 条暗线线程
|
||||
3. `6~10` 个旧事件伤痕
|
||||
4. `12~20` 个世界词根 / 意象母题
|
||||
|
||||
这些词根不是为了写百科,而是为了让:
|
||||
|
||||
- NPC 名字外的说话习惯
|
||||
- 物品名称中的来源词
|
||||
- 物品描述中的事件痕迹
|
||||
- 地标描述中的遗留痕迹
|
||||
|
||||
能够反复互相印证。
|
||||
|
||||
## 6. 大世界 NPC 叙事档案设计
|
||||
|
||||
## 6.1 当前 `backstoryReveal` 的问题
|
||||
|
||||
当前 `backstoryReveal` 已经有“按好感解锁”的结构,但更接近“把背景拆成 4 段”,还不够像“有明线暗线的角色档案”。
|
||||
|
||||
建议保留现有外层结构,但新增一层更强的叙事骨架。
|
||||
|
||||
## 6.2 建议新增的数据结构
|
||||
|
||||
```ts
|
||||
interface NpcNarrativeDossier {
|
||||
publicMask: string;
|
||||
firstContactMask: string;
|
||||
visibleLine: string;
|
||||
shadowLine: string;
|
||||
contradiction: string;
|
||||
debtOrOath: string;
|
||||
hiddenFearOrTaboo: string;
|
||||
scenePressure: string;
|
||||
relatedThreadIds: string[];
|
||||
relatedScarIds: string[];
|
||||
motifIds: string[];
|
||||
reactionHooks: string[];
|
||||
linkedItemSeeds: string[];
|
||||
}
|
||||
```
|
||||
|
||||
建议挂到:
|
||||
|
||||
```ts
|
||||
interface CustomWorldRoleProfile {
|
||||
narrativeDossier?: NpcNarrativeDossier;
|
||||
}
|
||||
```
|
||||
|
||||
字段含义如下:
|
||||
|
||||
- `publicMask`
|
||||
- 外人最容易听到或看到的版本。
|
||||
|
||||
- `firstContactMask`
|
||||
- 第一次接触时这人会先拿出来挡在前面的那层说辞。
|
||||
|
||||
- `visibleLine`
|
||||
- 当前出现在此地、此刻最能被玩家感知到的表层线。
|
||||
|
||||
- `shadowLine`
|
||||
- 背后真正连着哪条暗线,但还不会直接说透。
|
||||
|
||||
- `contradiction`
|
||||
- 这个角色最值得被玩家察觉的“说辞与事实错位”。
|
||||
|
||||
- `debtOrOath`
|
||||
- 让角色更像活在故事中的关键债务、誓言、旧命令或未结关系。
|
||||
|
||||
- `hiddenFearOrTaboo`
|
||||
- 这个角色不愿被提起的人、事、地、物或称谓。
|
||||
|
||||
- `scenePressure`
|
||||
- 这个角色此刻为什么紧绷、拖延、转移、误导。
|
||||
|
||||
- `reactionHooks`
|
||||
- 未来哪些人名、物名、伤痕、势力称呼会触发反应。
|
||||
|
||||
## 6.3 低初始好感角色的写法规则
|
||||
|
||||
低好感不是“少写”,而是换成“斜着写、卡着写、顶着写”。
|
||||
|
||||
建议按初始好感分 4 档处理。
|
||||
|
||||
| 初始好感区间 | 角色手感 | 必须出现的内容 | 禁止出现的内容 |
|
||||
| --- | --- | --- | --- |
|
||||
| `<= -10` | 敌意、误认、警惕、试图抢占叙事主导权 | 现场威胁、对玩家的判断、一个错误说辞、一个破绽 | 上来完整交代来历 |
|
||||
| `-9 ~ 14` | 戒备、带压力的克制、把话题往表层拖 | 当前局势、表面理由、一个不愿明说的对象、一个观察细节 | 平铺直叙式自我介绍 |
|
||||
| `15 ~ 39` | 正常交流但不交底 | 表层目标、与场景关联、一个旧事余波 | 直接说最终动机 |
|
||||
| `>= 40` | 有合作空间但仍保留底牌 | 合作可能、旧债或旧誓、阶段性真相 | 一次性摊牌全部秘密 |
|
||||
|
||||
关键规则:
|
||||
|
||||
1. 低好感角色的首轮输出必须带“错位感”。
|
||||
2. 至少要有一个让玩家觉得“这句话不全对”的缝隙。
|
||||
3. 至少要有一个和此地事件、旧痕、物件、人物有关的具体钩子。
|
||||
|
||||
## 6.4 背景章节的重组方式
|
||||
|
||||
当前仍可保留 4 章,但不建议继续把它们仅仅当成“摘要 1、摘要 2、摘要 3、摘要 4”。
|
||||
|
||||
建议把 4 章改成稳定的功能分层:
|
||||
|
||||
1. `surface`
|
||||
- 表层来意 / 当下伪装 / 公开身份切口
|
||||
|
||||
2. `scar`
|
||||
- 旧事裂痕 / 已经失去的东西 / 不愿再提的一次失败
|
||||
|
||||
3. `bind`
|
||||
- 关系债务 / 誓言 / 阵营绑缚 / 必须维护的错误
|
||||
|
||||
4. `truth`
|
||||
- 真正目标 / 最终底牌 / 真相代价
|
||||
|
||||
保留 `id` 稳定,标题允许按世界主题动态生成,而不是固定文案。
|
||||
|
||||
## 6.5 章节文本的写法要求
|
||||
|
||||
每一章都必须同时回答两件事:
|
||||
|
||||
1. 这段旧事和世界哪条明线 / 暗线有关?
|
||||
2. 它为什么会影响这个 NPC 今天的说话方式、站位、物品、关系或敌意?
|
||||
|
||||
也就是说,章节正文不该只是“以前发生了什么”,而要能连回“现在为什么会这样”。
|
||||
|
||||
## 7. 运行时物品叙事指纹设计
|
||||
|
||||
## 7.1 当前问题
|
||||
|
||||
当前运行时物品已经能贴合:
|
||||
|
||||
- 场景
|
||||
- 遭遇
|
||||
- build 缺口
|
||||
- 关系锚点
|
||||
|
||||
但它更像“上下文化奖励”,还不够像“故事痕迹”。
|
||||
|
||||
## 7.2 建议新增的数据结构
|
||||
|
||||
```ts
|
||||
interface RuntimeItemStoryFingerprint {
|
||||
visibleClue: string;
|
||||
witnessMark: string;
|
||||
unfinishedBusiness: string;
|
||||
hiddenHook: string;
|
||||
relatedThreadIds: string[];
|
||||
relatedScarIds: string[];
|
||||
motifIds: string[];
|
||||
reactionHooks: string[];
|
||||
namingPattern:
|
||||
| 'npc_relic'
|
||||
| 'scene_relic'
|
||||
| 'faction_issue'
|
||||
| 'monster_trophy'
|
||||
| 'quest_evidence'
|
||||
| 'forbidden_object';
|
||||
}
|
||||
```
|
||||
|
||||
并挂到:
|
||||
|
||||
```ts
|
||||
interface RuntimeItemMetadata {
|
||||
storyFingerprint?: RuntimeItemStoryFingerprint;
|
||||
}
|
||||
```
|
||||
|
||||
## 7.3 每件重点物品必须携带的叙事要素
|
||||
|
||||
对 `rare` 及以上,或者 `narrativeWeight = medium / heavy` 的物品,至少要同时有:
|
||||
|
||||
1. 一个可见线索
|
||||
- 玩家光看名字、描述或出处就能捕到的痕迹。
|
||||
|
||||
2. 一个见证痕
|
||||
- 它像谁留下的、从哪次旧事里滚出来的、带着什么使用痕迹。
|
||||
|
||||
3. 一个未完成问题
|
||||
- 这件物品背后还有什么没结掉。
|
||||
|
||||
4. 一个当前出现理由
|
||||
- 为什么偏偏是现在、是这里、是你拿到它。
|
||||
|
||||
5. 一个可回响对象
|
||||
- 哪个 NPC / 场景 / 势力 / 任务之后可能对它起反应。
|
||||
|
||||
## 7.4 命名系统升级
|
||||
|
||||
当前的三段式命名方向是对的,但需要从“词块拼装”升级为“叙事指纹编译”。
|
||||
|
||||
建议按来源分 6 种命名范式:
|
||||
|
||||
| 命名范式 | 适用来源 | 推荐结构 | 示例风格 |
|
||||
| --- | --- | --- | --- |
|
||||
| 人物遗物 | NPC 奖励、遗失物 | 旧称 / 誓约 / 功能物 | `断旗旧誓护心佩` |
|
||||
| 场景遗物 | 宝藏、废墟、秘境 | 地标 / 灾痕 / 品类 | `沉炉灰纹短刃` |
|
||||
| 势力制式 | 商店、军需、黑市 | 势力 / 制式 / 用途 | `巡河司缉印符` |
|
||||
| 怪物战利 | 怪物掉落、生态素材 | 生态 / 异化 / 精粹 | `雾骨猎印精粹` |
|
||||
| 任务证物 | 委托、追查、交付 | 事件 / 口供 / 信物 | `沉港失契信物` |
|
||||
| 禁忌物 | 关键宝藏、暗线物 | 禁名 / 封痕 / 器类 | `烬名封缄骨匣` |
|
||||
|
||||
要求不是字数更长,而是:
|
||||
|
||||
- 名字里至少有一个世界词根
|
||||
- 至少有一个事件痕或关系痕
|
||||
- 最后才落到功能词或器类词
|
||||
|
||||
## 7.5 描述文案升级
|
||||
|
||||
当前描述模板需要升级为三层表达:
|
||||
|
||||
1. 第一层:可见痕迹
|
||||
- 这件东西看起来像经历过什么。
|
||||
|
||||
2. 第二层:旧事牵连
|
||||
- 它和谁、哪处、哪次旧事有关。
|
||||
|
||||
3. 第三层:当前局势意义
|
||||
- 为什么此刻来到玩家手里,以及它偏向什么战斗或 build 方向。
|
||||
|
||||
示例结构:
|
||||
|
||||
```text
|
||||
表面痕迹句。旧事牵连句。当前局势与玩法意义句。
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
1. 第二句必须有“谁 / 哪处 / 哪次事”的具体指向之一。
|
||||
2. 不能只有“适合当前 build”这种系统性总结。
|
||||
3. 允许保留一点空白,不要把暗线直接讲穿。
|
||||
|
||||
## 8. Prompt Contract 升级
|
||||
|
||||
## 8.1 自定义世界 NPC 生成 prompt 的问题
|
||||
|
||||
当前 prompt 的主要问题,不是字段不够,而是:
|
||||
|
||||
1. 生成阶段没有先产“世界叙事图谱”,导致 NPC 和物品共享词根不稳定。
|
||||
2. 角色阶段过早要求完整字段,导致模型更像在补设定表。
|
||||
3. 文本长度限制过严,压缩掉了故事张力。
|
||||
|
||||
## 8.2 建议改成三阶段生成
|
||||
|
||||
### 阶段 A:世界叙事图谱
|
||||
|
||||
先产出:
|
||||
|
||||
- `visibleThreads`
|
||||
- `shadowThreads`
|
||||
- `scars`
|
||||
- `motifs`
|
||||
|
||||
### 阶段 B:角色骨架
|
||||
|
||||
只产出:
|
||||
|
||||
- `name`
|
||||
- `title`
|
||||
- `role`
|
||||
- `description`
|
||||
- `initialAffinity`
|
||||
- `relationshipHooks`
|
||||
- `tags`
|
||||
- `narrativeDossier`
|
||||
|
||||
### 阶段 C:背景章节、技能、初始物品
|
||||
|
||||
基于前两阶段结果,再补:
|
||||
|
||||
- `backstory`
|
||||
- `backstoryReveal`
|
||||
- `skills`
|
||||
- `initialItems`
|
||||
|
||||
这样做的目的不是把流程变复杂,而是防止:
|
||||
|
||||
- 世界叙事图谱还没稳定,角色就先各自长成独立设定卡。
|
||||
|
||||
## 8.3 自定义世界 NPC 生成时的必填叙事约束
|
||||
|
||||
每个 NPC 必须明确写出:
|
||||
|
||||
1. 当前站在哪条明线上
|
||||
2. 真正卷入哪条暗线
|
||||
3. 一件已经发生过、仍在影响他的旧事
|
||||
4. 一个不愿被直问的对象、地点、称呼或物件
|
||||
5. 一个与玩家可能建立连接的切入口
|
||||
|
||||
## 8.4 运行时物品 AI contract 升级
|
||||
|
||||
建议在当前 `RuntimeItemAiIntent` 外增加叙事指纹字段:
|
||||
|
||||
```ts
|
||||
interface RuntimeItemAiIntent {
|
||||
shortNameSeed: string;
|
||||
sourcePhrase: string;
|
||||
reasonToAppear: string;
|
||||
relationHooks: string[];
|
||||
desiredBuildTags: string[];
|
||||
desiredFunctionalBias: Array<'heal' | 'mana' | 'cooldown' | 'guard' | 'damage'>;
|
||||
tone: 'grim' | 'mysterious' | 'martial' | 'ritual' | 'survival';
|
||||
visibleClue?: string;
|
||||
witnessMark?: string;
|
||||
unfinishedBusiness?: string;
|
||||
hiddenHook?: string;
|
||||
reactionHooks?: string[];
|
||||
namingPattern?: string;
|
||||
}
|
||||
```
|
||||
|
||||
AI 仍然不直接产出成品,只负责:
|
||||
|
||||
- 提供线索
|
||||
- 提供见证感
|
||||
- 提供未完成之事
|
||||
- 提供命名范式建议
|
||||
|
||||
本地编译层再决定:
|
||||
|
||||
- 最终名称
|
||||
- 最终描述
|
||||
- metadata 回写
|
||||
- 稀有度与 build 预算
|
||||
|
||||
## 9. Prompt 可见性裁剪规则
|
||||
|
||||
## 9.1 自定义世界 NPC 遭遇 prompt
|
||||
|
||||
必须修正为:
|
||||
|
||||
1. 首遇或低披露阶段
|
||||
- 只注入 `publicSummary`
|
||||
- 只注入 `firstContactMask / visibleLine / scenePressure`
|
||||
- 只注入已解锁章节的 `contextSnippet`
|
||||
|
||||
2. 禁止直接注入
|
||||
- 完整 `backstory`
|
||||
- 未解锁 `backstoryReveal.content`
|
||||
- 全量章节摘要
|
||||
|
||||
## 9.2 自定义世界总档案注入
|
||||
|
||||
`buildCustomWorldReferenceText(...)` 不能再把多名 NPC 的完整背景和章节提示整体塞进主 prompt。
|
||||
|
||||
建议改成:
|
||||
|
||||
1. 世界摘要
|
||||
2. 叙事图谱摘要
|
||||
3. 与当前场景 / 当前遭遇最相关的少量 NPC 索引
|
||||
|
||||
每名 NPC 只保留:
|
||||
|
||||
- 名称
|
||||
- 身份
|
||||
- 公开背景
|
||||
- 所在线程
|
||||
- 关键反应钩子
|
||||
|
||||
## 9.3 低好感阶段的 prompt 目标
|
||||
|
||||
模型应该知道的是:
|
||||
|
||||
- 这个角色此刻为什么不松口
|
||||
- 他在盯什么
|
||||
- 哪个问题会让他产生反应
|
||||
|
||||
模型不应该知道的是:
|
||||
|
||||
- 他完整的人生说明书
|
||||
|
||||
## 10. UI 表达建议
|
||||
|
||||
UI 侧保持项目当前的清爽方向,不默认堆规则说明文案。
|
||||
|
||||
建议只做这几种表达:
|
||||
|
||||
1. NPC 档案页
|
||||
- 公开背景
|
||||
- 已解锁章节
|
||||
- 未解锁章节 teaser
|
||||
- 不额外展示系统术语
|
||||
|
||||
2. 重点物品 tooltip / 描述区
|
||||
- 名称
|
||||
- 三层式描述
|
||||
- 如需增加额外信息,只显示“来历”或“传闻”一行,不做规则说明板
|
||||
|
||||
3. 与物品 / 人物的回响
|
||||
- 优先通过剧情文本、反应文本、任务追加线索体现
|
||||
- 不优先通过 UI 标签硬显示“这是一条暗线”
|
||||
|
||||
## 11. 验收标准
|
||||
|
||||
做到以下几点,才算这次需求真正成立:
|
||||
|
||||
1. 随机抽样 `20` 个运行时重点物品时,至少 `80%` 的名称能看出明确来源词与事件痕,不再像纯功能拼接词。
|
||||
2. 随机抽样 `20` 个运行时重点物品时,`100%` 的描述都能同时回答“它经历过什么”和“为什么此刻出现”。
|
||||
3. 随机抽样 `20` 个自定义世界 NPC 时,`100%` 都能指出自己挂在哪条明线、暗线和哪道旧伤上。
|
||||
4. 初始好感度低于 `15` 的 NPC,首轮文本中至少有一个“说辞与真实意图错位”的点。
|
||||
5. 首遇与低披露阶段的自定义世界 NPC prompt 中,不再直接注入完整 `backstory` 与未解锁章节。
|
||||
6. 同一世界内,物品名、场景名、NPC 章节和剧情文本之间,能够复用同一组词根与事件痕,而不是每次随机飘散。
|
||||
7. 玩家在不看后台数据的情况下,也能从名字、描述、对话和档案 teaser 中隐约拼出世界里的明线与暗线。
|
||||
|
||||
## 12. 推荐落地顺序
|
||||
|
||||
## 阶段 A:先修正信息边界与现状问题
|
||||
|
||||
优先改:
|
||||
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/customWorldReferenceText` 相关逻辑
|
||||
|
||||
目标:
|
||||
|
||||
- 堵住完整背景与未解锁章节的越权注入
|
||||
- 让低好感阶段先重新成立
|
||||
|
||||
## 阶段 B:补世界叙事图谱
|
||||
|
||||
新增:
|
||||
|
||||
- `CustomWorldNarrativeGraph`
|
||||
- 世界线程、旧伤、意象词根
|
||||
|
||||
目标:
|
||||
|
||||
- 让 NPC 与物品共享同一套故事母题
|
||||
|
||||
## 阶段 C:补 NPC 叙事档案
|
||||
|
||||
新增:
|
||||
|
||||
- `NpcNarrativeDossier`
|
||||
|
||||
调整:
|
||||
|
||||
- `backstoryReveal` 的生成逻辑
|
||||
- 低初始好感 NPC 的首遇表达规则
|
||||
|
||||
目标:
|
||||
|
||||
- 让“低好感但有戏”成为稳定产物
|
||||
|
||||
## 阶段 D:补运行时物品叙事指纹
|
||||
|
||||
新增:
|
||||
|
||||
- `RuntimeItemStoryFingerprint`
|
||||
|
||||
调整:
|
||||
|
||||
- `runtimeItemAiPrompt`
|
||||
- `runtimeItemNarrative`
|
||||
|
||||
目标:
|
||||
|
||||
- 让物品名称与描述能承载旧事、见证与未完成问题
|
||||
|
||||
## 阶段 E:做回响与反应
|
||||
|
||||
最后接:
|
||||
|
||||
- NPC 对特定物品的反应
|
||||
- 任务对物品线索的承接
|
||||
- 场景与旧伤的互相印证
|
||||
|
||||
目标:
|
||||
|
||||
- 让“名字和背景有故事”真正进入游玩闭环,而不是只停在文案层
|
||||
|
||||
## 13. 涉及文件建议
|
||||
|
||||
建议优先改动这些区域:
|
||||
|
||||
- `src/types/customWorld.ts`
|
||||
- `src/types/runtimeItem.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `src/data/runtimeItemNarrative.ts`
|
||||
- `src/data/runtimeItemDirector.ts`
|
||||
|
||||
建议新增这些模块:
|
||||
|
||||
- `src/services/customWorldNarrative.ts`
|
||||
- `src/services/customWorldNarrativePrompt.ts`
|
||||
- `src/data/runtimeItemStoryCompiler.ts`
|
||||
|
||||
## 14. 一句话结论
|
||||
|
||||
这次要做的,不是把物品文案写得更华丽,也不是把 NPC 背景写得更长,而是:
|
||||
|
||||
**让世界里的每个人、每件物都像被主线和暗线真正碰过,名字里有来路,描述里有旧事,对话里有保留,低好感时也能让玩家感觉到背后压着一整段没被说出来的故事。**
|
||||
@@ -0,0 +1,496 @@
|
||||
# AI 原生 NPC 单轮聊天会话迭代 PRD
|
||||
|
||||
更新时间:`2026-04-18`
|
||||
|
||||
## 0. 文档目的
|
||||
|
||||
本 PRD 只定义 `npc_chat` 在冒险主面板中的这一轮迭代落地方式。
|
||||
|
||||
目标不是新建一套聊天系统,而是在保持现有游戏 UI 外壳、剧情面板结构、消息流位置不变的前提下,把 `npc_chat` 从“触发一次后回到普通剧情流”升级为“进入可持续续写的单轮聊天会话”。
|
||||
|
||||
本次文档必须直接指导编码,避免需求落地漂移。
|
||||
|
||||
---
|
||||
|
||||
## 1. 一句话定义
|
||||
|
||||
玩家点击 `npc_chat` 后,进入 NPC 聊天模式;每次只完成一轮“玩家输入 -> NPC 回复 -> 角色形象播出好感度变化特效 -> 下一轮 3 个建议选项 + 1 个自定义输入”,直到玩家主动退出聊天。
|
||||
|
||||
---
|
||||
|
||||
## 2. 背景与问题
|
||||
|
||||
当前 `npc_chat` 更接近“触发一段剧情性对话”,而不是“持续聊天”:
|
||||
|
||||
1. 玩家点击聊天后,常常是一次性生成较长结果,再回到普通冒险选项。
|
||||
2. 缺少稳定的续聊状态,无法把多轮聊天作为一个连续会话维持。
|
||||
3. 好感度变化更多停留在逻辑层,玩家在消息流中感知不明显。
|
||||
4. 没有单独的退出聊天控制,用户只能被动等系统切回普通状态。
|
||||
5. 选项形态仍偏剧情动作,不够像聊天接话。
|
||||
|
||||
这会导致 `npc_chat` 的体验不像“和角色对话”,而像“触发一个剧情功能”。
|
||||
|
||||
---
|
||||
|
||||
## 3. 本次目标
|
||||
|
||||
本次迭代必须同时满足以下目标:
|
||||
|
||||
1. `npc_chat` 触发后进入聊天交互态。
|
||||
2. 聊天态沿用当前主冒险面板,不新增页面、不弹新系统。
|
||||
3. 每次用户只推进一轮对话。
|
||||
4. 每轮结束后稳定出现 `3` 个建议续聊选项。
|
||||
5. 每轮结束后稳定出现 `1` 个自定义输入框。
|
||||
6. 玩家选择建议项或提交自定义输入后,继续在同一消息队列中续写。
|
||||
7. 好感度增减不能再作为聊天系统消息插入队列,必须改为角色形象上的数值特效反馈。
|
||||
8. NPC 回复必须支持流式传输,并在前端边接收边解析显示。
|
||||
9. 背包按钮所在行的最右侧必须新增“退出聊天”按钮。
|
||||
10. 退出聊天后恢复普通冒险态,不保留当前聊天输入框与聊天建议项。
|
||||
|
||||
---
|
||||
|
||||
## 4. 明确不做
|
||||
|
||||
本次不做:
|
||||
|
||||
1. 不新建独立聊天页面。
|
||||
2. 不重做现有主面板 UI 结构。
|
||||
3. 不引入多 NPC 并行聊天。
|
||||
4. 不做聊天记录存档面板。
|
||||
5. 不做复杂关系公式配置后台。
|
||||
6. 不做语音输入、表情、附件等扩展输入能力。
|
||||
7. 不把前端改成承担关系计算或剧情判定。
|
||||
|
||||
---
|
||||
|
||||
## 5. 核心体验
|
||||
|
||||
## 5.1 进入聊天
|
||||
|
||||
当玩家点击 `npc_chat` 选项时:
|
||||
|
||||
1. 保持当前冒险面板布局不变。
|
||||
2. 中部内容区切换为聊天消息流展示模式。
|
||||
3. 底部选项区切换为聊天建议区。
|
||||
4. 底部附加一个自定义输入框与发送按钮。
|
||||
5. 顶层不跳转、不弹窗、不覆盖成新页面。
|
||||
|
||||
## 5.2 单轮推进
|
||||
|
||||
单轮定义固定为:
|
||||
|
||||
1. 玩家通过“建议选项”或“自定义输入”提交一句话。
|
||||
2. 玩家消息立即进入消息队列。
|
||||
3. NPC 回复开始流式显示。
|
||||
4. 流式结束后,如果有关系变化,在角色形象上播放一次对应的数值特效。
|
||||
5. 系统刷新下一轮 `3` 个建议选项。
|
||||
6. 系统保留自定义输入入口,等待下一轮。
|
||||
|
||||
## 5.3 退出聊天
|
||||
|
||||
玩家点击“退出聊天”后:
|
||||
|
||||
1. 当前聊天态结束。
|
||||
2. 面板底部恢复普通冒险选项区域。
|
||||
3. 本轮聊天输入框、聊天建议项消失。
|
||||
4. 当前故事内容回到普通故事展示逻辑。
|
||||
|
||||
退出聊天不触发额外确认弹窗。
|
||||
|
||||
---
|
||||
|
||||
## 6. UI 设计要求
|
||||
|
||||
## 6.1 保持不变的部分
|
||||
|
||||
以下 UI 外壳保持当前实现:
|
||||
|
||||
1. 主冒险面板整体框架。
|
||||
2. 对话消息区所在位置。
|
||||
3. 底部操作区的整体层级。
|
||||
4. 队伍按钮、背包按钮的视觉风格。
|
||||
|
||||
## 6.2 必须变化的部分
|
||||
|
||||
### 消息区
|
||||
|
||||
1. 聊天态下,消息区按时间顺序展示:
|
||||
- 玩家消息
|
||||
- NPC 消息
|
||||
2. 好感度变化不再插入聊天消息流。
|
||||
3. 消息区不额外追加“关系升温 / 关系转冷”类文字提示。
|
||||
|
||||
### 角色形象特效
|
||||
|
||||
1. 若本轮好感度提升,必须在当前聊天对象的角色形象上飞出心形正向特效。
|
||||
2. 正向特效内必须显示本轮增加数值,例如:`+3`。
|
||||
3. 若本轮好感度下降,必须在当前聊天对象的角色形象上飞出负向特效。
|
||||
4. 负向特效内必须显示本轮减少数值,例如:`-2`。
|
||||
5. 特效应挂载在当前角色形象区域,而不是消息区、选项区或额外弹窗。
|
||||
6. 同一轮只播一次最近结算结果,不重复插入历史文本。
|
||||
|
||||
### 底部按钮区
|
||||
|
||||
1. 左侧仍保留队伍、背包按钮。
|
||||
2. 右侧在聊天态下展示“退出聊天”按钮。
|
||||
3. “退出聊天”按钮必须位于该行最右侧。
|
||||
4. 非聊天态下,该位置仍保持原有刷新选项按钮逻辑。
|
||||
|
||||
### 选项区
|
||||
|
||||
1. 聊天态下只展示 `3` 个续聊选项。
|
||||
2. 聊天态下不展示普通剧情选项附带的说明文案、目标提示、影响摘要。
|
||||
3. 聊天态下选项文案本身就是“下一句怎么接”。
|
||||
|
||||
### 输入区
|
||||
|
||||
1. 聊天态下在 3 个建议项下方展示输入框。
|
||||
2. 输入框右侧固定展示发送按钮。
|
||||
3. 输入框在请求进行中禁用。
|
||||
4. 点击发送或回车提交时,进入下一轮。
|
||||
|
||||
## 6.3 移动端要求
|
||||
|
||||
1. 移动端优先保证输入框与发送按钮可点击。
|
||||
2. 三个建议选项必须保持纵向堆叠,不做横向卡片排布。
|
||||
3. “退出聊天”按钮在小屏下仍需完整可见,不允许被背包按钮挤出。
|
||||
4. 输入框与发送按钮在窄屏下优先保证输入框宽度,其次压缩按钮内边距。
|
||||
|
||||
---
|
||||
|
||||
## 7. 前后端职责边界
|
||||
|
||||
遵循“前端只负责表现,逻辑和数据放后端”原则。
|
||||
|
||||
## 7.1 前端职责
|
||||
|
||||
前端只负责:
|
||||
|
||||
1. 进入/退出聊天态的 UI 切换。
|
||||
2. 渲染当前消息队列。
|
||||
3. 发送玩家本轮输入。
|
||||
4. 接收流式事件并实时更新 NPC 当前回复文本。
|
||||
5. 渲染角色形象上的好感度变化特效。
|
||||
6. 渲染下一轮 `3` 个建议项与自定义输入框。
|
||||
|
||||
前端不负责:
|
||||
|
||||
1. 生成 NPC 回复文本。
|
||||
2. 生成建议续聊选项。
|
||||
3. 计算关系增减。
|
||||
4. 解析剧情逻辑分支。
|
||||
|
||||
## 7.2 后端职责
|
||||
|
||||
后端负责:
|
||||
|
||||
1. 接收 NPC 单轮聊天请求。
|
||||
2. 结合当前世界、角色、NPC 状态、历史消息构建 prompt。
|
||||
3. 流式生成 NPC 回复。
|
||||
4. 解析回复内容。
|
||||
5. 生成下一轮 3 个建议续聊选项。
|
||||
6. 计算并返回本轮关系增减。
|
||||
7. 通过 SSE 向前端发送流式事件与最终结果。
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据结构要求
|
||||
|
||||
## 8.1 前端故事态扩展
|
||||
|
||||
`StoryMoment` 需要具备聊天态附加状态:
|
||||
|
||||
```ts
|
||||
type StoryNpcChatState = {
|
||||
npcId: string;
|
||||
npcName: string;
|
||||
turnCount: number;
|
||||
customInputPlaceholder?: string;
|
||||
};
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
1. 仅当当前故事处于 NPC 聊天模式时写入。
|
||||
2. `turnCount` 表示已完成的轮数。
|
||||
3. `npcId` 用于保证只续写当前聊天对象。
|
||||
|
||||
## 8.2 聊天消息结构
|
||||
|
||||
消息队列继续支持系统消息,用于战斗结算、流程收束等非好感提示:
|
||||
|
||||
```ts
|
||||
type StoryDialogueTurn = {
|
||||
speaker: 'player' | 'npc' | 'companion' | 'system';
|
||||
speakerName?: string;
|
||||
text: string;
|
||||
affinityDelta?: number;
|
||||
};
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
1. `system` 只用于关系变化、系统反馈类消息。
|
||||
2. `affinityDelta` 不再用于向聊天消息流插入好感提示。
|
||||
|
||||
新增聊天态特效事件:
|
||||
|
||||
```ts
|
||||
type StoryNpcAffinityEffect = {
|
||||
eventId: string;
|
||||
npcId: string;
|
||||
delta: number;
|
||||
};
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
1. 仅在本轮聊天真实发生好感变化时写入。
|
||||
2. `delta > 0` 表示正向心形特效。
|
||||
3. `delta < 0` 表示负向减少特效。
|
||||
4. 该事件只负责驱动角色形象表现,不负责生成消息文本。
|
||||
|
||||
## 8.3 单轮接口契约
|
||||
|
||||
请求:
|
||||
|
||||
```ts
|
||||
type NpcChatTurnRequest = {
|
||||
worldType: WorldType;
|
||||
player: Character;
|
||||
encounter: Encounter;
|
||||
history: StoryMoment[];
|
||||
dialogue: StoryDialogueTurn[];
|
||||
playerMessage: string;
|
||||
npcState: {
|
||||
affinity: number;
|
||||
chattedCount: number;
|
||||
recruited: boolean;
|
||||
};
|
||||
context: StoryGenerationContext;
|
||||
};
|
||||
```
|
||||
|
||||
返回完成事件载荷:
|
||||
|
||||
```ts
|
||||
type NpcChatTurnResult = {
|
||||
npcReply: string;
|
||||
affinityDelta: number;
|
||||
affinityText: string;
|
||||
suggestions: string[];
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 流式协议
|
||||
|
||||
本次统一使用 SSE。
|
||||
|
||||
## 9.1 事件类型
|
||||
|
||||
后端至少输出以下事件:
|
||||
|
||||
1. `reply_delta`
|
||||
2. `complete`
|
||||
3. `error`
|
||||
|
||||
## 9.2 事件含义
|
||||
|
||||
### `reply_delta`
|
||||
|
||||
用途:
|
||||
|
||||
1. 逐步推送 NPC 当前回复文本增量。
|
||||
2. 前端收到后立即更新消息流中“当前 NPC 气泡”的文本。
|
||||
|
||||
### `complete`
|
||||
|
||||
用途:
|
||||
|
||||
1. 标记本轮流式输出结束。
|
||||
2. 一次性返回最终结果对象:
|
||||
- `npcReply`
|
||||
- `affinityDelta`
|
||||
- `affinityText`
|
||||
- `suggestions`
|
||||
|
||||
### `error`
|
||||
|
||||
用途:
|
||||
|
||||
1. 标记本轮失败。
|
||||
2. 前端停止流式态并回退到可继续输入的状态。
|
||||
|
||||
## 9.3 前端解析规则
|
||||
|
||||
1. 当收到第一个 `reply_delta` 时,若消息流末尾还没有 NPC 临时消息,前端先插入一条空的 NPC 消息。
|
||||
2. 每次收到 `reply_delta`,替换该临时 NPC 消息文本。
|
||||
3. 收到 `complete` 后,把临时 NPC 消息固化为最终文本。
|
||||
4. 如果 `affinityDelta !== 0`,在 NPC 消息后追加一条系统关系消息。
|
||||
5. 之后再刷新下一轮建议选项。
|
||||
|
||||
---
|
||||
|
||||
## 10. 关系变化显示规则
|
||||
|
||||
## 10.1 显示位置
|
||||
|
||||
关系变化必须作为一条独立消息插入消息队列,位置在本轮 NPC 回复之后、下一轮建议项之前。
|
||||
|
||||
## 10.2 文案规则
|
||||
|
||||
1. 有增长时显示正向文案,例如:`关系升温 好感 +3`
|
||||
2. 有下降时显示负向文案,例如:`关系转冷 好感 -2`
|
||||
3. 无变化时不强制插入系统消息。
|
||||
|
||||
## 10.3 视觉规则
|
||||
|
||||
1. 关系变化消息居中显示。
|
||||
2. 关系变化消息使用不同于普通对话气泡的视觉样式。
|
||||
3. 正向变化可使用更暖色的边框/底色。
|
||||
4. 负向变化与中性反馈使用系统消息样式。
|
||||
|
||||
---
|
||||
|
||||
## 11. 交互流程
|
||||
|
||||
## 11.1 进入流程
|
||||
|
||||
```text
|
||||
玩家点击 npc_chat
|
||||
-> 系统进入聊天态
|
||||
-> 当前故事切换为聊天消息模式
|
||||
-> 展示本轮可选接话
|
||||
-> 展示自定义输入框
|
||||
```
|
||||
|
||||
## 11.2 单轮流程
|
||||
|
||||
```text
|
||||
玩家点击建议项或提交输入
|
||||
-> 玩家消息立即入队
|
||||
-> 前端发起 /runtime/chat/npc/turn/stream
|
||||
-> 后端流式返回 NPC 回复
|
||||
-> 前端边接收边渲染 NPC 当前回复
|
||||
-> complete 返回最终结果
|
||||
-> 前端插入关系变化系统消息
|
||||
-> 前端刷新下一轮 3 个建议项
|
||||
-> 等待下一轮输入
|
||||
```
|
||||
|
||||
## 11.3 退出流程
|
||||
|
||||
```text
|
||||
玩家点击退出聊天
|
||||
-> 清理当前聊天态标记
|
||||
-> 当前故事回到普通冒险展示
|
||||
-> 恢复普通选项区
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 状态更新规则
|
||||
|
||||
每完成一轮聊天,系统必须更新:
|
||||
|
||||
1. `npcState.affinity`
|
||||
2. `npcState.chattedCount`
|
||||
3. `npcState.relationState`
|
||||
4. `npcState.stanceProfile`
|
||||
5. `storyHistory`
|
||||
6. `currentStory.dialogue`
|
||||
7. `currentStory.npcChatState.turnCount`
|
||||
|
||||
要求:
|
||||
|
||||
1. 当前轮玩家输入和 NPC 回复都要进入故事历史。
|
||||
2. 关系变化消息属于展示型系统消息,可进入当前对话队列,但不要求作为独立剧情行动历史参与模型推理。
|
||||
|
||||
---
|
||||
|
||||
## 13. 异常与兜底
|
||||
|
||||
## 13.1 流式失败
|
||||
|
||||
如果流式失败:
|
||||
|
||||
1. 当前轮玩家消息保留。
|
||||
2. 不保留半截乱码式 NPC 文本。
|
||||
3. 前端恢复可继续输入状态。
|
||||
4. 使用后端或前端兜底建议项,保证仍有 3 个建议续聊选项可选。
|
||||
|
||||
## 13.2 建议项不足
|
||||
|
||||
如果后端返回建议项不足 `3` 条:
|
||||
|
||||
1. 由后端优先补齐兜底话术。
|
||||
2. 前端只展示最多 `3` 条。
|
||||
|
||||
## 13.3 空输入
|
||||
|
||||
空输入、纯空格输入不发请求。
|
||||
|
||||
---
|
||||
|
||||
## 14. 代码落点
|
||||
|
||||
本次迭代应优先落在现有链路:
|
||||
|
||||
### 前端
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts`
|
||||
2. `src/hooks/story/useStoryInteractionCoordinator.ts`
|
||||
3. `src/hooks/story/useStoryFlowCoordinator.ts`
|
||||
4. `src/hooks/useStoryGeneration.ts`
|
||||
5. `src/services/aiService.ts`
|
||||
6. `src/components/AdventurePanel.tsx`
|
||||
7. `src/components/GameShell.tsx`
|
||||
|
||||
### 共享契约
|
||||
|
||||
1. `packages/shared/src/contracts/story.ts`
|
||||
|
||||
### 后端
|
||||
|
||||
1. `server-node/src/routes/runtimeRoutes.ts`
|
||||
2. `server-node/src/services/chatService.ts`
|
||||
3. `server-node/src/modules/ai/chatPromptBuilders.ts`
|
||||
4. `server-node/src/modules/ai/chatOrchestrator.ts`
|
||||
|
||||
要求:
|
||||
|
||||
1. 复用现有故事流、运行时接口和主面板。
|
||||
2. 不另起新页面、新 store、新聊天系统。
|
||||
|
||||
---
|
||||
|
||||
## 15. 验收标准
|
||||
|
||||
以下全部满足才算通过:
|
||||
|
||||
1. 点击 `npc_chat` 后,面板进入聊天态而不是跳去新页面。
|
||||
2. 当前消息区能连续展示玩家消息、NPC 消息、系统关系消息。
|
||||
3. 每轮结束后稳定出现 `3` 个建议项。
|
||||
4. 每轮结束后稳定出现 `1` 个自定义输入框。
|
||||
5. 点击建议项可继续下一轮。
|
||||
6. 输入自定义文本后点击发送或回车可继续下一轮。
|
||||
7. NPC 回复支持流式逐字/逐段显示。
|
||||
8. 好感度变化会以消息形式插入聊天队列。
|
||||
9. 背包按钮所在行最右侧可见“退出聊天”按钮。
|
||||
10. 点击“退出聊天”后恢复普通冒险态。
|
||||
11. 聊天态下不显示普通剧情选项的说明、目标提示、影响摘要。
|
||||
12. 移动端下输入框、发送按钮、退出按钮均可正常操作。
|
||||
|
||||
---
|
||||
|
||||
## 16. 后续可扩展方向
|
||||
|
||||
本次上线后,再考虑后续迭代:
|
||||
|
||||
1. 更精细的关系变化公式。
|
||||
2. 基于 NPC 性格的建议续聊风格差异。
|
||||
3. 聊天摘要沉淀到长期记忆。
|
||||
4. 聊天中触发支线、任务、物品、邀约等事件。
|
||||
5. 退出聊天后保留“最近一次聊天摘要”。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user