๐ญ Regional LoRA QKV โ multi-character LoRAs in ONE image. We might have actually solved it.
Two (or more) trained character LoRAs, one frame, zero identity bleed โ at strength 1.0. If you've ever put two character LoRAs in the same Z-Image render and watched them melt into the same face, here's the part nobody told you: on fused-attention models, regional engines have been silently throwing away the layers that carry the identity. This pack fixes that โ and adds a router so you don't even have to draw the masks.
๐ฌ The actual problem (and the actual fix)
Z-Image / Lumina2 (NextDiT) fuses attention QKV into a single Linear(2560 โ 11520). Character LoRAs are trained on split projections โ separate to_q / to_k / to_v, each 2560 โ 3840. Those shapes don't match the fused module, so a typical regional engine's dimension gate skips them: it applies ~120 attention-out + MLP layers per character and drops the entire QKV stack โ where most of the likeness lives. That's why regional identity has felt weak, and why people crank strength to 1.3โ1.5 and still get mush.
This engine composes each split LoRA into the correct output slice of the fused module โ q into 0โ3840, k into 3840โ7680, v into 7680โ11520 โ as a mask-gated delta. The base forward is untouched, masking still gates tokens, and identity arrives at strength 1.0. With diagnostics on you can watch it happen: matched 120 full + 90 fused-QKV layers.
๐งญ Zero-touch placement (Auto Region)
Tier 1 โ box LLM: a local Ollama vision model (default
qwen3-vl:8b) reads your prompt and returns true 2D boxes per character โ big foreground face vs small figure down the hall, not just stripes.Tier 2 โ spatial language: no Ollama? "X on the left, Y on the right" is parsed deterministically, with depth handling and automatic axis choice.
Tier 3 โ mention order: equal feathered bands as the last resort. Feather is a fraction of band width, so seams look identical at every aspect ratio.
Trigger words drive everything: characters whose trigger is missing from the prompt are skipped automatically, so you can batch-queue a prompt file and each prompt selects its own cast. One character active โ full frame, no masking overhead.
๐ฆ What's in the zip
ComfyUI-Regional-LoRA-QKV/โ the node pack: Define Region (one per character), Auto Region (optional router), Apply to Model. No pip installs, no extra wheels โ plain Python on what ComfyUI already ships.workflows/ZImage_Regional_QKV.jsonโ a complete, grouped, titled two-character graph using core ComfyUI nodes only plus this pack.README.md(full technical writeup) +INSTALL.md.
๐ Complete install โ everything you need, start to finish
ComfyUI: a current build with native Z-Image / Lumina2 support (the workflow uses only core loaders/samplers:
UNETLoader,CLIPLoaderinlumina2mode,ModelSamplingAuraFlow,EmptySD3LatentImage,SamplerCustomAdvanced).The pack: unzip
ComfyUI-Regional-LoRA-QKVintoComfyUI/custom_nodes/, restart. Nodes appear under RIFT โ Regional LoRA QKV.Z-Image model โ
models/diffusion_models/. Any Z-Image Turbo build works; tested with fasciumzImageTurbo (lastMERGE) from Civitai.Text encoder โ
models/text_encoders/: the Qwen3-4B encoder from the official Z-Image release (fp16 or an fp8 build โ both fine). Load it withCLIPLoader, type lumina2 โ the workflow has this preset.VAE โ
models/vae/: the standard Z-Image 16-channel VAE; tested with UltraFlux VAE Improved v10.Your character LoRAs โ
models/loras/. Z-Image character LoRAs trained on split q/k/v (the common trainer output) are exactly what the fused composition is for; LoRAs that already match full layers compose too.Optional but recommended โ Ollama for box placement: install Ollama, then
ollama pull qwen3-vl:8b. The node callshttp://127.0.0.1:11434by default and yields VRAM back before sampling (keep_alive). Skip this entirely and Tier 2/3 take over โ nothing breaks.Open the bundled workflow, then touch exactly four things: Character A's LoRA + trigger word, Character B's LoRA + trigger word โ and write a prompt that mentions both triggers. Queue.
โ Verify it's working (first run)
Leave diagnostics ON. The console must print, per character:
matched ~120 full + <non-zero> fused-QKV layers
Fused QKV composition active: 30 fused module(s), equal 3-way split (out=11520 / slice=3840)fused-QKV: 0 on a Z-Image LoRA means your trainer used q/k/v key names the matcher doesn't know yet โ post the printed unresolved-target list in comments and the token rules get extended.
๐ Settings that matter (the workflow ships with all of these)
patch_size 2(MM-DiT: Z-Image / Lumina2 / Flux / Qwen-Image) ยทtext_token_position: beginningยทnormalize_overlapping_masks: ON(overlaps blend instead of double-stacking)strength 1.0โ the whole point; no more 1.3โ1.5 compensationfeather 0.15ยท sampling: euler / simple / 8 steps / shift 3.1 (the Turbo recipe)
โ More characters, manual masks, other models
More people: chain more Define nodes โ each
character_packoutput into the next node's input; the last one feeds Auto Region.Manual placement: delete Auto Region, wire the last Define straight into Apply, give each Define its own real mask. (The SolidMask in the workflow is just a placeholder โ Auto Region rewrites it per prompt.)
Other MM-DiT families (Flux, Qwen-Image): set
patch_sizeaccordingly; fused-QKV matching depends on that model's module naming.
โ ๏ธ Honest limitations
Slice composition assumes equal contiguous q/k/v (standard MHA โ true for Z-Image/Lumina2). GQA models are detected and logged, never mis-composed.
Masks are static per generation. Two characters is the tuned case; more works via chaining.
๐ Support
Everything here is free and stays free โ the format spec, the nodes, the workflows, the cartridges, the LoRAs. If it saved you a night of debugging (it contains several hundred of mine), tips keep the 5090 warm:
๐ Sponsor on GitHub
๐ Liberapay (recurring)
โก Or right here: the Civitai tip button on this page sends Buzz directly.