FLUX.3 Prompt Builder KJ
FLUX.3 Wants a Box Table, Not a Paragraph — Draw It Instead
- references
- image
- bboxes
- prompt
- preview
- bboxes
- width
- height
- upsampler_input
Most "where do I put things" prompting is a negotiation with a language model through adjectives. FLUX.3 short-circuits that: it reads layout boxes as part of the prompt, so composition stops being a suggestion and becomes data. The catch: the data is a JSON table in a specific coordinate order, and nobody wants to hand-write [y_min, x_min, y_max, x_max]. So this node hands you a canvas.
What it is
FLUX.3 Prompt Builder KJ is a visual layout editor in Kijai's KJNodes pack. You draw rectangles on a canvas, give each one an id and a description, cite the id as <id> in your prompt text, and the node appends the whole thing as a box table on FLUX.3's 0–1000 grid. It landed in the pack on 2026-10-15 and is flagged experimental, so expect widgets to move.
Some context: FLUX 3 is BFL's July 2026 multimodal turn, gated early access with the open Dev backbone promised later in the year - the moment those weights are in your models folder, this is the node you want in front of your prompt. The canvas isn't new either: it's the one Kijai built for Ideogram 4's JSON captions.
How it works
The format FLUX.3 reads is your prompt text, one space, then a JSON list of rows. Without references each row is {"id", "bbox", "desc"}. With references connected it becomes {"id", "from", "src_bbox", "tgt_bbox", "desc"} - from names the source image, and the two boxes say where the object sits in the reference and where it lands in the output. So a finished caption looks like:
A red balloon tied to a stone bench, overcast sky <obj_1>. [{"id": "obj_1", "bbox": [120, 340, 610, 520], "desc": "red balloon"}]
Boxes sharing one id across canvases collapse into one row: on a reference canvas it's the src_bbox, on the output canvas the tgt_bbox. A box only on a reference means removed; only on the output means new. The toolbar's view selector switches canvases, and the selected box follows you across - that's how you place something you traced on ref_1.
The inputs and outputs that matter
In practice you touch three things. width and height set the canvas aspect - multiples of 16, and they should match what you're actually going to generate, because the boxes are normalized to the canvas you drew on. prompt is your text with the <id> citations. references is an autogrow set of ref_1 through ref_10 in the order the model receives them - ref_1 becomes ref_image_0 in the table, so the order is load-bearing.
The optional ones are worth knowing. import_caption pulls an existing caption back into the editor; import_mode decides whether it does that only when empty (seeds the editor once, then your boxes win) or always (the wired caption wins and your edits get ignored). bboxes seeds the canvas from pixel boxes, and image is just a background to draw over.
You get six outputs. prompt is the caption string - that's the one you wire onward. preview renders your boxes and descriptions over the background, capped near 1024px on the long edge; it's a sanity check, not a generation, so send it to a PreviewImage. bboxes converts your regions back to pixel boxes for crop or detector-style consumers. width and height pass straight through so your empty latent can't disagree with the canvas. And upsampler_input is the odd one: the user turn for a prompt upsampler with box mode already baked in, meant to pair with the t2i_bbox system prompt (or i2i_bbox with references) and then run through FLUX.3 Box Reconcile KJ on the answer.
Installing it
Manager is easiest: search KJNodes and install "KJNodes for ComfyUI". Or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/kijai/ComfyUI-KJNodes
pip install -r ComfyUI-KJNodes/requirements.txt
Portable installs use python_embeded\python.exe -m pip install -r ComfyUI\custom_nodes\ComfyUI-KJNodes\requirements.txt. No model downloads here. The pack wants pillow, matplotlib, mss, opencv-python-headless and color-matcher, all imported lazily - skip them and most of the pack still loads, though Color Match and the screencap nodes will fail when you reach for them.
Where people get burned
Coordinate order. It's ymin, xmin, ymax, xmax, not the x1, y1, x2, y2 your instincts expect. The editor shows both a pixel box and the exported grid box next to each region, editable - use them.
Boxes drawn on the wrong canvas. A box on a reference with no matching output box is not "leave this alone", it's "remove this object". If something keeps vanishing from your generations, look for a stray reference-canvas box.
import_mode: always with an editing hand. Set it and the wired caption owns the output; the canvas becomes a viewer. Keep when empty while you're still drawing.
Aspect drift. Draw on 1024×1024, generate 1344×768, and every box lands wrong. Wire the node's width/height outputs into your latent.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| width | INT | 102464–16384 | Output canvas width (the aspect the boxes are drawn on). Multiples of 16. |
| height | INT | 102464–16384 | Output canvas height (the aspect the boxes are drawn on). Multiples of 16. |
| prompt | STRING | The prompt text; the box table is appended after it. Cite boxes as <id>. | |
| references | COMFY_AUTOGROW_V3 | The reference images, in the order the model gets them (ref_1 = ref_image_0). Each gets its own canvas in the editor. | |
| elements_data | STRING | Serialized boxes from the editor (managed by the node UI). | |
| bg_brightness | INT | 250–100 | Background image brightness % (managed by the node UI slider). |
| import_mode | COMBO | when empty | How a wired import_caption is used: 'when empty' only seeds the editor while it has no boxes (then the editor wins, so you can edit); 'always' makes the wired caption authoritative. |
| imageopt | IMAGE | Optional background for the output canvas (and behind the preview). | |
| import_captionopt | STRING | Optional: a FLUX.3 caption (prompt + box table), e.g. the prompt upsampler's output. When connected, it loads into the editor and drives the output per 'import_mode'. | |
| bboxesopt | BOUNDING_BOX | [object Object] | Optional pixel-space boxes ({x, y, width, height}) used to seed the output canvas when the editor has no boxes. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| prompt | STRING | — |
| preview | IMAGE | — |
| bboxes | BOUNDING_BOX | — |
| width | INT | — |
| height | INT | — |
| upsampler_input | STRING | The prompt upsampler's user turn. With boxes: box mode, use the t2i_bbox (or with references i2i_bbox) system prompt, then FLUX.3 Box Reconcile KJ on its answer. |