diff --git a/.memory/worklog.json b/.memory/worklog.json
index d3669ca..1eeec9d 100644
--- a/.memory/worklog.json
+++ b/.memory/worklog.json
@@ -1,19 +1,5 @@
{
"entries": [
- {
- "files_changed": 0,
- "hash": "",
- "message": "项目创建: SKG AI 素材管线 - TK 二创验证",
- "ts": "2026-05-12T00:00:00+08:00",
- "type": "milestone"
- },
- {
- "files_changed": 7,
- "hash": "56d435f",
- "message": "init: project scaffold",
- "ts": "2026-05-12T15:37:36+08:00",
- "type": "commit"
- },
{
"files_changed": 4,
"hash": "bbd41fa",
@@ -3361,6 +3347,19 @@
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令:codex · 2 项未提交变更 · 最近提交:auto-save 2026-05-14 05:27 (~3)",
"files_changed": 2
+ },
+ {
+ "ts": "2026-05-14T05:32:54+08:00",
+ "type": "commit",
+ "message": "auto-save 2026-05-14 05:32 (~4)",
+ "hash": "f3636a5",
+ "files_changed": 4
+ },
+ {
+ "ts": "2026-05-13T21:33:13Z",
+ "type": "session-heartbeat",
+ "message": "Claude 会话活跃 · 最近命令:claude · 2 项未提交变更 · 最近提交:auto-save 2026-05-14 05:32 (~4)",
+ "files_changed": 2
}
]
}
diff --git a/docs/source-analysis.html b/docs/source-analysis.html
index 5426efe..4921de5 100644
--- a/docs/source-analysis.html
+++ b/docs/source-analysis.html
@@ -664,7 +664,7 @@ api/main.py
KeyElement
-
从关键帧里识别或手动添加的主体候选。Vision 给的是候选,用户可编辑、删除,并可基于它生成主体资产包。
+
从关键帧识别结果里确认出来的主体候选。Vision 给的是候选,用户可编辑、删除,并可基于它生成主体资产包。
KeyElement {
id,
name_zh, name_en, position,
@@ -788,7 +788,7 @@ SubjectAsset {
手动按时间戳加关键帧。
关键帧清洗水印,全图或区域清洗。
Vision 识别关键帧,输出 scene、objects、style、suggested_prompt,并作为主体候选来源。
-
主体候选增改删、区域主体添加、主体资产包生成。
+
主体候选确认、改名、删除和主体资产包生成。
分镜工作台 4 图槽和改造说明自动保存。
nano-banana-pro image-to-image 生图。
@@ -846,8 +846,8 @@ SubjectAsset {
UX
-
问题:面板标题仍叫“关键帧详情 · 元素提取”,里面还露出普通 cutout 抠图、AI 提取、元素清单等旧流程入口;“选用此帧”也无法说明它其实是在维护目标关键帧集合。
-
改动:KeyframePanelNode 标题改为“关键帧素材准备”;FrameLightbox 的主体页改成“主体识别 / 主体清单 / 主体资产包”,移除普通抠图列表和 AI 提取按钮;“选用此帧”改为“加入目标帧 / 目标帧 · 点击移出”。VisualLabNode 上方缩略图也不再展示普通抠图分组,只展示关键帧、场景图、主体包和视频任务。
+
问题:面板标题仍叫“关键帧详情 · 元素提取”,里面还露出普通 cutout 抠图、AI 提取、元素清单等旧流程入口;“选用此帧 / 加入目标帧”也无法说明实际价值,因为抽帧阶段已经筛过图,进入画面工作台的关键帧默认就应该参与素材准备。
+
改动:KeyframePanelNode 标题改为“关键帧素材准备”;FrameLightbox 的主体页改成“主体识别 / 主体清单 / 主体资产包”,移除普通抠图列表、AI 提取按钮和详情内的目标帧开关,改为只显示“已在素材准备流程”的状态说明;VisualLabNode 上方缩略图也不再展示普通抠图分组,只展示关键帧、场景图、主体包和视频任务。
影响:web/components/lightbox.tsx、web/components/nodes/index.tsx、docs/source-analysis.html。底层旧 cutout 数据和接口暂保留兼容历史任务,但不再作为新素材准备流程的可见入口。
@@ -859,7 +859,7 @@ SubjectAsset {
问题:画面工作台从展示缩略图扩展为素材生产中枢后,关键帧、场景图、主体资产包和视频任务继续混在一个列表里会让流程不清晰;关键帧详情面板也把清洗、识别、场景和主体生成都堆在一屏。
-
改动:VisualLabNode 改成素材准备进度看板,显示目标关键帧、场景图、主体资产和分镜/视频四个入口。FrameLightbox 新增“原图/清洗、场景图、主体资产、审核”四个页签,素材审核信息从普通列表中拆出来。
+
改动:VisualLabNode 改成素材准备进度看板,显示关键帧素材、场景图、主体资产和分镜/视频四个入口。FrameLightbox 新增“原图/清洗、场景图、主体资产、审核”四个页签,素材审核信息从普通列表中拆出来。
影响:web/components/nodes/index.tsx、web/components/lightbox.tsx、docs/source-analysis.html。这轮只重排工作台信息架构,批量自动准备队列仍留到下一阶段。
diff --git a/web/components/lightbox.tsx b/web/components/lightbox.tsx
index 7d9ab54..f78d179 100644
--- a/web/components/lightbox.tsx
+++ b/web/components/lightbox.tsx
@@ -62,8 +62,6 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
const [applying, setApplying] = useState(false)
const [sceneGenerating, setSceneGenerating] = useState(false)
const [subjectGenerating, setSubjectGenerating] = useState
(null)
- const [addingZh, setAddingZh] = useState(false)
- const [addInput, setAddInput] = useState("")
const [assetSize, setAssetSize] = useState("source")
const [subjectKinds, setSubjectKinds] = useState>({})
const [subjectBackgrounds, setSubjectBackgrounds] = useState>({})
@@ -82,9 +80,6 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
const [regions, setRegions] = useState([])
const [draftRegion, setDraftRegion] = useState(null) // 当前正在拖的
const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null)
- const [subjectRegionPrompt, setSubjectRegionPrompt] = useState(false)
- const [subjectRegionName, setSubjectRegionName] = useState("")
- const [addingRegionSubject, setAddingRegionSubject] = useState(false)
const imgWrapRef = useRef(null)
useEffect(() => setMounted(true), [])
@@ -94,8 +89,6 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
setRegions([])
setDraftRegion(null)
setDragStart(null)
- setSubjectRegionPrompt(false)
- setSubjectRegionName("")
}, [activeIndex])
useEffect(() => {
@@ -201,26 +194,6 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
})
}
- const handleAddRegionSubject = async () => {
- if (regions.length !== 1 || !subjectRegionName.trim()) return
- const r = regions[0]
- setAddingRegionSubject(true)
- try {
- const added = await addElement(jobId, f.index, {
- name_zh: subjectRegionName.trim(),
- source: "region",
- region: r,
- })
- onJobUpdate?.(added)
- toast.success(`「${subjectRegionName.trim()}」已加入主体清单`)
- setCropMode(false); setRegions([]); setSubjectRegionPrompt(false); setSubjectRegionName("")
- } catch (e) {
- toast.error("添加主体失败:" + (e instanceof Error ? e.message : String(e)))
- } finally {
- setAddingRegionSubject(false)
- }
- }
-
// 画框 mouse handlers — 坐标基于 img wrapper 相对位置
const getRelXY = (clientX: number, clientY: number) => {
const el = imgWrapRef.current
@@ -284,14 +257,11 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
const handleAddElement = async (name_zh: string, name_en?: string, position?: string, source: "auto" | "manual" = "manual") => {
const zh = name_zh.trim()
if (!zh) return
- setAddingZh(true)
try {
const updated = await addElement(jobId, f.index, { name_zh: zh, name_en, position, source })
onJobUpdate?.(updated)
} catch (e) {
toast.error("加入失败:" + (e instanceof Error ? e.message : String(e)))
- } finally {
- setAddingZh(false)
}
}
@@ -472,92 +442,47 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
<>
{/* 画框工具栏 */}
{cropMode ? (
- subjectRegionPrompt ? (
-
-
setSubjectRegionName(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === "Enter" && !e.nativeEvent.isComposing && subjectRegionName.trim()) {
- e.preventDefault()
- handleAddRegionSubject()
- }
- if (e.key === "Escape") { setSubjectRegionPrompt(false); setSubjectRegionName("") }
- }}
- placeholder="给这个主体起名(如:手持产品的人)"
- className="w-full text-[11.5px] px-2 py-1.5 rounded-md bg-black/40 border border-violet-300/50 outline-none text-white placeholder:text-white/30 focus:ring-2 focus:ring-violet-400/40"
- />
-
-
-
-
+
+
+ {regions.length === 0
+ ? "在图上拖动鼠标 → 框选要清洗的水印、字幕、平台 UI 或杂物"
+ : `已框 ${regions.length} 个 · 继续加框或点击「去掉」批量清洗`}
- ) : (
-
-
- {regions.length === 0
- ? "在图上拖动鼠标 → 框选要处理的区域(可连续画多个)"
- : `已框 ${regions.length} 个 · 继续加框 · 「去掉」批量清洗 · 单框可加入主体清单`}
-
-
-
-
-
-
-
+
+
+
+
- )
+
) : (
)}
@@ -1050,34 +975,8 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
)}
- {/* 添加 */}
-
-
setAddInput(ev.target.value)}
- onKeyDown={(ev) => {
- if (ev.key === "Enter" && !ev.nativeEvent.isComposing) {
- ev.preventDefault()
- if (addInput.trim() && !addingZh) {
- handleAddElement(addInput)
- setAddInput("")
- }
- }
- }}
- placeholder="添加主体候选 · 中文回车自动翻英文"
- className="flex-1 text-[12px] px-2.5 py-1.5 rounded-md bg-black/40 border border-white/15 outline-none text-white placeholder:text-white/30 focus:ring-2 focus:ring-violet-400/40 focus:border-violet-400/40"
- />
-
-
- 主体候选会持久化保存;主体资产包和场景图准备好后,再复制到「分镜头编排」。
+ 主体候选来自识别结果;确认名称、类型和视角后生成主体资产包。