Angelo — click to refine
The click-to-edit sampler that replaces your whole fix-it chain
- model
- positive
- negative
- vae
- clip
- latent
- overrides
- image
- latent
- source_image
If you've ever generated something 95% right and then burned ten minutes fixing it - save the image, open MaskEditor, paint a mask, wire it back through a second KSampler, requeue, repeat for the next thing - AngeloRefine exists to make you stop doing that. It's a sampler with an interactive canvas bolted onto the front: generate the base image in Sampler Mode, flip to Edit Mode, then click, paint, or drag directly on the node's own preview to fix what's wrong. One node instead of a KSampler plus ADetailer plus MaskEditor plus an outpaint-pad chain, and every fix redraws immediately, in place.
The underlying idea isn't new - it's the same detect-mask-inpaint loop that made A1111's ADetailer beloved and that Impact Pack's FaceDetailer ported to ComfyUI: crop a struggling region, refine it at real resolution, composite back so everything else stays untouched. What's different is where the pieces live. ADetailer and FaceDetailer are separate detect → crop → sample → composite nodes you wire together; Angelo folds the mask, the crop-and-upscale (called Xtra-Fine here), and the composite into one sampler, driven by your mouse instead of a YOLO model. Same payoff - a 64-latent-unit face jumping to roughly 1000 units of working room - with no detector graph to assemble.
Two modes gate everything. Sampler Mode is Angelo acting like a plain KSampler off your Empty Latent - sampler_denoise, sampler_seed, and the seed-control widget live here. Flip Mode to Edit Mode and those grey out; instead you get denoise (per the node's own tooltip: 0.3 for a subtle touch-up, 0.6 for a real redo, 0.9+ to essentially regenerate the region), click_radius for how big a single click's refine area is, and feather_radius to soften the mask edge. inpainting_mode decides how a painted region gets treated: Refine partially denoises whatever's already there and works on any sampler-compatible checkpoint - SDXL, SD 1.5, FLUX 1, anything. Smart Inpaint and Smart Guided Inpaint zero the masked latent and inject reference_latents, which only an edit-trained model can use - FLUX 2 Klein 9B or Qwen-Image-Edit. That's the same reference-latent-plus-InpaintModelConditioning trick people wire by hand elsewhere to get true masked inpainting out of an edit model; Angelo just does it natively when you drag a rectangle or pick a location from a dropdown. Outpaint grows the canvas instead, with a review-before-commit step so a bad extension costs nothing.
Required wiring is unremarkable: model, positive, negative, vae. clip is optional but you'll want it connected - without it, the in-node Area Prompt box and both Smart modes are dead. latent is optional too; skip it and use Load Image instead if you're editing a real photo rather than something you generated. There's also an overrides slot that takes the paired Angelo - Overrides node, for driving steps/cfg/sampler/scheduler from elsewhere in your graph instead of the toolbar. Outputs are image, latent, and source_image - that last one is the original, pre-edit base, useful for wiring straight into a before/after compare node. Most of the remaining schema fields (click_x, stroke_points, rect_points, seg_polygon, and a pile of *_seq counters) aren't things you type - they're state the toolbar JavaScript writes when you click, paint, or drag. Ignore them and use the actual toolbar.
Installing it is a plain custom-node clone: cd ComfyUI/custom_nodes && git clone https://github.com/shootthesound/ComfyUI-Angelo, then restart. No extra Python dependencies for the core node, which is genuinely nice given how much it does. The one opt-in extra is Detect, which lets you type "the face" instead of clicking it - that needs Meta's SAM 3, which isn't on PyPI, so it ships as a separate installer (install_sam3_support.sh / .bat) you run with ComfyUI closed; the ~1GB weights pull down automatically the first time you use it. Skip it if you don't need "type a word, get a mask" - everything else in the node works without it.
Where people actually get stuck: pointing Smart Inpaint or Smart Guided Inpaint at a plain checkpoint instead of an edit model. A base Qwen-Image (not the Edit variant) has the reference-latent code path but was never trained for it, so you get color-distorted output rather than a clean error - regular Refine works on anything, the Smart modes specifically need Klein 9B or Qwen-Image-Edit. Second: ComfyUI's global latent-preview setting can render into the node mid-sample and squash the editing canvas down to nothing - a real, reported annoyance; the fix (disable_live_preview) lives on the companion Overrides node, not here. And go in knowing this is in-process state: undo history and cached refinements live in the running ComfyUI server, not the saved workflow JSON, so a restart clears the canvas back to nothing and you're loading the base image again.
Inputs (71)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| positive | CONDITIONING | — | |
| negative | CONDITIONING | — | |
| vae | VAE | — | |
| mode | COMBO | Sampler Mode | Sampler Mode: AngeloRefine acts like a KSampler — generates the base latent from the incoming (usually empty) latent. Toolbar and canvas clicks are inert. Edit Mode: click / paint / drag to refine or inpaint the cached base. Switching to Edit Mode auto-locks sampler_seed_control to 'fixed' so the base stays stable. |
| sampler_denoise | FLOAT | 1.000.05–1 | [Sampler Mode] Denoise level for the base generation. 1.0 = generate fully from noise (KSampler default). Lower = img2img-style from the incoming latent. |
| sampler_seed | INT | 00–18446744073709550000 | [Sampler Mode] Seed for the base generation. Controlled by sampler_seed_control after each run. |
| sampler_seed_control | COMBO | randomize | [Sampler Mode] After-generation seed behaviour. Defaults to randomize so each base generation gets a fresh seed. Auto-forced to 'fixed' (locked to the seed that produced the base) when you switch to Edit Mode so refine clicks stay stable. |
| seed | INT | 00–18446744073709550000 | [Edit Mode] Seed for the refine pass. Hidden — controlled by the Seed input on the toolbar. |
| seed_control | COMBO | randomize | [Edit Mode] After-click seed behaviour. Hidden — controlled by the Seed Ctrl dropdown on the toolbar. Defaults to randomize so each refine click produces a fresh variation rather than repeating the same result. |
| steps | INT | 41–100 | Match the model's expected step count. FLUX 2 Klein distilled = 4. |
| cfg | FLOAT | 1.00–30 | FLUX 2 Klein distilled uses CFG=1 (no negative). |
| 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 |
| denoise | FLOAT | 0.500.05–1 | How much noise to add back for the refinement. 0.3 = subtle touch-up, 0.6 = real redo, 0.9+ = essentially regenerate that region. |
| click_radius | INT | 968–1024 | Pixel-space radius of the refinement region. Updated automatically by the JS click widget. |
| feather_radius | INT | 240–256 | Pixel-space gaussian blur applied to the mask before sampling. Smooths the seam between the refined region and the preserved surroundings. Roughly half of click_radius is a good default. |
| click_x | INT | -1-1–16384 | — |
| click_y | INT | -1-1–16384 | — |
| click_seq | INT | 00–2147483647 | — |
| image_w | INT | 00–16384 | — |
| image_h | INT | 00–16384 | — |
| undo_seq | INT | 00–2147483647 | — |
| reset | BOOLEAN | false | Tick + re-queue to discard the cached refined latent and start over from the incoming latent. |
| auto_decode | BOOLEAN | true | (Deprecated — preview always decodes now.) |
| fine_upscaling | BOOLEAN | false | When ON, the painted region is cropped, bilinear-upscaled in latent space to hit min_megapixels, refined, downscaled, and composited back. Gives the model more effective resolution on small painted regions. Upscale capped at 8× linear internally. Set via the Fine Upscale toggle above the preview. |
| min_megapixels | FLOAT | 1.00.1–4 | Target megapixels for the refine pass when Fine Upscaling is on. Only used in that mode. Set via the MP input above the preview. |
| max_upscale | FLOAT | 8.01–16 | Hard cap on the linear upscale factor in Fine Upscaling. 8.0 was the original internal default. Lower values reduce smoothing artifacts from extreme upscales at the cost of less effective resolution gain. Set via the Max input above the preview. |
| resize_method | COMBO | lanczos | Pixel-space upscale method for Fine Upscale. lanczos is the default — sharpest detail recovery for natural images. bilinear is smooth (good for skin/faces); bicubic middle ground; nearest-exact preserves exact sample values; area/bislerp niche. |
| inpainting_mode | COMBO | Refine | How the painted region is treated. Refine — the painted region is partially denoised from the existing content. Best for refining what's already there (faces, hands, textures). Paint/click as normal. Smart Inpaint — adds NEW content where you drag a rectangle. Click+hold one corner, release at the opposite corner. Locks denoise=1.0, Fine Upscale=ON, Ctx Pad=0 (the right defaults for adding new subjects with an edit model — Klein 9B etc.). Reference_latents are auto-injected so the model's edit branch activates. Smart Guided Inpaint — no painting or boxes. Pick a location from the dropdown above the Area Prompt; it's prepended to your prompt (e.g. 'In the top left of the image, ...') and the edit model places the content there across the whole image. Locks denoise=1.0, Fine Upscale=OFF, Area Prompt=ON; press 'Generate Guided Edit' to run. Outpaint — extend the canvas. Pick a direction (arrows, or click near an edge of the preview), review the result, Accept to commit. Accepting installs the new canvas as a fresh session base — history resets. |
| guided_location | STRING | (none) | — |
| fine_context_pad | INT | 640–512 | [Fine Upscale] Pixel-space padding around the painted-shape bbox before cropping. Gives the model surrounding context (skin, hair, background) so a tight face mask at high denoise still produces a coherent face that matches its surroundings. The painted shape is unchanged — only the area the model SEES grows. Outside the painted shape, the surrounding pixels are preserved (not refined). Larger pad = more context + less effective resolution on the painted area (bump MP to compensate). |
| persistent_mask | BOOLEAN | false | When ON, the last mask used (click point or paint stroke) is held in the node. Pressing the standard ComfyUI Queue button re-runs that same mask + a fresh seed on the LATEST result, so each press builds further on that region — use it to gradually morph an area over several presses while the rest of the image stays unchanged. (To re-roll the same edit on the ORIGINAL image instead of building on it, use the Re-roll button.) Toggled via the Persistent Mask button above the preview. |
| paint_mode | BOOLEAN | false | When ON, hold + drag on the preview paints a freeform brush stroke (each dragged point is the centre of a circle of click_radius; the union is the refine mask). Release to submit. Single clicks in paint mode work as one-point strokes. When OFF, clicks behave as before (single-circle refine). |
| stroke_points | STRING | — | |
| rect_points | STRING | — | |
| area_prompt | BOOLEAN | false | When ON, refinements encode the Area Prompt text (typed in the box below the canvas) with the connected CLIP and use it instead of the main positive/negative — useful for reshaping a region with a different prompt (e.g. main prompt = wide shot, area prompt = "detailed face, photorealistic eyes"). The click-and-mask behaviour is unchanged; only the prompt differs. If CLIP isn't connected or the area text is empty, the main positive/negative are used. Forced ON in Smart Inpaint. |
| area_text_positive | STRING | — | |
| area_text_negative | STRING | — | |
| loaded_image | STRING | — | |
| loaded_image_seq | INT | 00–4294967295 | — |
| loaded_resize_mode | COMBO | keep | 2 options: keep, mp |
| loaded_target_mp | FLOAT | 1.50.1–8 | — |
| seg_polygon | STRING | — | |
| reroll_seq | INT | 00–2147483647 | — |
| seg_mask_png | STRING | — | |
| redo_seq | INT | 00–2147483647 | — |
| restore_mode | BOOLEAN | false | When ON, clicks and paint strokes restore the painted region back to the session base image (a feathered latent blend — no sampling, instant). Refine mode only. Toggled via the Restore button on the toolbar. |
| area_prompt_slots | STRING | — | |
| vary_seq | INT | 00–2147483647 | — |
| vary_pick | INT | -1-1–15 | — |
| vary_pick_seq | INT | 00–2147483647 | — |
| outpaint_seq | INT | 00–2147483647 | — |
| outpaint_dir | STRING | right | — |
| outpaint_amount | INT | 25616–2048 | Outpaint: how many pixels to extend the canvas by (snapped to /16). Set via the Amount input on the Outpaint row. |
| outpaint_overlap | INT | 640–512 | Outpaint: feathered band reaching this many pixels INTO the existing image, redrawn so the seam blends instead of butting. Set via the Overlap input on the Outpaint row. |
| outpaint_accept_seq | INT | 00–2147483647 | — |
| outpaint_protect | STRING | — | |
| outpaint_instruction_pos | COMBO | prepend | 2 options: prepend, append |
| refine_reference | BOOLEAN | false | Anchor refines to the current image (edit models). The strength box beside the toolbar button sets the blend. Toggled via the Reference button. |
| quick_refine_seq | INT | 00–2147483647 | — |
| reference_strength | FLOAT | 0.000–1 | How strongly the current image anchors a refine — a true blend between the anchored and free predictions. 0 = off, 1 = fully anchored. Set via the Ref box on the toolbar. |
| upscale_seq | INT | 00–2147483647 | — |
| quick_prompt_mode | COMBO | Identity + Quality | 4 options: Identity + Quality, Restore Photo, Identity + Colours, Use Area Prompt |
| shrink_seq | INT | 00–2147483647 | — |
| shrink_scale | FLOAT | 0.500.05–0.95 | — |
| quick_lite | BOOLEAN | false | — |
| remove_mode | BOOLEAN | false | When ON, clicks / paint / Detect masks REMOVE the painted object: the hole is filled with surrounding background, a removal pass reconstructs it, then a neutral refine cleans it up (edit models only). Refine mode only; toggled via the Remove button on the toolbar. |
| clipopt | CLIP | — | |
| latentopt | LATENT | — | |
| overridesopt | ANGELO_OVERRIDES | Optional. Wire from an 'Angelo — Overrides' node to drive steps / cfg / sampler / scheduler from your workflow instead of the toolbar — and/or to supply a dedicated GENERATION model (gen bundle): Sampler Mode generates the base with it, then the main model handles all edits. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| latent | LATENT | — |
| source_image | IMAGE | — |