Commit Graph
13 Commits
Author SHA1 Message Date
ausboss 653cf2c8cc Merge branch 'fix/transform-first-pick-refit' into fix/clip-node-ux
# Conflicts:
#	CHANGELOG.md
#	js/shared/transform_editor.mjs
2026-09-29 21:43:45 -05:00
ausboss fe7f301264 Crop + Rotate + Pad: clearer padlock, Fit, added space and editor
The padlock:
- Reset and tapping the lit ratio turn it off.
- It does nothing on the untouched picture (the row says Source), so a
  trim there only trims.
- The row says Held while it is on, and a locked drag splits the new
  bands evenly (each move is solved from where the drag started).
- Reset crop also removes the bands the lock added.
- The lit ratio and the lock share the pack's solid teal "on" look;
  hover is a light outline.

Shapes and sizes:
- A picture within about 1% of a ratio counts as that ratio: tapping 9:16
  on a nearly 9:16 photo adds no 1 px band.
- While a ratio is lit, the line under the picture says what it did,
  and "Already 9:16: nothing to add. Pick another ratio or turn it." when
  there was nothing to do (a saved ratio re-applies to every new picture).
- The resize warning reads "1.5% taller: each side rounds to 32 px"; its
  tooltip names a Step that avoids it, and in pad mode Even out adds a few
  pixels of padding so nothing stretches.
- Fit dims and says "pick a ratio first" until a ratio is lit.
- Over the picture, the cursor and small arrows show only the ways it can
  move; with nowhere to go it is a plain pointer.

Drawing:
- Added space is drawn in the real fill colour with a faint hatch, and
  only the picture the crop cuts away is darkened, so black bands on the
  black stage show.
- The rotate knob keeps clear of the padding diamonds and crop squares.
- On a big node the controls stay at most 460 px wide, centred, and only
  the picture grows. A new picture fits the picture area to its shape,
  never taller than the height you gave it.

Words: Align is "Round canvas to", Local path is "Server file", Resize is
an off | on switch, and the canvas row labels read like the others.

The full editor is built from the node's own controls: the ratio row with
its turn button and padlock, the Fit switch, and number boxes for the
rotation (Shift for 0.1 degree) in place of the coarse slider. Ratios
from ausboss_presets.json that no button shows sit in a More list. The
size box keeps clear of the handles, and the editor's button style no
longer reaches the number boxes.
2026-09-29 21:33:25 -05:00
ausboss 8ed782de89 Crop + Rotate + Pad: one state per ratio button, a padlock, a real turn
Prototype of the ratio row, for review. A chip used to stay lit after a
drag changed the shape (16:9 lit on a 1889x1280 canvas), a second tap on
it locked and a third cleared every pad, the portrait/landscape button
threw away hand edits, a locked diamond dragged inward did not move, and
Crop | Pad looked like two more ratio chips.

- A chip is lit only while the canvas (crop plus padding, before Align)
  has its ratio; the pick (properties.ausboss_fit_aspect) is dropped when
  a gesture leaves it, so a new clip is only fitted to a shape the canvas
  still has. Without a picture a tapped ratio waits for the first one.
- Tap = reach the ratio (pad, or crop with Fit on crop), tap the lit one =
  back to the whole picture. No other chip state.
- Holding the shape is a padlock button (ausboss_aspect_lock): drags keep
  the lit ratio, or the custom one, from the moment you grab a handle.
- The orientation button turns the shape: pad mode pads the current crop
  to the turned ratio, crop mode turns the crop box about its centre.
  Nothing to turn (no picture, untouched, square): only the labels turn.
- Custom / Source caption, and the real ratio on the size line.
- Fit is a segmented pill; switching it re-reaches a lit ratio.
- Rotation keeps a lit ratio (and a held custom one).
- Dragging the picture where the crop spans the source slides it inside
  its padding (slidePadding).
- The editor's Ratio list applies at once; Hold shape is the padlock.

Saved properties and widget values keep their names and meaning; an old
locked chip opens with the padlock on. Pure rules in transform_geometry
(canvasSize, aspectMatches, turnAspect, turnedCrop, padAround,
slidePadding, ratioLabel, isUntouched) with node:test coverage.
2026-09-29 16:22:27 -05:00
ausboss f1fedbf345 Crop + Rotate + Pad: keep the picture on the node big enough to see
The stage could be squeezed to about 130 px on all three nodes: the
declared floors counted the rows around it short, and the Clip node's rows
alone take 450 px. A padded portrait clip ended up a sliver in a 16:9
canvas.

- The stage's floor follows its width (stageHeightForWidth: 0.6 x width,
  200 to 340 px). The panel's minimum is the measured rows around the
  stage plus that floor, so a corner drag stops there; before the panel
  is on screen a per-kind estimate stands in. A new node opens at it.
- keepStageRoom grows the node to the same floor when a row appears later
  (Resize, a wrapping readout), and sets it as the stage's CSS minimum so
  Nodes 2.0, which sizes nodes by content, holds it too.
- exactMinWidth and holdVueNodeMinWidth make 330 the real minimum width in
  both renderers (the classic corner drag jumped to 434; Nodes 2.0 went
  down to 225 and crushed the chip row).
- The source card's "Choose an uploaded ..." line hides once a file is
  chosen, which is the room older layouts need for the new floor.
- The LTX 2.3 example moves the two nodes under the Clip node down for its
  new height; the contract and a live load find no overlaps.
2026-09-29 16:05:38 -05:00
ausboss b62bda9ba2 Crop + Rotate + Pad: the first file after a blank load is a new picture
A transform node is created on the first file in the input folder. When
a workflow saved with an empty loader configured it blank, the node kept
remembering that first file, because a blank source never replaced the
remembered one. Picking the first file then looked like no change: the
workflow's saved rotation, crop and padding stayed and a lit ratio was
not refit. Any other file reset as it should.

The node's first sync and a workflow load now remember what the node
holds, blank included (rememberedSource in transform_geometry.mjs). Only
a blank the user makes, such as Local path before a path is typed, keeps
the last source, so going back to the same file is still no change.
Covers the image node and both video nodes.
2026-09-29 05:15:06 -05:00
ausboss a3a9be54bf Crop + Rotate + Pad: rotation keeps the crop, size readout, Clip Length
- Rotating keeps the crop's size over the same part of the picture from
  the knob, slider, number box and Reset rotation (cropForRotation).
- A readout under the picture names every step that sets the output size
  (crop -> pad -> align -> resize) and warns when the resize Step
  stretches the picture or Align pads fill ahead of a resize; ticking
  Resize shows Megapixels and Step on the face.
- Locked-aspect crops use integer maths (_ratio_box / ratioBox), so the
  size shown equals the run.
- Image Crop + Rotate + Pad's four resize inputs are optional, so API
  prompts saved before them validate again.
- Video Crop + Rotate + Pad -> Clip: one Length switch replaces the Fixed
  frames and Limit boxes; OUT sits on the last output frame; a connected
  fixed_frames / frame_load_cap takes over the length.
- The stitcher pastes the unfaded canvas when feather > 0
  (transform_pil_layers / keep_unfaded). Superseded by mask-only feather
  and dropped in the next commit.

Carries a copy of the editor Cancel / discard-prompt change from
feat/editor-cancel-discard (#73), which this work was built on.
2026-09-26 22:21:16 -05:00
ausboss beb98ad6a8 Video timeline overhaul, outpaint-ready clip canvas, example styling
Video Crop + Rotate + Pad -> Clip / -> Frame:
- The rail under the preview is a timeline: playhead scrubbing on the node
  face, frame-accurate IN/OUT handles that carry the playhead, Set IN/OUT
  and I/O keys in the editor; js/shared/timeline_math.mjs mirrors the
  backend's inclusion rule and emits hundredth-grid seconds.
- Scrubbing no longer flickers: storyboard tiles only stand in when nearer
  than the frame on stage and are decoded at their target times; the scrub
  session returns the frame it already decoded instead of the next one;
  served previews are cached.
- Aspect lock on the format chips (pad, lock, clear) with lockPadding in
  transform_geometry; Lock aspect in the editor.
- A new source keeps fill, feather, resize, Snap and Limit and re-pads to
  the lit chip; a canvas row (fill, feather, resize) sits on the node face.
- The clip node declares a black fill and feather 0 as its defaults and the
  editor's Reset all follows the node's own declaration, so a fresh node or
  a reset never lands on the grey, feathered canvas the LTX IC-LoRA cannot
  paint; image nodes keep grey/24.

Examples:
- LTX 2.3 Video Outpaint: Select Frame -> core Generate Text writes the
  positive prompt; note rewritten with the tested rules (53 renders over
  six clips: only fill #000000 + feather 0 decide painting).
- Core model loaders coloured and Workflow Notes grown to fit across the
  other examples.
2026-09-09 17:03:01 -05:00
ausboss 699208dadc Prepare 2.0.0 release candidate 2026-09-07 19:56:23 -05:00
ausboss dd118c7386 Image Crop + Rotate + Pad: megapixel resize, quick row, relocated size readout
- Optional resize of the transformed output to a pixel budget, with core
  Scale Image to Total Pixels semantics: megapixels x 1024^2, aspect
  preserved, each dimension rounded to resolution_steps. The image uses
  the chosen filter (lanczos/area/bicubic/bilinear/nearest-exact); the
  mask always resizes bilinear so feathered edges cannot ring. The math
  is mirrored py+js (scale_to_megapixels / scaleToMegapixels) and
  fixture-tested on both sides; the new widgets append after the stable
  V1 set so saved workflows keep loading, and IS_CHANGED fingerprints
  them.
- A quick row under the node's canvas: Reset (rotation, crop, padding),
  a Feather toggle that remembers the amount it turns off, and the
  Resize toggle with its megapixel scrub box.
- The editor gains a Resize output section (megapixels and steps as
  scrub controls, method select) and its status names the exact resized
  size.
- The output size readout moved off the pixels: centered below the image,
  flipping above when clipped, and showing the resize target.
- CHANGELOG entries for this round and the two commits before it.
2026-08-30 22:14:39 -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 ac8cf4832c Attach rotate knob to the rotated image corner, feather QoL, live fade preview
The rotation knob previously anchored to axis-aligned bounding boxes, so
under rotation or padding it floated in space, visually attached to
nothing. It now rides the actual top-right corner of the rotated image
quad (short stem, offset outward along the corner's radial direction)
and orbits with the image as the angle changes - the grab-the-object's-
corner model design tools use. Verified at 0/30/-60/135 degrees: the
drawn knob sits exactly at the computed rotated-corner position.

Feather quality of life: default is now 24 (a no-op until padding or
rotation creates generated area), and the slider is paired with a number
box with single-step arrows for granular control; both stay in sync and
values above the slider range remain typeable up to 4096.

The sidebar Preview now renders the feather fade live: it builds the
generated-area mask (padding, rotation corners, source alpha), blurs it,
draws it twice to match the engine's edge-pinned ramp, tints it with the
fill color, and overlays - so tweaking feather shows the real blend as
you type. Verified: preview pixels near the crop edge move measurably
toward the fill color as feather increases.
2026-07-25 00:21:08 -05:00
ausboss 7436cf0c12 Fix editor geometry parity, video seek performance, and preview route exposure
Review fixes verified against live ComfyUI 0.28.0:

- rotatedSize now reproduces Pillow's expand=True output exactly (transpose
  fast path at axis angles, corner extents elsewhere). The previous formula
  was 1px short on 34 of 78 sampled size/angle combos, so editor-predicted
  output dimensions disagreed with queued results at most free angles.
  Verified 0 mismatches across 6776 combinations and end-to-end on the
  server (predicted 848x496 == queued image and mask at 77.7 degrees).
- decode_video_frame seeks to the nearest keyframe and decodes forward
  instead of scanning from frame 0, with the sequential scan kept as the
  fallback for files without usable timestamps. Scrubbing long videos no
  longer decodes the entire prefix per preview request.
- Preview routes no longer serve arbitrary local paths to any HTTP client:
  local-path previews outside ComfyUI's input/output/temp folders now
  require AUSBOSS_TRANSFORM_LOCAL_PREVIEW=1, checked before touching the
  filesystem so denied requests cannot probe path existence. Queued
  workflows are unaffected.
- Editor: metadata is cached per source instead of refetched every scrub
  tick, timeline seeks fetch only the frame with a 70ms trailing debounce,
  AbortError from superseded requests no longer paints the error state,
  and switching source mode before picking a file no longer resets the
  transform.
- Tests: 13 -> 18 Python (seek vs sequential ground truth, time-mode seek,
  out-of-range clamp, preview gate), 8 -> 9 JS (Pillow-verified rotated-size
  fixtures including the odd/even transpose edge).
2026-07-24 22:00:27 -05:00
ausboss 83fae3b36b Build polished transform editors 2026-07-24 20:43:53 -05:00