Update Match3D/image-generation docs & code
Adds/updates documentation, assets and implementation for Match3D and puzzle image generation workflows. Key changes: decision logs and pitfalls updated to prefer VectorEngine Gemini for Match3D material sheets and to require edits (multipart) for 1:1 container reference images; guidance added for when to use APIMart vs VectorEngine. .env.example clarified APIMart/Responses config. Many new public assets and PPT visuals added. Code changes across frontend and backend: updated shared contracts, server-rs match3d/puzzle/image-generation handlers, VectorEngine/OpenAI image generation clients, and multiple React components/tests to handle UI/background/container image signing, edits workflow, and puzzle UI background resolution. Added src/services/puzzle-runtime/puzzleUiBackgroundSource.ts and related test updates. Includes notes about multipart HTTP/1.1 requirement and test/verification commands in docs.
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
# 抓大鹅草稿素材生成流水线 2026-05-10
|
||||
|
||||
## 0. 2026-05-14 临时关闭音频生成
|
||||
|
||||
抓大鹅音频生成能力暂时关闭:
|
||||
|
||||
1. `match3d_compile_draft` 不再调用 Suno 生成背景音乐,也不再生成点击音效。
|
||||
2. 结果页 `素材配置` 不再展示 `背景音乐` 子 Tab;物品详情面板不再展示点击音效提示词和生成按钮。
|
||||
3. 批量新增物品只生成 2D 五视角图片,不生成点击音效。
|
||||
4. 通用 `/api/creation/audio/*` 路由对 `match3d_work` / `match3d_item` 暂时返回 `410 Gone`;视觉小说专用音频路由保持可用。
|
||||
5. 历史 `generatedItemAssets[].backgroundMusic` 与 `clickSound` 字段保留,运行态仍可消费旧音频。
|
||||
|
||||
## 1. 范围
|
||||
|
||||
本方案用于改造 `生成抓大鹅草稿` 的首版生成链路:点击按钮后先进入独立生成过程页,生成结束后自动进入抓大鹅结果页,并在结果页 `素材配置 > 物品` 预览本次生成的 2D 多视角物品素材。
|
||||
@@ -8,7 +18,7 @@
|
||||
|
||||
## 2. 前端流程
|
||||
|
||||
入口仍复用 `Match3DAgentWorkspace` 表单。点击 `生成抓大鹅草稿` 后:
|
||||
入口仍复用 `Match3DAgentWorkspace` 表单。点击 `生成抓大鹅草稿` 后必须先弹出 `确认消耗泥点` 面板,展示 `消耗 10 泥点`;用户确认后才进入后端生成流程:
|
||||
|
||||
1. 创建 Match3D session。
|
||||
2. 后端先用当前题材和本地兜底元信息创建同一个 Match3D 草稿 profile,草稿 Tab 必须立即能看到这份存档。
|
||||
@@ -20,7 +30,7 @@
|
||||
生成页步骤固定为:
|
||||
|
||||
```text
|
||||
建立草稿存档 -> 生成作品计划 -> 生成背景提示词 -> 分批生成素材图 -> 切割独立图片 -> 上传图片资产 -> 校验素材结构 -> 生成背景音乐 -> 生成UI背景与容器 -> 写入草稿页
|
||||
建立草稿存档 -> 生成作品计划 -> 生成背景提示词 -> 分批生成素材图 -> 切割独立图片 -> 上传图片资产 -> 校验素材结构 -> 生成UI背景与容器 -> 写入草稿页
|
||||
```
|
||||
|
||||
生成页只展示题材和物品数量,不展示玩法规则说明。
|
||||
@@ -29,29 +39,27 @@
|
||||
|
||||
## 3. 后端编排边界
|
||||
|
||||
外部生图、音频生成和 OSS 上传全部由 `api-server` 编排,不进入 SpacetimeDB reducer。SpacetimeDB 继续只负责 Match3D 会话、草稿和作品 profile 的确定性写入。
|
||||
外部生图和 OSS 上传全部由 `api-server` 编排,不进入 SpacetimeDB reducer。音频生成当前临时关闭。SpacetimeDB 继续只负责 Match3D 会话、草稿和作品 profile 的确定性写入。
|
||||
|
||||
`match3d_compile_draft` action 的后端顺序为:
|
||||
|
||||
1. 读取 session config。
|
||||
2. 对本次 `match3d_compile_draft` 生成动作按 `sessionId + profileId + action 时间戳` 构造幂等流水并预扣 `10` 泥点。余额不足时不继续创建草稿;后续任一步失败时自动按同额退款。
|
||||
3. 草稿编译先创建可恢复 profile;素材生成数量由入口页难度派生的物品种类决定:轻松 `3` 种、标准 `9` 种、进阶 `15` 种、硬核 `21` 种。
|
||||
4. 先调用 SpacetimeDB compile procedure 写入草稿。首次执行使用新 `profileId`;重试时复用 session draft / work profile 中已有 `profileId`。这一步不能等待 LLM、图片、音频或 OSS 成功后才执行。
|
||||
5. 基于入口页题材设定文本调用文本模型生成作品生成计划。模型固定请求 `gpt-4o`,只返回 JSON,其中 `gameName` 为 4 到 12 个中文字符的游戏名称,`summary` 为 18 到 48 个中文字符的作品描述。生成计划还必须包含 `tags`、`backgroundMusic.title`、`backgroundMusic.style`、`backgroundMusic.prompt`、`backgroundPrompt`,以及 `items[]` 中每个物品的 `name` 与 `soundPrompt`。`backgroundMusic.title` 是背景音乐名称,`backgroundMusic.prompt` 固定为空字符串,用于后续 Suno 纯音乐生成;`backgroundPrompt` 用于生成局内竖屏纯背景图,只描述题材氛围、色彩和环境,不得描述锅、圆盘、托盘、拼图槽、物品槽、HUD、UI、文字、按钮、倒计时、分数或物品。文本模型不可用时保留第 4 步的本地兜底,不阻断草稿。
|
||||
4. 先调用 SpacetimeDB compile procedure 写入草稿。首次执行使用新 `profileId`;重试时复用 session draft / work profile 中已有 `profileId`。这一步不能等待 LLM、图片或 OSS 成功后才执行。
|
||||
5. 基于入口页题材设定文本调用文本模型生成作品生成计划。模型固定请求 `gpt-4o`,只返回 JSON,其中 `gameName` 为 4 到 12 个中文字符的游戏名称,`summary` 为 18 到 48 个中文字符的作品描述。生成计划还必须包含 `tags`、`backgroundPrompt`,以及 `items[]` 中每个物品的 `name` 与 `soundPrompt`。`soundPrompt` 只作为历史字段保留,当前不触发音效生成;`backgroundPrompt` 用于生成局内竖屏纯背景图,只描述题材氛围、色彩和环境,不得描述锅、圆盘、托盘、拼图槽、物品槽、HUD、UI、文字、按钮、倒计时、分数或物品。文本模型不可用时保留第 4 步的本地兜底,不阻断草稿。
|
||||
6. 后端把生成计划中的 `gameName` 和 `summary` 写入 `match3d_work_profile` 作品信息后,自动调用作品标签生成器。标签生成器使用题材、作品名称和作品描述生成 3 到 6 个中文短标签;若调用失败或返回不足,则使用生成计划 tags 和本地兜底标签补齐。结果页手动 `AI生成作品标签` 也使用同一接口,并传入当前作品描述。
|
||||
7. 后端从同一份作品生成计划读取当前难度所需数量的短物品名称和音效提示词;不得再只生成物品名称而丢失后续音效生成上下文。
|
||||
8. 调用 APIMart `nanobanana2` / Gemini 图片模型生成 `1:1`、`1K` 素材图,请求模型固定为 `gemini-3.1-flash-image-preview`,走 `POST {APIMART_BASE_URL}/images/generations`,并携带 `official_fallback = true`。提示词必须合入入口页选择的 `assetStylePrompt`,并强制每格使用统一纯绿色绿幕背景,避免白底或纹理背景进入运行态素材。该调整只作用于抓大鹅物品素材 sheet;封面、9:16 纯背景图和 1:1 容器 UI 图仍继续使用项目现有 VectorEngine `gpt-image-2-all` 链路。
|
||||
7. 后端从同一份作品生成计划读取当前难度所需数量的短物品名称,并兼容保存历史 `soundPrompt` 字段;当前不生成点击音效。
|
||||
8. 调用 VectorEngine Gemini 原生图片接口生成 `1:1` 素材图,请求模型固定为 `gemini-3-pro-image-preview`,走 `POST {VECTOR_ENGINE_BASE_URL}/v1beta/models/gemini-3-pro-image-preview:generateContent?key={VECTOR_ENGINE_API_KEY}`。请求体使用 `contents[].parts[].text` 和 `generationConfig.responseModalities = ["TEXT", "IMAGE"]`、`generationConfig.imageConfig.aspectRatio = "1:1"`,响应从 `candidates[].content.parts[].inlineData.data` / `inline_data.data` 读取 base64 图片。提示词必须合入入口页选择的 `assetStylePrompt`,并强制每格使用统一纯绿色绿幕背景,避免白底或纹理背景进入运行态素材。该调整只作用于抓大鹅物品素材 sheet;封面和 `9:16` 纯背景图继续使用 VectorEngine `/v1/images/generations` 的 `gpt-image-2-all` JSON 链路,`1:1` 容器 UI 图必须使用 VectorEngine `/v1/images/edits` multipart 图生图链路,不能再把参考图作为 generations 的 `image` 数组弱参考。
|
||||
9. 每个物品固定需要 `5` 个不同视角。单张素材图固定为 `5*5 = 25` 格,因此单张图承载 `5` 个物品。若用户要求或难度派生的物品种类不是 `5` 的倍数,后端必须向上补齐物品名称和对应图片到最近的 `5` 的倍数;例如标准难度需要 `9` 种玩法物品,实际生成 `10` 个物品名称和对应五视角图片。若草稿物品数超过 `5`,后端按每批 `5` 个物品自动分批,多张素材图并行生成。
|
||||
10. 将每张素材图按固定 `5 行 * 5 列` 切割成独立图片,并按物品顺序连续分配 `5` 张视角图。素材图提示词必须要求 `5*5` 严格均匀排布、每格主体完整居中、统一纯绿色绿幕背景、相邻物体主体至少保留 `1/4` 单格宽度空白间距、不得跨格、贴边或越界,避免裁剪后相邻格内容污染。切割前必须先在整张素材图上把绿幕背景处理为透明 alpha,再在每个理论格子内按透明背景/前景像素做内容边界校准,并带少量安全留白导出;不能做固定内缩裁剪,避免贴近格线但未跨格的樱桃、叶片、把手等主体边缘被切掉。每个物品 JSON 写入 `imageViews[]`,同时把第一个视角兼容写入 `imageSrc/imageObjectKey`。
|
||||
11. 将素材图和每张独立视角图片上传到 OSS。每次获得可恢复的图片资产后,都要回写 `match3d_work_profile.generated_item_assets_json`。成功素材状态为 `image_ready`;失败素材保留已成功图片引用并记录 `error`。每个素材 JSON 同步保存 `soundPrompt`,首个素材 JSON 同步保存 `backgroundMusicTitle` 与 `backgroundMusicStyle`,`backgroundMusicPrompt` 保存为空字符串作为兼容字段。
|
||||
12. 后端在图片素材生成后使用 `backgroundMusic.title` 提交 Suno 背景音乐任务,`prompt` 为空,`tags` 来自 `backgroundMusic.style`,并固定走纯音乐生成。轮询完成后通过通用创作音频资产链路转存 OSS、确认 `asset_object`、绑定到 `match3d_work/background_music`,再写回首个素材的 `backgroundMusic`。自动草稿阶段必须拿到非空 `backgroundMusic.audioSrc` 才能返回成功;曲名为空、Suno 提交/轮询失败、音频下载失败、OSS 转存失败或资产绑定失败时,本次 `match3d_compile_draft` 返回失败并停留在生成页,不能进入结果页后显示“暂无音乐”。
|
||||
13. 草稿生成阶段不生成点击音效,只保存 `generatedItemAssets[].soundPrompt`;点击音效由结果页 `素材配置 > 物品` 详情面板手动生成并写回对应素材。
|
||||
14. UI 背景生成由 `api-server` 调用 VectorEngine `gpt-image-2-all` 分成两张资产:第一张是 `9:16` 纯背景图,不传锅参考图,且必须禁止锅、圆盘、托盘、拼图槽、物品槽、HUD、文字、按钮、倒计时、分数和物品;第二张是 `1:1` 题材容器 UI 图,固定传入 `public/match3d-background-references/pot-fused-reference.png` 作为参考图,只生成一个贴合题材设定的圆形或浅盘状竞技容器,不生成整页背景、文字、按钮或物品。容器图必须沿用参考图的大尺寸轻俯视构图:外轮廓接近画布四边,宽度约占 `86%-92%`、高度约占 `82%-90%`,内口为横向椭圆,禁止生成小容器、正俯视圆盘、侧视碗、餐盘或小托盘。纯背景上传到 `generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.png`,容器 UI 图上传到 `generated-match3d-assets/{sessionId}/{profileId}/ui-container/{taskId}/container.png`,两者都作为 `backgroundAsset` 挂在首个 `generatedItemAssets[]` JSON 上;HTTP DTO 同时顶层输出兼容的 `backgroundPrompt`、`backgroundImageSrc`、`backgroundImageObjectKey` 与 `generatedBackgroundAsset`,容器图通过 `generatedBackgroundAsset.containerImageSrc/containerImageObjectKey` 返回。若作品尚无用户自定义封面,草稿生成完成后默认把容器 UI 图写入 `coverImageSrc`,作为草稿架和作品信息的默认封面。
|
||||
15. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息、背景音乐资产信息、背景资产信息和默认封面;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets` 与 `coverImageSrc` 恢复同一批素材、音乐、UI 与封面。
|
||||
10. 将每张素材图按固定 `5 行 * 5 列` 切割成独立图片,并按物品顺序连续分配 `5` 张视角图。素材图提示词必须要求 `5*5` 严格均匀排布、每格主体完整居中、统一纯绿色绿幕背景、相邻物体主体至少保留 `1/4` 单格宽度空白间距、不得跨格、贴边或越界,避免裁剪后相邻格内容污染。切割前必须先在整张素材图上做透明背景后处理:连通到 sheet 外边缘的绿幕/近白底要清成 alpha;每格内部未连到外边缘但高置信的纯绿绿幕块也必须清成 alpha;物品边缘的绿幕抗锯齿和近白白边要做透明或去污染处理;不够纯的绿色主体像素不得被当作绿幕误删。随后再在每个理论格子内按透明背景/前景像素做内容边界校准,并带少量安全留白导出;不能做固定内缩裁剪,避免贴近格线但未跨格的樱桃、叶片、把手等主体边缘被切掉。每个物品 JSON 写入 `imageViews[]`,同时把第一个视角兼容写入 `imageSrc/imageObjectKey`。
|
||||
11. 将素材图和每张独立视角图片上传到 OSS。每次获得可恢复的图片资产后,都要回写 `match3d_work_profile.generated_item_assets_json`。成功素材状态为 `image_ready`;失败素材保留已成功图片引用并记录 `error`。每个素材 JSON 可继续保存历史 `soundPrompt`;不再写入新的 `backgroundMusicTitle/backgroundMusicStyle/backgroundMusicPrompt`。
|
||||
12. UI 背景生成由 `api-server` 分成两张资产:第一张是 `9:16` 纯背景图,走 VectorEngine `/v1/images/generations` 的 `gpt-image-2-all` JSON 请求,不传锅参考图,且必须禁止锅、圆盘、托盘、拼图槽、物品槽、HUD、文字、按钮、倒计时、分数和物品;第二张是 `1:1` 题材容器 UI 图,走 VectorEngine `/v1/images/edits` multipart 请求,把 `public/match3d-background-references/pot-fused-reference.png` 作为 `image` part 上传,只生成一个贴合题材设定的圆形或浅盘状竞技容器,不生成整页背景、文字、按钮或物品。容器图必须沿用参考图的大尺寸轻俯视构图:外轮廓接近画布四边,宽度约占 `86%-92%`、高度约占 `82%-90%`,内口为横向椭圆,禁止生成小容器、正俯视圆盘、侧视碗、餐盘或小托盘。纯背景上传到 `generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.png`,容器 UI 图上传到 `generated-match3d-assets/{sessionId}/{profileId}/ui-container/{taskId}/container.png`,两者都作为 `backgroundAsset` 挂在首个 `generatedItemAssets[]` JSON 上;HTTP DTO 同时顶层输出兼容的 `backgroundPrompt`、`backgroundImageSrc`、`backgroundImageObjectKey` 与 `generatedBackgroundAsset`,容器图通过 `generatedBackgroundAsset.containerImageSrc/containerImageObjectKey` 返回。若作品尚无用户自定义封面,草稿生成完成后默认把容器 UI 图写入 `coverImageSrc`,作为草稿架和作品信息的默认封面。
|
||||
13. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息、背景资产信息和默认封面;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets` 与 `coverImageSrc` 恢复同一批素材、UI 与封面。历史音频字段只做兼容传递。
|
||||
|
||||
若文本模型不可用或返回无法解析,后端必须降级为 `{themeText}抓大鹅`、本地作品描述与本地标签兜底,不阻断素材生成;标签仍通过作品标签生成器优先生成,失败后再用兜底标签补齐。
|
||||
|
||||
草稿生成阶段不再调用 Hyper3D Rodin,不生成 GLB,也不等待任何模型轮询。前端 `match3d_compile_draft` action 的长耗时主要来自文本生成、分批 1K 生图、切图、OSS 上传、纯背景图、容器 UI 图和可选音频生成。批量新增物品由 `POST /api/creation/match3d/works/{profileId}/item-assets` 复用同一套 2D 素材图生成、固定 `5*5` 切图、OSS 上传和可选点击音效链路;若本次新增数量不是 `5` 的倍数,同样向上补齐名称和图片到最近的 `5` 的倍数。整图生成完成后立即丢弃补齐用临时物品,只对用户实际新增项执行绿幕抠背景、切割和上传,并只把这些真实新增项的 `imageViews[]` 写回 `generatedItemAssets`。
|
||||
草稿生成阶段不再调用 Hyper3D Rodin,不生成 GLB,也不等待任何模型轮询。前端 `match3d_compile_draft` action 的长耗时主要来自文本生成、分批 1K 生图、切图、OSS 上传、纯背景图和容器 UI 图。批量新增物品由 `POST /api/creation/match3d/works/{profileId}/item-assets` 复用同一套 2D 素材图生成、固定 `5*5` 切图和 OSS 上传链路;若本次新增数量不是 `5` 的倍数,同样向上补齐名称和图片到最近的 `5` 的倍数。整图生成完成后立即丢弃补齐用临时物品,只对用户实际新增项执行绿幕抠背景、切割和上传,并只把这些真实新增项的 `imageViews[]` 写回 `generatedItemAssets`。批量重新生成同样调用该接口,但请求体增加 `mode = "replace"`,前端从现有素材列表收集用户确认的物品名称;后端只匹配已存在的同名素材,保留原 `itemId`、列表顺序、UI 背景、历史背景音乐和点击音效字段,只替换该素材的 `imageSrc/imageObjectKey/imageViews/status/error`,避免试玩和正式运行态的物品类型映射漂移。
|
||||
|
||||
## 4. 图片提示词
|
||||
|
||||
@@ -92,7 +100,7 @@ public/match3d-style-references/painterly-icon.png
|
||||
public/match3d-background-references/pot-fused-reference.png
|
||||
```
|
||||
|
||||
这张图只作为容器 UI 图的 VectorEngine `image` 参考输入,用来锁定“大尺寸轻俯视浅盘容器”的构图。参考图本身是 `1:1` 透明底容器素材,外轮廓接近画布四边,内口为横向椭圆;结果页没有真实生成容器时也只把它作为容器预览兜底,不能再作为 `9:16` 背景预览。每次草稿生成仍会根据 `backgroundPrompt` 生成新的题材化纯背景图;纯背景图不再传入该参考图,也不得生成锅或 UI 元素。
|
||||
这张图只作为容器 UI 图的 VectorEngine `/v1/images/edits` multipart `image` part,用来锁定“大尺寸轻俯视浅盘容器”的构图。参考图本身是 `1:1` 透明底容器素材,外轮廓接近画布四边,内口为横向椭圆;结果页没有真实生成容器时也只把它作为容器预览兜底,不能再作为 `9:16` 背景预览。每次草稿生成仍会根据 `backgroundPrompt` 生成新的题材化纯背景图;纯背景图不再传入该参考图,也不得生成锅或 UI 元素。
|
||||
|
||||
## 5. OSS 路径
|
||||
|
||||
@@ -116,7 +124,9 @@ generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.
|
||||
|
||||
`itemSlug` 必须带 `itemId` 前缀,例如 `match3d-item-1-item`。中文物品名清洗后可能都退回 `item`,不能只用物品名做路径,否则多张切割图会写到同一个 object key,导致草稿页预览图全部一致。
|
||||
|
||||
HTTP DTO 同时返回兼容字段 `imageSrc`、`imageObjectKey`,以及正式 2D 字段 `imageViews[]`、`backgroundAsset` 和 `status`。图片素材生成成功后 `status = image_ready`;纯背景和容器 UI 图都生成成功后首个素材的 `backgroundAsset.status = image_ready`,并携带 `containerImageSrc/containerImageObjectKey`。前端通过 `/api/assets/read-url` 将 generated legacy path 换签后加载私有图片,不直接请求裸 `/generated-match3d-assets/...` 路径。运行态背景图和容器 UI 图同样通过 `/api/assets/read-url` 换签后加载:背景作为全屏 `object-cover`,容器作为中心棋盘覆盖层。
|
||||
HTTP DTO 同时返回兼容字段 `imageSrc`、`imageObjectKey`,以及正式 2D 字段 `imageViews[]`、`backgroundAsset` 和 `status`。图片素材生成成功后 `status = image_ready`;纯背景和容器 UI 图都生成成功后首个素材的 `backgroundAsset.status = image_ready`,并携带 `containerImageSrc/containerImageObjectKey`。前端通过 `/api/assets/read-url` 将 generated legacy path 换签后加载私有图片,不直接请求裸 `/generated-match3d-assets/...` 路径。运行态背景图和容器 UI 图同样通过 `/api/assets/read-url` 换签后加载:背景作为全屏 `object-cover`,容器作为中心棋盘视觉层;当容器图成功解析为可渲染图片时,`Match3DRuntimeShell` 必须移除默认圆形锅壳、边框和径向底色,让生成容器接管棋盘外观。
|
||||
|
||||
结果页手动点击 `素材配置 > UI > 重新生成` 时,目标库可能仍运行旧 SpacetimeDB wasm,缺少钱包扣退费或 Match3D 写回相关 procedure。`api-server` 对这类 `No such procedure` 只做临时容错:泥点预扣阶段跳过扣费,背景图和容器 UI 已经生成但草稿写回失败时,HTTP 响应仍返回本次生成的 `generatedBackgroundAsset` 和带该资产的内存 profile,避免草稿页直接报错。该容错不等于持久化成功;刷新、换设备或公开详情稳定恢复仍以发布最新 SpacetimeDB module、确认 procedure 导出和重新生成 bindings 为准。
|
||||
|
||||
## 5.1 运行态 2D 素材消费
|
||||
|
||||
@@ -124,25 +134,25 @@ HTTP DTO 同时返回兼容字段 `imageSrc`、`imageObjectKey`,以及正式 2
|
||||
|
||||
```text
|
||||
Match3DWorkProfile / PlatformMatch3DGalleryCard
|
||||
-> Match3DRuntimeShell(generatedItemAssets, backgroundImageSrc)
|
||||
-> Match3DRuntimeShell(generatedItemAssets, generatedBackgroundAsset, backgroundImageSrc)
|
||||
-> Match3DPhysicsBoard / Match3DTrayPreviewBoard
|
||||
```
|
||||
|
||||
运行态按运行快照中的 `itemTypeId` 稳定排序后,把 `generatedItemAssets` 顺序映射到对应类型。加载某个物品实例时,从该类型素材的 `imageViews[]` 中按实例 id 稳定随机选择一个视角;若历史数据没有 `imageViews[]`,则回退到 `imageSrc/imageObjectKey`。没有生成图片或图片加载失败时,继续使用默认积木图标兜底。
|
||||
|
||||
运行态背景优先读取 `backgroundImageSrc` / `generatedBackgroundAsset.imageSrc`,为空时从 `generatedItemAssets[].backgroundAsset.imageSrc/imageObjectKey` 兜底。中心容器优先读取 `generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey`;为空时继续使用默认圆形容器样式。运行态入口判断是否需要补读作品详情时,只能把 `imageViews[]` 或 `imageSrc/imageObjectKey` 视为“已有物品图片素材”;`backgroundMusic.audioSrc`、`clickSound.audioSrc`、`backgroundAsset.image*` 和 `backgroundAsset.containerImage*` 是随物品素材一起传入的附属运行态资产,不能单独证明物品素材已完整。也不能继续只用历史 `modelSrc/modelObjectKey` 判断,否则新 2D 草稿会在试玩或推荐流中被当成“无素材”并回退默认积木。`Match3DRuntimeShell` 只保留顶部返回、倒计时、重开三个控件;这些顶部控件和底部备选栏统一使用题材无关的半透明玻璃组件样式,不能随背景题材改成木质、金属、果园、科幻等主题皮肤,也不能重新烘进 AI 背景图。进度、组数、版本等状态信息不得再作为顶部常驻 UI 出现,避免遮挡生成背景和中心容器。
|
||||
运行态背景优先读取 `backgroundImageSrc` / 顶层 `generatedBackgroundAsset.imageSrc/imageObjectKey`,为空时从 `generatedItemAssets[].backgroundAsset.imageSrc/imageObjectKey` 兜底。中心容器优先读取顶层 `generatedBackgroundAsset.containerImageSrc/containerImageObjectKey`,再读取 `generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey`;为空或换签/图片加载失败时继续使用默认圆形容器样式。容器图成功加载后,`Match3DRuntimeShell` 的棋盘容器必须切换为透明、可溢出承载,不再叠加默认 `rounded-full` 圆形锅壳、金色边框和默认径向背景,避免 AI 生成的大尺寸轻俯视容器被裁切或被默认锅视觉覆盖。运行态入口判断是否需要补读作品详情时,只能把 `imageViews[]` 或 `imageSrc/imageObjectKey` 视为“已有物品图片素材”;`backgroundMusic.audioSrc`、`clickSound.audioSrc`、`generatedBackgroundAsset`、`backgroundAsset.image*` 和 `backgroundAsset.containerImage*` 是随物品素材一起传入的附属运行态资产,不能单独证明物品素材已完整。也不能继续只用历史 `modelSrc/modelObjectKey` 判断,否则新 2D 草稿会在试玩或推荐流中被当成“无素材”并回退默认积木。`Match3DRuntimeShell` 只保留顶部返回、倒计时、重开三个控件;这些顶部控件和底部备选栏统一使用题材无关的半透明玻璃组件样式,不能随背景题材改成木质、金属、果园、科幻等主题皮肤,也不能重新烘进 AI 背景图。进度、组数、版本等状态信息不得再作为顶部常驻 UI 出现,避免遮挡生成背景和中心容器。
|
||||
|
||||
前端加载规则:
|
||||
|
||||
1. 优先读取 `imageViews[]` 中的 `imageSrc/imageObjectKey`,为空时使用兼容字段 `imageSrc/imageObjectKey`。
|
||||
2. 对 generated legacy path 通过同源 `/api/assets/read-url` 换签后交给浏览器图片加载;结果页 `素材配置 > 背景音乐` 与 `素材配置 > 物品` 的音频试听控件也必须先换签,不能把裸 `/generated-match3d-assets/...` 音频路径直接交给 `<audio>`。
|
||||
2. 对 generated legacy path 通过同源 `/api/assets/read-url` 换签后交给浏览器图片加载;结果页音频试听入口当前隐藏,后续恢复时也必须先换签,不能把裸 `/generated-match3d-assets/...` 音频路径直接交给 `<audio>`。
|
||||
3. 场内物品、点击命中和备选栏继续使用后端快照中的 `itemInstanceId/itemTypeId/x/y/radius/layer`;生成 2D 图片只替换视觉表现,不承接规则真相。
|
||||
4. 同一物品类型的多个实例可以展示不同视角,但同一实例在本局中应稳定使用同一个视角,避免移动或入槽时闪图。
|
||||
5. 图片缺失、读取失败或解码失败时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算。
|
||||
|
||||
结果页点击 `试玩` 时,前端必须把当前结果页可见的 `generatedItemAssets` 带入运行态启动入参。`PUT /api/runtime/match3d/works/{profileId}` 若因为并发或旧快照返回了缺少素材的 profile,`Match3DResultView` 需要把当前 draft / profile 的素材重新合并到运行态 profile,并在启动试玩前调用生成素材保存接口把当前可见的 `generatedItemAssets` 写回作品 profile;不能只在内存里把素材补到 `onStartTestRun(profile)`。发布同理必须先落库当前素材,再调用 `publish_match3d_work`,否则公开推荐流和正式运行态只能读到旧 profile 快照。结果页顶部返回按钮固定回到平台创作页,不再回到抓大鹅专属内嵌入口表单;需要修改题材时由用户在创作页重新选择或从草稿继续进入。若历史草稿同时存在旧 `draft.generatedItemAssets` 和较新的 `profile.generatedItemAssets`,同 `itemId` 下以 profile 中已有的 `imageViews[]`、`imageSrc`、`imageObjectKey`、`backgroundMusic` 或 `backgroundAsset` 补齐 draft,不能让旧 draft 把素材覆盖成空列表。`PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dRuntimeProfile / match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`;即使当前 profile 暂时没有物品图片,也不能把同 profile 的已有 `generatedItemAssets` 覆盖为空数组。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少物品图片素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成图片、背景音乐和 UI 素材写入 `match3dRuntimeProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 2D 素材、音乐或 UI 覆盖成空列表。
|
||||
结果页点击 `试玩` 时,前端必须把当前结果页可见的 `generatedItemAssets` 带入运行态启动入参。`PUT /api/runtime/match3d/works/{profileId}` 若因为并发或旧快照返回了缺少素材的 profile,`Match3DResultView` 需要把当前 draft / profile 的素材重新合并到运行态 profile,并在启动试玩前调用生成素材保存接口把当前可见的 `generatedItemAssets` 写回作品 profile;不能只在内存里把素材补到 `onStartTestRun(profile)`。发布同理必须先落库当前素材,再调用 `publish_match3d_work`,否则公开推荐流和正式运行态只能读到旧 profile 快照。结果页顶部返回按钮固定回到平台创作页,不再回到抓大鹅专属内嵌入口表单;需要修改题材时由用户在创作页重新选择或从草稿继续进入。若历史草稿同时存在旧 `draft.generatedItemAssets` 和较新的 `profile.generatedItemAssets`,同 `itemId` 下以 profile 中已有的 `imageViews[]`、`imageSrc`、`imageObjectKey`、`backgroundMusic` 或 `backgroundAsset` 补齐 draft,不能让旧 draft 把素材覆盖成空列表。`PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dRuntimeProfile / match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`;即使当前 profile 暂时没有物品图片,也不能把同 profile 的已有 `generatedItemAssets` 覆盖为空数组。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少物品图片素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成图片、历史背景音乐和 UI 素材写入 `match3dRuntimeProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 2D 素材、历史音乐或 UI 覆盖成空列表。
|
||||
|
||||
2026-05-14 补充:`backgroundMusic` 虽然暂存在 `generatedItemAssets[]` 中,但语义上是作品级音乐。前端读取、保存、试玩、推荐流和运行态入口都必须先通过统一归一化逻辑把任意素材上的 `backgroundMusic/backgroundMusicTitle/backgroundMusicStyle/backgroundMusicPrompt` 迁移到首个素材,并清空其它素材上的作品级音乐字段,避免 `素材配置 > 背景音乐` 只读首项时显示“暂无音乐”,也避免 action response 中缺音乐的 draft assets 覆盖 work detail 中已经持久化的音乐。`match3d_compile_draft` action 完成后,如果同时拿到 `response.session.draft.generatedItemAssets` 和 `getMatch3DWorkDetail(profileId).item.generatedItemAssets`,必须以同 `itemId` 合并,保留详情里的背景音乐、UI 背景和点击音效,再进入结果页或试玩。
|
||||
2026-05-14 补充:`backgroundMusic` 虽然暂存在 `generatedItemAssets[]` 中,但语义上是作品级音乐。前端读取、保存、试玩、推荐流和运行态入口都必须先通过统一归一化逻辑把任意素材上的 `backgroundMusic/backgroundMusicTitle/backgroundMusicStyle/backgroundMusicPrompt` 迁移到首个素材,并清空其它素材上的作品级音乐字段,避免 action response 中缺音乐的 draft assets 覆盖 work detail 中已经持久化的音乐,也为未来恢复音乐入口保留稳定读取口径。`match3d_compile_draft` action 完成后,如果同时拿到 `response.session.draft.generatedItemAssets` 和 `getMatch3DWorkDetail(profileId).item.generatedItemAssets`,必须以同 `itemId` 合并,保留详情里的历史背景音乐、UI 背景和点击音效,再进入结果页或试玩。
|
||||
|
||||
历史草稿若仍保存 `status = model_ready`、`modelSrc` 或 `modelObjectKey`,仅作为旧版本兼容读取,不再参与新素材生产。历史外部模型链接转存接口只用于清理旧数据,不能被新草稿生成、批量新增或结果页普通编辑入口调用。
|
||||
|
||||
@@ -152,9 +162,9 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
|
||||
|
||||
点击 `生成抓大鹅草稿` 后,草稿存档创建与素材生成解耦:
|
||||
|
||||
1. 首次 compile 必须先写 `match3d_work_profile` 草稿行,即使后续卡在文本模型、图片生成、音频生成或 OSS 上传任意阶段。
|
||||
1. 首次 compile 必须先写 `match3d_work_profile` 草稿行,即使后续卡在文本模型、图片生成或 OSS 上传任意阶段。
|
||||
2. 失败态前端要重新读取 session / work detail,并刷新草稿作品架,保证用户离开生成页后仍能在草稿 Tab 找到这份作品。
|
||||
3. 重新生成时优先使用当前 session 的 `draft.profileId` 或 `publishedProfileId`,不得重新创建 session;后端读取同一 profile 的 `generated_item_assets_json` 后,只补齐缺失图片或缺失音频的阶段。
|
||||
3. 重新生成时优先使用当前 session 的 `draft.profileId` 或 `publishedProfileId`,不得重新创建 session;后端读取同一 profile 的 `generated_item_assets_json` 后,只补齐缺失图片、UI 背景或容器资源。
|
||||
4. 已有 `status = image_ready` 且带 `imageViews[]` 或 `imageSrc/imageObjectKey` 的素材视为完成,不再重复生成图片。
|
||||
|
||||
抓大鹅结果页的基础信息自动保存继续调用 `PUT /api/runtime/match3d/works/{profileId}` 更新名称、题材、描述、标签、封面、消除数和难度;该保存不得清空 `generated_item_assets_json`。结果页 `素材配置 > 物品` 只在独立面板中预览和编辑当前素材,不再提供单项重新生成入口;删除单项或批量新增成功后,都必须把当前素材列表重新序列化成 `generatedItemAssets` 并写回作品 profile,否则试玩、发布和重进草稿会读取旧素材快照。SpacetimeDB `update_match3d_work` / `publish_match3d_work` 必须保留当前行的生成素材 JSON。
|
||||
@@ -174,7 +184,7 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
|
||||
1. `作品名称` 对应 Match3D `gameName`。
|
||||
2. `作品描述` 对应 Match3D `summary`,草稿生成阶段由同一次作品生成计划自动填入。
|
||||
3. `作品标签` 对应 Match3D `tags`,草稿生成阶段在写入名称和描述后自动调用标签生成器填入;结果页仍允许用户继续编辑或再次 AI 生成。
|
||||
4. 封面图与作品名称不再拆成左右两个大模块;封面只作为同一 Tab 内的可选入口,避免和作品基础信息割裂。草稿生成默认使用生成出的中心容器 UI 图作为 `coverImageSrc`。点击封面图必须弹出独立编辑面板,不允许在当前作品信息面板下方展开。封面面板布局参考拼图创作页上传卡:移动端优先、左侧/上方为方形预览,右侧/下方为提示词与操作区。面板支持三类输入:本地上传图片、上传后开启 AI 重绘、直接引用 `物品素材` 或 `UI素材` 中已有图片作为封面或 AI 重绘参考图。AI 重绘通过 `api-server` 的 Match3D 作品封面生成接口调用 VectorEngine `gpt-image-2-all`,生成结果转存到 `generated-match3d-assets/{sessionId}/{profileId}/cover/{taskId}/cover.png` 后再写回 `coverImageSrc`;关闭 AI 重绘时只把选中的 Data URL 或 generated legacy path 写入封面字段。
|
||||
4. 封面图与作品名称不再拆成左右两个大模块;封面只作为同一 Tab 内的可选入口,避免和作品基础信息割裂。旧称“碰面图”统一改为“封面图”。草稿生成默认使用生成出的中心容器 UI 图作为 `coverImageSrc`。点击封面图必须弹出独立编辑面板,不允许在当前作品信息面板下方展开。封面面板布局对齐拼图创作页上传卡:移动端优先,左侧/上方为方形预览卡,预览卡本身就是上传热区;上传图片后,预览卡内出现和拼图入口一致的 `AI重绘` 开关与删除按钮,面板底部不再额外展示旧 `AI重绘` 选项。已有上传图时,右侧/下方输入框标题为 `AI重绘要求`;关闭 AI 重绘时只把上传图 Data URL 写入封面字段,不调用生图模型。没有上传图时,输入框标题为 `封面描述`,可选择多张参考图后调用 VectorEngine `gpt-image-2-all` 文生图链路,参考图通过请求体 `image` 数组传入;参考图来源支持直接引用 `物品素材` / `UI素材` 中已有图片,也支持自定义上传。上传图 AI 重绘与无上传图多参考图生成都通过 `api-server` 的 Match3D 作品封面生成接口完成,生成结果转存到 `generated-match3d-assets/{sessionId}/{profileId}/cover/{taskId}/cover.png` 后再写回 `coverImageSrc`。
|
||||
|
||||
结果页 `难度配置` Tab 取代旧 `玩法配置`,不再展示旧的分散输入项。该 Tab 顶部使用横向离散拖动条调整难度,四个刻度分别为 `轻松 / 标准 / 进阶 / 硬核`;拖动条只能落在这四个点上,刻度标签可点击切换。该 Tab 必须与创作入口页使用同一组难度选项,并统一把原“类型素材图片 / 局内类型”等口径归一为 `物品种类`:
|
||||
|
||||
@@ -187,36 +197,36 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
|
||||
|
||||
预览区展示 `需要消除`、`总物品数`、`物品种类` 和 `已生成物品种类`。历史草稿如果保存的是旧 `clearCount/difficulty`,前端按 `clearCount` 精确命中优先、否则按 `difficulty` 就近归一到上述选项,并把归一后的数值保存回 profile。发布校验以 `generatedItemAssets[]` 中 `image_ready` 且至少有 `5` 张有效 `imageViews[]` 的素材数量为准;试玩启动时用同一数量计算 `itemTypeCountOverride`,不足时自动降低,不修改草稿难度配置本身。历史单图 `imageSrc/imageObjectKey` 只作为运行态和预览兜底,不计入新发布素材完成数。
|
||||
|
||||
结果页 `素材配置` Tab 取代旧一级素材入口,并包含三个子 Tab:
|
||||
结果页 `素材配置` Tab 取代旧一级素材入口,当前包含三个子 Tab:
|
||||
|
||||
1. `物品`:显示 2D 物品素材列表、五视角预览、素材名称、点击音效提示词和点击音效生成入口。
|
||||
2. `UI`:预览生成的竖屏游戏纯背景图和中心容器 UI 图。背景读取顺序为 draft 顶层背景、draft `generatedBackgroundAsset`、profile 顶层背景、profile `generatedBackgroundAsset`、`generatedItemAssets[].backgroundAsset`、本地兜底图;容器读取 `generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey`,缺失时使用默认圆形容器。该页必须展示默认画面描述提示词,默认值来自草稿生成计划的 `backgroundPrompt` 或持久化 `backgroundAsset.prompt`;用户修改后点击重新生成,后端同时生成纯背景图和容器 UI 图,并把新的 `backgroundAsset` 写回同一份 `generated_item_assets_json`。UI 子 Tab 还必须提供独立的运行态 UI 预览面板,直接用当前纯背景图、容器 UI 图、顶部返回/倒计时/重开控件和底部默认托盘模拟竖屏页面,不在 Tab 下方内联展开。
|
||||
3. `背景音乐`:承载原一级音乐 Tab 的背景音乐曲名、风格、生成进度和试听控件;背景音乐始终按纯音乐生成,前端不提供提示词输入。
|
||||
1. `物品`:显示 2D 物品素材列表、五视角预览和素材名称;点击音效提示词与生成入口已临时隐藏。
|
||||
2. `UI`:预览生成的竖屏游戏纯背景图,并在独立运行态 UI 预览面板中叠加当前中心容器形象。背景读取顺序为 draft 顶层背景、draft `generatedBackgroundAsset`、profile 顶层背景、profile `generatedBackgroundAsset`、`generatedItemAssets[].backgroundAsset`、本地兜底图;容器读取 `generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey`,缺失时使用默认圆形容器。该页必须展示默认画面描述提示词,默认值来自草稿生成计划的 `backgroundPrompt` 或持久化 `backgroundAsset.prompt`;用户修改后点击重新生成,先弹出 `确认消耗泥点` 面板并展示 `消耗 2 泥点`,确认后调用 `POST /api/creation/match3d/works/{profileId}/background-image`,现阶段后端仍会同时生成纯背景图和容器 UI 图,并把新的 `backgroundAsset` 写回同一份 `generated_item_assets_json`。确认后按钮区域必须显示生成进度条,按 `90` 秒估算倒计时,后端真实返回后立即收口。UI 子 Tab 的预览面板直接用当前纯背景图、容器 UI 图、顶部返回/倒计时/重开控件和底部默认托盘模拟竖屏页面,不在 Tab 下方内联展开。
|
||||
3. `容器形象`:预览和重新生成 `1:1` 中心容器 UI 图,页面能力与 `UI` 子 Tab 对齐,包含方形容器预览、容器提示词输入、独立运行态 UI 预览面板、泥点确认和生成进度。默认提示词来自持久化 `backgroundAsset.containerPrompt`,缺失时从当前题材、作品描述和容器参考约束生成兜底提示词;用户修改后点击重新生成,先弹出 `确认消耗泥点` 面板并展示 `消耗 2 泥点`,确认后调用 `POST /api/creation/match3d/works/{profileId}/container-image`,按钮区域同样按 `90` 秒估算显示倒计时进度。该接口只重新生成并写回 `backgroundAsset.containerPrompt/containerImageSrc/containerImageObjectKey`,必须保留已有纯背景 `prompt/imageSrc/imageObjectKey`、物品素材、历史背景音乐和点击音效字段,避免用户只换容器时刷新掉背景图或物品素材。
|
||||
|
||||
旧一级 `音乐` Tab 删除;抓大鹅背景音乐入口只保留在 `素材配置 > 背景音乐`。
|
||||
旧一级 `音乐` Tab 删除;`素材配置 > 背景音乐` 当前也不展示。
|
||||
|
||||
`素材配置 > 物品` 详情页只保留:
|
||||
|
||||
1. 五视角预览区:优先展示 `imageViews[]`,缺失时展示兼容字段 `imageSrc/imageObjectKey`。
|
||||
2. 素材名称输入。
|
||||
3. 可编辑的点击音效提示词输入。
|
||||
4. 点击音效生成入口。
|
||||
3. 不展示点击音效提示词输入或点击音效生成入口。
|
||||
|
||||
五视角预览区采用“上方大预览 + 底部缩略图栏”的布局:上方是方形焦点预览区,中间横向排列当前物品的各视角图片,并用内框标出当前焦点;底部缩略图栏固定露出 `4` 个方形槽位,多出的第 `5` 个视角通过横向滚动访问。点击缩略图只切换焦点视角,不在面板内新增说明文案或额外规则区。
|
||||
|
||||
详情页不再展示参考图、用途、模型提示词、文生/图生切换、状态查询、下载列表、taskUuid 或 subscriptionKey。
|
||||
|
||||
`物品素材` 列表项点击必须弹出独立预览面板,不允许在列表右侧或列表下方内联展示。列表本身使用移动端至少两列的多列卡片布局;每个列表项只展示图片预览、物品名称和垃圾箱删除图标,不展示用途、状态胶囊、视角数量或 `2D素材` 标记。预览面板只承担查看五视角图片、编辑素材名称、编辑点击音效提示词和生成点击音效;不再展示 `重新生成` 按钮。列表项自身支持单项删除,删除后立即把剩余 `generatedItemAssets` 写回作品 profile。批量新增通过列表顶部按钮打开独立面板,面板内每个输入框只输入一个物品名称,`新增物品名称` 按钮追加一个输入框;提交后按输入框顺序清洗、去重并调用 Match3D 作品批量生图接口。生成进度同时显示在批量新增面板和 `素材配置 > 物品` 列表顶部,面板可关闭,后台生成继续推进,不阻塞封面、音频等其他生成操作。后端复用草稿生成的素材图、切图、OSS 上传和可选点击音效流程,但仅按实际可新增名称持久化,不重新生成已有物品,不新增 SpacetimeDB 表,最终仍写回同一份 `generated_item_assets_json`。批量新增先补齐到 `5` 个参与整图生成,随后丢弃补齐用临时物品,只对真实新增物品抠背景、切割和上传。批量新增计费按实际可新增名称每 `5` 个消耗 `2` 泥点,不足 `5` 个向上取整;重复名称、已有名称和超过容量上限的名称不计费。
|
||||
`物品素材` 列表项点击必须弹出独立预览面板,不允许在列表右侧或列表下方内联展示。列表本身使用移动端至少两列的多列卡片布局;每个列表项只展示图片预览、物品名称和垃圾箱删除图标,不展示用途、状态胶囊、视角数量或 `2D素材` 标记。预览面板只承担查看五视角图片和编辑素材名称;不再展示单项 `重新生成` 按钮。列表项自身支持单项删除,删除后立即把剩余 `generatedItemAssets` 写回作品 profile。批量新增通过列表顶部按钮打开独立面板,面板内每个输入框只输入一个物品名称,`新增物品名称` 按钮追加一个输入框;提交按钮点击后必须先弹出 `确认消耗泥点` 面板并展示按当前有效名称计算出的泥点数,用户确认后才按输入框顺序清洗、去重并调用 Match3D 作品批量生图接口。批量重新生成通过列表顶部另一个按钮打开独立面板,面板预填当前全部素材名称,用户可清空不需要重新生成的输入框;提交按钮点击后同样先弹出泥点确认面板,确认后按输入框顺序清洗、去重并以替换模式调用同一接口。生成进度同时显示在批量面板和 `素材配置 > 物品` 列表顶部,面板可关闭,后台生成继续推进,不阻塞封面或 UI 生成操作。后端复用草稿生成的素材图、切图和 OSS 上传流程,但新增模式仅按实际可新增名称持久化,不重新生成已有物品;替换模式仅按实际匹配到的已有名称持久化,不新增物品、不改变 `itemId`。两者都不新增 SpacetimeDB 表,最终仍写回同一份 `generated_item_assets_json`。批量新增和批量重新生成都先补齐到 `5` 个参与整图生成,随后丢弃补齐用临时物品,只对真实新增或真实替换物品抠背景、切割和上传。计费按实际新增或替换名称每 `5` 个消耗 `2` 泥点,不足 `5` 个向上取整;重复名称、已有名称、未匹配名称和超过容量上限的名称不计费。
|
||||
|
||||
## 6.1 音频生成与扣费
|
||||
|
||||
抓大鹅结果页音频生成复用通用创作音频路由:
|
||||
抓大鹅结果页音频生成当前临时关闭:
|
||||
|
||||
1. `素材配置 > 背景音乐` 默认读取首个 `generatedItemAssets[0].backgroundMusicTitle/backgroundMusicStyle`,用户可继续编辑曲名和风格;`backgroundMusicPrompt` 保留为空字符串兼容旧 JSON,生成请求固定传空 `prompt`。
|
||||
2. 物品点击音效默认读取对应 `generatedItemAssets[].soundPrompt`,用户可在 `素材配置 > 物品` 详情面板内编辑。
|
||||
3. 背景音乐与物品音效生成过程必须显示进度条;提交任务、等待生成、转存资产和完成分别推进到不同进度,不再只展示旋转图标。
|
||||
4. 音频生成完成后立即展示浏览器原生 audio 控件,支持试听。
|
||||
5. `POST /api/creation/audio/background-music/{task_id}/asset` 和 `POST /api/creation/audio/sound-effect/{task_id}/asset` 在真正拿到音频并转存资产前,由后端按 `taskId + 资产槽位` 幂等预扣;背景音乐扣 `5` 泥点,物品点击音效扣 `10` 泥点。任务仍在处理中时不扣费。资产下载、OSS 转存或资产绑定失败时后端自动退款。前端只展示生成按钮和进度,不自行计算或写入钱包。
|
||||
1. `素材配置 > 背景音乐` 不展示。
|
||||
2. `素材配置 > 物品` 详情面板不展示点击音效提示词和生成入口。
|
||||
3. 通用 `/api/creation/audio/*` 路由对 `match3d_work` / `match3d_item` 暂时返回 `410 Gone`,防止旧前端或脚本继续触发抓大鹅扣费音频任务。
|
||||
4. 历史 `generatedItemAssets[].backgroundMusic` 与 `clickSound` 字段保留,运行态仍可消费旧音频;结果页不提供重新生成入口。
|
||||
|
||||
创作入口不展示 `生成音效` Toggle。草稿生成阶段不产生物品点击音效任务,也不产生点击音效相关扣费;入口只产生一次固定 `10` 泥点的草稿生成扣费。结果页 `素材配置 > UI` 重新生成背景固定扣 `2` 泥点。物品点击音效由结果页 `素材配置 > 物品` 详情面板手动触发,每个音效按单独任务和单独 `match3d_click_sound` 资产槽位扣费。音效生成失败不影响草稿,失败素材保留 `soundPrompt`,用户可在结果页物品详情面板手动重试。
|
||||
创作入口不展示 `生成音效` Toggle。草稿生成阶段不产生背景音乐或物品点击音效任务,也不产生音频相关扣费;入口只产生一次固定 `10` 泥点的草稿生成扣费。结果页 `素材配置 > UI` 重新生成背景固定扣 `2` 泥点;`素材配置 > 容器形象` 单独重新生成容器同样固定扣 `2` 泥点。
|
||||
|
||||
## 7. 验收
|
||||
|
||||
@@ -238,4 +248,4 @@ cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
|
||||
cargo check -p spacetime-module --manifest-path server-rs\Cargo.toml
|
||||
```
|
||||
|
||||
真实草稿生成需要本地私密环境配置 `APIMART_BASE_URL` / `APIMART_API_KEY` / `APIMART_IMAGE_REQUEST_TIMEOUT_MS` 用于物品素材 sheet,配置 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 用于封面、背景和容器 UI,并补齐完整 `ALIYUN_OSS_BUCKET`、`ALIYUN_OSS_ENDPOINT`、`ALIYUN_OSS_ACCESS_KEY_ID`、`ALIYUN_OSS_ACCESS_KEY_SECRET`。如果只配置 bucket 和 endpoint,抓大鹅素材、封面或背景生成会在调用外部生图前返回 `OSS 未完成环境变量配置`,`details.missingEnv` 会列出缺少的 AccessKey 项;不要回退到 Rodin/GLB 或伪造本地上传成功。开启音频生成还需要对应音频上游配置。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`。
|
||||
真实草稿生成需要本地私密环境配置 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` / `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;其中物品素材 sheet 走 VectorEngine Gemini 原生 `generateContent`,封面和 `9:16` 纯背景走 VectorEngine `/v1/images/generations` 的 `gpt-image-2-all` JSON 链路,`1:1` 容器 UI 走 VectorEngine `/v1/images/edits` multipart 参考图链路。同时必须补齐完整 `ALIYUN_OSS_BUCKET`、`ALIYUN_OSS_ENDPOINT`、`ALIYUN_OSS_ACCESS_KEY_ID`、`ALIYUN_OSS_ACCESS_KEY_SECRET`。如果只配置 bucket 和 endpoint,抓大鹅素材、封面或背景生成会在调用外部生图前返回 `OSS 未完成环境变量配置`,`details.missingEnv` 会列出缺少的 AccessKey 项;不要回退到 Rodin/GLB 或伪造本地上传成功。临时关闭期间不需要音频上游配置。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`。
|
||||
|
||||
Reference in New Issue
Block a user