This commit is contained in:
2026-04-26 14:27:48 +08:00
parent f68f4914ec
commit ea33413187
155 changed files with 8130 additions and 1740 deletions

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

@@ -199,4 +199,12 @@
---
## 17. 2026-04-26 创作编辑器关闭确认弹窗亮色主题修正
- `RpgCreationEntityEditorShared.tsx` 的未保存关闭确认统一收口为 `CloseConfirmDialog`,弹窗只保留确认信息和两个动作,不新增说明文案。
- `CloseConfirmDialog` 通过 `platform-close-confirm-dialog` 语义类接入平台主题 token提示块使用 `--platform-warm-*`,确认按钮使用 `--platform-button-primary-*`,继续编辑按钮使用 `--platform-neutral-*`
- 后续新增关闭 / 退出确认面板时,不要继续复制 `text-amber-50``text-sky-50``bg-black/*` 这类深色 Tailwind 组合;优先复用语义类,避免亮色主题出现浅底白字和按钮文字不可读。
---
_文档目的交接给下一个 Agent 时,优先读本文件 + `UI_CODING_STANDARD.md`,再改 `uiAssets.ts` / `App.tsx` / `index.css`。_

View File

@@ -97,6 +97,12 @@
- 当前仓库已进一步收口为:
不再提供右上角全局账号悬浮条,统一只保留页面内入口与独立账号面板。
### 4.6 冒险主场景双方角色必须按画面中线镜像
- 非滚动画面的交谈、预览、单体对峙态,主角和对面角色不能分别用左右边距、世界坐标和角色宽度重复推算。
- 正确做法是先定义“角色容器中心距离画面中线”的统一间距,再让主角中心落在中线左侧、对面角色中心落在中线右侧。
- 角色容器宽度、角色图片缩放和左右朝向必须各自独立处理,不能用额外 left inset 去修正角色图片,否则会破坏左右对称。
- 自定义图片 NPC、模板角色和组合式 NPC 都要进入同一 112px 场景容器,再按各自素材锚点做场景缩放,保证视觉大小不漂移。
## 5. 队伍面板经验
### 5.1 移动端成员列表不能太“卡片化”
@@ -202,3 +208,9 @@
- 可扮演角色的形象预览容器统一使用 1:1 方形,入口选择轮播、角色资产工坊和结果页角色卡片都不能用纵向长卡片去拉伸预览图。
- 预览图片本身使用 `object-contain`,保证 AI 生成主形象、模板像素角色和运行时动画都在方形容器内完整显示,不裁切角色主体。
- 卡片可以在方形预览下方放角色名、称号、状态等信息,但这些文本区不能反向影响预览区比例。
- 编辑角色弹窗也遵循同一规则:移动端不能用固定高度压扁预览区,预览容器应随宽度保持 `aspect-square`
### 10.2 运行画面怪物锚点按视觉底边校准
- 对战预览里主角和对手要沿画面中线成对出现,但纵向不能只共用一个 `bottom` 常量。
- 怪物精灵帧的空白、体型和脚底位置差异很大,运行画面应按帧高分档下沉,让怪物视觉底边落在主角同一条地面线上。
- 后续新增怪物资源时,先检查红圈标注的实际落点,再调整锚点分档或单怪物偏移,避免出现“悬在地面上方”的状态。

View File

@@ -214,7 +214,7 @@
- `name`
- `description`
- `imageSrc`
- `sceneNpcIds`
- `sceneNpcIds`(仅作为兼容字段,由多幕配置自动派生,不再作为创作者可编辑字段)
- `connections`
- `sceneChapterBlueprints` 对应的多幕配置
2. 场景配置面板中,开局场景必须复用普通场景同级的配置 UI而不是继续保留一套缩水版表单。
@@ -224,7 +224,7 @@
4. 除“初始所在场景”语义之外,不允许再因为它是开局场景而裁掉 NPC、连接、多幕、危险度等配置能力。
5. 为兼容现有数据,当前 `camp` 字段可以继续保留,但其承载的结构必须与普通场景对齐,不能再是阉割版场景结构。
6. 运行时编译时,开局场景也必须按普通场景规则参与:
- 场景 NPC 编译
- 多幕相遇 NPC 编译
- 场景连接编译
- 多幕蓝图读取
- 场景图片 / 残痕 / 预览数据生成
@@ -500,7 +500,7 @@ type NpcChatTurnResult = {
1. “场景图片”不再作为场景详情页里的独立字段展示,创作者只能通过每一幕的“配置背景”入口管理视觉。
2. “场景内 NPC”不再作为场景详情页里的独立字段展示创作者只能通过每一幕角色槽位配置相遇 NPC。
3. 为兼容现有运行时与旧数据结构,场景对象上的 `imageSrc / sceneNpcIds` 仍然保留,但必须由多幕配置自动回填,前台不再暴露单独编辑控件。
3. 为兼容现有运行时与旧数据结构,场景对象上的 `imageSrc / sceneNpcIds` 仍然保留,但必须由多幕配置自动回填,前台不再暴露单独编辑控件,且不能再用 `sceneNpcIds` 限制每幕可选角色
多幕区块至少展示:
@@ -553,7 +553,7 @@ type NpcChatTurnResult = {
NPC 配置面板必须支持:
1. 从当前世界的 `playableNpcs + storyNpcs` 中选择角色
2. 只展示与当前场景相关的优先推荐角色
2. 当前场景相关角色只能作为排序或推荐依据,不能过滤掉其他世界角色
3.`3` 个固定槽位进行配置,而不是长列表表单
4. 第一槽位明确标记为“主角色”
5. 允许同一角色出现在多个不同幕
@@ -566,6 +566,7 @@ NPC 配置面板必须支持:
3. 不允许把不存在于当前世界角色池中的 id 写入幕配置。
4. 若主角色未与当前场景或线程建立任何关联,给出发布警告。
5. 存储时继续落到 `encounterNpcIds` 有序数组,槽位从左到右按顺序压缩写入。
6. `sceneNpcIds` 不再作为创作者字段,也不再作为幕角色选择范围;保存时只从所有幕的 `encounterNpcIds` 自动派生兼容值。
## 7.6 幕预览

View File

@@ -0,0 +1,32 @@
# 创作页场景世界地图面板修复设计2026-04-25
## 背景
创作结果页进入“场景”编辑面板后,底部“查看世界地图”弹出的面板存在两个问题:
1. 面板仍使用偏运行时的深色地图容器,放在浅色创作页主题下时配色割裂,节点文字与背景层次也不稳定。
2. 地图只按传入的地标列表渲染,普通场景编辑时容易漏掉开局场景,无法形成完整“世界地图”视角。
## 落地范围
- `src/components/rpg-creation-editor/RpgCreationEntityEditorShared.tsx`
- `src/components/CustomWorldEntityEditorModal.test.tsx`
## 设计约束
1. 不新增说明类大段 UI 文案,只保留必要的节点名、方向标签和空状态。
2. 地图面板继续作为独立弹窗,不在当前场景连接面板下方展开。
3. 地图数据必须使用当前编辑中的草稿状态:
- 普通场景编辑:开局场景 + 已保存场景列表,并用当前 `draft` 替换正在编辑的场景。
- 新增普通场景:开局场景 + 已保存场景列表 + 当前 `draft`
- 开局场景编辑:当前 `draft` 开局场景 + 已保存场景列表。
4. 地图节点要标记当前编辑场景,连接线要展示方向短标签,避免用户只能看到无语义的线。
5. 配色使用 `platform-*` 主题变量,适配浅色与深色创作页主题。
## 验收点
1. 在普通场景编辑器点击“查看世界地图”后,弹窗中能同时看到开局场景和当前场景。
2. 未保存的场景连接关系会立刻体现在地图弹窗里。
3. 当前编辑场景节点有明确高亮。
4. 地图容器和节点不再固定为深色运行时风格。
5. 相关前端测试覆盖普通场景与开局场景两条入口。

View File

@@ -41,6 +41,7 @@
- 角色主图:`server-rs/crates/api-server/src/custom_world_asset_prompts.rs`
- `build_character_visual_prompt`
- 内部使用 `build_master_prompt`
- 只拼入用户可见的 `promptText` / `visualPromptText`,不再拼入 `characterBriefText` 或角色摘要字段。
- 角色动作视频:`server-rs/crates/api-server/src/custom_world_asset_prompts.rs`
- `build_character_animation_prompt`
- 图生视频分支使用 `build_video_action_prompt`

View File

@@ -20,6 +20,7 @@
- `eventDescription: string`
- 描述当前幕正在发生的事件。
- 必须强绑定 `oppositeNpcId` / `primaryNpcId` 所指角色,写清该角色的行动、阻碍、试探、求助或冲突。
- 三幕默认遵循戏剧曲线:第一幕铺垫并露出异常,第二幕让阻碍或立场冲突升级,第三幕进入高潮、关键抉择或直接后果。
- 默认生成兜底规则:`第N幕中玩家在当前场景遭遇/处理与某角色直接相关的事件,并推动当前场景问题升级或转向。`
兼容字段:
@@ -43,12 +44,33 @@
- `camp.sceneTaskDescription` 默认生成开局场景核心任务。
- `landmarks[*].sceneTaskDescription` 默认生成关键场景核心任务。
- `actEventDescriptions` 恰好 3 条,对应每一幕事件。
- `actEventDescriptions[0] / [1] / [2]` 必须分别承担铺垫、冲突、高潮,不允许三条只是同一事件的近义复述。
- `actBackgroundPromptTexts[n]` 必须基于同序号幕事件和相关角色写出画面主体、站位空间、冲突痕迹与氛围,不能只用场景名或幕标题拼接。
3. 后端合成 `sceneChapterBlueprints` 时把这些源字段落到:
- `sceneChapterBlueprints[*].sceneTaskDescription`
- `sceneChapterBlueprints[*].acts[*].oppositeNpcId`
- `sceneChapterBlueprints[*].acts[*].eventDescription`
4. 若 LLM 遗漏字段,归一化阶段用场景描述、入口钩子、角色名单生成中文默认值,保证草稿阶段字段非空。
5. 前端类型与归一化逻辑必须允许读取这些字段,旧草稿缺字段时仍自动补默认值。
6. 幕信息编辑界面必须直接展示 `eventDescription`,并在保存时保留 `sceneTaskDescription / oppositeNpcId / eventDescription / backgroundPromptText`,避免旧草稿经前端编辑后丢失后端生成字段。
## 幕配置预览标识
1. 幕配置预览图里只保留简洁角色点位标识,不新增说明类文案。
2. 主角固定在画面左侧可站立区域,对面角色槽位固定在画面右侧可站立区域:
- 主角色槽位位于画面中右侧,作为当前幕的主要对峙对象。
- 第二、第三角色槽位位于右侧上、下两个辅助位置,形成清晰的纵向层次。
3. 每个槽位使用圆形短标识表达序号:`主 / 2 / 3`,旁边只展示角色名或“添加角色”。
4. 标识必须有高对比底色、描边和轻微阴影,避免在浅色天空、地面纹理或深色背景上丢失。
5. 空槽位仍然可点击,但只能显示 `+` 与短标签,不能显示大段规则说明。
## 对话选项差异要求
运行时 NPC 聊天每轮生成的 3 个对话选项必须导向不同氛围和好感结果:
1. 第一条为温和共情或愿意倾听,通常让气氛缓和并更容易带来好感上升。
2. 第二条为冷静追问或试探,通常保持中性但推进情报。
3. 第三条为施压、质疑或立场冲突,通常让气氛变紧,可能带来好感下降或代价。
## 非目标

View File

@@ -88,13 +88,13 @@ Rust Stage 2 不再使用“LLM 先摘要再拼 SVG”的链路。
新的生成 prompt 口径:
1. 以请求里的 `promptText + characterBriefText` 组装正式主图 prompt
1. 以请求里的 `promptText` 组装正式主图 prompt;主形象不再拼入 `characterBriefText`,避免角色名、身份摘要、参考模板等非形象描述干扰体型、视角和风格约束
2. 约束必须覆盖:
1. 单人
2. 右向斜侧身
3. 1:1 正方形画布
4. 纯绿色绿幕
5. 34 头身
5. 11.5 头身
6. 像素动作角色
7. 不要扩写复杂背景
3. 主目标是与旧 Node `buildNpcVisualPrompt` 生成出的正式约束保持同方向

View File

@@ -64,6 +64,13 @@
返回绑定后的邀请中心状态与本次奖励发放结果。
## 落地状态
- `server-rs/crates/spacetime-module` 已新增邀请码与邀请关系表,邀请中心读取和填码绑定均通过 SpacetimeDB procedure 执行。
- `server-rs/crates/api-server` 已挂接 `/api/runtime/profile/referrals/*``/api/profile/referrals/*` 两组路由。
- 前端“我的”Tab 三个快捷入口均打开独立弹窗,玩家社区先使用空白二维码占位。
- 复制邀请会复制邀请码和邀请链接;填码成功后刷新个人看板积分。
## 前端交互
- 三个入口继续放在“我的”Tab 常用功能区,不新增页面。

View File

@@ -0,0 +1,52 @@
# RPG Agent 单字段锚点结构重构方案
## 背景
当前 RPG 创作 Agent 的 `anchorContent` 把每个锚点继续拆成多个子字段,例如 `worldPromise.hook / differentiator / desiredExperience``playerFantasy.playerRole / corePursuit / fearOfLoss`。这些子字段在语义上会互相重叠,后续基础设定展示又会把子字段用分隔符连接成“标签”,导致同一内容在一个锚点内或跨锚点重复出现。
本次重构将 `anchorContent` 收束为“每个锚点一个字段”。子字段不再作为数据结构保存,只保留为 prompt 中的生成关注点。
## 新数据结构
`anchorContent` 保留原有 8 个键,便于上下游和旧存档兼容,但每个键的值统一为 `string | null`
```ts
type RpgCreationAnchorContent = {
worldPromise: string | null;
playerFantasy: string | null;
themeBoundary: string | null;
playerEntryPoint: string | null;
coreConflict: string | null;
keyRelationships: string | null;
hiddenLines: string | null;
iconicElements: string | null;
};
```
## 生成口径
1. Agent 每轮仍然输出完整 `nextAnchorContent`,并覆盖上一版。
2. 每个锚点只输出一段凝练中文,不再输出对象或数组。
3. 旧的子字段关注点进入 prompt 约束:
- `worldPromise` 关注世界钩子、差异点、玩家体验。
- `playerFantasy` 关注玩家身份、核心追求、失去风险。
- `themeBoundary` 关注主题气质、美术方向、禁用方向。
- `playerEntryPoint` 关注开局身份、开局问题、行动动机。
- `coreConflict` 关注表层冲突、隐藏危机、首次触发点。
- `keyRelationships` 关注关键人物关系、关系类型、代价或秘密。
- `hiddenLines` 关注隐藏真相、误导线索、揭示节奏。
- `iconicElements` 关注标志意象、组织/物件、硬规则。
## 兼容策略
1. 后端读取旧 `anchorContent` 时,允许把旧对象/数组压缩成字符串。
2. 后端新写回永远写单字段字符串结构。
3. 前端契约和展示只按字符串字段读取,不再把子字段连接成标签。
4. 草稿生成、`creatorIntent``anchorPack` 均从单字段锚点派生。
## 验收点
1. Agent 对话后 `anchorContent` 的 8 个锚点值均为字符串或 `null`
2. 基础设定面板不再因为子字段连接产生重复标签。
3. 旧存档中的对象结构仍可被读取并压缩展示。
4. `draft_foundation` 生成种子直接使用 8 个单字段锚点。

View File

@@ -90,6 +90,9 @@
前排主角色与玩家角色保持同一 y 轴后排两个角色改为同一列、x 轴对齐并上下分布,且后排整体 y 轴中点与前排主角色一致
9. 新增幕默认只带 1 个主角色,后续槽位由创作者按需补充
10. 小预览里的名字已移动到角色头顶,角色渲染不再带方形底板,避免遮挡场景背景
11. 幕预览复用真实游戏壳时隐藏左上角角色等级徽标,退出入口固定在上方画面区域底部居中,并使用“结束预览”作为操作文案
12. 创作侧场景列表封面、多幕配置卡片、配置背景弹层统一读取同一张场景显示图;在任一幕保存背景时同步回全部幕背景字段和场景兼容图,避免同一场景在不同层级出现不同预览图
13. 场景角色预览图背景改用平台主题变量,亮色主题下不再保留深色预览底
## 2.6 负好感主角色有限聊天闭环