---
title: Rendering text with FLUX 3 Image — FLUX 3 Image | Runware Docs
url: https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering
description: "How to render readable text with FLUX 3 Image: quoting the exact string, directing the typography, building a text hierarchy, and editing copy inside an existing image."
---
### [Introduction](https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering#introduction)

Typography is the part of FLUX 3 Image that changed most from earlier FLUX models, and it is what makes the model usable for **work that ships with words on it**: packaging, campaign creative, interface mockups and signage.

There are **no text layers and no font picker**. Every character, its weight, its position and its size come out of the same `positivePrompt` that describes the scene, which makes the phrasing of the text instruction the whole of the typographic control.

![A matte white skincare carton reading AURELIA in letterspaced capitals, Daily Mineral Fluid below it, and SPF 50 50ml along the bottom edge](https://runware.ai/docs/assets/hero.Da8CjeIs_1qarcH.jpg)

> **Prompt**: A matte white skincare carton standing upright on a pale travertine surface against a warm sand backdrop. The front panel reads "AURELIA" in thin black letterspaced capitals across the top, "Daily Mineral Fluid" in smaller black serif below it, and "SPF 50 · 50ml" in fine capitals along the bottom edge. Soft directional light from the upper left, a short soft shadow to the right. Straight-on shot at carton height, 85mm lens, the carton centered with clear space above. Photoreal beauty packaging photography, warm neutral palette.

Three strings at three sizes, each one placed by the prompt. This guide covers how to get the characters right, how to direct the typography, how to stack several strings into a layout, and how to change copy in an image you already have.

### [Quote the exact string](https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering#quote-the-exact-string)

Put every string you want rendered inside **quotation marks**. The quotes mark the boundary between the part of the sentence that describes the scene and the part that is literal content, Without them the model writes its own copy from your description: it reads cleanly, and it is not the copy you were handed.

![A clothing store window with SPRING SALE and 30% OFF applied to the glass in white capitals](https://runware.ai/docs/assets/quoted-without.D89SAR9k_ZhQFs4.jpg)

*Described, not quoted*

> **Prompt**: A clothing store window with a vinyl decal advertising a spring sale at thirty percent off, white lettering on the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette.

![A clothing store window reading SPRING SALE in large white capitals with 30% OFF EVERYTHING beneath it](https://runware.ai/docs/assets/quoted-with.CIPAjxI6_ZnOR7I.jpg)

*Quoted, with a size relationship*

> **Prompt**: A clothing store window with a vinyl decal reading "SPRING SALE" in large white capitals with "30% OFF EVERYTHING" in smaller white capitals beneath it, applied to the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette.

The unquoted prompt asked for a spring sale at thirty percent off and got exactly that. The quoted one got "30% OFF EVERYTHING", a word the description never implied, because the string was handed over instead of described.

The quoted version also carries a **size relationship**, "large" against "smaller beneath it", which is what turns two strings into a headline and a subhead rather than two lines of equal weight.

**Accuracy falls off as strings get longer.** A brand name, a headline or a short line of detail render reliably. A paragraph of body copy is where it stops being reliable.

**TypeScript**:

```typescript
import { createClient } from '@runware/sdk'

const client = await createClient({ apiKey: process.env.RUNWARE_API_KEY })
await client.connect()

const [result] = await client.run({
  model: 'bfl:flux@3-image',
  positivePrompt: 'A clothing store window with a vinyl decal reading "SPRING SALE" in large white capitals with "30% OFF EVERYTHING" in smaller white capitals beneath it, applied to the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette.',
  width: 1248,
  height: 832
})
```

**Python**:

```python
import asyncio
import os

from runware import Runware

async def main():
    async with Runware(api_key=os.environ["RUNWARE_API_KEY"]) as client:
        results = await client.run({
            "model": "bfl:flux@3-image",
            "positivePrompt": "A clothing store window with a vinyl decal reading \"SPRING SALE\" in large white capitals with \"30% OFF EVERYTHING\" in smaller white capitals beneath it, applied to the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette.",
            "width": 1248,
            "height": 832
        })

asyncio.run(main())
```

**cURL**:

```bash
curl https://api.runware.ai/v1 \
  -H "Authorization: Bearer $RUNWARE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "taskType": "imageInference",
      "taskUUID": "d4e5f6a7-b8c9-0123-def1-234567890123",
      "model": "bfl:flux@3-image",
      "positivePrompt": "A clothing store window with a vinyl decal reading \"SPRING SALE\" in large white capitals with \"30% OFF EVERYTHING\" in smaller white capitals beneath it, applied to the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette.",
      "width": 1248,
      "height": 832
    }
  ]'
```

**CLI**:

```bash
runware run bfl:flux@3-image \
  positivePrompt="A clothing store window with a vinyl decal reading \"SPRING SALE\" in large white capitals with \"30% OFF EVERYTHING\" in smaller white capitals beneath it, applied to the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette." \
  width=1248 \
  height=832
```

**JSON**:

```json
{
  "taskType": "imageInference",
  "taskUUID": "d4e5f6a7-b8c9-0123-def1-234567890123",
  "model": "bfl:flux@3-image",
  "positivePrompt": "A clothing store window with a vinyl decal reading \"SPRING SALE\" in large white capitals with \"30% OFF EVERYTHING\" in smaller white capitals beneath it, applied to the glass, racks of clothing visible inside, a pavement in front. Bright overcast daylight. Straight-on shot from across the pavement at standing height, 35mm lens. Photoreal retail photography, neutral palette.",
  "width": 1248,
  "height": 832
}
```

### [Direct the typography](https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering#direct-the-typography)

A quoted string gets the characters right. It does not decide the weight, the case, the color, or how much of the panel the words take up, and left unsaid those are chosen for you.

![A blue conference stage backdrop reading BUILDWEEK 2026 in white capitals, with a lectern at the left of the stage](https://runware.ai/docs/assets/type-loose.Dg3osnTX_2r4jjG.jpg)

*String only*

> **Prompt**: A conference stage backdrop with "BUILDWEEK 2026" on it, an empty lectern at the left of the stage. Stage lighting from above. Wide shot from the floor at standing height, 35mm lens. Photoreal event photography.

![A navy conference backdrop with BUILDWEEK 2026 in heavy white capitals across two thirds of the panel and a thin date line beneath](https://runware.ai/docs/assets/type-directed.BSv8S5M6_1zKXhF.jpg)

*Weight, case, coverage, second line*

> **Prompt**: A conference stage backdrop in deep navy with "BUILDWEEK 2026" centered across it in heavy white sans-serif capitals filling two thirds of the panel width, and "March 14 · Lisbon" beneath it in a thin white sans-serif at a quarter of that size. An empty pale oak lectern at the left of the stage. Even stage lighting from above with a soft gradient falloff at the panel edges. Wide shot from the floor at standing height, 35mm lens. Photoreal event photography, cool palette.

The directed prompt sets four things the first one left open:

- **Weight and family:** "heavy white sans-serif capitals"
- **Coverage:** "filling two thirds of the panel width"
- **Position:** "centered across it", "beneath it"
- **Relative size:** "at a quarter of that size"

Coverage is the one people leave out and then fight with. **Saying how much of the surface the text should occupy** is more reliable than asking for it to be large, because large is relative to a frame the model has not drawn yet.

### [Building a layout](https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering#building-a-layout)

Text-heavy work is several strings with **a stated relationship between them**. Name each string, say where it sits relative to the last one, and give it a size and a weight. The model holds a hierarchy of three or four levels comfortably.

![A laptop screen showing an analytics dashboard with a sidebar, a Weekly performance heading, three stat cards and a line chart](https://runware.ai/docs/assets/layout-dashboard.s6MM3BiL_Z2hi7Ys.jpg)

*Interface mockup*

> **Prompt**: A laptop screen filling the frame showing an analytics dashboard on a white background. A left sidebar lists "Overview", "Campaigns", "Audience" and "Reports" in small dark sans-serif. The main panel is headed "Weekly performance" with three stat cards reading "12,480 Sessions", "3.2% Conversion" and "€18,940 Revenue", and a line chart below them. Even daylight, no screen glare. Straight-on shot at screen height, 50mm lens. Photoreal product interface photography, clean bright palette.

![A framed poster on a gallery wall reading OPEN STUDIOS with a date line and a venue line beneath](https://runware.ai/docs/assets/layout-poster.DCNUM4-g_kuVQ.jpg)

*Event poster*

> **Prompt**: A framed poster on a white gallery wall reading "OPEN STUDIOS" in large black condensed capitals across the top, "Saturday 18 October, 11am to 6pm" in a smaller black serif in the middle, and "Building 4, Riverside Works" in fine capitals at the bottom, on a warm cream ground. Even gallery lighting. Straight-on shot at eye height, 50mm lens, the frame centered with clear wall either side. Photoreal interior photography, neutral palette.

![A printed membership pricing card on a walnut counter showing a large price figure and three bullet lines](https://runware.ai/docs/assets/layout-pricing.CsalpOXQ_18gFQu.jpg)

*Pricing card*

> **Prompt**: A printed pricing card standing on a walnut counter, reading "MEMBERSHIP" in small gray capitals at the top, "€39" in very large black figures below it, "per month" in fine gray letters beneath, then a short list reading "Unlimited classes", "Two guest passes" and "Locker included" in dark sans-serif. Soft daylight from the left. Three-quarter view at counter height, 50mm lens, shallow depth of field. Photoreal retail photography, warm neutral palette.

![A brushed aluminum office sign reading LEVEL 2 with three department lines beneath it](https://runware.ai/docs/assets/layout-wayfinding.Bm6yATzV_Zjca0l.jpg)

*Wayfinding sign*

> **Prompt**: A brushed aluminum wayfinding sign mounted on a concrete wall in an office lobby, reading "LEVEL 2" in large dark capitals at the top and, beneath it, three lines reading "Product · 2.01 to 2.09", "Design · 2.10 to 2.14" and "Meeting rooms · 2.15" in a smaller dark sans-serif. Even ambient lighting. Straight-on shot at eye height, 50mm lens. Photoreal architectural photography, cool neutral palette.

Each of these is one prompt, and each one orders its strings top to bottom in the same order they appear on the surface. **Writing the strings in reading order** is worth doing deliberately, because a prompt that introduces the footer before the headline tends to come back with them swapped.

> [!NOTE]
> Small type is the first thing a lower tier loses. A pricing list or a sidebar of menu labels that reads cleanly at 2K can turn mushy at 0.75K, so generate text-heavy layouts at the tier you intend to deliver rather than proofing at a cheap one.

### [Editing copy in place](https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering#editing-copy-in-place)

Text is editable the same way anything else is: send the image in `inputs.referenceImages` and name the string you want changed. Because the type is **rebuilt rather than overlaid**, the replacement picks up the surface it sits on, including its curve, its finish and the light across it.

**ORIGINAL**:

![A white supplement carton reading NORDVIT, Magnesium Complex, and ORIGINAL on a teal band](https://runware.ai/docs/assets/edit-source.9f6kByAh_Z2tVSpN.jpg)

> **Prompt**: A white supplement carton standing on a pale gray surface against a plain gray backdrop. The front panel reads "NORDVIT" in bold black capitals at the top, "Magnesium Complex" in a smaller black sans-serif below it, and "ORIGINAL" in white capitals on a teal band across the lower third. Soft even studio light from the front left, a short soft shadow to the right. Straight-on shot at carton height, 85mm lens, the carton centered. Photoreal supplement packaging photography, cool neutral palette.

**EXTRA STRENGTH**:

![The same carton with the teal band now reading EXTRA STRENGTH](https://runware.ai/docs/assets/edit-after.BzysT4qO_ZWPwh9.jpg)

> **Prompt**: Change the text on the teal band to read "EXTRA STRENGTH" in the same white capitals, fitted to the same band. Keep the "NORDVIT" wordmark, the "Magnesium Complex" line, the teal band itself, the carton shape, the gray backdrop, the shadow, the framing and the lighting unchanged.

The instruction names **which string changes and which ones stay**, which matters more here than in other edits because a carton carries several pieces of text and "change the text" gives the model no way to pick. Quoting the survivors, "NORDVIT" and "Magnesium Complex", pins them as literally as the new string.

This is the practical route to a variant set. **One packaging render becomes the whole product line** by editing the flavor band, and the lighting and the carton geometry stay identical across the set in a way that separate generations never would.

> [!WARNING]
> Editing text works best when the target is **visually separated from its surroundings**, like the band here. Copy set over a photograph or a busy texture is harder to isolate, and the edit tends to take some of the background with it. When a frame holds several strings, identify the one you mean by its position or its container rather than by calling it the text.

### [Tips for best results](https://runware.ai/docs/models/bfl-flux-3-image/guides/text-rendering#tips-for-best-results)

1. **Quote every string.** Unquoted copy is a description, and the model will rewrite it into something that means the same thing.
    
2. **Keep strings short.** A wordmark, a headline, a date line. Reliability drops with length, and body copy is where it breaks.
    
3. **Say how much room the text takes.** "Filling two thirds of the panel width" beats "large", which has nothing to be large relative to.
    
4. **State sizes relative to each other.** "At a quarter of that size" builds a hierarchy. Absolute point sizes mean nothing here.
    
5. **Write the strings in reading order.** Headline, then subhead, then footer. Prompts that jump around come back with the levels swapped.
    
6. **Generate at the delivery tier.** Small type is the first casualty of a lower tier, and there is no upscale pass to recover it.
    
7. **Quote the survivors when editing.** Name the strings that must not change as precisely as the one that must, or the model picks for you.