Commit Graph
17 Commits
Author SHA1 Message Date
ausboss 36a0b5ca6a Merge branch 'fix/mask-refine-fill-limit' into rc/2026-09-30
# Conflicts:
#	CHANGELOG.md
2026-09-29 22:39:30 -05:00
ausboss 11b5a6d56a Mask Refine: Max hole size, so fill holes leaves the part you kept
Paint everything except a person or a pet, turn on fill holes, and it
filled the unpainted subject too, so the part meant to stay was repainted.
The new optional max_hole_size input (a percent of the picture, 0 to 100)
sets the biggest hole fill holes fills. The default, 0, fills every hole
exactly as before, so saved workflows and API prompts run the same; at 2
the gaps a quick brush leaves still fill and a subject left unpainted
stays. Areas touching the picture's edge are never holes, as before.

- Hole sizes come from scipy's labels, the same 4-connected holes its
  fill finds; the torch fallback labels the same 8-connected holes as its
  own fill. Each picture in a batch is measured on its own, after expand.
- The card gets a Max hole size row with a % unit, dimmed while Fill holes
  is off, and a resetUnknown fallback of 0 for 2.x saves that hold the
  card's empty value in its slot.
- Tests: a hole above the limit stays, holes up to it fill, 0 matches the
  old fill, edge-touching areas never fill, the torch fallback agrees,
  batches, and older saves opening with 0.
- Node API snapshot, help page and changelog.
2026-09-29 22:38:36 -05:00
ausboss ae2af9db47 Merge branch 'fix/clip-node-ux' into rc/2026-09-30
# Conflicts:
#	CHANGELOG.md
#	example_workflows/LTX 2.3 Video Outpaint (AusBoss).json
#	js/input_preview/index.js
2026-09-29 22:16:33 -05:00
ausboss 71b354f54b Merge branch 'fix/save-image-nodes2-height' into rc/2026-09-30 2026-09-29 21:40:53 -05:00
ausboss 5b2f2508ab Preview and padlock: two leftovers after the first pass
- A node dragged taller while its preview was off keeps that height when
  the preview comes back.
- A new picture with no ratio lit starts with the padlock off, as the
  untouched picture has no shape to hold.
2026-09-29 21:40:23 -05:00
ausboss 8ab3ce334a Preview switch: on again brings back the last result at the old height
Switching a preview off and on again (Mask Refine, LaMa Inpaint, Select
Frame, Save Image) left an empty box until the next run, and the node came
back shorter than it was.

Now the node remembers its height when the preview goes off (saved with
the workflow) and returns to it, with the last result in the box. If the
node ran while its preview was off, the box says "Run the workflow again
to see it here" rather than showing an older picture. With nothing to show
yet it says "Run the workflow to see it here".

Mask Refine's AUTO button now says what it does in its tooltip.
2026-09-29 21:33:06 -05:00
ausboss 5babcc7ed6 Keep a run's results on the workflow tab that queued it
Every workflow tab in a page shares one server connection, and ComfyUI
files a node's results by node id. A run from one tab that finished while
another tab was open landed on the open tab's node with the same id. On
Video Crop + Rotate + Pad -> Clip that was a second video under the
buttons that grew the node over the one below; Show Text and Seed also
saved the other workflow's text and seed into this one, and Save Video and
Compare replaced their own result.

- The three Crop + Rotate + Pad nodes stand down ComfyUI's image and video
  previews (they send no picture of their own), in both renderers.
- suppressCoreVideoPreview sets hideOutputImages, so Nodes 2.0 no longer
  draws Save Video's clip a second time under its player.
- shared/prompt_scope.mjs notes which graph queued each run (the queue
  call is wrapped for the prompt id). For a result from another tab, the
  AusBoss node here gets this tab's own stored result back, every pack
  onExecuted handler returns early, and the result is handed to the owner
  tab's AusBoss nodes when that tab is open again. Core nodes are left
  alone.

Tests: prompt_scope (scope rules plus a policy check that every
onExecuted handler asks isForeignRun first) and core_preview (every
transform kind suppresses both previews; video suppression sets
hideOutputImages) fail on main and pass here.
2026-09-29 15:53:03 -05:00
ausboss 7b8aa698e6 Preview nodes keep their size in Nodes 2.0
In Nodes 2.0 a node's saved height is only a minimum and its content can
make it taller. The preview panel's picture was in normal flow, so a
portrait result drawn at full width grew Save Image from 730 to 1276 px in
the Krea 2 Outpaint example, over the Run Timer under it. Nodes 2.0 also
drew its own copy of the result under the panel, because the panel never
set hideOutputImages.

- The stage's picture is out of flow and centred, so the stage gets its
  size from the node and the picture scales to fit, in both renderers.
- suppressCoreImagePreview sets hideOutputImages; classic never reads it.
- In Nodes 2.0 that copy was the only thing filling node.imgs, so the
  panel falls back to the node's stored output (app.nodeOutputs) and
  re-reads it when a workflow tab restores its outputs. node.imgs still
  wins where it exists, so classic keeps its old path.

Select Frame, Mask Refine and LaMa Inpaint share the panel and grew the
same way. Core Save Image and Preview Image keep their size in Nodes 2.0.
Classic is unchanged.

Tests: the stage-picture guard in panel_guards, hideOutputImages in
core_preview and the stored-output lookup in input_preview fail on main
and pass here.
2026-09-29 05:11:19 -05:00
ausboss 2a3268f934 Cards and panels: leave them out of saved workflows
Every card and DOM panel was added with options.serialize = false, which
only keeps a widget out of the queued prompt. The frontend saves each
widget whose own serialize is not false and hands saved values back by
position, so each card and panel saved an empty value of its own after the
node's real values, and an input appended to the node later opened holding
it (Stitch Inpaint's seam, Crop For Inpaint's keep_inside). Every DOM widget
now also sets widget.serialize = false, as the frontend's own previews do,
so new saves carry only real values.

Older saves still end in those empty values, and loading them now skips
the cards and panels. On every node that saves by position they come after
all real values (Save Image's card sits mid-list, but Save Image saves by
name), so nothing moves. On frontend 1.53.6 the examples (the 21 from
before the trim and the 7 now) and 14 older saved workflows queue
byte-identical prompts before and after, keep every value, and save and
reopen cleanly.

An input appended later still needs a fallback for those older saves.
tests/saved_widget_values.test.mjs checks that every DOM widget sets the
flag, that the examples keep their values with the panels skipped, and that
each input appended to a node whose older saves end in an empty value is
declared and, as a widget input, has a card resetUnknown fallback that
fires. tests/test_card_fallbacks.py (ComfyUI's Python) checks each fallback
is the input's own default. AGENTS.md states the rule.
2026-09-29 03:20:45 -05:00
ausboss 2a5df316cb Save Image: preview switch and Embed workflow no | yes
Save Image joins the shared input_preview panel with the PREVIEW switch,
backed by a new optional preview input (display only: the file is saved
and listed in the queue either way). The embed row reads
Embed workflow: no | yes.
2026-09-26 17:58:25 -05:00
ausboss f656a3d954 Record LoRA, Compare and Mask Refine panel edits in undo history
The pack's DOM panels must tell ComfyUI's change tracker about their
writes, and several did not: LoRA Loader row edits other than a few
menu actions, Compare's slide / A-B mode, and Mask Refine's AUTO. LoRA
rows now record on every commit, with strength drags recording once on
release, and the other two record when they change a saved value.
2026-09-24 00:08:36 -05:00
ausboss 699208dadc Prepare 2.0.0 release candidate 2026-09-07 19:56:23 -05:00
ausboss fb40d4288c Let the result preview follow the node's height
Mask Refine, LaMa Inpaint and Select Frame drew their picture into a
container pinned at 140px, so dragging any of them taller only added dead
space underneath - the same complaint already fixed for Load Video, Image
Compare A/B and Save Video.

The panel is shared, and it was pinned deliberately: while it showed a small
thumbnail of the node's INPUT, a constant height was right, and the guard in
panel_guards.test.mjs listed it under fixedByDesign for exactly that reason.
Making it show the node's own RESULT turned it into a viewport onto a
picture, which is what the other set is for, and that reclassification was
missed - so the guard kept passing while the panel it described no longer
existed.

It goes through fillNodeHeight now, with a 140px floor and no ceiling, and
declares a minimum width to both layout paths because it carries the
AUTO/MORE buttons and can no longer be exempt from that. The guard moves it
to mustGrow and says out loud that this classification is a decision to
review whenever what a panel DISPLAYS changes, not only when one is added -
verified by reintroducing the pin and watching both guards name it.
2026-08-18 17:14:51 -05:00
ausboss 0e4749db6b Preview each node's own result, and rework Save Video
Five things surfaced by release testing.

Node search: ComfyUI's search dialog cuts at 64 results and ranks by
[match tier, global popularity, name length], where tier 1 needs the name
to START with what was typed. Popularity is a fixed global table in which
every node from a new pack scores zero, so tier is the only lever. As
"Refine Mask" this node came 121st for "mask" and was never on screen.
Renamed to Mask Refine, which is 15th, and kept "refine mask" as an alias.
The mapping key is untouched, so saved workflows are unaffected. Aliases
alone cannot fix this: the frontend indexes them but drops them from the
tier scoring because they are a list rather than a string, so they decide
whether a node is findable, not where it lands.

Previews: Mask Refine, LaMa Inpaint and Select Frame showed whatever fed
their input, which is nothing when a segmentation node is upstream - Mask
Refine's panel was blank however the mask turned out. Each now returns its
result as a preview and the panel shows that, falling back to the input
before the first run. A node does not need to be an OUTPUT_NODE for this;
returning a ui payload is enough. ComfyUI's own preview for these nodes is
stood down so the picture appears once, in the panel, rather than also
underneath the node. That also fixes LaMa finishing a single image with an
empty panel: frame previews were only attached for batches over one frame,
on the assumption that one image would preview through the output path,
which a non-output node does not have.

Mask Refine opens on expand and blur with the other five behind MORE.
Hidden widgets keep their values and their saved positions. AUTO sets both
from the mask's size, scaled off the 8/4 hand-tuned for the watermark
workflow at 576px, because a feather is a fraction of the picture rather
than a fixed pixel count.

Save Video gains nvenc h264/h265, webm av1, ProRes mov, lossless ffv1 mkv,
gif and webp, plus pingpong and save_metadata. Every format is encoded and
read back in the tests rather than trusted from its table row. fps steps in
whole frames but stays FLOAT: an INT would refuse Load Video's fps link and
round 29.97 to 30, drifting picture off audio. mov files now carry the
embedded workflow, which they silently did not. The reload button is gone -
it only re-fetched what was already on screen.

Not done: Select Frame's preview updates on a run, not as the number
changes. Seeking to a frame needs the source fps, which the browser never
learns, so live scrubbing needs a server route - the surface Frame Chooser
was just demoted for.
2026-08-18 16:31:44 -05:00
ausboss 8ee79fedd8 Discard planted widget widths so panels track their node
The frontend sizes a DOM widget's wrapper as widget.width ?? node.width
(GraphView, useDomWidget updateWidgets), and LiteGraph's layout plants
widget.width during draws. Once planted it outranks the node width
forever: resize the node narrower and the wrapper keeps the old width,
parking the panel's right edge - and the LoRA row's strength and info
controls - outside the border. None of the containment guards could
reach it: border-box and the overflow clip act at the wrapper's edge,
which is precisely the thing that is too wide, and the minimum-width
paths only stop the node going BELOW a floor, not the wrapper staying
ABOVE the node.

Diagnosed from a console measurement in the reporting browser (wrapper
styled 470px on a 328px node, scale 1.21) and reproduced exactly by
planting widget.width = 470: overflow +183px. keepDomWidgetWidthAuto
defines width as a discard-writes accessor, so the frontend's lookup
stays on its node-width fallback for the life of the widget. All six
DOM panels call it, the policy test requires it, and the fix was
verified end-to-end in a live classic-renderer session: with the plant
attempted, the wrapper tracked the node through narrow, add-row,
linked, grow and shrink at -13px inside the border throughout.
2026-08-15 21:50:39 -05:00
ausboss 4fa7799a70 Extend the containment guards to every DOM panel
The audit behind the LoRA fix found two residual gaps and closed the
policy hole that let them hide. Frame Chooser declared its minimum
width to the modern layout but not through options.minNodeSize, the
path older frontends read - so on those, the node could still be
resized under the panel, which holds MIN_WIDTH and pokes past the
border exactly like the LoRA row did; the overflow clip cannot help
there because it cuts at the panel's edge, not the node's. The
input-preview thumbnail now clips at its root as well, making every
root uniform.

The policy test now requires the full set of every resizable panel:
border-box and an overflow clip reaching the root class (a blanket
group selector counts), plus a minimum width on BOTH layout paths -
computeLayoutSize for modern frontends and options.minNodeSize for
older ones. Against main's pre-fix LoRA file it fails 4 of 6, and
stashing the chooser change fails 1, so both halves are proven to
catch what they were written for.
2026-08-15 21:13:51 -05:00
ausboss 350c886928 Preview the upstream input on Refine Mask and LaMa Inpaint 2026-08-12 22:52:13 -05:00