From 9ad5d69bec38ee9d08853248a916b47b4118e7f2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Apr 2026 11:27:53 +0800 Subject: [PATCH] align grid split with reference workflow --- .../canvas/LiblibVideoCanvasReplica.tsx | 29 ++++++------------- lib/video-canvas/config.ts | 9 ++++-- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/components/canvas/LiblibVideoCanvasReplica.tsx b/components/canvas/LiblibVideoCanvasReplica.tsx index c55e6351e..259ef1a09 100644 --- a/components/canvas/LiblibVideoCanvasReplica.tsx +++ b/components/canvas/LiblibVideoCanvasReplica.tsx @@ -1173,7 +1173,7 @@ function createNineGridCompositeNode({ nineGridCells: Array.from({ length: cellCount }).map((_, index) => getGridCellVisual(index)), nineGridComposite: true, nodeType: "image", - outputSizeLabel: cellCount === 9 ? "2752 × 1536" : "", + outputSizeLabel: "2752 × 1536", params: { columns, functionKey, @@ -1810,7 +1810,7 @@ function normalizeGridSplitState(value: unknown): GridSplitState | null { rects, rows, selectedIndices, - sourceMode: String(record.sourceMode || "detected-lines"), + sourceMode: String(record.sourceMode || "uniform-grid"), }; } @@ -1875,7 +1875,9 @@ function getLineScore(data: Uint8ClampedArray, width: number, height: number, ax const alpha = data[offset + 3] / 255; if (alpha < 0.1) continue; const luminance = data[offset] * 0.299 + data[offset + 1] * 0.587 + data[offset + 2] * 0.114; - score += luminance < 96 ? ((96 - luminance) / 96) * alpha : 0; + const darkScore = luminance < 96 ? ((96 - luminance) / 96) * alpha : 0; + const lightScore = luminance > 220 ? ((luminance - 220) / 35) * alpha : 0; + score += Math.max(darkScore, lightScore); samples += 1; } @@ -3289,9 +3291,7 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib if (action === "crop") { const { columns, rows, tileCount } = normalizeGridOption(option); - const anchorMediaUrl = getNodeMediaUrl(anchor); const currentSplit = getNodeGridSplitState(anchor); - const isSyntheticGrid = Boolean(anchor.draftValues?.nineGridComposite) && !anchorMediaUrl; if (currentSplit && currentSplit.columns === columns && currentSplit.rows === rows) { setNodes((current) => current.map((node) => @@ -3311,14 +3311,7 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib toast.success("已取消宫格切分"); return; } - const detectedSplit = - !isSyntheticGrid && anchorMediaUrl - ? await detectGridSplitFromImage(anchorMediaUrl, rows, columns) - : null; - const rects = - detectedSplit?.rects && detectedSplit.rects.length >= tileCount - ? detectedSplit.rects - : createEqualGridRects(rows, columns); + const rects = createEqualGridRects(rows, columns); setNodes((current) => current.map((node) => node.id === anchor.id @@ -3328,11 +3321,11 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib ...(node.draftValues || {}), gridSplit: { columns, - detectedDivider: Boolean(detectedSplit?.detected), + detectedDivider: false, rects, rows, selectedIndices: [], - sourceMode: isSyntheticGrid ? "synthetic-grid" : "detected-lines", + sourceMode: "uniform-grid", }, }, } @@ -3344,11 +3337,7 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib setNodeContextMenu(null); setConnectionMenu(null); setActivePanel(null); - toast.success( - detectedSplit?.detected - ? `已在当前图上识别黑色分割线,进入 ${tileCount} 宫格选择模式` - : `已在当前图上按 ${columns}x${rows} 进入宫格选择模式` - ); + toast.success(`已在当前图上按 ${columns}x${rows} 进入 ${tileCount} 宫格选择模式`); return; } diff --git a/lib/video-canvas/config.ts b/lib/video-canvas/config.ts index a5a948e42..2a0832f80 100644 --- a/lib/video-canvas/config.ts +++ b/lib/video-canvas/config.ts @@ -84,7 +84,7 @@ const defaultFunctions: VideoCanvasFunctionDefinition[] = [ enabled: true, creditCost: 14, prompt: - "以选中图片作为角色、服装、发型、场景光线和电影质感的唯一参考,生成一张 5x5 连贯分镜合成图。必须是 25 个连续镜头,体现从远景建立场景、人物动作推进、情绪变化、细节特写到结尾反应的完整微型叙事,不是同一张图重复裁切。保持同一角色身份和绿色服装一致,森林自然光线统一;每格景别、机位、主体大小或动作都要有明显差异。输出为单张 16:9 图片,5x5 等分排版,使用清晰分割线,不能出现文字、水印、编号或多余边框说明。", + "以选中图片作为角色、服装、发型、场景光线和电影质感的唯一参考,生成一张 5x5 连贯分镜合成图。必须是 25 个连续镜头,体现从远景建立场景、人物动作推进、情绪变化、细节特写到结尾反应的完整微型叙事,不是同一张图重复裁切。保持同一角色身份和绿色服装一致,森林自然光线统一;每格景别、机位、主体大小或动作都要有明显差异。输出为单张 16:9 图片,必须严格 5x5 等分排版,25 个宫格的宽高一致、间距一致、边界完整,所有宫格之间使用清晰纯黑分割线,分割线等宽且横线竖线都要贯穿整张图;禁止使用白线、浅色线、柔边、渐变线、不规则拼贴、错位排版、跨格大图、留白边距、文字、水印、编号或额外边框说明。", description: "官方 25 宫格连贯分镜:生成 5x5 连续镜头合成图。", }, { @@ -127,8 +127,8 @@ const defaultFunctions: VideoCanvasFunctionDefinition[] = [ route: "local", enabled: true, creditCost: 0, - prompt: "识别黑色宫格分割线,将合成图切分为可单独调整的镜头图片。", - description: "浏览器端识别黑色分割线并生成切片节点;后端可后续替换为更稳的图像分割服务。", + prompt: "按当前图的标准宫格布局进行固定等分切分,将合成图切分为可单独调整的镜头图片。", + description: "对齐官方画布:4/9/16/25 和自定义宫格都按当前图的行列固定等分切分,并支持在当前图上多选宫格后继续创建生图或高清节点。", }, { key: "lighting", @@ -313,6 +313,9 @@ const legacyFunctionPrompts: Record = { "以选中图片作为角色身份、服装、发型、场景光线、镜头距离和画面质感的唯一参考,生成一张 2x2 剧情推演四宫格合成图。四格都必须保持参考图的近景/半身近中景人物构图,主体占画面主要面积,不要远景、全景、森林空镜或主体很小的画面。四格是同一角色在同一自然光场景中的连续轻微剧情变化:1 正面安静凝视,2 保留参考图抬手/袖摆动作的延续,3 视线或表情轻微变化,4 情绪收束的近中景反应。保持五官、发型、绿色服装、柔和森林逆光、色调和景深一致;每格角度和动作有轻微差异,但不能像 9 个不同机位分镜。输出单张 16:9 图片,2x2 等分排版,分割线清晰干净,不能出现文字、水印、编号、边框标签或 3x3/5x5 宫格。", "以选中图片作为角色、服装、发型、场景光线的唯一参考,生成一张 3x3 多机位分镜合成图。必须是 9 个明显不同的镜头画面,不是同一张图裁切或重复人脸。九格分别包含:1 森林环境远景/主体很小,2 全身远景,3 中景正面,4 侧面半身,5 低机位或俯拍,6 面部近景,7 手部/衣袖/动作细节,8 背面或侧背,9 仰视或情绪特写。保持同一角色身份、绿色服装、自然森林光线一致,每格构图、景别、机位和主体大小必须不同。输出为单张 16:9 图片,九格之间使用清晰黑色分割线,不能出现文字、水印、编号,不能白底棚拍。", ], + "continuous-storyboard-grid-25": [ + "以选中图片作为角色、服装、发型、场景光线和电影质感的唯一参考,生成一张 5x5 连贯分镜合成图。必须是 25 个连续镜头,体现从远景建立场景、人物动作推进、情绪变化、细节特写到结尾反应的完整微型叙事,不是同一张图重复裁切。保持同一角色身份和绿色服装一致,森林自然光线统一;每格景别、机位、主体大小或动作都要有明显差异。输出为单张 16:9 图片,5x5 等分排版,使用清晰分割线,不能出现文字、水印、编号或多余边框说明。", + ], "character-three-view": [ "以输入角色图为唯一角色参考,生成正面、侧面、背面三视图角色设定图。保持五官、发型、服装、颜色和体型一致,干净白底,三视图水平排布,适合后续视频角色一致性使用。", ],