Nodes/ComfyUI-PuLID-Flux-Chroma/ChromapplyPulidFlux
ComfyUI Node

ChromapplyPulidFlux

The node that makes Chroma remember a face

By nazgut·Created about a year ago·Updated about a year ago· 0
ChromapplyPulidFlux
  • model
  • pulid_flux
  • eva_clip
  • face_analysis
  • image
  • attn_mask
  • prior_image
  • MODEL
weight1.00
start_at0.000
end_at1.000
fusion
fusion_weight_max1.0
fusion_weight_min0.0
train_step1000
use_graytrue

PuLID on Chroma used to just crash. Point the stock PuLID-Flux apply node at a Chroma checkpoint and you'd get 'Chroma' object has no attribute 'time_in' - a hard error that felt absurd, because Chroma is a Flux Schnell derivative and the adapter should have just worked. This node is the fix. ChromapplyPulidFlux is the apply step of nazgut/ComfyUI-PuLID-Flux-Chroma, a fork that teaches PuLID to patch its identity attention into Chroma's modified Flux transformer (and still does plain FLUX). One reference photo in, a face that survives across outfits, poses, and scenes - no LoRA, no training.

It's the payoff node in a four-node pipeline. The three loaders - ChromaPulidFluxModelLoader (PuLID weights), ChromaPulidFluxInsightFaceLoader (face detector + ArcFace embedder), and ChromaPulidFluxEvaClipLoader (the CLIP visual encoder) - each hand this node an object. You plug in a reference image, and the MODEL that comes out the bottom is your diffusion model with identity conditioning baked in. Wire that to a KSampler and you're done.

How it works

Under the hood it runs the same routine as the original balazik node: detect the largest face in your image, pull an InsightFace ArcFace embedding, crop and align the face, mask off the background with a BiSeNet face-parsing model, run the cleaned face through EVA-CLIP, concatenate the two feature vectors, and feed them into PuLID's ID encoder to produce the conditioning tokens. That's the "contrastive alignment" part - identity gets injected in a way that barely perturbs what the base model would otherwise draw.

The Chroma-specific magic is the last mile. It checks the loaded diffusion model for a distilled_guidance_layer; Chroma has one, standard FLUX doesn't. If found, it swaps in a Chroma-aware forward pass that builds Chroma's custom modulation vectors and handles the missing time_in attribute that broke every stock node. That's the whole reason this pack exists.

The inputs that actually matter

  • model, pulid_flux, eva_clip, face_analysis - the three loader outputs plus your base model. All required.
  • image - your reference face. Better quality = better likeness; the author's own tested sweet spot is around 1512x1512, not 4K+.
  • weight (-1 to 5, default 1) - the strength dial. For the v0.9.1 PuLID model, 0.9–1.0 is the band people land in; crank past that and the face starts to distort.
  • start_at / end_at (0 to 1) - the portion of the denoising schedule where PuLID is active. 0 to 1 means everywhere; tightening the window can fix late-stage face weirdness.
  • fusion - how multiple reference images combine: mean is the safe official default, max / max_token emphasize dominant features (and can go uncanny), train_weight runs a fast embedding self-training pass.
  • use_gray (default on) - the official gray preprocessing. Turn it off for RGB if gray costs you detail.

The only output is a patched MODEL, which is why you can chain several of these nodes - each one registers its own identity under a unique ID, so two faces at different sigma windows works fine.

Install and models

ComfyUI Manager works if you search the pack title "PuLID Flux Chroma" (people have genuinely struggled to find it by node name - search the repo, not the node). Or manually:

cd ComfyUI/custom_nodes
git clone https://github.com/nazgut/ComfyUI-PuLID-Flux-Chroma
cd ComfyUI-PuLID-Flux-Chroma
pip install -r requirements.txt

Then restart ComfyUI. You still need pulid_flux_v0.9.1.safetensors (1.06 GB) in ComfyUI/models/pulid/, and the InsightFace antelopev2 model pack hand-placed in ComfyUI/models/insightface/. EVA-CLIP downloads itself on first run. The author tests on an AMD RX 6900 XT with fp8 Chroma, and the node quietly converts float8 models to bfloat16 internally so they don't blow up.

Common issues

  • No face detected - it logs a warning and passes your model through unmodified, so you get a face-free image instead of a crash. Feed it a clearer, properly lit reference.
  • Face too strong / melting - drop weight toward 0.8, or narrow start_at/end_at so identity only lands in the middle of sampling.
  • Still getting time_in errors - that means you're actually running the older balazik node, not this pack. Make sure the Chroma fork is the one in your graph.

One honest caveat: PuLID gets the skeleton and skin tone right and stops there. For exact likeness, pair it with a pixel-level swap pass afterward. But for "same person, totally different scene" with zero training, this is the tool.

Categorypulid

Inputs (15)

NameTypeDefaultDescription
modelMODEL
pulid_fluxPULIDFLUX
eva_clipEVA_CLIP
face_analysisFACEANALYSIS
imageIMAGE
weightFLOAT1.00-1–5
start_atFLOAT0.0000–1
end_atFLOAT1.0000–1
fusionCOMBO7 options: mean, concat, max, norm_id, max_token, auto_weight, +1
fusion_weight_maxFLOAT1.00–20
fusion_weight_minFLOAT0.00–20
train_stepINT10000–20000
use_grayBOOLEANtrue
attn_maskoptMASK
prior_imageoptIMAGE

Outputs (1)

NameTypeDescription
MODELMODEL