Detail Sampler (Custom Advanced) [Not Working]
A Detailer With No Detector — and the Author Labels It [Not Working]
- noise
- guider
- sampler
- sigmas
- latent_image
- vae
- image
- mask
- latent
Every automatic detailer you've used has the same first step: a model finds the face. YOLO weights, SAM, a community segmentation checkpoint - detection is a separate job with its own download, its own licence headaches, and its own habit of masking a rock formation it decided was a person.
This node deletes that step. No detector, no SEGS, no weights - it watches the sampler's own intermediate steps, works out where the latent is starving for resolution, and re-renders those regions inside the same node. If you know Impact Pack's DetailerForEach, this is that loop with a statistics function where the YOLO used to be.
It's also, per its own author, not working - the registered display name literally ends in [Not Working]. Set expectations accordingly: lab toy, not a face-repair button.
How it actually works
Pass one is an ordinary generation. A callback reads the sampler's x0 at a couple of points but never writes, so the base image is exactly what a plain sampler would have produced - nothing is sacrificed to detection.
Then it scores those reads. Two maps get pooled down to a coarse grid: local high-frequency energy (x0 minus its own blur - the blur-and-difference trick behind unsharp masking) and residual, how much x0 is still moving between the last two reads. The score is HF × (1 - residual). The source is blunt about why: high frequency alone also selects detail the model is still changing, and low residual alone selects flat sky. You want structure that exists and has stopped moving.
That score map gets thresholded, split into 8-connected islands, speck-filtered, and ranked by mean score - not area, so one big mass can't hog every slot. Each survivor is cropped with context around it, upscaled, re-encoded, re-sampled for a burst of steps from the tail of your sigma schedule, decoded, scaled back, and composited with a feathered mask.
The knobs that matter
detect_at(0.65) - how far into the schedule the detail map is read. Too early and x0 is still noise; too late and everything has settled.mask_threshold(0.35) - the cutoff on the detail score. Lower makes larger islands that merge into one blob.detail_denoise(0.5) - the author's own framing: 0.3 refines, 0.7+ reinvents. Above 0.6, with no way to give the island its own prompt, you're rolling dice.detail_strength(1.0) - composite opacity. Set it to 0 for a free dry run: the node emits the mask, skips every detail pass, and hands you the base image untouched. Check where it's looking before paying for it.
max_regions (3) and detail_steps (12) are the cost dials - each island is a full extra sampling pass plus two VAE trips. Down the list, detail_scale (2.0) is how far each island is upscaled before its re-render, context_pad (64) is how much surrounding image travels with the crop, and preserve_context pins everything outside the island at every step instead of regenerating the crop and blending afterwards.
The six real inputs - noise, guider, sampler, sigmas, latent_image, vae - are exactly the sockets core's SamplerCustomAdvanced takes. If you don't already run that graph (RandomNoise → CFGGuider → KSamplerSelect → a scheduler), this node has nothing to plug into.
Outputs
image is the composited result, same size as the base - this is not an upscaler. mask is the union of the softened islands at pixel resolution - all zeros when nothing crossed the threshold, so it's the honest record of what the node chose to touch. latent is the base pass's latent, not a detailed one: the detail work happens in pixel space and never writes back, so don't chain it downstream expecting refinement.
Installing it
ComfyUI Manager, search WtlNodes (publisher writili), or:
cd ComfyUI/custom_nodes
git clone https://github.com/Scorpiosis0/ComfyUI-WtlNodes.git
Restart ComfyUI. That's the whole story: requirements are scipy, numpy, pillow - no model downloads, nothing to compile, no AGPL detector weights. The pack imports every submodule at startup, though, so one broken file takes the whole pack down; check the console for the failed import.
Where people get burned
Detection is purely spectral - it has no idea what a face is. It finds busy regions, which in practice is often foliage, fabric weave and hair rather than the thing you wanted fixed. And there's no second prompt input here - the pass inherits yours, so a mangled hand comes back sharper and still mangled.
Read the console - the node logs the detect step, how many islands it found, the upscale factor and the starting sigma. That log is your only feedback loop, and the README's node list doesn't mention this node at all; it's stale, the source is truth. Large islands crashing? Turn on tiled_vae, which forces tiled encode/decode from the start instead of spiking and recovering. Every island is also two more VAE round trips, and those are lossy - don't stack this behind three other detail passes.
The mechanism is genuinely clever and I'd love it to work. The author's own label says don't build on it yet.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| noise | NOISE | — | |
| guider | GUIDER | — | |
| sampler | SAMPLER | — | |
| sigmas | SIGMAS | — | |
| latent_image | LATENT | — | |
| vae | VAE | — | |
| detect_at | FLOAT | 0.650.1–1 | Point in the schedule the detail map is read from. The generation itself always runs to completion — this only decides when to look. |
| mask_threshold | FLOAT | 0.350.02–0.95 | Cutoff on the normalised detail score. Everything above it becomes mask; connected areas become one island each. Lower = larger islands that can merge. |
| detail_scale | FLOAT | 2.001–4 | Upscale applied to every island equally, in pixel space, before re-rendering. |
| detail_denoise | FLOAT | 0.500.05–1 | How much of each island is re-rendered, as a fraction of the schedule. The strength dial: 0.3 refines, 0.7+ reinvents. |
| detail_steps | INT | 121–50 | Steps per island. |
| detail_strength | FLOAT | 1.000–1 | Composite opacity of the detailed result. 0 = detector only: emits the mask, skips every detail pass, returns the base image untouched. |
| min_blob_size | INT | 488–512 | Islands smaller than this many pixels square are discarded as specks. |
| context_pad | INT | 640–512 | Surrounding pixels included in each crop. Too little and the crop loses the context it needs to stay consistent with the scene. |
| max_regions | INT | 31–8 | Islands are ranked by mean score; this many are kept. |
| preserve_context | BOOLEAN | true | Hold everything outside the island fixed during the detail pass (noise_mask inpainting) instead of regenerating the whole crop and blending after. The island is then rendered against the real surroundings at every step, so it fits what it is pasted into. Off = the previous behaviour, for A/B. |
| tiled_vae | BOOLEAN | false | Force tiled VAE encode/decode for the island crops. comfy already retries tiled after an OOM, but only after spiking first; this keeps the peak low from the start. Turn on if large islands crash. |
| feather | INT | 480–256 | Composite falloff in pixels, applied to the island shape. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| mask | MASK | — |
| latent | LATENT | — |