MOSS-Image’s layout/bbox feature only changes the prompt. CreateBoundingBoxes turns the boxes into a layout JSON, but nothing scopes a LoRA to a region. I wanted a two-character scene where each character LoRA stays inside its own box and a style LoRA covers the whole image, so I built a workflow for it.
How it works
Pass 1: the stock MOSS-Image subgraph draws the whole scene from the layout prompt, with the style LoRA applied globally.
Pass 2: the area inside box 1 is re-sampled with character LoRA 1 and its own prompt, using a latent noise mask.
Pass 3: same for box 2 with LoRA 2.
Pass 4: repeat and so on..
Each pass only touches its own masked region, so the LoRAs can’t bleed into each other or into the background.
The part that makes it dynamic
A small custom node, moss_bboxes_to_masks.py, reads the bboxes output of CreateBoundingBoxes and builds the masks automatically. Drag a box or change the resolution and the masks follow, with no typing coordinates. It has:
box_index_1/box_index_2: which box feeds which LoRA passpadding: grow or shrink the box in pixelsfeather: soft mask edges to hide seamsan info output that lists the boxes it read, so you can check them
Why not hook LoRAs?
My first attempt used ComfyUI’s hook LoRAs (CreateHookLoraModelOnly + conditioning masks), which would let you do it in a single pass. On the int8-convrot checkpoint it crashes in the sampler with 'Linear' object has no attribute 'weight_scale'. Normal LoRA loaders work fine on that checkpoint, so the two-pass approach avoids the problem. I haven’t tested the hook version on the bf16 checkpoint.
Setup
Put
moss_bboxes_to_masks.pyinComfyUI/custom_nodes/and restart.Load the workflow JSON.
Pick your LoRAs, fill in the two character prompts, and draw your boxes in
CreateBoundingBoxes.Check that
box_index_1/box_index_2match your box order (index 0 is the first box in the node).
Tips
Put the style trigger word in the character prompts too, since the passes still run the style LoRA.
Don’t stack the turbo LoRA twice. The subgraph’s model output already includes it.
Passes 2 and 3 start at denoise ~0.5 to 0.6. Raise it for stronger character identity, lower it to keep the pass 1 composition.
A little
padding(20 to 40 px) plus somefeatherhelps with subjects that spill outside their box.
Limitations
It’s built for up to 5 characters. If you need less, just bypass some nodes, if you need more, you'll have to hook more from the custom node yourself.
I’m guessing at the format of the
bboxesoutput, so the node accepts several formats. It works on my setup (ComfyUI 0.42.5), but let me know if it can’t read your boxes.Character LoRAs need to be trained on MOSS-Image to apply properly.
Due to the nature of MOSS's bbox node, this only works with Nodes 2.0
Download: [workflow JSON] / [custom node .py]
extract the moss_bboxes_to_masks.py and drop the file itself into your custom nodes folder.
Feedback welcome, especially if you get it working with three or more characters.
