From 75d9ec1866eb0bf5fe8669984bd315e0c7dbeb73 Mon Sep 17 00:00:00 2001 From: kang Date: Thu, 14 May 2026 02:03:19 +0800 Subject: [PATCH] auto-save 2026-05-14 02:02 (+3, ~5) --- .memory/worklog.json | 19 ++ .../page-2026-05-13T17-57-36-343Z.yml | 320 ++++++++++++++++++ .../page-2026-05-13T18-03-03-246Z.yml | 36 ++ .../page-2026-05-13T18-03-06-345Z.yml | 300 ++++++++++++++++ docs/source-analysis.html | 16 +- web/app/page.tsx | 26 +- web/components/nodes/hover-preview.tsx | 9 +- web/components/nodes/index.tsx | 88 ++++- 8 files changed, 777 insertions(+), 37 deletions(-) create mode 100644 .playwright-mcp/page-2026-05-13T17-57-36-343Z.yml create mode 100644 .playwright-mcp/page-2026-05-13T18-03-03-246Z.yml create mode 100644 .playwright-mcp/page-2026-05-13T18-03-06-345Z.yml diff --git a/.memory/worklog.json b/.memory/worklog.json index 9ac2da5..f5a26e9 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -2830,6 +2830,25 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 01:51 (~2)", "files_changed": 1 + }, + { + "ts": "2026-05-14T01:57:34+08:00", + "type": "commit", + "message": "auto-save 2026-05-14 01:57 (+1, ~4)", + "hash": "11de581", + "files_changed": 5 + }, + { + "ts": "2026-05-13T17:58:48Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 01:57 (+1, ~4)", + "files_changed": 1 + }, + { + "ts": "2026-05-13T18:03:11Z", + "type": "session-heartbeat", + "message": "Claude 会话活跃 · 最近命令:claude · 5 项未提交变更 · 最近提交:auto-save 2026-05-14 01:57 (+1, ~4)", + "files_changed": 5 } ] } diff --git a/.playwright-mcp/page-2026-05-13T17-57-36-343Z.yml b/.playwright-mcp/page-2026-05-13T17-57-36-343Z.yml new file mode 100644 index 0000000..64305d6 --- /dev/null +++ b/.playwright-mcp/page-2026-05-13T17-57-36-343Z.yml @@ -0,0 +1,320 @@ +- generic [active] [ref=e1]: + - generic [ref=e36] [cursor=pointer]: + - button "Open Next.js Dev Tools" [ref=e37]: + - img [ref=e38] + - generic [ref=e43]: + - button "Open issues overlay" [ref=e44]: + - generic [ref=e45]: + - generic [ref=e46]: "0" + - generic [ref=e47]: "1" + - generic [ref=e48]: Issue + - button "Collapse issues badge" [ref=e49]: + - img [ref=e50] + - main [ref=e53]: + - button "自动排版 · 保留每个节点的尺寸,重新排好间距和列布局" [ref=e55]: + - img [ref=e56] + - button "切到明亮主题" [ref=e62]: + - img [ref=e63] + - generic [ref=e69]: + - generic [ref=e72]: + - generic [ref=e73]: + - img [ref=e74] + - generic [ref=e79]: 分镜头编排 + - generic [ref=e80]: 0 分镜 · 0 元素 + - generic [ref=e81]: · 组织分镜画面 → 为生成视频做准备 + - button "展开编排" [disabled] [ref=e83]: + - img [ref=e84] + - text: 展开编排 + - application [ref=e87]: + - generic [ref=e89]: + - generic: + - generic: + - img: + - group "Edge from input to keyframe" [ref=e90] [cursor=pointer] + - img: + - group "Edge from input to asr" [ref=e93] [cursor=pointer] + - img: + - group "Edge from asr to translate" [ref=e96] [cursor=pointer] + - img: + - group "Edge from translate to rewrite" [ref=e99] [cursor=pointer] + - img: + - group "Edge from keyframe to storyboard" [ref=e102] [cursor=pointer] + - img: + - group "Edge from storyboard to videogen" [ref=e105] [cursor=pointer] + - img: + - group "Edge from videogen to compose" [ref=e108] [cursor=pointer] + - img: + - group "Edge from rewrite to compose" [ref=e111] [cursor=pointer] + - generic: + - group [ref=e114]: + - generic [ref=e115]: + - generic [ref=e116]: + - button "再上传一个视频" [ref=e117]: + - img [ref=e118] + - button "64.5s" [ref=e120]: + - generic [ref=e122]: 64.5s + - button "72.4s" [ref=e124]: + - generic [ref=e126]: 72.4s + - button "64.5s" [ref=e128]: + - generic [ref=e130]: 64.5s + - button "71.4s" [ref=e132]: + - generic [ref=e134]: 71.4s + - button "72.4s" [ref=e136]: + - generic [ref=e138]: 72.4s + - button "71.4s" [ref=e140]: + - generic [ref=e142]: 71.4s + - button "71.4s" [ref=e144]: + - generic [ref=e146]: 71.4s + - button "71.4s" [ref=e148]: + - generic [ref=e150]: 71.4s + - button "71.4s" [ref=e152]: + - generic [ref=e154]: 71.4s + - button "71.4s" [ref=e156]: + - generic [ref=e158]: 71.4s + - button "8.0s" [ref=e160]: + - generic [ref=e162]: 8.0s + - button "8.0s" [ref=e164]: + - generic [ref=e166]: 8.0s + - button "8.0s" [ref=e168]: + - generic [ref=e170]: 8.0s + - button "8.0s" [ref=e172]: + - generic [ref=e174]: 8.0s + - button "…" [ref=e176]: + - img [ref=e178] + - generic [ref=e180]: … + - button "…" [ref=e182]: + - img [ref=e184] + - generic [ref=e186]: … + - button "…" [ref=e188]: + - img [ref=e190] + - generic [ref=e192]: … + - generic: + - generic: + - generic: + - generic: 1080×1920 + - generic: 64.5s + - generic [ref=e193]: + - generic [ref=e194]: + - img [ref=e196] + - generic [ref=e199]: 输入 · Input + - generic [ref=e200]: + - img [ref=e201] + - button "钉住 · 锁定位置与尺寸" [ref=e205]: + - img [ref=e206] + - generic [ref=e209]: + - generic [ref=e210]: STEP 1 · 视频就绪 · 完成 + - textbox "再加一个 TK 链接" [ref=e211] + - generic [ref=e212]: + - button "+ 加链接" [disabled] [ref=e213] + - button "再传一个" [ref=e214]: + - img [ref=e215] + - text: 再传一个 + - generic [ref=e218]: + - generic [ref=e219]: 1080×1920 · 64.5s + - generic [ref=e220]: 🔗 链接 + - button "重新解析" [ref=e221] + - generic "拖动调整宽度" [ref=e223] + - generic "拖动调整大小(宽 × 高)" [ref=e224] + - group [ref=e225]: + - generic [ref=e226]: + - generic [ref=e227]: + - generic [ref=e228]: + - button "frame 9 1.7s" [ref=e229]: + - img "frame 9" [ref=e230] + - generic [ref=e231]: 1.7s + - button "📋" [ref=e232] + - button "删除该关键帧" [ref=e233]: + - img [ref=e234] + - generic [ref=e237]: + - button "frame 0 ✨ 24.7s" [ref=e238]: + - img "frame 0" [ref=e239] + - generic "已清洗" [ref=e241]: ✨ + - generic [ref=e242]: 24.7s + - button "📋" [ref=e243] + - button "删除该关键帧" [ref=e244]: + - img [ref=e245] + - generic [ref=e248]: + - button "frame 1 33.6s" [ref=e249]: + - img "frame 1" [ref=e250] + - generic [ref=e251]: 33.6s + - button "📋" [ref=e252] + - button "删除该关键帧" [ref=e253]: + - img [ref=e254] + - generic [ref=e257]: + - button "frame 2 37.7s" [ref=e258]: + - img "frame 2" [ref=e259] + - generic [ref=e260]: 37.7s + - button "📋" [ref=e261] + - button "删除该关键帧" [ref=e262]: + - img [ref=e263] + - generic [ref=e266]: + - button "frame 3 39.4s" [ref=e267]: + - img "frame 3" [ref=e268] + - generic [ref=e269]: 39.4s + - button "📋" [ref=e270] + - button "删除该关键帧" [ref=e271]: + - img [ref=e272] + - generic [ref=e275]: + - button "frame 4 1 43.1s" [ref=e276]: + - img "frame 4" [ref=e277] + - generic "1 个元素已抠图" [ref=e279]: "1" + - generic [ref=e280]: 43.1s + - button "📋" [ref=e281] + - button "删除该关键帧" [ref=e282]: + - img [ref=e283] + - generic [ref=e286]: + - button "frame 5 45.0s" [ref=e287]: + - img "frame 5" [ref=e288] + - generic [ref=e289]: 45.0s + - button "📋" [ref=e290] + - button "删除该关键帧" [ref=e291]: + - img [ref=e292] + - generic [ref=e295]: + - button "frame 6 53.6s" [ref=e296]: + - img "frame 6" [ref=e297] + - generic [ref=e298]: 53.6s + - button "📋" [ref=e299] + - button "删除该关键帧" [ref=e300]: + - img [ref=e301] + - generic [ref=e304]: + - button "frame 7 56.0s" [ref=e305]: + - img "frame 7" [ref=e306] + - generic [ref=e307]: 56.0s + - button "📋" [ref=e308] + - button "删除该关键帧" [ref=e309]: + - img [ref=e310] + - generic [ref=e313]: + - button "frame 8 58.4s" [ref=e314]: + - img "frame 8" [ref=e315] + - generic [ref=e316]: 58.4s + - button "📋" [ref=e317] + - button "删除该关键帧" [ref=e318]: + - img [ref=e319] + - generic [ref=e322]: + - generic [ref=e324]: + - img [ref=e326] + - generic [ref=e330]: 镜头拆解 · 元素提取 + - generic [ref=e331]: + - img [ref=e332] + - button "钉住 · 锁定位置与尺寸" [ref=e336]: + - img [ref=e337] + - generic [ref=e340]: + - generic [ref=e341]: STEP 2 · 0/10 入编排 · 完成 + - generic [ref=e342]: + - text: 自动 10 张 · + - generic [ref=e343]: 1 已清洗 + - text: · + - generic [ref=e344]: 1/2 已抠图 + - text: 点缩略图 → 清洗水印 / 提取可借鉴元素 → 改造成 SKG 画面素材 + - generic "拖动调整宽度" [ref=e346] + - generic "拖动调整大小(宽 × 高)" [ref=e347] + - group [ref=e348]: + - generic [ref=e349]: + - generic [ref=e351]: + - img [ref=e353] + - generic [ref=e356]: 声音文案 · ASR + - button "钉住 · 锁定位置与尺寸" [ref=e359]: + - img [ref=e360] + - generic [ref=e363]: + - generic [ref=e364]: STEP 3 · 可选文案轨 · 待运行 + - generic [ref=e365]: Gemini 2.5 · 英文带时间戳分段 + - generic "拖动调整宽度" [ref=e367] + - generic "拖动调整大小(宽 × 高)" [ref=e368] + - group [ref=e369]: + - generic [ref=e370]: + - generic [ref=e372]: + - img [ref=e374] + - generic [ref=e378]: 翻译理解 · Translate + - button "钉住 · 锁定位置与尺寸" [ref=e381]: + - img [ref=e382] + - generic [ref=e385]: + - generic [ref=e386]: STEP 4 · EN → ZH · 待运行 + - generic [ref=e387]: 中文翻译 · 段落级 · 实时输出 + - generic "拖动调整宽度" [ref=e389] + - generic "拖动调整大小(宽 × 高)" [ref=e390] + - group [ref=e391]: + - generic [ref=e392]: + - generic [ref=e394]: + - button "透明骷髅" [ref=e395]: + - img "透明骷髅" [ref=e396] + - button "📋" [ref=e397] + - button "删除该提取图" [ref=e398]: + - img [ref=e399] + - generic [ref=e402]: + - generic [ref=e404]: + - img [ref=e406] + - generic [ref=e411]: 元素改造 · Storyboard + - generic [ref=e412]: + - img [ref=e413] + - button "钉住 · 锁定位置与尺寸" [ref=e417]: + - img [ref=e418] + - generic [ref=e421]: + - generic [ref=e422]: STEP 6 · 参考元素 → SKG 画面 · 完成 + - generic [ref=e423]: + - text: 不是复刻原视频:先把参考图里的主体 / 场景 / 动作 / 道具拆出来,再替换成 SKG 产品画面。 + - generic [ref=e424]: 已有 1 个提取元素 · 0 个分镜进入编排 + - button "进入分镜编排" [disabled] [ref=e425] + - generic "拖动调整宽度" [ref=e427] + - generic "拖动调整大小(宽 × 高)" [ref=e428] + - group [ref=e429]: + - generic [ref=e430]: + - generic [ref=e432]: + - img [ref=e434] + - generic [ref=e438]: 产品文案 · Rewrite + - button "钉住 · 锁定位置与尺寸" [ref=e441]: + - img [ref=e442] + - generic [ref=e445]: + - generic [ref=e446]: STEP 5 · 接 SKG 卖点 · 待运行 + - textbox "粘贴 SKG 产品信息 / 关键卖点(可作为视频脚本和镜头动作参考)" [disabled] [ref=e447] + - generic [ref=e448]: 下一冲刺接入 + - generic "拖动调整宽度" [ref=e450] + - generic "拖动调整大小(宽 × 高)" [ref=e451] + - group [ref=e452]: + - generic [ref=e454]: + - generic [ref=e456]: + - img [ref=e458] + - generic [ref=e460]: 生成视频 · Video Gen + - button "钉住 · 锁定位置与尺寸" [ref=e463]: + - img [ref=e464] + - generic [ref=e467]: + - generic [ref=e468]: STEP 7 · 首帧 + 动作 prompt · 待运行 + - generic [ref=e469]: + - generic [ref=e470]: Seedance + - generic [ref=e471]: Kling + - generic [ref=e472]: Veo 3 + - generic "拖动调整宽度" [ref=e474] + - generic "拖动调整大小(宽 × 高)" [ref=e475] + - group [ref=e476]: + - generic [ref=e477]: + - generic [ref=e479]: + - img [ref=e481] + - generic [ref=e485]: 合成成品 · Compose + - button "钉住 · 锁定位置与尺寸" [ref=e488]: + - img [ref=e489] + - generic [ref=e492]: + - generic [ref=e493]: STEP 8 · ffmpeg + 字幕 · 待运行 + - generic [ref=e494]: + - text: 视频片段 + 字幕 / TTS + - text: → 最终 mp4 输出 + - generic "拖动调整宽度" [ref=e495] + - generic "拖动调整大小(宽 × 高)" [ref=e496] + - img + - generic "Control Panel" [ref=e497]: + - button "Zoom In" [ref=e498] [cursor=pointer]: + - img [ref=e499] + - button "Zoom Out" [ref=e501] [cursor=pointer]: + - img [ref=e502] + - button "Fit View" [ref=e504] [cursor=pointer]: + - img [ref=e505] + - button "Toggle Interactivity" [ref=e507] [cursor=pointer]: + - img [ref=e508] + - img "Mini Map" [ref=e511] + - region "Notifications alt+T": + - list: + - listitem [ref=e521]: + - img [ref=e523] + - generic [ref=e526]: 已自动排版 · 保留每个节点的尺寸 + - listitem [ref=e527]: + - img [ref=e529] + - generic [ref=e532]: 📥 视频已就绪 — 请点 Input 节点里的「点这里开始解析」按钮 + - alert [ref=e533] \ No newline at end of file diff --git a/.playwright-mcp/page-2026-05-13T18-03-03-246Z.yml b/.playwright-mcp/page-2026-05-13T18-03-03-246Z.yml new file mode 100644 index 0000000..151684a --- /dev/null +++ b/.playwright-mcp/page-2026-05-13T18-03-03-246Z.yml @@ -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" \ No newline at end of file diff --git a/.playwright-mcp/page-2026-05-13T18-03-06-345Z.yml b/.playwright-mcp/page-2026-05-13T18-03-06-345Z.yml new file mode 100644 index 0000000..76d928a --- /dev/null +++ b/.playwright-mcp/page-2026-05-13T18-03-06-345Z.yml @@ -0,0 +1,300 @@ +- 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] + - generic [ref=e22]: + - generic [ref=e90]: + - generic [ref=e91]: + - img [ref=e92] + - generic [ref=e97]: 分镜头编排 + - generic [ref=e98]: 0 分镜 · 0 元素 + - generic [ref=e99]: · 组织分镜画面 → 为生成视频做准备 + - button "展开编排" [disabled] [ref=e101]: + - img [ref=e102] + - text: 展开编排 + - application [ref=e24]: + - generic [ref=e26]: + - generic: + - generic: + - img: + - group "Edge from input to keyframe" [ref=e104] [cursor=pointer] + - img: + - group "Edge from input to audio" [ref=e107] [cursor=pointer] + - img: + - group "Edge from keyframe to storyboard" [ref=e110] [cursor=pointer] + - img: + - group "Edge from storyboard to videogen" [ref=e113] [cursor=pointer] + - img: + - group "Edge from videogen to compose" [ref=e116] [cursor=pointer] + - img: + - group "Edge from audio to compose" [ref=e119] [cursor=pointer] + - generic: + - group [ref=e27]: + - generic [ref=e28]: + - generic [ref=e122]: + - button "再上传一个视频" [ref=e123]: + - img [ref=e124] + - button "64.5s" [ref=e126]: + - generic [ref=e128]: 64.5s + - button "72.4s" [ref=e130]: + - generic [ref=e132]: 72.4s + - button "64.5s" [ref=e134]: + - generic [ref=e136]: 64.5s + - button "71.4s" [ref=e138]: + - generic [ref=e140]: 71.4s + - button "72.4s" [ref=e142]: + - generic [ref=e144]: 72.4s + - button "71.4s" [ref=e146]: + - generic [ref=e148]: 71.4s + - button "71.4s" [ref=e150]: + - generic [ref=e152]: 71.4s + - button "71.4s" [ref=e154]: + - generic [ref=e156]: 71.4s + - button "71.4s" [ref=e158]: + - generic [ref=e160]: 71.4s + - button "71.4s" [ref=e162]: + - generic [ref=e164]: 71.4s + - button "8.0s" [ref=e166]: + - generic [ref=e168]: 8.0s + - button "8.0s" [ref=e170]: + - generic [ref=e172]: 8.0s + - button "8.0s" [ref=e174]: + - generic [ref=e176]: 8.0s + - button "8.0s" [ref=e178]: + - generic [ref=e180]: 8.0s + - button "…" [ref=e182]: + - img [ref=e184] + - generic [ref=e186]: … + - button "…" [ref=e188]: + - img [ref=e190] + - generic [ref=e192]: … + - button "…" [ref=e194]: + - img [ref=e196] + - generic [ref=e198]: … + - generic: + - generic: + - generic: + - generic: 1080×1920 + - generic: 64.5s + - generic [ref=e29]: + - generic [ref=e30]: + - img [ref=e32] + - generic [ref=e35]: 输入 · Input + - generic [ref=e36]: + - img [ref=e199] + - button "钉住 · 锁定位置与尺寸" [ref=e38]: + - img [ref=e39] + - generic [ref=e42]: + - generic [ref=e43]: STEP 1 · 视频就绪 · 完成 + - textbox "再加一个 TK 链接" [ref=e202] + - generic [ref=e45]: + - button "+ 加链接" [disabled] [ref=e203] + - button "再传一个" [ref=e204]: + - img [ref=e48] + - text: 再传一个 + - generic [ref=e205]: + - generic [ref=e206]: 1080×1920 · 64.5s + - generic [ref=e207]: 🔗 链接 + - button "重新解析" [ref=e208] + - generic "拖动调整宽度" [ref=e52] + - generic "拖动调整大小(宽 × 高)" [ref=e53] + - group [ref=e209]: + - generic [ref=e210]: + - generic [ref=e211]: + - generic [ref=e212]: + - button "frame 9 1.7s" [ref=e213]: + - img "frame 9" [ref=e214] + - generic [ref=e215]: 1.7s + - button "📋" [ref=e216] + - button "删除该关键帧" [ref=e217]: + - img [ref=e218] + - generic [ref=e221]: + - button "frame 0 ✨ 24.7s" [ref=e222]: + - img "frame 0" [ref=e223] + - generic "已清洗" [ref=e225]: ✨ + - generic [ref=e226]: 24.7s + - button "📋" [ref=e227] + - button "删除该关键帧" [ref=e228]: + - img [ref=e229] + - generic [ref=e232]: + - button "frame 1 33.6s" [ref=e233]: + - img "frame 1" [ref=e234] + - generic [ref=e235]: 33.6s + - button "📋" [ref=e236] + - button "删除该关键帧" [ref=e237]: + - img [ref=e238] + - generic [ref=e241]: + - button "frame 2 37.7s" [ref=e242]: + - img "frame 2" [ref=e243] + - generic [ref=e244]: 37.7s + - button "📋" [ref=e245] + - button "删除该关键帧" [ref=e246]: + - img [ref=e247] + - generic [ref=e250]: + - button "frame 3 39.4s" [ref=e251]: + - img "frame 3" [ref=e252] + - generic [ref=e253]: 39.4s + - button "📋" [ref=e254] + - button "删除该关键帧" [ref=e255]: + - img [ref=e256] + - generic [ref=e259]: + - button "frame 4 1 43.1s" [ref=e260]: + - img "frame 4" [ref=e261] + - generic "1 个元素已抠图" [ref=e263]: "1" + - generic [ref=e264]: 43.1s + - button "📋" [ref=e265] + - button "删除该关键帧" [ref=e266]: + - img [ref=e267] + - generic [ref=e270]: + - button "frame 5 45.0s" [ref=e271]: + - img "frame 5" [ref=e272] + - generic [ref=e273]: 45.0s + - button "📋" [ref=e274] + - button "删除该关键帧" [ref=e275]: + - img [ref=e276] + - generic [ref=e279]: + - button "frame 6 53.6s" [ref=e280]: + - img "frame 6" [ref=e281] + - generic [ref=e282]: 53.6s + - button "📋" [ref=e283] + - button "删除该关键帧" [ref=e284]: + - img [ref=e285] + - generic [ref=e288]: + - button "frame 7 56.0s" [ref=e289]: + - img "frame 7" [ref=e290] + - generic [ref=e291]: 56.0s + - button "📋" [ref=e292] + - button "删除该关键帧" [ref=e293]: + - img [ref=e294] + - generic [ref=e297]: + - button "frame 8 58.4s" [ref=e298]: + - img "frame 8" [ref=e299] + - generic [ref=e300]: 58.4s + - button "📋" [ref=e301] + - button "删除该关键帧" [ref=e302]: + - img [ref=e303] + - generic [ref=e306]: + - generic [ref=e308]: + - img [ref=e310] + - generic [ref=e314]: 镜头拆解 · 元素提取 + - generic [ref=e315]: + - img [ref=e316] + - button "钉住 · 锁定位置与尺寸" [ref=e320]: + - img [ref=e321] + - generic [ref=e324]: + - generic [ref=e325]: STEP 2 · 0/10 入编排 · 完成 + - generic [ref=e326]: + - text: 自动 10 张 · + - generic [ref=e327]: 1 已清洗 + - text: · + - generic [ref=e328]: 1/2 已抠图 + - text: 点缩略图 → 清洗水印 / 提取可借鉴元素 → 改造成 SKG 画面素材 + - generic "拖动调整宽度" [ref=e330] + - generic "拖动调整大小(宽 × 高)" [ref=e331] + - group [ref=e332]: + - generic [ref=e333]: + - generic [ref=e335]: + - img [ref=e337] + - generic [ref=e340]: 音频处理 · Audio + - button "钉住 · 锁定位置与尺寸" [ref=e343]: + - img [ref=e344] + - generic [ref=e347]: + - generic [ref=e348]: STEP 3 · ASR + 翻译 + 改写 · 待运行 + - generic [ref=e349]: + - generic [ref=e350]: + - generic [ref=e351]: ASR · 英文转录 + - generic [ref=e352]: Gemini 2.5 · 带时间戳分段 + - generic [ref=e353]: + - generic [ref=e354]: 翻译 · EN → ZH + - generic [ref=e355]: 中文翻译 · 段落级 · 实时输出 + - generic [ref=e356]: + - generic [ref=e357]: 产品文案 · Rewrite + - textbox "粘贴 SKG 产品信息 / 关键卖点(可作为视频脚本和镜头动作参考)" [disabled] [ref=e358] + - generic "拖动调整宽度" [ref=e360] + - generic "拖动调整大小(宽 × 高)" [ref=e361] + - group [ref=e362]: + - generic [ref=e363]: + - generic [ref=e365]: + - button "透明骷髅" [ref=e366]: + - img "透明骷髅" [ref=e367] + - button "📋" [ref=e368] + - button "删除该提取图" [ref=e369]: + - img [ref=e370] + - generic [ref=e373]: + - generic [ref=e375]: + - img [ref=e377] + - generic [ref=e382]: 元素改造 · Storyboard + - generic [ref=e383]: + - img [ref=e384] + - button "钉住 · 锁定位置与尺寸" [ref=e388]: + - img [ref=e389] + - generic [ref=e392]: + - generic [ref=e393]: STEP 6 · 参考元素 → SKG 画面 · 完成 + - generic [ref=e394]: + - text: 不是复刻原视频:先把参考图里的主体 / 场景 / 动作 / 道具拆出来,再替换成 SKG 产品画面。 + - generic [ref=e395]: 已有 1 个提取元素 · 0 个分镜进入编排 + - button "进入分镜编排" [disabled] [ref=e396] + - generic "拖动调整宽度" [ref=e398] + - generic "拖动调整大小(宽 × 高)" [ref=e399] + - group [ref=e400]: + - generic [ref=e402]: + - generic [ref=e404]: + - img [ref=e406] + - generic [ref=e408]: 生成视频 · Video Gen + - button "钉住 · 锁定位置与尺寸" [ref=e411]: + - img [ref=e412] + - generic [ref=e415]: + - generic [ref=e416]: STEP 7 · 首帧 + 动作 prompt · 待运行 + - generic [ref=e417]: + - generic [ref=e418]: Seedance + - generic [ref=e419]: Kling + - generic [ref=e420]: Veo 3 + - generic "拖动调整宽度" [ref=e422] + - generic "拖动调整大小(宽 × 高)" [ref=e423] + - group [ref=e424]: + - generic [ref=e425]: + - generic [ref=e427]: + - img [ref=e429] + - generic [ref=e433]: 合成成品 · Compose + - button "钉住 · 锁定位置与尺寸" [ref=e436]: + - img [ref=e437] + - generic [ref=e440]: + - generic [ref=e441]: STEP 8 · ffmpeg + 字幕 · 待运行 + - generic [ref=e442]: + - text: 视频片段 + 字幕 / TTS + - text: → 最终 mp4 输出 + - generic "拖动调整宽度" [ref=e443] + - generic "拖动调整大小(宽 × 高)" [ref=e444] + - 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=e450]: + - img [ref=e452] + - generic [ref=e455]: 已自动排版 · 保留每个节点的尺寸 + - listitem [ref=e456]: + - img [ref=e458] + - generic [ref=e461]: 📥 视频已就绪 — 请点 Input 节点里的「点这里开始解析」按钮 + - alert [ref=e462] \ No newline at end of file diff --git a/docs/source-analysis.html b/docs/source-analysis.html index 2ccc55a..6105b7f 100644 --- a/docs/source-analysis.html +++ b/docs/source-analysis.html @@ -618,7 +618,7 @@ api/main.py
你看到的区域镜头拆解节点上方关键帧
主要源码KeyframeNode 内嵌 FrameLightbox;后端 /frames/describe/cleanup
-
适合怎么描述“关键帧详情面板在无限画布上怎么展示、缩放、跟随,以及清洗/识别/元素提取的操作顺序”。
+
适合怎么描述“关键帧详情面板在无限画布上怎么展示、缩放、跟随;缩略图 hover 原尺寸预览要贴缩略图上边缘,不是贴节点卡片上边缘”。
你看到的区域元素列表和提取图
@@ -628,7 +628,7 @@ api/main.py
你看到的区域元素改造 · Storyboard 节点
主要源码StoryboardNode;上方元素缩略图来自所有已提取 cutouts。
-
适合怎么描述“这里是素材入口,不是最终视频编辑器;点击是否进入工作台要不要打断当前任务”。
+
适合怎么描述“这里是素材入口,不是最终视频编辑器;缩略图 hover 预览仍在无限画布里,并贴当前缩略图的上边缘”。
你看到的区域顶部分镜条
@@ -831,6 +831,18 @@ api/main.py

变更记录

这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。

+
+
+

2026-05-14 · 缩略图 hover 原尺寸预览贴缩略图上边缘

+ Canvas + HoverPreview +
+
+

问题:用户要的是“鼠标停在卡片缩略图上时,原尺寸图片/视频在该缩略图上方边缘展示,并且仍属于无限画布”;不能贴节点卡片上边缘,也不能放到页面 fixed 层。

+

改动:HoverPreview 增加缩略图锚点坐标,预览层仍渲染在 ReactFlow 节点 DOM 内,但用缩略图的中心 x 和 top y 定位,预览底边贴缩略图上边缘;Input 视频、镜头拆解关键帧、元素改造 cutout、生成视频缩略图统一走该逻辑。

+

影响:web/components/nodes/hover-preview.tsxweb/components/nodes/index.tsxdocs/source-analysis.html

+
+

2026-05-13 · 打开应用自动恢复历史 job

diff --git a/web/app/page.tsx b/web/app/page.tsx index cebcbe0..e3274b0 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -9,8 +9,8 @@ import { import { Toaster, toast } from "sonner" import { LayoutGrid } from "lucide-react" import { - InputNode, KeyframeNode, ASRNode, - TranslateNode, RewriteNode, StoryboardNode, VideoGenNode, ComposeNode, KeyframePanelNode, + InputNode, KeyframeNode, AudioNode, + StoryboardNode, VideoGenNode, ComposeNode, KeyframePanelNode, type NodeData, } from "@/components/nodes" import { ThemeToggle } from "@/components/theme-toggle" @@ -26,9 +26,7 @@ import { VideoLightbox } from "@/components/video-lightbox" const NODE_TYPES = { input: InputNode, keyframe: KeyframeNode, - asr: ASRNode, - translate: TranslateNode, - rewrite: RewriteNode, + audio: AudioNode, storyboard: StoryboardNode, videogen: VideoGenNode, compose: ComposeNode, @@ -39,14 +37,12 @@ const KEYFRAME_PANEL_ID = "keyframe-detail-panel" // 合并 input + download + split 为一个节点 // 分叉:上路 input → keyframe → storyboard → videogen ↘ -// 下路 input → asr → translate → rewrite ──────→ storyboard / compose +// 下路 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: "asr", type: "asr", x: 460, y: 440, w: 320 }, - { id: "translate", type: "translate", x: 840, y: 440, w: 320 }, + { id: "audio", type: "audio", x: 460, y: 440, w: 320 }, { id: "storyboard", type: "storyboard", x: 880, y: 60, w: 360 }, - { id: "rewrite", type: "rewrite", x: 1220, y: 440, w: 320 }, { id: "videogen", type: "videogen", x: 1260, y: 60, w: 280 }, { id: "compose", type: "compose", x: 1640, y: 240, w: 320 }, ] @@ -79,13 +75,11 @@ function loadNodePins(): string[] { const EDGES_RAW: Array<[string, string]> = [ ["input", "keyframe"], - ["input", "asr"], - ["asr", "translate"], - ["translate", "rewrite"], + ["input", "audio"], ["keyframe", "storyboard"], ["storyboard", "videogen"], ["videogen", "compose"], - ["rewrite", "compose"], + ["audio", "compose"], ] export default function Home() { @@ -527,9 +521,9 @@ export default function Home() { // 按管线列分组(顶 → 底):图层 1 输入 → 5 合成 const COLUMNS: string[][] = [ ["input"], - ["keyframe", "asr"], - ["storyboard", "translate"], - ["videogen", "rewrite"], + ["keyframe", "audio"], + ["storyboard"], + ["videogen"], ["compose"], ] const GAP_X = 80 diff --git a/web/components/nodes/hover-preview.tsx b/web/components/nodes/hover-preview.tsx index 5457aaa..b3d8179 100644 --- a/web/components/nodes/hover-preview.tsx +++ b/web/components/nodes/hover-preview.tsx @@ -3,7 +3,7 @@ import { X } from "lucide-react" /** * 视觉类节点统一大预览: - * - **在 ReactFlow 节点 DOM 内**作为 absolute 元素,贴节点卡片上边缘 + * - **在 ReactFlow 节点 DOM 内**作为 absolute 元素,底边贴当前缩略图上方边缘 * - 跟随 ReactFlow 画布 pan/zoom 一起变化(属于"无限画布"的一部分) * - 媒体按"自然像素分辨率"渲染,不做 max 尺寸限制 * - 不 pinned 时:pointer-events-none,依赖调用方传入 visible @@ -20,6 +20,7 @@ interface Props { borderClass?: string visible?: boolean anchorX?: number + anchorY?: number pinned?: boolean onClose?: () => void } @@ -30,6 +31,7 @@ export function HoverPreview({ borderClass = "border-violet-300/55", visible = false, anchorX, + anchorY, pinned = false, onClose, }: Props) { @@ -41,9 +43,10 @@ export function HoverPreview({
diff --git a/web/components/nodes/index.tsx b/web/components/nodes/index.tsx index 5f85f59..a86e15c 100644 --- a/web/components/nodes/index.tsx +++ b/web/components/nodes/index.tsx @@ -85,15 +85,19 @@ function asrStatus(job: Job | null): NodeStatus { return "pending" } -type PreviewAnchor = { id: T; x: number } +type PreviewAnchor = { id: T; x: number; y: number } -function canvasAnchorX(root: HTMLDivElement | null, target: HTMLElement) { - if (!root) return 160 +function canvasThumbnailAnchor(root: HTMLDivElement | null, target: HTMLElement) { + if (!root) return { x: 160, y: 0 } const rootRect = root.getBoundingClientRect() const targetRect = target.getBoundingClientRect() - if (rootRect.width <= 0) return root.clientWidth / 2 - const ratio = (targetRect.left + targetRect.width / 2 - rootRect.left) / rootRect.width - return ratio * root.clientWidth + if (rootRect.width <= 0 || rootRect.height <= 0) return { x: root.clientWidth / 2, y: 0 } + const xRatio = (targetRect.left + targetRect.width / 2 - rootRect.left) / rootRect.width + const yRatio = (targetRect.top - rootRect.top) / rootRect.height + return { + x: xRatio * root.clientWidth, + y: yRatio * root.clientHeight, + } } /* ============================================================ @@ -162,7 +166,7 @@ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | an isActive ? "border-violet-400 ring-2 ring-violet-400/60" : "border-white/25" }`} style={{ height: 160, aspectRatio: aspectStr }} - onMouseEnter={(e) => setHoverPreviewJob({ id: j.id, x: canvasAnchorX(rootRef.current, e.currentTarget) })} + onMouseEnter={(e) => setHoverPreviewJob({ id: j.id, ...canvasThumbnailAnchor(rootRef.current, e.currentTarget) })} onMouseLeave={() => setHoverPreviewJob(null)} >