Commit Graph
17 Commits
Author SHA1 Message Date
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 45b27dd94a Latent Size (was Resolution Master): resizable; LoRA Loader long-name choice
Resolution Master is renamed Latent Size: the old name belongs to another
node pack. The node id AUSBOSS_NODES_Resolution is unchanged, so saved
workflows and API graphs load and run as before. Workflows only store a
title that differs from the default, so they pick up the new name; a saved
title that starts with "Resolution Master 🆎" gets the new name in its
place on load. The example, its thumbnail and the README image follow.

- Latent Size can be resized: wider stretches the chips, fields and size
  picks, and taller gives the stage the room. It opens at 340 x 531 as
  before and goes down to 320, where the size row tightens so W, H and MP
  stay whole.
- LoRA Loader: gear -> Long names, end (the default, as before) or middle,
  which keeps the checkpoint number at the end of a name in view. The
  picker opens wide enough for long names and shortens the folder first.
- The frontend adds 104 px to a DOM panel's minWidth before using it as
  the node's floor (LGraphNode.computeSize), so a node that opened
  narrower jumped wider the moment its corner was touched: the LoRA Loader
  could not go under 424. fillNodeHeight gains exactMinWidth, which
  measures that padding and takes it back off, and holdVueNodeMinWidth
  lends the floor to Nodes 2.0, whose corner drag reads the node's inline
  min-width instead. Both nodes use them; the other panels keep their old
  floors for now.
- README: the workflow-tools image shows Latent Size alone; the Seed card
  is gone.
2026-09-28 18:34:03 -05:00
ausboss 70c15690e8 Keep the video transform panels visible when zoomed out
The frontend hides a DOM widget below a zoom threshold unless it opts
out. The video transform nodes mounted their panel through the one
addDOMWidget call without hideOnZoom: false, so zooming out left an
empty box. A guard test now checks every DOM widget in the pack.
2026-09-23 23:55:50 -05:00
ausboss 699208dadc Prepare 2.0.0 release candidate 2026-09-07 19:56:23 -05:00
ausboss da5649e3b2 LoRA loader and panel polish round
- Drag-to-reorder actually drops: the row preview's reparenting silently
  released pointer capture, so the gesture now listens on the window for
  its whole lifetime.
- Step arrows on every strength box (configured step; Shift = 0.01), with
  range tinting carried over.
- The control bar (templates, stack toggle, count, settings) sits directly
  on top of the row stack and + Add LoRA pins to the node's bottom edge;
  the triggers output got its narrower name (slot links reconnect by index).
- Civitai lookup reads the whole response instead of the first TCP chunk,
  so successful lookups stop dying as 'lookup failed'.
- Compare and Load Video declare their height floors WITH the DOM-widget
  frame allowance, so minimum-height nodes stop shaving the caption and
  trim strip; panel_layout documents the rule.
- README and the LoRA doc catch up; panel_guards comments follow the
  body-as-layout-box reality.
2026-08-30 22:14:30 -05:00
ausboss 3f715a4af8 Ship the crush-list build-out: 7 new node files, replace button, video and LoRA polish
- New nodes: Image Resize plus the Utility group (Text, Integer, Float,
  Show Text, Math Expression, Select Every Nth, Split Batch, Merge
  Batches, Free Memory) - the dependency-free gaps that let shared
  workflows drop heavy packs.
- Replace with AusBoss nodes (prototype): preview-then-confirm graph
  rewrite swapping known third-party nodes for pack equivalents, with a
  tested translation map, per-node opt-out, and refuse-with-reason for
  nodes the pack cannot stand in for.
- Load Video: single-frame FRAME picker, an honest "what will load"
  label from the probed source rate, drop-a-video-to-restore. Save
  Video: format-aware widgets and a file_path output. Stitch Inpaint
  gained a blend_mask output, Select Frame negative from-the-end
  indexing, Image Size a batch count - all appended, saved workflows
  load unchanged.
- LoRA Loader: drag-to-reorder rows, hover thumbnails on rows, file
  size and date in the info card.
- Appearance: flagship scheme deepened to slate-teal; the retired
  bright-teal pair upgrades automatically via LEGACY_SCHEME_PAIRS.
  Optional queue-completion chime, off by default.
- Image Resize invariant: pixels are only invented on an explicit
  width+height pad request - scale-derived modes resolve divisible_by
  snaps with a sub-half-step resize, never bars.
- Docs refreshed for six stale pages, stale text and metadata fixed
  across the pack, the panel-height rule codified in AGENTS.md and the
  brand skill, and ausboss_node_tour.json added - a model-free example
  exercising 17 node types in one graph.

Validated: scripts/validate_nodes.py (24 files), 300 JS tests, all
Python suites under the ComfyUI embedded interpreter.
2026-08-27 13:30:35 -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 5a93c3c44a Move Frame Chooser to the lab
Pausing the graph for an interactive pick is a bigger surface than
anything else here - a server route, a resumable pause, a panel that has
to survive a reload - and it has open issues that are not worth holding a
release for. The lab is where that belongs until they are fixed.

Removes the node, its helpers, its panel, its shared DOM-free module,
its docs and its tests, and drops it from NODE_MODULES, PUBLIC_NODE_IDS,
the panel guard list and the README. _execution_helpers stays: Load Video
and Save Video use it too.

The port lives in ComfyUI-AusBoss-Lab as AUSBOSS_LAB_FrameChooser, with
its routes moved from /ausboss/frame_chooser to /ausboss_lab/ so both
packs can be installed at once. A saved workflow using the public id
reports it as missing.
2026-08-17 23:40:20 -05:00
ausboss 591f8505d2 Redraw the transform panel when its element resizes
Video Crop + Rotate + Pad drew its preview stretched after a resize. The
canvas is CSS-stretched to whatever box the panel is given, but
prepareCanvas() sizes the backing store from the element at DRAW time, so
a box that changes shape without a redraw shows the last frame at the
wrong aspect ratio.

The panel's ResizeObserver was created inside a `kind === "image"` branch,
grouped with the interactive drag handlers because the comment there
reasons about hit-testing. Hit-testing is only half of what it does. The
image node redrew on resize and looked right; the video node - a passive
preview with no other reason to redraw - did not.

Latent until panels started taking the node's leftover height: before
that the box could not change shape without a width change, and a width
change forced a relayout that redrew anyway.

The observer now runs for both kinds; only the drag handlers stay
image-only. Two tests hold the line - one fails if any canvas-painting
panel ships without a resize observer, one fails if this observer is
gated on node kind again. Verified by reintroducing the bug: the second
test fails and names the offending condition.
2026-08-17 23:18:22 -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 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 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 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 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 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 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