Files
Genarrative/docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md
2026-05-14 14:21:17 +08:00

34 KiB
Raw Blame History

抓大鹅草稿素材生成流水线 2026-05-10

1. 范围

本方案用于改造 生成抓大鹅草稿 的首版生成链路:点击按钮后先进入独立生成过程页,生成结束后自动进入抓大鹅结果页,并在结果页 素材配置 > 物品 预览本次生成的 2D 多视角物品素材。

草稿生成不再调用 Hyper3D Rodin也不再生成 GLB 模型。物品素材继续沿用原来的“生成图片 -> 网格拆分 -> 上传 OSS -> 写回草稿”机制,但每个物品必须生成 5 个不同视角的 2D 视图。试玩和正式运行态的消除次数、总物品数和物品种类数以结果页 难度配置 保存的难度为准。难度对应物品种类固定为:轻松 3 种、标准 9 种、进阶 15 种、硬核 21 种。历史硬核草稿若仍保存 clearCount = 20,运行态按新硬核升为 21 次消除、63 件总物品。正式发布前如果已生成 image_ready 且具备至少 5 张有效 imageViews[] 的物品种类不足当前难度要求,必须阻断发布;试玩不阻断,但启动时把物品种类自动降到当前可用 2D 素材数量。

2. 前端流程

入口仍复用 Match3DAgentWorkspace 表单。点击 生成抓大鹅草稿 后:

  1. 创建 Match3D session。
  2. 后端先用当前题材和本地兜底元信息创建同一个 Match3D 草稿 profile草稿 Tab 必须立即能看到这份存档。
  3. 进入 match3d-generating 生成过程页。
  4. 过程页复用拼图生成页的 CustomWorldGenerationView 结构。
  5. 生成成功后自动进入 match3d-result
  6. 生成失败时停留在生成过程页,允许重新生成或返回创作中心;重新生成必须复用同一个 session / profile并从缺失的素材阶段继续不新建第二份草稿。

生成页步骤固定为:

建立草稿存档 -> 生成作品计划 -> 生成背景提示词 -> 分批生成素材图 -> 切割独立图片 -> 上传图片资产 -> 校验素材结构 -> 生成背景音乐 -> 生成UI背景与容器 -> 写入草稿页

生成页只展示题材和物品数量,不展示玩法规则说明。

当前 match3d-generating 进度页不是后端 task 状态订阅页,而是一个覆盖 match3d_compile_draft 长 action 的本地时间进度页:前端每 500ms 以本地时间刷新阶段展示,真正的生成完成仍以 action 返回为准。为避免长 action 未返回时页面完全无感,生成页在 match3d_compile_draft 执行期间每 3 秒旁路读取一次 session 和 work detail并用 profile 中已写回的 generatedItemAssets 更新图片素材完成数量。若 generatedItemAssets 已出现 image_ready 且带 imageViews,前端应逐步显示完成数量。

3. 后端编排边界

外部生图、音频生成和 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 个中文字符的作品描述。生成计划还必须包含 tagsbackgroundMusic.titlebackgroundMusic.stylebackgroundMusic.promptbackgroundPrompt,以及 items[] 中每个物品的 namesoundPromptbackgroundMusic.title 是背景音乐名称,backgroundMusic.prompt 固定为空字符串,用于后续 Suno 纯音乐生成;backgroundPrompt 用于生成局内竖屏纯背景图只描述题材氛围、色彩和环境不得描述锅、圆盘、托盘、拼图槽、物品槽、HUD、UI、文字、按钮、倒计时、分数或物品。文本模型不可用时保留第 4 步的本地兜底,不阻断草稿。
  6. 后端把生成计划中的 gameNamesummary 写入 match3d_work_profile 作品信息后,自动调用作品标签生成器。标签生成器使用题材、作品名称和作品描述生成 3 到 6 个中文短标签;若调用失败或返回不足,则使用生成计划 tags 和本地兜底标签补齐。结果页手动 AI生成作品标签 也使用同一接口,并传入当前作品描述。
  7. 后端从同一份作品生成计划读取当前难度所需数量的短物品名称和音效提示词;不得再只生成物品名称而丢失后续音效生成上下文。
  8. 调用 APIMart nanobanana2 / Gemini 图片模型生成 1:11K 素材图,请求模型固定为 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 链路。
  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 同步保存 backgroundMusicTitlebackgroundMusicStylebackgroundMusicPrompt 保存为空字符串作为兼容字段。
  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 同时顶层输出兼容的 backgroundPromptbackgroundImageSrcbackgroundImageObjectKeygeneratedBackgroundAsset,容器图通过 generatedBackgroundAsset.containerImageSrc/containerImageObjectKey 返回。若作品尚无用户自定义封面,草稿生成完成后默认把容器 UI 图写入 coverImageSrc,作为草稿架和作品信息的默认封面。
  15. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息、背景音乐资产信息、背景资产信息和默认封面;后续重进草稿页时从 work profile 的持久化 generatedItemAssetscoverImageSrc 恢复同一批素材、音乐、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

4. 图片提示词

素材图提示词必须显式包含:

生成一张1:1图片
生成严格5*5均匀网格素材图
整体画风遵循:...
只绘制这些物品:...
每格背景必须是统一纯绿色绿幕背景,方便后续转透明
物品本身不得使用与绿幕相同的纯绿色
每格主体完整居中,禁止跨格、贴边或越界影响裁剪后的效果
相邻物体主体之间至少保留 1/4 单格宽度空白间距,物体主体不得占满格子
不要出现文字、水印、UI、边框、网格线、白色背景、灰色背景、纹理背景

包含若干个物品名称 在落地中解释为“按生成出的物品名称绘制对应主体”,不要求图片上写出物品名称。这样可以避免文字渲染污染切图和局内 2D 素材表现。

内置 像素复古 不能只写“复古像素”或“有限色板”。入口页、参考图脚本和后端素材图 prompt 必须使用同一组硬约束:真正复古像素 2D 游戏道具 sprite先按约 64x64 低分辨率像素块绘制再整数倍放大,硬边方块像素清晰可见,有限色板 12-24 色;同时在负向约束中禁止抗锯齿、柔焦、平滑渐变、真实 3D 渲染、PBR 材质、摄影光照和平滑插画。后端即使只收到 assetStyleId = pixel-retroassetStyleLabel = 像素复古,也必须补齐这组约束,避免旧会话、恢复会话或批量新增物品退回普通插画风格。

入口页内置 2D 风格参考图通过同一 VectorEngine gpt-image-2-all 能力生成,执行命令为 npm run assets:match3d-style-references -- --live。每张入口参考图只展示 1 个完整独立物品,不能展示 5 个物品样张或多物品散点图,避免风格选择被误读为物品数量配置。保存路径固定为:

public/match3d-style-references/flat-icon.png
public/match3d-style-references/cel-cartoon.png
public/match3d-style-references/pixel-retro.png
public/match3d-style-references/watercolor.png
public/match3d-style-references/sticker-outline.png
public/match3d-style-references/painterly-icon.png

这些图片只作为入口页风格选择的视觉参考,不进入用户草稿资产,不替代生成时的物品素材图。

局内容器 UI 图生成固定参考图路径为:

public/match3d-background-references/pot-fused-reference.png

这张图只作为容器 UI 图的 VectorEngine image 参考输入,用来锁定“大尺寸轻俯视浅盘容器”的构图。参考图本身是 1:1 透明底容器素材,外轮廓接近画布四边,内口为横向椭圆;结果页没有真实生成容器时也只把它作为容器预览兜底,不能再作为 9:16 背景预览。每次草稿生成仍会根据 backgroundPrompt 生成新的题材化纯背景图;纯背景图不再传入该参考图,也不得生成锅或 UI 元素。

5. OSS 路径

新增 generated legacy prefix

generated-match3d-assets

建议对象分组:

generated-match3d-assets/{sessionId}/{profileId}/material-sheet/{taskId}/sheet.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-01.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-02.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-03.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-04.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-05.png
generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.png

itemSlug 必须带 itemId 前缀,例如 match3d-item-1-item。中文物品名清洗后可能都退回 item,不能只用物品名做路径,否则多张切割图会写到同一个 object key导致草稿页预览图全部一致。

HTTP DTO 同时返回兼容字段 imageSrcimageObjectKey,以及正式 2D 字段 imageViews[]backgroundAssetstatus。图片素材生成成功后 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,容器作为中心棋盘覆盖层。

5.1 运行态 2D 素材消费

生成的 2D 五视角素材不仅用于结果页预览,也必须进入游戏运行态。运行态入口的传递链路为:

Match3DWorkProfile / PlatformMatch3DGalleryCard
-> Match3DRuntimeShell(generatedItemAssets, 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.audioSrcclickSound.audioSrcbackgroundAsset.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>
  3. 场内物品、点击命中和备选栏继续使用后端快照中的 itemInstanceId/itemTypeId/x/y/radius/layer;生成 2D 图片只替换视觉表现,不承接规则真相。
  4. 同一物品类型的多个实例可以展示不同视角,但同一实例在本局中应稳定使用同一个视角,避免移动或入槽时闪图。
  5. 图片缺失、读取失败或解码失败时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算。

结果页点击 试玩 时,前端必须把当前结果页可见的 generatedItemAssets 带入运行态启动入参。PUT /api/runtime/match3d/works/{profileId} 若因为并发或旧快照返回了缺少素材的 profileMatch3DResultView 需要把当前 draft / profile 的素材重新合并到运行态 profile并在启动试玩前调用生成素材保存接口把当前可见的 generatedItemAssets 写回作品 profile不能只在内存里把素材补到 onStartTestRun(profile)。发布同理必须先落库当前素材,再调用 publish_match3d_work,否则公开推荐流和正式运行态只能读到旧 profile 快照。结果页顶部返回按钮固定回到平台创作页,不再回到抓大鹅专属内嵌入口表单;需要修改题材时由用户在创作页重新选择或从草稿继续进入。若历史草稿同时存在旧 draft.generatedItemAssets 和较新的 profile.generatedItemAssets,同 itemId 下以 profile 中已有的 imageViews[]imageSrcimageObjectKeybackgroundMusicbackgroundAsset 补齐 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.generatedItemAssetsgetMatch3DWorkDetail(profileId).item.generatedItemAssets,必须以同 itemId 合并保留详情里的背景音乐、UI 背景和点击音效,再进入结果页或试玩。

历史草稿若仍保存 status = model_readymodelSrcmodelObjectKey,仅作为旧版本兼容读取,不再参与新素材生产。历史外部模型链接转存接口只用于清理旧数据,不能被新草稿生成、批量新增或结果页普通编辑入口调用。

生成完成后自动进入试玩依赖 selectionStageRef.current === 'match3d-generating' 的同步判断。执行 match3d_compile_draft 前切到生成页时,必须同时写 selectionStageRef.current = 'match3d-generating'setSelectionStage('match3d-generating');只调用 React state 会让 action 很快返回时读到旧 stage表现为生成页已经 100% 但不进入试玩或结果页。拼图、大鱼吃小鱼、方洞挑战等同类生成页也遵循同一规则。

6. 自动保存与草稿恢复

点击 生成抓大鹅草稿 后,草稿存档创建与素材生成解耦:

  1. 首次 compile 必须先写 match3d_work_profile 草稿行,即使后续卡在文本模型、图片生成、音频生成或 OSS 上传任意阶段。
  2. 失败态前端要重新读取 session / work detail并刷新草稿作品架保证用户离开生成页后仍能在草稿 Tab 找到这份作品。
  3. 重新生成时优先使用当前 session 的 draft.profileIdpublishedProfileId,不得重新创建 session后端读取同一 profile 的 generated_item_assets_json 后,只补齐缺失图片或缺失音频的阶段。
  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。

草稿架重进路径为:

草稿 Tab -> getMatch3DWorkDetail(profileId) -> Match3DResultView(profile.generatedItemAssets)

若草稿卡已经带有前端生成中标记,即使作品列表已经刷新成真实 match3d_work_profile 草稿行,点击该卡也必须优先回到 match3d-generating 生成过程页,并按 sourceSessionId 重新读取当前 session不能因为 getSession 返回了带 draft 的快照就直接进入结果页。若后台生成已经收口为 ready 且草稿卡仍有未读红点,首次点击必须消费红点并直接启动抓大鹅试玩,返回后展示 Match3DResultView;红点已读后的后续点击才按常规结果页恢复路径进入 Match3DResultView。因此点击恢复优先级固定为:未读 ready 红点自动试玩 > 仍在 generating 的本地 / 后台任务回生成页 > 普通草稿结果页。

因此 map_match3d_work_summary_response / map_match3d_work_profile_response 需要从 work profile snapshot 反序列化 generated_item_assets_json 并输出 generatedItemAssets 与顶层背景字段。前端 Match3DResultView 的读取顺序为:有 draft.generatedItemAssets 时先用 draft 保留本次生成顺序和图片;同 itemIdprofile.generatedItemAssets 中已有 imageViews[]imageSrc/imageObjectKey 时,用 profile 图片字段补齐 draft背景资产同样必须从 profile 或 draft 的首个 backgroundAsset 保留到保存 payload从草稿架重进没有 draft 时,用 profile.generatedItemAssets;两者都没有才回退到默认素材占位。

结果页 作品信息 Tab 字段命名对齐拼图草稿:

  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 写入封面字段。

结果页 难度配置 Tab 取代旧 玩法配置,不再展示旧的分散输入项。该 Tab 顶部使用横向离散拖动条调整难度,四个刻度分别为 轻松 / 标准 / 进阶 / 硬核;拖动条只能落在这四个点上,刻度标签可点击切换。该 Tab 必须与创作入口页使用同一组难度选项,并统一把原“类型素材图片 / 局内类型”等口径归一为 物品种类

难度 clearCount difficulty 总物品数 物品种类
轻松 8 2 24 3
标准 12 4 36 9
进阶 16 6 48 15
硬核 21 8 63 21

预览区展示 需要消除总物品数物品种类已生成物品种类。历史草稿如果保存的是旧 clearCount/difficulty,前端按 clearCount 精确命中优先、否则按 difficulty 就近归一到上述选项,并把归一后的数值保存回 profile。发布校验以 generatedItemAssets[]image_ready 且至少有 5 张有效 imageViews[] 的素材数量为准;试玩启动时用同一数量计算 itemTypeCountOverride,不足时自动降低,不修改草稿难度配置本身。历史单图 imageSrc/imageObjectKey 只作为运行态和预览兜底,不计入新发布素材完成数。

结果页 素材配置 Tab 取代旧一级素材入口,并包含三个子 Tab

  1. 物品:显示 2D 物品素材列表、五视角预览、素材名称、点击音效提示词和点击音效生成入口。
  2. UI:预览生成的竖屏游戏纯背景图和中心容器 UI 图。背景读取顺序为 draft 顶层背景、draft generatedBackgroundAsset、profile 顶层背景、profile generatedBackgroundAssetgeneratedItemAssets[].backgroundAsset、本地兜底图;容器读取 generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey,缺失时使用默认圆形容器。该页必须展示默认画面描述提示词,默认值来自草稿生成计划的 backgroundPrompt 或持久化 backgroundAsset.prompt;用户修改后点击重新生成,后端同时生成纯背景图和容器 UI 图,并把新的 backgroundAsset 写回同一份 generated_item_assets_json。UI 子 Tab 还必须提供独立的运行态 UI 预览面板,直接用当前纯背景图、容器 UI 图、顶部返回/倒计时/重开控件和底部默认托盘模拟竖屏页面,不在 Tab 下方内联展开。
  3. 背景音乐:承载原一级音乐 Tab 的背景音乐曲名、风格、生成进度和试听控件;背景音乐始终按纯音乐生成,前端不提供提示词输入。

旧一级 音乐 Tab 删除;抓大鹅背景音乐入口只保留在 素材配置 > 背景音乐

素材配置 > 物品 详情页只保留:

  1. 五视角预览区:优先展示 imageViews[],缺失时展示兼容字段 imageSrc/imageObjectKey
  2. 素材名称输入。
  3. 可编辑的点击音效提示词输入。
  4. 点击音效生成入口。

详情页不再展示参考图、用途、模型提示词、文生/图生切换、状态查询、下载列表、taskUuid 或 subscriptionKey。

物品素材 列表项点击必须弹出独立预览面板,不允许在列表右侧或列表下方内联展示。列表本身使用移动端至少两列的多列卡片布局;每个列表项只展示图片预览、物品名称和垃圾箱删除图标,不展示用途、状态胶囊、视角数量或 2D素材 标记。预览面板只承担查看五视角图片、编辑素材名称、编辑点击音效提示词和生成点击音效;不再展示 重新生成 按钮。列表项自身支持单项删除,删除后立即把剩余 generatedItemAssets 写回作品 profile。批量新增通过列表顶部按钮打开独立面板面板内每个输入框只输入一个物品名称新增物品名称 按钮追加一个输入框;提交后按输入框顺序清洗、去重并调用 Match3D 作品批量生图接口。生成进度同时显示在批量新增面板和 素材配置 > 物品 列表顶部面板可关闭后台生成继续推进不阻塞封面、音频等其他生成操作。后端复用草稿生成的素材图、切图、OSS 上传和可选点击音效流程,但仅按实际可新增名称持久化,不重新生成已有物品,不新增 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}/assetPOST /api/creation/audio/sound-effect/{task_id}/asset 在真正拿到音频并转存资产前,由后端按 taskId + 资产槽位 幂等预扣;背景音乐扣 5 泥点,物品点击音效扣 10 泥点。任务仍在处理中时不扣费。资产下载、OSS 转存或资产绑定失败时后端自动退款。前端只展示生成按钮和进度,不自行计算或写入钱包。

创作入口不展示 生成音效 Toggle。草稿生成阶段不产生物品点击音效任务也不产生点击音效相关扣费入口只产生一次固定 10 泥点的草稿生成扣费。结果页 素材配置 > UI 重新生成背景固定扣 2 泥点。物品点击音效由结果页 素材配置 > 物品 详情面板手动触发,每个音效按单独任务和单独 match3d_click_sound 资产槽位扣费。音效生成失败不影响草稿,失败素材保留 soundPrompt,用户可在结果页物品详情面板手动重试。

7. 验收

建议执行:

npm run check:encoding
npm run test -- src\services\miniGameDraftGenerationProgress.test.ts
npm run test -- src\components\match3d-result\Match3DResultView.test.tsx
npm run test -- src\components\match3d-runtime\Match3DRuntimeShell.test.tsx
npm run test -- src\components\rpg-entry\RpgEntryFlowShell.agent.interaction.test.tsx
npm run typecheck
cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml
cargo test -p spacetime-client match3d --manifest-path server-rs\Cargo.toml
cargo test -p platform-oss --manifest-path server-rs\Cargo.toml
cargo test -p api-server match3d --manifest-path server-rs\Cargo.toml
cargo check -p api-server --manifest-path server-rs\Cargo.toml
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_BUCKETALIYUN_OSS_ENDPOINTALIYUN_OSS_ACCESS_KEY_IDALIYUN_OSS_ACCESS_KEY_SECRET。如果只配置 bucket 和 endpoint抓大鹅素材、封面或背景生成会在调用外部生图前返回 OSS 未完成环境变量配置details.missingEnv 会列出缺少的 AccessKey 项;不要回退到 Rodin/GLB 或伪造本地上传成功。开启音频生成还需要对应音频上游配置。后端改动后使用 npm run api-server 启动,并检查 /healthz