Commit Graph
182 Commits
Author SHA1 Message Date
ausboss 38aeec6d09 Merge pull request #41 from ausboss/feat/promote-krea2-outpaint
Promote the Krea 2 outpaint pair from the lab
2026-08-17 22:26:08 -05:00
ausboss bf87fd92a6 Merge pull request #40 from ausboss/fix/panels-follow-node-height
Panels follow the node's height; rename Compare to Image Compare A/B
2026-08-17 22:25:45 -05:00
ausboss ec50d3acfe Promote the Krea 2 outpaint pair from the lab
Krea 2 accepts reference latents, but they arrive with no position, so the
model treats them as a loose style hint: it borrows the look and reinvents
the content. That is the whole reason an outpaint drifts instead of
continuing the photo.

Krea 2 Encode attaches the reference latents and emits the negative from
the same node, so a turbo graph at CFG 1.0 stops carrying a second text
encode that does nothing. Krea 2 Outpaint Model Patch registers those
reference tokens into the target grid at the rectangle the stitcher
records, on frame axis 1.

Load Image + Pad gained a `reference` output - the unpadded source, fitted
to a 384px long edge and a multiple of 16, because the VAE downsamples by
8 and the DiT patchifies by 2. It is APPENDED after `stitcher`, never
inserted: a workflow stores links by output slot index, so any other
position silently rewires every saved graph.

The stitcher now records where the source sits, as source_bbox in pixels
and bbox_normalized in 0..1. Padding knows the rectangle exactly, so it
rides with the canvas instead of a parallel wire that can be left
unplugged. apply_stitch reads neither key, so an older stitcher stitches
identically.

Ported from the lab rather than copied: the lab's _krea2_helpers had its
own pad_image, feather_pad_mask, plan_pad_canvas, parse_fill_color and
build_canvas_stitcher. Duplicating the padding engine here would let the
outpaint path and the inpaint path disagree about what a stitcher is, so
the public module keeps only what is specific to Krea 2 and uses the
existing helpers for the rest.

Two departures from the lab version. The model patch declared a kv_cache
input and never read it - the cache was always on - so it is wired up now.
And it imports comfy's flux internals when you run it rather than at
startup: a core release that moves one then surfaces as an error on that
node, instead of deleting it from the menu and leaving saved workflows
reporting it missing.
2026-08-17 22:17:19 -05:00
ausboss 4b5d6429d8 Rename Compare to Image Compare A/B
The old display name led with the mechanism. "Image Compare A/B" says
what the node is first, which is what someone scanning the menu reads.
"image compare" joins the search aliases; "compare" and "a/b" stay.

The mapping key AUSBOSS_NODES_Compare is untouched - it is the
workflow-compatibility contract - so saved workflows are unaffected.
2026-08-17 22:15:16 -05:00
ausboss 9262c515e5 Let every node panel follow the node's height
Dragging a node taller only ever widened its stage. The frontend
arranges widgets in one pass:

  if (w.computeSize)            -> fixed height, kept OUT of the split
  else if (w.computeLayoutSize) -> joins distributeSpace(freeSpace, ...)
  else                          -> one standard widget row

It is an else-if, so a widget declaring both is pinned by computeSize
and its computeLayoutSize is never called. Every stage, player and
filmstrip here derived that fixed height from the node's WIDTH, so the
extra height became dead space underneath. Compare was fixed by hand;
the other six had the same defect.

Adds js/shared/panel_layout.mjs with one fillNodeHeight() that deletes
computeSize and declares a floor with no ceiling - distributeSpace reads
a missing maxSize as Infinity, so the panel takes whatever is left.
Applied to Compare, Save Video, Load Video, Frame Chooser, Load Image +
Pad, Image Crop+Rotate+Pad, and the shared transform panel that Video
Crop+Rotate+Pad mounts. Removing computeSize also removed where those
nodes got their opening height, so Save Video, Load Video and Load Image
+ Pad now state a default; a saved size still wins through onConfigure.

Measured in the browser: all seven grow 1:1 with the node and clamp at
their own floor.

The panel audit now enforces it - a DOM panel is either a stage that
calls fillNodeHeight and never assigns computeSize, or is listed as
fixed by design - so a new panel cannot quietly reintroduce this.
2026-08-17 22:15:16 -05:00
ausboss 2364d60338 Merge pull request #39 from ausboss/chore/prune-redundant-nodes
Remove Drop Shadow and Pad Image
2026-08-17 22:08:44 -05:00
ausboss 772f78d031 Remove Pad Image
Load Image + Pad does the same job from the same stage and starts from
the file, so the only thing the second node added was taking an IMAGE
wire - one idea holding two slots in the menu.

Deletes the node, its panel, its help doc and its stage-only shared
helpers (padEmptyStateText, findPadPreview), and drops it from
NODE_MODULES, PUBLIC_NODE_IDS, the README and the panel guard list.

The padding helpers are untouched; Load Image + Pad and Align Image both
use them. Two console labels there named the removed node, so
_fill_tensor now takes the source name - Align Image passes its own
pad_color, and a colour it cannot read is no longer reported against
padding. The BHWC and mode errors read "Padding"/"Pad mode" instead.

The on-node pad stage moves to ComfyUI-AusBoss-Lab, which has its own
AUSBOSS_LAB_PadImage.
2026-08-17 21:59:07 -05:00
ausboss 10382f1643 Remove Drop Shadow
The node produced a mask offset, grown and blurred - no contact
darkening, no perspective - so it read as a sticker halo rather than a
shadow in the scene. That is the approach, not a tuning problem, so it
comes out rather than shipping under the pack's name.

Deletes the node, its helper module, its test file and its help doc, and
drops it from NODE_MODULES, PUBLIC_NODE_IDS and the README. The colour
helper tests keep their two-callers case using Pad Image and Transform,
the real remaining call sites.

blur_mask and grow_shrink_mask stay in _mask_helpers - Crop For Inpaint
and Pad Image use both.
2026-08-17 21:59:07 -05:00
ausboss 9ad24d7314 Merge pull request #38 from ausboss/fix/node-polish-round
Fix LoRA mismatch detection, LM Studio reasoning, Compare height; add pad stitcher
2026-08-17 21:03:08 -05:00
ausboss 139082a9d9 Fix LoRA mismatch detection, LM Studio reasoning, Compare height; add pad stitcher
Six fixes found while testing every node against real workflows.

LoRA Loader: the "wrong base model" warning never fired on a modern stack.
It matched comfy's model class name against a table covering 8 of the 81
classes comfy ships, so Krea 2, Qwen, WAN, LTXV, Z-Image and friends read as
"unknown" and skipped the check entirely - an SD 1.5 LoRA on Krea 2 patched
nothing, changed nothing, and said nothing. It now measures the applied-patch
count across model and CLIP before and after each row and warns when a row
patched nothing, which needs no table, no LoRA metadata, and works on every
model family. base_model_family also stopped mining ss_sd_model_name: that is
the trainer's source filename, and reading substrings out of it labelled any
..._v1.safetensors as SD1.5 and anything containing xl as SDXL.

LM Studio Chat: reasoning returned in the server's own reasoning_content field
now reaches the thinking output. Only inline <think> tags were read, so with
gemma/qwen-style hybrids the whole reply landed in a field the node never
looked at and text came back blank. An empty answer now explains itself,
naming the max_tokens budget when the model ran out of room mid-thought.

Compare: the stage follows the node's height, not only its width. Its panel
declared a computeSize, and the widget layout gives any widget that defines one
a fixed height and leaves it out of the leftover-space split, so dragging the
node taller only added dead space under the image.

Pad Image / Load Image + Pad: a stitcher output, so an outpaint can put the
source back exactly. Padding now builds the same stitcher shape Crop For
Inpaint emits - the crop is simply the whole canvas - so the existing Stitch
Inpaint node serves both and no second stitch node has to exist. Appended
last, so saved workflows keep their links.

Settings menus: editing one row no longer reverts the others. Each save handed
back a value set rebuilt from stored defaults, silently replacing every other
row on a node whose workflow differed from those defaults.

LoRA templates popover: Save was clipped off the panel edge and each saved
row's delete x was stretched across the whole row - one blanket
.ausboss-lora-menu button rule outranked the specialized buttons inside it.
2026-08-17 20:47:27 -05:00
ausboss 6f3adb1ad9 Release 1.1.1: fix the registry metadata 1.1.0 shipped wrong
The ComfyUI version floor never reached the registry. comfy-cli reads it from
a [tool.comfy] key named requires-comfyui; the pack declared
supported_comfyui_version, which the parser ignores, so 1.1.0 published with
an empty floor and Manager had nothing to refuse an incompatible install on.

Also declares Operating System :: OS Independent, which is where the registry
sources supported_os from, and publishes the license as a readable name rather
than the literal string {"file": "LICENSE"} that a file reference
serializes to. Accelerator classifiers stay off rather than asserting hardware
nobody has tested.

Verified by parsing pyproject.toml through comfy-cli itself: the floor now
reads >=0.27.1 and supported_os reads ['OS Independent']. No node behaviour
changes.
v1.1.1
2026-08-17 17:48:26 -05:00
ausboss cc477c4ec4 Release 1.1.0
Closes the Unreleased section into 1.1.0 and syncs the version across
pyproject.toml and AUSBOSS_JS_VERSION, which release_preflight.py compares so
a fresh install never trips the stale-browser warning.

First version published to the Comfy Registry. 1.0.0 was never tagged or
released anywhere, so it stays as changelog history rather than becoming the
registry's first entry describing a fifth of what it contains.
v1.1.0
2026-08-17 17:38:38 -05:00
ausboss 176115245d Merge pull request #37 from ausboss/chore/gate-unlisted-node-ids
Gate the public node list in both directions, and point the docs at the lab
2026-08-17 17:38:09 -05:00
ausboss 02193e71f0 Point the docs at the lab repo
AGENTS.md and the brand skill both read as if this repo were the only place a
node can live, so an agent adding one had no reason not to add it here. Both
now name ComfyUI-AusBoss-Lab as the default destination, list what disqualifies
a node from the public pack, and carry the namespace table.

The brand skill also gets an explicit note not to spend the polish budget on a
lab node: example workflows, thumbnails and frontend work are release-gate
items, and lab nodes stay outside js/appearance/ by prefix on purpose.
2026-08-17 16:43:19 -05:00
ausboss e152b903e0 Gate the public node list in both directions
PUBLIC_NODE_IDS only checked that every listed id was still registered. A
brand-new id could register and validation stayed green, so the release gate
could not tell when a node reached the public pack without anyone deciding it
should ship.

Also pins SimpleWatermarkRemover in its own LEGACY_NODE_IDS set. It is the
pre-convention id kept so already-published workflows keep loading, and it was
never listed - so the new check now asserts the compatibility shim is present
rather than flagging it as a stray.
2026-08-17 16:33:20 -05:00
ausboss 0fd5ca2d80 Merge pull request #36 from ausboss/feat/audit-batch
Pack audit batch: on-node pad editors, ecosystem feature gaps, node removals
2026-08-17 10:52:06 -05:00
ausboss c15c6c9317 Implement the pack audit batch: on-node pad editors, feature gaps, removals
The audit compared every node against ComfyUI core and the major packs;
this lands its outcomes in one branch.

On-node visual editing (the old Codex-pack interaction, rebuilt):
- New Load Image + Pad: image loader with whole-edge pad dragging on the
  node canvas, align-to-multiple rounding, and a megapixel target that
  rescales the source before padding so the mask seam stays binary.
- Pad Image gains the same handle canvas, fed by an execution-time
  snapshot of its input; wireframe with diagnostic empty states before
  the first run. Widgets, outputs, and saved workflows unchanged.
- Image Crop + Rotate + Pad's compact panel is now a live stage - crop,
  pad, and rotate handles on the node, one shared implementation with
  the full-screen editor so the two surfaces cannot drift.

Feature gaps closed against the ecosystem:
- Crop For Inpaint: target_megapixels, selectable rescale_algorithm
  (recorded in the stitcher for the paste-back), and extend_* inputs
  that grow the frame itself for outpainting.
- Save Video: format choice - mp4 h264, mp4 h265, webm vp9 with Opus
  (resampled to 48 kHz); CRF drives all three.
- Load Video: every_nth thinning (fps output divides to match) and a
  max_frames cap that ends the decode early.
- LoRA Loader: saved stack templates behind a bar button, and a console
  warning when a LoRA's base-model family disagrees with the checkpoint.
- LM Studio Chat: history in/out for multi-turn chains and a json_schema
  widget for structured replies.
- Drop Shadow: multiply blend and a shadow_mask output. Align Image:
  offset outputs for un-aligning after sampling. Color Match:
  first_frame reference mode as a one-node video flicker fix.

Removed (backed up in git history): Select Frame Range and the Video
Bundle family - core ImageFromBatch and the core VIDEO wire now cover
both jobs. Dead NODE_ID module variables cleaned out of every node file.

455 Python tests, 216 JS tests, validate_nodes.py green on 19 node files.
2026-08-17 10:49:55 -05:00
ausboss d2eb198c81 Update .gitignore 2026-08-16 23:56:30 -05:00
ausboss 9c60700ad2 Merge pull request #35 from ausboss/feat/ui-polish-batch
UI polish batch: brand theme, gear settings, help badges, and node upgrades
2026-08-16 20:36:30 -05:00
ausboss a82803cd46 Declare the chat toolbar tall enough to clear the wrapper margins
The frontend keeps ~16px of a DOM widget's declared height as wrapper
margins; 32 declared left a 16px box that clipped the 22px buttons.
Declaring 48 yields the 32px box the row actually needs - calibrated
against the live frontend.
2026-08-16 20:34:17 -05:00
ausboss ec44f7c64c Size the chat toolbar by its content, not the widget wrapper
The DOM-widget wrapper's CSS height is not authoritative (the LoRA panel
renders from a 0px wrapper); height:100% chained the toolbar to that
sliver and clipped the buttons. The row now takes its natural content
height, like every other panel.
2026-08-16 20:31:26 -05:00
ausboss 4e435e3013 Trade the display-name suffix for the 🆎 signature and unclip the chat toolbar
Every display name swaps ' (AusBoss)' for ' 🆎' - menus, docs, tooltips,
the README, and the example workflow's notes. Mapping keys never change,
so saved workflows keep loading; 'ausboss' keeps finding everything via
the category, the AUSBOSS_NODES_ prefix, and SEARCH_ALIASES. Python error
messages drop the suffix entirely so exception text stays ASCII for
cp1252 consoles.

The LM Studio endpoint toolbar declared no getMinHeight, so the frontend
gave its wrapper a 12px sliver and the buttons clipped; it now declares
32px through every sizing path, and the buttons breathe at 22px.
2026-08-16 20:29:38 -05:00
ausboss 01e4c2120b Round of feedback fixes on the polish batch
Frame Chooser: the notice inflated the grid's auto flex basis and squeezed
the action buttons into the bottom clip - the grid now flexes from a zero
basis, the fixed rows never shrink, and idle gets a little more room.

LoRA Loader: the empty state is just 'No LoRAs yet' and is itself a click
target that adds a row and opens the picker.

Align Image: pad mode gained an anchor (pad_position), a fill choice
(replicate or color), and pad_color - all hidden outside pad mode, the
color field hidden until the color fill is chosen.

LM Studio Chat: the gear moved off the node's tail into an endpoint
toolbar - status light, Test (asks the server for its model list through a
new /ausboss/lmstudio/models route; green/red + toast), Models (pick from
the server's list straight into the model field), gear. A visible
unload_llm switch frees the LLM right after the reply via LM Studio's JIT
ttl, overriding the gear's idle timer.
2026-08-16 20:15:20 -05:00
ausboss 4e07e51be5 Note the UI polish batch in the changelog 2026-08-16 19:42:31 -05:00
ausboss 0f0d1d9081 Extend Crop For Inpaint's selection controls
invert_mask inpaints outside the drawn region, mask_grow dilates or
shrinks the sampling mask, mask_blur softens its edge for models that
honor soft masks, and context_pixels adds flat margin on top of
context_factor's growth. Defaults keep the old hard-edged behavior
bit-identical.
2026-08-16 19:42:31 -05:00
ausboss 0303d42e61 Fix A/B Compare's HOLD trap with dedicated mode buttons
In hold mode the stage captured the pointer on press, which retargeted the
release and ate the mode button's click - one way into HOLD, no way out.
SLIDE and HOLD are now two labeled buttons, and presses born on the
toolbar never reach the stage behaviors.
2026-08-16 19:42:31 -05:00
ausboss 1478038da0 Teach Color Match four methods and an invert switch
lab keeps the old per-channel LAB mean/std behavior as the default; rgb
does the same in raw channels; mkl maps the full RGB covariance through
the closed-form Monge-Kantorovich linear transform; histogram matches each
channel's quantiles exactly. invert_mask flips which side of the mask gets
corrected, and the tooltips now spell out that the mask only scopes the
fix, which is why there is no mask output.
2026-08-16 19:42:31 -05:00
ausboss 04a32557c4 Give LM Studio Chat a gear menu of advanced knobs
top-p, top-k, min-p, repeat and presence penalty, thinking on/off via
chat_template_kwargs with custom reasoning tags, LM Studio idle-unload
TTL, and free-ComfyUI-VRAM-first. Values ride hidden standard widgets so
they save with the workflow and reach the API; neutral defaults are
omitted from the request body.
2026-08-16 19:42:22 -05:00
ausboss 43cffbce0d Restyle the LoRA Loader around one control language and a gear menu
Full-width filled Add button, master-toggle bar with the gear, rows in an
inset stack with a dashed empty state, system-ui info glyph. The gear
holds default strength, strength step, separate model/CLIP strengths, the
trigger-word separator (a hidden widget the output honors), hide-extension,
thumbnail, and Civitai-lookup preferences.
2026-08-16 19:42:22 -05:00
ausboss 70262b4762 Give Align Image a crop anchor shown only in crop mode
crop_position picks which part of the frame survives a crop (center, top,
bottom, left, right); the widget hides outside crop mode so the node face
stays compact.
2026-08-16 19:42:15 -05:00
ausboss f39908de05 Adopt the brand scheme pack-wide and add the title-bar help badge
The teal pair the video nodes hard-painted becomes the AusBoss scheme row
and the pack-wide default; Load/Save Video stop painting themselves so the
appearance setting and per-node menu govern every node the same way. Every
AusBoss node also gets a quiet ? badge whose card is built from the node's
own DESCRIPTION and tooltips.
2026-08-16 19:42:15 -05:00
ausboss ae931c9b36 Add shared per-node settings and help-card infrastructure
A schema-driven gear menu (toggles, numbers, text, segmented choices)
persisted per node type in localStorage, a reusable info-card popup, a
widget show/hide helper that keeps widgets_values stable, and a hand-drawn
gear icon - the plumbing the LoRA Loader and LM Studio gears build on.
2026-08-16 19:42:08 -05:00
ausboss 3de415ad08 Merge pull request #34 from ausboss/fix/dom-widget-width-ratchet
Discard planted widget widths so panels track their node
2026-08-15 21:52:06 -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 86eb998cca Merge pull request #33 from ausboss/fix/panel-overflow
Keep the LoRA panel inside its node
2026-08-15 21:15:37 -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 e026bfb0cc Keep the LoRA panel inside its node
The strength box and info button hung past the node's right edge, two
gaps stacked: the panel's 10px padding rendered outside the width the
frontend allocates (content-box), and nothing declared a minimum width
to the modern layout - computeSize clamped the PANEL to 300px, but
without computeLayoutSize the NODE could be resized narrower, and the
row's fixed-width trailing controls kept their size while the picker
shrank to nothing.

Every other DOM panel in the pack already carries the full guard set -
border-box, an overflow clip, computeLayoutSize minWidth, minNodeSize -
through the shared video root or its own CSS; the LoRA loader was the
one that had none of it. It now matches the house pattern, sharing one
PANEL_MIN_WIDTH constant across every sizing path the frontends
consult so the panel and the node can never disagree about how narrow
is legal.

tests/panel_guards.test.mjs makes the pattern policy: every entry that
calls addDOMWidget must carry the guards or mount the shared root that
does. Against the pre-fix file it fails 3 of 5.
2026-08-15 21:11:51 -05:00
ausboss 5d227d26af Merge pull request #32 from ausboss/feat/utility-nodes
Add Align Image, Image Size, and LM Studio Chat
2026-08-15 21:10:02 -05:00
ausboss 85b70389ff Add Align Image, Image Size, and LM Studio Chat
Align Image snaps width and height to a clean multiple - 16, 32,
whatever the model wants - because Qwen image models, VAEs and plenty of
samplers only behave on cleanly divisible sizes. Each mode implies its
own rounding, so there is no separate direction widget: resize rescales
to the nearest multiple, crop center-crops down, pad replicate-pads up,
and a side smaller than one multiple always grows to exactly one rather
than erroring. The new size comes out as INTs for wiring into latents.

Image Size reads width, height, longest edge and shortest edge off the
wire so resizes and latents key off the actual image instead of retyped
numbers that drift.

LM Studio Chat posts a prompt - and optionally one image - to a local
LM Studio server, or anything else speaking the OpenAI-compatible chat
API. The interface is the middle ground the installed ecosystem packs
miss on either side: endpoint string, model string where EMPTY means
whatever the server has loaded (a dropdown fetched at ComfyUI startup
goes stale whenever LM Studio was not running yet), optional system
prompt, prompt required unless an image is connected, temperature,
max_tokens, seed as the re-roll knob, a timeout, and an image downscale
cap. Reasoning-model think blocks land on their own output so the text
stays clean for conditioning. Stdlib urllib only - no new dependencies -
and the POST runs off the executor thread. Every error names what to
fix, with the server's own words when it had any.

Verified live against a running LM Studio: a JIT-loaded qwen3.5-9b
answered a text round trip in 7.6 s through the real node; the
no-model-loaded 400 and a dead port both surfaced their actionable
messages. The vision payload shape is unit-tested; the two local VL
quants refused images server-side (missing projector / failed load), so
the live vision check stays on the deployment checklist.

48 offline tests cover the alignment math, both size nodes, the URL and
payload builders, think-splitting, image encoding, and every mocked
network error path.
2026-08-15 20:51:51 -05:00
ausboss 8f326e563c Merge pull request #31 from ausboss/fix/review-findings
Fix the fifteen defects the code review found
2026-08-15 20:35:17 -05:00
ausboss 41ad62853b Apply the measured performance follow-ups from the review
Morphology first, because three things stand on it: grow_shrink_mask now
dilates or erodes in one separable pass - n 3x3 max pools equal a single
(2n+1) square filter, which splits into two 1-D passes - instead of one
full-image pool per pixel of growth. Bit-identical on hard and soft
masks in both directions (asserted against the old iterated form), and
measured 6-7x at 32 px. The matting trimap, which was rebuilding that
morphology inside its per-frame loop, builds it once per batch: 11.0 s
of trimap work on 48 frames of 832x480 becomes 0.4 s.

Pad Image's pillarbox backdrop blurs at quarter resolution when sigma is
large enough that the blur destroys detail anyway - that one blur was
~90% of the node's runtime, and the low-res path is 6-7x cheaper with a
mean difference around 0.001 in a band that is then dimmed. Light blurs
stay on the exact full-resolution path, so small canvases (and the
existing tests) are unchanged.

Frame Interpolate estimates flow exactly once per source pair at every
batch_size: blend batches now take whole (a, b) groups, and a one-batch
flow cache covers a pair a tiny batch_size splits, so batch_size=1 - the
setting the tooltip recommends for limited VRAM - no longer re-solves
each pair once per output frame (4x the RAFT work at 24 -> 120 fps).
The counting-stub test pins solves to the unique-pair count and checks
outputs across batch sizes with a content-dependent flow, a tolerance a
deliberately poisoned cache overshoots by five orders of magnitude.

Smaller: the guide-image batch is validated as a view and converted per
frame instead of duplicated up front (398 MB resident for 16 frames of
1080p); the scene-cut scan reuses its subtraction temporary in place;
and the edge-halo spread drops EDGE_HALO_SPREAD_PIXELS - tuned to 0 and
provably a no-op - along with the full-batch alpha copy that rode on it,
clamping per frame instead so values are unchanged.
2026-08-15 20:25:15 -05:00
ausboss 3f75c288af Close the documentation gaps the readiness sweep found
Every registered node now has rich help: Video Unbundle and Video Bundle
Edit only existed inside the family page, which ComfyUI's help panel
never shows because it looks docs up by exact node id, and the
SimpleWatermarkRemover compatibility alias had nothing pointing users at
LaMa Inpaint. 21 of 21 mapping keys now have a js/docs page.

Three statements the review verifiers caught as false stay fixed too:
the README said no minimum ComfyUI version is declared while
pyproject.toml declares and Manager enforces 0.27.1; the optional-extras
comment promised a warn-and-fall-back that only Stitch Inpaint actually
does, where Refine Mask deliberately stops with the package name; and
the Load Video tooltip cited 0.3.26 for a VIDEO type that landed in
0.3.31 - moot either way, since every supported core has it.
2026-08-15 20:06:11 -05:00
ausboss 5e6cdb2ecc Fix the fifteen defects the review found
Frame Chooser, mostly. A pause did not survive a workflow load: LiteGraph
clears a graph by removing every node, so undo, a tab switch, Clear
Workflow and opening another file all fired the teardown a deleted node
uses to release its pause, and killed a run that was still going. That
now only fires for a real deletion. Answering "keep all" wrote the batch
out as 1,2,...,N into pick_list, so the next run dropped whatever the
enumeration did not reach or failed outright on a shorter clip; it
writes the empty answer it was given. And pick_list is only written back
under "keep last selection" - it pre-answers the node, so filling it in
automatically meant a chooser left at the default paused exactly once.

Refine Mask: smooth applies only the change it made to the jaggy edge
rather than binarizing everything, so an already-soft matte keeps its
alpha (binary masks stay bit-identical), and blur now reaches the
matting solve instead of being thresholded back out of the trimap.

Frame Interpolate's copy path honours batch_size; it gathered every
copied frame at once, which on a long clip at an integer multiple was a
multi-gigabyte allocation on the frames device that no setting bounded.

Subgraph execution ids are resolved by walking the chain instead of
stripping the prefix, which could match an unrelated node with the same
number. Status and runtime badges appear inside subgraphs again, and a
subgraph pause renders on the node that actually paused.

Also: the Custom colour scheme no longer strips every node's colour when
its stored colour is unreadable; Drop Shadow and Pad Image name their
own widget for an unreadable colour instead of blaming Transform; a
non-ASCII token and a non-object JSON body answer 400 rather than
throwing a 500 and stranding the pause; pick_list rejects Unicode
digits, which used to raise during validation or silently read as a
frame nobody typed.

Tooling: validate_nodes parses NODE_MODULES rather than matching it
anywhere in the text, and an unregistered module is an error - it used
to exit 0 printing nothing. It also refuses mapping keys declared
outside nodes/, which is how the registry fixtures came to be advertised
to ComfyUI-Manager as installable nodes; they are .py.txt now. And the
video test no longer leaves ComfyUI on sys.path, which was flipping
every fail-soft seam for whatever ran next.
2026-08-15 00:00:15 -05:00
ausboss df5c9120a6 Merge pull request #30 from ausboss/docs/wave-four
Document the wave-four features
2026-08-14 10:35:15 -05:00
ausboss 75eb4e732a Merge pull request #24 from ausboss/feat/ui-adoption
Polish frontend adoption and appearance controls
2026-08-14 10:34:58 -05:00
ausboss 2c9c16ad16 Merge pull request #29 from ausboss/chore/registry-guard
Guard mapping keys against a scanner-invisible regression
2026-08-14 10:18:21 -05:00
ausboss e0813c765d Merge pull request #27 from ausboss/feat/frame-interpolate
Add FPS-aware frame interpolation
2026-08-14 10:18:07 -05:00
ausboss 04293ca6c0 Merge pull request #25 from ausboss/feat/chooser-hardening
Settle a Frame Chooser pause once, and harden the panel around it
2026-08-14 10:17:42 -05:00
ausboss 1c440ae3c0 Merge pull request #28 from ausboss/feat/image-finishing
Add image finishing nodes
2026-08-14 10:16:55 -05:00
ausboss e00bccf9f3 Merge pull request #23 from ausboss/feat/core-video-interop
Core VIDEO interoperability and async video I/O
2026-08-14 10:16:24 -05:00