Inpaint Studio (ZFRNodes)
Paint a mask inside the node
- reference_images
- image
- log
Inpainting in ComfyUI normally means a five- or six-node chain - Load Image, Mask Editor, InpaintModelConditioning, a KSampler, a composite - and a prayer that the mask and the sampler actually line up. Inpaint Studio is the ZFRNodes take on that: load an image, paint a mask, and sample, all inside one node. It's a "mini Photoshop" that lives in the graph.
Worth a sentence of framing before you install it. The mask-based approach isn't the trendy one anymore - instruction-edit models like Flux 2 Klein and Qwen-Image-Edit will fix a sentence worth of changes from text alone. What a mask still owns is surgical control: pixels outside the mask stay bit-identical, and you get a denoise dial instead of a yes/no. If you're the kind of person who still prefers masks for exactly that reason, this node is squarely aimed at you.
How it works
You load an image right in the node (upload, drag-and-drop, or paste with Ctrl+V while it's selected), then right-click → open it in ComfyUI's built-in Mask Editor and paint the area you want regenerated. The mask gets embedded in the PNG's alpha channel, and the node reads it back out. Leave the mask empty and it warns and returns the original unchanged - a genuinely useful safeguard against accidentally running inpaint with nothing painted.
From there the settings are grouped into tabs instead of one scrolling widget list. The Inpaint tab is where the interesting stuff lives: grow_mask (default 6, dilate/erode the edges), feather_mask (soften them), noise_mask, differential_diffusion (smoother blending at the mask boundary), and composite_back (default on - pastes the result back onto the untouched original, so everything outside the mask stays pixel-identical). The Model tab holds the loaders and an optional LoRA; Generation has the sampler controls; Output handles saving to disk.
The standout feature is use_references. Turn it on and connect any IMAGE to reference_images, and the masked area can pull content from that reference via the same Flux2 ReferenceLatent mechanism the rest of the pack uses - mask a bag and write "add the logo shown in image 1 to the bag", and it transfers the logo in. With references off, the masked area is repainted purely from the text prompt - "change hair color to red", mask the hair, done.
The inputs that matter
image- load it here, don't wire a Load Image node.prompt+trigger_words- what should appear in the masked area.use_references- toggle for pulling content fromreference_imagesinstead of prompt-only.denoise- the dial that decides how much of the mask gets regenerated; 1.0 (the default) is a full rewrite of the masked region.composite_back- keep this on unless you want the whole frame re-sampled.
Outputs: image (the inpainted result) and log.
Install
Standard ZFRNodes install - search ComfyUI-ZFRNodes in ComfyUI Manager, or:
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/zfrsgtcu/ComfyUI-ZFRNodes.git
Dependencies are just numpy, torch, and Pillow - already present in any ComfyUI. One gotcha specific to this node: the tabbed UI is added by a frontend script, so a full ComfyUI restart is required after installing or updating; a browser refresh will leave the node looking broken.
Common issues
- It returned the original image - that's the empty-mask safeguard doing its job; paint something and re-run.
- Reference mode does nothing -
use_referencesmust be on and the model must supportReferenceLatent; the pack is tested on flux-2-klein with a Qwen text encoder. - Seams at the mask edge - this is the classic mask complaint, not a node bug. Raise
grow_maska little and nudgefeather_maskup;differential_diffusionexists specifically for this. - Seed mode is
randomorfixedonly - noincrementhere, so if you want a controlled series of variations you set seeds yourself.
Inputs (27)
| Name | Type | Default | Description |
|---|---|---|---|
| image | COMBO | 1 options: example.png | |
| prompt | STRING | — | |
| trigger_words | STRING | — | |
| use_references | BOOLEAN | true | — |
| unet_name | COMBO | 0 options: | |
| vae_name | COMBO | 0 options: | |
| clip_name | COMBO | 0 options: | |
| clip_type | COMBO | flux2 | 28 options: stable_diffusion, stable_cascade, sd3, stable_audio, mochi, ltxv, +22 |
| lora_name | COMBO | 1 options: None | |
| lora_strength | FLOAT | 1.00-10–10 | — |
| denoise | FLOAT | 1.000–1 | — |
| grow_mask | INT | 6-64–256 | — |
| feather_mask | INT | 00–256 | — |
| noise_mask | BOOLEAN | true | — |
| differential_diffusion | BOOLEAN | false | — |
| composite_back | BOOLEAN | true | — |
| steps | INT | 201–200 | — |
| cfg | FLOAT | 1.00–30 | — |
| guidance | FLOAT | 3.50–100 | — |
| sampler_name | COMBO | euler | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 |
| scheduler | COMBO | simple | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 |
| seed | INT | 00–18446744073709550000 | — |
| seed_mode | COMBO | random | 2 options: random, fixed |
| save_to_disk | BOOLEAN | false | — |
| output_subdir | STRING | inpaint_studio | — |
| filename_prefix | STRING | inpaint | — |
| reference_imagesopt | IMAGE | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| log | STRING | — |