diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md
index 0ca4927b..fcc727ec 100644
--- a/.hermes/shared-memory/decision-log.md
+++ b/.hermes/shared-memory/decision-log.md
@@ -1305,3 +1305,11 @@
- 影响范围:拼消消工作台 payload、`shared-contracts` / `packages/shared` 契约、api-server 生成编排、SpacetimeDB session/work snapshot、文档与生成进度展示。
- 验证方式:`npm run spacetime:generate`、`npm run check:encoding`、`npm run check:server-rs-ddd`、`cargo test -p module-puzzle-clear`、`cargo test -p spacetime-client puzzle_clear -- --nocapture`、`npm run test -- src/components/puzzle-clear-creation/PuzzleClearWorkspace.test.tsx src/services/miniGameDraftGenerationProgress.test.ts src/routing/appPageRoutes.test.ts src/services/publicWorkCode.test.ts`。
- 关联文档:`docs/prd/【玩法创作】拼消消玩法模板PRD-2026-05-30.md`、`docs/technical/【玩法创作】拼消消玩法模板技术方案-2026-05-30.md`、`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。
+
+## 2026-06-06 统一创作页表头跟随后台玩法入口配置
+
+- 背景:统一创作页长期使用固定表头 `想做个什么玩法?`,导致跳一跳等玩法希望按自身语义展示标题时只能改前端或默认契约。
+- 决策:`creationTypes[].unifiedCreationSpec.title` 继续作为统一创作页表头传输字段,但默认值改为玩法入口中文名称;读取和保存时如果发现旧公共表头或代码默认中文名,则归一为当前入口 `title`,后台手动配置成其它标题时保留自定义值。
+- 影响范围:`shared-contracts` 默认 spec、`module-runtime` 入口配置响应、`spacetime-module` 后台保存归一化、后台入口开关页摘要和前端 fallback spec。
+- 验证方式:`GET /api/creation-entry/config` 中各玩法 `unifiedCreationSpec.title` 默认等于入口中文名;后台修改入口名称后,未自定义表头的统一创作页跟随变化。
+- 关联文档:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`。
diff --git a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx
index da9362d7..adad5145 100644
--- a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx
+++ b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.test.tsx
@@ -27,7 +27,7 @@ vi.mock('../api/adminApiClient', () => ({
const puzzleSpec: UnifiedCreationSpecPayload = {
playId: 'puzzle',
- title: '想做个什么玩法?',
+ title: '拼图',
workspaceStage: 'puzzle-agent-workspace',
generationStage: 'puzzle-generating',
resultStage: 'puzzle-result',
@@ -88,6 +88,9 @@ test('创作入口后台展示并保存统一创作契约', async () => {
await screen.findByText('pictureDescription');
expect(container.querySelector('.admin-subsection .admin-info-list')).not.toBeNull();
+ expect(
+ container.querySelector('.admin-subsection .admin-info-list')?.textContent,
+ ).toContain('拼图');
expect(container.querySelector('.admin-panel .admin-panel')).toBeNull();
expect(container.querySelector('.admin-muted')).toBeNull();
diff --git a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx
index 9de00709..9390f0f1 100644
--- a/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx
+++ b/apps/admin-web/src/pages/AdminCreationEntrySwitchPage.tsx
@@ -707,6 +707,10 @@ function UnifiedCreationSpecSummary({specJson}: {specJson: string}) {
玩法
{parsed.spec.playId}
+
+
表头
+ {parsed.spec.title}
+
阶段
diff --git a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md
index 9f950b43..4ed742ed 100644
--- a/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md
+++ b/docs/【玩法创作】平台入口与玩法链路-2026-05-15.md
@@ -14,7 +14,7 @@
创作恢复参数只保留 `sessionId`、`profileId`、`draftId`、`workId` 这四个私有 query。它们只允许在同一条创作链路的结果页、生成页、工作台之间保留;切到首页、公开作品详情、runtime 或另一条玩法链路时必须清掉。生成页等待时间统一以生成状态里的 `startedAtMs` 为准;创建该状态时优先使用后端 session 下发的时间戳,作品摘要里的 `updatedAt` 仍只用于排序与摘要展示,不作为前端自行推导业务状态的真相。
-统一创作入口覆盖当前可进入创作链路的已有模板:`rpg`、`big-fish`、`puzzle`、`match3d`、`jump-hop`、`wooden-fish`、`square-hole`、`bark-battle`、`visual-novel`、`baby-object-match` 和 `creative-agent`;`airp` 仍是未开放占位,不作为当前统一创作链路目标。拼图、抓大鹅、跳一跳和敲木鱼在前端继续经过 `UnifiedCreationWorkspace` 和 `UnifiedGenerationPage`:`UnifiedCreationWorkspace` 作为平台壳依赖的统一创作编排层,再内部调用 `src/components/unified-creation/workspaces/` 下的 `PuzzleCreationWorkspace`、`Match3DCreationWorkspace`、`JumpHopCreationWorkspace` 和 `WoodenFishCreationWorkspace`。其它已有模板由平台壳用 `UnifiedCreationPage` 包住既有工作台,复用统一标题栏、返回入口、页面级纵向滚动和隐藏字段契约,同时保留各玩法自己的表单、草稿恢复和后续编排。创作页字段清单由后端在 `GET /api/creation-entry/config` 的 `creationTypes[].unifiedCreationSpec` 下发,前端仅在该扩展位缺失时回退到本地默认 spec;字段类型只保留 `text`、`select`、`image`、`audio`。`UnifiedCreationPage` 不在 UI 中额外展示字段说明 chip,也不在右上角显示内部 `playId`、模板 ID 或工作台阶段名;竖屏移动端必须能从标题、表单一路滑到提交按钮。各玩法工作台负责渲染真实输入控件、上传、历史素材、校验和提交,但返回按钮只保留在统一页头,工作台内部不再重复渲染。暗色创作进度卡片位于 `platform-remap-surface` 内时,必须用组件专属 class 覆盖浅色主题 remap,确保白字、浅色边框和进度条底色不会被全局规则改成深色;不要只依赖通用 `text-white*` 类。敲木鱼的音效和功德词条面板不得放进独立内部滚动容器,移动端应跟随页面自然滚动展开。生成页统一展示阶段、当前步骤、总进度、错误和重试动作。
+统一创作入口覆盖当前可进入创作链路的已有模板:`rpg`、`big-fish`、`puzzle`、`match3d`、`jump-hop`、`wooden-fish`、`square-hole`、`bark-battle`、`visual-novel`、`baby-object-match` 和 `creative-agent`;`airp` 仍是未开放占位,不作为当前统一创作链路目标。拼图、抓大鹅、跳一跳和敲木鱼在前端继续经过 `UnifiedCreationWorkspace` 和 `UnifiedGenerationPage`:`UnifiedCreationWorkspace` 作为平台壳依赖的统一创作编排层,再内部调用 `src/components/unified-creation/workspaces/` 下的 `PuzzleCreationWorkspace`、`Match3DCreationWorkspace`、`JumpHopCreationWorkspace` 和 `WoodenFishCreationWorkspace`。其它已有模板由平台壳用 `UnifiedCreationPage` 包住既有工作台,复用统一标题栏、返回入口、页面级纵向滚动和隐藏字段契约,同时保留各玩法自己的表单、草稿恢复和后续编排。创作页字段清单和表头由后端在 `GET /api/creation-entry/config` 的 `creationTypes[].unifiedCreationSpec` 下发,前端仅在该扩展位缺失时回退到本地默认 spec;字段类型只保留 `text`、`select`、`image`、`audio`。统一创作页表头属于后台玩法入口配置,默认使用同一入口的中文名称;旧库里仍持久化为 `想做个什么玩法?` 或代码默认中文名的 spec title,会在读取和保存时归一到当前入口名称,后台单独写成其它标题时保留该自定义值。`UnifiedCreationPage` 不在 UI 中额外展示字段说明 chip,也不在右上角显示内部 `playId`、模板 ID 或工作台阶段名;竖屏移动端必须能从标题、表单一路滑到提交按钮。各玩法工作台负责渲染真实输入控件、上传、历史素材、校验和提交,但返回按钮只保留在统一页头,工作台内部不再重复渲染。暗色创作进度卡片位于 `platform-remap-surface` 内时,必须用组件专属 class 覆盖浅色主题 remap,确保白字、浅色边框和进度条底色不会被全局规则改成深色;不要只依赖通用 `text-white*` 类。敲木鱼的音效和功德词条面板不得放进独立内部滚动容器,移动端应跟随页面自然滚动展开。生成页统一展示阶段、当前步骤、总进度、错误和重试动作。
创作表单提交前的泥点余额前置校验只允许用独立弹窗提示失败原因,不得把用户退回创作入口或玩法模板列表,也不得清空当前表单状态。当前适用拼图、抓大鹅和汪汪声浪等会在前端提交前校验泥点的生成入口;余额不足、余额读取失败都应停留在当前工作台,由用户关闭提示后继续编辑或自行补足泥点。
diff --git a/server-rs/crates/module-runtime/src/application.rs b/server-rs/crates/module-runtime/src/application.rs
index 2c578dd9..cae5c119 100644
--- a/server-rs/crates/module-runtime/src/application.rs
+++ b/server-rs/crates/module-runtime/src/application.rs
@@ -12,7 +12,7 @@ use crate::format_utc_micros;
use shared_contracts::creation_entry_config::{
CreationEntryConfigResponse, CreationEntryEventBannerResponse, CreationEntryStartCardResponse,
CreationEntryTypeModalResponse, CreationEntryTypeResponse,
- encode_unified_creation_spec_response, resolve_unified_creation_spec_response,
+ encode_unified_creation_spec_response, resolve_unified_creation_spec_response_with_entry_title,
};
/// 将创作入口领域快照转换为前后台共享的 HTTP 契约响应。
@@ -45,8 +45,9 @@ pub fn build_creation_entry_config_response(
.creation_types
.into_iter()
.map(|item| {
- let unified_creation_spec = resolve_unified_creation_spec_response(
+ let unified_creation_spec = resolve_unified_creation_spec_response_with_entry_title(
item.id.as_str(),
+ item.title.as_str(),
item.unified_creation_spec_json.as_deref(),
);
CreationEntryTypeResponse {
@@ -161,10 +162,9 @@ fn normalize_creation_entry_announcement_banner_value(
);
}
- let banner = serde_json::from_value::(Value::Object(
- object.clone(),
- ))
- .map_err(|error| format!("第 {} 条公告对象非法:{error}", index + 1))?;
+ let banner =
+ serde_json::from_value::(Value::Object(object.clone()))
+ .map_err(|error| format!("第 {} 条公告对象非法:{error}", index + 1))?;
normalize_creation_entry_event_banner_response(index, banner)
}
@@ -243,8 +243,8 @@ pub fn resolve_creation_entry_event_banner_responses(
banners
}
.into_iter()
- .map(build_creation_entry_event_banner_response)
- .collect()
+ .map(build_creation_entry_event_banner_response)
+ .collect()
}
/// 把领域公告快照转换为 HTTP 响应字段。
@@ -332,10 +332,7 @@ fn normalize_banner_html_code(
}
let lower_html_code = html_code.to_ascii_lowercase();
if lower_html_code.contains("