Merge remote-tracking branch 'origin/master' into opt/design_agent
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m18s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m22s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m24s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m45s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m39s
Project CI / Repository checks (pull_request) Failing after 19s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m1s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m10s
Project CI / Frontend tests (pull_request) Successful in 4m50s
Project CI / Native shell tests (pull_request) Successful in 7m19s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m18s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m22s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m24s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m45s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m39s
Project CI / Repository checks (pull_request) Failing after 19s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m1s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m10s
Project CI / Frontend tests (pull_request) Successful in 4m50s
Project CI / Native shell tests (pull_request) Successful in 7m19s
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
## 1. 一句话
|
||||
|
||||
功能画布 = 资源栏目页;栏目页左下角渲染一条由栏目 `category` 决定的工具栏,图片类入口走本地 `generate_local_project_asset`,音频入口复用既有无源生成链路,上传复用 `upload_local_asset`;生成 / 上传成功后一律走既有 manifest 刷新与资源定位。
|
||||
功能画布 = 资源栏目页;栏目页左下角渲染一条由栏目 `category` 决定的工具栏,图片类入口走本地 `start_local_project_asset_generation`(提交即返回、后台生成),音频入口复用既有无源生成链路,上传复用 `upload_local_asset`;生成 / 上传成功后一律走既有 manifest 刷新与资源定位。
|
||||
|
||||
## 2. 入口矩阵(事实源)
|
||||
|
||||
@@ -31,20 +31,26 @@
|
||||
|
||||
## 4. 请求载荷映射
|
||||
|
||||
| 入口 | IPC | 载荷要点 |
|
||||
| --------------------- | ------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| 生成图片 | `generate_local_project_asset` | `kind: 'image'`,比例 / 尺寸可调,默认 `1:1 · 1K` |
|
||||
| 生成角色形象 | 同上 | `kind: 'character'`,默认 `1:1 · 1K` |
|
||||
| 生成规范 → 图标规范 | 同上 | `kind: 'icon-spec'`,固定 `1:1 · 1K`;缺权威规范图时 `outputPath: 'assets/art-spec.png'` |
|
||||
| 生成规范 → 角色规范 | 同上 | `kind: 'spec'`,固定 `1:1 · 1K` |
|
||||
| 生成规范 → 自定义规范 | 同上 | `kind: 'spec'`,固定 `1:1 · 1K` |
|
||||
| 生成图标素材 | 同上 | `kind: 'art-spritesheet'`,默认 `1:1 · 1K`;前置:已登记 `assets/art-spec.png` |
|
||||
| 生成 UI 设计图 | 同上 | `kind: 'ui-prototype'`,默认 `16:9 · 1K`;前置同上 |
|
||||
| 生成背景音乐 | `derive_local_project_resource` | `editKind: 'background-music'`、`generationMode: 'create'`、`sourceMediaType: 'audio/mpeg'` |
|
||||
| 生成音效 | `derive_local_project_resource` | `editKind: 'sound-effect'`、其余同上 |
|
||||
| 上传 | `upload_local_asset` | `{ projectPath, fileName, mediaType, bytes }` |
|
||||
| 入口 | IPC | 载荷要点 |
|
||||
| --------------------- | --------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| 生成图片 | `start_local_project_asset_generation` | `kind: 'image'`,比例 / 尺寸可调,默认 `1:1 · 1K` |
|
||||
| 生成角色形象 | 同上 | `kind: 'character'`,默认 `1:1 · 1K` |
|
||||
| 生成规范 → 图标规范 | 同上 | `kind: 'icon-spec'`,固定 `1:1 · 1K`;缺权威规范图时 `outputPath: 'assets/art-spec.png'` |
|
||||
| 生成规范 → 角色规范 | 同上 | `kind: 'spec'`,固定 `1:1 · 1K` |
|
||||
| 生成规范 → 自定义规范 | 同上 | `kind: 'spec'`,固定 `1:1 · 1K` |
|
||||
| 生成图标素材 | 同上 | `kind: 'art-spritesheet'`,默认 `1:1 · 1K`;前置:已登记 `assets/art-spec.png` |
|
||||
| 生成 UI 设计图 | 同上 | `kind: 'ui-prototype'`,默认 `16:9 · 1K`;前置同上 |
|
||||
| 生成背景音乐 | `derive_local_project_resource` | `editKind: 'background-music'`、`generationMode: 'create'`、`sourceMediaType: 'audio/mpeg'` |
|
||||
| 生成音效 | `derive_local_project_resource` | `editKind: 'sound-effect'`、其余同上 |
|
||||
| 上传 | `upload_local_asset` | `{ projectPath, fileName, mediaType, bytes }` |
|
||||
|
||||
`generate_local_project_asset` 的完整参数是 `{ projectPath, kind, prompt, aspectRatio, imageSize, assetName, outputPath }`(Rust `src-tauri/src/commands.rs` 的 `generate_local_project_asset`,返回 `{ id, localPath, absolutePath, manifestPath }`)。
|
||||
`start_local_project_asset_generation` 的完整参数是 `{ projectPath, projectId, taskId, kind, prompt, aspectRatio, imageSize, assetName, outputPath }`(Rust `src-tauri/src/asset_generation_tasks.rs`),**提交即返回**一条任务记录(`taskId / status / phaseDetail / assetId / error` 等);生成在 `tauri::async_runtime::spawn` 出来的后台任务里跑,账本落在项目内 `.agent/runtime/asset-generation-tasks/tasks.json`,进度由 `list_local_project_asset_generations` 读回。截图面板不再「等生成结束」,所以**点「生成」即同步关闭面板**(不等 IPC),面板内不出现阶段文案;只有「点击瞬间就失败」才带草稿重开(关闭 ≠ 取消)。
|
||||
|
||||
## 4a. 本地排队与「生成任务」侧栏
|
||||
|
||||
- **本地排队**:AGC 本地 durable 输出槽按**精确动作指纹**分槽(`run_id = slot-<sha256(动作材料)>`,材料为 prompt / outputPath / 比例 / 尺寸 / assetKind / assetLabel / replaceExisting / requireSlices;不同 prompt 或素材名各自独立成槽,不再按 `outputPath` 共用;旧 `{outputPath,requireSlices}` 槽账本由同一精确动作懒迁移)。因此后端已具备并行能力,但**本批前端仍按「同一时刻只派发一条」排队**——真并行派发需要并发收口设计(配对读 + manifest CAS + 聚焦意图互不覆盖),留待下一批。所以第二条提交停在**前端本地队列**里(不调用提交 IPC,阶段显示本地排队的「排队中。」),第一条终态后由同一条循环自动补发;判据是「存在 `dispatched && 未终态` 的任务时不派发下一条」。
|
||||
- **阶段文案只来自后端,且只出现在任务侧栏**:派发之后由任务侧栏渲染后端账本给的 `phaseDetail`(「排队中。」/「正在生成。」/「生成已完成。」/失败原因),提交面板已关闭、不渲染任何阶段文案;前端不拼阶段、不做百分比。
|
||||
- **「生成任务」是常驻画布的可折叠侧栏**(形态对齐网页端美术画布的任务侧栏):折叠时留贴边把手并在把手上显示在途数量;展开是两个分栏「排队/生成中」与「已完成」(各带条数,「已完成」封顶 20 条 + 列表滚动 + 高度有界);位置在画布左侧标题栏之下、**覆盖式**(不 reflow 挤窄画布视口)。侧栏非模态(不铺全屏遮罩、不做焦点陷阱、**不参与** `isResourceCanvasFloatingPanelOpen` / `resourceCanvasHostGenerationPanelOpen` 的遮挡判据),提交受理后自动展开;工具栏入口按钮常驻并显示 `生成任务 · N`。每项的「定位到素材」**每次点击都终局化**(含跨栏目先切栏目、不在投影里给结论、3 秒有界兜底),不允许提示条永久停在「正在定位生成的素材…」。
|
||||
|
||||
## 5. 参数口径与复用程度
|
||||
|
||||
@@ -71,12 +77,18 @@
|
||||
npx vitest run apps/ai-game-creator-shell/tests/appSurface.test.ts
|
||||
npx vitest run apps/ai-game-creator-shell/tests/resourceCanvasBottomToolbar.test.tsx
|
||||
npx vitest run apps/ai-game-creator-shell/tests/resourceCanvasGenerationEntry.test.tsx
|
||||
npx vitest run apps/ai-game-creator-shell/tests/resourceCanvasAssetGenerationBackgroundClose.test.tsx
|
||||
npx vitest run apps/ai-game-creator-shell/tests/resourceCanvasAssetGenerationQueue.test.ts
|
||||
npx vitest run apps/ai-game-creator-shell/tests/resourceCanvasAssetGenerationTasksPanel.test.tsx
|
||||
npx vitest run apps/ai-game-creator-shell/tests/projectResourceLiveIntegration.test.tsx
|
||||
npm run agc:typecheck
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
cargo test -p genarrative-ai-game-creator-shell asset_generation_task
|
||||
```
|
||||
|
||||
- 模型层:四个栏目的工具集与顺序、未命中栏目返回空、「所有资源」与 `null` 返回空、二级菜单分流、比例 / 尺寸白名单收窄、前置判据、不可用原因、`outputPath` 策略。
|
||||
- 组件层:工具栏渲染与二级菜单开合、不可用入口可点击 + 原因可关闭、上传回调。
|
||||
- AppSurface 层:进入栏目出现工具栏 / 回总览与展开态消失、每个图片类入口的 `generate_local_project_asset` 载荷、前置缺失可点击说明且零请求、音频入口走 `derive_local_project_resource`、上传走 `upload_local_asset` + 配对读清单、工具栏与右下 Dock 的几何契约。
|
||||
- 生成任务层:`resourceCanvasAssetGenerationTaskModel`(状态机 / 在途判据 / 恢复 / 耗时文案)、`resourceCanvasAssetGenerationQueue`(第二条不发提交 IPC、前一条终态后自动补发、失败与账本丢失都能收口)、`ResourceCanvasAssetGenerationTasksPanelView`(非模态、阶段文案来自后端记录、按 `assetId` 定位)、两块生成浮层在提交期间可关闭、「后台运行并关闭」文案。
|
||||
- Rust 层:`asset_generation_tasks` 的账本落项目内、排队阶段文案由后端拥有、进程重启把无人推进的记录收口为中断失败、账本上限与 task id 边界。
|
||||
- AppSurface 层:进入栏目出现工具栏 / 回总览与展开态消失、每个图片类入口的 `start_local_project_asset_generation` 载荷、前置缺失可点击说明且零请求、音频入口走 `derive_local_project_resource`、上传走 `upload_local_asset` + 配对读清单、生成面板关闭后任务仍在「生成任务」面板且第二条按本地排队补发、工具栏与右下 Dock 的几何契约。
|
||||
|
||||
@@ -51,13 +51,13 @@
|
||||
| **S9** 选择与多选 | 单击卡片 → `Shift`/`Ctrl`/`Meta` 再点 → 空白处拖拽框选 | 点卡 = 选中并在卡片旁浮出工具条;三种修饰键等效追加;框选可见选框 | L51、L61–62、L318–319 | `data-resource-card-id` + class 含 `is-selected` + `aria-pressed="true"`;浮出容器 `role="toolbar"`(图片 `aria-label="图片工具栏"`,音频 `"素材工具栏"`) | ⚠️ **PRD L61–62 要求的「打开详情」按钮在代码中不存在**(测试显式断言为 `null`),按 Issue #309 C3「取消资源详情面板与全屏编辑路由」判,不要判为缺失;真正入口是 `aria-label="选中资源:<栏目> <名>"` 按钮。**只读信息浮层已回归**(2026-09-11,工具条「信息」动作,见 `decision-log`):**C3 取消的仍只是可编辑详情面板与全屏编辑路由** |
|
||||
| **S10** 快速编辑(图片) | 选中 PNG/JPEG/WEBP 卡 → 工具条「快速编辑」→ 输入 → 提交(提示词下方另有「AI 润色」) | 先 `normalize_local_project_raster_resource`,再 `derive_local_project_resource(editKind='image-reference')` → 服务端 `/api/editor/images/edits`;**产出一张新素材**,源素材与源文件不变,新资源带 `referenceResourceIds` 血缘 | L123、L193、L476–478、L557;#309 C3/C10 | 提交后 `assets[]` +1、卡片 +1 且 `data-resource-card-id` 为新 id;**源卡仍在且内容未变**;工具条真渲染的只有 `quick-edit` 与 `download`;「AI 润色」`aria-label="AI 润色"` + `aria-busy`,成功回填并出现「恢复原文」,失败保留原文并给「AI 润色失败,可重试」 | ① 服务端白名单 17 项(`editor_project.rs:4120-4141`),`character-animation`/`video`/`audio`/`document`/`code` 等**仍会 400**;② 工具条 7 个动作(重绘 / 裁剪扩图 / 去背景 / 像素完美 / 切图集 / 提取 UI 素材 / 角色动画)按 opt-in **不渲染**;③ 润色结果超 `resourceEditPromptMaxLength` 会**截断并提示「已按长度上限截断」**;④ 提示词变了(改写或润色回填)必须换 `operationId`/幂等键,否则 Rust `request_fingerprint` 判「已绑定到不同资源编辑请求」 |
|
||||
| **S11** 画布生成入口(视频) | 画布级入口 → 只呈现视频 → 填名与提示词 → 提交(提示词下方另有「AI 润色」) | 无源新建视频 → 新卡产出并定位(音效 / 背景音乐已移到栏目工具栏,见 S11a) | 飞书 §4(首轮由对话启动)、L122 | 提交后 `assets[]` +1;面板是独立浮层(非在当前面板下方追加);「AI 润色」走 `polish_local_project_prompt` 并带上「这是素材生成提示词(类型)」的场景约束,成功回填、失败保留原文 | ⚠️ **Issue #309 写「画布生成入口未接」,但当前代码已接三类**(`resourceCanvasGenerationModel.ts` 仅 `video`/`sound-effect`/`background-music`);图片等类型会直接报「当前资源类型不支持无源生成」;润色结果超该类型上限(背景音乐 140 / 音效 1900 / 视频 4000)会截断并提示「已按长度上限截断」 |
|
||||
| **S12** 编辑标签 | 选中已登记素材 → 工具条「编辑标签」→ 增删标签 → 保存 | 面板**只编辑 `manifest.assets[].tags`**;`category` 读一次权威值后**原样回传**;顶部没有分类 chip 排 | L360(2026-09-11 收口)、#309 C2 | 面板标题「编辑素材标签」,底部只有「取消 / 保存标签」;保存后 `assets[n].tags` 变化而 `assets[n].category` **逐字不变** | 面板内的「删除资源」按钮是**唯一**删除入口,保留;「用户手动设置 category」这项能力已移除 |
|
||||
| **S12** 编辑标签 | 选中已登记素材 → 工具条「编辑标签」→ 增删标签 → 保存 | 面板**只编辑 `manifest.assets[].tags`**;`category` 读一次权威值后**原样回传**;顶部没有分类 chip 排 | L360(2026-09-11 收口)、#309 C2 | 面板标题「编辑素材标签」,底部只有「取消 / 保存标签」;保存后 `assets[n].tags` 变化而 `assets[n].category` **逐字不变** | 面板内的「删除资源」按钮保留(删除入口另见 S15 的选中卡工具条);「用户手动设置 category」不再放在本面板,改为独立入口(工具条「素材类型」与信息浮层「分类 → 设置」,选中即落盘,见 decision-log 2026-09-14) |
|
||||
| **S13** 重命名 | 工具条「重命名」→ 新文件名 → 确认 | 磁盘文件名与 manifest `localPath` 更新;**asset id 不变**;写盘失败回滚文件 | L362(资源身份稳定)、L515 | 弹窗 `ariaLabel="重命名素材"`;改名后「选中资源:…」按钮的无障碍名同步变化;引用 chip 与 @ 候选列表显示名刷新 | ⚠️ **不改游戏源码里对旧 `assets/<name>` 的引用**,后果由用户自负 |
|
||||
| **S14** 下载 | 选中可下载卡 → 工具条「下载」 | 弹出**原生保存对话框**选目标路径 → 分块复制;取消即停止 | L507、飞书 §11.1.2 | 出现 `title="保存素材"` 的原生对话框;成功后状态提示含 `已保存 <路径>` | 语义是"另存为",不是静默直下;虚拟版本条目没有文件、不放行 |
|
||||
| **S15** 删除 | 工具条 / 标签面板「删除」→ 确认弹窗 | 三分支:① 无引用→直接删;② 被引用未勾选→只删素材、版本保留**悬空绑定**、界面不合成幽灵资源卡;③ 勾选→素材与该批版本在**同一次 manifest 写入**内一起删 | L413(版本只追加的唯一例外)、L532–533;#309 C5 | 弹窗 `ariaLabel="确认删除资源"`;被引用时出现 `被 N 个游戏版本使用` + 版本列表 + checkbox `把相关游戏版本一并删除`;无引用时该 body 整块不渲染 | **只摘登记、不删磁盘文件**;读引用命令精确名是 `read_local_project_asset_references` |
|
||||
| **S15a** 替换素材(含点选替换) | 选中被**当前版本**绑定的素材 → 工具条「替换素材」→ 候选弹窗(弹窗内可筛可选);再点 footer「点选替换」→ 弹窗关闭、进入画布点选态 → 在画布上直接点目标素材 | 弹窗确认与点选是**同一条**写入链路(`replace_local_project_version_resource`,载荷逐字一致):改该版本绑定、不建新版本;点选态下合法目标直接提交并自动退出点选态,非法目标零写入、**留在**点选态并在提示条上说明原因 | PRD §5.3 / §7.8 第 8 条;#309「直接替换」口径 | 点选态判据:候选弹窗 `role="dialog"` 已卸载;画布出现 `.game-resource-canvas-pick-hint`,文案含「在画布上点选要替换成的素材」与「点击空白处不会退出」,并有「取消」按钮;非法目标后提示条仍在且出现 `role="alert"`(「替换素材不兼容:分类不同」/「替换素材与源素材相同」/「替换素材未登记或已被删除」);点选期间卡片 `aria-pressed` 不变(单击只用于点选)、源素材选中与工具条不因点空白或点非法目标而丢;Esc 退出点选(画布全局 Esc 的清选中不随之触发);点选态下滚轮平移与缩放照常可用 | 点选只能点**当前画布上可见**的卡:目标在别的栏目时先切栏目(点选会话跨栏目存活,不因「收起资源」或切栏目结束);空白点击不退出、也不清画布选中 |
|
||||
|
||||
| **S11a** 栏目画布底部工具栏 | 进「UI 交互 / 角色与对象 / 场景与环境 / 音频」任一栏目 → 点左下角工具栏里的入口生成 → 「收起资源」回总览看工具栏消失 | 工具栏只在矩阵四个栏目(功能画布)渲染;图片类入口走 `generate_local_project_asset`,音频入口复用既有无源生成链路,上传复用 `upload_local_asset`;生成 / 上传成功后走既有 manifest 刷新与资源定位 | PRD §3.10、§7.9 | DOM 判据 `[data-resource-bottom-toolbar="<category>"]`(资源总览、「所有资源」展开态、文档、待归类、项目版本都**没有**这个节点);工具栏是 `.game-resource-book-manager` 的直接子节点(`closest('.game-resource-book-scene')` 为 `null`);每个入口一次 `generate_local_project_asset`,载荷逐字为 `{ projectPath, kind, prompt, aspectRatio, imageSize, assetName, outputPath }`(`kind` 映射见 PRD §7.9 第 3 条);写入命令之后有 `get_local_game_project_revision` + `get_local_game_manifest` 的配对读;缺 `assets/art-spec.png` 时「生成图标素材 / 生成 UI 设计图」仍可点击(`aria-disabled="true"` 但**不是**原生 disabled)并给出含该路径的 `role="alert"` 原因、零生成请求;音频入口面板标题即「生成背景音乐」/「生成音效」且没有类型选择器 | ① 本地通道没有 `model` / `specType` / `replaceExisting` 入参:面板不渲染模型选择器,角色规范与自定义规范共用 `spec` 通道(靠 `assetName` 与提示词区分),「图标规范」在项目已有权威规范图时不再指向 `assets/art-spec.png`(否则会被 Rust 的防覆盖校验硬拒);② 本轮不做生成视频 / 宣发素材 / 生成游戏场景 / 选择工具 / 抓手工具;③ 既有「生成素材」浮层入口只保留生成视频,音频入口只在音频栏目工具栏出现 |
|
||||
| **S11a** 栏目画布底部工具栏 | 进「UI 交互 / 角色与对象 / 场景与环境 / 音频」任一栏目 → 点左下角工具栏里的入口生成 → 「收起资源」回总览看工具栏消失 | 工具栏只在矩阵四个栏目(功能画布)渲染;图片类入口走 `start_local_project_asset_generation`(提交即返回、生成在后台跑),音频入口复用既有无源生成链路,上传复用 `upload_local_asset`;生成 / 上传成功后走既有 manifest 刷新与资源定位 | PRD §3.10、§7.9 | DOM 判据 `[data-resource-bottom-toolbar="<category>"]`(资源总览、「所有资源」展开态、文档、待归类、项目版本都**没有**这个节点);工具栏是 `.game-resource-book-manager` 的直接子节点(`closest('.game-resource-book-scene')` 为 `null`);每个入口一次 `start_local_project_asset_generation`,载荷逐字为 `{ projectPath, projectId, taskId, kind, prompt, aspectRatio, imageSize, assetName, outputPath }`(`kind` 映射见 PRD §7.9 第 3 条;`taskId` 是前端每次提交新铸的本地任务 id);该命令提交即返回,之后有 `list_local_project_asset_generations` 轮询与 `get_local_game_project_revision` + `get_local_game_manifest` 的配对读;提交期间点 × / 遮罩 / Esc /「后台运行并关闭」任一都能关面板且请求继续(画布立即恢复可交互),关闭后任务仍出现在「生成任务」面板(入口按钮 `aria-label="生成任务"`,非模态浮层、无 `aria-modal`)并显示后端 `phaseDetail`;第一条未终态时提交第二条 → 第二条显示「排队中。」且生成提交 IPC 次数仍为 1,第一条终态后自动补发(次数变 2);缺 `assets/art-spec.png` 时「生成图标素材 / 生成 UI 设计图」仍可点击(`aria-disabled="true"` 但**不是**原生 disabled)并给出含该路径的 `role="alert"` 原因、零生成请求;音频入口面板标题即「生成背景音乐」/「生成音效」且没有类型选择器 | ① 本地通道没有 `model` / `specType` / `replaceExisting` 入参:面板不渲染模型选择器,角色规范与自定义规范共用 `spec` 通道(靠 `assetName` 与提示词区分),「图标规范」在项目已有权威规范图时不再指向 `assets/art-spec.png`(否则会被 Rust 的防覆盖校验硬拒);② 本轮不做生成视频 / 宣发素材 / 生成游戏场景 / 选择工具 / 抓手工具;③ 既有「生成素材」浮层入口只保留生成视频,音频入口只在音频栏目工具栏出现 |
|
||||
|
||||
### D 阶段 · 版本与运行
|
||||
|
||||
@@ -101,6 +101,8 @@
|
||||
|
||||
先记住状态枚举:`data-preview-kind` ∈ `raster-image | media-image | video | audio | code | document | version | placeholder`;`data-preview-status` **只有 `idle | loading | loaded | failed` 四个值,不存在 `unsupported`**。"不适用"不是状态,表现为**永远 idle**。
|
||||
|
||||
棋盘格底另有一条独立判据:`data-preview-has-alpha` **只在预览已加载且这张图真的带 alpha 通道时才写 `'true'`**(原生头部判据:PNG colorType 4/6 或 `tRNS`、WebP alpha 标志;JPEG 恒不透明)。缺属性与不透明同档,卡面退回纯色底。因此「真透明底」与「AI 把棋盘格画进像素里」不再同形:**看 `data-preview-has-alpha` 而不是看卡面有没有棋盘格**。
|
||||
|
||||
```js
|
||||
// ① 全量分布(首选)
|
||||
[...document.querySelectorAll('.game-resource-card[data-preview-kind]')]
|
||||
@@ -120,6 +122,11 @@
|
||||
[...document.querySelectorAll('.game-resource-card[data-preview-status="loaded"]')]
|
||||
.filter(e => !e.querySelector('.game-resource-card-visual img, .game-resource-card-visual video'))
|
||||
.map(e => [e.dataset.resourceCardId, e.dataset.previewKind])
|
||||
|
||||
// ⑤ 真假透明底:已加载的图片卡按 alpha 分组
|
||||
// 真透明(true)才应有棋盘格底;AI 画了棋盘格的不透明图这里必须是 undefined
|
||||
[...document.querySelectorAll('.game-resource-card[data-preview-status="loaded"][data-preview-kind="raster-image"], .game-resource-card[data-preview-status="loaded"][data-preview-kind="media-image"]')]
|
||||
.reduce((m, e) => { const k = e.dataset.previewHasAlpha ?? '(无 alpha 判据)'; m[k] = (m[k] || 0) + 1; return m; }, {})
|
||||
```
|
||||
|
||||
| 现象 | 说明 | 第一眼做什么 |
|
||||
@@ -128,6 +135,7 @@
|
||||
| `failed` + `data-preview-error` | 读取或解码真失败,读 `data-preview-error` 原文 | `retryable=false` 表示永久失败(超尺寸、损坏、类型不支持、不安全 SVG);可见性预取遇 failed 会直接放弃,不会自愈 |
|
||||
| `loaded` 但无主体节点 | 原生返回的 dataUrl 为空、或解码不出画面 | 这类**不报错**,只能靠脚本 ④ 抓 |
|
||||
| `placeholder` + `idle` | **不适用**(游戏代码、无法识别的二进制产物等),正常 | 不要当 bug 报 |
|
||||
| 卡面有棋盘格但 `data-preview-has-alpha` 缺失 | **这张图其实不透明**:棋盘格是图里画进去的(旧构建会额外再铺一层卡面棋盘格,两者叠在一起) | 脚本 ⑤ 分组确认;真透明卡才允许有 `'true'` |
|
||||
|
||||
**IPC 侧**:预览只走 4 条命令 `read_local_project_image_preview`、`read_local_project_media_preview`、`read_local_project_text_preview`、`cancel_local_project_resource_preview_scope`。媒体那条的 `category` **只接受 `art` / `audio`**,传栏目值会被原生拒绝,表现是卡片全空、没有缩略图。
|
||||
|
||||
@@ -238,7 +246,7 @@ api-server 是否本次重启:□ 是 □ 否
|
||||
### 7.3 已知未做 / 已取消(不要报成缺陷)
|
||||
|
||||
1. **C6 的候选素材 / 替换关系 / 替换队列 / Agent 审核 / 批量提交整条取消**(#309)。PRD §5.3 的 `ProjectVersionResourceReplacement` 与 §3.2 的「创建下一迭代版本」**当前不实现**(2026-09-11 用户 DDL 口径「替换这块先做成直接替换」),但**保留为未来合同**:今天的实现是「改该版本的绑定,不建新版本」,验收见 PRD §7.8。
|
||||
2. **画布生成入口分为两条**(2026-09-13 起):既有「生成素材」浮层入口只保留视频;音频(背景音乐 / 音效)与图片类(生成图片 / 生成规范 / 生成角色形象 / 生成图标素材 / 生成 UI 设计图)改由栏目画布左下角的底部工具栏承载,走本地 `generate_local_project_asset`。工具栏之外的其它无源生成类型仍会直接报"当前资源类型不支持无源生成",这是设计而非缺陷。见 PRD §3.10 / §7.9 与下面的 S11a。
|
||||
2. **画布生成入口分为两条**(2026-09-13 起):既有「生成素材」浮层入口只保留视频;音频(背景音乐 / 音效)与图片类(生成图片 / 生成规范 / 生成角色形象 / 生成图标素材 / 生成 UI 设计图)改由栏目画布左下角的底部工具栏承载,走本地 `start_local_project_asset_generation`(提交即返回、生成在后台跑完写回项目,任务账本在项目内 `.agent/runtime/asset-generation-tasks/`)。工具栏之外的其它无源生成类型仍会直接报"当前资源类型不支持无源生成",这是设计而非缺陷。见 PRD §3.10 / §7.9 与下面的 S11a。
|
||||
3. **工具条 7 个动作按 opt-in 不渲染**:重绘 / 裁剪扩图 / 去背景 / 像素完美 / 切图集 / 提取 UI 素材 / 角色动画;只有 `快速编辑` 与 `下载` 真渲染(宿主另附加 `UI 编辑器` / `编辑标签` / `重命名`,以及**只在素材被当前版本绑定时**出现的 `替换素材`)。
|
||||
4. **C7 只做记录层 + UI 层**:切换版本即重载当前预览;版本化资源解析机制未实现。资源替换同样不做运行时资源重映射:改绑定只改「这个版本用哪些素材」的记录,运行画面要按游戏自身引用的资源路径渲染。
|
||||
5. **「首轮进度投影」无编码级判据**,可见性由底部 Agent 状态栏承载。
|
||||
|
||||
Reference in New Issue
Block a user