Nodes/ComfyUI-EditUtils/EditUtils: Flux3Klein Config Preparer lrzjason
ComfyUI Node

EditUtils: Flux3Klein Config Preparer lrzjason

The Switchboard Every FLUX.3 Reference Passes Through Before Sampling

By lrzjason·Created 9 months ago·Updated 3 days ago· 256
EditUtils: Flux3Klein Config Preparer lrzjason
  • image
  • configs
  • mask
  • configs
  • config
◄to_reftrue►
◄ref_main_imagetrue►
◄ref_longest_edge1024►
◄ref_croppad►
◄ref_upscalelanczos►
◄pad_modecolor►
◄pad_colorblack►
◄pad_color_rgb-►
◄pad_noise0.00►
◄ref_resize_modelongest_edge►
◄rope_x_offset0►
◄rope_y_offset0►

A single-image edit graph is easy to hold in your head. Three reference images are not, because each one wants its own resolution, its own crop treatment and its own pad colour, and by the time you've duplicated the encoder four times you've forgotten which one is the main image.

EditUtils solves that with a config chain, and Flux3KleinConfigPreparer_EditUtils is the per-image link in it. One node per image. It doesn't encode anything - it packages "here's an image, here's how to prepare it" into a dict, and the encoder consumes the whole chain later.

What it produces

Two outputs, and the difference matters. configs is the accumulated chain: whatever came in on the configs input plus this node's own entry appended. config is just this image's entry on its own. Wire configs onward to the next preparer or into the encoder; wire config into a Flux3KleinBBox_EditUtils if this particular image needs an element table attached to it.

The chain survives a downstream deepcopy because each entry gets a stable config_id stamped on it, which is what lets a bbox node further along find and replace the right entry instead of duplicating your image.

The settings you'll actually change

image is the only required input. Then:

to_ref adds the image to the reference latents, ref_main_image marks it as the main image whose latent becomes the sampling start latent and whose pixels come back out as main_image. Exactly one image in a chain should be the main one; the rest are plain references.

ref_longest_edge (1024 by default) is the reference's own token-grid size. The example graph pushes it to 1536 for a 1536-ish edit. Unlike FLUX.2 klein, FLUX.3 references keep individual resolutions - each gets its own token grid and its own position id - so this sizes that reference and nothing else.

ref_crop takes pad, center or disabled. pad is the one you want: it keeps the source aspect ratio inside a latent grid aligned to 16 pixels (the FLUX.2 packed VAE's token size) and is recovered after decode by CropWithPadInfo_EditUtils. A reference is only ever grown onto that grid, never cropped below its content.

ref_upscale (lanczos/bicubic/area) and ref_resize_mode (longest_edge scales so the longest side hits your number; area scales so total pixels equal its square) are the fine controls. mask is optional and self-checking: if its dimensions don't match the image, the node prints a warning and skips it rather than misaligning anything.

Padding, which is more interesting than it sounds

pad_mode and friends decide what fills the padded strip: color (solid), edge (replicate the outermost row), mirror (reflect), or border_mean (mean of the nearest 8 pixels per side). pad_color picks red/green/blue/white/black/custom - black is the FLUX.3 default - and pad_color_rgb overrides it with a 6-digit hex, # optional. Anything that isn't a valid hex (-, r,g,b, a plain number) is silently ignored, so leave it at - unless you mean it.

pad_noise adds Gaussian jitter to the pad area only, never the image content. 0.02–0.05 is the suggested range with solid colours. The reason all this exists is model-family-specific and worth internalising: Qwen paths were trained with black pads, so black padding tends to get amplified into big black edges during generation, which is why the Qwen configs default to white. FLUX.3 defaults to black because that's what it expects. Don't "unify" your graphs across model families on this setting.

The two dead knobs, on purpose

rope_x_offset and rope_y_offset are accepted and do absolutely nothing. FLUX.3 derives reference position ids internally - references are told apart on the l axis with negative coordinates - and the EditUtils rope-offset patch is a FLUX.2 MMDiT forward rewrite that doesn't apply to this architecture. The tools' own tooltips say so. If you're porting a Qwen-Image 2.1 graph where these did something, that's why your regional control stopped working.

There's also no to_vl here, unlike the Flux2 and Qwen preparers. FLUX.3's text encoder is text-only - references are pure VAE latents on their own token mode - so there's no vision tower to feed.

Wiring

LoadImage ──► Flux3KleinConfigPreparer ─┬─ configs ─────────────────┐
                                        └─ config ──► Flux3KleinBBox┴─► configs ──► EditTextEncode
LoadImage ──────────────────────────────────────────── image ────────┘

For multiple references, chain preparers: the first one's configs goes into the second one's configs input, and so on. Getting one reference and not the others is almost always a missing configs link in the middle of the chain.

Install

Manager → search ComfyUI-EditUtils → install → restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/lrzjason/ComfyUI-EditUtils

No pip dependencies. You'll need a ComfyUI build with native FLUX.3 support, plus qwen3vl_4b_fp8_scaled.safetensors loaded through CLIPLoader with type flux3 and flux2-vae.safetensors - the CLIP type is the one people get wrong, and a mismatch fails in ways that look like a broken model.

Categoryadvanced/conditioning

Inputs (15)

NameTypeDefaultDescription
imageIMAGE—
configsoptLISTConfigs list
to_refoptBOOLEANtrueAdd image to reference latent
ref_main_imageoptBOOLEANtrueSet image as main image which would return the latent as output.
ref_longest_edgeoptINT102416–4096Longest edge of this reference's latent grid
ref_cropoptCOMBOpadCrop method for reference image
ref_upscaleoptCOMBOlanczosUpscale method for reference image
pad_modeoptCOMBOcolorHow to fill the padding area when ref_crop == pad. color = solid pad_color, edge = replicate edge pixels, mirror = reflect content, border_mean = fill with the mean of the nearest edge pixels
pad_coloroptCOMBOblackPad fill color when pad_mode == color: red / green / blue / white / black / custom
pad_color_rgboptSTRING-Optional override: 6-digit hex color, with or without '#' (e.g. FF0000 or #FF0000). When valid it overrides pad_color. Anything else ("-", wrong length, non-hex, numbers, "r,g,b") is ignored
pad_noiseoptFLOAT0.000–0.2Gaussian jitter (std) added to the pad area to avoid perfectly flat regions; 0.02-0.05 recommended with solid colors
maskoptMASK—
ref_resize_modeoptCOMBOlongest_edgelongest_edge: scale so the longest dimension equals ref_longest_edge. area: scale so total pixels equals ref_longest_edge squared.
rope_x_offsetoptINT00–4096Accepted for graph compatibility. FLUX.3 derives reference position ids internally, so this has no effect.
rope_y_offsetoptINT00–4096Accepted for graph compatibility. FLUX.3 derives reference position ids internally, so this has no effect.

Outputs (2)

NameTypeDescription
configsLIST—
configANY—