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:
2026-05-14 20:34:45 +08:00
parent d33c937ebc
commit 548db78ca7
103 changed files with 6687 additions and 3270 deletions

View File

@@ -16,14 +16,38 @@
---
## 2026-05-14 抓大鹅物品素材 sheet 改用 APIMart nanobanana
## 2026-05-14 抓大鹅物品素材批量重新生成复用 item-assets 替换模式
- 背景:抓大鹅 2D 五视角物品素材仍沿用 5x5 sheet、绿幕去背、切图、OSS 转存和 `generatedItemAssets` 持久化,但用户要求物品素材图片生成步骤改用 APIMart 已接好的 nanobanana / Gemini 图片模型
- 决策:抓大鹅物品素材 sheet 生图固定走 APIMart `POST {APIMART_BASE_URL}/images/generations`,模型为 `gemini-3.1-flash-image-preview``size = 1:1``resolution = 1K``official_fallback = true`;响应优先读图片 URL 或 base64缺图片时按 `task_id` 轮询 `/tasks/{task_id}`。封面、9:16 纯背景图、1:1 容器 UI 图、音频、切图、OSS、扣费和运行态消费链路保持不变
- 影响范围:`server-rs/crates/api-server/src/match3d.rs``server-rs/crates/api-server/src/config.rs``deploy/env/api-server.env.example`、抓大鹅素材生成技术文档。
- 验证方式:执行 `cargo test -p api-server match3d_material_sheet --manifest-path server-rs\Cargo.toml``cargo test -p api-server from_env_reads_non_public_models_and_urls --manifest-path server-rs\Cargo.toml``cargo check -p api-server --manifest-path server-rs\Cargo.toml``npm run check:encoding`
- 背景:抓大鹅结果页 `素材配置 > 物品` 需要在不改变玩法物品映射的前提下,批量重新生成已存在物品的 2D 五视角图片
- 决策:继续复用 `POST /api/creation/match3d/works/{profileId}/item-assets`,请求体通过 `mode = "replace"` 表达替换模式;前端面板预填当前素材名称,只提交仍能匹配到已有素材的名称。后端只替换匹配素材的 `imageSrc/imageObjectKey/imageViews/status/error`,保留原 `itemId`、列表顺序、模型兼容字段、UI 背景、历史背景音乐和点击音效字段;未匹配名称不计费、不新增、不持久化
- 影响范围:Match3D 结果页素材配置、前端/后端 shared contracts、`api-server` Match3D item-assets 编排、运行态物品类型映射和素材生成技术文档。
- 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``cargo test -p api-server match3d_item_asset --manifest-path server-rs\Cargo.toml``cargo test -p api-server match3d_regenerated_asset --manifest-path server-rs\Cargo.toml``npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-14 拼图与抓大鹅音频生成入口临时关闭
- 背景:当前需要暂时关闭抓大鹅、拼图中生成背景音乐和音效的能力,并隐藏草稿中的相关入口。
- 决策:拼图 `compile_puzzle_draft` 不再自动生成背景音乐,结果页素材配置只保留 `UI`;抓大鹅 `match3d_compile_draft` 和批量新增只生成 2D 图片、背景和容器 UI不再调用 Suno/Vidu结果页隐藏 `背景音乐` 子 Tab 与点击音效生成控件;通用 `/api/creation/audio/*` 当前整体返回 `410 Gone`。历史已写入的 `backgroundMusic` / `clickSound` 字段保留,运行态继续兼容播放旧音频。
- 影响范围:`api-server` 拼图/抓大鹅草稿编排、通用创作音频路由、拼图/抓大鹅结果页、生成进度模型、相关技术文档。
- 验证方式:执行拼图/抓大鹅结果页定向测试、生成进度单测、`cargo check -p api-server --manifest-path server-rs/Cargo.toml``npm run check:encoding`
- 关联文档:`docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-14 抓大鹅物品素材 sheet 改用 VectorEngine Gemini
- 背景:抓大鹅 2D 五视角物品素材仍沿用 5x5 sheet、绿幕去背、切图、OSS 转存和 `generatedItemAssets` 持久化,但用户要求物品素材图片生成步骤改用 VectorEngine Apifox `api-381740608` 对应的 Gemini 原生图片接口。
- 决策:抓大鹅物品素材 sheet 生图固定走 VectorEngine `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"]``imageConfig.aspectRatio = "1:1"`;响应从 `candidates[].content.parts[].inlineData.data` / `inline_data.data` 读取 base64 图片。封面、9:16 纯背景图、1:1 容器 UI 图、切图、OSS、扣费和运行态消费链路保持不变音频以后续“拼图与抓大鹅音频生成入口临时关闭”决策为准。
- 影响范围:`server-rs/crates/api-server/src/match3d.rs``server-rs/crates/api-server/src/config.rs``deploy/env/api-server.env.example`、抓大鹅素材生成技术文档。
- 验证方式:执行 `cargo test -p api-server match3d_material_sheet --manifest-path server-rs\Cargo.toml``cargo test -p api-server match3d_vector_engine_gemini --manifest-path server-rs\Cargo.toml``cargo check -p api-server --manifest-path server-rs\Cargo.toml``npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-14 草稿页作品卡对齐分类页列表
- 背景:草稿页作品架原本偏封面大卡片,和发现页分类列表的横向卡片样式不一致;生成中状态也缺少整卡级的统一遮罩。
- 决策:草稿页作品卡统一收口为与分类页一致的横向列表卡结构,左侧承载标题/状态/类型/摘要与必要数据,右侧显示带透明度的封面图;移动端保持单列列表,网页端使用两到三列卡片式网格,避免宽屏长条列表。不再常驻“继续创作”“查看详情”“查看进度”等右侧动作按钮。原有删除、分享、积分激励、公开统计、未读红点全部保留,其中删除与分享进入左滑操作层,常态不显示删除按钮,也不得透出删除底层。生成中的作品在整卡上加半透明蒙版、旋转等待符号和“生成中...”标识,但不移除任何原有信息。
- 影响范围:`src/components/custom-world-home/CustomWorldCreationHub.tsx``src/components/custom-world-home/CustomWorldWorkCard.tsx`、相关样式与测试、草稿页 UI 文档。
- 验证方式:草稿页作品卡与分类页列表视觉口径保持一致;`npm run test -- src/components/custom-world-home/CustomWorldCreationHub.test.tsx src/components/custom-world-home/CustomWorldCreationHub.interaction.test.tsx``npm run typecheck``npm run check:encoding`
- 关联文档:`docs/design/MOBILE_CREATION_WORK_LIST_TWO_COLUMN_LAYOUT_2026-04-29.md``docs/experience/MOBILE_UI_DEV_EXPERIENCE.md`
## 2026-05-13 认证运行期同步直接导入正式认证表
- 背景:`auth_store_snapshot` 是 Stage 1 整包快照过渡表,主键固定 `default`,会让所有用户状态集中在一条 `snapshot_json`Stage 2/3 已有 `user_account/auth_identity/refresh_session` 正式认证表,继续刷新 `default` 容易让运行时真相和表拆分目标混在一起。
@@ -82,8 +106,8 @@
## 2026-05-12 抓大鹅结果页素材编辑统一走作品级资产面板
- 背景:抓大鹅结果页需要支持面图上传 / AI 重绘、物品素材独立预览、单项删除和批量新增,且不能把素材编辑继续做成列表内联展开或前端临时状态。
- 决策:结果页 `作品信息`面图点击打开独立面板,参考图可来自本地上传、物品素材和 UI 素材AI 重绘统一调用 `POST /api/creation/match3d/works/{profileId}/cover-image` 并转存到 `generated-match3d-assets``素材配置 > 物品` 列表项点击打开独立预览面板,不再提供单项重新生成按钮;单项删除和批量新增都写回同一份 `generated_item_assets_json`。批量新增调用 `POST /api/creation/match3d/works/{profileId}/item-assets`,复用草稿生成的 2D 素材图、5x5 切图、OSS 上传和可选点击音效链路,仅作用于新增物品,不新增 SpacetimeDB 表。
- 背景:抓大鹅结果页需要支持面图上传 / AI 重绘、物品素材独立预览、单项删除和批量新增,且不能把素材编辑继续做成列表内联展开或前端临时状态。
- 决策:结果页 `作品信息`面图点击打开独立面板,封面图面板对齐拼图入口上传卡。已有上传主图时,请求体传 `uploadedImageSrc`AI 重绘走 VectorEngine `/v1/images/edits`;关闭 AI 重绘时只写回上传图,不调用生图。没有上传主图时,请求体传 `referenceImageSrcs`,可混合本地上传、物品素材和 UI 素材,多参考图作为 `gpt-image-2-all` generations 的 `image` 数组传入。生成结果统一调用 `POST /api/creation/match3d/works/{profileId}/cover-image` 并转存到 `generated-match3d-assets``素材配置 > 物品` 列表项点击打开独立预览面板,不再提供单项重新生成按钮;单项删除和批量新增都写回同一份 `generated_item_assets_json`。批量新增调用 `POST /api/creation/match3d/works/{profileId}/item-assets`,复用草稿生成的 2D 素材图、5x5 切图、OSS 上传和可选点击音效链路,仅作用于新增物品,不新增 SpacetimeDB 表。
- 影响范围Match3D 结果页、Match3D works shared contracts、`api-server` Match3D 作品路由、生成资产历史类型和草稿恢复路径。
- 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run typecheck``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``cargo check -p api-server --manifest-path server-rs/Cargo.toml``npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
@@ -136,6 +160,14 @@
- 验证方式:执行入口配置、创作 Hub 和平台入口交互定向测试,确认看不到“方洞挑战” Tab、按钮和作品架条目。
- 关联文档:`docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md``docs/design/PLATFORM_CREATE_TAB_CREATIVE_AGENT_HOME_2026-05-05.md`
## 2026-05-14 视觉小说从创作页入口隐藏
- 背景:当前创作页需要关闭视觉小说模板入口,不能继续在模板 Tab、旧选择弹层或创作 Hub 卡片中展示。
- 决策SpacetimeDB `creation_entry_type_config` 默认种子中 `visual-novel.visible=false``open=false`;旧默认可见配置会被迁移为隐藏和关闭。前端继续只消费 `GET /api/creation-entry/config`,不得用硬编码恢复视觉小说模板入口。
- 影响范围SpacetimeDB 入口配置默认种子、api-server 测试配置、创作页模板 Tab、创作 Hub 测试和创作入口文档。
- 验证方式:执行入口配置、创作 Hub、平台入口交互和 api-server 路由熔断定向测试,确认“视觉小说”不出现在创作页且 `/api/creation/visual-novel/*` 默认被熔断。
- 关联文档:`docs/design/PLATFORM_CREATE_TAB_CREATIVE_AGENT_HOME_2026-05-05.md``docs/technical/ADMIN_CREATION_ENTRY_SWITCH_CONFIG_2026-05-11.md`
## 2026-05-10 运行态输入设备抽象层全项目通用化
- 背景:拼图运行态接入 mocap 后,鼠标/触控和 mocap 各自维护输入逻辑会导致合并大块、拖拽语义和取消会话行为不一致;后续其他玩法也需要复用体感、摇杆、键盘等设备输入。
@@ -147,7 +179,7 @@
## 2026-05-11 前端调试模式统一判断
- 背景:拼图 mocap 调试面板此前在运行态常驻展示,生产构建和正式体验里容易遮挡棋盘内容;后续其它局部诊断 UI 也需要统一的调试模式入口。
- 决策:前端新增 `src/config/debugMode.ts` 作为全局调试模式判断,默认跟随 Vite 开发态,允许 `VITE_DEBUG_MODE=true/false` 显式覆盖。拼图运行态 mocap 调试面板只在调试模式下渲染,并默认折叠,只保留连接状态行
- 决策:前端新增 `src/config/debugMode.ts` 作为全局调试模式判断,默认跟随 Vite 开发态,允许 `VITE_DEBUG_MODE=true/false` 显式覆盖。2026-05-14 起,拼图运行态已临时移除 mocap 调用、体感光标和 mocap 调试面板调试模式仍供其它局部诊断 UI 使用
- 影响范围:前端局部调试 UI、拼图运行态 mocap 诊断面板、`.env.example` 和运行态输入技术文档。
- 验证方式:执行 `npm run test -- src\components\puzzle-runtime\PuzzleRuntimeShell.test.tsx``npm run typecheck` 和编码检查。
- 关联文档:`docs/technical/RUNTIME_INPUT_DEVICE_ABSTRACTION_2026-05-10.md`

View File

@@ -14,6 +14,14 @@
- 关联:相关文件、文档、提交或 Issue
```
## 抓大鹅批量重新生成物品不要新增 itemId
- 现象:结果页批量重新生成物品后,试玩或正式运行态的物品类型和图片对应关系漂移,或者用户输入一个不存在名称后被当作新物品追加。
- 原因:重新生成和批量新增共用 `item-assets` 接口,如果前端不传 `mode = "replace"`,或后端替换时重新分配 `itemId` / 追加未匹配名称,就会破坏 `generatedItemAssets` 顺序和运行态类型映射。
- 处理:批量重新生成只提交当前素材列表中能匹配到的名称,并传 `mode = "replace"`;后端只对同名已有素材生成新图片,合并时保留原 `itemId``itemName`、模型兼容字段、UI 背景和历史音频字段,未匹配名称直接忽略且不计费。
- 验证:`npm run test -- src\components\match3d-result\Match3DResultView.test.tsx` 覆盖前端提交口径,`cargo test -p api-server match3d_item_asset --manifest-path server-rs\Cargo.toml``cargo test -p api-server match3d_regenerated_asset --manifest-path server-rs\Cargo.toml` 覆盖后端替换计划与身份保留。
- 关联:`src/components/match3d-result/Match3DResultView.tsx``server-rs/crates/api-server/src/match3d.rs``packages/shared/src/contracts/match3dWorks.ts``server-rs/crates/shared-contracts/src/match3d_works.rs``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## OSS V4 签名时间和 bucket/object_key 兼容
- 现象OSS V4 私有读签名在部分时间点失败,可能出现 `OSS V4 签名时间格式化失败` 或服务端判定签名格式错误;排查用例中 bucket 为 `xushi-dev`object_key 为 `generated-square-hole-assets/.../image.png`
@@ -67,7 +75,7 @@
- 验证:`npm run test -- src/services/apiClient.test.ts` 覆盖 `details.reason``cargo test -p api-server state --manifest-path server-rs/Cargo.toml` 覆盖半配置 OSS 不阻断启动;`npm run api-server` 后按实际 `GENARRATIVE_API_PORT` 请求 `/healthz`,不要默认打 `3100`
- 关联:`packages/shared/src/http.ts``server-rs/crates/api-server/src/state.rs``docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md``docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md`
2026-05-14 补充:抓大鹅“物品素材 sheet”已改用 APIMart `gemini-3.1-flash-image-preview`,真实生成还需要 `APIMART_BASE_URL``APIMART_API_KEY``APIMART_IMAGE_REQUEST_TIMEOUT_MS`;封面、背景图和容器 UI 仍继续使用 VectorEngine。排查时先按失败阶段区分缺 APIMart、VectorEngine 还是 OSS不能把物品素材缺 APIMart 误判成 VectorEngine 缺配置
2026-05-14 补充:抓大鹅“物品素材 sheet”已改用 VectorEngine Gemini `gemini-3-pro-image-preview` 原生 `generateContent`,真实生成读取 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY``VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;封面和 `9:16` 背景图走 VectorEngine `/v1/images/generations``1:1` 容器 UI VectorEngine `/v1/images/edits` multipart 参考图链路。排查素材 sheet 时看请求路径是否为 `/v1beta/models/gemini-3-pro-image-preview:generateContent?key=...`,响应图片在 `candidates[].content.parts[].inlineData.data` / `inline_data.data`,不要再按 APIMart `/images/generations``/tasks/{task_id}` 排查
## `.hermes` 只放共享内容,不放个人 Hermes 配置
@@ -150,13 +158,13 @@
- 验证:`curl -i -X POST https://api.vectorengine.ai/v1/images/edits -H "Authorization: Bearer invalid" -F "model=gpt-image-2-all" -F "prompt=test" -F "n=1" -F "size=1024x1024"` 至少应返回 HTTP `401`说明域名、TLS 和路径可达;执行 `cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`
- 关联:`server-rs/crates/api-server/src/puzzle.rs``docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md``docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`
## 拼图自动试玩缺 UI 背景先查本地运行态字段继承
## 拼图 UI 背景缺失先区分生成失败和消费链路丢字段
- 现象:拼图草稿生成完成后,草稿数据里已有首关 `uiBackgroundImageSrc`,结果页素材配置也能看到背景图,但自动试玩结果页“试玩”进入局内仍只显示封面模糊背景,甚至看不到 UI 背景。
- 原因:生成完成后的自动试玩走前端 `startLocalPuzzleRun(...)` 本地运行态兜底,不经过后端 `start_puzzle_run`;如果本地 run 只把 `coverImageSrc` 带入 `currentLevel`,就会丢掉 `levels[].uiBackgroundImageSrc``levels[].backgroundMusic`
- 处理:`startLocalPuzzleRun` 与本地下一关 handoff 都要从关卡 `levels[]` 复制 `uiBackgroundImageSrc``backgroundMusic``currentLevel``PuzzleRuntimeShell` 继续读取 `currentLevel.uiBackgroundImageSrc` 渲染全屏背景
- 验证:`npm run test -- src/services/puzzle-runtime/puzzleLocalRuntime.test.ts src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx`
- 关联:`src/services/puzzle-runtime/puzzleLocalRuntime.ts``src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``src/components/puzzle-result/PuzzleResultView.tsx``docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`
- 现象:拼图草稿生成完成后,素材配置页没有展示生成的 UI 背景,或结果页能看到背景但自动试玩 / 结果页“试玩”进入局内仍只显示封面模糊背景。
- 原因:`compile_puzzle_draft` 设计上会在首图后生成 UI 背景,且缺 `uiBackgroundImageSrc/uiBackgroundImageObjectKey` 会让自动草稿失败;若草稿已成功,通常不是“没生成”,而是前端消费链路漏了 `levels[].uiBackgroundImageObjectKey` 回退,或本地 `startLocalPuzzleRun(...)` 只把 `coverImageSrc` 带入 `currentLevel`
- 处理:结果页预览、运行态和本地运行态统一用 `resolvePuzzleUiBackgroundSource`,优先 `uiBackgroundImageSrc`,为空时把 `uiBackgroundImageObjectKey` 规范成 `/generated-...` 路径并交给 `/api/assets/read-url` 换签;`startLocalPuzzleRun` 与本地下一关 handoff 都要从 `PuzzleWorkSummary.levels[]` 复制 `uiBackgroundImageSrc/uiBackgroundImageObjectKey/backgroundMusic``currentLevel`。结果页 `UI背景提示词` 输入框不得把本地兜底 prompt 直接显示成已保存提示词,避免误判为后端已生成
- 验证:`npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx src/services/puzzle-runtime/puzzleLocalRuntime.test.ts src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx`,以及 `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "puzzle draft generation auto starts trial"`;后端用 `cargo test -p api-server puzzle_ui_background --manifest-path server-rs\Cargo.toml` 确认生成 / 序列化链路
- 关联:`src/services/puzzle-runtime/puzzleUiBackgroundSource.ts``src/services/puzzle-runtime/puzzleLocalRuntime.ts``src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``src/components/puzzle-result/PuzzleResultView.tsx``docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`
## 拼图草稿生成后音乐/UI 又变空先查结果页回包合并
@@ -182,6 +190,14 @@
- 验证:运行 `npm run test -- src/services/creation-agent/creationAgentClientFactory.test.ts src/services/apiClient.test.ts``cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`,真实联调重启 `npm run api-server` 后检查 `/healthz`
- 关联:`src/services/creation-agent/creationAgentClientFactory.ts``server-rs/crates/api-server/src/puzzle.rs``docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`
## 本地脚本调 VectorEngine 生图卡住先区分 fetch 首部超时
- 现象:用 Node `fetch` 直接请求 `POST /v1/images/generations`,已经设置较长的 AbortController 超时,但仍在约 180 到 300 秒后抛 `AbortError``TypeError: fetch failed``UND_ERR_HEADERS_TIMEOUT`;同一 prompt 改用原生 `https.request` 可以在较短时间内成功返回图片。
- 原因Node/Undici 的默认 headers timeout 可能早于业务脚本期望的长生图等待窗口触发,表现上容易被误判成 VectorEngine 上游本身超时。
- 处理:长期脚本优先复用后端 reqwest 或项目已有生成脚本;临时本地工具若必须用 Node可改用原生 `http`/`https.request` 并显式设置 socket timeout或为 Undici 单独配置 headers timeout。仍需隐藏 `VECTOR_ENGINE_API_KEY`,只报告配置是否存在。
- 验证:同一 `gpt-image-2-all` 请求体、同一环境变量下,原生 HTTP 请求能返回 `url` / `b64_json` 并落盘;失败时错误里能区分请求发送、首部等待、下载和解码阶段。
- 关联:`.codex/skills/gpt-image-2-apimart/SKILL.md``server-rs/crates/api-server/src/openai_image_generation.rs`
## 旧后端路线文档造成判断漂移
- 现象:开发时参考到 Express、Node、PostgreSQL 或 Go 方向旧文档,导致接口、数据真相或部署路径与当前主线不一致。
@@ -591,6 +607,22 @@
- 验证:执行 `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`,并检查历史草稿和公开 M3 作品的 Network 响应里 `generatedItemAssets[].imageViews/imageSrc/imageObjectKey`
- 关联:`src/components/match3d-result/Match3DResultView.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``src/components/match3d-runtime/Match3DPhysicsBoard.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅 UI 背景和容器只在顶层字段时也要传进运行态
- 现象:抓大鹅草稿 / 推荐卡片响应里已有 `generatedBackgroundAsset`,结果页 UI 预览能看到纯背景图和容器图,但进入试玩或正式局内仍显示默认渐变背景和默认圆形容器。
- 原因:部分链路把 UI 资产只放在作品顶层 `generatedBackgroundAsset` / `backgroundImageObjectKey`,没有同步放进首个 `generatedItemAssets[].backgroundAsset`;如果运行态入口只传 `generatedItemAssets``backgroundImageSrc``Match3DRuntimeShell` 就拿不到 `containerImageObjectKey`
- 处理:`PlatformMatch3DGalleryCard``mapPublicWorkDetailToMatch3DWork``resolveMatch3DRuntimeGeneratedBackgroundAsset``Match3DRuntimeShell` 都必须保留并传递顶层 `generatedBackgroundAsset`;运行态背景读取顺序为 `backgroundImageSrc` / 顶层 `generatedBackgroundAsset.image*` / `generatedItemAssets[].backgroundAsset.image*`,容器读取顺序为顶层 `generatedBackgroundAsset.containerImage*` / `generatedItemAssets[].backgroundAsset.containerImage*`
- 验证:执行 `npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx``npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "Match3D runtime"`;浏览器 Network 中背景和容器 generated path 应先请求 `/api/assets/read-url` 换签,局内出现 `match3d-background-image``match3d-container-image` 对应图片。
- 关联:`src/components/match3d-runtime/Match3DRuntimeShell.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``src/components/rpg-entry/rpgEntryWorldPresentation.ts``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅容器参考图必须走 edits 并接管棋盘外观
- 现象:抓大鹅结果页看似有容器生成入口,但真实生成出的局内容器不像 `pot-fused-reference.png`,或进入试玩后仍被默认圆形锅壳、金色边框和径向底色覆盖/裁切。
- 原因:`/v1/images/generations``image` 数组更适合弱参考文生图,难以稳定锁定大尺寸轻俯视容器构图;即使生成了容器图,如果运行态继续保留默认 `rounded-full` 锅壳和 `overflow-hidden`,生成图也会被默认视觉覆盖或裁掉。
- 处理:抓大鹅 `1:1` 容器 UI 图必须用 VectorEngine `POST /v1/images/edits` multipart`public/match3d-background-references/pot-fused-reference.png` 作为 `image` part 上传;共享 GPT-image-2 HTTP client 承载 multipart 时强制 HTTP/1.1。`Match3DRuntimeShell` 在容器图换签并成功加载后,把棋盘外壳切为透明和 `overflow-visible`,只在容器缺失或加载失败时使用默认圆形容器。
- 验证:执行 `cargo test -p api-server vector_engine --manifest-path server-rs/Cargo.toml``cargo test -p api-server match3d_background --manifest-path server-rs/Cargo.toml``npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx src/components/match3d-result/Match3DResultView.test.tsx`;真实联调看容器生成请求是否命中 `/v1/images/edits`,局内 `match3d-container-image` 是否渲染且 `match3d-board` 不再含默认 `rounded-full`
- 关联:`server-rs/crates/api-server/src/openai_image_generation.rs``server-rs/crates/api-server/src/match3d.rs``src/components/match3d-runtime/Match3DRuntimeShell.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅结果页音频试听也要先换签
- 现象:抓大鹅草稿生成完成后,背景音乐已写在 `generatedItemAssets[0].backgroundMusic.audioSrc`,但 `素材配置 > 背景音乐` 或物品详情音效 `<audio>` 不能播放Network 可能请求裸 `/generated-match3d-assets/...mp3` 并返回 403。
@@ -646,6 +678,22 @@
- 验证:`cargo test -p api-server match3d_tag_normalization --manifest-path server-rs/Cargo.toml`,并保留 `normalize_match3d_tag("3D素材") == "3D素材"` 的单测。
- 关联:`server-rs/crates/api-server/src/match3d.rs`
## 抓大鹅物品切图白边或绿幕残留先查后端透明化
- 现象:抓大鹅生成的物品视角图裁剪后仍带白边,或者整块纯绿色绿幕背景没有被透明化,运行态看到绿色方块。
- 原因:素材 sheet 可能是“每格内部绿幕、整张图外圈近白底”,内部绿幕不一定连通到 sheet 外边缘;旧 flood fill 只从外边缘找背景会漏掉这种绿幕块。白底抗锯齿如果不纳入抠像和边缘去污染,也会随裁剪输出成一圈白边。
- 处理:`api-server``slice_match3d_material_sheet` 必须先在整张 sheet 上做透明背景后处理:外边缘连通绿幕/近白底清 alpha非连通但高置信纯绿块也清 alpha边缘近白和绿幕抗锯齿做透明或去污染同时保护不够纯的绿色主体像素。
- 验证:`cargo test -p api-server match3d_material_sheet_slicing --manifest-path server-rs\Cargo.toml` 覆盖非连通绿幕、白边、贴边主体保留和固定 5x5 切图。
- 关联:`server-rs/crates/api-server/src/match3d.rs``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 草稿页卡片有真实素材但仍显示黑卡先查摘要字段
- 现象:草稿页拼图卡片没有关卡图背景,抓大鹅卡片没有背景图或物品图背景,甚至兜底视觉也退回黑色面板。
- 原因:拼图列表摘要若不下发 `levels`,前端拿不到关卡 `coverImageSrc` / 候选图;抓大鹅列表摘要若只提供公开 URL、不保留 `generatedBackgroundAsset``generatedItemAssets` 中的 object key前端无法换签读取私有生成图。卡片封面组件如果自带暗色默认背景也会让兜底失败时看起来仍是黑卡。
- 处理:拼图 `map_puzzle_work_summary_response` 必须保留 `levels`;草稿页优先用关卡 `coverImageSrc`,再用候选图。抓大鹅货架封面解析必须读取 `backgroundImageObjectKey``generatedBackgroundAsset.imageObjectKey/containerImageObjectKey``generatedItemAssets[].imageObjectKey``imageViews[].imageObjectKey`。图片渲染统一交给 `ResolvedAssetImage` 换签,并给卡片传入玩法参考图与暖色底兜底。
- 验证:执行 `npm run test -- src/components/custom-world-home/creationWorkShelf.test.ts src/components/custom-world-home/CustomWorldCreationHub.test.tsx src/hooks/useResolvedAssetReadUrl.test.tsx``cargo test -p api-server puzzle_work_summary_response_keeps_levels_for_shelf_cover --manifest-path server-rs\Cargo.toml``npm run typecheck`
- 关联:`src/components/custom-world-home/creationWorkShelf.ts``src/components/CustomWorldCoverArtwork.tsx``server-rs/crates/api-server/src/puzzle.rs``docs/technical/CREATION_WORK_SHELF_UNIFICATION_2026-04-25.md`
## 用户标签不要直接外显SpacetimeDB Vec 字段不要写 default 宏
- 现象:给 `user_account.user_tags` 或邀请码独立标签列写 `#[default(Vec::<String>::new())]`SpacetimeDB WASM 构建报 `destructor of Vec<String> cannot be evaluated at compile-time`
@@ -661,3 +709,27 @@
- 处理:公开详情失效统一走 `resolveWorkNotFoundRecoveryAction(...)`,覆盖 `/works/detail``/gallery/puzzle/detail``/gallery/visual-novel/detail`;搜索失败和拼图详情 404 分支清理详情/运行态临时状态并回首页;`work-detail` 空数据阶段显示轻量读取态,避免异步间隙白屏。
- 验证:`npm run test -- src/routing/runtimeNotFoundRecovery.test.ts``npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "direct missing public work detail alert returns to platform home"`
- 关联:`docs/technical/PUBLIC_WORK_DETAIL_NOT_FOUND_RECOVERY_2026-05-11.md``src/routing/runtimeNotFoundRecovery.ts``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
## 拼图 UI 背景只有 objectKey 时不要回退默认 UI
- 现象:拼图草稿页、试玩和正式运行态都显示默认 UI或者只在结果页看到生成图进入试玩后又回到默认背景。
- 原因:`uiBackgroundImageSrc` 可能为空而真实生成结果只写了 `uiBackgroundImageObjectKey`;如果前端和运行态只读 `src`,或者本地试玩 / 正式 run 没把 `objectKey` 一起传递,就会丢掉已有背景。
- 处理:统一通过一个解析入口把 `uiBackgroundImageSrc || uiBackgroundImageObjectKey` 归一到可展示路径;本地试玩和正式运行态都要保留 `uiBackgroundImageObjectKey`,并在 `uiBackgroundImageSrc` 为空时换签读取。
- 验证:结果页 UI Tab、`startLocalPuzzleRun``PuzzleRuntimeShell` 都应在仅有 `objectKey` 时显示生成背景,不再回落默认 UI。
- 关联:`src/services/puzzle-runtime/puzzleUiBackgroundSource.ts``src/components/puzzle-result/PuzzleResultView.tsx``src/services/puzzle-runtime/puzzleLocalRuntime.ts``src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``server-rs/crates/module-puzzle/src/application.rs`
## 拼图 UI 背景提示词不像 AI 生成先查首关命名契约
- 现象:拼图草稿生成完成后,`素材配置 > UI` 里显示的 `UI背景提示词` 像前端或后端模板拼接,而不是 AI 生成的视觉提示词。
- 原因:首关命名 LLM 旧契约只返回 `levelName`,自动 UI 背景阶段只能用作品名、作品描述、关卡描述和标签拼接确定性兜底提示词;前端旧实现又会在 `uiBackgroundPrompt` 为空时把本地默认模板直接填进文本框,造成“看起来已有 AI 提示词”的假象。
- 处理:首关命名 LLM 契约必须同时返回 `{"levelName":"...","uiBackgroundPrompt":"..."}`;草稿自动 UI 背景生成优先使用该 AI 提示词,视觉精修请求若返回新提示词则覆盖文本请求提示词,否则保留文本请求提示词。前端文本框只展示已保存的 `uiBackgroundPrompt` 或用户编辑值,字段为空时不展示本地兜底模板。
- 验证:执行 `cargo test -p api-server puzzle_level_naming --manifest-path server-rs\Cargo.toml``cargo test -p api-server puzzle_initial_ui_background_prompt --manifest-path server-rs\Cargo.toml``npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx`
- 关联:`server-rs/crates/api-server/src/prompt/puzzle/level_name.rs``server-rs/crates/api-server/src/puzzle.rs``src/components/puzzle-result/PuzzleResultView.tsx``docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`
## 拼图 / 抓大鹅 UI 背景重生成报 No such procedure 先查 SpacetimeDB 版本漂移
- 现象:拼图或抓大鹅结果页点击 `重新生成` UI 背景时报 `No such procedure`,常见位置是泥点预扣、`save_puzzle_ui_background` 或 Match3D 草稿写回。
- 原因:`api-server``spacetime-client` 已按新 bindings 调用 procedure但目标 SpacetimeDB 数据库仍运行旧 wasm尚未导出钱包扣退费、拼图 UI 背景保存或 Match3D 写回相关 procedure。
- 处理:临时容错是把这类 `No such procedure` 当作后端版本漂移:泥点预扣阶段跳过扣费,图片已经生成但保存失败时返回本次内存快照 / 内存 profile避免草稿页直接报错。长期修复仍是发布最新 `spacetime-module`、重新生成 bindings并用 `spacetime describe` 或定向 smoke 确认 procedure 已导出。
- 验证:`cargo test -p api-server asset_operation_billing_skips_spacetime_connectivity_errors --manifest-path server-rs\Cargo.toml``cargo test -p api-server match3d_fallback_work_profile_keeps_generated_background_asset --manifest-path server-rs\Cargo.toml``npm run api-server` 后检查 `/healthz`
- 关联:`server-rs/crates/api-server/src/asset_billing.rs``server-rs/crates/api-server/src/match3d.rs``docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`