init with react+axum+spacetimedb
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-26 18:06:23 +08:00
commit cbc27bad4a
20199 changed files with 883714 additions and 0 deletions

View 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、能进锻造、能进存档、还能被剧情解释的正式物品。**

View File

@@ -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. 一句话收束
这次需求的关键不是“给开局补一段特判对白”,而是把:
- 首遇节奏
- 背景披露节奏
- 私聊入口
- 关系记忆
统一到同一套“好感度 + 首遇状态 + 信息解锁”的通用规则里。
只有这样,玩家遇见每一个角色时才都会有对应关系位置上的初识感,角色背景才会像一步步了解出来的,同伴私聊也才会真的有价值。

View File

@@ -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 签名和过程入参漂移。

View File

@@ -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 应该负责“让这个世界长出来并跑起来”。**

View File

@@ -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 负责把它整理成可修改的策划初稿,系统负责把它稳定地跑成一个游戏世界。**

View File

@@ -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 阶段 BAgent 输出首轮世界底稿
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 风险 2Agent 过度代写,创作者失去作品归属感
防护方式:
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 化,但绝不能把“世界状态管理”也做成纯聊天。**

View File

@@ -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. 只负责兼容的旧模板字段
这样之后,自定义世界才会真正从:
**模板依赖型生成架构**
迁移成:
**跨题材、自有设定层、且兼容当前流程的生成架构。**

View File

@@ -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 从“依附模板世界”改成“直接从自定义世界自身编译”
同时整个过程必须遵守一条底线:
**任何优化都不能破坏当前自定义世界生成与运行主链。**
所以这不是“删模板”的问题,而是一次:
**在兼容现有流程前提下,把自定义世界从模板依赖型架构,迁移成真正跨题材、自足型架构。**

View 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 相似度”的方式形成构筑强度,并把这份构筑强度直接接进当前伤害输出,同时让怪物掉落、宝藏、交易、拆解、合成、锻造、铭刻围绕同一套标签体系形成闭环。

View File

@@ -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 强度自动落位的刻度

View File

@@ -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 不新增规则说明类文案。
- 原有“直接选择游戏创作模板,立刻进入对应的共创工作台。”说明在移动端隐藏,桌面端保留为辅助说明。
- 锁定、可创建、正在开启等状态继续来自既有模板元数据或忙碌状态。

View File

@@ -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
- 任务详情查看
- 正式领取后回流聊天
整合成一个更自然的叙事交接过程。

View File

@@ -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不新增后端逻辑。

View File

@@ -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. 未登录移动端首页页头存在明确 `登录` 入口,点击后打开同一个登录弹窗。

View File

@@ -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 文案。
- 修改中文文件后通过编码检查。

View 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
View 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

View File

@@ -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. 聊天结束后的“继续冒险”直接进入下一幕;最后一幕则展示多个相邻场景方向入口。

View File

@@ -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. 一条能延续到后面的余波
只有这样,当前项目的“场景章节化”才会从结构成立,进一步走到体验成立。

View File

@@ -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` 把章节任务继续编译成玩家当前目标
最终玩家感受到的就不再是“我只是进了一个新场景”,而会更接近:
**我进入了这一章,接住了这一章的任务,见到了这一章该见的人,也在这一章里把一段局势真正走完了。**

View 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` 时都不会关闭。
- 类型检查、编码检查通过。

View 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 连续几轮聊天时,信息释放节奏是连续的,不会忽冷忽热