auto-save 2026-05-14 02:30 (+2, ~4)
This commit is contained in:
@@ -2901,6 +2901,19 @@
|
||||
"type": "session-heartbeat",
|
||||
"message": "Claude 会话活跃 · 最近命令:claude · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 02:19 (~4)",
|
||||
"files_changed": 1
|
||||
},
|
||||
{
|
||||
"ts": "2026-05-14T02:25:30+08:00",
|
||||
"type": "commit",
|
||||
"message": "auto-save 2026-05-14 02:25 (~2)",
|
||||
"hash": "eace01e",
|
||||
"files_changed": 2
|
||||
},
|
||||
{
|
||||
"ts": "2026-05-13T18:28:48Z",
|
||||
"type": "session-heartbeat",
|
||||
"message": "Codex 会话活跃 · 最近命令:codex · 3 项未提交变更 · 最近提交:auto-save 2026-05-14 02:25 (~2)",
|
||||
"files_changed": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
36
.playwright-mcp/page-2026-05-13T18-29-57-259Z.yml
Normal file
36
.playwright-mcp/page-2026-05-13T18-29-57-259Z.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
- generic [active] [ref=e1]:
|
||||
- button "Open Next.js Dev Tools" [ref=e7] [cursor=pointer]:
|
||||
- img [ref=e8]
|
||||
- main [ref=e14]:
|
||||
- button "自动排版 · 保留每个节点的尺寸,重新排好间距和列布局" [ref=e16]:
|
||||
- img [ref=e17]
|
||||
- application [ref=e24]:
|
||||
- group [ref=e27]:
|
||||
- generic [ref=e29]:
|
||||
- generic [ref=e30]:
|
||||
- img [ref=e32]
|
||||
- generic [ref=e35]: 输入 · Input
|
||||
- button "钉住 · 锁定位置与尺寸" [ref=e38]:
|
||||
- img [ref=e39]
|
||||
- generic [ref=e42]:
|
||||
- generic [ref=e43]: STEP 1 · 待运行
|
||||
- textbox "粘贴 TikTok 链接" [ref=e44]
|
||||
- generic [ref=e45]:
|
||||
- button "提交链接" [disabled] [ref=e46]
|
||||
- button "上传" [ref=e47]:
|
||||
- img [ref=e48]
|
||||
- text: 上传
|
||||
- generic "拖动调整宽度" [ref=e52]
|
||||
- generic "拖动调整大小(宽 × 高)" [ref=e53]
|
||||
- img
|
||||
- generic "Control Panel" [ref=e54]:
|
||||
- button "Zoom In" [ref=e55] [cursor=pointer]:
|
||||
- img [ref=e56]
|
||||
- button "Zoom Out" [ref=e58] [cursor=pointer]:
|
||||
- img [ref=e59]
|
||||
- button "Fit View" [ref=e61] [cursor=pointer]:
|
||||
- img [ref=e62]
|
||||
- button "Toggle Interactivity" [ref=e64] [cursor=pointer]:
|
||||
- img [ref=e65]
|
||||
- img "Mini Map" [ref=e68]
|
||||
- region "Notifications alt+T"
|
||||
245
.playwright-mcp/page-2026-05-13T18-30-00-447Z.yml
Normal file
245
.playwright-mcp/page-2026-05-13T18-30-00-447Z.yml
Normal file
@@ -0,0 +1,245 @@
|
||||
- generic [active] [ref=e1]:
|
||||
- generic [ref=e6] [cursor=pointer]:
|
||||
- button "Open Next.js Dev Tools" [ref=e7]:
|
||||
- img [ref=e8]
|
||||
- generic [ref=e71]:
|
||||
- button "Open issues overlay" [ref=e72]:
|
||||
- generic [ref=e73]:
|
||||
- generic [ref=e74]: "0"
|
||||
- generic [ref=e75]: "1"
|
||||
- generic [ref=e76]: Issue
|
||||
- button "Collapse issues badge" [ref=e77]:
|
||||
- img [ref=e78]
|
||||
- main [ref=e14]:
|
||||
- button "自动排版 · 保留每个节点的尺寸,重新排好间距和列布局" [ref=e16]:
|
||||
- img [ref=e17]
|
||||
- button "切到明亮主题" [ref=e81]:
|
||||
- img [ref=e82]
|
||||
- application [ref=e24]:
|
||||
- generic [ref=e26]:
|
||||
- generic:
|
||||
- generic:
|
||||
- img:
|
||||
- group "Edge from input to visual" [ref=e88] [cursor=pointer]
|
||||
- img:
|
||||
- group "Edge from input to audio" [ref=e91] [cursor=pointer]
|
||||
- img:
|
||||
- group "Edge from visual to compose" [ref=e94] [cursor=pointer]
|
||||
- img:
|
||||
- group "Edge from audio to compose" [ref=e97] [cursor=pointer]
|
||||
- generic:
|
||||
- group [ref=e27]:
|
||||
- generic [ref=e28]:
|
||||
- generic [ref=e100]:
|
||||
- button "再上传一个视频" [ref=e101]:
|
||||
- img [ref=e102]
|
||||
- button "64.5s" [ref=e104]:
|
||||
- generic [ref=e106]: 64.5s
|
||||
- button "72.4s" [ref=e108]:
|
||||
- generic [ref=e110]: 72.4s
|
||||
- button "64.5s" [ref=e112]:
|
||||
- generic [ref=e114]: 64.5s
|
||||
- button "71.4s" [ref=e116]:
|
||||
- generic [ref=e118]: 71.4s
|
||||
- button "72.4s" [ref=e120]:
|
||||
- generic [ref=e122]: 72.4s
|
||||
- button "71.4s" [ref=e124]:
|
||||
- generic [ref=e126]: 71.4s
|
||||
- button "71.4s" [ref=e128]:
|
||||
- generic [ref=e130]: 71.4s
|
||||
- button "71.4s" [ref=e132]:
|
||||
- generic [ref=e134]: 71.4s
|
||||
- button "71.4s" [ref=e136]:
|
||||
- generic [ref=e138]: 71.4s
|
||||
- button "71.4s" [ref=e140]:
|
||||
- generic [ref=e142]: 71.4s
|
||||
- button "8.0s" [ref=e144]:
|
||||
- generic [ref=e146]: 8.0s
|
||||
- button "8.0s" [ref=e148]:
|
||||
- generic [ref=e150]: 8.0s
|
||||
- button "8.0s" [ref=e152]:
|
||||
- generic [ref=e154]: 8.0s
|
||||
- button "8.0s" [ref=e156]:
|
||||
- generic [ref=e158]: 8.0s
|
||||
- button "…" [ref=e160]:
|
||||
- img [ref=e162]
|
||||
- generic [ref=e164]: …
|
||||
- button "…" [ref=e166]:
|
||||
- img [ref=e168]
|
||||
- generic [ref=e170]: …
|
||||
- button "…" [ref=e172]:
|
||||
- img [ref=e174]
|
||||
- generic [ref=e176]: …
|
||||
- generic [ref=e29]:
|
||||
- generic [ref=e30]:
|
||||
- img [ref=e32]
|
||||
- generic [ref=e35]: 输入 · Input
|
||||
- generic [ref=e36]:
|
||||
- img [ref=e177]
|
||||
- button "钉住 · 锁定位置与尺寸" [ref=e38]:
|
||||
- img [ref=e39]
|
||||
- generic [ref=e42]:
|
||||
- generic [ref=e43]: STEP 1 · 视频就绪 · 完成
|
||||
- textbox "再加一个 TK 链接" [ref=e180]
|
||||
- generic [ref=e45]:
|
||||
- button "+ 加链接" [disabled] [ref=e181]
|
||||
- button "再传一个" [ref=e182]:
|
||||
- img [ref=e48]
|
||||
- text: 再传一个
|
||||
- generic [ref=e183]:
|
||||
- generic [ref=e184]: 1080×1920 · 64.5s
|
||||
- generic [ref=e185]: 🔗 链接
|
||||
- button "重新解析" [ref=e186]
|
||||
- generic "拖动调整宽度" [ref=e52]
|
||||
- generic "拖动调整大小(宽 × 高)" [ref=e53]
|
||||
- group [ref=e187]:
|
||||
- generic [ref=e188]:
|
||||
- generic [ref=e189]:
|
||||
- generic [ref=e190]:
|
||||
- button "分镜 10 1.66s" [ref=e191]:
|
||||
- img "分镜 10" [ref=e192]
|
||||
- generic [ref=e193]: 1.66s
|
||||
- button "📋" [ref=e194]
|
||||
- button "删除该关键帧" [ref=e195]:
|
||||
- img [ref=e196]
|
||||
- generic [ref=e199]:
|
||||
- button "分镜 1 24.73s" [ref=e200]:
|
||||
- img "分镜 1" [ref=e201]
|
||||
- generic [ref=e202]: 24.73s
|
||||
- button "📋" [ref=e203]
|
||||
- button "删除该关键帧" [ref=e204]:
|
||||
- img [ref=e205]
|
||||
- generic [ref=e208]:
|
||||
- button "分镜 2 33.61s" [ref=e209]:
|
||||
- img "分镜 2" [ref=e210]
|
||||
- generic [ref=e211]: 33.61s
|
||||
- button "📋" [ref=e212]
|
||||
- button "删除该关键帧" [ref=e213]:
|
||||
- img [ref=e214]
|
||||
- generic [ref=e217]:
|
||||
- button "分镜 3 37.70s" [ref=e218]:
|
||||
- img "分镜 3" [ref=e219]
|
||||
- generic [ref=e220]: 37.70s
|
||||
- button "📋" [ref=e221]
|
||||
- button "删除该关键帧" [ref=e222]:
|
||||
- img [ref=e223]
|
||||
- generic [ref=e226]:
|
||||
- button "分镜 4 39.42s" [ref=e227]:
|
||||
- img "分镜 4" [ref=e228]
|
||||
- generic [ref=e229]: 39.42s
|
||||
- button "📋" [ref=e230]
|
||||
- button "删除该关键帧" [ref=e231]:
|
||||
- img [ref=e232]
|
||||
- generic [ref=e235]:
|
||||
- button "分镜 5 43.13s" [ref=e236]:
|
||||
- img "分镜 5" [ref=e237]
|
||||
- generic [ref=e238]: 43.13s
|
||||
- button "📋" [ref=e239]
|
||||
- button "删除该关键帧" [ref=e240]:
|
||||
- img [ref=e241]
|
||||
- generic [ref=e244]:
|
||||
- button "分镜 6 45.05s" [ref=e245]:
|
||||
- img "分镜 6" [ref=e246]
|
||||
- generic [ref=e247]: 45.05s
|
||||
- button "📋" [ref=e248]
|
||||
- button "删除该关键帧" [ref=e249]:
|
||||
- img [ref=e250]
|
||||
- generic [ref=e253]:
|
||||
- button "分镜 7 53.60s" [ref=e254]:
|
||||
- img "分镜 7" [ref=e255]
|
||||
- generic [ref=e256]: 53.60s
|
||||
- button "📋" [ref=e257]
|
||||
- button "删除该关键帧" [ref=e258]:
|
||||
- img [ref=e259]
|
||||
- generic [ref=e262]:
|
||||
- button "分镜 8 55.96s" [ref=e263]:
|
||||
- img "分镜 8" [ref=e264]
|
||||
- generic [ref=e265]: 55.96s
|
||||
- button "📋" [ref=e266]
|
||||
- button "删除该关键帧" [ref=e267]:
|
||||
- img [ref=e268]
|
||||
- generic [ref=e271]:
|
||||
- button "分镜 9 58.39s" [ref=e272]:
|
||||
- img "分镜 9" [ref=e273]
|
||||
- generic [ref=e274]: 58.39s
|
||||
- button "📋" [ref=e275]
|
||||
- button "删除该关键帧" [ref=e276]:
|
||||
- img [ref=e277]
|
||||
- generic [ref=e280]:
|
||||
- button "透明骷髅 元素" [ref=e281]:
|
||||
- img "透明骷髅" [ref=e282]
|
||||
- generic [ref=e283]: 元素
|
||||
- button "📋" [ref=e284]
|
||||
- button "删除该提取图" [ref=e285]:
|
||||
- img [ref=e286]
|
||||
- generic [ref=e289]:
|
||||
- generic [ref=e291]:
|
||||
- img [ref=e293]
|
||||
- generic [ref=e298]: 画面工作台 · Visual Lab
|
||||
- generic [ref=e299]:
|
||||
- img [ref=e300]
|
||||
- button "钉住 · 锁定位置与尺寸" [ref=e304]:
|
||||
- img [ref=e305]
|
||||
- generic [ref=e308]:
|
||||
- generic [ref=e309]: STEP 2-7 · 10 帧 · 完成
|
||||
- generic [ref=e310]:
|
||||
- button "10 关键帧" [ref=e311]:
|
||||
- generic [ref=e312]: "10"
|
||||
- generic [ref=e313]: 关键帧
|
||||
- button "1 元素 / 编排" [ref=e314]:
|
||||
- generic [ref=e315]: "1"
|
||||
- generic [ref=e316]: 元素 / 编排
|
||||
- generic [ref=e317]:
|
||||
- generic [ref=e318]: "0"
|
||||
- generic [ref=e319]: 视频任务
|
||||
- generic [ref=e320]: 1 已清洗 · 1 已抠图 · 0/10 入编排 · 0 已完成
|
||||
- generic "拖动调整宽度" [ref=e322]
|
||||
- generic "拖动调整大小(宽 × 高)" [ref=e323]
|
||||
- group [ref=e324]:
|
||||
- generic [ref=e325]:
|
||||
- generic [ref=e327]:
|
||||
- img [ref=e329]
|
||||
- generic [ref=e332]: 音频处理 · Audio
|
||||
- button "钉住 · 锁定位置与尺寸" [ref=e335]:
|
||||
- img [ref=e336]
|
||||
- generic [ref=e339]:
|
||||
- generic [ref=e340]: STEP 3 · 待运行
|
||||
- generic [ref=e341]:
|
||||
- text: 音轨 → ASR 转录 → 英中翻译 → 接 SKG 卖点改写文案
|
||||
- text: Gemini 2.5 Flash
|
||||
- generic "拖动调整宽度" [ref=e343]
|
||||
- generic "拖动调整大小(宽 × 高)" [ref=e344]
|
||||
- group [ref=e345]:
|
||||
- generic [ref=e346]:
|
||||
- generic [ref=e348]:
|
||||
- img [ref=e350]
|
||||
- generic [ref=e354]: 合成成品 · Compose
|
||||
- button "钉住 · 锁定位置与尺寸" [ref=e357]:
|
||||
- img [ref=e358]
|
||||
- generic [ref=e361]:
|
||||
- generic [ref=e362]: STEP 8 · ffmpeg + 字幕 · 待运行
|
||||
- generic [ref=e363]:
|
||||
- text: 视频片段 + 字幕 / TTS
|
||||
- text: → 最终 mp4 输出
|
||||
- generic "拖动调整宽度" [ref=e364]
|
||||
- generic "拖动调整大小(宽 × 高)" [ref=e365]
|
||||
- img
|
||||
- generic "Control Panel" [ref=e54]:
|
||||
- button "Zoom In" [ref=e55] [cursor=pointer]:
|
||||
- img [ref=e56]
|
||||
- button "Zoom Out" [ref=e58] [cursor=pointer]:
|
||||
- img [ref=e59]
|
||||
- button "Fit View" [ref=e61] [cursor=pointer]:
|
||||
- img [ref=e62]
|
||||
- button "Toggle Interactivity" [ref=e64] [cursor=pointer]:
|
||||
- img [ref=e65]
|
||||
- img "Mini Map" [ref=e68]
|
||||
- region "Notifications alt+T":
|
||||
- list:
|
||||
- listitem [ref=e369]:
|
||||
- img [ref=e371]
|
||||
- generic [ref=e374]: 已自动排版 · 保留每个节点的尺寸
|
||||
- listitem [ref=e375]:
|
||||
- img [ref=e377]
|
||||
- generic [ref=e380]: 📥 视频已就绪 — 请点 Input 节点里的「点这里开始解析」按钮
|
||||
- alert [ref=e381]
|
||||
@@ -557,7 +557,7 @@
|
||||
<div class="step"><div class="num">4</div><h3>Vision 识别</h3><p>识别场景和候选元素,只是候选,不应锁死。</p></div>
|
||||
<div class="step"><div class="num">5</div><h3>元素提取</h3><p>编辑/新增/删除元素,对元素反复生成提取图。</p></div>
|
||||
<div class="step"><div class="num">6</div><h3>元素改造</h3><p>把参考主体、场景、动作和 SKG 产品放入分镜结构。</p></div>
|
||||
<div class="step"><div class="num">7</div><h3>生成视频</h3><p>用分镜 4 图槽、改造目标和时长调用 Seedance / Kling / Veo 3 生视频 API,结果回写到 Video Gen 节点。</p></div>
|
||||
<div class="step"><div class="num">7</div><h3>生成视频</h3><p>用分镜 4 图槽、改造目标和时长调用 Seedance / Kling / Veo 3 生视频 API,结果回写到画面工作台节点。</p></div>
|
||||
<div class="step"><div class="num">8</div><h3>合成成品</h3><p>片段、字幕、配音、转场合成最终 mp4。当前未实现。</p></div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -570,7 +570,7 @@
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td><code>web/app/page.tsx</code></td><td>产品工作台主状态:jobs、activeJobId、selectedFrames、clipboard、ReactFlow 节点和边。</td></tr>
|
||||
<tr><td><code>web/components/nodes/index.tsx</code></td><td>DAG 节点定义:Input、Keyframe、ASR、Translate、Rewrite、Storyboard、VideoGen、Compose。</td></tr>
|
||||
<tr><td><code>web/components/nodes/index.tsx</code></td><td>DAG 节点定义:Input、VisualLab、Audio、Compose、KeyframePanel;旧 Keyframe/Storyboard/VideoGen 组件保留但不再挂主画布。</td></tr>
|
||||
<tr><td><code>web/components/lightbox.tsx</code></td><td>镜头拆解和元素提取的主工作面板:清洗、识别、元素编辑、区域提取、抠图。</td></tr>
|
||||
<tr><td><code>web/components/storyboard-bar.tsx</code></td><td>顶部分镜编排条:展示选入编排的关键帧,并作为唯一分镜导航。</td></tr>
|
||||
<tr><td><code>web/components/storyboard-workbench.tsx</code></td><td>顶部分镜编排条下方的明细区:4 图槽、改造目标、时长、自动保存。</td></tr>
|
||||
@@ -595,9 +595,9 @@
|
||||
<pre>前端主链路:
|
||||
web/app/page.tsx
|
||||
-> ReactFlow 节点:web/components/nodes/index.tsx
|
||||
-> 画布内镜头拆解面板:KeyframeNode 内嵌 web/components/lightbox.tsx
|
||||
-> 顶部分镜条:web/components/storyboard-bar.tsx
|
||||
-> 分镜工作台:web/components/storyboard-workbench.tsx
|
||||
-> 主画布:Input → VisualLab / Audio → Compose
|
||||
-> 画布内镜头拆解面板:VisualLabNode 打开 keyframePanel,内嵌 web/components/lightbox.tsx
|
||||
-> 分镜工作台:web/components/storyboard-workbench.tsx(底层保留)
|
||||
-> API 契约:web/lib/api.ts
|
||||
|
||||
后端主链路:
|
||||
@@ -616,25 +616,15 @@ api/main.py
|
||||
<div><strong>适合怎么描述</strong><span>“输入/下载/视频就绪这个节点应该如何提示用户下一步”。</span></div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div><strong>你看到的区域</strong><span>镜头拆解节点上方关键帧</span></div>
|
||||
<div><strong>主要源码</strong><span><code>KeyframeNode</code> 内嵌 <code>FrameLightbox</code>;后端 <code>/frames</code>、<code>/describe</code>、<code>/cleanup</code>。</span></div>
|
||||
<div><strong>适合怎么描述</strong><span>“关键帧详情面板在无限画布上怎么展示、缩放、跟随;缩略图 hover 原尺寸预览要贴缩略图上边缘,不是贴节点卡片上边缘”。</span></div>
|
||||
<div><strong>你看到的区域</strong><span>画面工作台 · Visual Lab</span></div>
|
||||
<div><strong>主要源码</strong><span><code>VisualLabNode</code> in <code>web/components/nodes/index.tsx</code>;它汇总关键帧、元素 cutout 和视频任务缩略图。</span></div>
|
||||
<div><strong>适合怎么描述</strong><span>“画布上只保留一个视觉展示卡片;缩略图 hover 原尺寸预览贴缩略图上边缘,点击再进入镜头处理 / 分镜编排 / 视频任务操作”。</span></div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div><strong>你看到的区域</strong><span>元素列表和提取图</span></div>
|
||||
<div><strong>主要源码</strong><span><code>FrameLightbox</code>;类型 <code>KeyElement</code>;接口 <code>addElement/updateElement/deleteElement/cutoutElement/deleteCutout</code>。</span></div>
|
||||
<div><strong>适合怎么描述</strong><span>“Vision 识别出来的是候选,用户要能修正、重复提取、删除错误元素”。</span></div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div><strong>你看到的区域</strong><span>元素改造 · Storyboard 节点</span></div>
|
||||
<div><strong>主要源码</strong><span><code>StoryboardNode</code>;上方元素缩略图来自所有已提取 cutouts。</span></div>
|
||||
<div><strong>适合怎么描述</strong><span>“这里是素材入口,不是最终视频编辑器;缩略图 hover 预览仍在无限画布里,并贴当前缩略图的上边缘”。</span></div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div><strong>你看到的区域</strong><span>顶部分镜条</span></div>
|
||||
<div><strong>主要源码</strong><span><code>StoryboardBar</code>;只展示 selectedFrames,不负责提取元素。</span></div>
|
||||
<div><strong>适合怎么描述</strong><span>“选好的分镜如何按时间序组织,以及如何进入具体分镜编排”。</span></div>
|
||||
</div>
|
||||
<div class="flow-row">
|
||||
<div><strong>你看到的区域</strong><span>顶部分镜头编排下拉面板</span></div>
|
||||
<div><strong>主要源码</strong><span><code>StoryboardWorkbench</code>;保存到 <code>frame.storyboard</code>;接口 <code>PUT /storyboard</code>。</span></div>
|
||||
@@ -736,16 +726,10 @@ api/main.py
|
||||
<td><code>page.tsx</code>、<code>InputNode</code>、<code>api/main.py</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="tag orange">镜头拆解 / 元素提取</span></td>
|
||||
<td>关键帧选择、清洗、Vision 候选、元素编辑、区域提取、元素 cutout。</td>
|
||||
<td>不要把 Vision 结果当最终结论;不要点击元素就跳走。</td>
|
||||
<td><code>KeyframeNode</code>、<code>FrameLightbox</code>、元素接口</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="tag violet">元素改造 Storyboard</span></td>
|
||||
<td>展示可用元素素材,承接“参考元素 → SKG 画面”的入口。</td>
|
||||
<td>不要等同于最终视频生成;不要暗示复刻原视频。</td>
|
||||
<td><code>StoryboardNode</code>、<code>StoryboardBar</code></td>
|
||||
<td><span class="tag violet">画面工作台 Visual Lab</span></td>
|
||||
<td>在一个画布卡片里展示关键帧、元素 cutout 和视频任务;点击缩略图进入对应处理面板。</td>
|
||||
<td>不要在主卡片里堆复杂表单;主卡片只做状态总览和入口。</td>
|
||||
<td><code>VisualLabNode</code>、<code>FrameLightbox</code>、<code>StoryboardWorkbench</code>、视频任务接口</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="tag violet">分镜工作台</span></td>
|
||||
@@ -760,10 +744,10 @@ api/main.py
|
||||
<td><code>ASRNode</code>、<code>TranslateNode</code>、<code>RewriteNode</code>、ASR 接口</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="tag green">Video Gen / Compose</span></td>
|
||||
<td>承载生视频任务状态和完成后的 MP4。</td>
|
||||
<td>分镜工作台提交任务,Video Gen 节点只展示任务和结果。</td>
|
||||
<td><code>VideoGenNode</code>、<code>/storyboard/video</code>、<code>generated_videos</code></td>
|
||||
<td><span class="tag green">Video / Compose</span></td>
|
||||
<td>视频任务状态展示在 Visual Lab;Compose 承载最终合成。</td>
|
||||
<td>不要把 Compose 提前变成视频生成控制台。</td>
|
||||
<td><code>VisualLabNode</code>、<code>/storyboard/video</code>、<code>generated_videos</code>、<code>ComposeNode</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -831,6 +815,18 @@ api/main.py
|
||||
<h2>变更记录</h2>
|
||||
<p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p>
|
||||
<div class="changelog">
|
||||
<article class="change">
|
||||
<header>
|
||||
<h3>2026-05-14 · 三个视觉节点合并为画面工作台</h3>
|
||||
<span class="tag violet">VisualLab</span>
|
||||
<span class="tag blue">Canvas</span>
|
||||
</header>
|
||||
<div class="body">
|
||||
<p><strong>问题:</strong>镜头拆解、元素改造、生成视频三个卡片在主画布上占同等权重,但它们只是视觉素材状态展示和入口;真正处理都在点击后的工作台/面板中完成。</p>
|
||||
<p><strong>改动:</strong>新增 <code>VisualLabNode</code>,把关键帧、元素 cutout、视频任务缩略图合并到一个“画面工作台 · Visual Lab”卡片里;DAG 从 <code>Input → Keyframe → Storyboard → VideoGen → Compose</code> 简化为 <code>Input → VisualLab → Compose</code>,音频线仍独立。</p>
|
||||
<p><strong>影响:</strong><code>web/app/page.tsx</code>、<code>web/components/nodes/index.tsx</code>、<code>docs/source-analysis.html</code>。底层数据、接口和旧节点组件暂不删除。</p>
|
||||
</div>
|
||||
</article>
|
||||
<article class="change">
|
||||
<header>
|
||||
<h3>2026-05-14 · 修复节点右下角缩放点击偏移</h3>
|
||||
|
||||
@@ -380,3 +380,32 @@
|
||||
::-webkit-scrollbar { width: 8px; height: 8px; }
|
||||
::-webkit-scrollbar-thumb { background: var(--divider); border-radius: 4px; }
|
||||
::-webkit-scrollbar-track { background: transparent; }
|
||||
|
||||
/* 节点内缩略图浮条(横滚)专用:加粗 + 紫色高亮 + 大可拖区,避免在画布 zoom 下拖不到 */
|
||||
.react-flow__node .overflow-x-auto {
|
||||
scrollbar-color: rgba(167, 139, 250, 0.65) rgba(255, 255, 255, 0.08);
|
||||
scrollbar-width: auto;
|
||||
}
|
||||
.react-flow__node .overflow-x-auto::-webkit-scrollbar {
|
||||
height: 14px;
|
||||
}
|
||||
.react-flow__node .overflow-x-auto::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border-radius: 8px;
|
||||
margin: 0 4px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.react-flow__node .overflow-x-auto::-webkit-scrollbar-thumb {
|
||||
background: rgba(167, 139, 250, 0.55);
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.18);
|
||||
min-width: 48px;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.react-flow__node .overflow-x-auto::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(167, 139, 250, 0.85);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
.react-flow__node .overflow-x-auto::-webkit-scrollbar-thumb:active {
|
||||
background: rgba(217, 70, 239, 0.95);
|
||||
}
|
||||
|
||||
@@ -9,13 +9,11 @@ import {
|
||||
import { Toaster, toast } from "sonner"
|
||||
import { LayoutGrid } from "lucide-react"
|
||||
import {
|
||||
InputNode, KeyframeNode, AudioNode,
|
||||
StoryboardNode, VideoGenNode, ComposeNode, KeyframePanelNode,
|
||||
InputNode, VisualLabNode, AudioNode,
|
||||
ComposeNode, KeyframePanelNode,
|
||||
type NodeData,
|
||||
} from "@/components/nodes"
|
||||
import { ThemeToggle } from "@/components/theme-toggle"
|
||||
import { StoryboardBar } from "@/components/storyboard-bar"
|
||||
import { StoryboardWorkbench } from "@/components/storyboard-workbench"
|
||||
import {
|
||||
addManualFrame, analyzeJob, createJob, getJob, listJobs, uploadJob, deleteFrame, deleteGeneratedImage,
|
||||
deleteGeneratedVideo, deleteCutout, generateStoryboardVideo,
|
||||
@@ -25,10 +23,8 @@ import { VideoLightbox } from "@/components/video-lightbox"
|
||||
|
||||
const NODE_TYPES = {
|
||||
input: InputNode,
|
||||
keyframe: KeyframeNode,
|
||||
visual: VisualLabNode,
|
||||
audio: AudioNode,
|
||||
storyboard: StoryboardNode,
|
||||
videogen: VideoGenNode,
|
||||
compose: ComposeNode,
|
||||
keyframePanel: KeyframePanelNode,
|
||||
}
|
||||
@@ -36,15 +32,13 @@ const NODE_TYPES = {
|
||||
const KEYFRAME_PANEL_ID = "keyframe-detail-panel"
|
||||
|
||||
// 合并 input + download + split 为一个节点
|
||||
// 分叉:上路 input → keyframe → storyboard → videogen ↘
|
||||
// 分叉:上路 input → visual lab ↘
|
||||
// 下路 input → audio ──────────────────────────→ compose
|
||||
const LAYOUT: Array<{ id: string; type: keyof typeof NODE_TYPES; x: number; y: number; w: number }> = [
|
||||
{ id: "input", type: "input", x: 40, y: 240, w: 320 },
|
||||
{ id: "keyframe", type: "keyframe", x: 460, y: 60, w: 360 },
|
||||
{ id: "visual", type: "visual", x: 460, y: 60, w: 620 },
|
||||
{ id: "audio", type: "audio", x: 460, y: 440, w: 320 },
|
||||
{ id: "storyboard", type: "storyboard", x: 880, y: 60, w: 360 },
|
||||
{ id: "videogen", type: "videogen", x: 1260, y: 60, w: 280 },
|
||||
{ id: "compose", type: "compose", x: 1640, y: 240, w: 320 },
|
||||
{ id: "compose", type: "compose", x: 1160, y: 240, w: 320 },
|
||||
]
|
||||
|
||||
const NODE_SIZES_KEY = "skg-tk:node-sizes:v2"
|
||||
@@ -74,11 +68,9 @@ function loadNodePins(): string[] {
|
||||
}
|
||||
|
||||
const EDGES_RAW: Array<[string, string]> = [
|
||||
["input", "keyframe"],
|
||||
["input", "visual"],
|
||||
["input", "audio"],
|
||||
["keyframe", "storyboard"],
|
||||
["storyboard", "videogen"],
|
||||
["videogen", "compose"],
|
||||
["visual", "compose"],
|
||||
["audio", "compose"],
|
||||
]
|
||||
|
||||
@@ -521,9 +513,7 @@ export default function Home() {
|
||||
// 按管线列分组(顶 → 底):图层 1 输入 → 5 合成
|
||||
const COLUMNS: string[][] = [
|
||||
["input"],
|
||||
["keyframe", "audio"],
|
||||
["storyboard"],
|
||||
["videogen"],
|
||||
["visual", "audio"],
|
||||
["compose"],
|
||||
]
|
||||
const GAP_X = 80
|
||||
@@ -602,11 +592,11 @@ export default function Home() {
|
||||
|
||||
let shouldFocusNewPanel = false
|
||||
setNodes((prev) => {
|
||||
const keyframeNode = prev.find((n) => n.id === "keyframe")
|
||||
const visualNode = prev.find((n) => n.id === "visual")
|
||||
const inputNode = prev.find((n) => n.id === "input")
|
||||
const defaultPosition = {
|
||||
x: (inputNode?.position.x ?? 40) - 820,
|
||||
y: (keyframeNode?.position.y ?? 60),
|
||||
y: (visualNode?.position.y ?? 60),
|
||||
}
|
||||
const exists = prev.some((n) => n.id === KEYFRAME_PANEL_ID)
|
||||
if (exists) {
|
||||
@@ -637,7 +627,7 @@ export default function Home() {
|
||||
if (shouldFocusNewPanel) {
|
||||
window.setTimeout(() => {
|
||||
flowRef.current?.fitView?.({
|
||||
nodes: [{ id: KEYFRAME_PANEL_ID }, { id: "keyframe" }],
|
||||
nodes: [{ id: KEYFRAME_PANEL_ID }, { id: "visual" }],
|
||||
padding: 0.18,
|
||||
duration: 260,
|
||||
})
|
||||
@@ -649,11 +639,10 @@ export default function Home() {
|
||||
useEffect(() => {
|
||||
const doneOf: Record<string, boolean> = {
|
||||
input: !!job?.video_url,
|
||||
keyframe: !!job && job.frames.length > 0,
|
||||
visual: !!job && (job.frames.length > 0 || (job.generated_videos?.length ?? 0) > 0),
|
||||
asr: !!job && job.transcript.length > 0,
|
||||
translate: !!job && (job.transcript.some((s) => s.zh) ?? false),
|
||||
rewrite: !!job && (job.transcript.some((s) => s.zh) ?? false),
|
||||
storyboard: selectedFrames.size > 0,
|
||||
}
|
||||
setEdges((prev) => prev.map((e) => ({ ...e, animated: !!doneOf[e.source] })))
|
||||
}, [job, setEdges])
|
||||
|
||||
Reference in New Issue
Block a user