ComfyUI Extension: comfyui-ReferenceLatentPlus
Run ComfyUI workflows without the setup
No installs, no CUDA version roulette, no GPU sitting idle on your bill. Bring a workflow and run it in the browser.
A drop-in replacement for ComfyUI's stock ReferenceLatent node, with per-image strength, per-image timestep gating, per-image MediaPipe auto-masks, megapixel cap on attention cost, and 1–4 image inputs in a single node.
Looking for a different extension?
Custom Nodes (0)
README
Why I built this
The stock ReferenceLatent is a tiny wrapper — it just attaches a latent to the conditioning's reference_latents key and walks away. That's fine for the obvious case (drop in a ref, get an output), but the moment I tried to push it I hit walls:
- No way to dial strength up or down — it's binary on/off.
- No timestep gating — the ref is active for the whole denoising schedule whether I want it or not.
- The ref's whole image leaks into output: pose, framing, background, even crop. There's no "use the face only, ignore the rest" knob.
- Multi-ref means wiring multiple
LoadImage → VAE Encode → ReferenceLatentchains by hand. - Bigger refs = quadratic attention cost, with no easy way to cap it.
I built Reference Latent+ as the node I wished existed. Each image gets its own strength, its own timestep range, and its own auto-mask config. Slots reveal progressively as you connect them. MediaPipe-driven masks for face / body / clothes / background are built in. There's a global cap on ref size to keep attention compute under control.
I tested all of this against Flux2/Klein 9B (the model I'm building Fizgig for), but the underlying mechanism is generic — it works on every model in ComfyUI that consumes reference_latents.
What's new vs stock ReferenceLatent
- Per-image signed strength (
-5.0 … 50.0, default0.85). 1.0 = stock strength. 0 = bypass that image entirely. <0 = experimental "anti-reference" — model pulled away from this ref's features. - Per-image timestep range. Restrict any ref to a specific portion of the denoising schedule. Different refs can have different ranges; the node partitions the schedule so each timestep has exactly one set of active refs (no double-counting via overlapping conditioning).
- Per-image compositional masks with MediaPipe auto-detection. Tick
face/hair/body/clothes/backgroundto isolate just that part of the ref before encoding. Or wire your own MASK and it overrides. - Three mask-fill modes —
pixel_grey(in-distribution soft neutral),latent_zero(cleanest "ignore these tokens"),latent_noise(randomised attention shape). All three are novel; no existing ComfyUI node masks reference latents. - Megapixel cap with aspect-preserving downscale. Default 1 MP — keeps attention compute proportional to a 1024² generation regardless of how big your source image is. Never upscales.
- 1–4 image inputs in one node. No manual VAE Encode wiring. Slots reveal progressively as previous ones get connected; collapsible per-image config groups appear only for connected images.
- VAE input on the node — handles VAE encode internally so I don't have to chain it.
Quick start
- Drop the
comfyui-ReferenceLatentPlusfolder intoComfyUI/custom_nodes/. - (Optional, for the auto-mask feature)
pip install mediapipeinto your ComfyUI venv. The selfie_multiclass model auto-downloads on first use. - Restart ComfyUI. The node appears under
advanced/conditioning > Reference Latent+.
There's a ready-made example workflow in examples/klein-9b-reference-latent-plus.json — drag it into ComfyUI to see the wiring (Flux2/Klein 9B Distilled, 4-step). Adjust the model filenames in the loaders to match what you have installed.
Wire it up:
LoadImage ───► image_1 ┐
VAE ───► vae │
Prompt CLIP ──► conditioning ├──► Reference Latent+ ───► KSampler [positive]
│
(optional) LoadMask ──► mask_1
That's it. As you connect image_1, an image_2 slot appears. Connect that and image_3 shows up. And so on.
Inputs at a glance
Required
conditioning(CONDITIONING) — your prompt's CONDITIONING.vae(VAE) — for encoding the input images.image_1(IMAGE) — first reference (always required).max_megapixels(FLOAT, 0.1–4.0, default 1.0). Caps each ref by area. Aspect ratio preserved, never upscales. Lower = faster.mask_fill_mode(DROPDOWN). How masked-out regions are neutralised:pixel_grey(default) — replace with mid-grey before VAE encode. In-distribution.latent_zero— encode full image, zero the latent at masked positions. Cleanest "ignore" but off-distribution.latent_noise— encode full image, fill masked latent positions with deterministic Gaussian noise.
Optional reference inputs (progressive disclosure)
image_2/image_3/image_4— additional refs. Slots reveal as you connect the previous one.mask_1/mask_2/mask_3/mask_4— explicit per-image masks. Override the auto-mask config if wired.
Per-image collapsible groups (one per connected image)
strength(-5.0 to 50.0, default 0.85) — signed scaling of this image's ref latent.face/hair/body/clothes/background— MediaPipe-driven auto-mask regions.ignore_area(none / left / right / top / bottom) — exclude a side strip from the auto-mask.feather(0–200 px) — soften mask edges.grow(-200 to 200 px) — grow (>0) or shrink (<0) the mask area.start_percent/end_percent(0.0–1.0) — per-image timestep range. ComfyUI's percent:0.0= start of denoising (noisy),1.0= end (clean).
Mask precedence
For each image:
- If
mask_Nis wired → use it, ignore that image's auto-mask config. - Else if any region boolean is ticked → run MediaPipe, generate mask.
- Else → no mask, image used as-is (= what stock ReferenceLatent would do).
Empirical notes (Flux2/Klein 9B)
I built this against Klein and tested most of the defaults there:
strength = 0.85felt like the sweet spot for typical prompts. 1.0 was slightly too dominant; <0.5 too subtle.- For style/identity, gate the ref to the late timesteps — try
start_percent=0.6, end_percent=1.0. Klein's clean-end timesteps carry style/identity signal; the noisy-early timesteps drive composition. Restricting refs to the clean end lets your prompt's composition come through unconstrained.
On other models the mechanism still works but the sweet-spot values may differ — try strength=1.0 first, then dial.
Compatibility
The node attaches reference_latents to the conditioning dict. Models that read this key (and therefore work with this node):
- Flux family — Flux1, Flux2/Klein, LongCatImage
- Lumina2 / Z-Image
- Wan family — Wan21, Wan22, Wan21_HuMo, Wan22_Animate
- Hunyuan
- Qwen-Image
The optional reference_latents_method key is read by Flux-family models only. Others ignore it harmlessly.
Limitations / known gotchas
- MediaPipe is optional. If you don't have it installed, the auto-mask feature is silently a no-op — ticking a region does nothing. Explicit
mask_Nwiring still works. latent_noiseandlatent_zeroare off-distribution. No model was trained with masked-out reference latents; behaviour at high mask coverage is exploratory.pixel_greystays in-distribution and is the safe default.- Negative strength is experimental. Models weren't trained on negative refs; results vary. Useful for "generate something that does NOT look like this" but unpredictable.
- The masking-of-ref-latents idea is novel. No other ComfyUI node does it (I checked). That means there's no community-validated baseline for what works — test on your own use cases.
Support the project
If this node saves you wiring time or unlocks something you couldn't do with the stock node, consider supporting development:
<a href="https://buymeacoffee.com/lorasandlenses"><img src="https://img.shields.io/badge/Buy%20me%20a%20coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me A Coffee"></a>
I also build Fizgig — a focused trainer, profiler, repair workbench and explorer for Flux 2 Klein 9B LoRAs. If you train LoRAs on Klein, take a look.
Run ComfyUI workflows without the setup
No installs, no CUDA version roulette, no GPU sitting idle on your bill. Bring a workflow and run it in the browser.