diff --git a/pyproject.toml b/pyproject.toml index 7416df5..9cd2dab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "bfsnodes" description = "Custom ComfyUI nodes for reference-guided video: BFS Sampler (guide-driven IC-LoRAs with auto crop, mask inpainting and temporal chunking), LTX Multiple Controls and Identity Transfer, LTXV Edit Anything, Head-Swap/Anime2Real conditioning, AMV Guide Builder, MiniMax-H3 downscaled latent guides with training-matched geometry, overlap/sidecar source-phase RoPE, single-frame/video targets and VAE loaders, LoRA Surgery (scale or drop a LoRA's layers live to find a defect, save the result), and Shot Planner / Shot Loop (split long videos into model-sized shots at camera cuts with PySceneDetect, YOLO person/face filters, face-tracked cast with a reference per person, a reference and prompt per shot, run any workflow per shot, join with the original timing and audio), and H3 Duet (pin a source clip or reference beside the video, training-free, cropped off before decoding)." -version = "1.65.1" +version = "1.65.2" license = {file = "LICENSE"} dependencies = [ "torch", diff --git a/web/js/bfs_shot_loop.js b/web/js/bfs_shot_loop.js index 76eb703..fcfc4a2 100644 --- a/web/js/bfs_shot_loop.js +++ b/web/js/bfs_shot_loop.js @@ -968,7 +968,7 @@ function Panel(io) { h("input", { type: "checkbox", checked: cur.crop, onChange: e => setMeta(sel.value, "crop", e.target.checked) }), "✂ Crop to mask"]), h("input", { type: "text", value: cur.mask.text || "", style: "flex:1;min-width:160px", placeholder: "what to segment, in English: person in white, red car…", - title: "SAM 3 text prompt (up to 32 tokens; separate several things with commas). Points, when set, take priority.", + title: "What to segment, in English (up to 32 tokens; commas for several things), e.g. 'woman in pink top'. Enough on its own - no points needed: SAM 3 finds and tracks it through the shot. Points, when set, take priority.", onChange: e => setMask(sel.value, "text", e.target.value) }), h("button", { title: "Pick positive / negative points on a frame of this shot", onClick: () => openPoints(sel.value) }, (cur.mask.points || []).length ? `🎯 Points (${cur.mask.points.length})` : "🎯 Points…"), @@ -978,10 +978,10 @@ function Panel(io) { h("button", { disabled: !(cur.mask.text || (cur.mask.points || []).length || cur.crop), title: "Remove this shot's segmentation (points, text, crop) - for shots where it picked the wrong thing", onClick: () => clearMask(sel.value) }, "✕ Clear mask"), - h("button", { title: "Use this text prompt for every shot (points stay per shot)", onClick: () => { + h("button", { title: "Copy this shot's mask TEXT (e.g. 'woman in pink top') to every shot. Points are not copied (use Points → all). SAM 3 then finds that subject in every shot by itself - no clicking needed. Shots that have their own points keep using the points.", onClick: () => { const t = cur.mask.text || ""; segs.value.forEach((_, i) => { const m = meta(i); m.mask = { ...(m.mask || {}), text: t }; }); save(); - } }, "Mask → all"), - h("button", { title: "Crop every shot that has a mask", onClick: () => { + } }, "Mask text → all"), + h("button", { title: "Set '✂ Crop to mask' on every shot that has a mask (text or points) to this shot's value: on = only the masked region is generated and BFS Shot Join pastes it back; off = the whole frame is generated.", onClick: () => { segs.value.forEach((x, i) => { if (x.mask.text || (x.mask.points || []).length || cur.mask.text) meta(i).crop = cur.crop; }); save(); } }, "Crop → all"), ]), diff --git a/web/js/docs/BFSShotPlanner.md b/web/js/docs/BFSShotPlanner.md index 068a858..a4e66e2 100644 --- a/web/js/docs/BFSShotPlanner.md +++ b/web/js/docs/BFSShotPlanner.md @@ -251,7 +251,10 @@ Open a shot and click **🎯 Points…**. The modal shows one frame of the shot; description then misses the clothes. - **Right-click** (or shift+click) puts an *exclude* point, e.g. on a second person standing close. - **👁 Segment** shows what SAM 3 picked (red). Add or remove points until only that person is red. -- Instead of points you can type what to segment (`woman in pink`, `man with glasses`). Points win when both are set. +- Instead of points you can just type what to segment (`woman in pink`, `man with glasses`, `dog`): no clicking is + needed, SAM 3 finds and tracks it through the shot. Points are for when the text is ambiguous (two similar people). + Points win when both are set. **Mask text → all** copies the text to every shot; **Crop → all** sets *✂ Crop to + mask* on every shot that has a mask. Then save: