新增编辑器生成规范、生成角色形象、生成图标素材等功能
新增编辑器生成规范、生成角色形象、生成图标素材等功能
This commit is contained in:
106
docs/superpowers/plans/【编辑器】图片画布生成对象独立化修复计划-2026-06-16.md
Normal file
106
docs/superpowers/plans/【编辑器】图片画布生成对象独立化修复计划-2026-06-16.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 图片画布生成对象独立化修复 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking.
|
||||
|
||||
**Goal:** 修复图片画布底部生成按钮复用单一状态导致后创建对象销毁前一个对象的问题。
|
||||
|
||||
**Architecture:** 保留现有图片画布组件结构,先以回归测试锁定“规范占位 + 角色占位可并存”。实现上把生成占位状态从单个 `generateDialog` 扩展为 active dialog + inactive dialog 列表;每次新建生成对象只新增一个 dialog 实例,旧实例保留占位和逻辑状态,只有当前 active 实例渲染编辑面板。
|
||||
|
||||
**Tech Stack:** React、TypeScript、Vitest、Testing Library。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 补充失败回归测试
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/src/components/image-editor/ImageCanvasEditorView.test.tsx`
|
||||
|
||||
- [x] **Step 1: Write the failing test**
|
||||
|
||||
在 `keeps the bottom AI toolbar visible while generation panels are open` 附近新增测试:
|
||||
|
||||
```tsx
|
||||
it('keeps existing generation placeholders when another bottom generation object is created', () => {
|
||||
render(<ImageCanvasEditorView />);
|
||||
|
||||
const bottomToolbar = screen.getByRole('toolbar', { name: 'AI画布工具栏' });
|
||||
fireEvent.click(
|
||||
within(bottomToolbar).getByRole('button', { name: '生成规范' }),
|
||||
);
|
||||
fireEvent.click(screen.getByRole('menuitem', { name: '角色形象规范' }));
|
||||
|
||||
expect(screen.getByLabelText('规范生成占位图')).toBeTruthy();
|
||||
expect(screen.getByRole('dialog', { name: '生成规范' })).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '生成角色形象' }));
|
||||
|
||||
expect(screen.getByLabelText('规范生成占位图')).toBeTruthy();
|
||||
expect(screen.getByLabelText('角色生成占位图')).toBeTruthy();
|
||||
expect(screen.getByRole('dialog', { name: '生成角色形象' })).toBeTruthy();
|
||||
});
|
||||
```
|
||||
|
||||
- [x] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run: `npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx -t "keeps existing generation placeholders"`
|
||||
|
||||
Expected: FAIL because only the latest placeholder remains.
|
||||
|
||||
### Task 2: 实现最小独立生成对象状态
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/src/components/image-editor/ImageCanvasEditorView.tsx`
|
||||
|
||||
- [x] **Step 1: Add stable dialog ids and inactive dialog state**
|
||||
|
||||
Add `id: string` to `GenerateDialogState`; add `generationDialogCounterRef`; add `inactiveGenerateDialogs` state. Provide helpers to create ids, archive current active dialog before replacing it, update active/inactive dialogs by id, and list all canvas generation dialogs.
|
||||
|
||||
- [x] **Step 2: Update bottom generation openers**
|
||||
|
||||
Change `openGenerateDialog`、`openSpecDialog`、`openCharacterGenerationDialog`、`openIconGenerationDialog` so each call archives the current active canvas generation dialog and sets a newly created active dialog. Edit modal remains single active dialog and does not archive.
|
||||
|
||||
- [x] **Step 3: Render all placeholders**
|
||||
|
||||
Replace the single placeholder render block with a map over inactive dialogs plus active dialog. Only active dialog shows composer; inactive dialogs remain visible and can be clicked to reactivate their own panel.
|
||||
|
||||
- [x] **Step 4: Keep actions scoped to active dialog**
|
||||
|
||||
Keep submit/update/upload/pick actions operating on active dialog only. Adjust delete, drag, blur, and generated-layer cleanup so they update or remove only the matching active/inactive dialog.
|
||||
|
||||
- [x] **Step 5: Keep archived async generation writeback scoped by dialog id**
|
||||
|
||||
当一个生成对象已经进入 `generating`,随后用户再创建第二个生成对象并把第一个对象归档为 inactive 时,第一个对象仍可能继续被拖拽或等待异步完成。完成回写必须按 `dialog.id` 从 active + inactive 的最新状态读取占位图,不能使用提交瞬间的旧 `placeholder` 快照。
|
||||
|
||||
回归测试:
|
||||
|
||||
```bash
|
||||
npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx -t "keeps archived generation logic"
|
||||
```
|
||||
|
||||
### Task 3: 验证并更新文档
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`
|
||||
- Optional Modify: `C:/Genarrative/.hermes/shared-memory/pitfalls.md`
|
||||
|
||||
- [x] **Step 1: Run focused tests**
|
||||
|
||||
Run: `npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx -t "keeps existing generation placeholders|opens character spec generation form|opens icon asset generation panel|removes the active character generation placeholder"`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [x] **Step 2: Run full image editor test**
|
||||
|
||||
Run: `npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [x] **Step 3: Run encoding check**
|
||||
|
||||
Run: `npm run check:encoding`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [x] **Step 4: Document behavior**
|
||||
|
||||
Add one sentence to the image canvas editor technical plan: bottom generation buttons create independent canvas generation objects; creating a new one must not destroy previous placeholders or generated-object logic.
|
||||
128
docs/superpowers/plans/【编辑器】画板角色动画生成实施计划-2026-06-15.md
Normal file
128
docs/superpowers/plans/【编辑器】画板角色动画生成实施计划-2026-06-15.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 画板角色动画生成 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在图片画布编辑器中,仅对角色图片提供角色动画生成入口,并通过后端 seedance2.0 链路生成视频、抽帧、去绿幕并持久化到 OSS。
|
||||
|
||||
**Architecture:** 前端在 `ImageCanvasEditorView` 中基于图层 `assetKind === "character"` 控制悬浮按钮和右键菜单,打开锚定到图片右侧的独立动画生成面板。前端 service 调用新增编辑器角色动画 API,后端复用 `character_animation_assets.rs` 中现有视频生成、抽帧、绿幕去背、OSS 写入能力,避免新建平行资产系统。
|
||||
|
||||
**Tech Stack:** React + TypeScript + Vitest;Rust Axum `api-server`;现有 `shared-contracts` 资产 DTO;Aliyun OSS 资产持久化;VectorEngine/Ark seedance2.0 角色动画链路。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 文档补充
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md`
|
||||
|
||||
- [ ] **Step 1: 补充角色动画生成章节**
|
||||
- 明确仅 `assetKind: "character"` 图层展示入口。
|
||||
- 明确右侧独立面板字段、预设动作、价格、模型、抽帧和 OSS 存储口径。
|
||||
- 明确非角色图层不展示按钮。
|
||||
|
||||
- [ ] **Step 2: 运行编码检查**
|
||||
- Run: `npm run check:encoding`
|
||||
- Expected: PASS 或仅与本任务无关的既有问题。
|
||||
|
||||
### Task 2: 前端失败测试
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/src/components/image-editor/ImageCanvasEditorView.test.tsx`
|
||||
- Modify: `C:/Genarrative/src/services/image-editor/editorProjectClient.test.ts`
|
||||
|
||||
- [ ] **Step 1: 写失败测试**
|
||||
- 测试角色图层显示悬浮 / 右键 `生成动画`。
|
||||
- 测试非角色图层不显示 `生成动画`。
|
||||
- 测试面板提交请求包含 `sourceLayerId`、`sourceImageSrc`、prompt、resolution、ratio、frameCount、durationSeconds、priceMudPoints、model。
|
||||
|
||||
- [ ] **Step 2: 验证 RED**
|
||||
- Run: `npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx src/services/image-editor/editorProjectClient.test.ts`
|
||||
- Expected: FAIL,失败原因是功能/API 尚未实现。
|
||||
|
||||
### Task 3: 前端实现
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/src/services/image-editor/editorProjectClient.ts`
|
||||
- Modify: `C:/Genarrative/src/components/image-editor/ImageCanvasEditorView.tsx`
|
||||
- Modify: `C:/Genarrative/src/index.css`
|
||||
|
||||
- [ ] **Step 1: 新增 service 类型和请求函数**
|
||||
- `generateEditorCharacterAnimation(input)` 调用 `/api/editor/character-animations/generations`。
|
||||
- 限定 model 固定为 `seedance2.0` 的回包展示字段。
|
||||
|
||||
- [ ] **Step 2: 扩展图层 assetKind**
|
||||
- `CanvasLayer.assetKind` 支持 `'character' | 'spec' | null`。
|
||||
- hydrate / serialize / 图片类型展示跟随扩展。
|
||||
|
||||
- [ ] **Step 3: 加入口和面板**
|
||||
- 角色图层悬浮工具条和右键菜单显示 `生成动画`。
|
||||
- 面板锚定图片右侧,字段按设计实现,文本框 maxLength=4000。
|
||||
- 价格通过 `resolution * durationSeconds` 计算。
|
||||
|
||||
- [ ] **Step 4: 验证 GREEN**
|
||||
- Run: `npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx src/services/image-editor/editorProjectClient.test.ts`
|
||||
- Expected: PASS。
|
||||
|
||||
### Task 4: 后端失败测试
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/server-rs/crates/shared-contracts/src/assets.rs`
|
||||
- Modify: `C:/Genarrative/server-rs/crates/api-server/src/character_animation_assets.rs`
|
||||
- Modify: `C:/Genarrative/server-rs/crates/api-server/src/modules/play_flow.rs` 或现有 editor router 文件(按现有路由事实选择)
|
||||
|
||||
- [ ] **Step 1: 写 DTO / prompt / plan 单测**
|
||||
- 验证请求 480p/720p、32/40/48 帧、比例枚举、模型固定 seedance2.0。
|
||||
- 验证构造 prompt 包含用户给定固定骨架与动作描述。
|
||||
- 验证价格计算:480p 每秒 10,720p 每秒 20。
|
||||
|
||||
- [ ] **Step 2: 验证 RED**
|
||||
- Run: `cargo test -p api-server editor_character_animation --manifest-path server-rs/Cargo.toml`
|
||||
- Expected: FAIL,失败原因是 helper 或 handler 尚未实现。
|
||||
|
||||
### Task 5: 后端实现
|
||||
|
||||
**Files:**
|
||||
- Modify: `C:/Genarrative/server-rs/crates/shared-contracts/src/assets.rs`
|
||||
- Modify: `C:/Genarrative/server-rs/crates/api-server/src/character_animation_assets.rs`
|
||||
- Modify: `C:/Genarrative/server-rs/crates/api-server/src/modules/play_flow.rs` 或现有 editor router 文件
|
||||
|
||||
- [ ] **Step 1: 新增编辑器角色动画 DTO**
|
||||
- 请求字段:sourceLayerId/sourceImageSrc/promptText/resolution/ratio/frameCount/durationSeconds/sourceWidth/sourceHeight。
|
||||
- 响应字段:taskId/model/prompt/previewVideoPath/frames/priceMudPoints。
|
||||
|
||||
- [ ] **Step 2: 新增 handler**
|
||||
- 校验 prompt 1..4000、resolution、ratio、frameCount 与 durationSeconds 组合。
|
||||
- sourceImageSrc 作为首尾帧参考。
|
||||
- 调用现有 seedance image-to-video 逻辑生成预览视频。
|
||||
- 调用现有抽帧 + 绿幕去背 + OSS 持久化逻辑输出帧。
|
||||
|
||||
- [ ] **Step 3: 路由接入**
|
||||
- `POST /api/editor/character-animations/generations`。
|
||||
- 保持走 play_flow 创作/游玩支撑主干或 editor 路由现有聚合,不回到 `app.rs` 平行挂载。
|
||||
|
||||
- [ ] **Step 4: 验证 GREEN**
|
||||
- Run: `cargo test -p api-server editor_character_animation --manifest-path server-rs/Cargo.toml`
|
||||
- Expected: PASS。
|
||||
|
||||
### Task 6: 总验证与收口
|
||||
|
||||
**Files:**
|
||||
- All modified files.
|
||||
|
||||
- [ ] **Step 1: 定向前端测试**
|
||||
- Run: `npm run test -- src/components/image-editor/ImageCanvasEditorView.test.tsx src/services/image-editor/editorProjectClient.test.ts`
|
||||
- Expected: PASS。
|
||||
|
||||
- [ ] **Step 2: 定向后端测试 / check**
|
||||
- Run: `cargo test -p api-server editor_character_animation --manifest-path server-rs/Cargo.toml`
|
||||
- Run: `cargo check -p api-server --manifest-path server-rs/Cargo.toml`
|
||||
- Expected: PASS。
|
||||
|
||||
- [ ] **Step 3: 类型与编码**
|
||||
- Run: `npm run typecheck`
|
||||
- Run: `npm run check:encoding`
|
||||
- Expected: PASS。
|
||||
|
||||
- [ ] **Step 4: 检查 diff**
|
||||
- Run: `git diff --check`
|
||||
- Expected: PASS。
|
||||
@@ -18,7 +18,8 @@
|
||||
- 图片拖拽时显示水平 / 垂直吸附参考线,吸附到其它图层或画板的边缘与中心线。
|
||||
- 生成资源右上角显示元数据按钮,点击打开独立元数据窗口。
|
||||
- 对生成资源执行修改时,在右侧创建新的生成结果图层,并自动调整视图显示原图和新图。
|
||||
- 图片生成 / 修改统一经 api-server BFF 接入 VectorEngine `gpt-image-2`:纯文本生成走 `/api/editor/images/generations`,基于当前生成图的修改走 `/api/editor/images/edits`。纯文本生成入口采用 Lovart 式画布内占位图 + 锚定生成输入框:点击生成工具后先在画布中心创建选中的灰色占位框,输入框跟随占位框显示;提交成功后真实生成图落在占位框位置,输入框继续跟随新生成图;基于已有生成图的修改仍通过轻量弹窗承载。前端不持有 provider 密钥;上游失败或配置缺失时只在当前生成输入框展示失败,不创建 mock 成功图。
|
||||
- 图片生成 / 修改统一经 api-server BFF 接入 VectorEngine `gpt-image-2`:纯文本生成走 `/api/editor/images/generations`,基于当前生成图的修改走 `/api/editor/images/edits`。纯文本生成入口采用 Lovart 式画布内占位图 + 锚定生成输入框:点击生成工具后先在画布中心创建选中的灰色占位框,输入框跟随占位框显示;待生成、生成中和失败后保留的占位图都必须继续支持拖动,生成完成时真实生成图落在最新占位框位置,输入框继续跟随新生成图;点击所有图片生成入口并确认请求开始后,必须隐藏对应设置面板,只保留画布内占位图或原图预览,并在预览上显示 Lovart 式生成中遮罩,避免“面板仍占屏”或“预览一起消失”。快速编辑和修改图片在调用后端前必须把当前图层图片源读取为图片 Data URL,来源可以是本地上传 Data URL、站内 public 图片、历史 `/generated-*` 路径或可读取的 OSS generated URL;后端仍只接收图片 Data URL,不把普通 URL 直接透传到 VectorEngine edits。前端不持有 provider 密钥;上游失败或配置缺失时恢复当前生成设置面板展示失败,不创建 mock 成功图。
|
||||
- 底部生成类按钮每次点击都必须创建独立的画布生成对象;新建规范、角色形象或图标素材时,只切换当前编辑面板,不得销毁此前尚未生成或已生成后的其它生成对象状态。归档为非当前编辑对象的生成占位仍可拖动、删除和等待异步完成,完成 / 失败回写必须按生成对象 ID 读取最新占位状态,不能使用提交瞬间的旧快照。
|
||||
|
||||
## 交互规则
|
||||
|
||||
@@ -61,8 +62,8 @@
|
||||
- `POST /api/editor/assets`:批量或单个创建账号级素材,支持按钮上传和拖拽上传后的 data URL / 后续 OSS 元数据。
|
||||
- `PATCH /api/editor/assets/{assetId}`:重命名素材或移动素材到文件夹。
|
||||
- `DELETE /api/editor/assets/{assetId}`:删除素材。已放入画布的 project resource 不被级联删除,避免旧画布丢图。
|
||||
- `POST /api/editor/images/generations`:按提示词调用 VectorEngine `gpt-image-2` 生成图片,返回 data URL、尺寸、prompt、model、provider 和 taskId。
|
||||
- `POST /api/editor/images/edits`:按提示词和当前生成图 Data URL 调用 VectorEngine edits,返回新的生成图片元数据。
|
||||
- `POST /api/editor/images/generations`:按提示词调用 VectorEngine `gpt-image-2` 生成图片;携带参考图的快速编辑也走该接口,前端必须把参考图源预读成图片 Data URL 后放入 `referenceImageSrcs`;接口返回 data URL、尺寸、prompt、model、provider 和 taskId。
|
||||
- `POST /api/editor/images/edits`:按提示词和当前图片 Data URL 调用 VectorEngine edits,返回新的生成图片元数据。
|
||||
|
||||
所有写接口都必须校验 Bearer 登录态和 owner;接口只返回当前用户有权读取的工程与资源。
|
||||
|
||||
@@ -82,8 +83,11 @@
|
||||
- 默认选择模式;底部工具栏能切换工具;中键拖拽和 Space 临时抓手都能平移画布。
|
||||
- 拖拽图片接近其它图片边缘或中心时显示吸附线,并保存吸附后的最终布局。
|
||||
- 生成工具点击后显示画布内 `Image Generator` 占位框和跟随占位框的生成输入框,生成失败保留占位和输入状态,生成成功后在占位位置创建真实图层,并让输入框继续跟随该生成图。
|
||||
- 生成类入口打开画布内面板时,底部 AI 工具栏必须保持可见;`生成规范`、角色 / 图标规范来源这类轻量菜单通过页面级 fixed portal 渲染,不能留在底部工具栏或参考图横向滚动容器内部,避免被局部 `overflow` 裁切。
|
||||
- 点击生成、生成规范、生成角色形象或生成图标素材后创建的占位图可继续保留;点击画布空白区域让当前图片或占位图失焦时,关闭当前生成面板并移除图片选中样式,但不删除占位图本身。
|
||||
- 生成资源显示元数据按钮,元数据窗口展示来源、prompt、model、provider、task、尺寸和 OSS 引用。
|
||||
- 修改生成资源后,右侧出现新生成结果图层,并自动 fit 原图 + 新图。
|
||||
- 快速编辑站内 public 示例图、历史 generated 图或 OSS generated 图时,前端先读取成 `data:image/*;base64,...` 再提交,后端不得再收到 `/creation-type-references/*`、`/generated-*` 或 OSS URL 作为 `referenceImageSrcs/sourceImageSrc`。
|
||||
- 素材文件夹可以新建、折叠、重命名和删除;删除普通文件夹后,其素材移动到“项目素材”。
|
||||
- 上传按钮和拖拽上传都支持多文件;拖到文件夹或该文件夹内素材时进入目标文件夹;拖到画布时进入默认文件夹并在投放点创建画布图层。
|
||||
- 素材面板支持选择模式框选,一次选中多个素材,并可批量移动或删除上传素材。
|
||||
|
||||
@@ -49,6 +49,8 @@ Linux 本机多用户并发开发时,`npm run dev` 和 `npm run dev:*` 单模
|
||||
|
||||
后端日志默认写入 `logs/api-server/`。后端 API smoke 使用 `npm run dev:api-server` 并检查 `/healthz`;需要确认实例可接生产流量时检查 `/readyz`。不要使用旧 `api-server:maincloud` 或任何 `GENARRATIVE_SPACETIME_MAINCLOUD_*` 口径。
|
||||
|
||||
Windows 本地 `npm run dev` / `npm run dev:api-server` 会用空的 `RUSTC_WRAPPER` / `CARGO_BUILD_RUSTC_WRAPPER` 覆盖 `server-rs/.cargo/config.toml` 里的 `sccache`,从而直连真实 `rustc`。不要把 wrapper 绕过值写成 `rustc`;Cargo 会按 wrapper 协议调用 `rustc <真实rustc路径> - ...`,最终报 `multiple input filenames provided` 并导致 api-server 无法启动。排查本地启动失败时,先看 dev 日志是否出现该错误,再确认脚本注入的 wrapper 为空。
|
||||
|
||||
开发态 `npm run dev` 与 `npm run dev:api-server` 会默认注入 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED=true`,因此密码登录在本地开发环境可直接注册未知手机号账号;生产环境仍按 `api-server` 配置默认关闭该开关。
|
||||
|
||||
本地 `npm run dev` 和 `npm run dev:api-server` 默认保留 inline 开发体验:未显式设置 `GENARRATIVE_EXTERNAL_GENERATION_MODE=queue` 时,外部生成 handler 会同步复用 worker executor,完成后返回 `completed`,便于快速确认 provider、OSS 和 SpacetimeDB 写回链路。inline 不创建 `external_generation_job`,也不能验证 worker lease、队列等待展示或动态扩缩容。
|
||||
|
||||
77
docs/【编辑器】画板图标素材生成入口设计-2026-06-15.md
Normal file
77
docs/【编辑器】画板图标素材生成入口设计-2026-06-15.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# 画板图标素材生成入口设计
|
||||
|
||||
日期:`2026-06-15`
|
||||
|
||||
## 背景
|
||||
|
||||
图片画布编辑器已有普通图片生成、生成规范、生成角色形象和角色动画入口。本次新增 `生成图标素材`,用于一次输入多条图标素材描述,先生成一张绿幕 spritesheet,再自动去背、按连通域拆分为独立图标素材并铺到画布。
|
||||
|
||||
## 入口与画布表现
|
||||
|
||||
- 底部 AI 画布工具栏新增 `生成图标素材` 按钮。
|
||||
- 点击后立即在画布中心创建图标素材占位图,不复用普通“单张空白图片”图标;占位图表现为一叠空白素材图标卡片。
|
||||
- 图标素材面板锚定在占位图下方,和现有生成输入框同一层级展示。
|
||||
- 生成完成后删除占位态,把拆分出的每个独立图标素材作为画布图片图层铺开,图标之间不重叠,并保留少量间距。
|
||||
- 图标素材图层写入 `assetKind: "icon"`;图标素材规范图写入 `assetKind: "icon-spec"`,用于刷新后保留标签和限制点选来源。
|
||||
|
||||
## 面板结构
|
||||
|
||||
1. 第一模块为 `图标素材规范`。
|
||||
- 点击后弹出菜单:`从画布中选择`、`新建图标素材规范`、`上传图片`。
|
||||
- `从画布中选择` 进入画布点选状态,只允许选择 `assetKind: "icon-spec"` 的图标素材规范图片;其它图片点击无效。
|
||||
- `新建图标素材规范` 复用生成规范表单,规格类型为 `图标素材规范`,生成成功后图层标记为 `icon-spec`。
|
||||
- `上传图片` 使用现有本地图片上传入口,上传图只绑定到本次面板,不自动放入画布。
|
||||
2. 第二模块为素材描述列表。
|
||||
- 每个文本框输入一个素材描述。
|
||||
- 默认填入:`返回按钮`、`设置按钮`、`下一关按钮`、`提示按钮`、`原图按钮`、`冻结按钮`。
|
||||
- 可以继续添加新的素材描述框,最多 `100` 个。
|
||||
- 生成时过滤空文本,按面板从上到下顺序作为 prompt 的素材清单。
|
||||
|
||||
## 面板外观
|
||||
|
||||
- 图标素材面板不使用内部纵向滑动列表;素材描述项按横向卡片铺开,新增一项就让面板整体更宽,保持列表一眼可扫。
|
||||
- 图标素材规范入口采用 Lovart 式参考卡:左侧预览缩略图,中间显示当前绑定名称,右侧显示绑定状态和三个轻量动作入口,不再只是两行文字平铺。
|
||||
- 规范卡的 `从画布中选择 / 新建图标素材规范 / 上传图片` 继续保留独立菜单,但菜单只负责来源切换,不承载说明文案。
|
||||
|
||||
## 生成契约
|
||||
|
||||
- 前端提交到 `POST /api/editor/icon-spritesheets/generations`。
|
||||
- 请求字段:
|
||||
- `referenceImageSrc`:图标素材规范 Data URL。
|
||||
- `iconDescriptions`:过滤空文本后的图标描述数组,`1..100`。
|
||||
- `model`:固定 `gemini-3.1-flash-image-preview`。
|
||||
- 后端根据图标数量选择尺寸:
|
||||
- `<=25` 个:`512x512`,即 0.5K 1:1。
|
||||
- `>25` 个:`1024x1024`,即 1K 1:1。
|
||||
- 后端使用 VectorEngine 图片编辑接口,把 `referenceImageSrc` 作为参考图 1,模型固定传 `gemini-3.1-flash-image-preview`。
|
||||
- Prompt 固定为:
|
||||
|
||||
```text
|
||||
参考图1的图标素材规范,纯绿幕背景方便扣除背景,禁止出现文字,保证每个图标素材的所有内容区域是完全连通的。按照以下的素材的顺序从上到下从左到右依次生成并整理成一张spritesheet:
|
||||
|
||||
<素材描述按中文顿号拼接>
|
||||
```
|
||||
|
||||
## 去背与拆分
|
||||
|
||||
- 后端收到 spritesheet 后先复用 `platform-image::generated_asset_sheets` 的绿幕去背能力。
|
||||
- 去背后基于 alpha 可见像素执行 8 邻域连通域检测。
|
||||
- 连通域按从上到下、从左到右排序;排序结果依次绑定面板中的素材描述名称。
|
||||
- 每个连通域裁剪时保留少量透明边距,并输出独立透明 PNG Data URL。
|
||||
- 若模型返回的连通域数量少于素材描述数量,接口返回失败,不在画布上铺半成品,避免名称和图标错位。
|
||||
|
||||
## 前端铺放规则
|
||||
|
||||
- 第一张图标放在原占位图左上附近。
|
||||
- 后续图标按行铺开,图标之间保留约 `24px` 世界坐标间距。
|
||||
- 每个图标图层标题使用对应素材描述文本。
|
||||
- 生成成功后关闭图标素材面板,选中第一张图标素材,并打开图层面板。
|
||||
|
||||
## 验收
|
||||
|
||||
- 点击 `生成图标素材` 后出现一叠空白图标占位和图标素材面板。
|
||||
- `图标素材规范 -> 从画布中选择` 只能选择图标素材规范图,点击普通图片或角色规范图不会绑定。
|
||||
- 默认 6 个素材描述会进入 prompt;新增描述最多到 100 个。
|
||||
- `<=25` 个描述提交时后端请求尺寸为 `512x512`;`>25` 个描述提交时后端请求尺寸为 `1024x1024`。
|
||||
- VectorEngine 请求体的 `model` 为 `gemini-3.1-flash-image-preview`。
|
||||
- 生成成功后画布出现按描述命名的多个透明图标素材图层,图层之间不重叠。
|
||||
123
docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md
Normal file
123
docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 画板角色形象生成入口设计
|
||||
|
||||
日期:`2026-06-15`
|
||||
|
||||
## 背景
|
||||
|
||||
图片画布编辑器已有普通图片生成与“生成规范”能力。本次新增“生成角色形象”入口,用于在同一画布内生成标注为“角色”的单张角色形象图片,并支持绑定角色形象规范与常规参考图。
|
||||
|
||||
## 入口与画布表现
|
||||
|
||||
- 底部 AI 画布工具栏新增 `生成角色形象` 按钮。
|
||||
- 点击后在画布中心创建一张空白图片占位图,面板锚定在占位图下方,视觉风格复用现有生成新图片面板;底部 AI 工具栏继续保持可见,不因角色面板打开而隐藏。
|
||||
- 占位图与生成成功后的图片右上角都覆盖 `角色` 标签。
|
||||
- 角色图层在布局快照中写入 `assetKind: "character"`,刷新后仍显示 `角色` 标签。
|
||||
|
||||
## 面板结构
|
||||
|
||||
角色生成面板只包含创作必需输入;每个输入框、参考图入口和选项按钮都必须展示对应中文字段标题,不只依赖 placeholder、按钮文案或 aria-label:
|
||||
|
||||
1. 第一项参考图入口为 `角色形象规范`。
|
||||
- 入口必须采用 Lovart 式参考图卡片:左侧小预览 / 图标,中间短标题,右侧仅保留必要状态,不把说明性规则文案铺在 UI 上。
|
||||
- 点击后弹出菜单:`从画布中选择`、`新建角色形象规范`、`上传图片`。
|
||||
- 来源菜单通过页面级 fixed portal 渲染,层级高于角色面板与参考图横向滚动区,不能被 `.image-canvas-editor__character-reference-row` 裁切。
|
||||
- `从画布中选择` 进入画布点选状态,点击已有图片后把该图绑定为角色形象规范;按 `Esc` 退出点选状态。
|
||||
- `新建角色形象规范` 复用当前 `生成规范 -> 角色形象规范` 流程。
|
||||
- `上传图片` 使用现有本地图片上传入口。
|
||||
2. 规范入口后方是常规参考图入口。
|
||||
- `上传常规参考图` 同样使用 Lovart 式参考图卡片,不只显示一段文字按钮。
|
||||
- 上传后的每张常规参考图以缩略图展示。
|
||||
- 每张常规参考图右下角显示大号序号,从 `1` 开始递增。
|
||||
3. 唯一文本框为 `角色设定`。
|
||||
4. 左下角展示画面比例和大小选择按钮。
|
||||
5. 右下角展示模型选择和生成按钮。
|
||||
|
||||
## 生成与参考图契约
|
||||
|
||||
- 前端提交角色生成时,使用 `POST /api/editor/images/generations`。
|
||||
- `kind` 传 `character`,用于后端日志 / 审计语义识别。
|
||||
- 角色形象规范与常规参考图作为 `referenceImageSrcs` 传入,顺序固定为:
|
||||
1. 角色形象规范图。
|
||||
2. 常规参考图列表。
|
||||
- 当前请求尺寸沿用编辑器普通生成默认值;比例和大小按钮先复用现有占位交互。
|
||||
- 后端如果收到参考图,则走带多参考图的图片编辑/参考图生成链路;没有参考图时走纯文本生成链路。
|
||||
- `kind = "character"` 时,后端不直接把前端文本当完整生图提示词,而是把文本作为 `角色设定` 填入固定提示词骨架:
|
||||
|
||||
```text
|
||||
基于图1的角色美术视觉规范指导生成游戏角色形象图。画面中心构图,角色主体完整置于画面中央,禁止镜头透视,禁止特写。背景固定为纯绿色绿幕,只作为抠像底色,禁止生成美术视觉规范、出现建筑、室内布景、风景、地面道具、漂浮物、烟雾叙事元素、文字或其他角色以外的场景内容。
|
||||
角色设定:<用户输入的角色设定>
|
||||
```
|
||||
|
||||
- 角色图生成完成后,后端必须先对返回图片执行绿幕 / 近白背景去背,并统一输出透明背景 PNG;随后写入 OSS 私有对象,并确认 `asset_object`。接口回包仍返回透明 PNG Data URL 供画板立即显示,同时返回 `objectKey` / `assetObjectId`,前端创建图层和画板资源记录时必须保存这两个字段。
|
||||
|
||||
## 可访问性与状态
|
||||
|
||||
- 点选状态下画布显示状态提示 `请选择画布中的图片作为角色形象规范,按 Esc 退出`。
|
||||
- 已绑定的角色形象规范入口显示所选图片标题。
|
||||
- 生成中禁用参考图入口、文本框和按钮。
|
||||
- 点击画布空白区域让当前占位图或图片失焦时,关闭角色生成面板并移除图片选中样式;占位图本身保持可重新打开。删除图层逻辑沿用现有图层删除能力。
|
||||
|
||||
## 验收
|
||||
|
||||
- 点击 `生成角色形象` 后出现角色占位图、角色标签和角色生成面板。
|
||||
- 角色生成面板打开时底部 AI 工具栏仍可见;点击画布空白区域后面板关闭,当前图片不再显示选中边框。
|
||||
- `角色形象规范` 与 `上传常规参考图` 入口是带预览视觉块的参考图卡片,不是无样式文字。
|
||||
- `从画布中选择` 后点击已有画布图片可绑定为角色形象规范,`Esc` 可退出点选状态。
|
||||
- 上传常规参考图后缩略图右下角显示序号。
|
||||
- 输入角色设定并生成时,请求包含 `kind: "character"`、角色设定 prompt 和参考图数组。
|
||||
- 生成成功后在占位图位置创建 `assetKind: "character"` 图层,右上角显示 `角色` 标签,布局保存包含该字段。
|
||||
|
||||
## 当前落地记录
|
||||
|
||||
- 前端画板已接入 `生成角色形象` 底部入口、角色占位图、角色面板、画布点选规范图、上传规范图、上传常规参考图和序号角标。
|
||||
- 角色生成提交统一走 `/api/editor/images/generations`,按 `角色形象规范 -> 常规参考图` 顺序传 `referenceImageSrcs`,并写入 `assetKind: "character"`。
|
||||
- 角色生成后端已按固定 prompt 骨架补入 `角色设定`,并在生成成功后自动执行绿幕去背、写入 `generated-character-drafts/editor/character-images/<taskId>/image.png` 路径下的 OSS 私有对象,返回的 `objectKey` / `assetObjectId` 会随画板资源记录保存。
|
||||
- `Esc` 只退出角色规范画布点选状态,不关闭角色生成面板。
|
||||
- 已补充回归测试覆盖角色形象生成、点选退出、角色动画入口隔离和快速编辑入口。
|
||||
- 本次验证命令:
|
||||
- `npm test -- src/components/image-editor/ImageCanvasEditorView.test.tsx`
|
||||
- `npm test -- src/services/image-editor/editorProjectClient.test.ts`
|
||||
- `npm run typecheck -- --pretty false`
|
||||
|
||||
## 角色动画生成
|
||||
|
||||
### 入口规则
|
||||
|
||||
- 仅 `assetKind: "character"` 的角色图片图层显示 `生成动画` 入口。
|
||||
- 入口同时出现在图片上方悬浮工具条和图片右键功能列表中。
|
||||
- 非角色图片不得显示 `生成动画`,也不得通过右键菜单触发角色动画生成。
|
||||
- 点击 `生成动画` 后,在角色图片右侧打开独立的 `角色动画生成面板`;面板不在当前图片下方展开。
|
||||
|
||||
### 面板字段
|
||||
|
||||
1. 第一模块为 `动画描述` 文本框,最多输入 `4000` 字。
|
||||
2. 文本框下方提供预设动作提示词按钮:`待机`、`行走`、`奔跑`、`跳跃`、`攻击`、`受击`、`倒下`。点击后把对应动作文本写入动画描述文本框。
|
||||
3. 其它设置包括:
|
||||
- 分辨率:`480p`、`720p`。
|
||||
- 画面比例:默认 `与角色图片保持同尺寸`,可选 `1:1`、`4:3`、`16:9`、`9:16`、`3:4`。
|
||||
- 时长:`32帧·4秒`、`40帧·5秒`、`48帧·6秒`。
|
||||
4. 模型固定使用 `seedance2.0`,前端不提供模型切换。
|
||||
5. 生成按钮上方显示本次生成文本摘要和生成价格:
|
||||
- `480p` 每秒 `10` 泥点。
|
||||
- `720p` 每秒 `20` 泥点。
|
||||
|
||||
### Prompt 与生成契约
|
||||
|
||||
- 前端提交到 `POST /api/editor/character-animations/generations`。
|
||||
- 请求必须带上角色图片来源、原始尺寸、动画描述、分辨率、画面比例、帧数和时长。
|
||||
- 后端使用角色图片作为首帧和尾帧参考,模型固定映射到 seedance2.0 对应后端模型。
|
||||
- 后端 prompt 使用以下固定骨架,并把面板输入追加到 `动作描述:` 后:
|
||||
|
||||
```text
|
||||
生成游戏角色动画,参考图作为首帧和尾帧,画面中心构图,角色主体完整置于画面中央,禁止镜头透视,禁止特写。背景固定为纯绿色绿幕,只作为抠像底色,禁止出现建筑、室内布景、风景、地面道具、漂浮物、烟雾叙事元素、文字或其他角色以外的场景内容。
|
||||
动作描述:
|
||||
<用户输入的动画描述>
|
||||
```
|
||||
|
||||
### 抽帧与 OSS 存储
|
||||
|
||||
- 视频生成完成后,后端按面板选择抽取对应帧数:`32`、`40` 或 `48`。
|
||||
- 每帧必须执行绿幕去背,输出透明背景 PNG。
|
||||
- 抽帧结果写入 OSS,并返回帧路径、帧尺寸、帧数、fps、预览视频路径、模型、价格和实际 prompt。
|
||||
- 画板前端首版只展示生成完成结果摘要,不把帧序列自动铺到画布上;后续若要展示逐帧图层,必须继续复用画布图层与素材库资源模型。
|
||||
|
||||
Reference in New Issue
Block a user