144 Commits

Author SHA1 Message Date
Alexander Eichhorn
06a1881bbd feat(ui): group nodes by category in add-node dialog (#8912)
* feat(ui): group nodes by category in add-node dialog

Add collapsible category grouping to the node picker command palette.
Categories are parsed from the backend schema and displayed as
expandable sections with caret icons. All categories auto-expand
when searching.

* feat(ui): add toggle for category grouping in add-node dialog and prioritize exact matches

Add a persistent "Group Nodes by Category" setting to workflow editor settings,
allowing users to switch between grouped and flat node list views. Also sort
exact title matches to the top when searching.

* fix: update test schema categories to match expected templates

* feat: add expand/collapse all buttons to node picker and fix node categories

Add "Expand All" and "Collapse All" link-buttons above the grouped
category list in the add-node dialog so users can quickly open or
close all categories at once. Buttons are hidden during search since
categories auto-expand while searching.

Fix two miscategorized nodes: Z-Image ControlNet was in "Control"
instead of "Controlnet", and Upscale (RealESRGAN) was in "Esrgan"
instead of "Upscale".

* refactor(nodes): clean up node category taxonomy

Reorganize all built-in invocation categories into a consistent set of
18 groups (model, prompt, conditioning, controlnet_preprocessors,
latents, image, mask, inpaint, tiles, upscale, segmentation, math,
strings, primitives, batch, metadata, multimodal, canvas).

- Move denoise/i2l/l2i nodes consistently into "latents"
- Move all mask creation/manipulation nodes into "mask"
- Split ControlNet preprocessors out of "controlnet" into their own group
- Fold "unet", "vllm", "string", "ip_adapter", "t2i_adapter" into larger
  groups
- Move metadata_linked denoise wrappers from "latents" to "metadata"
- Add missing category to ideal_size
- Introduce dedicated "canvas" group for canvas/output/panel nodes

Also adds the now-required `category` field to invocation template
fixtures in validateConnection.test.ts.

* Chore Ruff Format

---------

Co-authored-by: dunkeroni <dunkeroni@gmail.com>
2026-04-14 00:38:47 +00:00
Lincoln Stein
ed268b1cfc Feature (frontend): Add invisible watermark decoder node. (#8967)
* Initial plan

* Add invisible watermark decoding node and utility method

Co-authored-by: lstein <111189+lstein@users.noreply.github.com>

* chore(frontend): typegen

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lstein <111189+lstein@users.noreply.github.com>
2026-04-04 20:00:21 +00:00
dunkeroni
bd4bb075a5 bump node version to 2.0.0 2025-10-09 17:55:13 +11:00
dunkeroni
f8d0b43a9b change Colorspace title to "Color Space" 2025-10-09 17:55:13 +11:00
dunkeroni
50c77d9bf0 error message for incorrect mask size 2025-10-09 17:55:13 +11:00
dunkeroni
358cc0349e (chore) cleanup and schema 2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
417e6ebdbc Simplify mask application by pasting base on corrected instead of inverting mask
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
7919d659b7 Use PIL Image.paste() for mask application instead of numpy array blending
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
dunkeroni
ec665d2c7f remove extra conversion 2025-10-09 17:55:13 +11:00
dunkeroni
020d36b234 remove extra conversion 2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
d67272c027 Switch from LAB to YCbCr colorspace for simpler conversions
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
82548f9e41 Fix mask loading and blending: load as L, white=original, black=result
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
07a2369105 Add safety check for CDF normalization in histogram matching
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
b1f7e2dfdc Refactor ColorCorrectInvocation with histogram matching
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
psychedelicious
65ad392361 feat(nodes): add node to prep images for FLUX Kontext 2025-08-04 23:03:12 +10:00
dunkeroni
139ecc10ce ruff 2025-05-27 07:28:47 +10:00
dunkeroni
23627cf18d compositing in frontend 2025-05-27 07:28:47 +10:00
psychedelicious
021a334240 fix(nodes): fix spots where default of None was provided for non-optional fields 2025-05-20 10:47:02 +10:00
psychedelicious
4109ea5324 fix(nodes): expanded masks not 100% transparent outside the fade out region
The polynomial fit isn't perfect and we end up with alpha values of 1 instead of 0 when applying the mask. This in turn causes issues on canvas where outputs aren't 100% transparent and individual layer bbox calculations are incorrect.
2025-03-31 11:17:00 +11:00
psychedelicious
258bf736da fix(nodes): handle zero fade size (e.g. mask blur 0)
Closes #7850
2025-03-28 08:14:06 +11:00
psychedelicious
9ca071819b chore(nodes): remove beta/prototype flag from a lot of stable nodes 2025-03-27 08:08:44 +11:00
psychedelicious
c013a6e38d feat(nodes): deprecate canvas_v2_mask_and_crop 2025-03-21 10:24:03 +11:00
psychedelicious
6cfeb71bed feat(nodes): add expand_mask_with_fade to better handle canvas compositing needs
Previously we used erode/dilate and a Gaussian blur to expand and fade the edges of Canvas masks. The implementation a number of problems:
- Erode/dilate kernel sizes were not calculated correctly, and extra iterations were run to compensate. The result is the blur size, which should have been pixels, was very inaccurate and unreliable.
- What we want is to add a "soft bleed" - like a drop shadow with no offset - starting from the edge of the mask, extending out by however many pixels. But Gaussian blur does not do this. The blurred area starts _inside_ the mask and extends outside it. So it kinda blurs inwards and outwards. We compensated for this by expanding the mask.
- Using a Gaussian blur can cause banding artifacts. Gaussian blur doesn't have a "size" or "radius" parameter in the sense that you think it should. It's a convolution matrix and there are _no non-zero values in the result_. This means that, far away from the mask, once compositing completes, we have some values that are very close to zero but not quite zero. These values are quantized by HTML Canvas, resulting in banding artifacts where you'd expect the blur to have faded to 0% alpha. At least, that is my understanding of why the banding artifacts occur.

The new node uses a better strategy to expand the mask and add the fade out effect:
- Calculate the distance from each white pixel to the nearest black pixel.
- Normalize this distance by dividing by the fade size in px, then clip the values to 0 - 1. The result represents the distance of each white pixel to its nearest black pixel as a percentage of the fade size. At this point, it is a linear distribution.
- Create a polynomial to describe the fade's intensity so that we can have a smooth transition from the masked region (black) to unmasked (white). There are some magic numbers here, deterined experimentally.
- Evaluate the polynomial over the normalized distances, so we now have a matrix representing the fade intensity for every pixel
- Convert this matrix back to uint8 and apply it to the mask

This works soooo much better than the previous method. Not only does it fix the banding issues, but when we enable "output only generated regions", we get a much smaller image. Will add images to the PR to clarify.
2025-03-21 10:24:03 +11:00
psychedelicious
534f993023 feat(nodes): add apply_mask_to_image node
It simply applies the mask to an image.
2025-03-21 10:24:03 +11:00
dunkeroni
9e6f3e9338 image channel multiply node loads as RGBA now 2025-02-11 18:32:56 +11:00
psychedelicious
8fc5d3dd20 chore(nodes): bump versions of changed nodes 2025-02-04 12:06:17 +11:00
dunkeroni
9c7bac693b fix image adjust hue handling 2025-02-04 12:06:17 +11:00
dunkeroni
cc27730cb4 fix: image channel invocations respect alpha 2025-02-04 12:06:17 +11:00
dunkeroni
58255ab7ba add adjust image filter to canvas 2025-02-04 12:06:17 +11:00
psychedelicious
e926d2f24b fix(nodes): add beta classification to new inpainting support nodes 2025-01-21 17:58:47 +11:00
psychedelicious
cf4c79fe2e feat(nodes): add PasteImageIntoBoundingBoxInvocation 2025-01-21 17:45:32 +11:00
psychedelicious
e0edfe6c40 feat(nodes): add CropImageToBoundingBoxInvocation 2025-01-21 17:45:32 +11:00
psychedelicious
1ad65ffd53 feat(nodes): re-title "Mask from ID" -> "Mask from Segmented Image" 2025-01-21 17:45:32 +11:00
psychedelicious
14b5c871dc feat(nodes): simplify MaskFromIDInvocation 2025-01-21 17:45:32 +11:00
psychedelicious
3f70e947fd chore: ruff 2025-01-16 09:27:36 +11:00
dunkeroni
157290bef4 add: size option for image noise node and filter 2025-01-16 09:27:36 +11:00
dunkeroni
b7389da89b add: Noise filter on Canvas 2025-01-16 09:27:36 +11:00
dunkeroni
2b122d7882 add: image noise invocation 2025-01-16 09:27:36 +11:00
dunkeroni
ded9213eb4 trim blur splitting logic 2025-01-16 09:27:36 +11:00
dunkeroni
9d51eb49cd fix: ImageBlurInvocation handles transparency now 2025-01-16 09:27:36 +11:00
dunkeroni
0a6e22bc9e fix: ImagePasteInvocation respects transparency 2025-01-16 09:27:36 +11:00
psychedelicious
6540381fb5 feat(nodes): clean up canvas v2's output node
- Marked internal
- Changed output type to plain ol' `ImageOutput`
- Removed unused code
2024-09-20 16:01:02 +03:00
psychedelicious
1f1777f7a6 feat(nodes): CanvasV2MaskAndCropInvocation can paste generated image back on source
This is needed for `Generate` mode.
2024-09-06 22:56:24 +10:00
psychedelicious
257b18230a tidy(app): clean up app changes for canvas v2 2024-09-06 22:56:24 +10:00
psychedelicious
5fb9ffca6f feat(nodes): temp disable canvas output crop 2024-09-06 22:56:24 +10:00
psychedelicious
919f8b1386 fix(nodes): fix canvas mask erode
it wasn't eroding enough and caused incorrect transparency in result images
2024-09-06 22:56:24 +10:00
psychedelicious
2c5e76aa8b feat(invocation): reduce canvas v2 mask & crop mask dilation 2024-09-06 22:56:24 +10:00
psychedelicious
9ce74d8eff feat(app): update CanvasV2MaskAndCropInvocation 2024-09-06 22:56:24 +10:00
psychedelicious
513f95e221 feat(app): add CanvasV2MaskAndCropInvocation & CanvasV2MaskAndCropOutput
This handles some masking and cropping that the canvas needs.
2024-09-06 22:56:24 +10:00
Ryan Dick
1d449097cc Apply ruff rule to disallow all relative imports. 2024-07-04 09:35:37 -04:00