Ideogram 4 Regional LoRA
Two character LoRAs, one frame, without the faces averaging together
- model
- bboxes
- model_uncond
- model
- model_uncond
If you've ever loaded two character LoRAs into one Ideogram 4 image and watched both faces come out as the same smeared average of the two, this node is the fix. Ideogram 4's JSON prompt gives every element a bounding box, but those boxes are just text tokens to the model - it has no spatial handle to hang a per-region LoRA on. Load two character LoRAs normally and both deltas land in the weights globally, so everyone in the frame wears both identities at once. Ideogram 4 Regional LoRA applies each LoRA's delta only to the image tokens inside its own box, in a single forward pass, and leaves the base weights alone.
One scope note: this is for the local Ideogram 4 DiT - the ideogram4_*.safetensors weights, e.g. ideogram4_fp8_scaled - not the cloud API nodes. API users, wrong pack.
How it works
Ideogram 4 runs one packed [text | image] sequence where the image tokens form a row-major (gh, gw) grid. That layout is the trick: a bbox maps exactly onto a set of token positions, so the node can turn your drawn rectangle into a mask over actual tokens. At forward time it reads the sequence layout off the model wrapper's own arguments, then registers a forward hook on each target Linear that adds the LoRA's low-rank delta weighted per token:
out = base_out + w_token · B(A(x))
The delta lives in activation space (bf16), never baked into the fp8 weight, which keeps ComfyUI's own weight-patching and fp8 casting path untouched. The hooks are installed per forward and removed in a finally, so a clone stays cheap and nothing leaks between runs. Measured on ideogram4_fp8_scaled against a stock global LoRA, you get roughly 88% of the in-bbox strength with about 3× less off-target change; the residual is bake-vs-bypass on quantized weights, not a real difference.
The inputs that matter
You get up to 8 LoRA slots, each a trio of widgets: lora_N (pick the file, or leave at None to skip), strength_N, and region_index_N - which placed bbox that LoRA applies to. That last one is where people get burned - covered below.
After the slots sit the three tuning knobs:
feather_cells- softens every region edge in latent cells, 1 cell ≈ 16 px. Default 1; 0 is a hard edge.overlap_mode- what happens where two boxes intersect:normalizescales down to sum 1,sumstacks and can over-drive,first_winslets the earlier slot occlude.mask_adaln- includes the broadcastadaln_modulationdeltas, worth 19–26% of a face LoRA's effect. Defaults on; turning it off saves a ~150 MB/block transient tensor at 4k tokens.
Regions come from either the bboxes output of Ideogram 4 Prompt Builder KJ (with width/height wired in) or the caption prompt JSON string itself, which takes precedence. Ideogram 4 does CFG with two models, so patch the unconditional one too: wire it into model_uncond. Both model and model_uncond outputs feed a DualModelGuider. The demo workflow in examples/IDEOGRAM4_REGIONAL_LORA_demo.json (a face + hands pairing) mirrors a standard Ideogram 4 path but replaces the usual pair of throttled-to-0.2 global LoRA loaders with one of these nodes.
Install
Via ComfyUI Manager (search "Ideogram 4 Regional LoRA"), or the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/kat3ri/ComfyUI-ideogram4-regional-lora
# restart ComfyUI
No extra Python dependencies - the one requirement is a ComfyUI recent enough to include comfy/ldm/ideogram4/ (local Ideogram 4 support). If you're running the model, you already qualify.
Where people get burned
region_indexis not the prompt builder's numbering. It counts placed boxes in editor order, zero-based - the KJ builder's own preview tags boxes01,02one-based and counts unplaced elements too. Typing one of those numbers silently selects the wrong region. That mismatch is exactly what the pack's sibling node, Ideogram 4 Region Preview, exists to solve - run it and read the numbers off the image.- Don't also load these LoRAs in a Power Lora Loader. That applies them globally and the whole masking becomes moot.
- Leaving
model_uncondunwired is a choice, not a default. It keeps the uncond at base weights, which makes CFG pull each region back toward base identity - a legitimate A/B that amplifies the delta, but not what you want by accident. - Attention crosses the seam by design. Tokens in the bbox still exchange keys and values with the rest of the image at every layer, so the delta is concentrated in the box, never perfectly confined. The leakage is diffuse drift, not a boundary halo; feathering softens it but won't remove it.
- It fails closed, not wrong. If the token layout can't be resolved, the node skips to base weights rather than applying a character LoRA to the whole image. Symptom: your LoRA does nothing at all - the safe failure, and a useful diagnostic.
Inputs (33)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| lora_1 | COMBO | None | LoRA for region 1. Leave at 'None' to skip this slot. |
| strength_1 | FLOAT | 1.00-10–10 | — |
| region_index_1 | INT | 00–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_2 | COMBO | None | LoRA for region 2. Leave at 'None' to skip this slot. |
| strength_2 | FLOAT | 1.00-10–10 | — |
| region_index_2 | INT | 10–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_3 | COMBO | None | LoRA for region 3. Leave at 'None' to skip this slot. |
| strength_3 | FLOAT | 1.00-10–10 | — |
| region_index_3 | INT | 20–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_4 | COMBO | None | LoRA for region 4. Leave at 'None' to skip this slot. |
| strength_4 | FLOAT | 1.00-10–10 | — |
| region_index_4 | INT | 30–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_5 | COMBO | None | LoRA for region 5. Leave at 'None' to skip this slot. |
| strength_5 | FLOAT | 1.00-10–10 | — |
| region_index_5 | INT | 40–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_6 | COMBO | None | LoRA for region 6. Leave at 'None' to skip this slot. |
| strength_6 | FLOAT | 1.00-10–10 | — |
| region_index_6 | INT | 50–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_7 | COMBO | None | LoRA for region 7. Leave at 'None' to skip this slot. |
| strength_7 | FLOAT | 1.00-10–10 | — |
| region_index_7 | INT | 60–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| lora_8 | COMBO | None | LoRA for region 8. Leave at 'None' to skip this slot. |
| strength_8 | FLOAT | 1.00-10–10 | — |
| region_index_8 | INT | 70–63 | Which placed bbox this LoRA applies to. Run Ideogram 4 Region Preview to see the numbers. |
| feather_cells | FLOAT | 1.000–16 | Soften every region edge by this many latent cells (1 cell = 16 px). 0 = hard edge. |
| overlap_mode | COMBO | Where regions overlap: normalize (scale down to sum 1), sum (stack, can over-drive), first_wins (earlier slot occludes later ones). | |
| mask_adaln | BOOLEAN | true | Include the adaln_modulation deltas, broadcast per token. Worth 19-26% of a face LoRA's effect. Off saves a transient per-token modulation tensor (~150 MB/block at 4k tokens). |
| bboxesopt | BOUNDING_BOX | Pixel-space boxes from Ideogram 4 Prompt Builder KJ. Needs width/height wired too. | |
| widthopt | INT | 00–16384 | — |
| heightopt | INT | 00–16384 | — |
| promptopt | STRING | Alternative region source: the caption JSON itself (0-1000 bboxes). Takes precedence over `bboxes`. | |
| model_uncondopt | MODEL | Ideogram 4's unconditional model, patched identically. Recommended — CFG uses both. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |
| model_uncond | MODEL | — |