11 KiB
11 KiB
漫剧画布工作流(LibTV 式)实施计划
目标:在 LocalMiniDrama 现有
project.json/ SQLite 数据之上,增加 LibTV 风格的无限画布视图;列表模式(FilmCreate)与画布模式双视图、单数据源。
最后更新:2026-06-15(阶段 D:交互增强、媒体对齐、全能模式)
设计原则
- 真源不变:角色、分镜、图片、视频仍存现有表与
project.json结构。 - 画布是视图层:额外持久化
drama.metadata.canvas_layout(坐标、视口)与workflow_groups(工作流组)。 - 旧 JSON 兼容:无
canvas_layout时自动布局;导入/导出忽略未知 metadata 字段不影响旧版。 - 列表模式对齐:画布读取分镜图/视频/首尾帧/全能词的逻辑与
FilmCreate.vue一致(通过/images、/videosAPI +storyboardMedia.js)。 - 技术栈:Vue 3 +
@vue-flow/core^1.48(与 Element Plus / Pinia 一致)。
阶段 A:只读画布 MVP(已完成)
交付物
- 路由
/film/:id/canvas FilmCreate/DramaDetail顶部「画布模式」入口dramaCanvasAdapter.js:dramaAPI 数据 → nodes/edges 自动布局DramaCanvas.vue:平移缩放、小地图、集数筛选- 双击分镜节点 → 跳转列表模式并定位集数
阶段 B:布局持久化 + 素材侧栏交互(已完成)
交付物
- 节点可拖动,debounce 保存
metadata.canvas_layout(PUT/dramas/:id/canvas-layout) - 导出 ZIP 时
canvas_layout写入drama.metadata - 左侧素材库点击高亮关联分镜与连线
- 画布 ↔ 列表模式双向入口,保留集数筛选 query
- 分镜节点展示生成状态,生成中自动轮询刷新
阶段 C:工作流编排(整组重跑)(已完成)
交付物
- 框选 / Ctrl 多选分镜 →「创建工作流」
metadata.workflow_groups持久化(随项目导出)- 流水线配置:生图 → 生视频 → 配音(可勾选)
- 「整组重跑」按组内分镜顺序依次执行
- 分镜节点显示所属工作流标签
数据结构(实际实现)
{
"canvas_layout": {
"version": 1,
"viewport": { "x": 0, "y": 0, "zoom": 0.75 },
"nodes": { "sb:12": { "x": 360, "y": 144 } },
"updated_at": "2026-06-15T12:00:00.000Z"
},
"workflow_groups": [
{
"id": "wg-1700000000-abc123",
"title": "第一场批量",
"storyboard_ids": [12, 13, 14],
"pipeline": ["image", "video", "audio"],
"created_at": "2026-06-15T12:00:00.000Z"
}
]
}
注:早期草案中的
node_refs已改为storyboard_ids(仅存分镜 ID,媒体节点由 adapter 动态生成)。
阶段 D:交互与媒体对齐(2026-06-15,已完成)
交付物
1. 连线与布局
- 连线改为 Vue Flow 贝塞尔曲线(
type: default,curvature: 0.62) - 默认布局改为竖排:每个分镜占一行,自上而下;单行内仍为「分镜 → 媒体链」横向展开
- 分镜顺序链改为上下连接(
chain-out/chain-in锚点)
2. 节点内操作面板(无需切列表模式)
- 单击分镜 / 媒体 / 素材节点,下方展开操作面板;单击空白画布关闭
- 分镜面板:编辑动作、对白、提示词;保存 / 润色 / 生图 / 生视频 / 配音
- 媒体面板:预览 + 对应步骤重跑
- 素材面板:信息展示 + 生成参考图 + 高亮关联分镜
- 面板区域
nodrag nopan,避免与画布拖拽冲突
3. 媒体读取与列表模式对齐
useCanvasStoryboardMedia.js:进入画布时按集批量拉取/images、/videosstoryboardMedia.js:首帧 / 尾帧 / 主图 / 视频解析(对齐FilmCreate.getSbFirstImage等)- 后端
dramaService.rowToStoryboard补全first_frame_*、last_frame_*字段 - 首尾帧模式:画布展示 首帧 + 尾帧 两个图节点(
sbimg-first/sbimg-last) - 画布内生成视频时传递
first_frame_url/last_frame_url
4. 全能模式(creation_mode === 'universal')
- 不展示空的分镜图节点
- 流水线:
分镜 → 全能分镜词 → 视频(节点sbuni:{id},kinduniversal) - 分镜卡片显示「全能」徽章;操作面板编辑
universal_segment_text,隐藏生图入口
5. 框选与工作流交互修复
- Vue Flow 1.48 移除
selection-on-drag,改为:selection-key-code="true"实现左键框选 :pan-on-drag="[1, 2]":左键框选,中键/右键平移画布
默认布局规则(2026-06-15)
┌─────────────────────────────────────────────────────────────────┐
│ 顶栏:列表模式 | 集数 | 工作流条(创建/选择/整组重跑/删除) │
├──────────────┬──────────────────────────────────────────────────┤
│ 素材库 │ 第1集 │
│ 👤 角色 │ [SB#1] ─→ [文本] ─→ [首帧] ─→ [尾帧] ─→ [视频] │
│ 🏞 场景 │ [SB#2] ─→ ... (竖排,每镜一行) │
│ 🎭 道具 │ [SB#3] ─→ [全能分镜词] ─→ [视频] (全能模式) │
│ 工作流列表 │ │
└──────────────┴──────────────────────────────────────────────────┘
- 左栏(x≈48):角色 / 场景 / 道具 + 工作流列表
- 右栏(x≥360):每集标题 + 分镜竖排;单行内媒体节点横向排列
- 虚线(绿色):素材 → 分镜
- 实线(紫色/蓝):分镜 → 媒体、分镜 ↓ 分镜(顺序链)
- 曲线:所有边为贝塞尔曲线
已有
canvas_layout的项目仍使用已保存坐标;清除 metadata 中canvas_layout.nodes可恢复新默认竖排。
节点 ID 规范
| ID 格式 | 含义 |
|---|---|
char:{id} |
角色 |
scene:{id} |
场景 |
prop:{id} |
道具 |
episode:{id} |
集标题 |
drama:header |
项目标题 |
sb:{id} |
分镜 |
sbtxt:{id} |
分镜文本摘要(经典模式) |
sbuni:{id} |
全能分镜词(全能模式) |
sbimg:{id} |
分镜图(经典单图) |
sbimg-first:{id} |
首帧图(首尾帧模式) |
sbimg-last:{id} |
尾帧图(首尾帧模式) |
sbvid:{id} |
分镜视频 |
sbaud:{id}:dialogue |
对白音频 |
用户使用说明
画布基本操作
| 操作 | 效果 |
|---|---|
| 左键在空白处拖拽 | 框选多个分镜 |
| Ctrl + 点击分镜 | 多选 / 取消选择 |
| 中键 / 右键拖拽 | 平移画布 |
| 滚轮 | 缩放 |
| 单击节点 | 展开下方操作面板 |
| 单击空白 | 关闭操作面板 |
| 双击分镜 | 跳转列表模式并定位 |
| 拖动节点 | 保存布局(debounce) |
工作流(批量生成)
- 框选或 Ctrl 选中多个分镜节点(带
#N的卡片,不是媒体子节点) - 勾选步骤:生图 / 生视频 / 配音(全能模式分镜建议只勾生视频)
- 点 创建工作流,输入名称
- 在 选择工作流 下拉框(或左侧列表)选中该组
- 点 整组重跑:按组内分镜顺序依次执行;某一镜失败则停止
- 删除工作流 仅删除分组配置,不删除分镜与媒体
经典 / 首尾帧 / 全能 三种流水线展示
| 模式 | 画布媒体链 |
|---|---|
| 经典 | 文本 → 分镜图 → 视频 →(音频) |
首尾帧(metadata.storyboard_use_first_last_frame) |
文本 → 首帧 → 尾帧 → 视频 →(音频) |
全能(creation_mode: universal) |
全能分镜词 → 视频 →(音频) |
文件结构
frontweb/src/
views/DramaCanvas.vue
composables/
useCanvasContext.js # provide/inject 画布上下文
useCanvasStoryboardMedia.js # 批量加载 images/videos
useCanvasWorkflowRunner.js # 单步/整组生成(export runImageStep 等)
utils/
dramaCanvasAdapter.js # drama → Vue Flow 图
canvasLayout.js # layout 解析/持久化
canvasWorkflow.js # workflow_groups CRUD
storyboardMedia.js # 首帧/尾帧/视频 URL 解析(对齐列表模式)
mediaUrl.js
components/dramaCanvas/
CanvasAssetNode.vue
CanvasAssetPanel.vue
CanvasEpisodeNode.vue
CanvasDramaHeaderNode.vue
CanvasLabelNode.vue
CanvasStoryboardNode.vue
CanvasStoryboardPanel.vue
CanvasMediaNode.vue
CanvasMediaPanel.vue
backend-node/src/services/
dramaService.js # rowToStoryboard 含首尾帧字段
API
GET /api/v1/dramas/:id— 项目数据(含 metadata)PUT /api/v1/dramas/:id/canvas-layout— 保存canvas_layout和/或workflow_groupsGET /api/v1/images?storyboard_id=— 画布加载分镜图列表GET /api/v1/videos?storyboard_id=— 画布加载分镜视频列表
Vue Flow 配置要点
<VueFlow
:selection-key-code="true"
:pan-on-drag="[1, 2]"
:pan-on-scroll="true"
:elements-selectable="true"
/>
勿使用 已废弃的
selection-on-drag(@vue-flow/core 1.41+ 已移除,配置了也不生效)。
风险与规避
| 风险 | 规避 |
|---|---|
| 分镜过多画布过长 | 集数筛选 + fitView + 小地图 + 竖排一镜一行 |
| metadata 合并覆盖 | update 时 merge 现有 metadata |
| 画布与列表媒体不一致 | 统一走 storyboardMedia.js + images/videos API |
| 全能模式误触生图 | 全能分镜隐藏生图;工作流勾选项需用户自行判断 |
| 框选无效 | 必须在空白处拖拽;或 Ctrl 点击多选 |
| Vue Flow 包体积 | 画布路由按需加载 |
后续可选 / TODO
画布与工作流
- 全能模式画布内润色 / 流式编辑全能词
- 工作流组内分镜顺序可视化拖拽调整
- 多集同时展示时的节点虚拟化(仅渲染视口内)
- 画布内首尾帧单独生图(走 frame-prompt 模块,对齐列表模式完整能力)
- 顶栏工作流区域增加简短帮助 tooltip
场景与素材
- 场景图 → 全景图:基于已有场景参考图/背景图,AI 扩展或生成超宽/360° 全景图;可用于场景库展示、分镜大景别运镜参考,以及全能模式
@图片N的环境图;需评估与现有scenes表、generateImage/ 四视图流程的衔接方式
其他
- 分镜参考图自由上传(列表模式已有部分能力,画布侧统一入口)
- 参考图自由选择(生成分镜图时手动指定角色/场景参考)