Author SHA1 Message Date
jetthuangai 359a3b56dd Bump version 1.6.1 2026-10-18 08:33:37 +07:00
jetthuangai d23c54eda3 refactor: split image tools, share helpers, harden routes (no node changes)
- nodes/image/image_tools_nodes.py (1776 lines) split into save_image_path,
  folder_loaders, layer_composite, image_label, image_compare and
  image_resize_unit; folder helpers in core/image_folders.py (set-based
  dedupe), image helpers in core/image_ops.py
- One tensor -> PIL converter (core.utils.tensor_to_pil, rgb=/keep_alpha=)
  that keeps the tensor's dtype; bf16 supported; duplicates removed from grid,
  large save and preview cache
- core/mask_ops.mask_bbox replaces five bbox copies; model helpers moved to
  core/model_files.py; Pillow fromarray(mode=) uses removed
- Routes moved to core/folder_routes.py: no absolute paths in responses,
  recursive honoured, proper status codes, scans off the event loop; large
  preview routes reject malformed JSON and hide paths
- web/nh_widget_utils.js shared by all extensions; widgets hidden via the
  frontend's `hidden` property when available; folder image count honours
  recursive
- A wired Load Images Folder path no longer fingerprints ComfyUI's input folder
- Node ids, inputs and outputs unchanged (69 nodes); new tests for routes,
  web helpers, mask ops, channel handling and Pillow usage
2026-10-18 08:33:36 +07:00
123 changed files with 329 additions and 14913 deletions
+319 -113
View File
@@ -1,148 +1,354 @@
<p align="center"><img src="docs/assets/banner.jpg" alt="NH-Nodes — image, mask, resolution and workflow nodes for ComfyUI" width="100%"></p>
<p align="center">
<a href="https://registry.comfy.org/nodes/nh-nodes"><img src="https://img.shields.io/badge/ComfyUI_Registry-nh--nodes-2563eb" alt="ComfyUI Registry"></a>
<a href="https://github.com/jetthuangai/NH-Nodes/actions/workflows/tests.yml"><img src="https://github.com/jetthuangai/NH-Nodes/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT_(see_notices)-16a34a" alt="License"></a>
<a href="docs/en/README.md"><img src="https://img.shields.io/badge/Docs-EN_%7C_VI-0f766e" alt="Documentation"></a>
</p>
<p align="center"><b>English</b> · <a href="docs/vi/README.md">Tiếng Việt</a></p>
# NH-Nodes for ComfyUI
**69 production-focused nodes** for ComfyUI: load and save image sets with their metadata, tile and composite large
images, pick the right resolution for current models and put results back into the original frame, refine masks,
segment garments and faces, build VTON masks, route workflows with lazy switches, generate prompts, and test many
LoRAs or models from one node.
Production-focused custom nodes for ComfyUI workflows: image loading, tiling,
compositing, mask utilities, smart resize, logic routing, prompt/text tooling,
batch helpers, indexed model loaders, garment/portrait segmentation, and VTON
preprocessing.
Every node is documented with a visual card, its inputs and outputs, and examples — in
[English](docs/en/README.md) and [Vietnamese](docs/vi/README.md).
[![ComfyUI Registry](https://img.shields.io/badge/ComfyUI_Registry-nh--nodes-2563eb)](https://registry.comfy.org/nodes/nh-nodes)
[![GitHub](https://img.shields.io/badge/GitHub-jetthuangai%2FNH--Nodes-111827)](https://github.com/jetthuangai/NH-Nodes)
[![License: MIT](https://img.shields.io/badge/License-MIT-16a34a.svg)](LICENSE)
## Highlights
- **Author:** [jetthuang.com](https://jetthuang.com)
- **Hugging Face:** [nhathoangfoto](https://huggingface.co/nhathoangfoto)
- **Support:** [PayPal](https://paypal.me/nhathoangfoto)
<table>
<tr>
<td width="50%"><a href="docs/en/resolution.md"><img src="docs/assets/examples/resize-modes.jpg" alt="Resize modes"></a><br>
<b>Resolution done right</b> — presets for FLUX.2, Qwen-Image and Z-Image, cover / contain / stretch resizing, and an
exact round trip back to the original frame.</td>
<td width="50%"><a href="docs/en/image-compose.md"><img src="docs/assets/examples/tile-untile.jpg" alt="Tile and untile"></a><br>
<b>Large images</b> — split into overlapping tiles, process them, and blend them back seamlessly; deep-zoom preview
for images too big for the canvas.</td>
</tr>
<tr>
<td><a href="docs/en/vision.md"><img src="docs/assets/examples/garment-segment.jpg" alt="Garment segmentation"></a><br>
<b>Segmentation</b> — garment and face-part masks from SegFormer models, plus VTON garment masks with pose and
parsing.</td>
<td><a href="docs/en/mask.md"><img src="docs/assets/examples/mask-morphology.jpg" alt="Mask morphology"></a><br>
<b>Mask tools</b> — fast grow / shrink on the CPU or the GPU, hole filling, soft edges, bounding boxes and
aspect-ratio matching.</td>
</tr>
<tr>
<td><a href="docs/en/image-compose.md"><img src="docs/assets/examples/layer-layout.jpg" alt="Layer layout"></a><br>
<b>Compositing</b> — layouts, layer stacks with alpha, labelled grids and side-by-side comparisons.</td>
<td><a href="docs/en/logic.md"><img src="docs/assets/examples/grid-composite.jpg" alt="Grid composite"></a><br>
<b>Workflow logic</b> — lazy If/Else and switches that run only the chosen branch, safe math, counters, lists and
prompt tools.</td>
</tr>
</table>
---
## Why NH-Nodes
NH-Nodes is built for practical workflow construction. It focuses on reusable
building blocks that remove repetitive graph work:
- Load images with filename/path metadata.
- Split images into tiles, upscale or process tiles, then stitch them back.
- Build image grids, layer composites, comparisons, and labeled previews.
- Resize images and masks with predictable aspect-ratio behavior.
- Route workflow branches with boolean logic and generic data switches.
- Generate prompts from templates, regex, lists, schedules, and text utilities.
- Pick indexed LoRA/diffusion models for larger configurable workflows.
- Prepare VTON masks, agnostic images, DensePose/parsing outputs, and related masks.
---
## Installation
**ComfyUI Manager** — search for `NH-Nodes`, install, restart ComfyUI.
### ComfyUI Manager
**Comfy CLI**
Search for `NH-Nodes`, install, then restart ComfyUI.
### Comfy CLI
```bash
comfy node install nh-nodes
```
**Manual**
### Manual
```bash
cd ComfyUI/custom_nodes
git clone https://github.com/jetthuangai/NH-Nodes.git
cd NH-Nodes
python -m pip install -r requirements.txt
pip install -r requirements.txt
```
Restart ComfyUI afterwards. Requirements: a recent ComfyUI (tested with 0.41) and Python 3.10+.
Restart ComfyUI after installation.
### Optional: VTON and segmentation models
---
- **VTON Ultimate Processor** needs ONNX Runtime, which is not installed automatically (the CPU wheel would overwrite an
existing GPU build). Install one of them into ComfyUI's Python:
`python -m pip install onnxruntime-gpu` (NVIDIA) or `python -m pip install onnxruntime` (CPU).
- **Garment Segment**, **Portrait Segment** and **VTON** download their models from Hugging Face on first use (pinned
revisions, only the needed files). To keep models elsewhere, add these keys to `extra_model_paths.yaml`:
## Featured Workflows
```yaml
my_models:
base_path: D:/ai-models/
nh_nodes: NH-Nodes/ # SegFormer models (garment, face parsing)
vton_mask: ComfyUI-Vton-Mask/ # VTON pose + parsing ONNX models
```
### Tile, Process, Untile
## Quick start
Use this when an image is too large for a model, or when every tile needs the
same enhancement/upscale step.
| Goal | Chain | Guide |
|---|---|---|
| Upscale or refine a huge image piece by piece | Load Image → **Image Tile** → your sampler/upscaler per tile → **Image Untile** | [image-compose](docs/en/image-compose.md#image-tile-nh) |
| Generate at the model's native size, then restore the original framing | Load Image → **NH Smart Ratio Image Resize** → edit → **NH Restore Image Geometry** | [resolution](docs/en/resolution.md) |
| Inpaint only the clothes | Load Image → **Garment Segment** → **Mask Morphology** (grow) → inpaint | [vision](docs/en/vision.md) |
| Compare many LoRAs, one per queue | **Counter** → **Load LoRA Model Index** (index) → sampler → **Image Label** (prints the LoRA name) → Save Image | [loaders](docs/en/loaders.md) |
| Run one of two branches without executing the other | condition → **If/Else** (lazy) → … | [logic](docs/en/logic.md#ifelse-nh) |
```text
Load Image -> Image Tile (NH) -> upscale/process tiles -> Image Untile (NH)
```
## Node catalog
`Image Tile (NH)` supports:
| Group | Nodes | Guide |
|---|---|---|
| Image — load & save | Load Image Info, Load Images Folder, Load images matching, Save Image Path, NH Save Large Image | [EN](docs/en/image-io.md) · [VI](docs/vi/image-io.md) |
| Image — compose | Image Tile, Image Untile, Image Grid Composite, Layer Layout Composite, Layer Stack Composite, Image Compare, Image Label, Image Resize Unit | [EN](docs/en/image-compose.md) · [VI](docs/vi/image-compose.md) |
| Image — large preview | NH Large Image Preview, NH Large Image Compare, NH Large Preview Cache Manager | [EN](docs/en/image-preview.md) · [VI](docs/vi/image-preview.md) |
| Image — mask-based retouch | NH Mask-Aware Resize, NH Agnostic Image Generator, NH Simple Face Paste | [EN](docs/en/image-retouch.md) · [VI](docs/vi/image-retouch.md) |
| Resolution | NH Smart Resolution Picker, NH Smart Ratio Image Resize, NH Ratio Preset Image Resize, NH Remove Resize Padding, NH Restore Image Geometry | [EN](docs/en/resolution.md) · [VI](docs/vi/resolution.md) |
| Mask | Mask Morphology, Mask Properties, NH Create Box Mask, NH Mask Aspect Ratio Match | [EN](docs/en/mask.md) · [VI](docs/vi/mask.md) |
| Vision | Garment Segment, Portrait Segment | [EN](docs/en/vision.md) · [VI](docs/vi/vision.md) |
| VTON | VTON Ultimate Processor | [EN](docs/en/vton.md) · [VI](docs/vi/vton.md) |
| Logic | Compare, Logic Gate, If/Else, Switch N, Any Switch, Any Branch Switch, Gate Switch, Value Match Index, Math Eval, Random Choice | [EN](docs/en/logic.md) · [VI](docs/vi/logic.md) |
| Text | Prompt Template, Prompt Scheduler, String Operations, Prompt Join, Text Split, Regex Extract, Text Index, Text Concatenate, Text Split Lines, Text Random Line | [EN](docs/en/text.md) · [VI](docs/vi/text.md) |
| Batch & lists | Batch Index, Batch Merge, Counter, List Create, List Index, List Filter, Any List Split | [EN](docs/en/batch-lists.md) · [VI](docs/vi/batch-lists.md) |
| Loaders | Load LoRA Model Index, Load LoRA Clip Index, Load Diffusion Model Index, Load VAE Index, Load Clip Index | [EN](docs/en/loaders.md) · [VI](docs/vi/loaders.md) |
| Utils | Multi-Slider (FLOAT/INT), Boolean Switch, Pack Universal, Unpack Universal, Universal Slider Builder *(deprecated)* | [EN](docs/en/utils.md) · [VI](docs/vi/utils.md) |
- `original_ratio`: derive tile dimensions from the original image aspect ratio.
- `custom`: use explicit tile width and height.
- `square`: force square tiles, for example `1024 x 1024`.
- Automatic overlap calculation.
- Edge padding so square/custom tile outputs keep the requested tile size.
All nodes live under **NH-Nodes** in the node menu; search by name or by node id (for example `NH_ImageTile`).
`Image Untile (NH)` uses `tile_data` from the tile node to stitch results back.
It also handles tiles that were resized or upscaled, such as 2x or 3x per tile.
## Documentation
### Grid Contact Sheet
- **Guide:** [English](docs/en/README.md) · [Tiếng Việt](docs/vi/README.md)
- **PDF guides:** [English](https://github.com/jetthuangai/NH-Nodes/releases/latest/download/NH-Nodes-Guide-EN.pdf) ·
[Tiếng Việt](https://github.com/jetthuangai/NH-Nodes/releases/latest/download/NH-Nodes-Huong-dan-VI.pdf)
- **Changelog:** [docs/CHANGELOG.md](docs/CHANGELOG.md) — read it when updating: some fixes change outputs on purpose.
```text
Image batch -> Image Grid Composite (NH) -> Preview Image
```
Use manual cell size or first-image cell size. Resize modes include `stretch`,
`pad`, and `fill`.
### Metadata-Aware Image Load
```text
Load Image Info (NH) -> image / mask / file_name / path
```
Useful for naming outputs, logging source images, or routing by filename.
### Smart Resolution Resize
```text
Load Image -> NH Smart Ratio Image Resize -> (your pipeline) -> NH Remove Resize Padding
```
`NH Smart Ratio Image Resize` picks the closest model preset itself from
`model_family` + `resolution_level`, so it does not need `NH Smart Resolution
Picker` upstream. Resize with cover crop, contain pad, or stretch behavior.
In `contain_pad` mode it also emits `resize_data` describing the content region,
padding, and scale factor. Feed that into `NH Remove Resize Padding` at the end
of the pipeline to crop the padded border back off (`content_region`) or to
restore the original input size (`original_size`).
For `cover_crop`, use `NH Restore Image Geometry` after processing. Connect the
processed image to `image`, the source image to `original_image`, and the resize
node's `resize_data` to the matching input. It returns an image at the exact
original dimensions, with processed content placed back in its original region
and cropped-away borders retained from the source. Its `mask` is white in the
restored region and black in the retained borders; use it for masked blending
with the original, optionally softening the mask edges first.
Processed images may be upscaled, including by a non-integer factor, provided
their framing is unchanged. Additional crops, rotations, or model-generated
changes in geometry cannot be reversed by this metadata. The restore node also
accepts `contain_pad` and `stretch` metadata and supports matching batches or
singleton batch broadcasting. Restoration uses bicubic (default), bilinear, or
nearest sampling; it does not recover details lost during downsampling.
Use `NH Smart Resolution Picker` when you need target dimensions and a latent
for text-to-image, instead of resizing an existing image.
### Garment and Portrait Segmentation
```text
Load Image -> Garment Segment (NH) [part=upper_garment] -> mask / cutout_rgba / mask_image
Load Image -> Portrait Segment (NH) [hair + face] -> mask / cutout_rgba / mask_image
```
SegFormer-based masks at input resolution. `cutout_rgba` is the input image
with the mask as alpha (RGB is left untouched outside the mask); `mask_image`
is the mask as an RGB preview. Dresses and jumpsuits belong to `upper_garment`. Both nodes share `mask_expand`, `mask_blur`, and `fill_holes`.
Choose `part=all_garments` to combine upper/lower garments, footwear and headwear
in one mask, for example a shirt and pants together. `attach_parts` still controls
whether touching pockets, zippers and other garment decorations are included.
Models are auto-downloaded to `models/NH-Nodes/` on first use (existing
`models/face_parsing` or `models/RMBG/segformer_fashion` copies are reused).
---
## Node Catalog
### Image Loading and Saving
| Node | Purpose |
|---|---|
| `Load Image Info (NH)` | Load one image and output `IMAGE`, `MASK`, file name, and path. |
| `Save Image Path (NH)` | Save image batches to a chosen folder and output saved filenames/path/count. |
| `NH Save Large Image` | Save full-resolution images without attaching heavy full-res previews to the canvas. |
| `Load Images Folder (NH)` | Load images from a folder by index/step, with filename and path outputs. |
| `Load images matching` | Load source/matching images by text, folder context, and matching rules. |
### Image Tiling, Grid, and Composition
| Node | Purpose |
|---|---|
| `Image Tile (NH)` | Split image batches into overlapping tiles with metadata for reconstruction. |
| `Image Untile (NH)` | Rebuild full images from processed/upscaled tiles and tile metadata. |
| `Image Grid Composite (NH)` | Combine an image batch into a configurable grid. |
| `NH Large Image Preview` | Preview large images with lightweight canvas thumbnails and passthrough output. |
| `NH Large Image Compare` | Compare large A/B images with lightweight canvas proxy and tiled slider/side/difference viewer. |
| `NH Large Preview Cache Manager` | Inspect and clean the NH large preview tile cache by age, size, or cache id. |
| `Layer Layout Composite (NH)` | Place layers into preset, grid, or custom layout slots. |
| `Layer Stack Composite (NH)` | Paste multiple layers onto a background using explicit coordinates. |
| `Image Resize Unit (NH)` | Resize by pixel/mm/cm using stretch, pad, crop, or lock-ratio modes. |
| `Image Compare (NH)` | Compare two images side-by-side, top/bottom, split, difference, or overlay. |
| `Image Label (NH)` | Add header/bottom labels with font, padding, color, and outline controls. |
| `NH Agnostic Image Generator` | Create agnostic/masked/composite images for inpaint and VTON workflows. |
| `NH Simple Face Paste` | Paste a source face region into a target using mask feathering. |
### Smart Resolution
| Node | Purpose |
|---|---|
| `NH Smart Resolution Picker` | Pick model/preset-aware dimensions and latent setup. |
| `NH Smart Ratio Image Resize` | Auto-pick the closest model preset for the source aspect, then resize with cover, contain, or stretch; outputs `resize_data` for padding removal. |
| `NH Ratio Preset Image Resize` | Resize to a chosen model preset ratio with crop, pad, or fill behavior. |
| `NH Remove Resize Padding` | Remove the padded border from processed images using resize metadata. |
| `NH Restore Image Geometry` | Restore processed or upscaled images to original coordinates with a blend mask; keep source pixels outside the crop. |
### Vision Segmentation
| Node | Purpose |
|---|---|
| `Garment Segment (NH)` | Mask `upper_garment` (tops, jackets, coats, dresses, ties, scarves, collars, sleeves), `lower_garment` (pants, shorts, skirts, belts, tights; no shoes), `footwear`, `headwear`, or combine all four with `all_garments`. Attached parts (pockets, zippers, bows...) merge only when touching the selected garments. |
| `Portrait Segment (NH)` | Checklist mask of face, neck, hair, eyes, lips, nose, eyebrows, ears (+ optional mouth interior). `face` is the solid face region including features. |
### Mask Tools
| Node | Purpose |
|---|---|
| `Mask Morphology (NH)` | Expand/shrink masks, fill holes, and blur edges. |
| `Mask Properties (NH)` | Output mask bounding box, dimensions, and related measurements. |
| `NH Create Box Mask` | Convert a mask area into a rectangular box mask. |
| `NH Mask Aspect Ratio Match` | Adjust one mask to match another mask's aspect ratio. |
| `NH Mask-Aware Resize` | Resize an image/mask pair while preserving the masked subject region. |
### Logic and Flow Control
| Node | Purpose |
|---|---|
| `Compare (NH)` | Compare values with typed operators. |
| `Logic Gate (NH)` | AND, OR, NOT, XOR, NAND, and NOR boolean logic. |
| `If/Else (NH)` | Select between two inputs by condition. |
| `Switch N (NH)` | Pick one of several generic inputs by index. |
| `Any Switch (NH)` | Boolean switch helper. |
| `Any Branch Switch (NH)` | Route generic data through selected branches. |
| `Gate Switch (NH)` | Pass or block a generic input by boolean state. |
| `Value Match Index (NH)` | Return index of matching configured value. |
| `Math Eval (NH)` | Safe math expression evaluator with numeric/string outputs. |
| `Random Choice (NH)` | Weighted random choice from generic inputs. |
### Text and Prompt Tools
| Node | Purpose |
|---|---|
| `String Operations (NH)` | Strip, case convert, replace, slice, inspect, and test strings. |
| `Prompt Join (NH)` | Join text fragments with separators and empty-line handling. |
| `Text Split (NH)` | Split text by delimiter and expose count/first/last values. |
| `Regex Extract (NH)` | Extract, replace, split, and match with regex patterns. |
| `Text Index (NH)` | Select a line/item from text by index. |
| `Text Concatenate (NH)` | Concatenate multiple text inputs. |
| `Text Split Lines (NH)` | Split multiline text into selected parts and metadata. |
| `Text Random Line (NH)` | Pick a random line from multiline text. |
| `Prompt Template (NH)` | Fill `{placeholder}` variables from connected text values. |
| `Prompt Scheduler (NH)` | Select prompts by step, sequence, ping-pong, or seed. |
### Lists and Batch Helpers
| Node | Purpose |
|---|---|
| `List Create (NH)` | Build an `NH_LIST` from multiline or delimited text. |
| `List Index (NH)` | Select an item from an `NH_LIST`. |
| `List Filter (NH)` | Filter lists with contains, regex, equals, length, and related conditions. |
| `Batch Index (NH)` | Extract one or more images from an image batch. |
| `Batch Merge (NH)` | Merge image batches with resize handling. |
| `Counter (NH)` | Stateful counter for repeated queue runs. |
| `Any List Split (NH)` | Split any incoming list into an `All` output plus up to 10 indexed outputs. |
### Indexed Loaders
| Node | Purpose |
|---|---|
| `Load LoRA Model Index (NH)` | Apply one selected LoRA to `MODEL` by 1-based index. |
| `Load LoRA Clip Index (NH)` | Apply one selected LoRA to `CLIP` by 1-based index. |
| `Load Diffusion Model Index (NH)` | Load one diffusion model by 1-based index. |
| `Load VAE Index (NH)` | Load one VAE by 1-based index or boolean toggle. |
| `Load Clip Index (NH)` | Load one CLIP by 1-based index or boolean toggle, with CLIP type selection. |
### Workflow Utilities
| Node | Purpose |
|---|---|
| `Multi-Slider (FLOAT)` | Five float controls in one node. |
| `Multi-Slider (INT)` | Five integer controls in one node. |
| `Universal Slider Builder (NH)` | Generate dynamic slider outputs from text config. |
| `Boolean Switch (NH)` | Simple boolean toggle. |
| `Pack Universal (NH)` | Bundle generic values into an `NH_UNIVERSAL_PIPE`. |
| `Unpack Universal (NH)` | Extract values from an `NH_UNIVERSAL_PIPE`. |
### VTON Preprocessing
| Node | Purpose |
|---|---|
| `VTON Ultimate Processor (NH)` | Generate masks, agnostic image data, DensePose/parsing outputs, hair/hands masks, and related VTON preprocessing assets. |
---
## Menu Structure
```text
NH-Nodes/
Image/
Load/save helpers
Tile/untile
Grid and layer composition
Resize, compare, label
Mask/
Morphology, properties, bbox, aspect matching
Vision/
Garment and portrait segmentation
Logic/
Compare, gates, switches, branching, math, random choice
Text/
String, regex, split, concatenate, templates, scheduling
Batch/
Image batch, list helpers, any-list split
Resolution/
Smart resolution picker, ratio resize, preset resize, padding removal
Loaders/
Indexed LoRA, diffusion model, VAE, and CLIP loaders
Utils/
Sliders, booleans, universal pipe
VTON/
VTON Ultimate Processor
```
---
## Requirements
```text
numpy
Pillow
scipy
opencv-python
scikit-image>=0.18.0
transformers>=4.20.0
tqdm>=4.62.0
huggingface_hub>=0.16.0
```
`VTON Ultimate Processor (NH)` also needs ONNX Runtime, which is not installed
automatically (the CPU wheel would overwrite an existing GPU build). Install one:
`python -m pip install onnxruntime-gpu` (NVIDIA) or `python -m pip install onnxruntime` (CPU).
Most image/text/logic nodes use common ComfyUI dependencies. VTON and Vision
nodes download model assets on first use (`transformers` SegFormer weights for
Vision: ~190 MB fashion, ~340 MB face).
---
## Development Notes
- Layout: `core/` holds shared helpers and model backends (no nodes); `nodes/<category>/`
mirrors the ComfyUI menu, and every module there that defines `NODE_CLASS_MAPPINGS`
is registered automatically by `__init__.py` - drop a file in the right folder
and restart. VTON's vendored preprocessing lives in `nodes/vton/preprocess/`.
- Tests: `python -m pytest custom_nodes/NH-Nodes/tests -q` from the ComfyUI root.
- Restart ComfyUI after installing or updating nodes.
- If a node appears cached in the browser, refresh the ComfyUI page after restart.
- `Image Tile (NH)` and `Image Untile (NH)` must pass `tile_data` directly through
the workflow so reconstruction uses the original tile layout.
---
## License
NH-Nodes' own code is [MIT](LICENSE). Some features rely on third-party code or models with other terms — see
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md):
NH-Nodes' own code is [MIT](LICENSE). `VTON Ultimate Processor (NH)` and
`Portrait Segment (NH)` depend on third-party code or models that are licensed for
**non-commercial use only**, and the model behind `Garment Segment (NH)` declares no
license. See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) before using these
three nodes commercially.
- **VTON Ultimate Processor** and **Portrait Segment** are for **non-commercial use only** (CC BY-NC-SA 4.0 code and
parsing models; non-commercial face-parsing model).
- **Garment Segment**'s model does not declare a licence.
## Development
- Layout: `core/` holds shared helpers and model backends (no nodes); `nodes/<category>/` mirrors the menu, and every
module there that defines `NODE_CLASS_MAPPINGS` is registered automatically; `web/` holds the frontend extensions.
- Tests and lint (run from the ComfyUI root / the pack folder):
```bash
python -m pytest custom_nodes/NH-Nodes/tests -q
ruff check .
```
- Docs assets are generated from the live code: `docs/_tools/build_node_cards.py` (node cards) and
`docs/_tools/build_examples.py` (example images), both run from the ComfyUI root.
## Author
[jetthuang.com](https://jetthuang.com) · [Hugging Face](https://huggingface.co/nhathoangfoto) ·
[Support via PayPal](https://paypal.me/nhathoangfoto). If NH-Nodes helps your work, a ⭐ on GitHub is appreciated.
If NH-Nodes helps your workflow, consider starring the repository:
[github.com/jetthuangai/NH-Nodes](https://github.com/jetthuangai/NH-Nodes)
-7
View File
@@ -3,13 +3,6 @@
All notable changes to NH-Nodes. Versions follow the Comfy Registry releases.
"Behaviour change" marks fixes that can change the output of an existing workflow.
## 1.6.2 — Load images matching picks the right group
- `Load images matching` (behaviour change): when the source and the matching library share parent folders (for example
`D:/Photos/Source/Nu/…` and `D:/Photos/Library/{Nam,Nu}/…`), the shared folders no longer outweigh the source's
group, so a source in `Nu` picks `Nu/<match>` instead of the first folder in alphabetical order. Same-drive and
cross-drive setups now rank identically, and folders elsewhere in the library no longer change which match wins.
## 1.6.1 — Cleanup and hardening
- Internal restructuring with no change to node ids, inputs or outputs: the large image-tools module is split into one
File diff suppressed because it is too large Load Diff
-241
View File
@@ -1,241 +0,0 @@
"""Render a ComfyUI-style SVG card for every NH-Nodes node from its INPUT_TYPES / RETURN_TYPES.
Run with ComfyUI's Python from the ComfyUI root:
python custom_nodes/NH-Nodes/docs/_tools/build_node_cards.py [output_dir]
Cards are generated from the live node definitions, so they never drift from the code.
"""
import importlib
import json
import os
import re
import sys
from html import escape
COMFY_ROOT = os.getcwd()
sys.path[:0] = [COMFY_ROOT, os.path.join(COMFY_ROOT, "custom_nodes")]
import torch # noqa: E402
if not torch.cuda.is_available():
from comfy.cli_args import args # noqa: E402
args.cpu = True
PACK_DIR = os.path.join(COMFY_ROOT, "custom_nodes", "NH-Nodes")
OUT_DIR = sys.argv[1] if len(sys.argv) > 1 else os.path.join(PACK_DIR, "docs", "assets", "nodes")
# ComfyUI default dark palette (frontend 1.55) for link types; NH custom types get amber.
TYPE_COLORS = {
"IMAGE": "#64B5F6", "MASK": "#81C784", "LATENT": "#FF9CF9", "MODEL": "#B39DDB",
"CLIP": "#FFD500", "VAE": "#FF6E6E", "CONDITIONING": "#FFA931", "CONTROL_NET": "#6EE7B7",
"INT": "#9CC2E5", "FLOAT": "#9CC2E5", "STRING": "#C5E1A5", "BOOLEAN": "#F48FB1", "*": "#CFD8DC",
}
CUSTOM_TYPE_COLOR = "#E0B272"
WIDGET_TYPES = {"INT", "FLOAT", "STRING", "BOOLEAN"}
W = 360
PAD = 12
TITLE_H = 46
ROW_H = 22
WIDGET_H = 24
WIDGET_GAP = 5
FONT = "Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
MONO = "'JetBrains Mono', Consolas, 'Courier New', monospace"
FILE_EXTENSIONS = (".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tif", ".tiff", ".gif", ".safetensors", ".ckpt",
".pt", ".pth", ".bin", ".gguf", ".onnx", ".sft")
def is_file_combo(options, opts):
"""Combos listing files from the user's folders (inputs, models): never publish those names."""
if opts.get("image_upload") or opts.get("video_upload"):
return True
return any(str(option).lower().endswith(FILE_EXTENSIONS) for option in options)
def type_name(spec_type):
if isinstance(spec_type, (list, tuple)):
return "COMBO"
return str(spec_type)
def type_color(name):
return TYPE_COLORS.get(name, CUSTOM_TYPE_COLOR)
def short(value, limit=24):
text = str(value).replace("\n", " ⏎ ")
return text if len(text) <= limit else text[: limit - 1] + "…"
def fmt_number(value, opts):
if isinstance(value, float):
step = opts.get("step", 0.01) or 0.01
decimals = max(0, min(4, len(str(step).split(".")[1]) if "." in str(step) else 0))
return f"{value:.{decimals}f}"
return str(value)
def collapse_numbered(entries):
"""Fold long numbered families (lora_1..lora_64, enable_1..) into first two + a summary row."""
families = {}
for name, *_ in entries:
match = re.match(r"^(.*?)(\d+)$", name)
if match:
families.setdefault(match.group(1), []).append(int(match.group(2)))
folded = {prefix: max(nums) for prefix, nums in families.items() if len(nums) > 4}
result, emitted = [], set()
for entry in entries:
match = re.match(r"^(.*?)(\d+)$", entry[0])
if match and match.group(1) in folded:
prefix, num = match.group(1), int(match.group(2))
if num <= 2:
result.append(entry)
elif prefix not in emitted:
emitted.add(prefix)
result.append((f"{prefix}3 … {prefix}{folded[prefix]}", "FOLD", {}, entry[3]))
continue
result.append(entry)
return result
def node_entries(cls):
spec = cls.INPUT_TYPES()
entries = []
for section in ("required", "optional"):
for name, value in (spec.get(section) or {}).items():
spec_type = value[0] if isinstance(value, (list, tuple)) and value else value
opts = value[1] if isinstance(value, (list, tuple)) and len(value) > 1 and isinstance(value[1], dict) else {}
entries.append((name, spec_type, opts, section == "optional"))
return collapse_numbered(entries)
def split_entries(entries):
sockets, widgets = [], []
for name, spec_type, opts, optional in entries:
tname = type_name(spec_type)
is_widget = tname == "COMBO" or tname == "FOLD" or (tname in WIDGET_TYPES and not opts.get("forceInput"))
(widgets if is_widget else sockets).append((name, spec_type, opts, optional))
return sockets, widgets
def widget_value(spec_type, opts):
tname = type_name(spec_type)
if tname == "COMBO":
options = list(spec_type)
if is_file_combo(options, opts):
return "(choose a file)", ""
default = opts.get("default", options[0] if options else "")
return (short(default) if default != "" else "—"), f"{len(options)} options" if len(options) > 1 else ""
default = opts.get("default", "")
if tname == "BOOLEAN":
return ("true" if default else "false"), ""
if tname in ("INT", "FLOAT"):
return fmt_number(default, opts), ""
if tname == "STRING":
return short(default, 30) if default != "" else "", "multiline" if opts.get("multiline") else ""
return short(default), ""
def svg_card(node_id, display, category, cls):
entries = node_entries(cls)
sockets, widgets = split_entries(entries)
return_types = [str(t) for t in getattr(cls, "RETURN_TYPES", ())]
return_names = list(getattr(cls, "RETURN_NAMES", None) or return_types)
is_list = list(getattr(cls, "OUTPUT_IS_LIST", ()) or [])
output_node = getattr(cls, "OUTPUT_NODE", False)
io_rows = max(len(sockets), len(return_types))
multiline_rows = sum(1 for _, t, o, _ in widgets if type_name(t) == "STRING" and o.get("multiline"))
widgets_h = len(widgets) * (WIDGET_H + WIDGET_GAP) + multiline_rows * 22
height = TITLE_H + 10 + io_rows * ROW_H + (8 if io_rows and widgets else 0) + widgets_h + PAD
parts = [
f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{height}" viewBox="0 0 {W} {height}" '
f'font-family="{FONT}" role="img" aria-label="{escape(display)} node">',
f'<rect x="0.5" y="0.5" width="{W - 1}" height="{height - 1}" rx="10" fill="#26282c" stroke="#45484f"/>',
f'<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h{W - 21} a10 10 0 0 1 10 10 v{TITLE_H - 10} h-{W - 1} z" fill="#34373d"/>',
f'<circle cx="{PAD + 5}" cy="17" r="4.5" fill="{"#F6AD55" if output_node else "#8FD18F"}"/>',
f'<text x="{PAD + 16}" y="22" font-size="14" font-weight="600" fill="#EEF0F3">{escape(short(display, 40))}</text>',
f'<text x="{PAD + 16}" y="38" font-size="10.5" fill="#9AA0A8" font-family="{MONO}">'
f'{escape(node_id)} · {escape(category.replace("NH-Nodes/", ""))}</text>',
]
y = TITLE_H + 10
for index in range(io_rows):
cy = y + index * ROW_H + ROW_H / 2
if index < len(sockets):
name, spec_type, opts, optional = sockets[index]
tname = type_name(spec_type)
color = type_color(tname)
parts.append(f'<circle cx="{PAD}" cy="{cy}" r="5" fill="{color}" stroke="#1b1c1f" stroke-width="1.5"/>')
label = escape(name) + (' <tspan fill="#7d838c" font-style="italic">(optional)</tspan>' if optional else "")
parts.append(f'<text x="{PAD + 12}" y="{cy + 4}" font-size="12" fill="#D7DADF">{label}</text>')
if index < len(return_types):
tname = return_types[index]
color = type_color(tname)
name = return_names[index] if index < len(return_names) else tname
list_mark = " ≡" if index < len(is_list) and is_list[index] else ""
parts.append(f'<text x="{W - PAD - 12}" y="{cy + 4}" font-size="12" fill="#D7DADF" text-anchor="end">'
f'{escape(name)}{list_mark}</text>')
parts.append(f'<circle cx="{W - PAD}" cy="{cy}" r="5" fill="{color}" stroke="#1b1c1f" stroke-width="1.5"/>')
y += io_rows * ROW_H + (8 if io_rows and widgets else 0)
for name, spec_type, opts, optional in widgets:
tname = type_name(spec_type)
multiline = tname == "STRING" and opts.get("multiline")
h = WIDGET_H + (22 if multiline else 0)
parts.append(f'<rect x="{PAD}" y="{y}" width="{W - 2 * PAD}" height="{h}" rx="7" fill="#1d1f22" stroke="#3a3d43"/>')
if tname == "FOLD":
parts.append(f'<text x="{W / 2}" y="{y + 16}" font-size="11" fill="#9AA0A8" text-anchor="middle" '
f'font-style="italic">{escape(name)}</text>')
y += h + WIDGET_GAP
continue
value, hint = widget_value(spec_type, opts)
label = escape(name) + (' <tspan fill="#6f747c" font-style="italic">opt</tspan>' if optional else "")
if multiline:
parts.append(f'<text x="{PAD + 10}" y="{y + 16}" font-size="11.5" fill="#9AA0A8">{label}</text>')
parts.append(f'<text x="{PAD + 10}" y="{y + 36}" font-size="11.5" fill="#E6E8EB" font-family="{MONO}">'
f'{escape(value) or "…"}</text>')
elif tname == "BOOLEAN":
on = value == "true"
parts.append(f'<text x="{PAD + 10}" y="{y + 16}" font-size="11.5" fill="#9AA0A8">{label}</text>')
tx = W - PAD - 40
parts.append(f'<rect x="{tx}" y="{y + 6}" width="30" height="13" rx="6.5" fill="{"#4C8BF5" if on else "#4a4d53"}"/>')
parts.append(f'<circle cx="{tx + (23 if on else 7)}" cy="{y + 12.5}" r="5" fill="#F5F6F7"/>')
else:
arrows = tname in ("INT", "FLOAT", "COMBO")
if arrows:
parts.append(f'<text x="{PAD + 8}" y="{y + 16}" font-size="10" fill="#6f747c">◀</text>')
parts.append(f'<text x="{W - PAD - 16}" y="{y + 16}" font-size="10" fill="#6f747c">▶</text>')
lx = PAD + (22 if arrows else 10)
rx = W - PAD - (22 if arrows else 10)
parts.append(f'<text x="{lx}" y="{y + 16}" font-size="11.5" fill="#9AA0A8">{label}</text>')
parts.append(f'<text x="{rx}" y="{y + 16}" font-size="11.5" fill="#E6E8EB" text-anchor="end">{escape(value)}</text>')
y += h + WIDGET_GAP
parts.append("</svg>")
return "\n".join(parts) + "\n"
def main():
pack = importlib.import_module("NH-Nodes")
os.makedirs(OUT_DIR, exist_ok=True)
index = []
for node_id, cls in sorted(pack.NODE_CLASS_MAPPINGS.items()):
display = pack.NODE_DISPLAY_NAME_MAPPINGS.get(node_id, node_id)
category = getattr(cls, "CATEGORY", "")
svg = svg_card(node_id, display, category, cls)
with open(os.path.join(OUT_DIR, f"{node_id}.svg"), "w", encoding="utf-8", newline="\n") as handle:
handle.write(svg)
index.append({"id": node_id, "name": display, "category": category,
"deprecated": bool(getattr(cls, "DEPRECATED", False))})
with open(os.path.join(OUT_DIR, "index.json"), "w", encoding="utf-8", newline="\n") as handle:
json.dump(index, handle, ensure_ascii=False, indent=1)
print(f"wrote {len(index)} cards to {OUT_DIR}")
if __name__ == "__main__":
main()
File diff suppressed because it is too large Load Diff
-82
View File
@@ -1,82 +0,0 @@
"""Dump every NH node's live definition (inputs with defaults/ranges/options/tooltips, outputs) to JSON.
Run with ComfyUI's Python from the ComfyUI root: python dump_node_spec.py <out.json>
"""
import importlib
import json
import os
import sys
sys.path[:0] = [os.getcwd(), os.path.join(os.getcwd(), "custom_nodes")]
import torch # noqa: E402
if not torch.cuda.is_available():
from comfy.cli_args import args # noqa: E402
args.cpu = True
pack = importlib.import_module("NH-Nodes")
FILE_EXTENSIONS = (".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tif", ".tiff", ".gif", ".safetensors", ".ckpt",
".pt", ".pth", ".bin", ".gguf", ".onnx", ".sft")
def is_file_combo(options, opts):
"""Combos listing files from the user's folders (inputs, models): never publish those names."""
if opts.get("image_upload") or opts.get("video_upload"):
return True
return any(str(option).lower().endswith(FILE_EXTENSIONS) for option in options)
def jsonable(value):
try:
json.dumps(value)
return value
except TypeError:
return str(value)
spec = []
for node_id, cls in sorted(pack.NODE_CLASS_MAPPINGS.items()):
inputs = []
for section, entries in (cls.INPUT_TYPES() or {}).items():
if section == "hidden":
continue
for name, value in (entries or {}).items():
spec_type = value[0] if isinstance(value, (list, tuple)) and value else value
opts = value[1] if isinstance(value, (list, tuple)) and len(value) > 1 and isinstance(value[1], dict) else {}
entry = {"name": name, "section": section}
if isinstance(spec_type, (list, tuple)):
entry["type"] = "COMBO"
options = [str(o) for o in spec_type]
if is_file_combo(options, opts):
entry["options"] = ["(files from the user's folder)"]
opts = {k: v for k, v in opts.items() if k != "default"}
else:
entry["options"] = options if len(options) <= 40 else options[:40] + [f"... ({len(options)} total)"]
else:
entry["type"] = str(spec_type)
for key in ("default", "min", "max", "step", "multiline", "tooltip", "forceInput", "lazy"):
if key in opts:
entry[key] = jsonable(opts[key])
inputs.append(entry)
names = list(getattr(cls, "RETURN_NAMES", None) or getattr(cls, "RETURN_TYPES", ()))
types = [str(t) for t in getattr(cls, "RETURN_TYPES", ())]
is_list = list(getattr(cls, "OUTPUT_IS_LIST", ()) or [])
outputs = [{"name": n, "type": t, "is_list": bool(is_list[i]) if i < len(is_list) else False}
for i, (n, t) in enumerate(zip(names, types))]
spec.append({
"id": node_id,
"name": pack.NODE_DISPLAY_NAME_MAPPINGS.get(node_id, node_id),
"category": getattr(cls, "CATEGORY", ""),
"module": cls.__module__.replace("NH-Nodes.", ""),
"description": getattr(cls, "DESCRIPTION", "") or (cls.__doc__ or "").strip(),
"output_node": bool(getattr(cls, "OUTPUT_NODE", False)),
"deprecated": bool(getattr(cls, "DEPRECATED", False)),
"inputs": inputs,
"outputs": outputs,
})
with open(sys.argv[1], "w", encoding="utf-8") as handle:
json.dump(spec, handle, ensure_ascii=False, indent=1)
print(f"{len(spec)} nodes -> {sys.argv[1]}")
Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

@@ -1,42 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="287" viewBox="0 0 360 287" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Agnostic Image Generator node">
<rect x="0.5" y="0.5" width="359" height="286" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Agnostic Image Generator</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_AgnosticImageGenerator · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">agnostic_img</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">mask</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">masked_img</text>
<circle cx="348" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">composite</text>
<circle cx="348" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">fill_mode</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">gray</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">blur_radius</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">65</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">noise_strength</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">1.00</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">gray_value</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.50</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">feathering</text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

-36
View File
@@ -1,36 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="347" viewBox="0 0 360 347" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Any List Split (NH) node">
<rect x="0.5" y="0.5" width="359" height="346" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Any List Split (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_AnyListSplit · Batch</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">items</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">All ≡</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">index 1</text>
<circle cx="348" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">index 2</text>
<circle cx="348" cy="111.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">index 3</text>
<circle cx="348" cy="133.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">index 4</text>
<circle cx="348" cy="155.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">index 5</text>
<circle cx="348" cy="177.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="203.0" font-size="12" fill="#D7DADF" text-anchor="end">index 6</text>
<circle cx="348" cy="199.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="225.0" font-size="12" fill="#D7DADF" text-anchor="end">index 7</text>
<circle cx="348" cy="221.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="247.0" font-size="12" fill="#D7DADF" text-anchor="end">index 8</text>
<circle cx="348" cy="243.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="269.0" font-size="12" fill="#D7DADF" text-anchor="end">index 9</text>
<circle cx="348" cy="265.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="291.0" font-size="12" fill="#D7DADF" text-anchor="end">index 10</text>
<circle cx="348" cy="287.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="306" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="322" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="322" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="322" font-size="11.5" fill="#9AA0A8">index_count</text>
<text x="326" y="322" font-size="11.5" fill="#E6E8EB" text-anchor="end">4</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

-26
View File
@@ -1,26 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="237" viewBox="0 0 360 237" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Any Branch Switch (NH) node">
<rect x="0.5" y="0.5" width="359" height="236" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Any Branch Switch (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_AnySwitch · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">output 0</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">output 1</text>
<circle cx="348" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">output 2</text>
<circle cx="348" cy="111.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">output 3</text>
<circle cx="348" cy="133.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">output 4</text>
<circle cx="348" cy="155.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="177.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="196" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="212" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="212" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="212" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="212" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-19
View File
@@ -1,19 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="149" viewBox="0 0 360 149" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Any Switch (NH) node">
<rect x="0.5" y="0.5" width="359" height="148" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Any Switch (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_AnySwitchBoolean · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input_true</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">input_false</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">condition</text>
<circle cx="348" cy="89.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="124" font-size="11.5" fill="#9AA0A8">condition</text>
<rect x="308" y="114" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="120.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

-28
View File
@@ -1,28 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="207" viewBox="0 0 360 207" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Batch Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="206" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Batch Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_BatchIndex · Batch</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">batch</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">original_count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="124" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="124" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="124" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="137" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="153" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="153" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="153" font-size="11.5" fill="#9AA0A8">end_index <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="153" font-size="11.5" fill="#E6E8EB" text-anchor="end">-1</text>
<rect x="12" y="166" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="182" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="182" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="182" font-size="11.5" fill="#9AA0A8">step <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="182" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="171" viewBox="0 0 360 171" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Batch Merge (NH) node">
<rect x="0.5" y="0.5" width="359" height="170" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Batch Merge (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_BatchMerge · Batch</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">batch_a</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">batch_b <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">batch_c <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">resize_mode <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">stretch</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

-13
View File
@@ -1,13 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="127" viewBox="0 0 360 127" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Boolean Switch (NH) node">
<rect x="0.5" y="0.5" width="359" height="126" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Boolean Switch (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_BooleanSwitch · Utils</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">boolean</text>
<circle cx="348" cy="67.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="102" font-size="11.5" fill="#9AA0A8">boolean_switch</text>
<rect x="308" y="92" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="98.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

-55
View File
@@ -1,55 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="432" viewBox="0 0 360 432" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load Clip Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="431" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load Clip Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ClipIndex · Loaders</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">clip</text>
<circle cx="348" cy="67.0" r="5" fill="#FFD500" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">select_mode</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">index</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">type</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">stable_diffusion</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">clip_count</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">clip_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">enable_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="281" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="287.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="320" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="320" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="320" font-size="11.5" fill="#9AA0A8">clip_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="349" font-size="11.5" fill="#9AA0A8">enable_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="339" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="345.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="362" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="378" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">clip_3 … clip_64</text>
<rect x="12" y="391" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="407" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">enable_3 … enable_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

-27
View File
@@ -1,27 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="200" viewBox="0 0 360 200" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Compare (NH) node">
<rect x="0.5" y="0.5" width="359" height="199" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Compare (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_Compare · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">a</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">b</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">a_passthrough</text>
<circle cx="348" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">b_passthrough</text>
<circle cx="348" cy="111.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">op</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">is</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">type_cast <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">auto</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-34
View File
@@ -1,34 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="280" viewBox="0 0 360 280" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Counter (NH) node">
<rect x="0.5" y="0.5" width="359" height="279" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Counter (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_Counter · Batch</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">current</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">is_done</text>
<circle cx="348" cy="89.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">progress</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">remaining</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">start</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">step</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="226" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="226" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="226" font-size="11.5" fill="#9AA0A8">max_value</text>
<text x="326" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end">9</text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="255" font-size="11.5" fill="#9AA0A8">reset</text>
<rect x="308" y="245" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="251.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1,55 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="432" viewBox="0 0 360 432" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load Diffusion Model Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="431" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load Diffusion Model Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_DiffusionModelIndex · Loaders</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">model</text>
<circle cx="348" cy="67.0" r="5" fill="#B39DDB" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">select_mode</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">index</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">model_count</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">weight_dtype</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">default</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">diffusion_model_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">—</text>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">enable_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="281" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="287.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="320" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="320" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="320" font-size="11.5" fill="#9AA0A8">diffusion_model_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">—</text>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="349" font-size="11.5" fill="#9AA0A8">enable_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="339" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="345.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="362" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="378" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">diffusion_model_3 … diffusion_model_64</text>
<rect x="12" y="391" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="407" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">enable_3 … enable_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

-43
View File
@@ -1,43 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="316" viewBox="0 0 360 316" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Garment Segment (NH) node">
<rect x="0.5" y="0.5" width="359" height="315" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Garment Segment (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_GarmentSegment · Vision</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">mask</text>
<circle cx="348" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">cutout_rgba</text>
<circle cx="348" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">mask_image</text>
<circle cx="348" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">part</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">upper_garment</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">attach_parts</text>
<rect x="308" y="165" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="171.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">mask_expand</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">mask_blur</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="262" font-size="11.5" fill="#9AA0A8">fill_holes</text>
<rect x="308" y="252" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="258.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="291" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="291" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="291" font-size="11.5" fill="#9AA0A8">device</text>
<text x="326" y="291" font-size="11.5" fill="#E6E8EB" text-anchor="end">cuda</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

-15
View File
@@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="127" viewBox="0 0 360 127" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Gate Switch (NH) node">
<rect x="0.5" y="0.5" width="359" height="126" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Gate Switch (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_GateSwitch · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">output</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="102" font-size="11.5" fill="#9AA0A8">enabled</text>
<rect x="308" y="92" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="98.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

-19
View File
@@ -1,19 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="149" viewBox="0 0 360 149" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="If/Else (NH) node">
<rect x="0.5" y="0.5" width="359" height="148" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">If/Else (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_IfElse · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">if_true</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">if_false</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">condition_out</text>
<circle cx="348" cy="89.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="124" font-size="11.5" fill="#9AA0A8">condition</text>
<rect x="308" y="114" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="120.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

-33
View File
@@ -1,33 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="236" viewBox="0 0 360 236" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Image Compare (NH) node">
<rect x="0.5" y="0.5" width="359" height="235" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Image Compare (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ImageCompare · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image_a</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">image_b</text>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="124" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="124" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="124" font-size="11.5" fill="#9AA0A8">compare_mode</text>
<text x="326" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">side_by_side</text>
<rect x="12" y="137" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="153" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="153" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="153" font-size="11.5" fill="#9AA0A8">split_position</text>
<text x="326" y="153" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.50</text>
<rect x="12" y="166" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="182" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="182" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="182" font-size="11.5" fill="#9AA0A8">overlay_opacity</text>
<text x="326" y="182" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.50</text>
<rect x="12" y="195" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="211" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="211" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="211" font-size="11.5" fill="#9AA0A8">resize_method</text>
<text x="326" y="211" font-size="11.5" fill="#E6E8EB" text-anchor="end">lanczos</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

@@ -1,60 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="425" viewBox="0 0 360 425" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Image Grid Composite (NH) node">
<rect x="0.5" y="0.5" width="359" height="424" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Image Grid Composite (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ImageGridComposite · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">images</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">slot_count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">used_count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">grid_info</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">columns</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">2</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">rows</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">2</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="226" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="226" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="226" font-size="11.5" fill="#9AA0A8">cell_size_mode</text>
<text x="326" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end">manual</text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="255" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="255" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="255" font-size="11.5" fill="#9AA0A8">cell_width</text>
<text x="326" y="255" font-size="11.5" fill="#E6E8EB" text-anchor="end">512</text>
<rect x="12" y="268" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="284" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="284" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="284" font-size="11.5" fill="#9AA0A8">cell_height</text>
<text x="326" y="284" font-size="11.5" fill="#E6E8EB" text-anchor="end">512</text>
<rect x="12" y="297" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="313" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="313" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="313" font-size="11.5" fill="#9AA0A8">resize_mode</text>
<text x="326" y="313" font-size="11.5" fill="#E6E8EB" text-anchor="end">stretch</text>
<rect x="12" y="326" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="342" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="342" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="342" font-size="11.5" fill="#9AA0A8">gap_x</text>
<text x="326" y="342" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="355" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="371" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="371" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="371" font-size="11.5" fill="#9AA0A8">gap_y</text>
<text x="326" y="371" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="384" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="400" font-size="11.5" fill="#9AA0A8">background_color_hex</text>
<text x="338" y="400" font-size="11.5" fill="#E6E8EB" text-anchor="end">#000000</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

-70
View File
@@ -1,70 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="526" viewBox="0 0 360 526" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Image Label (NH) node">
<rect x="0.5" y="0.5" width="359" height="525" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Image Label (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ImageLabel · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="102" font-size="11.5" fill="#9AA0A8">label_text</text>
<text x="22" y="122" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH Label</text>
<rect x="12" y="137" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="153" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="153" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="153" font-size="11.5" fill="#9AA0A8">position</text>
<text x="326" y="153" font-size="11.5" fill="#E6E8EB" text-anchor="end">header</text>
<rect x="12" y="166" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="182" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="182" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="182" font-size="11.5" fill="#9AA0A8">frame_height</text>
<text x="326" y="182" font-size="11.5" fill="#E6E8EB" text-anchor="end">80</text>
<rect x="12" y="195" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="211" font-size="11.5" fill="#9AA0A8">fill_enabled</text>
<rect x="308" y="201" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="207.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="224" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="240" font-size="11.5" fill="#9AA0A8">frame_color_hex</text>
<text x="338" y="240" font-size="11.5" fill="#E6E8EB" text-anchor="end">#111111</text>
<rect x="12" y="253" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="269" font-size="11.5" fill="#9AA0A8">text_color_hex</text>
<text x="338" y="269" font-size="11.5" fill="#E6E8EB" text-anchor="end">#FFFFFF</text>
<rect x="12" y="282" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="298" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="298" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="298" font-size="11.5" fill="#9AA0A8">font_name</text>
<text x="326" y="298" font-size="11.5" fill="#E6E8EB" text-anchor="end">default</text>
<rect x="12" y="311" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="327" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="327" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="327" font-size="11.5" fill="#9AA0A8">font_size</text>
<text x="326" y="327" font-size="11.5" fill="#E6E8EB" text-anchor="end">32</text>
<rect x="12" y="340" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="356" font-size="11.5" fill="#9AA0A8">fit_text</text>
<rect x="308" y="346" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="352.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="369" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="385" font-size="11.5" fill="#9AA0A8">overlay_on_image</text>
<rect x="308" y="375" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="381.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="398" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="414" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="414" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="414" font-size="11.5" fill="#9AA0A8">align</text>
<text x="326" y="414" font-size="11.5" fill="#E6E8EB" text-anchor="end">left</text>
<rect x="12" y="427" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="443" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="443" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="443" font-size="11.5" fill="#9AA0A8">padding_x</text>
<text x="326" y="443" font-size="11.5" fill="#E6E8EB" text-anchor="end">20</text>
<rect x="12" y="456" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="472" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="472" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="472" font-size="11.5" fill="#9AA0A8">outline_width</text>
<text x="326" y="472" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="485" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="501" font-size="11.5" fill="#9AA0A8">outline_color_hex</text>
<text x="338" y="501" font-size="11.5" fill="#E6E8EB" text-anchor="end">#000000</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

@@ -1,48 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="345" viewBox="0 0 360 345" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Image Resize Unit (NH) node">
<rect x="0.5" y="0.5" width="359" height="344" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Image Resize Unit (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ImageResizeByUnit · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">width_px</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">height_px</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">unit</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">pixel</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">width_value</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024.0</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">height_value</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024.0</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">dpi</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">300</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">resize_mode</text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">stretch</text>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="291" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="291" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="291" font-size="11.5" fill="#9AA0A8">resize_method</text>
<text x="326" y="291" font-size="11.5" fill="#E6E8EB" text-anchor="end">nearest</text>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="320" font-size="11.5" fill="#9AA0A8">pad_color_hex</text>
<text x="338" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">#000000</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

-41
View File
@@ -1,41 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="324" viewBox="0 0 360 324" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Image Tile (NH) node">
<rect x="0.5" y="0.5" width="359" height="323" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Image Tile (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ImageTile · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">tiles</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">tile_data</text>
<circle cx="348" cy="89.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">tile_count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">overlap_x</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">overlap_y</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">tile_info</text>
<circle cx="348" cy="177.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="196" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="212" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="212" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="212" font-size="11.5" fill="#9AA0A8">tile_mode</text>
<text x="326" y="212" font-size="11.5" fill="#E6E8EB" text-anchor="end">original_ratio</text>
<rect x="12" y="225" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="241" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="241" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="241" font-size="11.5" fill="#9AA0A8">tile_size</text>
<text x="326" y="241" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024</text>
<rect x="12" y="254" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="270" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="270" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="270" font-size="11.5" fill="#9AA0A8">tile_width</text>
<text x="326" y="270" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024</text>
<rect x="12" y="283" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="299" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="299" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="299" font-size="11.5" fill="#9AA0A8">tile_height</text>
<text x="326" y="299" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

-15
View File
@@ -1,15 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="112" viewBox="0 0 360 112" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Image Untile (NH) node">
<rect x="0.5" y="0.5" width="359" height="111" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Image Untile (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ImageUntile · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">tiles</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">tile_data</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">untile_info</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1,64 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="432" viewBox="0 0 360 432" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Large Image Compare node">
<rect x="0.5" y="0.5" width="359" height="431" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#F6AD55"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Large Image Compare</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LargeImageCompare · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image_a</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image_a</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">image_b</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">image_b</text>
<circle cx="348" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">manifest</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">compare_mode</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">slider</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">sync_pan_zoom</text>
<rect x="308" y="165" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="171.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">preview_megapixels</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">1.00</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">preview_format</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">jpg</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">preview_quality</text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">90</text>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">title</text>
<text x="338" y="291" font-size="11.5" fill="#E6E8EB" text-anchor="end">NH Large Image Compare</text>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="320" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="320" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="320" font-size="11.5" fill="#9AA0A8">tile_size <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">512</text>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="349" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="349" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="349" font-size="11.5" fill="#9AA0A8">tile_format <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="349" font-size="11.5" fill="#E6E8EB" text-anchor="end">jpg</text>
<rect x="12" y="362" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="378" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="378" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="378" font-size="11.5" fill="#9AA0A8">tile_quality <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="378" font-size="11.5" fill="#E6E8EB" text-anchor="end">90</text>
<rect x="12" y="391" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="407" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="407" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="407" font-size="11.5" fill="#9AA0A8">cache_policy <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="407" font-size="11.5" fill="#E6E8EB" text-anchor="end">temp</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

@@ -1,56 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="381" viewBox="0 0 360 381" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Large Image Preview node">
<rect x="0.5" y="0.5" width="359" height="380" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#F6AD55"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Large Image Preview</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LargeImagePreview · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">manifest</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="124" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="124" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="124" font-size="11.5" fill="#9AA0A8">preview_megapixels</text>
<text x="326" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">1.00</text>
<rect x="12" y="137" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="153" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="153" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="153" font-size="11.5" fill="#9AA0A8">preview_format</text>
<text x="326" y="153" font-size="11.5" fill="#E6E8EB" text-anchor="end">jpg</text>
<rect x="12" y="166" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="182" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="182" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="182" font-size="11.5" fill="#9AA0A8">preview_quality</text>
<text x="326" y="182" font-size="11.5" fill="#E6E8EB" text-anchor="end">90</text>
<rect x="12" y="195" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="211" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="211" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="211" font-size="11.5" fill="#9AA0A8">viewer_mode</text>
<text x="326" y="211" font-size="11.5" fill="#E6E8EB" text-anchor="end">modal</text>
<rect x="12" y="224" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="240" font-size="11.5" fill="#9AA0A8">title</text>
<text x="338" y="240" font-size="11.5" fill="#E6E8EB" text-anchor="end">NH Large Image Preview</text>
<rect x="12" y="253" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="269" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="269" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="269" font-size="11.5" fill="#9AA0A8">tile_size <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="269" font-size="11.5" fill="#E6E8EB" text-anchor="end">512</text>
<rect x="12" y="282" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="298" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="298" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="298" font-size="11.5" fill="#9AA0A8">tile_format <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="298" font-size="11.5" fill="#E6E8EB" text-anchor="end">jpg</text>
<rect x="12" y="311" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="327" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="327" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="327" font-size="11.5" fill="#9AA0A8">tile_quality <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="327" font-size="11.5" fill="#E6E8EB" text-anchor="end">90</text>
<rect x="12" y="340" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="356" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="356" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="356" font-size="11.5" fill="#9AA0A8">cache_policy <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="356" font-size="11.5" fill="#E6E8EB" text-anchor="end">temp</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

@@ -1,33 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="280" viewBox="0 0 360 280" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Large Preview Cache Manager node">
<rect x="0.5" y="0.5" width="359" height="279" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#F6AD55"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Large Preview Cache Manager</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LargePreviewCacheManager · Image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">summary</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">removed</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">freed_mb</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">cache_root</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">action</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">info</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">max_age_hours</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">24.0</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="226" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="226" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="226" font-size="11.5" fill="#9AA0A8">max_total_mb</text>
<text x="326" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end">2048.0</text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="255" font-size="11.5" fill="#9AA0A8">cache_id</text>
<text x="338" y="255" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1,90 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="621" viewBox="0 0 360 621" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Layer Layout Composite (NH) node">
<rect x="0.5" y="0.5" width="359" height="620" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Layer Layout Composite (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LayerLayoutComposite · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">images</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">background_image <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">slot_count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">used_count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">layout_info</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">canvas_width</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">2480</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">canvas_height</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">3508</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="226" font-size="11.5" fill="#9AA0A8">background_color</text>
<text x="338" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end">#FFFFFF</text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="255" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="255" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="255" font-size="11.5" fill="#9AA0A8">layout_mode</text>
<text x="326" y="255" font-size="11.5" fill="#E6E8EB" text-anchor="end">preset</text>
<rect x="12" y="268" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="284" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="284" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="284" font-size="11.5" fill="#9AA0A8">layout_preset</text>
<text x="326" y="284" font-size="11.5" fill="#E6E8EB" text-anchor="end">2x3</text>
<rect x="12" y="297" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="313" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="313" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="313" font-size="11.5" fill="#9AA0A8">resize_mode</text>
<text x="326" y="313" font-size="11.5" fill="#E6E8EB" text-anchor="end">cover</text>
<rect x="12" y="326" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="342" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="342" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="342" font-size="11.5" fill="#9AA0A8">columns</text>
<text x="326" y="342" font-size="11.5" fill="#E6E8EB" text-anchor="end">2</text>
<rect x="12" y="355" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="371" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="371" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="371" font-size="11.5" fill="#9AA0A8">rows</text>
<text x="326" y="371" font-size="11.5" fill="#E6E8EB" text-anchor="end">3</text>
<rect x="12" y="384" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="400" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="400" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="400" font-size="11.5" fill="#9AA0A8">margin_x</text>
<text x="326" y="400" font-size="11.5" fill="#E6E8EB" text-anchor="end">150</text>
<rect x="12" y="413" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="429" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="429" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="429" font-size="11.5" fill="#9AA0A8">margin_y</text>
<text x="326" y="429" font-size="11.5" fill="#E6E8EB" text-anchor="end">150</text>
<rect x="12" y="442" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="458" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="458" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="458" font-size="11.5" fill="#9AA0A8">gap_x</text>
<text x="326" y="458" font-size="11.5" fill="#E6E8EB" text-anchor="end">150</text>
<rect x="12" y="471" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="487" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="487" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="487" font-size="11.5" fill="#9AA0A8">gap_y</text>
<text x="326" y="487" font-size="11.5" fill="#E6E8EB" text-anchor="end">150</text>
<rect x="12" y="500" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="516" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="516" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="516" font-size="11.5" fill="#9AA0A8">custom_units</text>
<text x="326" y="516" font-size="11.5" fill="#E6E8EB" text-anchor="end">auto</text>
<rect x="12" y="529" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="545" font-size="11.5" fill="#9AA0A8">custom_layout</text>
<text x="22" y="565" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">0.06,0.04,0.39,0.20 ⏎ 0.55,0.…</text>
<rect x="12" y="580" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="596" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="596" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="596" font-size="11.5" fill="#9AA0A8">background_fit</text>
<text x="326" y="596" font-size="11.5" fill="#E6E8EB" text-anchor="end">stretch</text>
</svg>

Before

Width:  |  Height:  |  Size: 6.9 KiB

@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="251" viewBox="0 0 360 251" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Layer Stack Composite (NH) node">
<rect x="0.5" y="0.5" width="359" height="250" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Layer Stack Composite (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LayerStackComposite · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">background_image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">layer_1 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">used_count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">layer_2 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">layer_info</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">layer_count</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="159" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">positions</text>
<text x="22" y="195" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">0,0</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="226" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">layer_3 … layer_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

-21
View File
@@ -1,21 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="244" viewBox="0 0 360 244" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="List Create (NH) node">
<rect x="0.5" y="0.5" width="359" height="243" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">List Create (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ListCreate · Batch</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">items</text>
<circle cx="348" cy="67.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">first</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">last</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="168" font-size="11.5" fill="#9AA0A8">text</text>
<text x="22" y="188" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">item 1 ⏎ item 2 ⏎ item 3</text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="219" font-size="11.5" fill="#9AA0A8">delimiter <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end">\n</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

-25
View File
@@ -1,25 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="222" viewBox="0 0 360 222" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="List Filter (NH) node">
<rect x="0.5" y="0.5" width="359" height="221" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">List Filter (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ListFilter · Batch</text>
<circle cx="12" cy="67.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">items</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">passed</text>
<circle cx="348" cy="67.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">rejected</text>
<circle cx="348" cy="89.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">passed_count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">rejected_count</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="168" font-size="11.5" fill="#9AA0A8">condition</text>
<text x="338" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">contains:dress</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">mode</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">include</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

-26
View File
@@ -1,26 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="222" viewBox="0 0 360 222" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="List Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="221" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">List Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ListIndex · Batch</text>
<circle cx="12" cy="67.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">items</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">item</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">is_first</text>
<circle cx="348" cy="89.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">is_last</text>
<circle cx="348" cy="111.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="197" font-size="11.5" fill="#9AA0A8">wrap <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="187" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="193.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-28
View File
@@ -1,28 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="251" viewBox="0 0 360 251" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load Image Info (NH) node">
<rect x="0.5" y="0.5" width="359" height="250" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load Image Info (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LoadImageInfo · Image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">mask</text>
<circle cx="348" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">file_name</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">path</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">image</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="197" font-size="11.5" fill="#9AA0A8">filename_extension</text>
<rect x="308" y="187" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="193.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="226" font-size="11.5" fill="#9AA0A8">path_include_filename</text>
<rect x="308" y="216" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="222.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,44 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="345" viewBox="0 0 360 345" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load Images Folder (NH) node">
<rect x="0.5" y="0.5" width="359" height="344" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load Images Folder (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LoadImagesFromFolder · Image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">images</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">path</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">folder_path</text>
<text x="338" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">step</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">seed_mode</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">fixed</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="262" font-size="11.5" fill="#9AA0A8">recursive</text>
<rect x="308" y="252" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="258.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">filename_extension</text>
<rect x="308" y="281" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="287.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="320" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="320" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="320" font-size="11.5" fill="#9AA0A8">path_output</text>
<text x="326" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">file_path</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

@@ -1,58 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="520" viewBox="0 0 360 520" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load images matching node">
<rect x="0.5" y="0.5" width="359" height="519" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load images matching</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LoadImagesMatching · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">fallback_images <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">images</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">path</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">matched_text</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">found</text>
<circle cx="348" cy="155.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="174" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="190" font-size="11.5" fill="#9AA0A8">source_folder_path</text>
<text x="338" y="190" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="219" font-size="11.5" fill="#9AA0A8">matching_root_path</text>
<text x="338" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="232" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="248" font-size="11.5" fill="#9AA0A8">match_text</text>
<text x="338" y="248" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="261" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="277" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="277" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="277" font-size="11.5" fill="#9AA0A8">match_mode</text>
<text x="326" y="277" font-size="11.5" fill="#E6E8EB" text-anchor="end">contains</text>
<rect x="12" y="290" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="306" font-size="11.5" fill="#9AA0A8">recursive</text>
<rect x="308" y="296" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="302.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="319" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="335" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="335" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="335" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="335" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="348" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="364" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="364" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="364" font-size="11.5" fill="#9AA0A8">step</text>
<text x="326" y="364" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="377" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="393" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="393" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="393" font-size="11.5" fill="#9AA0A8">repeat_count</text>
<text x="326" y="393" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="406" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="422" font-size="11.5" fill="#9AA0A8">context_folder_names</text>
<text x="22" y="442" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">Nam ⏎ Nu</text>
<rect x="12" y="457" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="473" font-size="11.5" fill="#9AA0A8">source_file_names <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="22" y="493" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">…</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="185" viewBox="0 0 360 185" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Logic Gate (NH) node">
<rect x="0.5" y="0.5" width="359" height="184" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Logic Gate (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LogicGate · Logic</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="102" font-size="11.5" fill="#9AA0A8">a</text>
<rect x="308" y="92" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="98.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="115" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="131" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="131" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="131" font-size="11.5" fill="#9AA0A8">op</text>
<text x="326" y="131" font-size="11.5" fill="#E6E8EB" text-anchor="end">AND</text>
<rect x="12" y="144" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="160" font-size="11.5" fill="#9AA0A8">b <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="150" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="156.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-66
View File
@@ -1,66 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="483" viewBox="0 0 360 483" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load LoRA Clip Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="482" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load LoRA Clip Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LoraClipIndex · Loaders</text>
<circle cx="12" cy="67.0" r="5" fill="#B39DDB" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">model</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">model</text>
<circle cx="348" cy="67.0" r="5" fill="#B39DDB" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#FFD500" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">clip</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">clip</text>
<circle cx="348" cy="89.0" r="5" fill="#FFD500" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">select_mode</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">index</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="226" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="226" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="226" font-size="11.5" fill="#9AA0A8">lora_count</text>
<text x="326" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="255" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="255" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="255" font-size="11.5" fill="#9AA0A8">strength_model</text>
<text x="326" y="255" font-size="11.5" fill="#E6E8EB" text-anchor="end">1.00</text>
<rect x="12" y="268" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="284" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="284" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="284" font-size="11.5" fill="#9AA0A8">strength_clip</text>
<text x="326" y="284" font-size="11.5" fill="#E6E8EB" text-anchor="end">1.00</text>
<rect x="12" y="297" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="313" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="313" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="313" font-size="11.5" fill="#9AA0A8">lora_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="313" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="326" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="342" font-size="11.5" fill="#9AA0A8">enable_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="332" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="338.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="355" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="371" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="371" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="371" font-size="11.5" fill="#9AA0A8">lora_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="371" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="384" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="400" font-size="11.5" fill="#9AA0A8">enable_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="390" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="396.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="413" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="429" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">lora_3 … lora_64</text>
<rect x="12" y="442" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="458" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">enable_3 … enable_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

-57
View File
@@ -1,57 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="432" viewBox="0 0 360 432" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load LoRA Model Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="431" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load LoRA Model Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_LoraModelIndex · Loaders</text>
<circle cx="12" cy="67.0" r="5" fill="#B39DDB" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">model</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">model</text>
<circle cx="348" cy="67.0" r="5" fill="#B39DDB" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">select_mode</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">index</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">lora_count</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">strength_model</text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">1.00</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">lora_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">enable_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="281" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="287.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="320" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="320" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="320" font-size="11.5" fill="#9AA0A8">lora_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="349" font-size="11.5" fill="#9AA0A8">enable_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="339" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="345.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="362" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="378" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">lora_3 … lora_64</text>
<rect x="12" y="391" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="407" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">enable_3 … enable_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

@@ -1,30 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="214" viewBox="0 0 360 214" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Mask Morphology (NH) node">
<rect x="0.5" y="0.5" width="359" height="213" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Mask Morphology (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MaskAdvancedMorphology · Mask</text>
<circle cx="12" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">mask</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">MASK</text>
<circle cx="348" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="102" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="102" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="102" font-size="11.5" fill="#9AA0A8">horizontal_expand</text>
<text x="326" y="102" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="115" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="131" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="131" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="131" font-size="11.5" fill="#9AA0A8">vertical_expand</text>
<text x="326" y="131" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="144" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="160" font-size="11.5" fill="#9AA0A8">fill_holes</text>
<rect x="308" y="150" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="156.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="173" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="189" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="189" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="189" font-size="11.5" fill="#9AA0A8">blur_radius</text>
<text x="326" y="189" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.0</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,18 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="149" viewBox="0 0 360 149" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Mask Aspect Ratio Match node">
<rect x="0.5" y="0.5" width="359" height="148" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Mask Aspect Ratio Match</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MaskAspectRatioMatch · Mask</text>
<circle cx="12" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">target_ratio_mask</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">MASK</text>
<circle cx="348" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">mask_to_adjust</text>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="124" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="124" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="124" font-size="11.5" fill="#9AA0A8">mode</text>
<text x="326" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">stretch</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-23
View File
@@ -1,23 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="222" viewBox="0 0 360 222" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Mask Properties (NH) node">
<rect x="0.5" y="0.5" width="359" height="221" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Mask Properties (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MaskProperties · Mask</text>
<circle cx="12" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">mask</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">width</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">height</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">x1</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">y1</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">x2</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">y2</text>
<circle cx="348" cy="177.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="203.0" font-size="12" fill="#D7DADF" text-anchor="end">bbox</text>
<circle cx="348" cy="199.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

-33
View File
@@ -1,33 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="236" viewBox="0 0 360 236" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Mask-Aware Resize node">
<rect x="0.5" y="0.5" width="359" height="235" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Mask-Aware Resize</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MaskResizeImage · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">mask</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">mask</text>
<circle cx="348" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="124" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="124" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="124" font-size="11.5" fill="#9AA0A8">width</text>
<text x="326" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">512</text>
<rect x="12" y="137" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="153" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="153" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="153" font-size="11.5" fill="#9AA0A8">height</text>
<text x="326" y="153" font-size="11.5" fill="#E6E8EB" text-anchor="end">512</text>
<rect x="12" y="166" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="182" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="182" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="182" font-size="11.5" fill="#9AA0A8">mode</text>
<text x="326" y="182" font-size="11.5" fill="#E6E8EB" text-anchor="end">crop</text>
<rect x="12" y="195" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="211" font-size="11.5" fill="#9AA0A8">pad_color_hex</text>
<text x="338" y="211" font-size="11.5" fill="#E6E8EB" text-anchor="end">#000000</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

-11
View File
@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="90" viewBox="0 0 360 90" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Create Box Mask node">
<rect x="0.5" y="0.5" width="359" height="89" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Create Box Mask</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MaskToBBox · Mask</text>
<circle cx="12" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">mask</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">box_mask</text>
<circle cx="348" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 1005 B

-41
View File
@@ -1,41 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="316" viewBox="0 0 360 316" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Math Eval (NH) node">
<rect x="0.5" y="0.5" width="359" height="315" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Math Eval (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MathEval · Logic</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result_float</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">result_int</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">result_string</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">expression</text>
<text x="338" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">a + b</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">a <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.00</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">b <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.00</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">c <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.00</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="262" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="262" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="262" font-size="11.5" fill="#9AA0A8">d <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="262" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.00</text>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="291" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="291" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="291" font-size="11.5" fill="#9AA0A8">round_to <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="291" font-size="11.5" fill="#E6E8EB" text-anchor="end">-1</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

-29
View File
@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="273" viewBox="0 0 360 273" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Multi-Slider (FLOAT) node">
<rect x="0.5" y="0.5" width="359" height="272" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Multi-Slider (FLOAT)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MultiSliderFloat · Utils</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">Float 1</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">Float 2</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">Float 3</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">Float 4</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">Float 5</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="174" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="190" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="190" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="190" font-size="11.5" fill="#9AA0A8">float_1</text>
<text x="326" y="190" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.00</text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="219" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="219" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="219" font-size="11.5" fill="#9AA0A8">float_2</text>
<text x="326" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end">0.00</text>
<rect x="12" y="232" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="248" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">float_3 … float_5</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

-29
View File
@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="273" viewBox="0 0 360 273" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Multi-Slider (INT) node">
<rect x="0.5" y="0.5" width="359" height="272" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Multi-Slider (INT)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_MultiSliderInt · Utils</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">Int 1</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">Int 2</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">Int 3</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">Int 4</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">Int 5</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="174" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="190" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="190" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="190" font-size="11.5" fill="#9AA0A8">int_1</text>
<text x="326" y="190" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="219" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="219" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="219" font-size="11.5" fill="#9AA0A8">int_2</text>
<text x="326" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="232" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="248" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">int_3 … int_5</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

-17
View File
@@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="171" viewBox="0 0 360 171" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Pack Universal (NH) node">
<rect x="0.5" y="0.5" width="359" height="170" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Pack Universal (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_PackUniversal · Utils/Pipe</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input_0 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">package</text>
<circle cx="348" cy="67.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">input_1 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<circle cx="12" cy="111.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">input_2 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="146" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">input_3 … input_9</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

-70
View File
@@ -1,70 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="519" viewBox="0 0 360 519" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Portrait Segment (NH) node">
<rect x="0.5" y="0.5" width="359" height="518" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Portrait Segment (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_PortraitSegment · Vision</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">mask</text>
<circle cx="348" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">cutout_rgba</text>
<circle cx="348" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">mask_image</text>
<circle cx="348" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">face</text>
<rect x="308" y="136" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="142.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">neck</text>
<rect x="308" y="165" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="171.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="204" font-size="11.5" fill="#9AA0A8">hair</text>
<rect x="308" y="194" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="200.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="233" font-size="11.5" fill="#9AA0A8">eyes</text>
<rect x="308" y="223" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="229.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="262" font-size="11.5" fill="#9AA0A8">lips</text>
<rect x="308" y="252" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="258.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">nose</text>
<rect x="308" y="281" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="287.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="320" font-size="11.5" fill="#9AA0A8">eyebrows</text>
<rect x="308" y="310" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="316.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="349" font-size="11.5" fill="#9AA0A8">ears</text>
<rect x="308" y="339" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="345.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="362" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="378" font-size="11.5" fill="#9AA0A8">mouth_interior</text>
<rect x="308" y="368" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="374.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="391" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="407" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="407" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="407" font-size="11.5" fill="#9AA0A8">mask_expand</text>
<text x="326" y="407" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="420" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="436" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="436" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="436" font-size="11.5" fill="#9AA0A8">mask_blur</text>
<text x="326" y="436" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="449" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="465" font-size="11.5" fill="#9AA0A8">fill_holes</text>
<rect x="308" y="455" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="461.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="478" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="494" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="494" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="494" font-size="11.5" fill="#9AA0A8">device</text>
<text x="326" y="494" font-size="11.5" fill="#E6E8EB" text-anchor="end">cuda</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

-24
View File
@@ -1,24 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="207" viewBox="0 0 360 207" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Prompt Join (NH) node">
<rect x="0.5" y="0.5" width="359" height="206" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Prompt Join (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_PromptJoin · Text</text>
<circle cx="12" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">text_1 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">text_2 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="124" font-size="11.5" fill="#9AA0A8">separator</text>
<text x="338" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">, </text>
<rect x="12" y="137" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="153" font-size="11.5" fill="#9AA0A8">skip_empty</text>
<rect x="308" y="143" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="149.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="166" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="182" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">text_3 … text_5</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

-36
View File
@@ -1,36 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="309" viewBox="0 0 360 309" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Prompt Scheduler (NH) node">
<rect x="0.5" y="0.5" width="359" height="308" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Prompt Scheduler (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_PromptScheduler · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">current_prompt</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">progress</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">step_index</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">prompts</text>
<text x="22" y="166" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">prompt 1 ⏎ prompt 2 ⏎ prompt 3</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">current_step</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="226" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="226" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="226" font-size="11.5" fill="#9AA0A8">total_steps</text>
<text x="326" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end">10</text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="255" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="255" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="255" font-size="11.5" fill="#9AA0A8">mode</text>
<text x="326" y="255" font-size="11.5" fill="#E6E8EB" text-anchor="end">sequential</text>
<rect x="12" y="268" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="284" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="284" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="284" font-size="11.5" fill="#9AA0A8">seed <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="284" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

-23
View File
@@ -1,23 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="229" viewBox="0 0 360 229" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Prompt Template (NH) node">
<rect x="0.5" y="0.5" width="359" height="228" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Prompt Template (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_PromptTemplate · Text</text>
<circle cx="12" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">var1 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">var2 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">missing_vars</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="108" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="124" font-size="11.5" fill="#9AA0A8">template</text>
<text x="22" y="144" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">a {color} {garment}, {style},…</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">var_names</text>
<text x="338" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">color,garment,style</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="204" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">var3 … var6</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-29
View File
@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="229" viewBox="0 0 360 229" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Random Choice (NH) node">
<rect x="0.5" y="0.5" width="359" height="228" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Random Choice (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_RandomChoice · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input_0 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">input_1 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">picked_index</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="111.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">input_2 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">probabilities</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">seed</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">weights</text>
<text x="338" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">1,1,1,1,1,1</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="204" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">input_3 … input_5</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

@@ -1,53 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="426" viewBox="0 0 360 426" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Ratio Preset Image Resize node">
<rect x="0.5" y="0.5" width="359" height="425" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Ratio Preset Image Resize</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_RatioPresetImageResize · Resolution</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">width</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">height</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">info</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">source_aspect_ratio</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">target_aspect_ratio</text>
<circle cx="348" cy="177.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="203.0" font-size="12" fill="#D7DADF" text-anchor="end">selected_preset</text>
<circle cx="348" cy="199.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="225.0" font-size="12" fill="#D7DADF" text-anchor="end">resize_data</text>
<circle cx="348" cy="221.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="240" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="256" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="256" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="256" font-size="11.5" fill="#9AA0A8">model_family</text>
<text x="326" y="256" font-size="11.5" fill="#E6E8EB" text-anchor="end">FLUX.2 Klein 9B</text>
<rect x="12" y="269" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="285" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="285" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="285" font-size="11.5" fill="#9AA0A8">resolution_level</text>
<text x="326" y="285" font-size="11.5" fill="#E6E8EB" text-anchor="end">1 MP</text>
<rect x="12" y="298" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="314" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="314" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="314" font-size="11.5" fill="#9AA0A8">target_ratio</text>
<text x="326" y="314" font-size="11.5" fill="#E6E8EB" text-anchor="end">1:1</text>
<rect x="12" y="327" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="343" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="343" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="343" font-size="11.5" fill="#9AA0A8">resize_mode</text>
<text x="326" y="343" font-size="11.5" fill="#E6E8EB" text-anchor="end">crop</text>
<rect x="12" y="356" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="372" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="372" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="372" font-size="11.5" fill="#9AA0A8">resize_method</text>
<text x="326" y="372" font-size="11.5" fill="#E6E8EB" text-anchor="end">lanczos</text>
<rect x="12" y="385" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="401" font-size="11.5" fill="#9AA0A8">pad_color_hex</text>
<text x="338" y="401" font-size="11.5" fill="#E6E8EB" text-anchor="end">#FFFFFF</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

-29
View File
@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="302" viewBox="0 0 360 302" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Regex Extract (NH) node">
<rect x="0.5" y="0.5" width="359" height="301" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Regex Extract (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_RegexExtract · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">matched</text>
<circle cx="348" cy="89.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">groups</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="133.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="168" font-size="11.5" fill="#9AA0A8">text</text>
<text x="22" y="188" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">…</text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="219" font-size="11.5" fill="#9AA0A8">pattern</text>
<text x="338" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end">(\d+)</text>
<rect x="12" y="232" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="248" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="248" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="248" font-size="11.5" fill="#9AA0A8">mode</text>
<text x="326" y="248" font-size="11.5" fill="#E6E8EB" text-anchor="end">match</text>
<rect x="12" y="261" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="277" font-size="11.5" fill="#9AA0A8">replacement <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="277" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="222" viewBox="0 0 360 222" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Remove Resize Padding node">
<rect x="0.5" y="0.5" width="359" height="221" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Remove Resize Padding</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_RemoveResizePadding · Resolution</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">resize_data</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">width</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">height</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">info</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">output_size</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">content_region</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">resize_method</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">lanczos</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

@@ -1,22 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="171" viewBox="0 0 360 171" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Restore Image Geometry node">
<rect x="0.5" y="0.5" width="359" height="170" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Restore Image Geometry</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_RestoreImageGeometry · Resolution</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">original_image</text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">mask</text>
<circle cx="348" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="111.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">resize_data</text>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">resize_method</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">bicubic</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-46
View File
@@ -1,46 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="374" viewBox="0 0 360 374" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Save Image Path (NH) node">
<rect x="0.5" y="0.5" width="359" height="373" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#F6AD55"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Save Image Path (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_SaveImagePath · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">images</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">filenames</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">path</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">saved_count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">folder_path</text>
<text x="338" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="175" font-size="11.5" fill="#9AA0A8">create_new_folder</text>
<rect x="308" y="165" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="171.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="204" font-size="11.5" fill="#9AA0A8">new_folder_name</text>
<text x="338" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="233" font-size="11.5" fill="#9AA0A8">filename_prefix</text>
<text x="338" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">NH</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="262" font-size="11.5" fill="#9AA0A8">number_suffix</text>
<rect x="308" y="252" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="258.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="291" font-size="11.5" fill="#9AA0A8">preview_image</text>
<rect x="308" y="281" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="287.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="320" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="320" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="320" font-size="11.5" fill="#9AA0A8">file_format</text>
<text x="326" y="320" font-size="11.5" fill="#E6E8EB" text-anchor="end">png</text>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="349" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="349" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="349" font-size="11.5" fill="#9AA0A8">dpi</text>
<text x="326" y="349" font-size="11.5" fill="#E6E8EB" text-anchor="end">300</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

-32
View File
@@ -1,32 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="258" viewBox="0 0 360 258" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Save Large Image node">
<rect x="0.5" y="0.5" width="359" height="257" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#F6AD55"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Save Large Image</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_SaveLargeImage · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">file_path</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">saved_count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">filename_prefix</text>
<text x="338" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">NH_Large</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">file_format</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">png</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">quality</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">95</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="233" font-size="11.5" fill="#9AA0A8">embed_metadata</text>
<rect x="308" y="223" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="229.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="193" viewBox="0 0 360 193" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Simple Face Paste node">
<rect x="0.5" y="0.5" width="359" height="192" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Simple Face Paste</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_SimpleFacePaste · Image</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">dest_image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">IMAGE</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">dest_mask</text>
<circle cx="12" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">source_image</text>
<circle cx="12" cy="133.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="137.0" font-size="12" fill="#D7DADF">source_mask</text>
<rect x="12" y="152" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="168" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="168" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="168" font-size="11.5" fill="#9AA0A8">feathering</text>
<text x="326" y="168" font-size="11.5" fill="#E6E8EB" text-anchor="end">20</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

@@ -1,48 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="397" viewBox="0 0 360 397" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Smart Ratio Image Resize node">
<rect x="0.5" y="0.5" width="359" height="396" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Smart Ratio Image Resize</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_SmartRatioImageResize · Resolution</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">image</text>
<circle cx="348" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">width</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">height</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">info</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">source_aspect_ratio</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">target_aspect_ratio</text>
<circle cx="348" cy="177.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="203.0" font-size="12" fill="#D7DADF" text-anchor="end">selected_preset</text>
<circle cx="348" cy="199.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="225.0" font-size="12" fill="#D7DADF" text-anchor="end">resize_data</text>
<circle cx="348" cy="221.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="240" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="256" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="256" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="256" font-size="11.5" fill="#9AA0A8">model_family</text>
<text x="326" y="256" font-size="11.5" fill="#E6E8EB" text-anchor="end">FLUX.2 Klein 9B</text>
<rect x="12" y="269" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="285" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="285" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="285" font-size="11.5" fill="#9AA0A8">resolution_level</text>
<text x="326" y="285" font-size="11.5" fill="#E6E8EB" text-anchor="end">1 MP</text>
<rect x="12" y="298" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="314" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="314" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="314" font-size="11.5" fill="#9AA0A8">resize_mode</text>
<text x="326" y="314" font-size="11.5" fill="#E6E8EB" text-anchor="end">cover_crop</text>
<rect x="12" y="327" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="343" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="343" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="343" font-size="11.5" fill="#9AA0A8">resize_method</text>
<text x="326" y="343" font-size="11.5" fill="#E6E8EB" text-anchor="end">lanczos</text>
<rect x="12" y="356" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="372" font-size="11.5" fill="#9AA0A8">pad_color_hex</text>
<text x="338" y="372" font-size="11.5" fill="#E6E8EB" text-anchor="end">#FFFFFF</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

@@ -1,50 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="389" viewBox="0 0 360 389" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="NH Smart Resolution Picker node">
<rect x="0.5" y="0.5" width="359" height="388" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">NH Smart Resolution Picker</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_SmartResolutionPicker · Resolution</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">width</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">height</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">latent</text>
<circle cx="348" cy="111.0" r="5" fill="#FF9CF9" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">info</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">aspect_ratio</text>
<circle cx="348" cy="155.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="174" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="190" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="190" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="190" font-size="11.5" fill="#9AA0A8">model_family</text>
<text x="326" y="190" font-size="11.5" fill="#E6E8EB" text-anchor="end">FLUX.2 Klein 9B</text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="219" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="219" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="219" font-size="11.5" fill="#9AA0A8">preset</text>
<text x="326" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end">2 MP (sweet spot) ⭐ | 1…</text>
<rect x="12" y="232" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="248" font-size="11.5" fill="#9AA0A8">use_custom <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="238" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="244.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="261" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="277" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="277" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="277" font-size="11.5" fill="#9AA0A8">custom_width <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="277" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024</text>
<rect x="12" y="290" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="306" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="306" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="306" font-size="11.5" fill="#9AA0A8">custom_height <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="306" font-size="11.5" fill="#E6E8EB" text-anchor="end">1024</text>
<rect x="12" y="319" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="335" font-size="11.5" fill="#9AA0A8">swap_orientation <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="325" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="331.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="348" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="364" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="364" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="364" font-size="11.5" fill="#9AA0A8">batch_size <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="364" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

-27
View File
@@ -1,27 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="280" viewBox="0 0 360 280" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="String Operations (NH) node">
<rect x="0.5" y="0.5" width="359" height="279" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">String Operations (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_StringOps · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">text_out</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">bool_out</text>
<circle cx="348" cy="89.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">int_out</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">text</text>
<text x="22" y="166" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">…</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">operation</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">upper</text>
<rect x="12" y="210" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="226" font-size="11.5" fill="#9AA0A8">param_a <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="226" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="239" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="255" font-size="11.5" fill="#9AA0A8">param_b <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="255" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

-24
View File
@@ -1,24 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="200" viewBox="0 0 360 200" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Switch N (NH) node">
<rect x="0.5" y="0.5" width="359" height="199" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Switch N (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_SwitchN · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input_0 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">result</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">input_1 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="111.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="115.0" font-size="12" fill="#D7DADF">input_2 <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="175" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">input_3 … input_9</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-29
View File
@@ -1,29 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="272" viewBox="0 0 360 272" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Text Concatenate (NH) node">
<rect x="0.5" y="0.5" width="359" height="271" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Text Concatenate (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_TextConcatenate · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">text</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="102" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="102" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="102" font-size="11.5" fill="#9AA0A8">string_count</text>
<text x="326" y="102" font-size="11.5" fill="#E6E8EB" text-anchor="end">2</text>
<rect x="12" y="115" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="131" font-size="11.5" fill="#9AA0A8">delimiter</text>
<text x="338" y="131" font-size="11.5" fill="#E6E8EB" text-anchor="end">/</text>
<rect x="12" y="144" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="160" font-size="11.5" fill="#9AA0A8">clean_whitespace</text>
<rect x="308" y="150" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="156.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="173" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="189" font-size="11.5" fill="#9AA0A8">string_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="189" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="202" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="218" font-size="11.5" fill="#9AA0A8">string_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="218" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="231" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="247" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">string_3 … string_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

-27
View File
@@ -1,27 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="287" viewBox="0 0 360 287" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Text Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="286" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Text Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_TextIndex · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">text</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="102" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="102" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="102" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="102" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="115" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="131" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="131" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="131" font-size="11.5" fill="#9AA0A8">text_count</text>
<text x="326" y="131" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="144" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="160" font-size="11.5" fill="#9AA0A8">text_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="22" y="180" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">…</text>
<rect x="12" y="195" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="211" font-size="11.5" fill="#9AA0A8">text_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="22" y="231" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">…</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="262" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">text_3 … text_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

-21
View File
@@ -1,21 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="222" viewBox="0 0 360 222" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Text Random Line (NH) node">
<rect x="0.5" y="0.5" width="359" height="221" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Text Random Line (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_TextRandomLine · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">text</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">picked_index</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">total_lines</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="146" font-size="11.5" fill="#9AA0A8">text</text>
<text x="22" y="166" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">option A ⏎ option B ⏎ option C</text>
<rect x="12" y="181" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="197" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="197" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="197" font-size="11.5" fill="#9AA0A8">seed</text>
<text x="326" y="197" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

-26
View File
@@ -1,26 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="273" viewBox="0 0 360 273" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Text Split (NH) node">
<rect x="0.5" y="0.5" width="359" height="272" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Text Split (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_TextSplit · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">items_joined</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="89.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">first</text>
<circle cx="348" cy="111.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">last</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="152" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="168" font-size="11.5" fill="#9AA0A8">text</text>
<text x="22" y="188" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">…</text>
<rect x="12" y="203" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="219" font-size="11.5" fill="#9AA0A8">delimiter</text>
<text x="338" y="219" font-size="11.5" fill="#E6E8EB" text-anchor="end">, </text>
<rect x="12" y="232" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="248" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="248" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="248" font-size="11.5" fill="#9AA0A8">max_splits <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="248" font-size="11.5" fill="#E6E8EB" text-anchor="end">-1</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

-52
View File
@@ -1,52 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="462" viewBox="0 0 360 462" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Text Split Lines (NH) node">
<rect x="0.5" y="0.5" width="359" height="461" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Text Split Lines (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_TextSplitLines · Text</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">lines ≡</text>
<circle cx="348" cy="67.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">selected</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">count</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">preview</text>
<circle cx="348" cy="133.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">is_first</text>
<circle cx="348" cy="155.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">is_last</text>
<circle cx="348" cy="177.0" r="5" fill="#F48FB1" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="196" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="212" font-size="11.5" fill="#9AA0A8">text</text>
<text x="22" y="232" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">first prompt ⏎ second prompt …</text>
<rect x="12" y="247" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="263" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="263" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="263" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="263" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="276" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="292" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="292" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="292" font-size="11.5" fill="#9AA0A8">mode</text>
<text x="326" y="292" font-size="11.5" fill="#E6E8EB" text-anchor="end">sequential</text>
<rect x="12" y="305" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="321" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="321" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="321" font-size="11.5" fill="#9AA0A8">seed</text>
<text x="326" y="321" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="334" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="350" font-size="11.5" fill="#9AA0A8">delimiter <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="350" font-size="11.5" fill="#E6E8EB" text-anchor="end">\n</text>
<rect x="12" y="363" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="379" font-size="11.5" fill="#9AA0A8">skip_empty <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="369" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="375.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="392" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="408" font-size="11.5" fill="#9AA0A8">strip_whitespace <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="398" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="404.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="421" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="437" font-size="11.5" fill="#9AA0A8">wrap_index <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="427" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="433.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="119" viewBox="0 0 360 119" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Universal Slider Builder (NH) node">
<rect x="0.5" y="0.5" width="359" height="118" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#F6AD55"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Universal Slider Builder (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_UniversalSliderBuilder · Utils</text>
<rect x="12" y="56" width="336" height="46" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="72" font-size="11.5" fill="#9AA0A8">config</text>
<text x="22" y="92" font-size="11.5" fill="#E6E8EB" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace"># Syntax: name, type, default…</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

-18
View File
@@ -1,18 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="149" viewBox="0 0 360 149" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Unpack Universal (NH) node">
<rect x="0.5" y="0.5" width="359" height="148" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Unpack Universal (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_UnpackUniversal · Utils/Pipe</text>
<circle cx="12" cy="67.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">package <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">item</text>
<circle cx="348" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<circle cx="12" cy="89.0" r="5" fill="#E0B272" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="93.0" font-size="12" fill="#D7DADF">pipe <tspan fill="#7d838c" font-style="italic">(optional)</tspan></text>
<rect x="12" y="108" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="124" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="124" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="124" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="124" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

-50
View File
@@ -1,50 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="403" viewBox="0 0 360 403" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Load VAE Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="402" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Load VAE Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_VAEIndex · Loaders</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">vae</text>
<circle cx="348" cy="67.0" r="5" fill="#FF6E6E" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">filename</text>
<circle cx="348" cy="89.0" r="5" fill="#C5E1A5" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="111.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="130" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="146" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="146" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="146" font-size="11.5" fill="#9AA0A8">select_mode</text>
<text x="326" y="146" font-size="11.5" fill="#E6E8EB" text-anchor="end">index</text>
<rect x="12" y="159" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="175" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="175" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="175" font-size="11.5" fill="#9AA0A8">index</text>
<text x="326" y="175" font-size="11.5" fill="#E6E8EB" text-anchor="end">1</text>
<rect x="12" y="188" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="204" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="204" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="204" font-size="11.5" fill="#9AA0A8">vae_count</text>
<text x="326" y="204" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="217" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="233" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="233" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="233" font-size="11.5" fill="#9AA0A8">vae_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="233" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="246" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="262" font-size="11.5" fill="#9AA0A8">enable_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="252" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="258.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="275" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="291" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="291" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="291" font-size="11.5" fill="#9AA0A8">vae_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="291" font-size="11.5" fill="#E6E8EB" text-anchor="end">(choose a file)</text>
<rect x="12" y="304" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="320" font-size="11.5" fill="#9AA0A8">enable_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="310" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="316.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="333" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="349" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">vae_3 … vae_64</text>
<rect x="12" y="362" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="378" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">enable_3 … enable_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

@@ -1,76 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="571" viewBox="0 0 360 571" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="VTON Ultimate Processor (NH) node">
<rect x="0.5" y="0.5" width="359" height="570" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">VTON Ultimate Processor (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_VTonUltimateProcessor · VTON</text>
<circle cx="12" cy="67.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">human_image</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">final_mask</text>
<circle cx="348" cy="67.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="93.0" font-size="12" fill="#D7DADF" text-anchor="end">agnostic_mask</text>
<circle cx="348" cy="89.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="115.0" font-size="12" fill="#D7DADF" text-anchor="end">densepose_image</text>
<circle cx="348" cy="111.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="137.0" font-size="12" fill="#D7DADF" text-anchor="end">parsing_image</text>
<circle cx="348" cy="133.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="159.0" font-size="12" fill="#D7DADF" text-anchor="end">masked_image</text>
<circle cx="348" cy="155.0" r="5" fill="#64B5F6" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="181.0" font-size="12" fill="#D7DADF" text-anchor="end">parsing_map_raw</text>
<circle cx="348" cy="177.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="203.0" font-size="12" fill="#D7DADF" text-anchor="end">hair_mask</text>
<circle cx="348" cy="199.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="336" y="225.0" font-size="12" fill="#D7DADF" text-anchor="end">hands_mask</text>
<circle cx="348" cy="221.0" r="5" fill="#81C784" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="240" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="256" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="256" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="256" font-size="11.5" fill="#9AA0A8">category</text>
<text x="326" y="256" font-size="11.5" fill="#E6E8EB" text-anchor="end">Upper-body</text>
<rect x="12" y="269" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="285" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="285" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="285" font-size="11.5" fill="#9AA0A8">mask_feathering</text>
<text x="326" y="285" font-size="11.5" fill="#E6E8EB" text-anchor="end">4</text>
<rect x="12" y="298" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="314" font-size="11.5" fill="#9AA0A8">cover_shoes</text>
<rect x="308" y="304" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="310.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="327" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="343" font-size="11.5" fill="#9AA0A8">refine_hands</text>
<rect x="308" y="333" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="339.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="356" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="372" font-size="11.5" fill="#9AA0A8">refine_hair</text>
<rect x="308" y="362" width="30" height="13" rx="6.5" fill="#4C8BF5"/>
<circle cx="331" cy="368.5" r="5" fill="#F5F6F7"/>
<rect x="12" y="385" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="401" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="401" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="401" font-size="11.5" fill="#9AA0A8">device</text>
<text x="326" y="401" font-size="11.5" fill="#E6E8EB" text-anchor="end">cpu</text>
<rect x="12" y="414" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="430" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="430" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="430" font-size="11.5" fill="#9AA0A8">offset_top <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="430" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="443" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="459" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="459" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="459" font-size="11.5" fill="#9AA0A8">offset_bottom <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="459" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="472" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="488" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="488" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="488" font-size="11.5" fill="#9AA0A8">offset_left <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="488" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="501" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="517" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="517" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="517" font-size="11.5" fill="#9AA0A8">offset_right <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="326" y="517" font-size="11.5" fill="#E6E8EB" text-anchor="end">0</text>
<rect x="12" y="530" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="546" font-size="11.5" fill="#9AA0A8">keep_model_loaded <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<rect x="308" y="536" width="30" height="13" rx="6.5" fill="#4a4d53"/>
<circle cx="315" cy="542.5" r="5" fill="#F5F6F7"/>
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

-39
View File
@@ -1,39 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="301" viewBox="0 0 360 301" font-family="Inter, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif" role="img" aria-label="Value Match Index (NH) node">
<rect x="0.5" y="0.5" width="359" height="300" rx="10" fill="#26282c" stroke="#45484f"/>
<path d="M0.5 10.5 a10 10 0 0 1 10 -10 h339 a10 10 0 0 1 10 10 v36 h-359 z" fill="#34373d"/>
<circle cx="17" cy="17" r="4.5" fill="#8FD18F"/>
<text x="28" y="22" font-size="14" font-weight="600" fill="#EEF0F3">Value Match Index (NH)</text>
<text x="28" y="38" font-size="10.5" fill="#9AA0A8" font-family="'JetBrains Mono', Consolas, 'Courier New', monospace">NH_ValueMatchIndex · Logic</text>
<circle cx="12" cy="67.0" r="5" fill="#CFD8DC" stroke="#1b1c1f" stroke-width="1.5"/>
<text x="24" y="71.0" font-size="12" fill="#D7DADF">input</text>
<text x="336" y="71.0" font-size="12" fill="#D7DADF" text-anchor="end">index</text>
<circle cx="348" cy="67.0" r="5" fill="#9CC2E5" stroke="#1b1c1f" stroke-width="1.5"/>
<rect x="12" y="86" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="102" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="102" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="102" font-size="11.5" fill="#9AA0A8">compare_mode</text>
<text x="326" y="102" font-size="11.5" fill="#E6E8EB" text-anchor="end">in</text>
<rect x="12" y="115" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="131" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="131" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="131" font-size="11.5" fill="#9AA0A8">value_count</text>
<text x="326" y="131" font-size="11.5" fill="#E6E8EB" text-anchor="end">5</text>
<rect x="12" y="144" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="160" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="160" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="160" font-size="11.5" fill="#9AA0A8">no_match_index</text>
<text x="326" y="160" font-size="11.5" fill="#E6E8EB" text-anchor="end">-1</text>
<rect x="12" y="173" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="20" y="189" font-size="10" fill="#6f747c">◀</text>
<text x="332" y="189" font-size="10" fill="#6f747c">▶</text>
<text x="34" y="189" font-size="11.5" fill="#9AA0A8">multi_match_index</text>
<text x="326" y="189" font-size="11.5" fill="#E6E8EB" text-anchor="end">-1</text>
<rect x="12" y="202" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="218" font-size="11.5" fill="#9AA0A8">value_1 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="218" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="231" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="22" y="247" font-size="11.5" fill="#9AA0A8">value_2 <tspan fill="#6f747c" font-style="italic">opt</tspan></text>
<text x="338" y="247" font-size="11.5" fill="#E6E8EB" text-anchor="end"></text>
<rect x="12" y="260" width="336" height="24" rx="7" fill="#1d1f22" stroke="#3a3d43"/>
<text x="180.0" y="276" font-size="11" fill="#9AA0A8" text-anchor="middle" font-style="italic">value_3 … value_64</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

-416
View File
@@ -1,416 +0,0 @@
[
{
"id": "NH_AgnosticImageGenerator",
"name": "NH Agnostic Image Generator",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_AnyListSplit",
"name": "Any List Split (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_AnySwitch",
"name": "Any Branch Switch (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_AnySwitchBoolean",
"name": "Any Switch (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_BatchIndex",
"name": "Batch Index (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_BatchMerge",
"name": "Batch Merge (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_BooleanSwitch",
"name": "Boolean Switch (NH)",
"category": "NH-Nodes/Utils",
"deprecated": false
},
{
"id": "NH_ClipIndex",
"name": "Load Clip Index (NH)",
"category": "NH-Nodes/Loaders",
"deprecated": false
},
{
"id": "NH_Compare",
"name": "Compare (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_Counter",
"name": "Counter (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_DiffusionModelIndex",
"name": "Load Diffusion Model Index (NH)",
"category": "NH-Nodes/Loaders",
"deprecated": false
},
{
"id": "NH_GarmentSegment",
"name": "Garment Segment (NH)",
"category": "NH-Nodes/Vision",
"deprecated": false
},
{
"id": "NH_GateSwitch",
"name": "Gate Switch (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_IfElse",
"name": "If/Else (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_ImageCompare",
"name": "Image Compare (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_ImageGridComposite",
"name": "Image Grid Composite (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_ImageLabel",
"name": "Image Label (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_ImageResizeByUnit",
"name": "Image Resize Unit (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_ImageTile",
"name": "Image Tile (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_ImageUntile",
"name": "Image Untile (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LargeImageCompare",
"name": "NH Large Image Compare",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LargeImagePreview",
"name": "NH Large Image Preview",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LargePreviewCacheManager",
"name": "NH Large Preview Cache Manager",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LayerLayoutComposite",
"name": "Layer Layout Composite (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LayerStackComposite",
"name": "Layer Stack Composite (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_ListCreate",
"name": "List Create (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_ListFilter",
"name": "List Filter (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_ListIndex",
"name": "List Index (NH)",
"category": "NH-Nodes/Batch",
"deprecated": false
},
{
"id": "NH_LoadImageInfo",
"name": "Load Image Info (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LoadImagesFromFolder",
"name": "Load Images Folder (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LoadImagesMatching",
"name": "Load images matching",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_LogicGate",
"name": "Logic Gate (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_LoraClipIndex",
"name": "Load LoRA Clip Index (NH)",
"category": "NH-Nodes/Loaders",
"deprecated": false
},
{
"id": "NH_LoraModelIndex",
"name": "Load LoRA Model Index (NH)",
"category": "NH-Nodes/Loaders",
"deprecated": false
},
{
"id": "NH_MaskAdvancedMorphology",
"name": "Mask Morphology (NH)",
"category": "NH-Nodes/Mask",
"deprecated": false
},
{
"id": "NH_MaskAspectRatioMatch",
"name": "NH Mask Aspect Ratio Match",
"category": "NH-Nodes/Mask",
"deprecated": false
},
{
"id": "NH_MaskProperties",
"name": "Mask Properties (NH)",
"category": "NH-Nodes/Mask",
"deprecated": false
},
{
"id": "NH_MaskResizeImage",
"name": "NH Mask-Aware Resize",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_MaskToBBox",
"name": "NH Create Box Mask",
"category": "NH-Nodes/Mask",
"deprecated": false
},
{
"id": "NH_MathEval",
"name": "Math Eval (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_MultiSliderFloat",
"name": "Multi-Slider (FLOAT)",
"category": "NH-Nodes/Utils",
"deprecated": false
},
{
"id": "NH_MultiSliderInt",
"name": "Multi-Slider (INT)",
"category": "NH-Nodes/Utils",
"deprecated": false
},
{
"id": "NH_PackUniversal",
"name": "Pack Universal (NH)",
"category": "NH-Nodes/Utils/Pipe",
"deprecated": false
},
{
"id": "NH_PortraitSegment",
"name": "Portrait Segment (NH)",
"category": "NH-Nodes/Vision",
"deprecated": false
},
{
"id": "NH_PromptJoin",
"name": "Prompt Join (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_PromptScheduler",
"name": "Prompt Scheduler (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_PromptTemplate",
"name": "Prompt Template (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_RandomChoice",
"name": "Random Choice (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_RatioPresetImageResize",
"name": "NH Ratio Preset Image Resize",
"category": "NH-Nodes/Resolution",
"deprecated": false
},
{
"id": "NH_RegexExtract",
"name": "Regex Extract (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_RemoveResizePadding",
"name": "NH Remove Resize Padding",
"category": "NH-Nodes/Resolution",
"deprecated": false
},
{
"id": "NH_RestoreImageGeometry",
"name": "NH Restore Image Geometry",
"category": "NH-Nodes/Resolution",
"deprecated": false
},
{
"id": "NH_SaveImagePath",
"name": "Save Image Path (NH)",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_SaveLargeImage",
"name": "NH Save Large Image",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_SimpleFacePaste",
"name": "NH Simple Face Paste",
"category": "NH-Nodes/Image",
"deprecated": false
},
{
"id": "NH_SmartRatioImageResize",
"name": "NH Smart Ratio Image Resize",
"category": "NH-Nodes/Resolution",
"deprecated": false
},
{
"id": "NH_SmartResolutionPicker",
"name": "NH Smart Resolution Picker",
"category": "NH-Nodes/Resolution",
"deprecated": false
},
{
"id": "NH_StringOps",
"name": "String Operations (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_SwitchN",
"name": "Switch N (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
},
{
"id": "NH_TextConcatenate",
"name": "Text Concatenate (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_TextIndex",
"name": "Text Index (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_TextRandomLine",
"name": "Text Random Line (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_TextSplit",
"name": "Text Split (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_TextSplitLines",
"name": "Text Split Lines (NH)",
"category": "NH-Nodes/Text",
"deprecated": false
},
{
"id": "NH_UniversalSliderBuilder",
"name": "Universal Slider Builder (NH)",
"category": "NH-Nodes/Utils",
"deprecated": true
},
{
"id": "NH_UnpackUniversal",
"name": "Unpack Universal (NH)",
"category": "NH-Nodes/Utils/Pipe",
"deprecated": false
},
{
"id": "NH_VAEIndex",
"name": "Load VAE Index (NH)",
"category": "NH-Nodes/Loaders",
"deprecated": false
},
{
"id": "NH_VTonUltimateProcessor",
"name": "VTON Ultimate Processor (NH)",
"category": "NH-Nodes/VTON",
"deprecated": false
},
{
"id": "NH_ValueMatchIndex",
"name": "Value Match Index (NH)",
"category": "NH-Nodes/Logic",
"deprecated": false
}
]
-70
View File
@@ -1,70 +0,0 @@
<p align="center"><img src="../assets/banner.jpg" alt="NH-Nodes for ComfyUI" width="100%"></p>
<p align="center"><b>English</b> · <a href="../vi/README.md">Tiếng Việt</a> · <a href="../../README.md">Project page</a></p>
# NH-Nodes guide
NH-Nodes adds **69 nodes** to ComfyUI for photo and production work: loading and saving image sets, tiling and compositing,
resolution management for current models, mask tools, garment and portrait segmentation, VTON masks, logic routing,
prompt and text tools, batch helpers and indexed model loaders.
This guide explains every node — what it is for, each input and output, and how it behaves in the details that matter.
Installation and a quick start are on the [project page](../../README.md#installation).
## Reading a node card
Every node section starts with a card drawn from the node's real definition:
<p align="center"><img src="../assets/nodes/NH_ImageTile.svg" alt="Example node card" width="360"></p>
- **Title bar** — the display name, then the node id (type it in the node search) and its menu group under `NH-Nodes`.
- **Dots on the left** are inputs you connect, **dots on the right** are outputs. The colour shows the data type:
IMAGE blue, MASK green, LATENT pink, MODEL purple, CLIP yellow, VAE red, numbers (INT, FLOAT) light blue,
text (STRING) light green, BOOLEAN rose, any type (`*`) grey, and NH-specific data (tile data, resize data…) amber.
- **Rounded rows** are widgets with their default value. `opt` marks an optional input; `≡` after an output means it
returns a list.
- A **green** dot in the title is an ordinary node; **orange** marks an output node, which runs even when nothing is
connected to it.
## Node groups
| Group | Page | Nodes |
|---|---|---|
| Image — load & save | [image-io](image-io.md) | Load Image Info · Load Images Folder · Load images matching · Save Image Path · NH Save Large Image |
| Image — compose | [image-compose](image-compose.md) | Image Tile · Image Untile · Image Grid Composite · Layer Layout Composite · Layer Stack Composite · Image Compare · Image Label · Image Resize Unit |
| Image — large preview | [image-preview](image-preview.md) | NH Large Image Preview · NH Large Image Compare · NH Large Preview Cache Manager |
| Image — mask-based retouch | [image-retouch](image-retouch.md) | NH Mask-Aware Resize · NH Agnostic Image Generator · NH Simple Face Paste |
| Resolution | [resolution](resolution.md) | NH Smart Resolution Picker · NH Smart Ratio Image Resize · NH Ratio Preset Image Resize · NH Remove Resize Padding · NH Restore Image Geometry |
| Mask | [mask](mask.md) | Mask Morphology · Mask Properties · NH Create Box Mask · NH Mask Aspect Ratio Match |
| Vision | [vision](vision.md) | Garment Segment · Portrait Segment |
| VTON | [vton](vton.md) | VTON Ultimate Processor |
| Logic | [logic](logic.md) | Compare · Logic Gate · If/Else · Switch N · Any Switch · Any Branch Switch · Gate Switch · Value Match Index · Math Eval · Random Choice |
| Text | [text](text.md) | Prompt Template · Prompt Scheduler · String Operations · Prompt Join · Text Split · Regex Extract · Text Index · Text Concatenate · Text Split Lines · Text Random Line |
| Batch & lists | [batch-lists](batch-lists.md) | Batch Index · Batch Merge · Counter · List Create · List Index · List Filter · Any List Split |
| Loaders | [loaders](loaders.md) | Load LoRA Model Index · Load LoRA Clip Index · Load Diffusion Model Index · Load VAE Index · Load Clip Index |
| Utils | [utils](utils.md) | Multi-Slider (FLOAT) · Multi-Slider (INT) · Boolean Switch · Pack Universal · Unpack Universal · Universal Slider Builder *(deprecated)* |
## Concepts used throughout
- **Images and masks.** An `IMAGE` is a batch of pictures with values from 0 to 1 (RGB, sometimes RGBA); a `MASK` is a
batch of single-channel maps where 1 is inside and 0 is outside, with soft values in between. Most NH nodes process
every item of a batch; an input with a single item is reused for every item of a larger batch.
- **Lazy branches.** The switches (If/Else, Switch N, Any Switch, Random Choice) only ask ComfyUI for the branch they pick,
so the other branches — even a second sampler — are never executed. Gate-style nodes *block* a branch instead: nodes
after a blocked output are skipped, nothing fails.
- **Seeds are literal.** Every seeded node gives the same result for the same seed, including seed 0. Use ComfyUI's
*control after generate* to vary it.
- **Paths.** Folder inputs accept absolute paths or paths relative to ComfyUI's `input`/`output` folders; details are on
[image-io](image-io.md#paths-and-file-types).
- **Resize data.** The resolution nodes return a `resize_data` record of how an image was cropped or padded, so a result
can be put back into the original frame with [NH Restore Image Geometry](resolution.md#nh-restore-image-geometry).
- **Licences.** All nodes are MIT except the parts listed in [THIRD_PARTY_NOTICES](../../THIRD_PARTY_NOTICES.md):
VTON Ultimate Processor and Portrait Segment are for **non-commercial** use, and Garment Segment's model declares no
licence.
## More
- [Changelog](../CHANGELOG.md) — what changed in each release, including behaviour changes.
- [Logic gate diagram](../logic_gate_diagram.html) — a visual truth-table sheet for the Logic Gate node (download and open
it in a browser).
- [Third-party notices](../../THIRD_PARTY_NOTICES.md) — licences of bundled code and downloaded models.
-372
View File
@@ -1,372 +0,0 @@
[← Back to guide](./README.md)
# Batch & Lists
Nodes for working with groups of things. Pick or join images in a batch, count how many times you have queued a workflow, and build, filter and index lists of text. One more node splits any ComfyUI list into separate outputs. Find them under **NH-Nodes → Batch** in the node menu.
The most common mistake with these nodes is mixing counting from 0 with counting from 1, so read [Counting rules](#counting-rules) first.
**On this page**
| Node | Use it to |
|---|---|
| [Batch Index (NH)](#batch-index-nh) | Pick one image, or a range of images, from a batch |
| [Batch Merge (NH)](#batch-merge-nh) | Join up to three batches into one |
| [Counter (NH)](#counter-nh) | Get a number that goes up on every queue |
| [List Create (NH)](#list-create-nh) | Turn text into a list |
| [List Index (NH)](#list-index-nh) | Take one item from a list |
| [List Filter (NH)](#list-filter-nh) | Split a list into matches and non-matches |
| [Any List Split (NH)](#any-list-split-nh) | Split any ComfyUI list into separate outputs |
In the tables, `*` means any data type.
---
## Counting rules
Some nodes count from 0 and some from 1. Check this table when you wire a number from one node into another.
| Where | The first item is |
|---|---|
| `Batch Index (NH)` — `index`, `end_index` | `0` |
| `List Index (NH)` — `index` | `0` |
| `Any List Split (NH)` — outputs | `index 1` |
| `Counter (NH)` — `current` | your `start` value (default `0`) |
| Indexed loaders — `index` (see [Loaders](./loaders.md)) | `1` |
To drive a loader with a Counter, set the Counter's `start` to `1`.
---
## Batch Index (NH)
<p align="center"><img src="../assets/nodes/NH_BatchIndex.svg" alt="Batch Index (NH) node" width="360"></p>
Picks one image, or a range of images, out of an image batch and tells you how many images the batch had.
**Use it when** you want a single image from a generated batch (for example the third of four), the last frame of a sequence, or only part of a batch.
| Input | Type | Default | Description |
|---|---|---|---|
| `batch` | IMAGE | — | The image batch to pick from. |
| `index` | INT | `0` | Position of the first image to return, starting at 0. A negative value counts from the end (`-1` is the last image). A value past the end gives the last image. Range -100 to 1000. |
| `end_index` | INT | `-1` | Optional. `-1` returns only the image at `index`. Any other value returns a range (see below). Range -100 to 1000. |
| `step` | INT | `1` | Optional. Take every n-th image of the range. Used only with a range. Range 1 to 10. |
| Output | Type | Description |
|---|---|---|
| `result` | IMAGE | The selected image or images. |
| `original_count` | INT | How many images the input batch had. |
**How it works**
- **One image (default):** with `end_index` at `-1`, you get the image at `index`.
- **A range:** a positive `end_index` is exclusive, like a list slice. `index` 2 and `end_index` 5 return images 2, 3 and 4. A negative `end_index` counts from the end and includes that image: `-2` stops at the second-to-last image, so only the last one is left out. `-1` is reserved for the one-image mode.
- **Empty range:** if `end_index` is not after `index`, the node prints a warning in the console and returns the first image of the batch.
- Any `end_index` larger than the batch simply means "to the end".
Results for a batch of 10 images, numbered 0 to 9:
| `index` | `end_index` | `step` | Result |
|---|---|---|---|
| `3` | `-1` | — | image 3 |
| `-1` | `-1` | — | image 9 (the last one) |
| `2` | `5` | `1` | images 2, 3, 4 |
| `2` | `5` | `2` | images 2, 4 |
| `0` | `-2` | `1` | images 0 to 8 (all but the last) |
| `-3` | `1000` | `1` | images 7, 8, 9 (the last three) |
| `0` | `1000` | `3` | images 0, 3, 6, 9 |
**Example — keep the third image of a batch**
```text
KSampler (batch of 4) → VAE Decode → Batch Index (NH) → Save Image
```
Set `index` to `2`. The node returns the third image, and `original_count` reads `4`. Use `index` `-1` to always get the last image, however long the batch is.
> **Tip:** Wire a `Counter (NH)` into `index` to step through a batch one image per queue. Set the Counter's `max_value` to the batch size minus one.
---
## Batch Merge (NH)
<p align="center"><img src="../assets/nodes/NH_BatchMerge.svg" alt="Batch Merge (NH) node" width="360"></p>
Joins up to three image batches into one longer batch, resizing the extra batches to match the first.
**Use it when** you want images from separate branches in one batch (to preview, save or send them on together), or when the batches you are combining have different sizes.
| Input | Type | Default | Description |
|---|---|---|---|
| `batch_a` | IMAGE | — | The first batch. Its width, height and channels (RGB or RGBA) set the format of the result. It is never resized. |
| `batch_b` | IMAGE | — | Optional. A second batch, added after `batch_a`. |
| `batch_c` | IMAGE | — | Optional. A third batch, added last. |
| `resize_mode` | COMBO | `stretch` | Optional. How images from `batch_b` and `batch_c` are fitted to the size of `batch_a`: `stretch`, `crop` or `pad`. Images that already have the right size are left alone. |
| Output | Type | Description |
|---|---|---|
| `result` | IMAGE | All images in order: `batch_a`, then `batch_b`, then `batch_c`. |
| `count` | INT | The number of images in `result`. |
**Resize modes**
| Mode | What it does | Proportions | Cost |
|---|---|---|---|
| `stretch` | Scales the image to exactly the target size. | Not kept — the image can look squashed or stretched. | Nothing is lost. |
| `crop` | Scales the image until the target is fully covered, then cuts the overflow evenly from the centre. | Kept. | The edges are cut off. |
| `pad` | Scales the image until all of it fits, centres it and fills the rest with bars. | Kept. | Bars are added: black in an RGB result, transparent in an RGBA result. |
**RGB and RGBA**
The result has the channels of `batch_a`. Every other batch is converted to match before it is joined.
| `batch_a` | Other batch | Result |
|---|---|---|
| RGB | RGB | RGB |
| RGBA | RGBA | RGBA |
| RGB | RGBA | RGB — the other batch loses its alpha channel. |
| RGBA | RGB | RGBA — the other batch gets a fully opaque alpha channel. With `pad`, the bars are transparent. |
Batches with any other channel count (for example a single channel) cannot be mixed with a different channel count. The node stops with an error that names both counts.
**Example — combine two images of different sizes**
```text
Load Image A + Load Image B → Batch Merge (NH) → Preview Image
```
Set `resize_mode` to `pad`. Image B keeps its proportions and sits in the centre of a frame the size of image A. `count` reads `2`.
> **Tip:** Connect the image whose size you want to keep to `batch_a`. To merge more than three batches, chain two nodes: send the `result` of the first into `batch_a` of the second.
---
## Counter (NH)
<p align="center"><img src="../assets/nodes/NH_Counter.svg" alt="Counter (NH) node" width="360"></p>
A counter that goes up by `step` every time you queue the workflow and tells you when it has passed `max_value`.
**Use it when** you want to go through a set of things one per queue: test several LoRAs, rotate through prompts, or process a batch image by image.
| Input | Type | Default | Description |
|---|---|---|---|
| `start` | INT | `0` | The first value of the count. |
| `step` | INT | `1` | How much the count goes up on each queue. Minimum 1. |
| `max_value` | INT | `9` | The last value to count to. Minimum 0. |
| `reset` | BOOLEAN | `false` | While on, every queue restarts the count at `start`. |
| Output | Type | Description |
|---|---|---|
| `current` | INT | The value for this queue. Never higher than `max_value`. |
| `is_done` | BOOLEAN | `true` once the count has passed `max_value`. |
| `progress` | FLOAT | `current` divided by `max_value`, from 0.0 to 1.0. |
| `remaining` | INT | Values left up to `max_value`, counting `current` itself (`max_value - current + 1`). Never below 0. |
**How it works**
- **It runs on every queue.** The node is never served from ComfyUI's cache, so each queue moves the count on: every click on Run, every repeat of the batch count, every auto-queue pass.
- **Counting:** the first queue returns `start`, the next one `start + step`, and so on. When the next value would pass `max_value`, you get `max_value` with `is_done` on, and the count stops. Extra queues repeat that result. With `step` 2 and `max_value` 9 the sequence is 0, 2, 4, 6, 8, then 9 with `is_done` on.
- **`reset`:** switch it on and queue once to rewind. That queue returns `start`. Switch `reset` off again and the next queue returns `start + step`. While `reset` stays on, every queue returns `start`.
- **Changing settings mid-count:** `step` and `max_value` apply at once. `start` is only read when counting begins and after a reset.
- **Where the count lives:** in memory, per node ID. Restarting ComfyUI starts over, and two Counter nodes count independently. Workflows that contain a Counter with the same node ID share one count, so use `reset` after switching between them.
With the default settings (`start` 0, `step` 1, `max_value` 9):
| Queue | 1 | 2 | … | 10 | 11 | 12 |
|---|---|---|---|---|---|---|
| `current` | 0 | 1 | … | 9 | 9 | 9 |
| `is_done` | false | false | … | false | true | true |
| `remaining` | 10 | 9 | … | 1 | 0 | 0 |
| `progress` | 0.0 | 0.11 | … | 1.0 | 1.0 | 1.0 |
**Example — test five LoRAs, one per queue**
```text
Counter (NH) → Load LoRA Model Index (NH) → KSampler
```
| Node | Settings |
|---|---|
| `Counter (NH)` | `start` 1, `step` 1, `max_value` 5. |
| `Load LoRA Model Index (NH)` | Wire `current` into `index`. Set `lora_count` to 5 and choose a LoRA in `lora_1` to `lora_5`. |
Set the batch count to 5 and press Run. Each queue uses the next LoRA, and the `filename` output tells you which one. The Counter starts at 1 because the loaders count from 1. See [Loaders](./loaders.md) for the full node.
> **Tip:** `is_done` is a plain BOOLEAN. Connect it to `If/Else (NH)` or `Logic Gate (NH)` (see [Logic](./logic.md)) to react when the sequence has finished. Turn `reset` on for one queue to run the sequence again.
---
## List Create (NH)
<p align="center"><img src="../assets/nodes/NH_ListCreate.svg" alt="List Create (NH) node" width="360"></p>
Turns text into a list of items, one per line or split on any delimiter you choose.
**Use it when** you keep a set of prompts, style names or keywords in one text box and want to pick, filter or loop through them with the List nodes.
| Input | Type | Default | Description |
|---|---|---|---|
| `text` | STRING | three lines: `item 1`, `item 2`, `item 3` | The text to split. Multiline text box. |
| `delimiter` | STRING | `\n` | Optional. What separates the items. `\n` is a new line and `\t` is a tab. Anything else is used exactly as typed, for example `,` or `;`. |
| Output | Type | Description |
|---|---|---|
| `items` | NH_LIST | The list. Only `List Index (NH)` and `List Filter (NH)` accept it. |
| `count` | INT | How many items the list has. |
| `first` | STRING | The first item. Empty when the list is empty. |
| `last` | STRING | The last item. Empty when the list is empty. |
**How it works**
- Every item is trimmed (spaces at both ends removed), and empty items are dropped, so blank lines never create items.
- The delimiter is plain text, not a pattern. It can be longer than one character, such as `||`.
- If nothing is left after trimming, `items` is an empty list, `count` is 0, and `first` and `last` are empty.
- Keep something in `delimiter`. An empty field makes the node stop with an "empty separator" error.
**Example — split one line into three items**
Set `text` to `red, green, blue` and `delimiter` to `,`. The list holds `red`, `green` and `blue`; `count` is `3`, `first` is `red` and `last` is `blue`.
> **Note:** `NH_LIST` is the pack's own list type. It travels as a single value, so it does not make ComfyUI run the next node once per item. To get one run per item, use `Text Split Lines (NH)` from [Text](./text.md) together with [Any List Split (NH)](#any-list-split-nh).
---
## List Index (NH)
<p align="center"><img src="../assets/nodes/NH_ListIndex.svg" alt="List Index (NH) node" width="360"></p>
Takes one item from a list by its position and tells you whether it is the first or the last one.
**Use it when** you want to pick a prompt or style by number, or step through a list one item per queue with a `Counter (NH)`.
| Input | Type | Default | Description |
|---|---|---|---|
| `items` | NH_LIST | — | The list, from `List Create (NH)` or `List Filter (NH)`. |
| `index` | INT | `0` | Position of the item, starting at 0. Range -100 to 1000. |
| `wrap` | BOOLEAN | `true` | Optional. What happens when `index` is outside the list (see below). |
| Output | Type | Description |
|---|---|---|
| `item` | STRING | The chosen item. |
| `is_first` | BOOLEAN | `true` if the item is the first of the list. |
| `is_last` | BOOLEAN | `true` if the item is the last of the list. |
| `count` | INT | How many items the list has. |
**How it works**
- **`wrap` on:** the position loops around the list, so a Counter can keep running and the list simply repeats. Negative values count back from the end.
- **`wrap` off:** a position past the end gives the last item. A negative position counts from the end and stops at the first item.
- **Empty list:** `item` is empty, `is_first` and `is_last` are both `true`, `count` is `0`, and the console shows a warning.
For a list of 4 items (0 to 3):
| `index` | `wrap` on | `wrap` off |
|---|---|---|
| `0` | item 0 | item 0 |
| `3` | item 3 | item 3 |
| `4` | item 0 | item 3 |
| `5` | item 1 | item 3 |
| `-1` | item 3 | item 3 |
| `-5` | item 3 | item 0 |
**Example — rotate through prompts**
```text
List Create (NH) → List Index (NH) → CLIP Text Encode
```
Write one prompt per line in `List Create (NH)`. Wire a `Counter (NH)` `current` into `index`. With `start` 0 and `max_value` set to `count` minus one, each queue uses the next prompt. Leave `wrap` on if you want the list to repeat instead of stopping.
---
## List Filter (NH)
<p align="center"><img src="../assets/nodes/NH_ListFilter.svg" alt="List Filter (NH) node" width="360"></p>
Splits a list in two: the items that match a condition and the items that do not.
**Use it when** you want to keep only the prompts that mention a word, drop items you do not need, or keep only short or long items.
| Input | Type | Default | Description |
|---|---|---|---|
| `items` | NH_LIST | — | The list to filter. |
| `condition` | STRING | `contains:dress` | The test to apply to every item (see below). |
| `mode` | COMBO | `include` | `include`: `passed` holds the items that match. `exclude`: `passed` holds the items that do not match. |
| Output | Type | Description |
|---|---|---|
| `passed` | NH_LIST | The items that passed. |
| `rejected` | NH_LIST | The items that did not pass. |
| `passed_count` | INT | How many items passed. |
| `rejected_count` | INT | How many items did not pass. |
**Conditions**
| Write | An item matches when… | Case |
|---|---|---|
| `contains:text` | it contains `text` | ignored |
| `startswith:text` | it starts with `text` | respected |
| `endswith:text` | it ends with `text` | respected |
| `equals:text` | it is exactly `text` | ignored |
| `regex:pattern` | the regular expression finds a match anywhere in it | respected (start the pattern with `(?i)` to ignore case) |
| `len>5`, `len>=5`, `len<5`, `len<=5`, `len==5`, `len!=5` | its length in characters passes the test | — |
| anything else, for example `dress` | it contains the whole condition text | ignored |
**How it works**
- The keyword before the colon is not case sensitive (`Contains:hat` works), but the word `len` must be written in lowercase. Spaces around the value and around the `len` operator are ignored.
- A condition with an unknown keyword, such as `foo:bar`, is treated as plain text and searched for as a whole.
- A broken regular expression matches nothing and prints a message in the console.
- There is one condition per node. To require two conditions, chain two nodes: send `passed` of the first into `items` of the second. To accept either of two words, use a single regular expression such as `regex:red|blue`.
**Example — keep only the prompts that mention a dress**
```text
List Create (NH) → List Filter (NH) → List Index (NH)
```
For the items `Red Dress`, `blue jeans`, `dress shirt` and `Hat`, the condition `contains:dress` with `include` gives `passed` = `Red Dress`, `dress shirt` (`passed_count` 2) and `rejected` = `blue jeans`, `Hat` (`rejected_count` 2). With `exclude` the two lists swap.
---
## Any List Split (NH)
<p align="center"><img src="../assets/nodes/NH_AnyListSplit.svg" alt="Any List Split (NH) node" width="360"></p>
Splits any ComfyUI list into a full-list output (`All`) plus up to ten separate outputs, one per item.
**Use it when** a node gives you a list (for example the `lines` of `Text Split Lines (NH)`, or a batch of images) and you want to send the first, second and third item to different places.
| Input | Type | Default | Description |
|---|---|---|---|
| `items` | `*` | — | The list or batch to split. Any type is accepted. |
| `index_count` | INT | `4` | How many `index` outputs the node shows and uses. Range 0 to 10. `All` is always there. |
| Output | Type | Description |
|---|---|---|
| `All` | `*` (list) | Every item as a ComfyUI list (the `≡` mark on the card). Nodes connected here run once per item. |
| `index 1` … `index 10` | `*` | One item each. `index 1` is the first item. Only the first `index_count` outputs are shown. |
**How it works**
- **Outputs follow `index_count`.** Change it, or press the `update outputs` button, and the node adds or removes outputs to match. Lowering it disconnects the links of the outputs that disappear. The card above shows all ten outputs; on the canvas you see `index_count` of them.
- **Image batches are split into single images.** A batch of 3 images followed by a batch of 2 gives 5 items. Other values are kept as they are, and empty entries are skipped.
- **Blocked outputs.** An `index N` output with no matching item is blocked: the list is shorter than N, or N is above `index_count`. The nodes after a blocked output are skipped silently, with no error. If the incoming list is empty, `All` is blocked too.
**Example — send two lines of one text box to two places**
```text
Text Split Lines (NH) → Any List Split (NH)
```
Write the positive prompt on line 1 and the negative prompt on line 2 of `Text Split Lines (NH)`. Connect `lines` to `items`, set `index_count` to `2`, then connect `index 1` to the positive prompt and `index 2` to the negative prompt.
> **Tip:** Use `All` when the next node should run once per item, and the `index` outputs when you need a specific item.
---
**See also:** [Loaders](./loaders.md) for the nodes a Counter can drive, [Text](./text.md) for `Text Split Lines (NH)`, and [Logic](./logic.md) for switches and branches.
[← Back to guide](./README.md)
-505
View File
@@ -1,505 +0,0 @@
[← Back to guide](./README.md)
# Image — Tile, Compose and Resize
Cut a large image into tiles and rebuild it, lay images out in grids and page layouts, paste layers at exact positions, compare two images, add a text label, and resize to millimetres or centimetres. These nodes work on the pixels of `IMAGE` batches. No model is involved. Find them under **NH-Nodes → Image** in the node menu.
**On this page**
| Node | Use it to |
|---|---|
| [Image Tile (NH)](#image-tile-nh) | Cut an image into overlapping tiles |
| [Image Untile (NH)](#image-untile-nh) | Put processed tiles back together, blending the overlaps |
| [Image Grid Composite (NH)](#image-grid-composite-nh) | Build a contact sheet from a batch |
| [Layer Layout Composite (NH)](#layer-layout-composite-nh) | Place images on a page from a preset, a grid or your own slots |
| [Layer Stack Composite (NH)](#layer-stack-composite-nh) | Paste layers on a background at positions you calculate |
| [Image Compare (NH)](#image-compare-nh) | Compare two images side by side, split, blended or as a difference |
| [Image Label (NH)](#image-label-nh) | Add a text band, or text over the picture |
| [Image Resize Unit (NH)](#image-resize-unit-nh) | Resize to pixels, millimetres or centimetres |
**Colour fields** (`background_color`, `frame_color_hex`, `pad_color_hex`, …) take `#RRGGBB`, `#RGB`, `#RRGGBBAA` or a colour name such as `red`. Always start a hex value with `#`. A value the node cannot read falls back to the default colour of that field. The alpha part counts only where the result can be transparent.
---
## Image Tile (NH)
<p align="center"><img src="../assets/nodes/NH_ImageTile.svg" alt="Image Tile (NH) node" width="360"></p>
Cuts an image into overlapping tiles of the same size, and records where every tile came from, so that Image Untile can rebuild the image.
**Use it when** an image is too large for a model or an upscaler, or when every part of the image needs the same treatment, such as an upscale or a detail pass per tile.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The image or batch to cut. Every image of a batch gets the same tile layout. |
| `tile_mode` | COMBO | `original_ratio` | How the tile size is chosen. `original_ratio`: tiles have the shape of the image and `tile_size` is their long side. `square`: `tile_size` × `tile_size`. `custom`: `tile_width` × `tile_height`. |
| `tile_size` | INT | `1024` | `16` to `16384`, step 8. Used by `original_ratio` and `square`. |
| `tile_width` | INT | `1024` | `16` to `16384`, step 8. Used by `custom` only. |
| `tile_height` | INT | `1024` | `16` to `16384`, step 8. Used by `custom` only. |
| Output | Type | Description |
|---|---|---|
| `tiles` | IMAGE | All tiles as one batch, all the same size, in reading order: left to right, top to bottom. For a batch, the tiles of the first image come first, then those of the second. |
| `tile_data` | NH_TILE_DATA | The tile layout. Connect it to Image Untile. |
| `tile_count` | INT | The total number of tiles. |
| `overlap_x` | INT | The horizontal overlap between neighbouring tiles, in pixels. |
| `overlap_y` | INT | The vertical overlap, in pixels. |
| `tile_info` | STRING | A two-line summary, such as `grid=3x2, overlap=128x128, tiles=6`. |
**How it works**
- **Overlap is automatic.** It is about one eighth of the tile side, rounded to a multiple of 8 and kept between 16 and 128 px (tiles under 128 px use proportionally less). On an axis where the image is not larger than the tile, there is no overlap.
- **Layout.** Tiles advance by the tile size minus the overlap. The last tile of each row and column is moved back so that it ends exactly on the image edge, so it can overlap its neighbour by more than `overlap_x` or `overlap_y`. Because of the overlap, a 2048 px side needs three 1024 px tiles, not two.
- **Small images.** If the image is smaller than a tile on one axis, the tile covers the whole side and the rest is filled by repeating the edge pixels. Image Untile cuts that filling off again.
Tile counts you can expect:
| Image | Settings | Tile | Grid | Tiles |
|---|---|---|---|---|
| 2048 × 1536 | `square`, `tile_size` 1024 | 1024 × 1024 | 3 × 2 | 6 |
| 3000 × 2000 | `original_ratio`, `tile_size` 1024 | 1024 × 683 | 4 × 4 | 16 |
| 1920 × 1080 | `custom`, 768 × 512 | 768 × 512 | 3 × 3 | 9 |
| 4096 × 4096 | `square`, `tile_size` 1024 | 1024 × 1024 | 5 × 5 | 25 |
| 4096 × 4096 | `square`, `tile_size` 512 | 512 × 512 | 9 × 9 | 81 |
| 800 × 600 | `square`, `tile_size` 1024 | 1024 × 1024 | 1 × 1 | 1 |
<p align="center"><img src="../assets/examples/tile-untile.jpg" alt="An image with its tile grid and overlap, the tiles, and the reassembled image" width="720"><br><em>An image with its tile grid and overlap, the tiles, and the image rebuilt by Image Untile.</em></p>
**Example — upscale in tiles**
```text
Load Image → Image Tile (NH) → Upscale Image (using Model) → Image Untile (NH) → Save Image
Image Tile (NH).tile_data → Image Untile (NH).tile_data
```
For a detail pass instead, put `VAE Encode → KSampler (low denoise) → VAE Decode` between the two tile nodes. Image Untile reads the size of the processed tiles, so the result is scaled by the same factor as the tiles.
**Common mistakes**
- Not connecting `tile_data` straight from Image Tile to Image Untile, or using the `tile_data` of a different Image Tile node.
- Changing the number or the order of the tiles between the two nodes, for example with a batch filter.
- Cropping or padding the tiles. Scaling them is fine, but all tiles must keep the same shape.
> **Tip:** A wide strip along the right or bottom edge where two tiles overlap more than usual is averaged, which can soften generated detail. Choose a size so that the image side is the tile size plus a whole number of (tile size − overlap), for example 1920 px with 1024 px tiles.
---
## Image Untile (NH)
<p align="center"><img src="../assets/nodes/NH_ImageUntile.svg" alt="Image Untile (NH) node" width="360"></p>
Puts processed tiles back together into the full image, blending the overlaps, using the layout from Image Tile.
**Use it when** you cut an image with Image Tile and want it whole again, at the original size or enlarged.
| Input | Type | Default | Description |
|---|---|---|---|
| `tiles` | IMAGE | — | The processed tiles, in the same number and order that Image Tile produced. Extra tiles are ignored. All tiles must have the same size, and they can all be enlarged by the same factor, such as 2× or 3×. |
| `tile_data` | NH_TILE_DATA | — | The layout from Image Tile. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The rebuilt image, one for each image that went into Image Tile. |
| `untile_info` | STRING | A summary, such as `images=1, tiles=6, scale=2x2, overlap=256x256`. |
**How it works**
- **Scale.** The node divides the size of the processed tiles by the original tile size, for width and height separately. Upscaled tiles give an upscaled image with no extra setting. The overlap is scaled the same way.
- **Feathering.** In every overlap strip, neighbouring tiles cross-fade with a linear ramp as wide as the overlap. The outer border of the image is not faded. There is no setting for this.
- **Edge filling.** The padding that Image Tile added to small images is cropped off.
- **Errors.** If you give fewer tiles than expected, the node stops with `Not enough tiles: got N, expected M`.
**Example**
```text
Image Tile (NH).tiles → Upscale Image (using Model) → Image Untile (NH).tiles
Image Tile (NH).tile_data → Image Untile (NH).tile_data
```
A 2048 × 1536 image cut into 6 tiles and upscaled 2× comes back as 4096 × 3072.
---
## Image Grid Composite (NH)
<p align="center"><img src="../assets/nodes/NH_ImageGridComposite.svg" alt="Image Grid Composite (NH) node" width="360"></p>
Puts a batch of images into a grid, a contact sheet, with cells of one size, gaps and a background colour.
**Use it when** you want to see several results side by side in one picture, or deliver a sheet of thumbnails.
| Input | Type | Default | Description |
|---|---|---|---|
| `images` | IMAGE | — | The images to place, left to right, top to bottom. It takes a batch, or several batches or lists, and puts all images in one sequence. |
| `columns` | INT | `2` | `1` to `64`. |
| `rows` | INT | `2` | `1` to `64`. |
| `cell_size_mode` | COMBO | `manual` | `manual`: use `cell_width` and `cell_height`. `first_image`: every cell gets the size of the first image, and the two size fields are ignored. |
| `cell_width` | INT | `512` | `1` to `16384`. |
| `cell_height` | INT | `512` | `1` to `16384`. |
| `resize_mode` | COMBO | `stretch` | How an image fits its cell. `stretch`: fill the cell, changing the proportions. `pad`: keep the proportions and fill the rest with the background colour. `fill`: keep the proportions, cover the cell and cut the overflow evenly from the centre. |
| `gap_x` | INT | `0` | `0` to `4096` px between columns. |
| `gap_y` | INT | `0` | `0` to `4096` px between rows. |
| `background_color_hex` | STRING | `#000000` | The colour of the gaps and of the `pad` areas. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The finished grid, one image. |
| `slot_count` | INT | `columns` × `rows`. |
| `used_count` | INT | How many images were placed: the smaller of the image count and `slot_count`. |
| `grid_info` | STRING | A summary, then one line per placed image with its position and size. |
**How it works**
- The sheet is `columns × cell_width + (columns − 1) × gap_x` wide and `rows × cell_height + (rows − 1) × gap_y` high. There is no outer margin.
- Images beyond `columns × rows` are left out. Empty cells show the background colour.
- The result is RGB. Transparency in the inputs is dropped.
- **Memory guard.** The node needs about 28 bytes of RAM for each pixel of the sheet. If the sheet would not fit in the free memory, it stops with a message asking you to lower the columns, rows, cell size or gaps.
<p align="center"><img src="../assets/examples/grid-composite.jpg" alt="A 2 by 2 contact sheet with labels" width="720"><br><em>A 2 × 2 contact sheet with labels.</em></p>
**Example — a labelled contact sheet**
```text
4 × Image Label (NH) → Image Batch → Image Grid Composite (NH) → Preview Image
```
Use any node that joins images into one batch, such as `Image Batch` or [Batch Merge (NH)](./batch-lists.md#batch-merge-nh). Set `columns` and `rows` to `2`, `resize_mode` to `pad`, and `gap_x` and `gap_y` to `8`.
> **Tip:** With `first_image`, all cells take the size of the first image. Put the image whose size you want first in the batch.
---
## Layer Layout Composite (NH)
<p align="center"><img src="../assets/nodes/NH_LayerLayoutComposite.svg" alt="Layer Layout Composite (NH) node" width="360"></p>
Places each image of a batch into the slots of a page layout, from a preset, a grid or your own coordinates, on a canvas of any size.
**Use it when** you build a poster, a photo sheet or a catalogue page, such as six photos on an A4 page.
| Input | Type | Default | Description |
|---|---|---|---|
| `images` | IMAGE | — | The images for the slots. Image 1 goes to slot 1, image 2 to slot 2, and so on. |
| `canvas_width` | INT | `2480` | `1` to `20000` px. The default canvas, 2480 × 3508 px, is an A4 page at 300 DPI. |
| `canvas_height` | INT | `3508` | `1` to `20000` px. |
| `background_color` | STRING | `#FFFFFF` | The canvas colour. A colour with alpha below `FF` (for example `#FFFFFF00`) gives a transparent RGBA result. |
| `layout_mode` | COMBO | `preset` | Where the slots come from. `preset`: from `layout_preset`. `grid`: from `columns` and `rows`. `custom`: from `custom_layout`. |
| `layout_preset` | COMBO | `2x3` | The preset for `preset` mode. See the table below. |
| `resize_mode` | COMBO | `cover` | How an image fits its slot. `cover`: fill the slot and cut the overflow from the centre. `contain`: fit the whole image, centred, with the background around it. `stretch`: fill the slot, changing the proportions. |
| `columns` | INT | `2` | `1` to `20`. Used in `grid` mode. |
| `rows` | INT | `3` | `1` to `20`. Used in `grid` mode. |
| `margin_x` | INT | `150` | `0` to `10000` px of empty space at the left and right edges. |
| `margin_y` | INT | `150` | `0` to `10000` px at the top and bottom edges. |
| `gap_x` | INT | `150` | `0` to `10000` px between slots in a row. |
| `gap_y` | INT | `150` | `0` to `10000` px between slots in a column. |
| `custom_units` | COMBO | `auto` | The unit of the numbers in `custom_layout`: `auto`, `relative`, `percent` or `pixels`. |
| `custom_layout` | STRING | six relative slots | One slot per line. See "Custom layout" below. |
| `background_fit` | COMBO | `stretch` | How `background_image` fits the canvas: `stretch`, `cover` or `contain`. |
| `background_image` *(optional)* | IMAGE | — | A picture drawn on the canvas before the slots. Only the first image of the batch is used. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The finished page, one image. |
| `slot_count` | INT | How many slots the layout has. |
| `used_count` | INT | How many slots were filled: the smaller of the image count and `slot_count`. |
| `layout_info` | STRING | One line per placed image, such as `0: x=10, y=10, w=323, h=687, mode=contain`. |
**Which inputs matter in which mode**
| Input | `preset` | `grid` | `custom` |
|---|:---:|:---:|:---:|
| `layout_preset` | yes | — | — |
| `columns`, `rows` | — | yes | — |
| `margin_x`, `margin_y`, `gap_x`, `gap_y` | yes | yes | — |
| `custom_layout`, `custom_units` | — | — | yes |
**Presets**
Margins shrink the area for the slots, and gaps separate them.
| Preset | Slots | Layout |
|---|---|---|
| `2x3` | 6 | 2 columns × 3 rows, all slots the same size |
| `2x3_mixed` | 6 | 2 columns × 3 rows, with rows of about 24 %, 24 % and 52 % of the height |
| `2_top_1_bottom` | 3 | two slots side by side on top (about 42 % of the height) and one wide slot below |
| `1_full` | 1 | one slot that fills the area inside the margins |
| `2_vertical` | 2 | 1 column × 2 rows, one above the other |
| `2_horizontal` | 2 | 2 columns × 1 row, side by side |
| `3_vertical` | 3 | 1 column × 3 rows |
| `4_grid` | 4 | 2 × 2 |
**Custom layout**
Write one slot per line as `x, y, width, height`.
```text
# x, y, width, height, relative to the canvas
0.05, 0.05, 0.90, 0.60 # a large photo on top
0.05, 0.70, 0.43, 0.25 # two small photos below
0.52, 0.70, 0.43, 0.25
```
- Separate the numbers with commas, semicolons or spaces. Everything after `#` is a comment. Empty lines are skipped.
- If a line has more than four numbers, the last four are used, so you can start a line with its own number.
- Width and height must be above zero. A slot can overlap another one or run past the canvas edge. The parts outside are cut off.
- Slot *n* gets image *n*. In this mode `margin_*` and `gap_*` are ignored.
| `custom_units` | The numbers mean |
|---|---|
| `relative` | A fraction of the canvas size, from `0` to `1`. |
| `percent` | A percentage of the canvas size, from `0` to `100`. |
| `pixels` | Pixels. |
| `auto` | `relative` when every number in the line is between −1 and 1, otherwise `pixels`. `auto` never picks `percent`. |
**How it works**
- If you give more images than slots, the extra images are left out. If you give fewer, the empty slots show the canvas.
- Images with an alpha channel are pasted with their own transparency, so the canvas shows through. The same goes for an RGBA `background_image`: its transparent areas show `background_color`.
- The result is RGB. It is RGBA only when `background_color` has an alpha below `FF`.
<p align="center"><img src="../assets/examples/layer-layout.jpg" alt="A page built with Layer Layout Composite" width="720"><br><em>A page built with Layer Layout Composite.</em></p>
**Example — six photos on an A4 page**
```text
Image Batch (6 images) → Layer Layout Composite (NH) → Save Image Path (NH)
```
Keep the defaults: `preset`, `2x3`, `cover`, 150 px margins and gaps. In Save Image Path, set `dpi` to `300` so the page prints at A4 size.
> **Tip:** Use `contain` when no part of a photo may be cut, and `cover` when a full slot looks better than a complete picture.
---
## Layer Stack Composite (NH)
<p align="center"><img src="../assets/nodes/NH_LayerStackComposite.svg" alt="Layer Stack Composite (NH) node" width="360"></p>
Pastes up to 64 layers on a background image. You write each position as numbers or as a formula.
**Use it when** you place a logo, a watermark or stickers at exact spots. A spot can depend on the size of the background or of another layer, such as "centred" or "bottom right with a 40 px margin".
| Input | Type | Default | Description |
|---|---|---|---|
| `background_image` | IMAGE | — | The base picture. Only the first image of the batch is used. The result has its size. |
| `layer_count` | INT | `1` | `0` to `64`. How many layers to place. The node shows that many `layer_N` inputs. |
| `positions` | STRING | `0,0` | One line per layer: `x, y` in pixels from the top-left corner. Formulas are allowed. See below. |
| `layer_1` … `layer_64` *(optional)* | IMAGE | — | The layers. Only the first image of each is used. `layer_1` is pasted first, so higher numbers sit on top. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The background with the layers pasted on it. |
| `used_count` | INT | How many layers were pasted, meaning at least partly inside the picture. |
| `layer_info` | STRING | One line per layer: its position and size, `missing` when no image is connected, or `outside canvas`. |
**Writing positions**
One line is one layer: line 1 is `layer_1`, line 2 is `layer_2`, and so on. Each line has an x formula and a y formula, separated by a comma or a semicolon. Empty lines and `#` comments do not count. A layer without a line goes to `0, 0`.
```text
(a - w1) / 2, (b - h1) / 2 # layer 1, centred
x1 + w1 + 20, y1 # layer 2, to the right of layer 1 with a 20 px gap
a - w3 - 40, b - h3 - 40 # layer 3, bottom right with a 40 px margin
```
Formulas use numbers, parentheses, `+ - * / // % **` and a leading minus. Decimal numbers use a dot. Functions such as `min` or `max` are not available, and `^` is not a power (use `**`). The result is rounded to whole pixels. Division by zero is an error.
| Variable | Value |
|---|---|
| `a`, `bg_w`, `width` | The width of the background. |
| `b`, `bg_h`, `height` | The height of the background. |
| `w1`, `w2`, … | The width of layer 1, 2, …. It is `0` when that layer has no image. |
| `h1`, `h2`, … | The height of layer 1, 2, …. |
| `x1`, `y1`, `x2`, … | The position already worked out for an earlier line. A line can use only the lines above it. |
Names are not case-sensitive. A formula the node cannot read stops the run with `Invalid position expression` and the text of the formula.
**How it works**
- The part of a layer outside the picture is cut off. A layer completely outside is not pasted, and `layer_info` says `outside canvas`.
- Layers with an alpha channel are pasted with their own transparency. The result has the channels of the background: RGB stays RGB, and an RGBA background gives an RGBA result.
- The node shows only the inputs up to `layer_count`. When you lower `layer_count`, the inputs above it, and their links, are removed. The **update layers** button on the node refreshes the inputs, for example after you load a workflow.
- The result is cached like that of any other node: the node runs again only when the background, a layer, `layer_count` or `positions` changes.
**Example — a watermark in the bottom right corner**
```text
Load Image (photo).image → Layer Stack Composite (NH).background_image
Load Image (logo).image + .mask → Join Image with Alpha → Layer Stack Composite (NH).layer_1
```
Set `layer_count` to `1` and `positions` to `a - w1 - 40, b - h1 - 40`.
> **Note:** Load Image gives the picture in RGB and its transparency as a separate `MASK`. To paste a logo with transparent areas, join the two again with the core node `Join Image with Alpha`, as above. The same works with the `image` and `mask` outputs of [Load Image Info (NH)](./image-io.md#load-image-info-nh).
**Common mistakes**
- Changing `layer_count` but not connecting the new inputs. The extra layers show `missing` in `layer_info`.
- Expecting a batch of layers. Only the first image of each input is used.
- Writing a formula with `min()` or `^`. Rewrite it with the operators above.
---
## Image Compare (NH)
<p align="center"><img src="../assets/nodes/NH_ImageCompare.svg" alt="Image Compare (NH) node" width="360"></p>
Combines two images into one picture so you can compare them: side by side, stacked, split, blended, or as a difference.
**Use it when** you want a before and after, or to see exactly what a step changed.
| Input | Type | Default | Description |
|---|---|---|---|
| `image_a` | IMAGE | — | The first image. It sets the size of the result. |
| `image_b` | IMAGE | — | The second image. It is resized to the size of `image_a`. |
| `compare_mode` | COMBO | `side_by_side` | How to combine them. See the table below. |
| `split_position` | FLOAT | `0.5` | `0` to `1`, step 0.01. Where the dividing line sits in the two `split_*` modes. |
| `overlay_opacity` | FLOAT | `0.5` | `0` to `1`, step 0.01. The blend in `overlay` mode: `0` shows only A, `1` shows only B. |
| `resize_method` | COMBO | `lanczos` | How `image_b` is resized to `image_a`: `lanczos`, `bicubic`, `bilinear` or `nearest`. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The combined picture. |
| `compare_mode` | Result |
|---|---|
| `side_by_side` | A on the left, B on the right. Twice as wide as A. |
| `top_bottom` | A on top, B below. Twice as tall as A. |
| `split_vertical` | One picture divided by a vertical line: A to the left of `split_position`, B to the right. |
| `split_horizontal` | One picture divided by a horizontal line: A above `split_position`, B below. |
| `difference` | The absolute difference of A and B in every channel. Black where they are the same. |
| `overlay` | A and B blended with `overlay_opacity`. |
**How it works**
- **Batches.** If both batches have the same size, image *n* of A is compared with image *n* of B. If one has a single image, it is repeated for every image of the other. Otherwise both are cut to the shorter length, and a message appears in the console.
- The result is RGB. Transparency is dropped.
<p align="center"><img src="../assets/examples/image-compare.jpg" alt="Output of Image Compare" width="720"><br><em>Output of Image Compare.</em></p>
**Example — before and after**
```text
Load Image → Image Compare (NH).image_a
KSampler → VAE Decode → Image Compare (NH).image_b
Image Compare (NH) → Preview Image
```
Set `compare_mode` to `split_vertical` and `split_position` to `0.5`.
> **Tip:** The difference is not amplified, so a small change looks almost black. Use `overlay` or a split to judge subtle changes. For images of tens of megapixels, use [NH Large Image Compare](./image-preview.md#nh-large-image-compare).
---
## Image Label (NH)
<p align="center"><img src="../assets/nodes/NH_ImageLabel.svg" alt="Image Label (NH) node" width="360"></p>
Adds a text band above or below an image, or writes the text over the picture, with a choice of font, colours and outline.
**Use it when** you want captions on a contact sheet, a "before" and "after" tag on a comparison, or the model or seed printed on a result.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The image or batch to label. Every image gets the same label. |
| `label_text` | STRING | `NH Label` | The text. Start a new line to write several lines. |
| `position` | COMBO | `header` | `header`: at the top. `bottom`: at the bottom. |
| `frame_height` | INT | `80` | `1` to `4096`. The height of the band in pixels. Make it taller than the text. |
| `fill_enabled` | BOOLEAN | `true` | `true`: fill the band with `frame_color_hex`. `false`: build the band from the top pixel row (header) or the bottom pixel row (bottom) of the image, stretched, so the band blends with the picture. |
| `frame_color_hex` | STRING | `#111111` | The band colour. |
| `text_color_hex` | STRING | `#FFFFFF` | The text colour. |
| `font_name` | COMBO | `default` | `default`, or a font file from the Windows `Fonts` folder. On other systems only `default` is offered. `default` uses Arial when it is available, and Pillow's built-in font otherwise. |
| `font_size` | INT | `32` | `6` to `512`. |
| `fit_text` | BOOLEAN | `true` | Shrink the text, down to size 8, until it fits the image width minus both side paddings. The text is never wrapped. |
| `overlay_on_image` | BOOLEAN | `false` | `false`: add the band outside, so the image grows taller by `frame_height`. `true`: draw the band over the edge of the picture and keep the size. |
| `align` | COMBO | `left` | `left`, `center` or `right`. |
| `padding_x` | INT | `20` | `0` to `2048` px of space at the left and right of the text. |
| `outline_width` | INT | `0` | `0` to `32` px. The width of a line around the letters. |
| `outline_color_hex` | STRING | `#000000` | The outline colour. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The labelled image, in RGB. |
**How it works**
- The text is centred vertically in the band. If the band is shorter than the text, the text runs past the band.
- With `overlay_on_image` on, the band covers part of the picture. Its height is limited to the image height.
- The list of fonts is read when ComfyUI starts. Restart ComfyUI after you install a font.
<p align="center"><img src="../assets/examples/image-label.jpg" alt="Output of Image Label" width="720"><br><em>Output of Image Label.</em></p>
**Example — tag a result**
```text
VAE Decode → Image Label (NH) → Preview Image
```
Set `label_text` to `After`, `position` to `bottom`, `align` to `center` and `outline_width` to `2`.
> **Tip:** To print text from elsewhere in your workflow, such as a file name, connect a STRING output to `label_text`.
---
## Image Resize Unit (NH)
<p align="center"><img src="../assets/nodes/NH_ImageResizeByUnit.svg" alt="Image Resize Unit (NH) node" width="360"></p>
Resizes an image to a width and height given in pixels, millimetres or centimetres. A DPI value converts physical units to pixels.
**Use it when** the result must have a print size, such as A4 or 10 × 15 cm, or when you want to set one side and let the other follow.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The image or batch to resize. |
| `unit` | COMBO | `pixel` | The unit of `width_value` and `height_value`: `pixel`, `mm` or `cm`. |
| `width_value` | FLOAT | `1024.0` | `0` to `100000`, step 0.1. The target width in `unit`. `0` means: work it out from the height and keep the proportions. |
| `height_value` | FLOAT | `1024.0` | `0` to `100000`, step 0.1. The target height. `0` means: work it out from the width. |
| `dpi` | INT | `300` | `1` to `2400`. Used only for `mm` and `cm`. Pixels = size ÷ 25.4 × `dpi` for millimetres, size ÷ 2.54 × `dpi` for centimetres. |
| `resize_mode` | COMBO | `stretch` | How the image reaches the size. See the table below. |
| `resize_method` | COMBO | `nearest` | The resampling filter: `nearest`, `bilinear`, `bicubic`, `area`, `nearest-exact` or `lanczos`. |
| `pad_color_hex` | STRING | `#000000` | The padding colour for `pad`. The alpha part applies to RGBA images. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The resized image. |
| `width_px` | INT | The real width in pixels. |
| `height_px` | INT | The real height in pixels. |
| `resize_mode` | Result |
|---|---|
| `stretch` | Exactly width × height. The proportions change if the shape differs. |
| `pad` | The whole image fits inside, centred, on a canvas of exactly width × height filled with `pad_color_hex`. |
| `crop` | The image covers the target, and the overflow is cut evenly from the centre. The size is exactly width × height. |
| `lock_ratio` | The proportions are kept and the image fits inside width × height. One side can be smaller than requested. |
**How it works**
- If both `width_value` and `height_value` are `0`, the image keeps its size.
- `nearest` and `nearest-exact` give the same result.
- The `dpi` here only converts units. To store a DPI value in a PNG or JPG file, set `dpi` in [Save Image Path (NH)](./image-io.md#save-image-path-nh).
Examples with an 800 × 600 image:
| Settings | Result |
|---|---|
| `mm`, 210 × 297, `dpi` 300, `stretch`, `pad` or `crop` | 2480 × 3508 px (A4) |
| `cm`, 10 × 15, `dpi` 300, `lock_ratio` | 1181 × 886 px |
| `pixel`, 1024 × 0, `stretch` | 1024 × 768 px |
| `pixel`, 0 × 0 | 800 × 600 px |
**Example — an A4 page**
```text
Load Image → Image Resize Unit (NH) → Save Image Path (NH)
```
Set `unit` to `mm`, `width_value` to `210`, `height_value` to `297`, `dpi` to `300` and `resize_mode` to `pad`. In Save Image Path, set `dpi` to `300`.
> **Tip:** The default `resize_method` is `nearest`, which is fast and keeps hard edges. For photos, choose `lanczos` or `bicubic`. To resize for a model, see [Resolution](./resolution.md).
---
**See also:** [Image — Load and Save](./image-io.md) for saving the result, [Image — Mask-Based Retouch](./image-retouch.md) for the mask-aware nodes, and [Resolution](./resolution.md) for model-aware resizing.
[← Back to guide](./README.md)
-287
View File
@@ -1,287 +0,0 @@
[← Back to guide](./README.md)
# Image — Load and Save
These nodes move images in and out of a workflow. Load one image together with its file name and path, step through a folder one image per run, pull the images of a matching folder by name, and save results to the folder and file name you choose. One node saves very large images without sending a heavy preview to the canvas. Find them under **NH-Nodes → Image** in the node menu.
**On this page**
| Node | Use it to |
|---|---|
| [Load Image Info (NH)](#load-image-info-nh) | Load one image and get its file name and path as text |
| [Load Images Folder (NH)](#load-images-folder-nh) | Load images from a folder by position, and move to the next one on every run |
| [Load images matching](#load-images-matching) | Find the folder that matches a subject name and load its images |
| [Save Image Path (NH)](#save-image-path-nh) | Save to any folder with your own prefix, numbering, format and DPI |
| [NH Save Large Image](#nh-save-large-image) | Save very large images without a heavy preview on the canvas |
## Paths and file types
| Where | A relative path starts in |
|---|---|
| `folder_path` of Load Images Folder, `matching_root_path` and `source_folder_path` of Load images matching | the ComfyUI `input` folder |
| `folder_path` of Save Image Path | the ComfyUI `output` folder |
| NH Save Large Image | always the ComfyUI `output` folder |
The folder loaders read `.png`, `.jpg`, `.jpeg`, `.webp`, `.avif`, `.bmp`, `.tif` and `.tiff` files. They sort names in natural order, so `img2` comes before `img10`, and they return RGB images.
---
## Load Image Info (NH)
<p align="center"><img src="../assets/nodes/NH_LoadImageInfo.svg" alt="Load Image Info (NH) node" width="360"></p>
Loads one image from the ComfyUI `input` folder, like the built-in Load Image, and also returns its file name and path as text.
**Use it when** you want to name or route your results after the source file, or record which file a run used.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | COMBO | — | The image to load. Lists the image files in the `input` folder. Use the upload button to add one. |
| `filename_extension` | BOOLEAN | `true` | `true`: `file_name` keeps its extension. `false`: the extension is removed. |
| `path_include_filename` | BOOLEAN | `true` | `true`: `path` is the full path of the file. `false`: `path` is only the folder that holds it. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The image in RGB. The frames of an animated file (GIF, WebP) become a batch. |
| `mask` | MASK | Built from the transparency of the file: opaque pixels are `0`, transparent pixels are `1`, as in Load Image. All `0` when the file has no transparency. |
| `file_name` | STRING | The name of the file. |
| `path` | STRING | The full path, or only the folder. See `path_include_filename`. |
**How it works**
- Loading follows ComfyUI's Load Image. The EXIF rotation is applied. In an animation, frames whose size differs from the first frame are skipped. For MPO files only the first frame is used.
- Transparency is not kept in `image`. It goes to `mask`.
- The node runs again when the content of the file changes, so you can edit and save the image in place.
**Example — name the result after the source file**
```text
Load Image Info (NH).image → … your workflow … → Save Image Path (NH).images
Load Image Info (NH).file_name → Save Image Path (NH).filename_prefix
```
Set `filename_extension` to `false` so the prefix does not end in `.png`.
> **Tip:** Set `path_include_filename` to `false` and connect `path` to `folder_path` of Save Image Path to save the result in the folder of the source image.
---
## Load Images Folder (NH)
<p align="center"><img src="../assets/nodes/NH_LoadImagesFromFolder.svg" alt="Load Images Folder (NH) node" width="360"></p>
Loads one or more images from a folder by position, and can move to the next image after every run.
**Use it when** you want to run a workflow over every image of a folder, one image per run (for example to upscale a whole folder), or to load a few consecutive images as a batch.
| Input | Type | Default | Description |
|---|---|---|---|
| `folder_path` | STRING | empty | The folder to read. An absolute path, or a path relative to the `input` folder. Empty means the `input` folder. A path to a file uses the folder of that file. |
| `index` | INT | `0` | Position of the first image to load, from `0` to `999999`. It wraps around: with 10 images, `12` loads image `2`. |
| `step` | INT | `1` | How many images to load per run (`1` to `9999`), one after the other from `index`. It is also the distance `index` moves between runs in `increment` and `decrement` modes. |
| `seed_mode` | COMBO | `fixed` | What happens to `index` each time you queue: `fixed` (stays), `increment` (adds `step`), `decrement` (subtracts `step`; the images are also read backwards), `random` (a new random position). |
| `recursive` | BOOLEAN | `false` | Also read the images in sub-folders. |
| `filename_extension` | BOOLEAN | `true` | Keep the extension in `filename`. |
| `path_output` | COMBO | `file_path` | What `path` lists: `file_path` (the full path of each file) or `folder_path` (the folder of each file). |
| Output | Type | Description |
|---|---|---|
| `images` | IMAGE | The loaded images as one batch. If their sizes differ, every image is resized to the size of the first one. |
| `filename` | STRING | The file names, one per line, in loading order. |
| `path` | STRING | The paths, one per line. |
**How it works**
- If the folder holds no images of its own, its sub-folders are searched even when `recursive` is off. A search of sub-folders skips the ComfyUI `models` folder.
- The browser moves `index` when you queue the workflow from the ComfyUI interface. It counts the images with the node's own `recursive` setting, so `increment`, `decrement` and `random` wrap and pick over the same images that the node loads. If you send the workflow through the API, set `index` yourself.
- The node runs again when one of the selected files changes on disk (name, size or date). If `folder_path` is wired from another node, the node cannot check the files in advance: it then runs again when the wired path or another setting changes, but not when a file inside the same folder changes.
- A folder that does not exist, or has no images, stops the run with an error.
**Example — upscale a whole folder**
```text
Load Images Folder (NH) → Upscale Image (using Model) → Save Image Path (NH)
```
Set `seed_mode` to `increment` and `step` to `1`. Each queue loads the next file. When `index` passes the last image, it starts again from the first.
> **Tip:** `step` `4` with `fixed` loads the same four images on every run. With `increment`, each run moves four images forward.
---
## Load images matching
<p align="center"><img src="../assets/nodes/NH_LoadImagesMatching.svg" alt="Load images matching node" width="360"></p>
Finds the folder under a root whose name matches a subject, and loads its images. The subject comes from your source folder, or from text you type.
**Use it when** your matching images are grouped in folders by subject, and you want the folder that belongs to the current source picked for you. This works well for libraries split into groups, such as `Nam` and `Nu` (Vietnamese for male and female), with one folder per person inside each group:
```text
matching_root_path
├── Nam
│ ├── subject_01
│ └── subject_02
└── Nu
├── subject_01 ← loaded when the source path ends in …/Nu/subject_01
└── subject_02
```
| Input | Type | Default | Description |
|---|---|---|---|
| `source_folder_path` | STRING | empty | The source folder of the subject. Only the folder **names** in the path are used, so the folder does not have to exist. The last name is the match text, unless you fill in `match_text`. A context folder in the path (see `context_folder_names`) tells the node which branch to prefer. |
| `matching_root_path` | STRING | empty | The root of the folder tree to search. An absolute path, or a path relative to the `input` folder. Required. |
| `match_text` | STRING | empty | The folder name to look for. Empty means: use the name of the source folder. |
| `match_mode` | COMBO | `contains` | `contains`: the folder name contains the text. `exact`: the folder name equals the text. Both ignore case and accents, and treat `_` and `-` as spaces. |
| `recursive` | BOOLEAN | `true` | `true`: search every folder below the root. `false`: check only the root and its direct sub-folders. |
| `index` | INT | `0` | Position of the first image in the matched folder, from `0` to `999999`. It wraps around. |
| `step` | INT | `1` | How many images to load from the matched folder (`1` to `9999`), one after the other from `index`. |
| `repeat_count` | INT | `1` | Repeats the loaded images this many times in the output batch (`1` to `9999`). The text outputs are not repeated. |
| `context_folder_names` | STRING | `Nam` and `Nu`, one per line | The names of the context folders. Separate names with new lines, commas, semicolons or vertical bars. Replace the defaults with the group names of your own library. |
| `source_file_names` *(optional)* | STRING | empty | One source file path per line. Each line is one match item: the match text is the name of the file's folder (unless `match_text` is set), and its path supplies the context. Use it to load the matches of several subjects at once. |
| `fallback_images` *(optional)* | IMAGE | — | The images to use when nothing matches. They are only evaluated on a miss, so the nodes that feed this input do not run when a folder matches. See "When nothing is found". |
| Output | Type | Description |
|---|---|---|
| `images` | IMAGE | The loaded images as one batch. If their sizes differ, every image is resized to the size of the first one. When nothing is found it carries `fallback_images` if that input is connected, and is blocked otherwise (see "When nothing is found"). |
| `filename` | STRING | The file names, one per line, one line per loaded image. |
| `path` | STRING | The matched folder of each loaded image, one per line. |
| `matched_text` | STRING | The text that was searched, one line per loaded image. |
| `found` | BOOLEAN | `true` when every item found a folder with images. Otherwise `false`, also when `fallback_images` supplies the images. |
**How it works**
- **Match text:** `match_text`, or else the name of the folder that holds each `source_file_names` line, or else the name of the source folder. Fill in at least one of `source_folder_path`, `source_file_names` and `match_text`. With none of them, the node looks for the name of ComfyUI's `input` folder, which rarely matches.
- **Context:** if the source path contains one of the `context_folder_names`, matches under the same context rank first. A source in `…/Nu/subject_01` picks `Nu/subject_01` before `Nam/subject_01`. If your root sits inside one context folder (`…/Nam`) and the source belongs to another (`Nu`), the same place under the other context folder is searched too.
- **Ties:** among equal matches, the folder whose path is most like the source path wins, then natural name order.
- **Limits:** the search stays inside the root. It does not scan parent folders, apart from the sibling context folders described above, and it never enters the ComfyUI `models` folder. With `recursive` on, a root that is a drive or a network share (such as `D:\` or `\\server\share`) is refused: it cannot be searched recursively. The `models` folder is refused as a root whatever `recursive` says.
- **Files:** the images of the matched folder are sorted in natural order. `index` and `step` choose which ones to load.
- **Caching:** the result is reused until the matched folder or one of the selected files changes (name, size or date). A search that finds nothing is never remembered, so a folder you add later is found on the next run. If a setting is wired from another node, the node cannot know the folder in advance. It then watches the whole tree below the root, and in a very large tree it runs on every queue.
**When nothing is found**
> **Note:** if no folder matches, or the matched folder has no images, the run does not crash. `found` is `false`, `filename` and `path` are empty, `matched_text` holds the text that was searched, and the reason is printed in the console. With several items, one miss makes the whole request "not found". A setting that cannot work still stops the run with an error: an empty or missing `matching_root_path`, a root that is a drive or a network share (with `recursive` on), or the `models` folder.
What `images` does on a miss depends on `fallback_images`:
- **Connected:** `images` outputs the fallback images, and the nodes that feed `fallback_images` run only now. `found` stays `false`, so you can still tell that nothing matched.
- **Not connected:** `images` is blocked. Nodes that need it are skipped, and ComfyUI shows the reason ("Execution Blocked"). The rest of the workflow keeps running.
> **Tip:** To carry on with another image when nothing matches, connect it to `fallback_images`. Do not route `images` through an If/Else or a switch: a blocked input blocks that node too, so it never gets to choose.
**Example — load the matching images for a source folder**
```text
Load Images Folder (NH).path → Load images matching.source_folder_path
Load images matching.images → … your workflow …
```
On Load Images Folder, set `path_output` to `folder_path`, so `path` is the folder of the source image. On Load images matching, set `matching_root_path` to the root of your library. Connect a default picture to `fallback_images`, or use `found` to decide what happens when no matching folder exists.
> **Tip:** Keep `matching_root_path` as close to the images as you can. With `recursive` on, every folder below the root is scanned.
---
## Save Image Path (NH)
<p align="center"><img src="../assets/nodes/NH_SaveImagePath.svg" alt="Save Image Path (NH) node" width="360"></p>
Saves an image batch to a folder you choose, with your own file name prefix and automatic numbering.
**Use it when** the results belong in a project folder outside the default `output` folder, or you need a format or a DPI value that the built-in Save Image does not offer.
| Input | Type | Default | Description |
|---|---|---|---|
| `images` | IMAGE | — | The images to save. Every image of the batch becomes a file. |
| `folder_path` | STRING | empty | Where to save. Empty means the `output` folder. A relative path is placed inside `output`. An absolute path is used as it is, even outside ComfyUI. Missing folders are created. A path to an existing file uses the folder of that file. |
| `create_new_folder` | BOOLEAN | `false` | Save into a sub-folder of `folder_path`. The `new_folder_name` field only shows while this is on. |
| `new_folder_name` | STRING | empty | The sub-folder, such as `day1` or `batch/day1`. It must stay inside `folder_path`. |
| `filename_prefix` | STRING | `NH` | The start of every file name. An empty value becomes `NH`. A `/` puts the files in a sub-folder, as in `renders/img`. |
| `number_suffix` | BOOLEAN | `true` | `true`: add a four-digit number. `false`: use the bare prefix first (see the table below). |
| `preview_image` | BOOLEAN | `false` | Also show the saved images on the node. |
| `file_format` | COMBO | `png` | `png`, `jpg`, `webp` or `avif`. |
| `dpi` | INT | `300` | `1` to `2400`. Print-size metadata that PNG and JPG files keep. WEBP and AVIF files do not store it. The pixels are not changed. |
| Output | Type | Description |
|---|---|---|
| `filenames` | STRING | The saved file names, one per line, including a sub-folder from `filename_prefix`. |
| `path` | STRING | The folder the files were saved to (`folder_path` plus the new folder). Join it with `filenames` for the full path. |
| `saved_count` | INT | How many files were written. |
**Where the files go**
| `folder_path` | New folder | `filename_prefix` | First file |
|---|---|---|---|
| empty | off | `NH` | `output/NH0001.png` |
| `renders` | off | `shot` | `output/renders/shot0001.png` |
| `D:\Projects\ClientA` | on, `day1` | `portrait` | `D:\Projects\ClientA\day1\portrait0001.png` |
| `D:\Projects\ClientA` | off | `final/portrait` | `D:\Projects\ClientA\final\portrait0001.png` |
**How numbering works**
The node never overwrites a file. It looks at the files that already use the prefix in the target folder (any of `png`, `jpg`, `webp`, `avif`) and takes the next free number.
| `number_suffix` | Two images, prefix `shot` | Next run |
|---|---|---|
| `true` | `shot0001.png`, `shot0002.png` | `shot0003.png`, `shot0004.png` |
| `false` | `shot.png`, `shot1.png` | `shot2.png`, `shot3.png` |
**Rules for names**
- `filename_prefix` and `new_folder_name` must stay inside the target folder. A `..` part or an absolute path stops the run with an error before anything is written. An absolute `folder_path` is allowed.
- On Windows, `filename_prefix` cannot contain `:`. It would select a drive instead of naming a file.
**How it works**
- Quality is fixed: `png` is lossless, `jpg` and `webp` use quality 95, `avif` uses quality 90. `avif` needs a Pillow build with AVIF support.
- Files are saved in RGB, so transparency is dropped. No ComfyUI workflow is embedded in the file.
- `dpi` is stored in `png` and `jpg` files. `webp` and `avif` files accept the value but do not keep it.
- This is an output node: it runs even when nothing is connected to its outputs.
> **Tip:** To drag a saved image back into ComfyUI and restore its workflow, use the built-in Save Image, or [NH Save Large Image](#nh-save-large-image) with a PNG.
---
## NH Save Large Image
<p align="center"><img src="../assets/nodes/NH_SaveLargeImage.svg" alt="NH Save Large Image node" width="360"></p>
Saves full-resolution images to the ComfyUI `output` folder and returns their paths. It sends no heavy preview of the saved image to the canvas.
**Use it when** the image is very large (tens of megapixels) and the browser struggles to show it, or you want TIFF output or a JPG or WEBP quality value.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The images to save. Every image of the batch is saved. |
| `filename_prefix` | STRING | `NH_Large` | Works like the prefix of the built-in Save Image. It can include a sub-folder (`project/shot`) and the tokens `%width%`, `%height%`, `%year%`, `%month%`, `%day%`, `%hour%`, `%minute%`, `%second%`. It cannot leave the `output` folder. |
| `file_format` | COMBO | `png` | `png`, `jpg`, `webp` or `tiff`. |
| `quality` | INT | `95` | `1` to `100`. Used by `jpg` and `webp`. Ignored by `png` and `tiff`, which are lossless. |
| `embed_metadata` | BOOLEAN | `true` | PNG only: store the prompt and workflow in the file, so you can drag it back into ComfyUI. It is always off when ComfyUI runs with `--disable-metadata`. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The input images, unchanged. |
| `file_path` | STRING | The full path of each saved file, one per line. |
| `saved_count` | INT | How many files were saved. |
**How it works**
- File names look like `NH_Large_00001_.png`: the prefix, a five-digit counter, then the extension. The counter continues from the highest number already used for the prefix, whatever the format.
- **Size limits:** WEBP allows up to 16383 px per side and JPEG up to 65500 px. The node checks this before it writes anything, and the error suggests PNG or TIFF. PNG and TIFF have no practical limit.
- **Transparency:** PNG and TIFF keep it. JPG and WEBP are saved in RGB. A single-channel (grey) image is accepted and saved as RGB.
- TIFF files use LZW compression.
- The node draws nothing on the canvas after saving. Read `file_path`, or open the `output` folder.
**Example — save an untiled result as TIFF**
```text
Image Untile (NH) → NH Save Large Image
```
Set `file_format` to `tiff` for a lossless file you can open in an editor. To look at the image first, add [NH Large Image Preview](./image-preview.md#nh-large-image-preview).
---
**See also:** [Image — Tile, Compose and Resize](./image-compose.md) for the tile nodes, and [Image — Large Image Preview](./image-preview.md) for the viewer.
[← Back to guide](./README.md)
-182
View File
@@ -1,182 +0,0 @@
[← Back to guide](./README.md)
# Image — Large Image Preview
The browser canvas struggles with images of tens of megapixels. These nodes keep a small thumbnail on the node and open a zoomable viewer when you ask for it. The full-size pixels wait in a temporary cache on disk. A third node shows what is in that cache and cleans it. Find them under **NH-Nodes → Image** in the node menu.
**On this page**
| Node | Use it to |
|---|---|
| [NH Large Image Preview](#nh-large-image-preview) | Look at a large image with a thumbnail on the node and a zoomable viewer |
| [NH Large Image Compare](#nh-large-image-compare) | Compare two large images with a slider, side by side or as a difference |
| [NH Large Preview Cache Manager](#nh-large-preview-cache-manager) | See what the preview cache holds, and delete old or oversized entries |
## How the viewer works
Each time a preview or compare node runs, it writes one cache entry for every image:
- a **thumbnail**, no larger than `preview_megapixels`, which appears on the node;
- **tiles** of the image at full size and at several smaller sizes, so the viewer loads only the part you look at, and sharper tiles as you zoom in;
- a **manifest**, a small JSON text that describes the entry. The node returns it in its `manifest` output.
Entries live in the ComfyUI `temp` folder, in a sub-folder named `nh_large_preview`. Each entry has a 32-character id. ComfyUI normally clears its `temp` folder when it starts, so the cache does not survive a restart. Every run adds new entries, so the cache grows until you clean it with [NH Large Preview Cache Manager](#nh-large-preview-cache-manager).
To open the viewer, run the workflow once, then click **Open Viewer** (preview) or **Open Compare** (compare) on the node. Before the first run, the button tells you to queue the node first.
| To | Do this |
|---|---|
| Pan | Drag with the mouse. |
| Zoom | Use the mouse wheel, or the **+** and **−** buttons. The zoom goes from a quarter of the fitted size up to 400 %. |
| Fit the image in the window | Click **Fit**. |
| See the real pixels | Click **100%**. |
| Move to the next or the previous image of a batch | Click ◀ or ▶, or press the Left or Right arrow key. These controls appear when the run produced more than one image, with a counter such as `2 / 5` between them. Each image starts fitted. |
| Open the thumbnail in a new browser tab | Click **Thumb** (preview viewer only). |
| Close | Click **Close**, press Esc, or click the dark area outside the window. |
---
## NH Large Image Preview
<p align="center"><img src="../assets/nodes/NH_LargeImagePreview.svg" alt="NH Large Image Preview node" width="360"></p>
Shows a thumbnail of a large image on the node, opens a zoomable viewer on demand, and passes the image on unchanged.
**Use it when** you need to inspect a large result, such as a tiled upscale of 50 megapixels, without sending the full image to the browser canvas.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The image or batch to preview. |
| `preview_megapixels` | FLOAT | `1.0` | `0.05` to `8`, step 0.05. The largest size of the thumbnail on the node, in megapixels. A smaller image keeps its size. |
| `preview_format` | COMBO | `jpg` | The thumbnail format: `jpg`, `webp` or `png`. |
| `preview_quality` | INT | `90` | `1` to `100`. The thumbnail quality. |
| `viewer_mode` | COMBO | `modal` | `modal`, `side_panel` or `new_tab`. The value is stored in the manifest. The viewer currently always opens as a window over the page, whatever you choose. |
| `title` | STRING | `NH Large Image Preview` | The title in the viewer header. |
| `tile_size` *(optional)* | INT | `512` | `128` to `2048`, step 64. The edge of a tile, in pixels. |
| `tile_format` *(optional)* | COMBO | `jpg` | The tile format: `jpg` or `webp`. |
| `tile_quality` *(optional)* | INT | `90` | `1` to `100`. The tile quality. |
| `cache_policy` *(optional)* | COMBO | `temp` | Where the cache is kept. Only `temp` exists. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The input image, unchanged. |
| `manifest` | STRING | JSON text with one entry for each image of the batch, including its cache id. |
**How it works**
- The node can sit in the middle of a workflow, because it passes the image through.
- The tiles are lossy at the default quality, so the viewer is for inspection. Use [NH Save Large Image](./image-io.md#nh-save-large-image) to keep the pixels.
- Every run creates new cache entries. See [How the viewer works](#how-the-viewer-works).
**Example — inspect a tiled upscale**
```text
Image Untile (NH) → NH Large Image Preview → NH Save Large Image
```
Run the workflow, then click **Open Viewer** on the preview node and zoom to **100%**.
> **Tip:** `preview_megapixels` changes only the thumbnail on the node. The viewer always shows the image at full size.
---
## NH Large Image Compare
<p align="center"><img src="../assets/nodes/NH_LargeImageCompare.svg" alt="NH Large Image Compare node" width="360"></p>
Compares two large images in a zoomable viewer with a slider, a side-by-side view or a difference view. Only a small thumbnail goes to the canvas.
**Use it when** you want to check a large upscale or edit against the original at pixel level, where [Image Compare (NH)](./image-compose.md#image-compare-nh) would produce a picture too large for the canvas.
| Input | Type | Default | Description |
|---|---|---|---|
| `image_a` | IMAGE | — | The first image. |
| `image_b` | IMAGE | — | The second image. |
| `compare_mode` | COMBO | `slider` | The view the viewer opens in and the thumbnail shows: `slider`, `side_by_side` or `difference`. |
| `sync_pan_zoom` | BOOLEAN | `true` | Stored in the manifest. The viewer currently always pans and zooms both images together. |
| `preview_megapixels` | FLOAT | `1.0` | `0.05` to `8`, step 0.05. The largest size of the thumbnails, in megapixels. |
| `preview_format` | COMBO | `jpg` | `jpg`, `webp` or `png`. |
| `preview_quality` | INT | `90` | `1` to `100`. |
| `title` | STRING | `NH Large Image Compare` | The title in the viewer header. |
| `tile_size` *(optional)* | INT | `512` | `128` to `2048`, step 64. |
| `tile_format` *(optional)* | COMBO | `jpg` | `jpg` or `webp`. |
| `tile_quality` *(optional)* | INT | `90` | `1` to `100`. |
| `cache_policy` *(optional)* | COMBO | `temp` | Only `temp` exists. |
| Output | Type | Description |
|---|---|---|
| `image_a` | IMAGE | The first image. If one batch had a single image, it is repeated to match the other. |
| `image_b` | IMAGE | The second image, matched in the same way. |
| `manifest` | STRING | JSON text with one entry for each pair, including both cache ids. |
**How it works**
- **Batches.** If both batches have the same size, image *n* of A is paired with image *n* of B. If one has a single image, it is repeated for every image of the other. Otherwise both are cut to the shorter length, and a message appears in the console. Use ◀ and ▶ in the viewer to move through the pairs.
- **Different sizes.** In the viewer, each image is scaled to fit one common frame, so images of different sizes are compared in the same area.
- **Views.** In the viewer, the **Slider**, **Side** and **Diff** buttons switch the view at any time. In slider view, a bar in the header moves the dividing line between 5 % and 95 %.
- **Thumbnail.** The thumbnail on the node shows the chosen view. In `difference` it is brightened three times so small changes are easier to see. The viewer's difference view is not brightened.
**Example — check an upscale**
```text
Load Image → NH Large Image Compare.image_a
Image Untile (NH) → NH Large Image Compare.image_b
```
Click **Open Compare**, drag the slider bar, and zoom in on an edge.
> **Tip:** If the two images have different sizes, the comparison is still lined up by their frames, not by their pixels. Resize one of them first when you need a pixel-exact check.
---
## NH Large Preview Cache Manager
<p align="center"><img src="../assets/nodes/NH_LargePreviewCacheManager.svg" alt="NH Large Preview Cache Manager node" width="360"></p>
Shows what the large-preview cache holds on disk, and deletes old entries, entries over a size limit, or one entry by id.
**Use it when** the `temp` folder grows because of many previews, or you want to free the space without restarting ComfyUI.
| Input | Type | Default | Description |
|---|---|---|---|
| `action` | COMBO | `info` | What to do. See the table below. |
| `max_age_hours` | FLOAT | `24.0` | `0` to `8760`, step 0.5. Entries older than this are deleted by the actions that use age. `0` deletes every entry. |
| `max_total_mb` | FLOAT | `2048.0` | `1` to `1048576`, step 64. The size the cache may keep, in megabytes, for the actions that use size. |
| `cache_id` | STRING | empty | The 32-character id of one entry. Used by `delete_cache_id` only. You find the id in the `manifest` output of a preview node. |
| `action` | What it does |
|---|---|
| `info` | Deletes nothing. Reports the number of entries, their total size and their age. |
| `cleanup_by_age` | Deletes the entries older than `max_age_hours`. |
| `enforce_size_limit` | Deletes the oldest entries until the cache is no larger than `max_total_mb`. |
| `cleanup_age_and_size` | Does both: age first, then size. |
| `delete_cache_id` | Deletes the one entry named in `cache_id`. The id is required. |
| Output | Type | Description |
|---|---|---|
| `summary` | STRING | JSON text: the action, the state of the cache before and after, and what was removed. |
| `removed` | INT | How many entries were deleted. |
| `freed_mb` | FLOAT | How many megabytes were freed. |
| `cache_root` | STRING | The folder that holds the cache. |
**How it works**
- The node runs on every queue. It is never skipped because its settings did not change.
- An entry is the cache of one image from one run. Deleting an entry also breaks the viewer for that run: tiles stop loading, and **Open Viewer** shows nothing for it. Run the preview node again to rebuild it.
- It is an output node, so it runs even when nothing is connected to its outputs.
**Example — keep the cache small**
```text
NH Large Preview Cache Manager
```
Add the node on its own, set `action` to `cleanup_age_and_size`, `max_age_hours` to `24` and `max_total_mb` to `2048`. Each run removes entries older than a day and trims the rest to 2 GB.
> **Note:** Do not set `max_age_hours` to `0` in a workflow that also shows a preview. The entries made in the same run would be deleted too.
---
**See also:** [NH Save Large Image](./image-io.md#nh-save-large-image) to write the full-size file, and [Image Compare (NH)](./image-compose.md#image-compare-nh) for a comparison picture you can save.
[← Back to guide](./README.md)
-183
View File
@@ -1,183 +0,0 @@
[← Back to guide](./README.md)
# Image — Mask-Based Retouch
Three nodes that work with a mask. One resizes an image to an exact size and keeps the masked subject whole. One erases the masked area, so a try-on or inpainting model has to fill it in. One pastes the masked face of one image onto another. Find them under **NH-Nodes → Image** in the node menu.
**On this page**
| Node | Use it to |
|---|---|
| [NH Mask-Aware Resize](#nh-mask-aware-resize) | Resize to an exact size while the whole masked subject stays in the picture |
| [NH Agnostic Image Generator](#nh-agnostic-image-generator) | Erase the masked area with grey, noise or blur |
| [NH Simple Face Paste](#nh-simple-face-paste) | Paste the masked face of one image onto the masked area of another |
A `MASK` is white (`1`) where the node should work and black (`0`) elsewhere. Get one from a segmentation node such as [Garment Segment (NH)](./vision.md#garment-segment-nh) or [Portrait Segment (NH)](./vision.md#portrait-segment-nh), or from any mask tool in ComfyUI.
---
## NH Mask-Aware Resize
<p align="center"><img src="../assets/nodes/NH_MaskResizeImage.svg" alt="NH Mask-Aware Resize node" width="360"></p>
Resizes an image to an exact width and height and keeps everything inside the mask. The masked subject is enlarged as far as the target allows, and the image is cropped or padded around it.
**Use it when** a model takes a fixed size (for example 832 × 1216) and the face, garment or product you mask must fit in it completely.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The image or batch to resize. |
| `mask` | MASK | — | The area to keep. Pixels above `0.5` count. It must have the same width and height as `image`. A single mask is used for every image of a batch. |
| `width` | INT | `512` | `64` to `8192`, step 8. The width of the result. |
| `height` | INT | `512` | `64` to `8192`, step 8. The height of the result. |
| `mode` | COMBO | `crop` | `crop`: cut a window out of the scaled image. `pad`: centre the subject and fill the empty space with a colour. |
| `pad_color_hex` | STRING | `#000000` | The padding colour, written as `#RRGGBB`. Any other form is read as black, including `#RGB` and `#RRGGBBAA`. |
| Output | Type | Description |
|---|---|---|
| `image` | IMAGE | The resized image, `width` × `height`. |
| `mask` | MASK | The mask, moved and scaled in the same way, so it still lines up with the new image. Padded areas are `0`. |
**How it works**
1. The node finds the box around the mask.
2. It scales the whole image by the largest factor at which that box still fits inside `width` × `height`. A small subject can be enlarged a lot.
3. It puts the centre of the box in the centre of the result.
- `crop` takes a window of the scaled image. The window slides back inside the image when needed, so a mask near an edge ends up off-centre, but nothing is padded. If the scaled image is smaller than the result, `crop` pads like `pad`.
- `pad` keeps the box exactly centred. Wherever the result reaches past the image, it is filled with `pad_color_hex`.
The whole mask is always in the result. The picture is never stretched, and the image uses Lanczos resampling.
Example: a 200 × 100 px mask in the top-left corner of a 1000 × 800 px image, with a 512 × 512 target. The scale is 2.56 in both modes.
| Mode | Where the mask lands | Padding |
|---|---|---|
| `crop` | At the top of the result, in rows 0 to 255. | None. |
| `pad` | Centred, in rows 128 to 383. | 128 rows of `pad_color_hex` above the image. |
With a mask near the middle of the image, both modes give the same picture. With a mask that covers the whole image, both fit the image inside the target and pad the rest.
<p align="center"><img src="../assets/examples/mask-aware-resize.jpg" alt="Crop and pad results of Mask-Aware Resize with the mask outlined" width="720"><br><em>The <code>crop</code> and <code>pad</code> results, with the mask outlined.</em></p>
**Example — prepare a garment for a fixed-size model**
```text
Load Image → Garment Segment (NH) → NH Mask-Aware Resize → your model
```
Connect the image to both Garment Segment and `image`, and the `mask` output of Garment Segment to `mask`. Set `width` to `832`, `height` to `1216` and `mode` to `crop`.
**Common mistakes**
- Using a mask with another size than the image. The node does not resize it, so the box lands in the wrong place.
- Expecting the whole image to survive. Only the mask is guaranteed. `crop` removes the surroundings that do not fit.
- Passing a soft mask whose values stay at `0.5` or below. Those pixels are ignored.
> **Note:** An empty mask counts as "the whole image". `crop` then covers the target and cuts the middle. `pad` fits the whole image inside the target. Nothing is stretched.
---
## NH Agnostic Image Generator
<p align="center"><img src="../assets/nodes/NH_AgnosticImageGenerator.svg" alt="NH Agnostic Image Generator node" width="360"></p>
Erases the masked area of an image and fills it with grey, noise or a heavy blur, so that a try-on or inpainting model has to invent what goes there. It also returns a white-masked copy and a before and after preview.
**Use it when** you prepare an "agnostic" person image for virtual try-on, where the garment area is removed, or you need a neutral base for an inpainting model.
| Input | Type | Default | Description |
|---|---|---|---|
| `image` | IMAGE | — | The image or batch to work on. |
| `mask` | MASK | — | The area to erase. Soft values blend partly. A single mask is used for every image of a batch. A 2-D mask is accepted. A mask of another size is resized to the image. |
| `fill_mode` | COMBO | `gray` | What fills the area: `gray`, `noise` or `blur`. |
| `blur_radius` | INT | `65` | `3` to `255`, step 2. The blur size for `blur`. An even value is raised to the next odd number. Larger means blurrier. |
| `noise_strength` | FLOAT | `1.0` | `0` to `1`, step 0.05. Used by `noise`: `0` gives flat grey, `1` gives pure noise. |
| `gray_value` | FLOAT | `0.5` | `0` to `1`, step 0.01. The brightness of the grey, from black to white. `noise` mixes with this grey. |
| `feathering` | INT | `0` | `0` to `100`. Softens the edge of the mask with a blur. Larger means a wider, softer edge. |
| Output | Type | Description |
|---|---|---|
| `agnostic_img` | IMAGE | The image with the masked area replaced by the fill. |
| `masked_img` | IMAGE | The image with the masked area painted white. |
| `composite` | IMAGE | A preview. The left half is the original with a green outline and tint around the mask, the right half is the agnostic image, and a white line marks the middle. |
| `fill_mode` | The masked area becomes |
|---|---|
| `gray` | Flat grey of brightness `gray_value`. |
| `noise` | Random noise mixed with the grey by `noise_strength`. The noise is repeatable: image *n* of a batch always gets the same noise. |
| `blur` | A heavily blurred copy of the whole image, so the colours stay but the detail is gone. Use a large `blur_radius` if the model must not see the original. |
**How it works**
- The mask works as a soft alpha. A value of `0.5` blends half of the fill with half of the image. `feathering` blurs that alpha further.
- The outline in `composite` follows the `0.5` level of the original mask.
- A single mask is reused for every image of a batch.
<p align="center"><img src="../assets/examples/agnostic.jpg" alt="An agnostic image made from a garment mask" width="720"><br><em>An agnostic image made from a garment mask.</em></p>
**Example — a try-on input**
```text
Load Image → Garment Segment (NH) → NH Agnostic Image Generator → agnostic_img → your try-on model
```
Use `fill_mode` `gray` with `gray_value` `0.5`, and `feathering` `8` for a soft edge.
> **Tip:** Grow the mask a little before this node (for example with [Mask Morphology (NH)](./mask.md#mask-morphology-nh)) so that no sliver of the old garment stays at the edge.
---
## NH Simple Face Paste
<p align="center"><img src="../assets/nodes/NH_SimpleFacePaste.svg" alt="NH Simple Face Paste node" width="360"></p>
Cuts the masked region out of a source image, resizes it to the masked region of a destination image, and blends it in with a soft edge.
**Use it when** you want to put one face onto another image, or restore a face from the original after other edits.
| Input | Type | Default | Description |
|---|---|---|---|
| `dest_image` | IMAGE | — | The image to paste onto. Its batch size sets the batch size of the result. |
| `dest_mask` | MASK | — | Marks where the face goes. Only the box around the mask (pixels above `0.5`) is used, for the position and the size. It must have the same size as `dest_image`. |
| `source_image` | IMAGE | — | The image that supplies the face. |
| `source_mask` | MASK | — | Marks the face to take. The box around it is cut out, and its shape, soft values included, decides what is pasted. It must have the same size as `source_image`. |
| `feathering` | INT | `20` | `0` to `200`. Blurs the edge of the pasted shape. `0` gives a hard edge. Larger means a softer edge. |
| Output | Type | Description |
|---|---|---|
| `IMAGE` | IMAGE | The destination images with the face pasted in. |
**How it works**
1. The node cuts the box around `source_mask` out of the source image.
2. It resizes that cut-out to the exact size of the box around `dest_mask`. The proportions are not kept: the face is stretched to fit.
3. It blends the cut-out into the destination with the soft `source_mask` as the opacity, after `feathering` has blurred it.
- **Batches.** The result has the batch size of `dest_image`. A source image, source mask or destination mask with fewer items is reused in turn, so a single source can be pasted onto a whole batch.
- **Empty masks.** If either mask of an item is empty, that image is returned unchanged.
- The work is done in 8 bits, so values are clipped to the range 0 to 1 first.
**Example — put a face onto several images**
```text
Load Image (source) → Portrait Segment (NH) → NH Simple Face Paste.source_mask
Load Image (source) → NH Simple Face Paste.source_image
Load Images Folder (NH) → NH Simple Face Paste.dest_image
Portrait Segment (NH) on the destination → NH Simple Face Paste.dest_mask
```
Set `feathering` to `20`. Because a single source is reused, every image of the batch gets the same face.
**Common mistakes**
- Using masks whose boxes have very different proportions. The face looks squashed or stretched.
- Giving a mask that has another size than its image.
- Setting `feathering` very high for a small face. The blur can eat the whole shape.
> **Tip:** Make `dest_mask` slightly larger than the face you replace, and keep `source_mask` tight. The soft edge of the source mask then blends into the destination.
---
**See also:** [Vision](./vision.md) for the segmentation nodes that make masks, [Mask](./mask.md) for masks you can grow, shrink and blur, and [VTON](./vton.md) for the full try-on preprocessing node.
[← Back to guide](./README.md)
-292
View File
@@ -1,292 +0,0 @@
[← Back to guide](./README.md)
# Loaders
Five loader nodes that each hold up to 64 model files and load exactly one of them, chosen by number or by an on/off toggle. Use them to switch LoRAs, diffusion models, VAEs or text encoders from a single node, by hand or automatically with a `Counter (NH)`. Find them under **NH-Nodes → Loaders** in the node menu.
Read [How the indexed loaders work](#how-the-indexed-loaders-work) first. It covers what the five nodes share: slots, `index` and `boolean` selection, what happens when nothing is selected, and what stays in memory.
**On this page**
| Node | Use it to |
|---|---|
| [Load LoRA Model Index (NH)](#load-lora-model-index-nh) | Apply one LoRA from a list of up to 64 to a `MODEL` |
| [Load LoRA Clip Index (NH)](#load-lora-clip-index-nh) | Apply one LoRA from a list to a `MODEL` and a `CLIP` |
| [Load Diffusion Model Index (NH)](#load-diffusion-model-index-nh) | Load one diffusion model from a list |
| [Load VAE Index (NH)](#load-vae-index-nh) | Load one VAE from a list |
| [Load Clip Index (NH)](#load-clip-index-nh) | Load one CLIP or text-encoder file from a list |
---
## How the indexed loaders work
All five nodes share the same controls and rules. Read this section once; the node sections below only list what is different.
### Slots
Each loader has up to 64 slots. A slot is a file list plus an on/off toggle (`enable_N`). The count widget sets how many slots are shown and used, and its default is 5. Slots above the count are hidden and ignored, but they keep their file, so raising the count brings them back.
| Node | Count widget | File lists | Files come from |
|---|---|---|---|
| `Load LoRA Model Index (NH)` | `lora_count` | `lora_1` … `lora_64` | `models/loras` |
| `Load LoRA Clip Index (NH)` | `lora_count` | `lora_1` … `lora_64` | `models/loras` |
| `Load Diffusion Model Index (NH)` | `model_count` | `diffusion_model_1` … `diffusion_model_64` | `models/diffusion_models` and `models/unet` |
| `Load VAE Index (NH)` | `vae_count` | `vae_1` … `vae_64` | `models/vae` |
| `Load Clip Index (NH)` | `clip_count` | `clip_1` … `clip_64` | `models/text_encoders` and `models/clip` |
The lists also include folders added in `extra_model_paths.yaml`. To see files you added while ComfyUI is running, refresh the node definitions (press `R`). The `update …` button at the bottom of each node only redraws which slots are visible. It does not rescan the folders.
### Choosing a slot: `select_mode`
| | `index` (default) | `boolean` |
|---|---|---|
| You choose with | the `index` number, where 1 is the first slot | the `enable_N` toggles |
| Shown on the node | `index` | the toggles of the visible slots (`index` is hidden) |
| Good for | automation: wire a `Counter (NH)`, a `Value Match Index (NH)` or a `Multi-Slider (INT)` into `index` | quick manual switching: tick the slot you want |
| Several toggles on | — | the lowest-numbered one inside the count is used (the node's interface keeps only one on at a time) |
### When nothing is selected
Nothing is selected when:
- in `index` mode, `index` is below 1 or above the count;
- in `boolean` mode, no toggle inside the count is on;
- the chosen slot has no file.
In that case the node loads nothing and:
- its `model`, `clip` or `vae` output is **blocked** (ComfyUI calls this an `ExecutionBlocker`). Every node that needs that output is skipped silently, with no error message, so the run can finish without producing an image;
- `filename` is empty and `index` is `-1`. These two outputs are not blocked.
> **Note:** A new node has empty slots. Choose a file in the slot you select, or nothing after the loader will run.
### What stays in memory
ComfyUI runs a node again whenever one of its inputs changes. A loader has up to 64 file lists and 64 toggles, so editing any slot, even one you are not using, counts as a change. To keep that from reloading a big file every time, the loaders reuse what they loaded:
- **`Load Diffusion Model Index (NH)`, `Load VAE Index (NH)` and `Load Clip Index (NH)`** hand back the model that ComfyUI still holds. Editing a slot that is not selected returns the model already in memory and reads no file. The model is loaded again when you select a different file, change `weight_dtype` (diffusion model) or `type` (CLIP), or the file on disk is replaced.
- **The node does not hold on to the model itself.** It keeps only a weak reference, so ComfyUI's own cache decides how long the model lives. When ComfyUI's default RAM-pressure cache frees the model because memory runs short, the next run loads it from disk again. With `--cache-classic` (which `--high-ram` switches on) the node keeps an ordinary reference, because that cache drops an output as soon as the workflow no longer needs it.
- **Only one model is kept per node.** Loading another file releases the previous one first, so two large models never sit in memory together. Cycling A, B, A therefore loads from disk each time. Clearing ComfyUI's execution cache releases the kept model too: use **Unload Models and Execution Cache** (called **Free model and node cache** in ComfyUI-Manager).
- **The LoRA nodes** keep the last LoRA file in memory and apply it to the incoming `model` on every run. The file is read again only when you select a different LoRA.
### Driving `index` automatically
| Source | What it gives you |
|---|---|
| `Counter (NH)` | One slot per queue. Set its `start` to `1`. See [Batch & Lists](./batch-lists.md). |
| `Value Match Index (NH)` | The 1-based position of a value that matches your input, or `-1` when nothing matches (which selects nothing). See [Logic](./logic.md). |
| `Multi-Slider (INT)` | A slot number you set by hand on a compact panel. See [Utils](./utils.md). |
---
## Load LoRA Model Index (NH)
<p align="center"><img src="../assets/nodes/NH_LoraModelIndex.svg" alt="Load LoRA Model Index (NH) node" width="360"></p>
Applies one LoRA, chosen from up to 64 slots, to a `MODEL`.
**Use it when** you want to compare several LoRAs on the same prompt without rewiring, or keep your favourite LoRAs together in one node.
| Input | Type | Default | Description |
|---|---|---|---|
| `select_mode` | COMBO | `index` | How a slot is chosen: `index` or `boolean`. |
| `model` | MODEL | — | The model to apply the LoRA to. |
| `index` | INT | `1` | The slot to use in `index` mode. 1 is the first slot. Range 1 to 64. |
| `lora_count` | INT | `5` | How many slots are shown and used. Range 1 to 64. |
| `strength_model` | FLOAT | `1.0` | How strongly the LoRA changes the model. Range -100 to 100, step 0.01. A negative value reverses its effect. `0` skips the LoRA. |
| `lora_1` … `lora_64` | COMBO | empty | Optional. The LoRA file for each slot, for example `my_style.safetensors`. |
| `enable_1` … `enable_64` | BOOLEAN | `false` | Optional. The on/off toggle of each slot, used in `boolean` mode. |
| Output | Type | Description |
|---|---|---|
| `model` | MODEL | The model with the LoRA applied. Blocked when nothing is selected. |
| `filename` | STRING | The LoRA file name as shown in the slot list. Empty when nothing is selected or when `strength_model` is `0`. |
| `index` | INT | The slot that was used, or `-1` when nothing is selected. |
**How it works**
- With `strength_model` at `0` the LoRA is not loaded. `model` passes through unchanged and `filename` is empty. It is a quick way to switch a LoRA off while keeping its slot.
- The node applies the LoRA to the model that comes in, so put it after `Load Checkpoint` and before the sampler.
- Slot choice, empty selection and memory work as described in [How the indexed loaders work](#how-the-indexed-loaders-work).
**Example — test your LoRAs one per queue and label each result**
```text
Counter (NH) → Load LoRA Model Index (NH) → KSampler → VAE Decode → Image Label (NH) → Save Image
```
- `Counter (NH)`: `start` 1, `step` 1, `max_value` equal to the number of LoRAs. Wire `current` into `index`.
- `Load LoRA Model Index (NH)`: set `lora_count` and choose a LoRA in each slot. Wire `filename` into `label_text` of `Image Label (NH)` (see [Image Compose](./image-compose.md)) to stamp the LoRA name on every image.
- Set the batch count to the number of LoRAs and press Run.
---
## Load LoRA Clip Index (NH)
<p align="center"><img src="../assets/nodes/NH_LoraClipIndex.svg" alt="Load LoRA Clip Index (NH) node" width="360"></p>
Applies one LoRA, chosen from up to 64 slots, to both a `MODEL` and a `CLIP`.
**Use it when** the LoRA should also change how the prompt is read, so the `CLIP` needs patching along with the `MODEL`.
| Input | Type | Default | Description |
|---|---|---|---|
| `select_mode` | COMBO | `index` | How a slot is chosen: `index` or `boolean`. |
| `model` | MODEL | — | The model to apply the LoRA to. |
| `clip` | CLIP | — | The text encoder to apply the LoRA to. |
| `index` | INT | `1` | The slot to use in `index` mode. 1 is the first slot. Range 1 to 64. |
| `lora_count` | INT | `5` | How many slots are shown and used. Range 1 to 64. |
| `strength_model` | FLOAT | `1.0` | LoRA strength on the model. Range -100 to 100, step 0.01. |
| `strength_clip` | FLOAT | `1.0` | LoRA strength on the CLIP. Range -100 to 100, step 0.01. |
| `lora_1` … `lora_64` | COMBO | empty | Optional. The LoRA file for each slot. |
| `enable_1` … `enable_64` | BOOLEAN | `false` | Optional. The on/off toggle of each slot, used in `boolean` mode. |
| Output | Type | Description |
|---|---|---|
| `model` | MODEL | The model with the LoRA applied. Blocked when nothing is selected. |
| `clip` | CLIP | The CLIP with the LoRA applied. Blocked when nothing is selected. |
| `filename` | STRING | The LoRA file name as shown in the slot list. Empty when nothing is selected or when both strengths are `0`. |
| `index` | INT | The slot that was used, or `-1` when nothing is selected. |
**How it works**
- With both strengths at `0` the LoRA is not loaded. `model` and `clip` pass through unchanged and `filename` is empty.
- Use `Load LoRA Model Index (NH)` instead when you only want to patch the model.
**Example — switch LoRAs by hand with toggles**
```text
Load Checkpoint → Load LoRA Clip Index (NH) → KSampler / CLIP Text Encode
```
Set `select_mode` to `boolean` and choose your LoRAs in the slots. Switch on the toggle of the slot you want. Switching one on turns the others off. Leave all toggles off to block everything after the loader.
---
## Load Diffusion Model Index (NH)
<p align="center"><img src="../assets/nodes/NH_DiffusionModelIndex.svg" alt="Load Diffusion Model Index (NH) node" width="360"></p>
Loads one diffusion model (the main image or video model), chosen from up to 64 slots.
**Use it when** you want to compare several base models or fine-tunes in one workflow, or switch between precisions of the same model, without rewiring.
| Input | Type | Default | Description |
|---|---|---|---|
| `select_mode` | COMBO | `index` | How a slot is chosen: `index` or `boolean`. |
| `index` | INT | `1` | The slot to use in `index` mode. 1 is the first slot. Range 1 to 64. |
| `model_count` | INT | `5` | How many slots are shown and used. Range 1 to 64. |
| `weight_dtype` | COMBO | `default` | Precision to load the weights in: `default`, `fp8_e4m3fn`, `fp8_e4m3fn_fast` or `fp8_e5m2`. |
| `diffusion_model_1` … `diffusion_model_64` | COMBO | empty | Optional. The model file for each slot, for example `my_model.safetensors`. |
| `enable_1` … `enable_64` | BOOLEAN | `false` | Optional. The on/off toggle of each slot, used in `boolean` mode. |
| Output | Type | Description |
|---|---|---|
| `model` | MODEL | The loaded diffusion model. Blocked when nothing is selected. |
| `filename` | STRING | The model file name as shown in the slot list. Empty when nothing is selected. |
| `index` | INT | The slot that was used, or `-1` when nothing is selected. |
**How it works**
- `weight_dtype` has the same options as ComfyUI's own `Load Diffusion Model` node. `default` loads the weights the way ComfyUI normally would. The `fp8_*` options load them in 8-bit floating point, which takes less memory, and `fp8_e4m3fn_fast` also turns on ComfyUI's fp8 optimizations. The widget is marked as advanced, so some ComfyUI versions keep it collapsed until you show advanced options.
- The node loads the diffusion model only. Load the text encoder and VAE with `Load Clip Index (NH)` and `Load VAE Index (NH)`.
- The loaded model is reused while ComfyUI still holds it (see [What stays in memory](#what-stays-in-memory)). Changing `weight_dtype` loads it again.
**Example — switch a whole model set with one number**
Put matching files in the same slot number of three loaders:
| Slot | Diffusion model | Text encoder | VAE |
|---|---|---|---|
| 1 | `model_a.safetensors` | `encoder_a.safetensors` | `vae_a.safetensors` |
| 2 | `model_b.safetensors` | `encoder_b.safetensors` | `vae_b.safetensors` |
```text
Counter (NH) → Load Diffusion Model Index (NH) → KSampler
Counter (NH) → Load Clip Index (NH) → CLIP Text Encode
Counter (NH) → Load VAE Index (NH) → VAE Decode
```
Wire the same `Counter (NH)` (or one `Multi-Slider (INT)`) into the `index` of all three. One number then changes the model, the text encoder and the VAE together.
---
## Load VAE Index (NH)
<p align="center"><img src="../assets/nodes/NH_VAEIndex.svg" alt="Load VAE Index (NH) node" width="360"></p>
Loads one VAE, chosen from up to 64 slots.
**Use it when** you want to compare how different VAEs decode the same image, or swap VAEs without rewiring.
| Input | Type | Default | Description |
|---|---|---|---|
| `select_mode` | COMBO | `index` | How a slot is chosen: `index` or `boolean`. |
| `index` | INT | `1` | The slot to use in `index` mode. 1 is the first slot. Range 1 to 64. |
| `vae_count` | INT | `5` | How many slots are shown and used. Range 1 to 64. |
| `vae_1` … `vae_64` | COMBO | empty | Optional. The VAE file for each slot, for example `my_vae.safetensors`. |
| `enable_1` … `enable_64` | BOOLEAN | `false` | Optional. The on/off toggle of each slot, used in `boolean` mode. |
| Output | Type | Description |
|---|---|---|
| `vae` | VAE | The loaded VAE. Blocked when nothing is selected. |
| `filename` | STRING | The VAE file name as shown in the slot list. Empty when nothing is selected. |
| `index` | INT | The slot that was used, or `-1` when nothing is selected. |
**How it works**
- Like ComfyUI's own VAE loader, the node passes the metadata stored in the file to the VAE and checks the file as it loads. A file that does not hold a usable VAE stops the run at this node with an error, instead of failing later when the image is decoded. A VAE that fails the check is not kept.
- The loaded VAE is reused while ComfyUI still holds it, until you select another file (see [What stays in memory](#what-stays-in-memory)).
**Example — compare two VAEs on the same latent**
```text
Load VAE Index (NH) → VAE Decode → Preview Image
```
Connect `vae` to the `vae` input of `VAE Decode`, and choose one VAE per slot. Set the sampler's seed to fixed, run once with `index` 1 and once with `index` 2, then compare the two decoded images.
---
## Load Clip Index (NH)
<p align="center"><img src="../assets/nodes/NH_ClipIndex.svg" alt="Load Clip Index (NH) node" width="360"></p>
Loads one CLIP or text-encoder file, chosen from up to 64 slots, and sets which CLIP type it is loaded as.
**Use it when** you want to compare text encoders, or switch between model families that each need their own text encoder.
| Input | Type | Default | Description |
|---|---|---|---|
| `select_mode` | COMBO | `index` | How a slot is chosen: `index` or `boolean`. |
| `type` | COMBO | `stable_diffusion` | The CLIP type to load the file as. The list follows your ComfyUI version, for example `stable_diffusion`, `sd3`, `flux` or `wan`. |
| `index` | INT | `1` | The slot to use in `index` mode. 1 is the first slot. Range 1 to 64. |
| `clip_count` | INT | `5` | How many slots are shown and used. Range 1 to 64. |
| `clip_1` … `clip_64` | COMBO | empty | Optional. The text-encoder file for each slot, for example `my_encoder.safetensors`. |
| `enable_1` … `enable_64` | BOOLEAN | `false` | Optional. The on/off toggle of each slot, used in `boolean` mode. |
| Output | Type | Description |
|---|---|---|
| `clip` | CLIP | The loaded text encoder. Blocked when nothing is selected. |
| `filename` | STRING | The file name as shown in the slot list. Empty when nothing is selected. |
| `index` | INT | The slot that was used, or `-1` when nothing is selected. |
**How it works**
- Choose the `type` that matches the model family the file belongs to. A type name that your ComfyUI does not know falls back to `stable_diffusion`.
- The node loads one file per run. For model families that need two or more text-encoder files at once, use ComfyUI's own dual or triple CLIP loaders.
- The loaded CLIP is reused while ComfyUI still holds it (see [What stays in memory](#what-stays-in-memory)). Changing `type` loads it again.
**Example — pick the text encoder by hand**
```text
Load Clip Index (NH) → CLIP Text Encode → KSampler
```
Set `type` to the family of your model, choose an encoder in each slot, and change `index` to switch.
---
**See also:** [Batch & Lists](./batch-lists.md) for `Counter (NH)`, [Utils](./utils.md) for `Multi-Slider (INT)`, and [Logic](./logic.md) for `Value Match Index (NH)`.
[← Back to guide](./README.md)
-476
View File
@@ -1,476 +0,0 @@
[← Back to guide](./README.md)
# Logic
Logic nodes let a workflow make decisions. Compare values, combine true/false results, choose between inputs, send data down one of several paths, calculate simple formulas, or pick at random. `If/Else`, `Switch N`, `Random Choice` and `Any Switch` use lazy evaluation: ComfyUI runs only the branch that is chosen, so a sampler on an unchosen branch never executes. Find the nodes under **NH-Nodes → Logic** in the node menu.
**On this page**
- [Which switch do I need?](#which-switch-do-i-need) — how each switch treats the branch you did not choose
- [Compare (NH)](#compare-nh) — turn two values into `True` or `False`
- [Logic Gate (NH)](#logic-gate-nh) — combine true/false values with AND, OR, NOT, XOR, NAND, NOR
- [If/Else (NH)](#ifelse-nh) — pick one of two inputs by a condition
- [Switch N (NH)](#switch-n-nh) — pick one of up to 10 inputs by number
- [Any Switch (NH)](#any-switch-nh) — pick one of two inputs by a condition, same logic as If/Else
- [Any Branch Switch (NH)](#any-branch-switch-nh) — send one input to one of five outputs
- [Gate Switch (NH)](#gate-switch-nh) — let data through, or stop it and everything after it
- [Value Match Index (NH)](#value-match-index-nh) — turn text, such as a file name, into a number for a switch
- [Math Eval (NH)](#math-eval-nh) — calculate a formula with the variables `a` to `d`
- [Random Choice (NH)](#random-choice-nh) — pick one of up to six inputs at random, with weights
In the tables, `*` means any data type.
## Which switch do I need?
Two mechanisms keep unused work from running. With **lazy evaluation**, nodes that only feed an unchosen input never run, so a sampler there costs no time. With **blocking**, the unchosen output carries a block signal: every node after it is skipped, silently and without an error, including Save and Preview nodes.
| Node | Chooses by | Inputs → outputs | The side that is not chosen |
|---|---|---|---|
| If/Else, Any Switch | `True` / `False` | 2 → 1 | Never runs (lazy). |
| Switch N | Number 0 to 9 | up to 10 → 1 | Never runs (lazy). |
| Random Choice | Seed and weights | up to 6 → 1 | Never runs (lazy). |
| Any Branch Switch | Number 0 to 4 | 1 → 5 | The other outputs are blocked. |
| Gate Switch | `True` / `False` | 1 → 1 | The input never runs (lazy). When disabled, the output is blocked. |
> **Note:** Lazy evaluation skips only what nothing else needs. If a node also feeds something that does run, it still runs.
---
## Compare (NH)
<p align="center"><img src="../assets/nodes/NH_Compare.svg" alt="Compare (NH) node" width="360"></p>
Compares `a` with `b` and outputs `True` or `False`. Both values also pass through unchanged.
**Use it when** you need a condition for If/Else or Gate Switch, such as "is the width larger than 1024?" or "does the file name contain `portrait`?".
| Input | Type | Default | Description |
|---|---|---|---|
| `a` | `*` | — | Left value, any type. Connect a node; there is no widget. |
| `b` | `*` | — | Right value, any type. Connect a node. |
| `op` | COMBO | `is` | `is`, `not`, `>`, `<`, `>=`, `<=` or `in`. |
| `type_cast` *(optional)* | COMBO | `auto` | `auto`, `int`, `float` or `string`. `in` ignores it. |
| Output | Type | Description |
|---|---|---|
| `result` | BOOLEAN | `True` when the comparison holds. |
| `a_passthrough` | `*` | `a`, unchanged. |
| `b_passthrough` | `*` | `b`, unchanged. |
**How it works**
- `auto` reads both values as numbers when it can (`"10"` equals `10`). If either side is not a number, it compares both as text.
- `int` and `float` convert both sides first; `int` drops decimals (3.7 becomes 3). If a value cannot be converted, `result` is `False` and the console explains why.
- `string` always compares text, character by character.
- `in` is plain membership. If `b` is a list, tuple or set, `a` must be one of its items. If `b` is a dictionary, `a` must be one of its keys. Otherwise `str(a)` must appear inside `str(b)`, case-sensitive. A number matches its text (`7` matches `"7"`). There is no fuzzy matching, and an empty `a` is found in any text.
- If `a` or `b` is empty (`None`), `result` is `False`.
| `a` | `op` | `b` | `type_cast` | `result` | Why |
|---|---|---|---|---|---|
| `1920` | `>` | `1024` | `auto` | `True` | Numbers. |
| `"10"` | `>` | `"9"` | `auto` | `True` | Both read as numbers. |
| `"10"` | `>` | `"9"` | `string` | `False` | As text, `"1"` sorts before `"9"`. |
| `3.7` | `is` | `3` | `int` | `True` | `int` drops the decimals. |
| `3.7` | `is` | `3` | `auto` | `False` | 3.7 is not 3. |
| `"portrait"` | `in` | `"portrait_01.png"` | — | `True` | Substring. |
| `"PORTRAIT"` | `in` | `"portrait_01.png"` | — | `False` | Case-sensitive. |
| `13` | `in` | `"a13b"` | — | `True` | Substring. |
| `13` | `in` | `"1024x768 3"` | — | `False` | `13` is not written anywhere in it. |
| `7` | `in` | list `[1, 7]` | — | `True` | List item. |
**Example — run a step only for wide images**
```text
Get Image Size.width → Compare (NH).a (op: >)
Int (value 1024) → Compare (NH).b
Compare (NH).result → If/Else (NH).condition
```
> **Tip:** To compare with a fixed value, connect one of ComfyUI's `Int`, `Float` or `Text` primitive nodes to `a` or `b`.
---
## Logic Gate (NH)
<p align="center"><img src="../assets/nodes/NH_LogicGate.svg" alt="Logic Gate (NH) node" width="360"></p>
Combines two true/false values with AND, OR, NOT, XOR, NAND or NOR and outputs one true/false result.
**Use it when** several conditions decide together, such as "the image is wide enough AND quality mode is on".
| Input | Type | Default | Description |
|---|---|---|---|
| `a` | BOOLEAN | `False` | First value. |
| `op` | COMBO | `AND` | `AND`, `OR`, `NOT`, `XOR`, `NAND` or `NOR`. |
| `b` *(optional)* | BOOLEAN | `False` | Second value. `NOT` ignores it. |
| Output | Type | Description |
|---|---|---|
| `result` | BOOLEAN | The result of `op`. |
| `op` | `True` when… |
|---|---|
| `AND` | both are `True` |
| `OR` | at least one is `True` |
| `NOT` | `a` is `False` (`b` is ignored) |
| `XOR` | exactly one is `True` |
| `NAND` | not both are `True` (the opposite of AND) |
| `NOR` | both are `False` (the opposite of OR) |
**Truth table** (`T` = `True`, `F` = `False`)
| `a` | `b` | AND | OR | NOT a | XOR | NAND | NOR |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| F | F | F | F | T | F | T | T |
| F | T | F | T | T | T | T | F |
| T | F | F | T | F | T | T | F |
| T | T | T | T | F | F | F | F |
**Example — both conditions must pass**
```text
Compare (NH) "width > 1024" → Logic Gate (NH).a (op: AND)
Boolean Switch (NH) → Logic Gate (NH).b
Logic Gate (NH).result → Gate Switch (NH).enabled
```
- `OR`: run a face fix when a detector finds a face **or** you force it on with a `Boolean Switch (NH)`.
- `NOT`: send a `Boolean Switch (NH)` named `skip_upscale` through `NOT` into `enabled`, so turning it on switches the upscale branch off.
> **Tip:** `docs/logic_gate_diagram.html` is an illustrated version of these recipes. Download it and open it in a browser.
---
## If/Else (NH)
<p align="center"><img src="../assets/nodes/NH_IfElse.svg" alt="If/Else (NH) node" width="360"></p>
Outputs `if_true` when `condition` is `True` and `if_false` otherwise. Only the chosen branch is executed.
**Use it when** you want two versions of a result, for example with or without a refine pass, without paying for both.
| Input | Type | Default | Description |
|---|---|---|---|
| `condition` | BOOLEAN | `True` | Chooses the branch. |
| `if_true` | `*` | — | Lazy. Used when `condition` is `True`. |
| `if_false` | `*` | — | Lazy. Used when `condition` is `False`. |
| Output | Type | Description |
|---|---|---|
| `result` | `*` | The chosen input, unchanged. |
| `condition_out` | BOOLEAN | `condition`, repeated for chaining. |
**How it works**
- ComfyUI evaluates `condition` first, then asks only for the chosen branch. Nodes that feed the other branch never run, so a sampler there is skipped.
- Both inputs must be connected, but only one of them is executed.
**Example — refine only when needed**
```text
Compare (NH).result → If/Else (NH).condition
VAE Decode → If/Else (NH).if_false (original image)
second KSampler → VAE Decode → If/Else (NH).if_true (refined image; runs only when True)
If/Else (NH).result → Save Image
```
> **Tip:** Unlike Gate Switch, If/Else always produces an output, so `Save Image` still runs when the condition is `False`.
---
## Switch N (NH)
<p align="center"><img src="../assets/nodes/NH_SwitchN.svg" alt="Switch N (NH) node" width="360"></p>
Outputs the input whose slot number equals `index` (`input_0` to `input_9`). Only the chosen input is executed.
**Use it when** you cycle through several prompts, models or images, or when another node picks the branch by number.
| Input | Type | Default | Description |
|---|---|---|---|
| `index` | INT | `0` | Slot to use, 0 to 9. |
| `input_0` … `input_9` *(optional)* | `*` | — | Lazy. Connect only the slots you need; gaps are fine. |
| Output | Type | Description |
|---|---|---|
| `result` | `*` | The chosen input. |
| `count` | INT | Number of connected slots. |
**How it works**
- Only the chosen slot is executed. The nodes behind the other slots never run.
- If the chosen slot is not connected, or `index` is out of range (for example `-1` arriving from another node), the lowest connected slot is used and the console prints a note.
- With no connected slot, `result` is empty and the console prints a warning; `count` is `0`.
- `count` counts connected slots, not slot numbers: `input_0` and `input_5` give `2`. A slot whose upstream node returns nothing still counts as connected.
**Example — Counter → Switch N → KSampler**
```text
Counter (NH).current → Switch N (NH).index (Counter: start 0, step 1, max_value 2)
CLIP Text Encode A / B / C → Switch N (NH).input_0 / input_1 / input_2
Switch N (NH).result → KSampler.positive
```
Each queue advances the counter, so the next prompt is used, and only its CLIP Text Encode node runs. See [Counter (NH)](./batch-lists.md#counter-nh).
> **Tip:** Value Match Index returns 1-based numbers, so `value_1` selects `input_1`. Connect your default branch to `input_0`: a "no match" index of `-1` falls back to the lowest connected slot.
---
## Any Switch (NH)
<p align="center"><img src="../assets/nodes/NH_AnySwitchBoolean.svg" alt="Any Switch (NH) node" width="360"></p>
A true/false switch for any data type. It outputs `input_true` or `input_false` and runs only the chosen one.
**Use it when** you prefer these socket names to If/Else. The logic is identical.
| Input | Type | Default | Description |
|---|---|---|---|
| `condition` | BOOLEAN | `True` | Chooses the input. |
| `input_true` | `*` | — | Lazy. Used when `condition` is `True`. |
| `input_false` | `*` | — | Lazy. Used when `condition` is `False`. |
| Output | Type | Description |
|---|---|---|
| `result` | `*` | The chosen input, unchanged. |
| `condition` | BOOLEAN | `condition`, repeated. |
**Example — choose between two source images**
```text
Boolean Switch (NH).boolean → Any Switch (NH).condition
Load Image A / Load Image B → Any Switch (NH).input_true / input_false
```
Only the chosen `Load Image` node runs.
---
## Any Branch Switch (NH)
<p align="center"><img src="../assets/nodes/NH_AnySwitch.svg" alt="Any Branch Switch (NH) node" width="360"></p>
Sends one input to one of five outputs, `output 0` to `output 4`. Nodes connected to the other outputs are skipped.
**Use it when** one image or value must go through exactly one of up to five pipelines, such as five different styles or upscalers.
| Input | Type | Default | Description |
|---|---|---|---|
| `input` | `*` | — | The data to route. Always evaluated. |
| `index` | INT | `0` | Output that receives the data, 0 to 4. Other values are clamped to that range. |
| Output | Type | Description |
|---|---|---|
| `output 0` … `output 4` | `*` | `input` on the chosen output; blocked on the others. |
| `index` | INT | The index actually used, after clamping. |
**How it works**
- Unchosen outputs are blocked. A node that receives a blocked value is skipped silently, and so is everything after it.
- `input` is not lazy: the node feeding it always runs. Only what comes after the switch is skipped.
- A node with several inputs is skipped when any one of them is blocked.
**Example — route by file name**
```text
Value Match Index (NH).index → Any Branch Switch (NH).index
VAE Decode → Any Branch Switch (NH).input
output 0 / output 1 / … → one processing chain per output, each ending in its own Save Image
```
> **Tip:** `-1` (no match) is clamped to `0`, so `output 0` works as the default path.
---
## Gate Switch (NH)
<p align="center"><img src="../assets/nodes/NH_GateSwitch.svg" alt="Gate Switch (NH) node" width="360"></p>
Passes `input` through when `enabled` is `True`. When it is `False`, it stops the data and every node after it.
**Use it when** an optional stage, such as an extra upscale or an extra save, should run only when a condition is met.
| Input | Type | Default | Description |
|---|---|---|---|
| `input` | `*` | — | Lazy. The data to pass on. |
| `enabled` | BOOLEAN | `True` | `True` lets the data through; `False` blocks it. |
| Output | Type | Description |
|---|---|---|
| `output` | `*` | `input` when enabled; blocked when disabled. |
**How it works**
- Enabled: `input` is evaluated and passed on unchanged.
- Disabled: `input` is never requested, so the nodes that feed it do not run. The output is blocked, so the nodes after the gate are skipped without an error.
**Example — an optional extra output**
```text
VAE Decode → Save Image (always runs)
VAE Decode → Upscale Image → Gate Switch (NH).input
Boolean Switch (NH) → Gate Switch (NH).enabled
Gate Switch (NH).output → second Save Image (runs only when enabled)
```
> **Tip:** To keep saving the original image when the optional step is off, use If/Else instead: `if_false` carries the original.
---
## Value Match Index (NH)
<p align="center"><img src="../assets/nodes/NH_ValueMatchIndex.svg" alt="Value Match Index (NH) node" width="360"></p>
Looks for your configured values in the input and returns the 1-based position of the single value that matches.
**Use it when** a file name, label or prompt should decide which branch to take, for example "name contains `red`" selects branch 2.
| Input | Type | Default | Description |
|---|---|---|---|
| `input` | `*` | — | The value to test. It is converted to text. |
| `compare_mode` | COMBO | `in` | `in`: the configured value must appear inside the input. `is`: it must equal the input exactly. |
| `value_count` | INT | `5` | How many `value_N` fields are used, 1 to 64. |
| `no_match_index` | INT | `-1` | Returned when nothing matches (-9999 to 9999). |
| `multi_match_index` | INT | `-1` | Returned when more than one value matches (-9999 to 9999). |
| `value_1` … `value_64` *(optional)* | STRING | `""` | The values to look for. Empty fields are ignored. |
| Output | Type | Description |
|---|---|---|
| `index` | INT | Number of the matching value (1 for `value_1`), or `no_match_index` / `multi_match_index`. |
**How it works**
- Matching is on text and is case-sensitive. Only the first `value_count` fields count.
- Exactly one match returns its number. No match returns `no_match_index`. Two or more matches return `multi_match_index`.
- The node shows only `value_count` fields. If the layout looks stale after loading a workflow, press `update values`.
With `value_count` 3, `value_1` `blue`, `value_2` `red`, `value_3` `green`, `no_match_index` `-1` and `multi_match_index` `-2`:
| `input` | `compare_mode` | `index` | Why |
|---|---|---|---|
| `red_dress_03.png` | `in` | `2` | Only `red` is inside the name. |
| `blue_red_mix.png` | `in` | `-2` | `blue` and `red` both match. |
| `black.png` | `in` | `-1` | Nothing matches. |
| `red` | `is` | `2` | Exact match. |
| `red_dress` | `is` | `-1` | `is` needs the whole text to match. |
| `Red` | `is` | `-1` | Case-sensitive. |
**Example — pick a branch from a file name**
```text
Load Image Info (NH).file_name → Value Match Index (NH).input
Value Match Index (NH).index → Switch N (NH).index
```
> **Tip:** Numbers are matched as text, so with `in` the value `1` also matches `12` and `21`. Use `is` for exact numbers.
---
## Math Eval (NH)
<p align="center"><img src="../assets/nodes/NH_MathEval.svg" alt="Math Eval (NH) node" width="360"></p>
Calculates a math expression that can use up to four variables, `a` to `d`, and returns the result as FLOAT, INT and STRING.
**Use it when** you need to snap a size to a multiple of 64, scale a value, or build a number for another node.
| Input | Type | Default | Description |
|---|---|---|---|
| `expression` | STRING | `a + b` | The formula, on one line. |
| `a`, `b`, `c`, `d` *(optional)* | FLOAT | `0.0` | Variables for the formula (step 0.01). |
| `round_to` *(optional)* | INT | `-1` | Decimal places to round to, from `-1` to `10`. `-1` leaves the result unrounded. |
| Output | Type | Description |
|---|---|---|
| `result_float` | FLOAT | The result. |
| `result_int` | INT | The result with decimals cut off (toward zero). |
| `result_string` | STRING | The result as text. |
| Part | Allowed |
|---|---|
| Numbers | `3`, `0.5`, `1e3` |
| Variables | `a`, `b`, `c`, `d` (lowercase only) |
| Operators | `+` `-` `*` `/` `//` `%` `**`, unary `+` and `-`, parentheses |
| Functions | `min(a, b)`, `max(a, b)` (two or more values), `abs(x)`, `round(x)` or `round(x, digits)`, `sqrt(x)`, `floor(x)`, `ceil(x)`, `clamp(value, low, high)` |
**How it works**
- `/` is true division (10 / 4 = 2.5), `//` rounds down (10 // 4 = 2), `%` is the remainder and `**` is the power.
- Division by zero with `/`, `//` or `%` gives 0 for that part of the formula and prints a warning in the console. The rest still evaluates: `a + b / 0` gives `a`.
- An invalid expression stops the run with an error that names it, for example `Math Eval: Unknown variable 'e' (expression: 'e + 1')`. It never returns 0 silently.
- `result_int` is taken after `round_to` is applied. Rounding ties go to the even digit (2.5 becomes 2.0, 3.5 becomes 4.0).
| `expression` | Variables | `round_to` | `result_float` | `result_int` | `result_string` |
|---|---|---|---|---|---|
| `a + b * 2` | `a` 1, `b` 3 | -1 | `7.0` | `7` | `7.0` |
| `round(a / 64) * 64` | `a` 1000 | -1 | `1024.0` | `1024` | `1024.0` |
| `ceil(a / 8) * 8` | `a` 1001 | -1 | `1008.0` | `1008` | `1008.0` |
| `clamp(a, 512, 2048)` | `a` 100 | -1 | `512.0` | `512` | `512.0` |
| `a * 9 / 16` | `a` 1920 | -1 | `1080.0` | `1080` | `1080.0` |
| `a * b / 1000000` | `a` 1024, `b` 1536 | -1 | `1.572864` | `1` | `1.572864` |
| `a / 3` | `a` 10 | 2 | `3.33` | `3` | `3.33` |
| `a` | `a` -2.7 (linked) | -1 | `-2.7` | `-2` | `-2.7` |
| `a / b` | `a` 5, `b` 0 (warning in console) | -1 | `0.0` | `0` | `0.0` |
**Example — snap a width to a multiple of 64**
```text
Float (value 1000) → Math Eval (NH).a (expression: round(a / 64) * 64)
Math Eval (NH).result_int → Empty Latent Image.width
```
> **Note:** A number widget without a range of its own accepts typed values from 0 to 2048 in ComfyUI. For a negative or larger number, write it in the expression or connect a FLOAT node. ComfyUI does not connect an INT output to a FLOAT input such as `a`.
---
## Random Choice (NH)
<p align="center"><img src="../assets/nodes/NH_RandomChoice.svg" alt="Random Choice (NH) node" width="360"></p>
Picks one of up to six connected inputs at random. `weights` make some inputs more likely. Only the picked input is executed.
**Use it when** each queue should use a random style, prompt or image, with chosen probabilities, and the unpicked chains should cost nothing.
| Input | Type | Default | Description |
|---|---|---|---|
| `seed` | INT | `0` | 0 to 4294967295. The same seed gives the same pick. |
| `weights` | STRING | `1,1,1,1,1,1` | Comma-separated weights. Weight *N* belongs to `input_N`. |
| `input_0` … `input_5` *(optional)* | `*` | — | Lazy. Connect the ones you want in the draw. |
| Output | Type | Description |
|---|---|---|
| `result` | `*` | The picked input. |
| `picked_index` | INT | Slot number of the pick (0 to 5), or `-1` when nothing is connected. |
| `probabilities` | STRING | Chance of each connected input in slot order, for example `75.0%, 25.0%`. |
**How it works**
- Weights are positional: the first belongs to `input_0`, the second to `input_1`, and so on. Weights of unconnected inputs are ignored and the rest are rescaled to 100%.
- A missing or non-numeric weight counts as 1. A negative weight counts as 0. An input with weight 0 is never picked. Only the first six weights are read.
- If every connected input has weight 0, the connected input with the highest slot number is picked.
- An input counts as connected as soon as a link is attached, even when the node behind it returns nothing. It keeps its slot and its share of the weights.
- The seed is used as given, 0 included. The same seed, weights and connections always give the same pick.
| `weights` | Connected inputs | `probabilities` |
|---|---|---|
| `1,1,1,1,1,1` | all six | `16.7%, 16.7%, 16.7%, 16.7%, 16.7%, 16.7%` |
| `3,1` | `input_0`, `input_1` | `75.0%, 25.0%` |
| `1,1,10` | `input_1`, `input_2` | `9.1%, 90.9%` |
| `0,1,1` | `input_0`, `input_1`, `input_2` | `0.0%, 50.0%, 50.0%` |
| `2` | `input_0`, `input_1`, `input_2` | `50.0%, 25.0%, 25.0%` |
**Example — a random style with chosen odds**
```text
three LoRA chains → Random Choice (NH).input_0 / input_1 / input_2 (weights: 6,3,1)
Random Choice (NH).result → KSampler
```
> **Tip:** The `seed` widget has ComfyUI's `control after generate` setting. `randomize` gives a new pick each time you queue; `fixed` repeats the same pick.
---
**See also:** [Batch & Lists](./batch-lists.md) for `Counter (NH)`, which drives a switch one step per queue; [Loaders](./loaders.md) for the indexed loaders that Value Match Index can drive; [Utils](./utils.md) for `Boolean Switch (NH)`; and [Text](./text.md) for `String Operations (NH)`, which turns text tests into true/false values.
[← Back to guide](./README.md)
-188
View File
@@ -1,188 +0,0 @@
[← Back to guide](./README.md)
# Mask
Four small nodes for working with masks: grow or soften one, measure it, turn it into a box, and give one mask's box the proportions of another. Find them under **NH-Nodes → Mask**.
A `MASK` is a batch of one-channel images. `1.0` is inside the mask, `0.0` is outside, and values in between are soft edges. The nodes that measure or box a mask count a pixel as inside when it is above `0.5`.
**On this page**
- [Mask Morphology (NH)](#mask-morphology-nh) — grow, shrink, fill holes and soften a mask
- [Mask Properties (NH)](#mask-properties-nh) — size and corners of a mask's bounding box
- [NH Create Box Mask](#nh-create-box-mask) — replace a mask with its bounding rectangle
- [NH Mask Aspect Ratio Match](#nh-mask-aspect-ratio-match) — give one mask's box the proportions of another's
---
## Mask Morphology (NH)
<p align="center"><img src="../assets/nodes/NH_MaskAdvancedMorphology.svg" alt="Mask Morphology (NH) node" width="360"></p>
Grows or shrinks a mask along each axis, fills holes in it and softens its edge.
**Use it when** a segmentation mask is too tight for inpainting and needs a margin, when it has holes you want closed, or when its hard edge needs a soft fade.
| Input | Type | Default | Description |
|---|---|---|---|
| `mask` | MASK | — | The mask or mask batch. A single 2-D mask is accepted as a batch of one. |
| `horizontal_expand` | INT | `0` | Range -512 to 512. Positive grows the mask to the left and right, negative shrinks it. The value is the kernel length in pixels: each edge moves by half of it, rounded down. |
| `vertical_expand` | INT | `0` | Range -512 to 512. The same for the top and bottom edges. |
| `fill_holes` | BOOLEAN | `false` | Closes holes that the mask completely encloses. Pixels above `0.5` count as inside. |
| `blur_radius` | FLOAT | `0.0` | Range 0 to 100, step 0.1. Strength of a Gaussian blur in pixels. `0` leaves the edge as it is. |
| Output | Type | Description |
|---|---|---|
| `MASK` | MASK | The processed mask batch, same size as the input. |
**How it works**
- **Order:** horizontal, then vertical, then fill holes, then blur.
- **Kernel length:** an even length is rounded up to the next odd one, so the result stays centred. The table below shows what that means for each edge.
- **Soft masks stay soft.** Growing takes the brightest nearby value and shrinking the darkest, so a gradient is kept and nothing is forced to 0 or 1.
- **The image border never eats the mask.** A shape that touches the border keeps touching it when you shrink.
- Growing and shrinking run as PyTorch operations on the device that holds the mask (CPU or GPU), so large masks and long mask batches are handled efficiently. Filling holes and blurring run on the CPU, one mask at a time.
| `horizontal_expand` or `vertical_expand` | Each edge moves by |
|---|---|
| `0`, `1`, `-1` | 0 px, no change |
| `2`, `3` (or negative) | 1 px |
| `4`, `5` (or negative) | 2 px |
| `10`, `11` (or negative) | 5 px |
<p align="center"><img src="../assets/examples/mask-morphology.jpg" alt="A mask grown, shrunk, opened and closed with Mask Morphology" width="720"><br><em>Grow, shrink, and two nodes chained: shrink then grow (open), grow then shrink (close).</em></p>
**Example**
```text
Garment Segment (NH) → Mask Morphology (NH) → inpaint
```
With `horizontal_expand` `17`, `vertical_expand` `17`, `fill_holes` on and `blur_radius` `4`, every edge moves out by 8 px, holes close, and the edge fades softly.
> **Note:** `fill_holes` makes the mask hard first: every pixel becomes `0` or `1` before the blur. Leave it off if you need to keep an existing soft gradient.
> **Tip:** Growing uses a rectangular kernel, so corners stay square. Add a small `blur_radius` to soften them.
---
## Mask Properties (NH)
<p align="center"><img src="../assets/nodes/NH_MaskProperties.svg" alt="Mask Properties (NH) node" width="360"></p>
Measures the bounding box of a mask: its size and its corner coordinates.
**Use it when** you need numbers for the area a mask covers, for example to crop an image around the subject or to pass the box size to another node.
| Input | Type | Default | Description |
|---|---|---|---|
| `mask` | MASK | — | The mask to measure. Only the first mask of a batch is measured. Pixels above `0.5` count as inside. |
| Output | Type | Description |
|---|---|---|
| `width` | INT | Box width in pixels, `x2 - x1 + 1`. |
| `height` | INT | Box height in pixels, `y2 - y1 + 1`. |
| `x1` | INT | Left edge: the first column inside the mask. |
| `y1` | INT | Top edge: the first row inside the mask. |
| `x2` | INT | Right edge: the last column inside the mask. |
| `y2` | INT | Bottom edge: the last row inside the mask. |
| `bbox` | BBOX | The same box as one value, `(x1, y1, x2, y2)`. |
**How it works**
- Both ends are inclusive. A mask that covers columns 10 to 29 and rows 5 to 24 gives `x1` 10, `x2` 29, `y1` 5, `y2` 24, `width` 20 and `height` 20.
- An empty mask (nothing above `0.5`) gives `0` for every number and `(0, 0, 0, 0)` for `bbox`.
**Example**
```text
Garment Segment (NH) → Mask Properties (NH) → x1, y1, width, height → a crop node
```
---
## NH Create Box Mask
<p align="center"><img src="../assets/nodes/NH_MaskToBBox.svg" alt="NH Create Box Mask node" width="360"></p>
Replaces each mask with the filled rectangle that tightly surrounds it.
**Use it when** you want a rectangular inpainting area around a subject instead of its exact outline.
| Input | Type | Default | Description |
|---|---|---|---|
| `mask` | MASK | — | The mask or mask batch. Pixels above `0.5` count as inside. |
| Output | Type | Description |
|---|---|---|
| `box_mask` | MASK | One rectangle of `1.0` per input mask, covering its bounding box. An empty mask gives an empty (all `0.0`) mask. |
**How it works**
- Every mask of a batch is boxed separately.
- The box is tight. To add a margin, send `box_mask` through [Mask Morphology (NH)](#mask-morphology-nh) and grow it.
**Example**
```text
Garment Segment (NH) → NH Create Box Mask → Mask Morphology (NH, grow) → inpaint
```
---
## NH Mask Aspect Ratio Match
<p align="center"><img src="../assets/nodes/NH_MaskAspectRatioMatch.svg" alt="NH Mask Aspect Ratio Match node" width="360"></p>
Reshapes the bounding box of one mask so it has the same aspect ratio as the bounding box of another mask.
**Use it when** a box mask must follow the proportions of a reference shape, for example a square box that should match the proportions of a garment before you inpaint or crop.
| Input | Type | Default | Description |
|---|---|---|---|
| `target_ratio_mask` | MASK | — | The mask whose bounding box sets the aspect ratio to aim for. Only its box matters. |
| `mask_to_adjust` | MASK | — | The mask to reshape. |
| `mode` | COMBO | `stretch` | How to reach the ratio: `stretch`, `pad` or `crop`. |
| Output | Type | Description |
|---|---|---|
| `MASK` | MASK | The reshaped mask batch. Everything outside the new box is `0.0`. |
**Modes**
| Mode | What it does |
|---|---|
| `stretch` | Scales the content to fill the new box, without smoothing (nearest sampling). |
| `pad` | Keeps the content where it is and adds mask pixels (`1.0`) around it until the box has the ratio. |
| `crop` | Keeps only the middle part of the content so the box has the ratio. What stays does not move. |
**How it works**
- The node changes one side only, around the centre of the `mask_to_adjust` box: `stretch` and `pad` make the box longer on one axis, `crop` makes it shorter.
- A box that would leave the image slides back inside it.
- Every mask of the batch is processed. If `target_ratio_mask` has fewer masks, they repeat in turn.
- An empty `target_ratio_mask` counts as 1:1. An empty `mask_to_adjust` is returned unchanged.
For a target box of 100 × 50 (2:1) and a box to adjust of 40 × 40:
| `mode` | New box | Result |
|---|---|---|
| `stretch` | 80 × 40 | The 40 × 40 content is scaled to 80 × 40. |
| `pad` | 80 × 40 | The 40 × 40 content stays, with 20 px of mask added on the left and on the right. |
| `crop` | 40 × 20 | The middle 40 × 20 of the content is kept. |
<p align="center"><img src="../assets/examples/mask-aspect.jpg" alt="Mask Aspect Ratio Match in pad, crop and stretch mode" width="720"><br><em>The same mask matched to a target ratio with <code>pad</code>, <code>crop</code> and <code>stretch</code>.</em></p>
**Example**
```text
Garment Segment (NH) mask → target_ratio_mask ┐
├→ NH Mask Aspect Ratio Match (pad) → inpaint mask
box mask → mask_to_adjust ────────────────────┘
```
> **Tip:** Use `pad` when the area must stay fully covered, and `crop` when you want a smaller, exact-ratio core.
---
[← Back to guide](./README.md)

Some files were not shown because too many files have changed in this diff Show More