This commit is contained in:
2026-05-14 01:11:58 +08:00
parent b13870f71b
commit 5a55180b78
61 changed files with 5050 additions and 1057 deletions

View File

@@ -101,11 +101,25 @@ HYPER3D_MODEL_REQUEST_TIMEOUT_MS / RODIN_MODEL_REQUEST_TIMEOUT_MS
3. 文本 LLM provider 为 `ark` 且未配置 `GENARRATIVE_LLM_BASE_URL` 时,仍回退到 Ark 公开基础 URL。
4. 角色视频 provider 复用 Ark 且未配置 `ARK_CHARACTER_VIDEO_BASE_URL` 时,仍回退到 Ark 公开基础 URL。
5. 具体模型名缺失时不在配置层伪造默认模型,调用到对应能力时由下游配置校验返回缺配置错误。
6. VectorEngine 图片与音频生成只读取 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY`,其中 GPT-image-2 图片生成额外读取 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;不复用 `APIMART_*``GENARRATIVE_LLM_*` 或前端变量。
6. VectorEngine 图片与音频生成只读取 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY`,其中 GPT-image-2 图片生成额外读取 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;不复用 `APIMART_*``GENARRATIVE_LLM_*` 或前端变量。拼图 Agent 的生成 action 不做前端自动重试,避免一次点击在上游超时后重复触发外部生图与钱包扣退费;若 VectorEngine 请求达到该超时窗口api-server 返回 `504 Gateway Timeout``error.details.provider``vector-engine`,并保留具体超时 message。
7. 火山引擎语音能力由 `platform-speech` 收口协议帧与上游鉴权,`api-server` 只暴露平台鉴权后的代理路由,不向前端返回任何密钥字段。
8. Hyper3D Rodin Gen-2 使用公开默认 `https://api.hyper3d.com/api/v2`API Key 只读取 `HYPER3D_API_KEY` / `RODIN_API_KEY`,不复用文本 LLM、图片或音频网关密钥。
9. APIMart 当前只保留给创意 Agent 的 `gpt-5` Responses 文本/多模态理解链路GPT-image-2 图片生成不得再读取 APIMart 配置。
10. 本地 `npm run api-server``npm run dev:rust``npm run dev` 的环境文件优先级固定为外层 shell 变量最高,其后 `.env``.env.local``.env.secrets.local` 逐层覆盖;真实密钥建议放在 `.env.secrets.local`,防止 `.env` 中的空示例值覆盖私密配置。
10. 本地 `npm run api-server``npm run dev:rust``npm run dev``npm run dev:web` 的环境文件优先级固定为非空外层 shell 变量最高,其后 `.env``.env.local``.env.secrets.local` 逐层覆盖;真实密钥建议放在 `.env.secrets.local`,防止 `.env` 中的空示例值覆盖私密配置。外层 shell 变量如果是空字符串或全空白,不再遮蔽本地 env 文件中的真实值。
11. OSS 客户端只在 `ALIYUN_OSS_BUCKET``ALIYUN_OSS_ENDPOINT``ALIYUN_OSS_ACCESS_KEY_ID``ALIYUN_OSS_ACCESS_KEY_SECRET` 四项齐全时初始化。四项全部缺失表示未启用 OSS部分缺失时 `api-server` 记录 warning 并继续启动,具体上传、换签或读取 generated 私有资产的接口返回 `OSS 未完成环境变量配置`,并在 `error.details.missingEnv` 中列出缺失变量。
12. 抓大鹅 2D 草稿素材生成需要同时具备 VectorEngine 与 OSS 配置VectorEngine 负责 `gpt-image-2-all` 生成 1K 素材图OSS 负责保存 5x5 切割后的五视角图片。缺少 VectorEngine 或 OSS 时应通过 `error.details.reason` 向前端暴露具体缺项,不能只显示泛化“服务暂不可用”。素材图生成、封面生成和背景图生成在调用 VectorEngine 前必须先预检 OSS避免已消耗外部生图后才发现无法落库。
13. 拼图有参考图且开启 AI 重绘时使用 VectorEngine `POST /v1/images/edits` multipart 接口。若返回 `error sending request for url`,代表后端未收到 HTTP 响应;响应 `details` 会带 `reason``source``connect``body``timeout``endpoint`排查时优先检查服务器网络、DNS、防火墙、代理和参考图大小。拼图图片客户端强制 HTTP/1.1,以降低上游 multipart HTTP/2 连接中断风险。
14. 本地排查 `OSS 未完成环境变量配置` 时必须核对键名是否精确为 `ALIYUN_OSS_ACCESS_KEY_SECRET`。常见误写是把 `OSS` 的首字母 `O` 写成数字 `0`,例如 `ALIYUN_0SS_ACCESS_KEY_SECRET`;该键不会被 `api-server` 读取。
## 本地配置检查
拼图真实生成同时依赖 VectorEngine 与 OSS。触发生成前可先运行
```bash
npm run check:api-server-env
```
该命令只输出配置项是否存在,不打印密钥值。若显示 `ALIYUN_0SS_*`,说明把 `OSS` 的字母 `O` 写成了数字 `0`。修正 env 文件后必须重启 `npm run api-server``npm run dev`,已经运行中的 `api-server` 进程不会自动读取新的环境变量。
## 示例文件

View File

@@ -20,6 +20,8 @@
- Big Fish Agent 动作 `big_fish_publish_game`
- Puzzle Agent 图片生成动作 `compile_puzzle_draft``generate_puzzle_images`
- Puzzle Agent 动作 `publish_puzzle_work`
- Match3D / 抓大鹅草稿生成动作 `match3d_compile_draft`
- 拼图 / 抓大鹅结果页手动生成背景音乐、UI 背景与抓大鹅批量新增物品素材
暂不接入以下入口:
@@ -31,6 +33,10 @@
## 计费规则
- 每次可计费资产操作消耗 `1` 枚光点。
- 例外Match3D / 抓大鹅草稿生成是一次完整草稿外部生成动作,固定消耗 `10` 枚光点;流水仍复用 `asset_operation_consume` / `asset_operation_refund``asset_kind = match3d_draft_generation`
- 例外:拼图 / 抓大鹅背景音乐生成固定消耗 `5` 枚光点;物品点击音效仍按单个音效任务消耗 `10` 枚光点。
- 例外:拼图 / 抓大鹅 UI 背景重新生成固定消耗 `2` 枚光点。
- 例外:抓大鹅结果页批量新增物品素材按实际可新增物品名计费,每 `5` 个消耗 `2` 枚光点,不足 `5` 个向上按 `5` 个计。重复名称、作品中已有名称和超过容量上限的名称不进入计费数量。
- 图片生成和作品发布都按资产操作计费;余额不足时禁止继续执行。
- 在调用外部图片生成或发布 mutation 前预扣,余额不足时直接返回业务错误,不继续调用后续资产操作。
- 如果图片生成、远程下载、OSS 写入、资产记录确认或发布 mutation 失败,资产操作服务自动发起同额退款。
@@ -38,10 +44,10 @@
## 钱包流水
公开两个流水来源类型,统一覆盖“资产生成”和“资产发布”这两类资产操作:
公开两个流水来源类型,统一覆盖“资产生成”和“资产发布”这两类资产操作。流水金额由具体资产操作成本决定,不再假定所有资产操作都是 `1` 枚光点
- `asset_operation_consume`:资产操作预扣,`amount_delta = -1`
- `asset_operation_refund`:资产操作失败退款,`amount_delta = +1`
- `asset_operation_consume`:资产操作预扣,`amount_delta = -points_cost`
- `asset_operation_refund`:资产操作失败退款,`amount_delta = +points_cost`
`wallet_ledger_id` 由 Axum 传入,格式:

View File

@@ -105,3 +105,18 @@ npm run dev:web
1. 远端 `xushi-p4wfr` 仍需恢复数据库挂起状态,否则对应玩法 procedure 仍不可用。
2. 本地开发如只为体验抓大鹅,可继续使用本地 SpacetimeDB 链路。
3. 认证快照同步失败会影响进程重启后的远端恢复完整性,需要在目标库恢复后重新完成一次成功同步。
## 7. 2026-05-13 补充:服务暂不可用的分层排查
抓大鹅生成页只看到“服务暂不可用”时,不应先回退旧 3D / Rodin 链路,应按 2D 素材生成链路逐层定位:
1. 前端通用 API 错误展示必须读取 `error.details.reason`。VectorEngine、OSS 等配置缺失类错误常把具体原因写在 `details.reason`,如果只读 `details.message`,用户只能看到泛化的“服务暂不可用”。
2. `api-server` 启动不应被 OSS 半配置阻断。`ALIYUN_OSS_BUCKET` / `ALIYUN_OSS_ENDPOINT` 已配置但 `ALIYUN_OSS_ACCESS_KEY_ID` / `ALIYUN_OSS_ACCESS_KEY_SECRET` 缺失时,服务应记录 warning 并跳过 OSS 客户端初始化;需要上传或读取 generated 私有资产的接口继续返回 `OSS 未完成环境变量配置`,并通过 `details.missingEnv` 明确缺少哪几项。
3. 启动阶段从 SpacetimeDB 恢复认证快照只能降级远端恢复能力,不能长期卡住 `/healthz`。本地库未发布、连接后立即 close 或远端库挂起时,`api-server` 应在启动恢复超时后使用本地 `auth_store` 继续进入监听。
4. 抓大鹅真实生成仍依赖两组私密配置:`VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 用于 `gpt-image-2-all` 生成 1K 素材图;完整 `ALIYUN_OSS_*` 四件套用于上传切割后的 `generated-match3d-assets` 五视角图片。缺任一组都应返回明确 `details.reason`;抓大鹅素材、封面和背景生成在调用 VectorEngine 前先预检 OSS不应先消耗生图调用再失败也不应恢复 GLB 生成。
验证时以实际 `GENARRATIVE_API_PORT` 为准;本地 `.env.local` 可能覆盖脚本默认 `3100`。例如当前本地端口为 `8082` 时,应请求:
```powershell
Invoke-WebRequest -UseBasicParsing http://127.0.0.1:8082/healthz
```

View File

@@ -20,7 +20,7 @@
生成页步骤固定为:
```text
生成游戏名称 -> 生成物品名称与背景音乐名称 -> 生成背景提示词 -> 分批生成1K素材图 -> 切割五视角图片 -> 上传图片资产 -> 生成背景音乐 -> 生成背景图 -> 写入草稿页
建立草稿存档 -> 生成作品计划 -> 生成背景提示词 -> 分批生成素材图 -> 切割独立图片 -> 上传图片资产 -> 校验素材结构 -> 生成背景音乐 -> 生成UI背景与容器 -> 写入草稿页
```
生成页只展示题材和物品数量,不展示玩法规则说明。
@@ -34,22 +34,24 @@
`match3d_compile_draft` action 的后端顺序为:
1. 读取 session config。
2. 草稿编译先创建可恢复 profile素材生成数量由入口页难度派生的物品种类决定轻松 `3` 种、标准 `9` 种、进阶 `15` 种、硬核 `21`
3. 先调用 SpacetimeDB compile procedure 写入草稿。首次执行使用新 `profileId`;重试时复用 session draft / work profile 中已有 `profileId`。这一步不能等待 LLM、图片、音频或 OSS 成功后才执行
4. 基于入口页题材设定文本调用文本模型生成作品生成计划。模型固定请求 `gpt-4o`,只返回 JSON其中 `gameName` 为 4 到 12 个中文字符的游戏名称,`tags` 为 3 到 6 个中文短标签;`summary` 首版必须保持空字符串,结果页 `作品描述` 默认留给用户填写。生成计划还必须包含 `backgroundMusic.title``backgroundMusic.style``backgroundMusic.prompt``backgroundPrompt`,以及 `items[]` 中每个物品的 `name``soundPrompt``backgroundMusic.title` 是背景音乐名称,`backgroundMusic.prompt` 固定为空字符串,用于后续 Suno 纯音乐生成;`backgroundPrompt` 用于生成局内竖屏背景图,必须描述绿色纵向背景与居中浅锅/圆盘状竞技区融合为一张完整背景图,且不包含 UI、文字、按钮、倒计时或物品。文本模型不可用时保留第 3 步的本地兜底,不阻断草稿
5. 后端从同一份作品生成计划读取当前难度所需数量的短物品名称和音效提示词;不得再只生成物品名称而丢失后续音效生成上下文
6. 调用项目当前图片链路 VectorEngine `gpt-image-2-all` 生成 `1:1``1024x1024` 素材图,提示词必须合入入口页选择的 `assetStylePrompt`。历史 `nanobanana2` 图片选项当前按项目统一决策回落到 VectorEngine不重新接入 APIMart 图片网关
7. 每个物品固定需要 `5` 个不同视角。单张素材图最多切成 `5*5 = 25` 格;因此单张图最多承载 `5` 个物品。若草稿物品数超过 `5`,后端按每批最多 `5` 个物品自动分批,多张素材图并行生成
8. 将每张素材图按 `n*n` 网格切割成独立图片,并按物品顺序连续分配 `5` 张视角图。每个物品 JSON 写入 `imageViews[]`,同时把第一个视角兼容写入 `imageSrc/imageObjectKey`
9. 将素材图和每张独立视角图片上传到 OSS。每次获得可恢复的图片资产后都要回写 `match3d_work_profile.generated_item_assets_json`。成功素材状态为 `image_ready`;失败素材保留已成功图片引用并记录 `error`。每个素材 JSON 同步保存 `soundPrompt`,首个素材 JSON 同步保存 `backgroundMusicTitle``backgroundMusicStyle``backgroundMusicPrompt` 保存为空字符串作为兼容字段
10. 后端在图片素材生成后使用 `backgroundMusic.title` 提交 Suno 背景音乐任务,`prompt` 为空,`tags` 来自 `backgroundMusic.style`,并固定走纯音乐生成。轮询完成后通过通用创作音频资产链路转存 OSS、确认 `asset_object`、绑定到 `match3d_work/background_music`,再写回首个素材的 `backgroundMusic`。音乐生成失败只记录 warning不阻断草稿页进入用户可在结果页 `素材配置 > 背景音乐` 重试
11. 若入口页 `generateClickSound=true`,后端在图片素材生成后继续为缺少 `clickSound` 的已生成物品并行提交 Vidu 点击音效任务,轮询完成后通过通用创作音频资产链路转存 OSS、确认 `asset_object`、绑定实体并写回对应素材的 `clickSound`;若开关关闭则只保存 `soundPrompt`,不调用音频生成
12. 背景图生成同样由 `api-server` 调用 VectorEngine `gpt-image-2-all`,尺寸固定为 `9:16`,并固定传入 `public/match3d-background-references/pot-fused-reference.png` 作为参考图。参考图只表达抓大鹅绿色页面背景和锅状圆形竞技区的融合构图,不包含 HUD、物品、文字或按钮。生成后的背景图上传到 `generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.png`,并作为 `backgroundAsset` 挂在首个 `generatedItemAssets[]` JSON 上HTTP DTO 同时顶层输出 `backgroundPrompt``backgroundImageSrc``backgroundImageObjectKey``generatedBackgroundAsset`
13. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息、背景音乐资产信息和背景资产信息;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets` 恢复同一批素材、音乐与背景
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 步的本地兜底,不阻断草稿
6. 后端把生成计划中的 `gameName` `summary` 写入 `match3d_work_profile` 作品信息后,自动调用作品标签生成器。标签生成器使用题材、作品名称和作品描述生成 3 到 6 个中文短标签;若调用失败或返回不足,则使用生成计划 tags 和本地兜底标签补齐。结果页手动 `AI生成作品标签` 也使用同一接口,并传入当前作品描述
7. 后端从同一份作品生成计划读取当前难度所需数量的短物品名称和音效提示词;不得再只生成物品名称而丢失后续音效生成上下文
8. 调用项目当前图片链路 VectorEngine `gpt-image-2-all` 生成 `1:1``1024x1024` 素材图,提示词必须合入入口页选择的 `assetStylePrompt`,并强制每格使用统一纯绿色绿幕背景,避免白底或纹理背景进入运行态素材。历史 `nanobanana2` 图片选项当前按项目统一决策回落到 VectorEngine不重新接入 APIMart 图片网关
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`。音乐生成失败只记录 warning不阻断草稿页进入用户可在结果页 `素材配置 > 背景音乐` 重试
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 与封面。
若文本模型不可用或返回无法解析,后端必须降级为 `{themeText}抓大鹅` 与本地标签兜底,不阻断素材生成;但描述仍保持空字符串
若文本模型不可用或返回无法解析,后端必须降级为 `{themeText}抓大鹅`、本地作品描述与本地标签兜底,不阻断素材生成;标签仍通过作品标签生成器优先生成,失败后再用兜底标签补齐
草稿生成阶段不再调用 Hyper3D Rodin不生成 GLB也不等待任何模型轮询。前端 `match3d_compile_draft` action 的长耗时主要来自文本生成、分批 1K 生图、切图、OSS 上传、背景图和可选音频生成。批量新增物品由 `POST /api/creation/match3d/works/{profileId}/item-assets` 复用同一套 2D 素材图生成、5x5 切图、OSS 上传和可选点击音效链路,只补齐本次新增物品并把 `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`
## 4. 图片提示词
@@ -57,15 +59,21 @@
```text
生成一张1:1图片
生成不超过5*5网格素材图
生成严格5*5均匀网格素材图
整体画风遵循:...
只绘制这些物品:...
不要出现文字、水印、UI、边框
每格背景必须是统一纯绿色绿幕背景,方便后续转透明
物品本身不得使用与绿幕相同的纯绿色
每格主体完整居中,禁止跨格、贴边或越界影响裁剪后的效果
相邻物体主体之间至少保留 1/4 单格宽度空白间距,物体主体不得占满格子
不要出现文字、水印、UI、边框、网格线、白色背景、灰色背景、纹理背景
```
`包含若干个物品名称` 在落地中解释为“按生成出的物品名称绘制对应主体”,不要求图片上写出物品名称。这样可以避免文字渲染污染切图和局内 2D 素材表现。
入口页内置 2D 风格参考图通过同一 VectorEngine `gpt-image-2-all` 能力生成,执行命令为 `npm run assets:match3d-style-references -- --live`,保存路径固定为:
内置 `像素复古` 不能只写“复古像素”或“有限色板”。入口页、参考图脚本和后端素材图 prompt 必须使用同一组硬约束:真正复古像素 2D 游戏道具 sprite先按约 `64x64` 低分辨率像素块绘制再整数倍放大,硬边方块像素清晰可见,有限色板 `12-24` 色;同时在负向约束中禁止抗锯齿、柔焦、平滑渐变、真实 3D 渲染、PBR 材质、摄影光照和平滑插画。后端即使只收到 `assetStyleId = pixel-retro``assetStyleLabel = 像素复古`,也必须补齐这组约束,避免旧会话、恢复会话或批量新增物品退回普通插画风格。
入口页内置 2D 风格参考图通过同一 VectorEngine `gpt-image-2-all` 能力生成,执行命令为 `npm run assets:match3d-style-references -- --live`。每张入口参考图只展示 `1` 个完整独立物品,不能展示 `5` 个物品样张或多物品散点图,避免风格选择被误读为物品数量配置。保存路径固定为:
```text
public/match3d-style-references/flat-icon.png
@@ -78,13 +86,13 @@ public/match3d-style-references/painterly-icon.png
这些图片只作为入口页风格选择的视觉参考,不进入用户草稿资产,不替代生成时的物品素材图。
局内背景生成固定参考图路径为:
局内容器 UI 图生成固定参考图路径为:
```text
public/match3d-background-references/pot-fused-reference.png
```
这张图作为 VectorEngine `image` 参考输入使用,用来锁定“绿色竖屏背景 + 居中锅状竞技区”的构图。每次草稿生成仍会根据 `backgroundPrompt` 生成新的题材化背景图;参考图本身不作为运行态最终背景
这张图作为容器 UI 图的 VectorEngine `image` 参考输入,用来锁定“大尺寸轻俯视浅盘容器”的构图。参考图本身是 `1:1` 透明底容器素材,外轮廓接近画布四边,内口为横向椭圆;结果页没有真实生成容器时也只把它作为容器预览兜底,不能再作为 `9:16` 背景预览。每次草稿生成仍会根据 `backgroundPrompt` 生成新的题材化背景图;纯背景图不再传入该参考图,也不得生成锅或 UI 元素
## 5. OSS 路径
@@ -108,7 +116,7 @@ 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`;背景生成成功后首个素材的 `backgroundAsset.status = image_ready`。前端通过 `/api/assets/read-url` 将 generated legacy path 换签后加载私有图片,不直接请求裸 `/generated-match3d-assets/...` 路径。运行态背景图同样通过 `/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`,容器作为中心棋盘覆盖层
## 5.1 运行态 2D 素材消费
@@ -122,17 +130,17 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
运行态按运行快照中的 `itemTypeId` 稳定排序后,把 `generatedItemAssets` 顺序映射到对应类型。加载某个物品实例时,从该类型素材的 `imageViews[]` 中按实例 id 稳定随机选择一个视角;若历史数据没有 `imageViews[]`,则回退到 `imageSrc/imageObjectKey`。没有生成图片或图片加载失败时,继续使用默认积木图标兜底。
运行态背景优先读取 `backgroundImageSrc` / `generatedBackgroundAsset.imageSrc`,为空时从 `generatedItemAssets[].backgroundAsset.imageSrc/imageObjectKey` 兜底。`Match3DRuntimeShell` 只保留顶部返回、倒计时、重开三个控件;进度、组数、版本等状态信息不得再作为顶部常驻 UI 出现,避免遮挡生成背景和锅状竞技区
运行态背景优先读取 `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 出现,避免遮挡生成背景和中心容器
前端加载规则:
1. 优先读取 `imageViews[]` 中的 `imageSrc/imageObjectKey`,为空时使用兼容字段 `imageSrc/imageObjectKey`
2. 对 generated legacy path 通过同源 `/api/assets/read-url` 换签后交给浏览器图片加载。
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` 补齐 draft不能让旧 draft 把素材覆盖成空列表。`PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成图片素材写入 `match3dProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 2D 素材覆盖成空列表。
结果页点击 `试玩` 时,前端必须把当前结果页可见的 `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 覆盖成空列表。
历史草稿若仍保存 `status = model_ready``modelSrc``modelObjectKey`,仅作为旧版本兼容读取,不再参与新素材生产。历史外部模型链接转存接口只用于清理旧数据,不能被新草稿生成、批量新增或结果页普通编辑入口调用。
@@ -160,11 +168,11 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
结果页 `作品信息` Tab 字段命名对齐拼图草稿:
1. `作品名称` 对应 Match3D `gameName`
2. `作品描述` 对应 Match3D `summary`,草稿生成默认空
3. `作品标签` 对应 Match3D `tags`可由 AI 首次生成并允许用户继续编辑
4. 封面图与作品名称不再拆成左右两个大模块;封面只作为同一 Tab 内的可选入口,避免和作品基础信息割裂。点击封面图必须弹出独立编辑面板,不允许在当前作品信息面板下方展开。封面面板布局参考拼图创作页上传卡:移动端优先、左侧/上方为方形预览,右侧/下方为提示词与操作区。面板支持三类输入:本地上传图片、上传后开启 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 写入封面字段。
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 取代旧 `玩法配置`,不再展示旧的分散输入项。该 Tab 顶部使用横向离散拖动条调整难度,四个刻度分别为 `轻松 / 标准 / 进阶 / 硬核`;拖动条只能落在这四个点上,刻度标签可点击切换。该 Tab 必须与创作入口页使用同一组难度选项,并统一把原“类型素材图片 / 局内类型”等口径归一为 `物品种类`
| 难度 | clearCount | difficulty | 总物品数 | 物品种类 |
| ---- | ---------: | ---------: | -------: | -------: |
@@ -178,7 +186,7 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
结果页 `素材配置` Tab 取代旧一级素材入口,并包含三个子 Tab
1. `物品`:显示 2D 物品素材列表、五视角预览、素材名称、点击音效提示词和点击音效生成入口。
2. `UI`:预览生成的竖屏游戏背景图读取顺序为 draft 顶层背景、draft `generatedBackgroundAsset`、profile 顶层背景、profile `generatedBackgroundAsset``generatedItemAssets[].backgroundAsset`、本地参考图兜底。该页必须展示默认画面描述提示词,默认值来自草稿生成计划的 `backgroundPrompt` 或持久化 `backgroundAsset.prompt`;用户修改后点击重新生成,后端继续固定使用 `public/match3d-background-references/pot-fused-reference.png` 作为 VectorEngine `image` 参考图,并把新的 `backgroundAsset` 写回同一份 `generated_item_assets_json`。UI 子 Tab 还必须提供独立的运行态 UI 预览面板,直接用当前背景图模拟抓大鹅竖屏页面的顶部返回倒计时重开控件、锅状竞技区和底部托盘,不在 Tab 下方内联展开。
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 的背景音乐曲名、风格、生成进度和试听控件;背景音乐始终按纯音乐生成,前端不提供提示词输入。
旧一级 `音乐` Tab 删除;抓大鹅背景音乐入口只保留在 `素材配置 > 背景音乐`
@@ -192,7 +200,7 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
详情页不再展示参考图、用途、模型提示词、文生/图生切换、状态查询、下载列表、taskUuid 或 subscriptionKey。
`物品素材` 列表项点击必须弹出独立预览面板,不允许在列表右侧或列表下方内联展示。预览面板只承担查看五视角图片、编辑素材名称、编辑点击音效提示词和生成点击音效;不再展示 `重新生成` 按钮。列表项自身支持单项删除,删除后立即把剩余 `generatedItemAssets` 写回作品 profile。批量新增通过列表顶部按钮打开独立面板面板内每个输入框只输入一个物品名称`新增物品名称` 按钮追加一个输入框;提交后按输入框顺序清洗、去重并调用 Match3D 作品批量生图接口。生成进度同时显示在批量新增面板和 `素材配置 > 物品` 列表顶部面板可关闭后台生成继续推进不阻塞封面、音频等其他生成操作。后端复用草稿生成的素材图、切图、OSS 上传和可选点击音效流程,但仅作用于本次新增名称,不重新生成已有物品,不新增 SpacetimeDB 表,最终仍写回同一份 `generated_item_assets_json`
`物品素材` 列表项点击必须弹出独立预览面板,不允许在列表右侧或列表下方内联展示。列表本身使用移动端至少两列的多列卡片布局;每个列表项只展示图片预览、物品名称和垃圾箱删除图标,不展示用途、状态胶囊、视角数量或 `2D素材` 标记。预览面板只承担查看五视角图片、编辑素材名称、编辑点击音效提示词和生成点击音效;不再展示 `重新生成` 按钮。列表项自身支持单项删除,删除后立即把剩余 `generatedItemAssets` 写回作品 profile。批量新增通过列表顶部按钮打开独立面板面板内每个输入框只输入一个物品名称`新增物品名称` 按钮追加一个输入框;提交后按输入框顺序清洗、去重并调用 Match3D 作品批量生图接口。生成进度同时显示在批量新增面板和 `素材配置 > 物品` 列表顶部面板可关闭后台生成继续推进不阻塞封面、音频等其他生成操作。后端复用草稿生成的素材图、切图、OSS 上传和可选点击音效流程,但仅按实际可新增名称持久化,不重新生成已有物品,不新增 SpacetimeDB 表,最终仍写回同一份 `generated_item_assets_json`批量新增先补齐到 `5` 个参与整图生成,随后丢弃补齐用临时物品,只对真实新增物品抠背景、切割和上传。批量新增计费按实际可新增名称每 `5` 个消耗 `2` 光点,不足 `5` 个向上取整;重复名称、已有名称和超过容量上限的名称不计费。
## 6.1 音频生成与扣费
@@ -202,9 +210,9 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
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 + 资产槽位` 幂等预扣 `10` 光点任务仍在处理中时不扣费。资产下载、OSS 转存或资产绑定失败时后端自动退款。前端只展示生成按钮和进度,不自行计算或写入钱包。
5. `POST /api/creation/audio/background-music/{task_id}/asset``POST /api/creation/audio/sound-effect/{task_id}/asset` 在真正拿到音频并转存资产前,由后端按 `taskId + 资产槽位` 幂等预扣;背景音乐扣 `5` 光点,物品点击音效扣 `10` 光点任务仍在处理中时不扣费。资产下载、OSS 转存或资产绑定失败时后端自动退款。前端只展示生成按钮和进度,不自行计算或写入钱包。
入口页 `生成音效` Toggle 复用同一扣费与资产绑定规则。默认关闭,关闭时草稿生成阶段不产生音频任务也不扣除音频光点;开启时每个首批物品点击音效按单独任务和单独 `match3d_click_sound` 资产槽位扣费。音效生成失败不阻断草稿结果页进入,失败素材保留 `soundPrompt`,用户可在结果页物品详情面板手动重试。
创作入口不展示 `生成音效` Toggle草稿生成阶段不产生物品点击音效任务也不产生点击音效相关扣费;入口只产生一次固定 `10` 光点的草稿生成扣费。结果页 `素材配置 > UI` 重新生成背景固定扣 `2` 光点。物品点击音效由结果页 `素材配置 > 物品` 详情面板手动触发,每个音效按单独任务和单独 `match3d_click_sound` 资产槽位扣费。音效生成失败不影响草稿,失败素材保留 `soundPrompt`,用户可在结果页物品详情面板手动重试。
## 7. 验收
@@ -226,4 +234,4 @@ cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
cargo check -p spacetime-module --manifest-path server-rs\Cargo.toml
```
真实草稿生成需要本地私密环境配置 `VECTOR_ENGINE_API_KEY` 和 OSS 访问变量;开启音频生成还需要对应音频上游配置。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`
真实草稿生成需要本地私密环境配置 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY`,以及完整 `ALIYUN_OSS_BUCKET``ALIYUN_OSS_ENDPOINT``ALIYUN_OSS_ACCESS_KEY_ID``ALIYUN_OSS_ACCESS_KEY_SECRET`。如果只配置 bucket 和 endpoint抓大鹅素材、封面或背景生成会在调用 VectorEngine 前返回 `OSS 未完成环境变量配置``details.missingEnv` 会列出缺少的 AccessKey 项;不要回退到 Rodin/GLB 或伪造本地上传成功。开启音频生成还需要对应音频上游配置。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`

View File

@@ -2,9 +2,13 @@
> 2026-05-08 更新:抓大鹅创作端入口已重新开放,当前 `match3d.visible` 为 `true`。本文件记录 F1 接入能力,入口是否展示以 `NEW_WORK_ENTRY_CONFIG_2026-05-01.md` 和 `src/config/newWorkEntryConfig.ts` 为准。
>
> 2026-05-10 更新:抓大鹅入口页对齐拼图入口页,直接嵌入创作页模板 Tab。入口表单不再展示参考图、消除次数输入、难度数值滑杆和题材/物品/难度摘要框,仅保留题材主题大输入框和难度选项。难度选项负责派生 `clearCount` 与 `difficulty`,生成按钮必须展示 `消耗20光点`
> 2026-05-10 更新:抓大鹅入口页对齐拼图入口页,直接嵌入创作页模板 Tab。入口表单不再展示参考图、消除次数输入、难度数值滑杆和题材/物品/难度摘要框,仅保留题材主题大输入框和难度选项。难度选项负责派生 `clearCount` 与 `difficulty`。
>
> 2026-05-12 补充:入口页风格选择收敛为 `2D素材风格`,首批常见 2D 素材风格参考图通过 `npm run assets:match3d-style-references -- --live` 调用 VectorEngine `gpt-image-2-all` 生成并保存到 `public/match3d-style-references/`。最后一个选项为 `自定义`,点击后弹出独立面板填写画风描述。
> 2026-05-12 补充:入口页风格选择收敛为 `2D素材风格`,首批常见 2D 素材风格参考图通过 `npm run assets:match3d-style-references -- --live` 调用 VectorEngine `gpt-image-2-all` 生成并保存到 `public/match3d-style-references/`。2026-05-13 起,入口参考图固定只展示 `1` 个完整独立物品,不再展示 `5` 个物品样张或多物品散点图。最后一个选项为 `自定义`,点击后弹出独立面板填写画风描述。
>
> 2026-05-13 补充:草稿素材实际生成数量按 `5` 的倍数向上补齐,补齐物品同样需要生成名称和五视角图片。素材图提示词固定要求 `5*5` 严格均匀排布,禁止主体跨格、贴边或越界影响裁剪效果。
>
> 2026-05-13 补充:创作页隐藏抓大鹅 `生成音效` Toggle草稿生成固定预扣 `10` 光点,按钮展示 `消耗10光点`。点击音效生成只保留在结果页 `素材配置 > 物品` 详情面板中手动触发。
## 1. 阶段边界
@@ -40,12 +44,11 @@ badge: 可创建
创作页 `选择模板` Tab 中切换到 `抓大鹅` 时,直接渲染该表单,不创建会话,也不跳到独立工作台。点击生成后才创建 Match3D 会话并执行 `match3d_compile_draft`
表单只展示个输入块:
表单只展示个输入块:
1. `想做一个什么题材的抓大鹅?`:大文本输入框,收集 `themeText`
2. `2D素材风格`:横向滑动风格卡,选择会写入 `assetStyleId``assetStyleLabel``assetStylePrompt`
3. `难度`:四个选项按钮,选项内部派生消除次数和难度数值。
4. `生成音效`Toggle默认关闭开启后提交 `generateClickSound=true`
当前难度映射固定为:
@@ -66,7 +69,7 @@ badge: 可创建
自定义风格必须在弹出面板中填写描述后才能应用。入口表单必须在移动端创作页可视区内完成题材、风格、难度和生成按钮的展示,页面自身不产生纵向滚动;风格卡只允许横向滑动。
生成按钮文案为 `生成抓大鹅草稿`,按钮内必须同时展示 `消耗20光点`。UI 中不默认展示玩法规则长文,也不展示隐藏派生数值的摘要框。
生成按钮文案为 `生成抓大鹅草稿`,按钮内必须同时展示 `消耗10光点`。UI 中不默认展示玩法规则长文,也不展示隐藏派生数值的摘要框。
## 5. mock client
@@ -112,7 +115,7 @@ POST /api/creation/match3d/sessions/:sessionId/compile
2. 切换到 `抓大鹅` Tab 后,页面内直接显示抓大鹅入口表单,不提前创建会话。
3. 表单不展示参考图、`需要消除次数``难度数值``题材``物品``难度`摘要框。
4. 输入题材、选择风格和难度后,提交 payload 包含派生后的 `clearCount``difficulty``referenceImageSrc``null`,并包含 `assetStyleId``assetStyleLabel``assetStylePrompt`
5. 生成按钮展示 `消耗20光点`
5. 生成按钮展示 `消耗10光点`,创作页不展示 `生成音效` Toggle
6. 点击 `自定义` 风格弹出独立面板,填写后应用到提交 payload未填写时不能应用空自定义风格。
7. 移动端创作页内抓大鹅入口内容不产生纵向滚动,风格卡横向滑动。
8. 点击生成后创建会话并进入草稿生成/结果页链路。

View File

@@ -18,7 +18,7 @@
1. 入口表单只展示 `画面描述`、参考图和图片模型选择;`画面描述` 是唯一必填字段。
2. 表单自动保存只保存 `pictureDescription`,不再保存入口作品名称、作品描述或推断标签。
3. 点击“生成草稿”后进入生成进度页,步骤固定“编译首关草稿 -> 生成首关画面 -> 写入正式草稿”
3. 点击“生成草稿”后进入生成进度页,步骤固定对齐后端当前编排:“编译首关草稿 -> 生成关卡名称 / 生成首关画面 -> 生成背景音乐 / 生成UI背景 -> 写入正式草稿”。其中关卡名称文本生成与首关画面生成可并行;首关最终名称确定后,背景音乐与 UI 背景必须并行启动
4. 生成进度页“当前拼图信息”只展示画面描述;不得展示空作品名称、空作品描述或旧五锚点结构。
5. 结果页打开后,作品名称默认使用首关名称,作品描述与作品标签保持为空,等待用户在作品信息 Tab 补全或触发 AI 标签生成。
@@ -90,24 +90,30 @@
12. `compile_puzzle_draft` 中的图片上游失败不得映射成 `400 BAD_REQUEST`。DashScope 返回 `InvalidParameter` 或任务失败时api-server 统一按 `502 UPSTREAM_ERROR` 暴露,并在 `details.message` 中保留“拼图图片生成失败:...”的业务原因,避免生成页只显示“请求参数不合法”。
13. `compile_puzzle_draft` 前置光点预扣失败不得映射成 `400 BAD_REQUEST`。余额不足返回 `409 CONFLICT`SpacetimeDB procedure 不可用、绑定不匹配、钱包服务异常等统一按 `502 UPSTREAM_ERROR` 暴露,并在 `details.message` 中保留真实钱包错误。
14. 生成拼图作品草稿动作涉及的表单 seed prompt 与首图 prompt 来源选择统一收口在 `server-rs/crates/api-server/src/prompt/puzzle/draft.rs``puzzle.rs` 只负责调用 SpacetimeDB、计费、图片服务和持久化不再直接拼草稿 prompt 文本。
15. `compile_puzzle_draft_with_initial_cover` 中,首关文本名称生成与首关图片生成互不等待:首图 prompt 只读取画面描述OSS 临时路径使用现有关卡名或确定性兜底名;首图返回后再用图片语义尝试精修最终关卡名。最终关卡名确定后,背景音乐与首关 UI 背景图通过 `tokio::join!` 并行生成,任一失败只记录 warning 并保留草稿。
16. `compile_puzzle_draft_with_uploaded_cover` 中,上传图解析后,文本名称生成、图片语义名称生成和上传图转存 OSS 可并行;上传图转存失败必须立即返回,不得继续触发背景音乐或 UI 背景生成。上传图转存成功且最终关卡名确定后,背景音乐与首关 UI 背景图同样并行生成。
## 结果页
拼图草稿结果页分为四个 Tab
拼图草稿结果页分为三个一级 Tab
1. 拼图关卡列表:默认展示草稿生成出的第一关。列表项参考 RPG 草稿卡片样式,显示画面图、关卡名称和轻量状态。支持新增关卡、删除关卡。点击列表项进入独立关卡详情页,不在列表项下方展开。关卡详情页可编辑关卡名称、画面描述、生成或重新生成画面,并在已有正式图后支持关卡测试。
2. 作品信息:展示并编辑作品名称、作品描述、作品标签。
3. UI展示并编辑拼图运行态 UI 背景提示词。`compile_puzzle_draft` 草稿编译完成首图和背景音乐后,`api-server` 会基于作品名称、作品描述、标签和首关信息自动生成首关 9:16 UI 背景图;结果页继续支持用户修改提示词并通过 `generate_puzzle_ui_background` 重新生成。图片生成在 `api-server` 中读取 `public/ui-previews/puzzle-image-compact-ui-2026-05-08.png` 作为非拼图 UI 背景参考图,并调用 VectorEngine `gpt-image-2-all``9:16` 图片生成链路。生成结果写入首关 `levels_json``uiBackgroundPrompt``uiBackgroundImageSrc``uiBackgroundImageObjectKey`,不新增 SpacetimeDB 表字段
4. 音乐:编辑并生成背景音乐,音乐资产暂存到首关 `levels_json[0].backgroundMusic`
3. 素材配置:对齐抓大鹅草稿页结构,内部包含 `UI``背景音乐` 子 Tab
`素材配置 > UI` 展示并编辑拼图运行态 UI 背景提示词。`compile_puzzle_draft` 草稿编译完成首图和背景音乐后,`api-server` 会基于作品名称、作品描述、标签和首关信息自动生成首关 9:16 纯背景图;结果页继续支持用户修改提示词并通过 `generate_puzzle_ui_background` 重新生成。图片生成调用 VectorEngine `gpt-image-2-all``9:16` 图片生成链路。生成结果写入首关 `levels_json``uiBackgroundPrompt``uiBackgroundImageSrc``uiBackgroundImageObjectKey`,不新增 SpacetimeDB 表字段。
`素材配置 > 背景音乐` 编辑并生成背景音乐,音乐资产暂存到首关 `levels_json[0].backgroundMusic`。拼图结果页不再保留一级 `UI` 或一级 `音乐` Tab。
### 2026-05-12 UI 背景生成补充
1. UI 背景图只生成拼图棋盘以外的运行态背景与 UI 容器层次,提示词必须要求中央正方形拼图区和外部 UI 背景之间有明确描边、容器或留白边界
2. UI 背景图不得生成文字、水印、按钮文字、数字、拼图碎片、完整拼图图像教程浮层,避免与真实拼图图块和运行态 HUD 混淆。
1. UI 背景图只生成拼图运行态的题材氛围纯背景不得把拼图槽、棋盘外框、按钮、HUD 或其它 UI 元素烘进图片。拼图槽位、棋盘边框和空格继续使用运行态默认样式绘制
2. UI 背景图不得生成文字、水印、按钮文字、数字、拼图碎片、完整拼图图像教程浮层、拼图槽或物品槽,避免与真实拼图图块和运行态 HUD 混淆。
3. 结果页 UI Tab 支持直接修改提示词并重新生成;点击生成前会把本地首关 `uiBackgroundPrompt` 同步进 `levelsJson`,使自动保存尚未完成时后端仍能拿到最新提示词。
4. 草稿编译阶段自动生成 UI 背景失败时只记录 warning并保留草稿进入结果页用户可在 UI Tab 重新生成,不因背景图上游波动阻断首图草稿主流程。
5. `api-server` 负责读取参考图、拼接生成 prompt、调用 VectorEngine、下载并转存 OSSSpacetimeDB 只通过 `save_puzzle_ui_background` procedure 保存结果,不做外部 I/O。
5. `api-server` 负责拼接生成 prompt、调用 VectorEngine、下载并转存 OSSSpacetimeDB 只通过 `save_puzzle_ui_background` procedure 保存结果,不做外部 I/O。
6. 拼图运行态读取 `currentLevel.uiBackgroundImageSrc` 渲染为全屏背景;无 UI 背景图时继续使用原封面模糊背景兜底。棋盘本身仍由正式拼图图生成,不能把 UI 背景当作拼图切块来源。
7. 生成完成后的自动试玩和结果页“试玩”走前端本地运行态兜底时,`startLocalPuzzleRun` 也必须从 `PuzzleWorkSummary.levels[]` 复制 `uiBackgroundImageSrc``backgroundMusic``currentLevel`;不得只带 `coverImageSrc`,否则草稿结果页有背景但试玩局内空白。
### 2026-05-12 草稿生成完成自动试玩补充
@@ -152,7 +158,7 @@
1. 从拼图创作入口只能看到作品名称、作品描述、画面描述和参考图上传,不出现 Agent 聊天输入、补齐设定、锚点问答。
2. 点击确认后进入拼图草稿生成进度页,并自动完成草稿编译、首图生成、正式图选择、背景音乐生成和首关 UI 背景图生成。
3. 首图生成请求使用玩家画面描述作为 prompt上传参考图时走图生图作品详情页展示玩家作品描述。
4. 结果页包含“拼图关卡”“作品信息”“UI”“音乐”四个 Tab关卡列表默认至少一关,支持新增、删除和进入关卡详情。
4. 结果页包含“拼图关卡”“作品信息”“素材配置”三个一级 Tab`素材配置` 内包含 `UI``背景音乐` Tab关卡列表默认至少一关,支持新增、删除和进入关卡详情。
5. 关卡详情页支持生成或重新生成画面;已有正式图后显示吸底“关卡测试”入口。
6. 发布、作品测试、自动保存作品名称、作品描述、作品标签和关卡列表仍可用。
7. 草稿初次生成后首关默认带 `uiBackgroundImageSrc`UI Tab 可修改提示词并重新生成背景图;生成后运行态应显示 `uiBackgroundImageSrc`拼图棋盘区域和 UI 背景区域有明确边界
7. 草稿初次生成后首关默认带 `uiBackgroundImageSrc`UI Tab 可修改提示词并重新生成背景图;生成后运行态应显示 `uiBackgroundImageSrc`,拼图槽位和棋盘边界仍由默认运行态样式绘制

View File

@@ -4,9 +4,9 @@
本方案把 VectorEngine 音频生成能力从视觉小说结果页扩展到拼图与抓大鹅结果页:
1. 拼图结果页新增 `音乐` Tab支持通过 Suno 生成作品背景音乐。
1. 拼图结果页 `素材配置 > 背景音乐` 支持通过 Suno 生成作品背景音乐;旧一级 `音乐` Tab 已删除
2. 抓大鹅结果页在 `素材配置 > 背景音乐` 中支持通过 Suno 生成作品背景音乐;旧一级 `音乐` Tab 已删除。
3. 抓大鹅 `素材配置 > 物品` 支持为每个生成物体通过 Vidu 生成点击音效。
3. 抓大鹅 `素材配置 > 物品` 支持为每个生成物体通过 Vidu 手动生成点击音效;创作入口不展示点击音效生成开关
4. 拼图运行态与抓大鹅运行态内置默认关卡音频配置:通用点击音效 `/audio/ui-click-soft.wav`、过关音效 `/audio/ui-level-clear.wav`、倒计时临界音效 `/audio/ui-countdown-warning.wav`
5. 拼图和抓大鹅草稿生成阶段会自动生成背景音乐并转存 OSS结果页继续支持试听和重新生成。
@@ -30,7 +30,7 @@
3. 下载音频字节。
4. 写入 OSS 私有对象。
5. 确认 `asset_object` 并绑定 `asset_entity_binding`
6. 音频真正可下载并准备转存时,按 `taskId + assetKind + entityId + slot` 幂等扣除 `10` 光点任务仍在处理中不扣费,转存或资产绑定失败自动退款。
6. 音频真正可下载并准备转存时,按 `taskId + assetKind + entityId + slot` 幂等扣费;背景音乐固定扣除 `5` 光点,物品点击音效固定扣`10` 光点任务仍在处理中不扣费,转存或资产绑定失败自动退款。
通用背景音乐提交允许 `prompt = ""`。拼图和抓大鹅草稿生成都按纯音乐处理:后端提交 Suno 时固定带 `make_instrumental = true`,只用 `title``tags` 约束作品气质,不把歌词或规则描述写入 prompt。视觉小说原路由保持兼容内部继续复用同一套提交、轮询、转存逻辑。
@@ -68,12 +68,12 @@
结果页 UI 保持轻量:
1. `音乐` Tab 只展示必要输入、生成按钮、状态与音频预览,不展示供应商规则说明。
1. 拼图 `素材配置 > 背景音乐` 与抓大鹅 `素材配置 > 背景音乐` 只展示必要输入、生成按钮、状态与音频预览,不展示供应商规则说明。
2. 生成完成后立即写回本地草稿状态,并触发既有保存链路或专用保存接口。
3. 抓大鹅每个物体音效生成入口放在对应素材详情面板内,不在列表下方展开大段配置。
4. 抓大鹅物体音效提示词允许在素材详情面板内编辑;背景音乐只允许在 `素材配置 > 背景音乐` 编辑曲名和风格,生成请求固定使用空 `prompt`
5. 背景音乐和物体音效生成期间都显示进度条,生成完成后展示 audio 控件试听。
6. 背景音乐重新生成只要求曲名非空;重新生成继续按纯音乐提交,`prompt = ""`
6. 背景音乐重新生成只要求曲名非空;重新生成继续按纯音乐提交,`prompt = ""`,按钮展示 `5` 光点成本
### 4.1 运行态默认点击音效
@@ -85,6 +85,15 @@
6. 默认关卡音效跟随现有 `musicVolume` 设置,不新增独立音量 UI不在运行态界面增加说明文案。
7. 拼图和抓大鹅运行态背景音乐同样跟随 `musicVolume`,读取 generated legacy path 时先换签,再交给隐藏 `<audio loop preload="auto">` 自动播放;浏览器拒绝自动播放时静默失败,不阻断游戏交互。
### 4.2 草稿音乐试听与自动播放补充
2026-05-13 修正:
1. 拼图 `素材配置 > 背景音乐` 的试听控件也必须通过 `useResolvedAssetReadUrl` 对 generated legacy path 换签后再设置 `<audio src>`;签名未就绪或失败时只显示“音频已绑定”,不得把裸 `/generated-puzzle-assets/...` 路径交给浏览器请求。
2. 抓大鹅结果页已使用同一换签口径,后续新增音频试听入口必须复用该模式。
3. 拼图和抓大鹅运行态在开局时会尝试自动播放背景音乐;若浏览器因自动播放策略拒绝,玩家首次按下拼图块或点击抓大鹅物品时必须再次调用同一个背景音乐播放函数,避免草稿音乐已经传入运行态但局内始终无声。
4. 播放失败仍只做静默兜底,不弹出规则说明或阻断局内交互。
## 5. 验收
建议执行:

View File

@@ -14,22 +14,25 @@
## 生成进度步骤
1. `compile` 展示为“编译首关草稿”:根据画面描述生成首关名称和结果页草稿,不在本步骤生成作品标签。
2. `puzzle-images` 展示为“生成首关画面”:按画面描述、参考图和当前图片模型生成第一张拼图图
3. `puzzle-select-image` 展示为“写入正式草稿”:把首图设为第一关正式图,并同步到结果页草稿
4. `ready` 文案提示进入结果页补作品信息;不得暗示作品名称、作品描述或作品标签已经完整生成
1. `compile` 展示为“编译首关草稿”:建立结果页草稿,不在本步骤生成作品标签。
2. `puzzle-level-name` 展示为“生成关卡名称”:按画面描述生成文本名,首图返回后可再基于图像语义精修最终关卡名
3. `puzzle-images` 展示为“生成首关画面”:按画面描述、参考图和当前图片模型生成第一张拼图图;后端允许该步骤与 `puzzle-level-name` 文本名生成并行
4. `puzzle-background-music` 展示为“生成背景音乐”:最终关卡名确定后生成纯音乐并转存音频资产
5. `puzzle-ui-background` 展示为“生成UI背景”最终关卡名确定后生成 9:16 纯背景图;后端必须与背景音乐并行启动。
6. `puzzle-select-image` 展示为“写入正式草稿”:把首图、最终关卡名、可用音乐和可用 UI 背景同步到结果页草稿。
7. `ready` 文案提示进入结果页补作品信息;不得暗示作品名称、作品描述或作品标签已经完整生成。
### 2026-05-08 进度页预计等待与步骤动效补充
1. 拼图草稿生成进度页预计等待时间固定按 `60` 秒展示和倒计时,后端真实完成后立即进入结果页,不强制等满 60 秒。
2. 60 秒进度拆成三段:`compile` 约 12 秒,`puzzle-images` 约 42 秒,`puzzle-select-image` 约 6 秒
2. 前端进度按本地时间展示为多段估算;后端真实编排中,首关名称文本生成与首关画面生成可并行,背景音乐与 UI 背景在最终关卡名确定后并行生成。进度条只是等待接口返回时的体验估算,不作为后端任务调度依据
3. 生成中即使后端 `compile_puzzle_draft` 仍是一次同步 action前端也必须按本地计时推进总进度和当前步骤进度避免页面停在静态等待态。
4. 每个步骤卡片都展示独立进度条;已完成步骤显示 100%,当前步骤按该段预计时长推进,后续步骤保留 0% 待处理状态。
5. 后端未返回前总进度最多推进到 98%,防止 UI 提前宣称生成完成;只有 action 成功并写回 `ready` 后才显示 100%。
## 草稿默认值
1. 后端先由 `module-puzzle` 生成可回滚的确定性草稿,再由 `api-server` 生成第一关关卡名。图片生成前可先基于画面描述生成临时关卡名;正式图片生成完成后,必须使用 APIMart Chat Completions 的 `gpt-4o-mini`,把正式图片 data URL 与画面描述一起传入模型,生成最终关卡名。
1. 后端先由 `module-puzzle` 生成可回滚的确定性草稿,再由 `api-server` 生成第一关关卡名。图片生成不等待文本关卡名,首图 OSS 临时路径使用现有关卡名或基于画面描述的确定性兜底名;正式图片生成完成后,必须使用 APIMart Chat Completions 的 `gpt-4o-mini`,把正式图片 data URL 与画面描述一起传入模型,生成最终关卡名。
2. 最终关卡名生成后,必须写回首关 `levelName`,并在入口直创默认场景下作为 `workTitle` 同步写入草稿和作品草稿卡;模型不可用、图片压缩失败或返回非法时,才保留前一步文本名或确定性兜底名。
3. `workDescription` 默认保持空字符串,不再回退为画面描述。
4. `themeTags` 默认保持空数组,不再由入口画面描述自动推断为正式作品标签。

View File

@@ -124,6 +124,8 @@ VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS=180000
1. `拼图参考图解析完成` / `拼图参考图解析跳过`:确认前端是否传入参考图,以及 Data URL 解析或旧 `/generated-*` OSS 读取耗时;日志只记录 `reference_mime``reference_bytes`,不记录图片内容。
2. `拼图 VectorEngine 图片生成 HTTP 返回`VectorEngine `POST /v1/images/generations` 的同步上游耗时,若这一段长,慢点在 VectorEngine 生图接口。
3. `拼图 VectorEngine 图片下载完成`:从 VectorEngine 返回的 `data[].url` 下载正式图耗时
4. `拼图生成图片已写入 OSS 与资产索引`:正式图上传 OSS、确认资产对象与实体绑定耗时
5. `拼图图片候选生成完成`:整段候选图生成总耗时。
3. `拼图 VectorEngine 图片编辑 HTTP 返回`:有参考图且 AI 重绘时命中 `POST /v1/images/edits`。如果前端报 `创建拼图 VectorEngine 图片编辑任务失败error sending request for url (...)` 且没有这条日志,说明请求在拿到 HTTP 响应前失败,先看响应 `details.reason/source/connect/body/timeout`,再查服务器 DNS、防火墙、代理或上游 multipart 连接中断
4. `拼图 VectorEngine 请求发送失败``reqwest``send()` 阶段失败时输出,包含 `connect``body``timeout` 和底层 `source`。拼图图片客户端强制 HTTP/1.1,以避开部分网关对 HTTP/2 multipart 的兼容问题
5. `拼图 VectorEngine 图片下载完成`:从 VectorEngine 返回的 `data[].url` 下载正式图耗时。
6. `拼图生成图片已写入 OSS 与资产索引`:正式图上传 OSS、确认资产对象与实体绑定耗时。
7. `拼图图片候选生成完成`:整段候选图生成总耗时。