ComfyUI Node

LatentDetailer

Put a photoreal detail pass between the sampler and the VAE

By SparknightLLC·Created 8 months ago·Updated 4 months ago· 36
LatentDetailer
  • model
  • latent
  • positive
  • negative
  • LATENT
seed-1
sigmas0.40
luma_clarity0.00
boost_confidence0.00
bloom_strength0.00
bloom_threshold0.65
bloom_radius8
color_drift0.25
color_drift_radius16
cfg7.00
cfg_hf_boost5.00
cfg_lf_boost0.00
cfg_radius5
cfg_radius_flat0
cfg_radius_adaptivetrue
cfg_adapt_feather2
cfg_adapt_gamma2.00
detail_strength0.65
hf_radius4
mid_strength0.05
detail_chroma0.10
chromatic_aberration0.00
protect_lows0.90
soft_clip_detailtrue
soft_clip_detail_k2.20
soft_clip_cfgtrue
soft_clip_cfg_k2.00
noise_scale0.10
grain_luma0.00
noise_tail-1.00
noise_radius1
noise_flat_suppress1.00
hires_scale1.0
hires_strength0.75
hires_use_importance_masktrue
hires_mask_strength1.00
ignore_cond_timestep_rangetrue
debugfalse

You know the complaint: SDXL output looks clean, smooth, plastic. The classic fixes all cost something - cranking CFG gets you saturation and burn, a full hi-res fix is a second generation, and a generative upscaler like SeedVR2 or SUPIR rewrites your faces along the way. LatentDetailer is the cheap middle option: a detail pass that runs entirely in latent space, right before the VAE decode, at the price of one extra UNet evaluation.

Its workflow position tells you what it does: wire it between your KSampler's LATENT output and the VAE Decode, and it adjusts the latent before it ever becomes pixels. It's a "detailer" in the Impact-Pack sense of the word, but where FaceDetailer detects a region and re-generates it at higher resolution, this one never detects anything and never re-generates.

How it works

The node runs your UNet again on the finished latent - once per entry in sigmas - at a chosen point in the denoise schedule, and computes what the model thinks the clean image would be there. Same denoised-estimate math your sampler uses every step, just a one-off probe instead of a full walk.

sigmas is a comma-delimited string of normalized positions from 0.0 (start of denoising, noisiest) to 1.0 (end, cleanest). Each entry triggers one UNet evaluation and the estimates are averaged, so 0.40 (the default) means one probe, and 0.25,0.55 means two. Then the interesting part: the difference between that clean estimate and your latent is split into low and high frequency, and the high-frequency part is reinjected as detail - scaled by detail_strength, tamed in flat areas by protect_lows, separated by hf_radius.

There's also a CFG-delta branch, a nice piece of reuse: it amplifies den_pos - den_neg, the same signal classifier-free guidance is built on. cfg_hf_boost pushes that high-frequency guidance into the result. The node's own cfg input is just the base for that shaping - set it to match your sampler's CFG. On a distilled model at CFG 1, this branch quietly shuts off, which is expected, not a bug.

On top of that come the finishing touches, all optional: noise_scale/noise_radius for photographic micrograin, bloom_strength/bloom_threshold for halation, color_drift for granular color variation, and chromatic_aberration for lens-like fringing. Defaults are subtle by design - the author aimed at "real photography," not a dramatic filter.

The inputs that matter

You won't set forty knobs on your first run. Start here:

  • model, latent, positive, negative - you wire your checkpoint and conditioning in again. It's a MODEL node that runs the UNet, not a free post-filter, so it needs the same ingredients as your KSampler.
  • sigmas - leave at 0.40 until you understand the effect.
  • detail_strength - the master detail dial (default 0.65). This is the one you'll actually turn.
  • hires_scale / hires_strength - a cheap built-in hi-res trick: if >1, one UNet pass at the upscaled latent, then downsampled and blended back. Not a substitute for a real hi-res fix, but a way to feed the detail pass more resolution.
  • noise_scale - micrograin; the author pairs a little bloom with it for convincing rolloff.

The output is a single LATENT, fed straight into your VAE Decode (or another KSampler, if you're feeling ambitious).

Install

ComfyUI Manager, search "LatentDetailer" (it's on the Comfy Registry), or clone it:

cd ComfyUI/custom_nodes
git clone https://github.com/SparknightLLC/ComfyUI-SpectralVAEDetailer

Restart ComfyUI. That's it - no requirements.txt, no model downloads, no heavy dependencies; the only cost is what those extra UNet evaluations use.

Gotchas

  • Images turn "splotchy"? The author hit this too and shipped a preset_subtle example workflow. If the effect is too strong, load that preset instead of fighting the sliders.
  • Noisy flat backgrounds were the original worst case - that's what the cfg_radius_adaptive mode (with cfg_radius_flat and cfg_adapt_feather) was built to fix. It uses a cheap detail mask so flat regions get gentler CFG-detail treatment.
  • It's subtle. You're micro-adjusting a latent, not running a restoration model. Compare side by side or you'll think it did nothing.
  • Speed scales with sigmas and hires_scale - one sigma at 1x is fast, three sigmas at 2x is a second mini-sampler.

It's tuned for SDXL photoreal workflows, though the author says it's model-agnostic - ZIT and friends work, just budget time to re-tune the starting parameters. For killing the AI-look on portraits without a face-rewriting upscale pass, it earns its slot.


The alias, and a name change

If you also see SpectralVAEDetailer in your node menu, that's this same node under its old name - the pack renamed itself from ComfyUI-SpectralVAEDetailer to ComfyUI-LatentDetailer in v0.3.0 and kept the old name registered as an alias. Both map to the same class, same inputs, same output; use either. See the SpectralVAEDetailer page for the full rename story.

Categorylatent/postprocess

Inputs (42)

NameTypeDefaultDescription
seedINT-1-1–2147483647Random seed for grain/color drift. Use -1 for random each run.
sigmasSTRING0.40Comma-delimited list of normalized sigma positions (0..1). Each entry runs one UNet evaluation and the denoised estimates are averaged. Example: 0.25,0.55. 0=start (noisiest), 1=end (cleanest).
modelMODEL
latentLATENT
positiveCONDITIONING
negativeCONDITIONING
luma_clarityFLOAT0.000–1Mid-band local contrast on latent channel 0. 1.0 is intentionally strong.
boost_confidenceFLOAT0.000–1Boosts UNet-proposed micro detail ONLY where it appears confident; suppresses flats and strong edges.
bloom_strengthFLOAT0.000–1Approximate photographic bloom/halation by spreading bright highlights (luma only). Best paired with a little noise_scale (e.g. 0.02–0.08) for a more convincing photographic rolloff.
bloom_thresholdFLOAT0.650–1Only highlights above this luma threshold contribute to bloom.
bloom_radiusINT80–64Blur radius for bloom spread. Larger is softer but slower.
color_driftFLOAT0.250–1Noise-driven granular color drift (micro color distribution). Higher = stronger.
color_drift_radiusINT160–64Granular drift scale. 1..3 is typical; 16 is very broad/slow drift.
cfgFLOAT7.000–10Base CFG. This node applies additional HF/LF shaping when cfg > 1.
cfg_hf_boostFLOAT5.000–5How strongly to inject high-frequency CFG detail (from den_pos - den_neg).
cfg_lf_boostFLOAT0.000–2How strongly to inject low-frequency CFG contrast (usually keep low).
cfg_radiusINT50–64CFG split radius. In adaptive mode, this is the DETAIL radius.
cfg_radius_flatINT00–64CFG split radius used in flat/low-detail regions when adaptive mode is ON.
cfg_radius_adaptiveBOOLEANtrueIf ON, blends between cfg_radius_flat (flat) and cfg_radius (detail).
cfg_adapt_featherINT20–32Blur radius applied to the adaptive mask. Higher reduces halos but can soften detail reach.
cfg_adapt_gammaFLOAT2.000.5–3Mask curve. >1 shrinks 'detailed' regions (less spill/halo). <1 expands them.
detail_strengthFLOAT0.650–2Strength of injected high-frequency detail from denoised estimate.
hf_radiusINT40–64Detail split radius for base projection (larger = coarser separation).
mid_strengthFLOAT0.050–0.5Adds some mid/low component of the base projection (contrast/shape).
detail_chromaFLOAT0.100–2Scales how much the detail + CFG injections affect chroma latent channels (1..3). This is NOT chromatic aberration (no spatial shift).
chromatic_aberrationFLOAT0.000–1Lens-like chromatic aberration (spatial misregistration) applied to chroma latent channels (1..3) after all other adjustments. Very subtle effects are usually best (0.02–0.10).
protect_lowsFLOAT0.900–1Prevents HF detail from over-applying in low-frequency regions (reduces harshness).
soft_clip_detailBOOLEANtrueSoft-limits HF detail to reduce halos/zipper edges.
soft_clip_detail_kFLOAT2.200.5–8Detail soft-clip amount. Higher = weaker limiting.
soft_clip_cfgBOOLEANtrueSoft-limits HF CFG injection to reduce harsh edges and background speckle.
soft_clip_cfg_kFLOAT2.000.5–8CFG soft-clip amount. Higher = weaker limiting.
noise_scaleFLOAT0.100–0.5Micrograin intensity in latent space.
grain_lumaFLOAT0.000–1Luma-dependent grain: increases grain in shadows and reduces it in highlights. This primarily modulates the grain injected by noise_scale (and shaped by noise_radius).
noise_tailFLOAT-1.00-1–1Tail-heaviness of the grain noise distribution. 0 = Gaussian. + = heavier tails (more occasional strong specks / grit). - = lighter tails (smoother). RMS-normalized so noise_scale stays comparable.
noise_radiusINT10–16Grain correlation radius. 0=white, 1..3 often looks most photographic.
noise_flat_suppressFLOAT1.000–1Suppresses grain in flat regions (local smoothstep mode, always-on).
hires_scaleFLOAT1.01–4If >1, runs ONE UNet pass at upscaled latent resolution, then downsamples denoised estimates back to 1x before post-processing.
hires_strengthFLOAT0.750–1How much of the hires-derived correction to apply. 0=off, 1=full.
hires_use_importance_maskBOOLEANtrueIf ON, applies hires correction mostly where small/foreground-ish features are detected (cheap heuristic).
hires_mask_strengthFLOAT1.000–10 = uniform hires blend, 1 = fully importance-masked blend.
ignore_cond_timestep_rangeBOOLEANtrueIf ON, strips timestep limits from conditioning ranges (more consistent behavior).
debugBOOLEANfalsePrints diagnostics to console.

Outputs (1)

NameTypeDescription
LATENTLATENT