Boyo BBOX Spatial Editor (Flux 3 / MOSS)
Draw boxes on a canvas, get a prompt string out
- image
- prompt
- bbox_json
- width
- height
What it actually is
BoyoBBOX is a drawing tool disguised as a prompt node. You get a canvas inside the node, drag boxes over things, type a caption with <element_id> tags, and it hands back one STRING for your text encoder.
That's all it does - no conditioning, no attention patching, no model. It's a spatial prompt formatter, because newer models increasingly read placement out of the caption itself. Ideogram 4 made that mainstream with a JSON caption schema where boxes overlap and nest. BoyoBBOX is that idea in a much smaller package; the author files it under BoyoNodes/Flux3 and the docstring calls it a "Bounding Box Spatial Prompt Editor for Flux 3."
If you've been fighting attribute bleed with Conditioning (Set Area) and getting that collaged look with seams on the boundaries, this is a different lever: you're not telling the sampler where things go, you're telling the text encoder in coordinates and trusting the model trained on that.
How it works
The Python class is about sixty lines. Nearly all the work happens in web/js/boyo_bbox.js, which mounts a DOM canvas widget and serialises your drawing into the node's only required input, a STRING called bbox_data:
{"mode":"generate","width":1024,"height":1024,"caption":"a woman <woman_1> under a lamp <lamp_1>","elements":[{"id":"woman_1","bbox":[312,148,880,530],"desc":"woman in a coat"}]}
On queue, Python parses that, rebuilds the elements as {"id","bbox","desc"} rows, and returns prompt = f"{caption} {bbox_json}" - your caption, a space, then the box array as a literal JSON string. That's the trick, and it's also the limit: whether you get a sane image depends entirely on the checkpoint understanding the convention. The node assumes it; it can't enforce it.
Two details that bite people. Box order is [y1, x1, y2, x2], not [x1, y1, x2, y2] - the JS swaps axes when normalising to 0–1000 and the source comments call that BFL's convention. It matches Ideogram 4's schema too, so it probably isn't a bug, but check it before hand-editing bbox_data or piping bbox_json into another grounding node. And IS_CHANGED returns nan, so the node re-runs on every queue - deliberate, or ComfyUI would cache on identical inputs and you'd never see caption edits.
Inputs and outputs
bbox_data is the only required input, and you'll basically never type it; the panel owns it. Leave it at the {} default and you get an empty prompt, which is the number one way this node "does nothing."
image is optional and is the one worth wiring: connect one and the node takes width/height from the tensor and stashes a preview in ComfyUI's temp directory, which is what the panel's 📥 Load Image button fetches so you can draw over the actual reference. All four outputs are useful:
prompt(STRING) → your CLIP Text Encode prompt input. Caption plus boxes.bbox_json(STRING) → just the rows array, for logging or another node that wants boxes, not prose.width/height(INT) → Empty Latent Image, so the latent matches the canvas you drew on.
The toolbar covers the rest: aspect presets from 1:1 to 21:9, a 1K/2K/4K switch in Generate mode, and Edit mode, which derives dimensions from the connected image. Ctrl+click cycles stacked boxes, the only way to select one fully covered by another.
Installing it
The pack isn't reliably findable by name in Manager, so do it manually:
cd ComfyUI/custom_nodes
git clone https://github.com/DragonDiffusionbyBoyo/Boyonodes
Restart ComfyUI. That's all this node needs - it imports json, numpy, torch, PIL, folder_paths and aiohttp, which ComfyUI already has.
Don't blindly install the pack's requirements.txt. That file serves the other forty-odd nodes: bitsandbytes, funasr, librosa, descript-audio-codec, diffusers, and a hard gradio==5.44.1 pin that has no business in a ComfyUI environment. The README treats audio/TTS and Seed-VC deps as separate installs for exactly that reason. If you only want the box editor, install nothing.
Where people get burned
Empty prompt out. Default bbox_data is {} → no caption → empty string, and the model generates from nothing. Add a caption and one element before judging it.
Canvas looks wiped when you reopen the workflow. Panel state saves in the bbox_data widget, but the JS never reads it back into the canvas on load. Your JSON and the resulting prompt are intact; only the drawing surface looks blank. Check the widget before redrawing from scratch.
Load Image 404s. It serves a PNG from the temp dir that only exists after a run with an image connected. Queue once, then click.
The boxes don't do anything. Model problem, not a node problem: the output is only text, so a checkpoint that ignores the JSON just sees noise after your caption. This is aimed at box-in-caption models; on plain-prose ones, use masked conditioning nodes for regional control.
Set expectations accordingly: this is an obscure pack, mentioned in a couple of Reddit threads at most, usually in passing. Nobody is writing guides for the BBOX editor. When something looks off, read web/js/boyo_bbox.js - that's the real documentation.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| bbox_data | STRING | {} | — |
| imageopt | IMAGE | — | |
| width_inopt | INT | — | |
| height_inopt | INT | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| prompt | STRING | — |
| bbox_json | STRING | — |
| width | INT | — |
| height | INT | — |