ER EditGen
The edit-model workflow that used to be 18 nodes is now one — and it stops the generation loss
- latent
- image_1
- image_2
- image_3
- image_4
- image_5
- image_6
- image_7
- image_8
- mask
- images
- latent
Instruction-based editing is where image generation went in 2025-26: feed an edit model a picture and a sentence ("put it on a table", "make it night") and it returns the edited frame. The KB's Qwen-Image-Edit and FLUX Kontext panels tell the story - these models won on convenience, but they cost you in plumbing. A serious two-image edit needs reference latents on both the positive and negative conditioning, which means roughly eighteen nodes: three loaders, a scale-and-encode chain per reference, an empty latent, a scheduler, a guider, a sampler, all wired the way the official template wires them.
ER EditGen is those eighteen nodes, collapsed into one. It's the flagship node of the ER VFX Nodepack by Héctor Gallego (ER Academy), built for the edit models that consume reference latents - FLUX.2 klein, FLUX.1 Kontext, Qwen-Image-Edit and friends. Drop it in, pick your model, plug an image, write a prompt, run.
How it works under the hood
The model family is detected automatically - the node reads the loaded model's latent format and knows a FLUX.2-family model from a FLUX.1/Qwen one, which matters because klein needs its own empirical noise schedule (scheduler = auto picks it) and a different latent geometry. The three loaders are handled inside the node: unet_name, clip_name, clip_type, vae_name pick from your installed files, and they stay cached between runs, so changing a seed never re-reads gigabytes from disk. Everything a manual graph does is done here - scaling references to the working megapixels, VAE-encoding them, chaining the reference latents onto both the positive and the (zeroed-out) negative conditioning, sampling.
The distilled-model defaults are set for you: 4 steps, cfg 1.0 for klein, 20-28 steps if you switch to a base model. At cfg 1.0 ComfyUI skips the negative pass entirely, so it costs nothing - but the negative is built correctly with the same references, ready for when you raise cfg.
The two features that make it worth it
Latent chaining - no generation loss. Every decode-to-image/re-encode round through the VAE loses a little: color shifts, fine detail smears, and it compounds. So the node outputs a latent alongside images, and has a latent input you can reveal (⛓ button). Feed one node's latent into the next and you can chain edit after edit in latent space - pixels encode once from your source and decode once at the end. Each node still previews its own result.
The edit lock (preserve). This one solves the real problem the KB panels name: edit models re-emit the whole frame, so pixels you never asked to change drift on every round. preserve (auto/strong/off) fixes it by comparing the sampled latent against your source in latent space, detecting where the image genuinely changed, and grafting the original back everywhere else - bit-exact. The info tag shows the lock percentage ("lock 80%"). auto steps aside when the edit is global (a relighting, a full regrade), strong locks tighter.
The inputs a beginner actually sets
- text - what to generate or how to edit. image_1 appears first; connect it and
image_2shows up, and so on up to 8. The first reference sets the output size; the rest are material (a product to insert, a style, a character). - megapixels - working resolution (references scale to it). seed / steps / cfg as above.
- mask - connect one and it inpaints: white = regenerate, black = untouched. Key gotcha from the docs: in mask mode the base is deliberately not fed as a reference (the model would just reconstruct the original masked content), so your prompt must describe what the hole should become, not what's there.
What to know before you rely on it
The loaders read from your ComfyUI diffusion_models, text_encoders, and vae folders - you still need the actual weights (klein, a Qwen-3 text encoder, the right VAE) installed, and the node ships defaulted to klein's files when it detects them. It's a heavy node: edit models are multi-GB and the first load takes a minute.
Installing
ER EditGen is part of the ER VFX Nodepack. ComfyUI Manager → search "ER VFX Nodepack" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/esperandoelrender/ComfyUI-ER-VFX-Nodepack.git
Restart and find it under image/generation. No extra Python dependencies. If you previously installed the standalone er_editgen pack, delete it first.
If you do multi-round edit work, this is the pack's reason to exist - and the preserve lock alone is worth the install, because it turns "the thing kept drifting every round" into "only what I edited ever moved."
Inputs (27)
| Name | Type | Default | Description |
|---|---|---|---|
| unet_name | COMBO | Diffusion model. Leave empty to use the model input. | |
| clip_name | COMBO | Text encoder. Leave empty to use the clip input. | |
| clip_type | COMBO | flux2 | Text encoder family: flux2 for FLUX.2 klein. |
| vae_name | COMBO | VAE. Leave empty to use the vae input. | |
| text | STRING | What to generate or how to edit the reference images. | |
| seed | INT | 00–18446744073709550000 | — |
| steps | INT | 41–200 | 4 for distilled models (FLUX.2 klein distilled), 20-28 for base ones. |
| cfg | FLOAT | 1.00–30 | 1.0 for distilled models. Above 1.0 the negative pass is computed too (slower). |
| megapixels | FLOAT | 1.000.1–4 | Working resolution: references are scaled to this, and the output matches the first one. |
| denoise | FLOAT | 1.000.05–1 | 1.0 = generate from scratch. Below 1.0 it refines the connected latent instead (no VAE round-trip). |
| latentopt | LATENT | Result of another ER EditGen: used as a reference WITHOUT re-encoding it (no quality loss). | |
| image_1opt | IMAGE | — | |
| image_2opt | IMAGE | — | |
| image_3opt | IMAGE | — | |
| image_4opt | IMAGE | — | |
| image_5opt | IMAGE | — | |
| image_6opt | IMAGE | — | |
| image_7opt | IMAGE | — | |
| image_8opt | IMAGE | — | |
| maskopt | MASK | Inpaint mask: white = area to regenerate, black = untouched. Applies over image_1 (or the chained latent). | |
| lorasopt | STRING | [] | — |
| weight_dtypeopt | COMBO | default | 4 options: default, fp8_e4m3fn, fp8_e4m3fn_fast, fp8_e5m2 |
| sampler_nameopt | COMBO | euler | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 |
| scheduleropt | COMBO | auto | 10 options: auto, simple, sgm_uniform, karras, exponential, ddim_uniform, +4 |
| preserveopt | COMBO | auto | Edit lock: keeps un-edited areas bit-exact from the source latent/image. auto = detect the changed region and graft the rest back (skipped when the edit is global); strong = tighter detection; off = raw model output. |
| widthopt | INT | 00–16384 | 0 = same size as the first reference (or 1024 with no references). |
| heightopt | INT | 00–16384 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| latent | LATENT | — |