> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bfl.ml/llms.txt
> Use this file to discover all available pages before exploring further.

# Bounding boxes with FLUX 3 Image

> Place every element of an image with bounding boxes, then recolor, move, replace, or remove elements box by box while the rest of the image stays unchanged.

FLUX 3 Image

# Bounding boxes

Tell FLUX 3 where each element goes. Draw a box, describe what belongs in it, and the model composes the image around your layout. Edit the same way: change one box, and everything outside it stays as it was.

## What you can do with boxes

Every image below was made or edited with FLUX 3 from a prompt that contains
boxes. Hover or tap an edit to compare it with its source.

Boxes need no extra parameter. They are written into `prompt` as a JSON array,
next to a description of the image. This tutorial builds that prompt step by
step: first for a new image, then for an edit.

> [!NOTE]
>
> Every box is **`[top, left, bottom, right]`** in integers from **0 to 1000**,
> measured from the top-left corner. `[0, 0, 500, 500]` is the top-left
> quarter of the image, whatever its size or aspect ratio.

## Generate a layout

You'll recreate the image below: a running figure, centered on a flat
chartreuse background. It has two elements, so its layout prompt is short.

**1. Describe the image and name each element**

Write one paragraph about the whole image. Where an element appears, give
it an id in angle brackets, such as `<silhouette_1>`. Use lowercase names
with a number, so you can add `silhouette_2` later.

```text Caption theme={null}
Minimalist graphic illustration featuring a black silhouette of a person <silhouette_1> centered against a solid, vibrant chartreuse background <background_1>. The figure is captured in a dynamic, mid-stride running pose, facing toward the left side of the frame.
```

**2. Give each element a box and a description**

Add one row per id. `bbox` says where the element sits, and `desc` says
what it looks like. The background fills the frame, and the runner takes
the middle 70% of it.

```json Element table theme={null}
[
  {"id": "background_1", "bbox": [0, 0, 1000, 1000], "desc": "A flat field of neon yellow-green with a subtle paper texture and fine, organic grain."},
  {"id": "silhouette_1", "bbox": [150, 150, 850, 850], "desc": "A black silhouette of a person in motion, made of dense stippled ink. The leading edges are solid; the trailing arm and leg dissolve into coarse square pixels and scattered dots."}
]
```

**3. Join them in one prompt and send it**

Put the caption first, then a space, then the JSON array. Send the result
as `prompt`, with the aspect ratio you designed the boxes for.

```python Python theme={null}
import json
import os
import time

import requests

API_KEY = os.environ["BFL_API_KEY"]

caption = (
    "Minimalist graphic illustration featuring a black silhouette of a person "
    "<silhouette_1> centered against a solid, vibrant chartreuse background "
    "<background_1>. The figure is captured in a dynamic, mid-stride running "
    "pose, facing toward the left side of the frame."
)
rows = [
    {"id": "background_1", "bbox": [0, 0, 1000, 1000],
     "desc": "A flat field of neon yellow-green with a subtle paper texture and fine, organic grain."},
    {"id": "silhouette_1", "bbox": [150, 150, 850, 850],
     "desc": "A black silhouette of a person in motion, made of dense stippled ink. The leading "
             "edges are solid; the trailing arm and leg dissolve into coarse square pixels and scattered dots."},
]


def generate(payload, name):
    submit = requests.post("https://api.bfl.ai/v1/flux-3-image",
                           headers={"x-key": API_KEY}, json=payload, timeout=60)
    submit.raise_for_status()
    polling_url = submit.json()["polling_url"]

    while True:
        time.sleep(1.5)
        result = requests.get(polling_url, headers={"x-key": API_KEY}, timeout=60).json()
        if result["status"] not in ("Pending", "Reasoning", "Generating"):
            break
    if result["status"] != "Ready":
        raise RuntimeError(result)

    image = requests.get(result["result"]["sample"], timeout=120)
    with open(name + ".png", "wb") as f:
        f.write(image.content)
    return name + ".png"


print(generate({"prompt": caption + " " + json.dumps(rows), "aspect_ratio": "1:1"}, "runner"))
```

The script saves `runner.png` and prints its path.

Hover an id in the prompt or a row in the table to find its box. The cursor
readout shows grid coordinates, so you can measure positions for your own layouts.

> [!TIP]
>
> A layout is easiest to write when a language model drafts it. Send it your
> short idea and the aspect ratio, and ask for the caption and element table.
> [Start from a short prompt](https://docs.bfl.ml/guides/prompting_layout.md#start-from-a-short-prompt)
> has an instruction you can reuse.

## Edit an image box by box

To edit, send the image as a reference and describe it with the same kind of
element table. Each row now says where an element comes from and where it
should end up, so the model knows what to keep, what to move, and what to make
new.

| Row | `from` | `src_bbox` | `tgt_bbox` | Effect |
| - | - | - | - | - |
| Keep | `"ref_image_0"` | Its box | The same box | Stays exactly where it is |
| Move | `"ref_image_0"` | Its box | A new box | Moves or resizes the element |
| New | `null` | `null` | Its box | Generates `desc` in the box: adds, replaces, or recolors |
| Remove | `"ref_image_0"` | Its box | `null` | Removes the element |

`ref_image_0` is the first image in `images`; the second is `ref_image_1`.

### Move an element

This edit moves a crocheted knight up the cliff and leaves the rest of the
scene alone.

**1. List the elements of the source image**

Start from the element table of the source. If you generated the image with
boxes, reuse that table. Otherwise, ask a vision model to list the main
elements with their boxes.

**2. Change only the rows you want to edit**

Keep every row as a *Keep* row, with `src_bbox` and `tgt_bbox` equal. Then
give the knight a new `tgt_bbox`:

```json Move row theme={null}
{"id": "knight_1", "from": "ref_image_0", "src_bbox": [500, 150, 850, 350], "tgt_bbox": [194, 55, 544, 255], "desc": "A miniature amigurumi knight crocheted from thick grey woolen yarn."}
```

**3. Write the edit as an instruction**

Refer to the image as `<ref_image_0>`, say what changes, and name what
stays the same:

```text Instruction theme={null}
In <ref_image_0>, move the miniature grey amigurumi knight figure <knight_1> upwards and to the left along the yarn cliff <cliff_1>. Keep the rest of the image completely unchanged, preserving the blurred yarn backdrop <backdrop_1>, the large knitted dragon <dragon_1>, and the fiery orange thread <fire_1>.
```

**4. Send the image and the prompt**

Pass the source in `images`, and join the instruction and rows into
`prompt` as before. This uses `generate()` from the layout example:

```python Python theme={null}
instruction = (
    "In <ref_image_0>, move the miniature grey amigurumi knight figure <knight_1> "
    "upwards and to the left along the yarn cliff <cliff_1>. Keep the rest of the "
    "image completely unchanged, preserving the blurred yarn backdrop <backdrop_1>, "
    "the large knitted dragon <dragon_1>, and the fiery orange thread <fire_1>."
)


def keep(element_id, box, desc):
    return {"id": element_id, "from": "ref_image_0", "src_bbox": box, "tgt_bbox": box, "desc": desc}


rows = [
    {"id": "knight_1", "from": "ref_image_0", "src_bbox": [500, 150, 850, 350],
     "tgt_bbox": [194, 55, 544, 255],
     "desc": "A miniature amigurumi knight crocheted from thick grey woolen yarn."},
    keep("backdrop_1", [0, 0, 1000, 1000], "A soft, out-of-focus backdrop of cream and indigo knitted yarn."),
    keep("cliff_1", [300, 0, 1000, 450], "A steep cliff of stacked yarn skeins in mustard, terracotta, and indigo."),
    keep("needle_1", [420, 250, 550, 450], "An oversized polished steel tapestry needle."),
    keep("dragon_1", [100, 600, 950, 1000], "A large, fluffy knitted dragon in terracotta and mustard yarn."),
    keep("fire_1", [350, 400, 650, 650], "Curled puffs of fiery orange angora thread suspended in mid-air."),
]

payload = {
    "prompt": instruction + " " + json.dumps(rows),
    "images": ["https://cdn.sanity.io/images/2gpum2i6/production/aa7b28af831835fcef86e770262c8c30fa308c2c-1360x768.webp"],
}
print(generate(payload, "knight_moved"))
```

`aspect_ratio` defaults to `auto`, which keeps the shape of the first
reference.

Switch between Before and After, and show the anchors to see every row of
this request. **Copy request body** gives you the complete JSON.

### Replace or recolor

To change what an element looks like, make its row a *New* row and describe
the result in `desc`. Several *New* rows in one request change several
elements at once:

```json New rows theme={null}
[
  {"id": "wolf_1", "from": null, "src_bbox": null, "tgt_bbox": [817, 120, 950, 167], "desc": "a cyberpunk dog"},
  {"id": "log_1", "from": null, "src_bbox": null, "tgt_bbox": [850, 600, 950, 850], "desc": "a fallen bamboo leaf made out of gold"},
  {"id": "bird_1", "from": null, "src_bbox": null, "tgt_bbox": [450, 500, 480, 530], "desc": "a bird made out of a robot"}
]
```

### Remove an element

Set `tgt_bbox` to `null` and say in the instruction what to remove. Name
anything the element leaves behind, such as its shadow, so it goes too. The
model fills the area with what was behind the element:

```json Remove row theme={null}
{"id": "cat_1", "from": "ref_image_0", "src_bbox": [265, 40, 855, 400], "tgt_bbox": null, "desc": "An orange tabby cat sitting on a folded blanket."}
```

Pixels outside the edited boxes usually stay identical. Switch to **Changed
pixels** to see which areas this removal touched:

## Format

Write a description using `<id>` to name each element, then append a JSON
array of rows. This all goes in `prompt`, with no separate box parameter.

Every box is **`[top, left, bottom, right]`**, in integers from **0 to 1000**.
For example, `[0, 0, 500, 500]` covers the top-left quarter of the image.

| Field | Generation | Editing |
| - | - | - |
| `id` | Element name used as `<id>` in the prompt | Same |
| `desc` | What the element looks like | What it should look like after the edit |
| `bbox` | Position in the output | Use `src_bbox` and `tgt_bbox` instead |
| `from` | Not used | Source reference, such as `ref_image_0`; `null` to generate the element at `tgt_bbox` (to add, replace, or recolor it) |
| `src_bbox` | Not used | Position in the source; `null` with `from: null` |
| `tgt_bbox` | Not used | Position in the output; `null` to remove an element |

## Examples

More layouts and edits from the FLUX 3 launch. Choose an example, inspect its
boxes, and copy the request body.
Boxes guide placement; they are not clipping masks.

> [tab] Generate

> [tab] Edit

## Tips and limits

> [card] Boxes guide, they don't clip
>
> An element can extend slightly past its box. Boxes set placement and
> scale, not a hard mask.

> [card] Keep the aspect ratio
>
> The 0–1000 grid stretches with the frame. Send the aspect ratio you
> designed the boxes for.

> [card] Give text its own box
>
> Put each line of text in its own row, and quote the exact words in
> `desc`, such as `text reading "Sauna"`.

> [card] Don't make boxes too small
>
> In our tests, a new element in a box of about 40 × 25 pixels often did
> not appear. Give new elements room.

> [card] Say it twice for edits
>
> State additions and removals in the instruction as well as in the rows.
> The instruction and the table should agree.

> [card] Anchor what must not move
>
> Add a *Keep* row for each element that has to stay put. Unlisted areas
> usually hold, but anchors make it explicit.

To convert pixel coordinates to the grid:

```python Python theme={null}
def to_bbox(left, top, right, bottom, width, height):
    return [round(top / height * 1000), round(left / width * 1000),
            round(bottom / height * 1000), round(right / width * 1000)]

to_bbox(384, 108, 1536, 972, 1920, 1080)  # [100, 200, 900, 800]
```

## Keep exploring

> [card] [FLUX 3 Image Editing](https://docs.bfl.ml/flux_3/flux3_image_layout.md)
>
> The full field reference and more layouts and edits to copy.

> [card] [Layout prompts](https://docs.bfl.ml/guides/prompting_layout.md)
>
> Write captions and element tables that hold, or let a model draft them.

> [card] [FLUX 3 Text to Image](https://docs.bfl.ml/flux_3/flux3_image_generate.md)
>
> Complete clients, edits by instruction, and multi-reference requests.

> [card] [API reference](https://docs.bfl.ml/api-reference/utility/generate-an-image-with-flux-3.md)
>
> The full request schema, limits, and response codes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.