---
title: Layer decomposition — Seedream 5.5 | Runware Docs
url: https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition
description: How to split one image into a base image and transparent layers with Seedream 5.5, from layer positions and split size to reading the text on text layers.
---
### [Introduction](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#introduction)

A finished design is **one flat bitmap**. Moving the headline or translating the copy means regenerating the whole image and hoping the rest survives, or rebuilding it by hand in a design tool.

`settings.layerDecomposition` turns that bitmap back into parts. Seedream 5.5 takes one image and returns **an opaque base image plus transparent PNG layers**, each with its position on the canvas, its place in the stack, and a short name and description.

![A gouache picture-book illustration of a girl in a yellow raincoat running across a green hill with a red kite, a small brown dog beside her and an oak tree on the right](https://runware.ai/docs/assets/source-kite.aJ0pKvg0_ZuyAqb.jpg)

*Input*

> **Prompt**: A flat children's picture-book illustration in gouache with visible paper texture. A girl of about seven in a bright yellow raincoat and red rubber boots runs across a rounded green hill from left to right, holding the string of a red diamond-shaped kite that flies high in the upper left of the sky. A small scruffy brown dog runs beside her with its ears flapping. A large oak tree with a round dark green canopy stands on the right edge of the hill. Soft white clouds drift across a pale blue sky. Warm, friendly palette, clean shapes with clear space between the girl, the dog, the kite and the tree. No text.

![The base image: the green hill and the pale blue sky with clouds, with the girl, the dog, the kite and the tree lifted out and the hill filled in where they stood](https://runware.ai/docs/assets/output-kite-base.BJrjvvzZ_ZtkCCX.jpg)

*Base image*

![The red diamond kite with its streamers and a length of pink string, with no background around it](https://runware.ai/docs/assets/output-kite-layer-1.CUpho8Zf_Z2nvbk3.jpg)

*Layer 1*

![The girl in the yellow raincoat, floral dress and red boots running with the kite string in her hand, with no background around her](https://runware.ai/docs/assets/output-kite-layer-2.De55ccWK_Z4dlIR.jpg)

*Layer 2*

![The scruffy brown and white dog running with its tongue out, with no background around it](https://runware.ai/docs/assets/output-kite-layer-3.B94pRfi2_Z2rcP94.jpg)

*Layer 3*

![The tree with its dark green canopy and a tuft of grass at its base, with no background around it](https://runware.ai/docs/assets/output-kite-layer-4.BJG6dwBh_Z2ofpry.jpg)

*Layer 4*

**Each part arrives as its own file**, so an animator can move the dog without touching the girl, and a layout can push the kite higher without regenerating the page.

This guide covers the request, what each layer carries, putting the layers back together, setting how finely the image splits, steering the split with a prompt and reading the text on text layers.

### [The request](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#the-request)

A decomposition request is **one reference image and one setting**. The prompt is optional.

**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: 'bytedance:seedream@5.5',
  inputs: {
    referenceImages: [
      'https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-kite.jpg'
    ]
  },
  settings: {
    layerDecomposition: true,
    layerDecompositionMaxImages: 6
  },
  outputFormat: 'PNG'
})
```

**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": "bytedance:seedream@5.5",
            "inputs": {
                "referenceImages": [
                    "https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-kite.jpg"
                ]
            },
            "settings": {
                "layerDecomposition": True,
                "layerDecompositionMaxImages": 6
            },
            "outputFormat": "PNG"
        })

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": "4c8e1f2a-7b3d-4e9a-a1c6-5d2f8b0e9c37",
      "model": "bytedance:seedream@5.5",
      "inputs": {
        "referenceImages": [
          "https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-kite.jpg"
        ]
      },
      "settings": {
        "layerDecomposition": true,
        "layerDecompositionMaxImages": 6
      },
      "outputFormat": "PNG"
    }
  ]'
```

**CLI**:

```bash
runware run bytedance:seedream@5.5 \
  inputs.referenceImages.0=https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-kite.jpg \
  settings.layerDecomposition=true \
  settings.layerDecompositionMaxImages=6 \
  outputFormat=PNG
```

**JSON**:

```json
{
  "taskType": "imageInference",
  "taskUUID": "4c8e1f2a-7b3d-4e9a-a1c6-5d2f8b0e9c37",
  "model": "bytedance:seedream@5.5",
  "inputs": {
    "referenceImages": [
      "https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-kite.jpg"
    ]
  },
  "settings": {
    "layerDecomposition": true,
    "layerDecompositionMaxImages": 6
  },
  "outputFormat": "PNG"
}
```

- **Exactly one image** goes in `inputs.referenceImages`, as a PNG or a JPEG holding at least 262,144 pixels, the area of 512 × 512.
- `positivePrompt` can be left out, and then **the model plans the split on its own**. A prompt only steers which parts become layers, as shown in [Steering the split with a prompt](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#steering-the-split-with-a-prompt).
- `width` and `height` are rejected in this mode, and so is `settings.background` with any value, because **the base is always opaque and every layer transparent**.
- `resolution` takes a tier. Leave it out and the output **keeps the size of the source** when the source holds between 921,600 and 4,624,220 pixels. A smaller source comes back at 1K and a larger one at 2K, both with the source's aspect ratio.

`outputFormat` sets the format of the base image only. **The layers are always PNG**, since they carry an alpha channel.

### [What each layer carries](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#what-each-layer-carries)

The base image comes back where every image result does, in `imageURL`. The layers come back in `outputs.layers`, **one entry per layer** with its file and where it belongs.

| Field | What it holds |
| --- | --- |
| `imageURL` | The base image, opaque, at the bottom of the stack |
| `outputs.layers[].url` | One part of the image as a PNG with an alpha channel |
| `outputs.layers[].zIndex` | The stacking order. The base sits at 0, and a higher number draws on top |
| `outputs.layers[].boundingBox.absolute` | The layer's box on the base image in pixels, as `[left, top, right, bottom]` |
| `outputs.layers[].boundingBox.normalized` | The same box on a 0 to 1000 scale |
| `outputs.layers[].name` | A short label written by the model |
| `outputs.layers[].description` | A sentence describing what the layer shows |

Each layer file holds **only its own box, at its own resolution**. A part that covers about a megapixel or more comes back at the size of its box, and a smaller one comes back enlarged: the dog's box above is 507 × 405 pixels, and its PNG is 1146 × 915. Scale each layer to the size of its `boundingBox.absolute` before placing it, and use `normalized` to place it on a canvas of a different size.

`name` and `description` are written by the model for each image. They help **match a layer to a role** in a template, such as finding the headline or the product, but they are free text rather than a fixed vocabulary, so match them loosely. **Their language is not fixed** either. A layer that merges several parts, which happens more at a low maximum, can get a `description` partly in Chinese, so translate or clean the text before showing it to a user.

### [Putting the layers back together](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#putting-the-layers-back-together)

Draw the base, then **each layer scaled to its box** and placed at the box's left and top, taken from `boundingBox.absolute`, in `zIndex` order. The stack rebuilds the source.

**Source and layer boxes**:

![A cream dog-treat tin labeled GOOD BOY BITES, a terracotta bowl embossed GOOD BOY full of bone-shaped biscuits and a red rubber ball on a pale mint backdrop with a potted plant and a small pumpkin behind, with the box of each layer drawn over it](https://runware.ai/docs/assets/source-tin.DChGjbHn_2uSu7G.jpg)

> **Prompt**: Photoreal product packaging mockup for a dog-treat brand on a pale mint seamless studio background. A round cream-colored metal tin with a domed lid stands slightly left of center, its printed label reading "GOOD BOY BITES" in bold navy sans-serif with "Peanut butter & pumpkin" in smaller type underneath. To its right, a small terracotta ceramic dog bowl filled with bone-shaped biscuits. In the front left, a red rubber ball. Soft even studio light from the upper left, soft natural shadows under each object, three-quarter eye-level view, crisp detail.

**Base plus layers**:

![The same tin, bowl and ball on the mint backdrop, rebuilt by drawing each layer over the base image at the size and position of its box](https://runware.ai/docs/assets/output-tin-rebuilt.MbeXLhZa_Z1tkF8b.jpg)

With the response array in `tasks`, [sharp](https://sharp.pixelplumbing.com/) does the whole stack in one call:

```typescript
import sharp from 'sharp'

const download = async (url: string) => Buffer.from(await (await fetch(url)).arrayBuffer())

const [result] = tasks
const layers = [...result.outputs.layers].sort((a, b) => a.zIndex - b.zIndex)

const rebuilt = await sharp(await download(result.imageURL))
  .composite(await Promise.all(layers.map(async (layer) => {
    const [left, top, right, bottom] = layer.boundingBox.absolute
    const input = await sharp(await download(layer.url))
      .resize(right - left, bottom - top, { fit: 'fill' })
      .toBuffer()

    return { input, left, top }
  })))
  .png()
  .toBuffer()
```

Change a layer's `left` and `top` before compositing to move it, or skip a layer to take it out of the picture. **The base fills in what the layers covered**, so taking a part out leaves backdrop rather than a hole.

![The base image of the mockup: the pale mint backdrop with the potted plant and the small pumpkin, and the tin, the bowl and the ball lifted out](https://runware.ai/docs/assets/output-tin-base.DFkt0b9E_2uK0WG.jpg)

*The base image on its own*

### [Setting the number of layers](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#setting-the-number-of-layers)

`settings.layerDecompositionMaxImages` caps the images in the response, **the base included**, so `4` means a base and at most three layers. Left out, it is 30.

The same social ad split twice, once with a maximum of 4 and once with 16:

![A flat-lay granola ad on a peach background with a bowl of granola, berries and a wooden spoon, scattered oats, almonds and berries, a napkin on a wooden board, a HARVEST HILL logo, the headline BREAKFAST, SORTED at the top and a green SHOP NOW button at the bottom](https://runware.ai/docs/assets/source-granola.DlHXPXuM_Zxk5W6.jpg)

*Input*

> **Prompt**: A flat-lay social media ad for a granola brand, shot from directly above on a soft peach background. At the center, a white ceramic bowl of golden oat granola topped with fresh blueberries and sliced strawberries, a wooden spoon resting against it. Around the bowl, scattered rolled oats, whole almonds, single blueberries and two halved strawberries, with a folded linen napkin in the lower right. At the top, a bold headline in deep green sans-serif reads "BREAKFAST, SORTED". At the bottom, a rounded deep green button with white text reads "SHOP NOW". Bright natural daylight, crisp commercial food photography.

![The three layers from a maximum of 4: the headline, the bowl together with the button, and the logo together with the napkin and the board](https://runware.ai/docs/assets/output-granola-4-sheet.CJZvlmZv_ZnfuaM.jpg)

*Maximum 4*

![The eight layers from a maximum of 16: the headline, the logo, the bowl with its spoon, two strawberry halves, the napkin, the board and the button](https://runware.ai/docs/assets/output-granola-16-sheet.Sodms0Vq_1fCO9m.jpg)

*Maximum 16*

A higher maximum gives **a finer split**. At 4 the model returned three layers and grouped parts that sit near each other: the bowl with the button under it, and the logo with the napkin and the board. At 16 it returned eight, with the headline, the logo, the bowl, two strawberries, the napkin, the board and the button each on its own, and the scattered oats, almonds and blueberries left in the base.

The maximum is a ceiling, not a target, and **the model can return fewer layers** than it allows. A maximum below the number of parts also splits less cleanly: at 4, the base kept its own copy of the logo, the button and the board.

At a maximum that low, **the grouping also changes from run to run**, so a retry can come back split differently. Two more runs at 4 kept the headline on its own but put the button with the napkin instead of the bowl, and one of them put the logo with the bowl. With room for every part, three runs of the room in the next section returned the same six layers, and only the wording of `name` and `description` changed.

Every image in the response is **billed as a separate output image**, the base and each layer, so the maximum also caps what a request can cost. Set it to the number of parts your edit needs, plus one for the base.

### [Steering the split with a prompt](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#steering-the-split-with-a-prompt)

Without a prompt, the model **plans the split from the image and the maximum**. A prompt that names the parts takes over that plan. The room below was split twice with the same maximum of 10.

![A bright living room with a deep green velvet sofa with mustard cushions against a white wall, a round oak coffee table on a cream rug, a black floor lamp, a rattan armchair and a curtained window](https://runware.ai/docs/assets/source-living.KweYGSlT_6VSDR.jpg)

*Input*

> **Prompt**: Photorealistic real estate listing photograph of a bright modern living room. A deep green velvet three-seat sofa with two mustard cushions stands against a plain white wall. A round light oak coffee table sits on a cream wool rug in front of it, a black metal floor lamp stands to the left of the sofa, and a woven rattan armchair is on the right. A large window with sheer white curtains fills the left wall. Light oak floorboards. Wide straight-on shot at eye level with a 24mm lens, bright natural daylight, crisp detail.

![The six layers from the split without a prompt: the curtain, the floor lamp, the sofa with its cushions, the rug, the coffee table and the armchair](https://runware.ai/docs/assets/output-living-default-sheet.DUNQwlof_1i1JTD.jpg)

*No prompt*

![The living room with the sofa lifted out, the white wall filled in behind where it stood, and the table, rug, lamp and armchair still in place](https://runware.ai/docs/assets/output-living-sofa-base.aNXiekpx_Z2nv4Hc.jpg)

*Base image*

> **Prompt**: Separate only the sofa, together with its cushions, into its own layer.

![The green velvet sofa with its two mustard cushions on its own, with no background around it](https://runware.ai/docs/assets/output-living-sofa-layer-1.BmIThzhP_Z1JOHAF.jpg)

*Layer 1*

> **Prompt**: Separate only the sofa, together with its cushions, into its own layer.

Without a prompt the room came back as six layers over an empty room. The prompted split returns one layer for the sofa and a base with the rest of the room, which is **the starting point for virtual staging**: drop a different sofa onto the base, or restyle the sofa layer and put it back.

Name every part you want as its own layer, and **leave the base out of the prompt**, since everything you do not name stays there. Ending a prompt on this room with "Leave everything else in the base image" returned, in four runs out of five, an extra opaque layer that covers the whole frame and nearly repeats the base, billed as one more image.

**Keep the maximum above the number of parts you name**, because a prompt that asks for more layers than the maximum allows loses some of what it names.

A part can also be **pointed at by its position** instead of its name, which suits an editor where the user drags a box over it. Put the box in the prompt between `<bbox>` tags, as left, top, right and bottom on the 0 to 1000 scale of `boundingBox.normalized`:

```text
Separate the regions at <bbox>308 484 438 570</bbox> and <bbox>566 484 694 570</bbox> into two separate layers, one per region.
```

On this room the two boxes returned **each mustard cushion as its own layer**, the same split that naming the cushions gave, with the sofa filled in behind them on the base.

### [Reading text with text recognition](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#reading-text-with-text-recognition)

`settings.layerDecompositionTextRecognition` adds a `textRecognition` object to **every layer the model reads as typeset text**: the full string, the box of each line, and runs of characters that share a style. It turns a flat flyer into copy a localization pipeline can translate and set again.

![A teal taco restaurant flyer with LA PALMA TAQUERIA at the top, a yellow TACO TUESDAY headline, a line reading $2 TACOS in red and ALL NIGHT in white, a plate of three tacos with lime wedges, small bowls of onion, salsa and chili flakes and a whole lime around it, a coral brush script reading ¡Buen provecho!, an italic line about Tuesday hours and an underlined web address](https://runware.ai/docs/assets/source-flyer.DC4jkbWF_1lAeRO.jpg)

*Input*

> **Prompt**: A printed promotional flyer for a taco restaurant, flat graphic design on a deep teal background. At the very top, the restaurant name "LA PALMA TAQUERIA" in small bold white sans-serif capitals. Below it, a huge bold condensed sans-serif headline in sunflower yellow reads "TACO TUESDAY". Under the headline, one line in bold sans-serif where "$2 TACOS" is bright red and "ALL NIGHT" is white. In the middle, a photo of three street tacos with cilantro, onion and lime wedges on a round white plate. Below the photo, a line in white italic sans-serif reads "Every Tuesday, 5 PM to close". Beside the plate, a hand-lettered brush script in coral reads "¡Buen provecho!". At the bottom, a white underlined sans-serif line reads "lapalmataqueria.com". Clean margins, crisp print-ready typography.

![The base image of the flyer: the plain teal background with every line of text, the plate, the bowls and the lime lifted out](https://runware.ai/docs/assets/output-flyer-base.BGsdM4Xl_Z25FEXi.jpg)

*Base image*

![The flyer's eleven layers side by side: the restaurant name, the TACO TUESDAY headline, the price line, the brush script, four small bowls, the plate of tacos, the whole lime, and the hours line together with the web address](https://runware.ai/docs/assets/output-flyer-sheet.DYBa3LRW_1Nu0VC.jpg)

*Layers*

The price line comes back as one layer with **two runs**, because the color changes partway through it:

**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: 'bytedance:seedream@5.5',
  inputs: {
    referenceImages: [
      'https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-flyer.jpg'
    ]
  },
  settings: {
    layerDecomposition: true,
    layerDecompositionMaxImages: 12,
    layerDecompositionTextRecognition: true
  },
  outputFormat: 'PNG'
})
```

**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": "bytedance:seedream@5.5",
            "inputs": {
                "referenceImages": [
                    "https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-flyer.jpg"
                ]
            },
            "settings": {
                "layerDecomposition": True,
                "layerDecompositionMaxImages": 12,
                "layerDecompositionTextRecognition": True
            },
            "outputFormat": "PNG"
        })

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": "b6d2a8f4-3e1c-4a97-9c05-7f8e2d1b4a63",
      "model": "bytedance:seedream@5.5",
      "inputs": {
        "referenceImages": [
          "https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-flyer.jpg"
        ]
      },
      "settings": {
        "layerDecomposition": true,
        "layerDecompositionMaxImages": 12,
        "layerDecompositionTextRecognition": true
      },
      "outputFormat": "PNG"
    }
  ]'
```

**CLI**:

```bash
runware run bytedance:seedream@5.5 \
  inputs.referenceImages.0=https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-flyer.jpg \
  settings.layerDecomposition=true \
  settings.layerDecompositionMaxImages=12 \
  settings.layerDecompositionTextRecognition=true \
  outputFormat=PNG
```

**JSON**:

```json
{
  "taskType": "imageInference",
  "taskUUID": "b6d2a8f4-3e1c-4a97-9c05-7f8e2d1b4a63",
  "model": "bytedance:seedream@5.5",
  "inputs": {
    "referenceImages": [
      "https://assets.runware.ai/guides/bytedance-seedream-5-5/layer-decomposition/source-flyer.jpg"
    ]
  },
  "settings": {
    "layerDecomposition": true,
    "layerDecompositionMaxImages": 12,
    "layerDecompositionTextRecognition": true
  },
  "outputFormat": "PNG"
}
```

- `text` is the whole layer as plain text, with **lines joined** by `\n`, ready to send to translation. The hours line and the web address on this flyer came back as one layer, so its `text` holds both lines.
- `lines[].boundingBox` **places each line** on the base, in the same `absolute` and `normalized` form as a layer's box.
- `runs[]` splits a line **wherever the style changes**, and each `style` holds the font, the color as `#RRGGBB` and six flags: `bold`, `italic`, `underline`, `strikethrough`, `shadow` and `translucent`.

To localize the flyer, translate `text`, then **set each line in its box on the base**, in a font close to `similarFontFamily` and the run's `foregroundColor`. The image layers stay as they are.

`similarFontFamily` is **the closest match** from the fonts the model recognizes, not the font the design used, and it reads `unknown` when the model is not confident. Map it to a font you license before setting type.

The style flags **describe the letters themselves**. A layer rotated on the canvas does not read as `italic`, and a solid light color does not read as `translucent`. **Check the flags against the image** before reusing them: the web address on this flyer is underlined, and it came back with `underline` set to false here and on an earlier version of the same flyer.

> [!WARNING]
> Only typeset text gets `textRecognition`. Hand-lettered and artistic text get none, and small or heavily stylized type may get none either, so the brush script on the flyer comes back as an image layer without it. Check for the field before reading it.

### [Tips](https://runware.ai/docs/models/bytedance-seedream-5-5/guides/layer-decomposition#tips)

1. **Name the parts you want.** Without a prompt the model decides the split. A prompt that lists the parts gets that split instead, and everything it does not name stays in the base.
    
2. **Size the maximum to the edit.** It counts the base, and every image that comes back is billed, so set it to the parts you need plus one.
    
3. **Read the layer count from the response.** The model can return fewer layers than the maximum, so loop over `outputs.layers` instead of expecting a fixed number.
    
4. **Scale each layer to its box.** A small part comes back enlarged, so resize it to the size of `boundingBox.absolute` before placing it at the box's left and top.
    
5. **Check for text recognition first.** Only layers read as typeset text carry `textRecognition`, so test for it before reading it.
    
6. **Treat the font and the flags as hints.** Map `similarFontFamily` to a licensed font, and check the style flags against the image.
    
7. **Retry the whole request when it fails.** If one layer fails to generate, the request fails, and nothing partial comes back.