UI Lab

Build nine-slice panels, button states, UI atlases and bitmap fonts in one workspace, then check them at real screen sizes.

A UI sheet (buttons, panels and icons drawn on one transparent PNG) has to become separate, named rectangles before an engine can draw any of it. The UI Lab finds every element as an island of pixels above an alpha threshold, joins islands closer than the merge distance (a button and the badge beside it), packs the elements into ui-atlas.png with padding and optional extrude, and writes each rect and any nine-slice border to ui-atlas.json. It writes numbers, not Godot or Unity resource files; the 9-Slice, States, Font and Check stages work on the same image.

Drop image files hereProcess many files at once
No upload · processed on this device

From a UI sheet to atlas rectangles

An element is found the way you would outline it by hand. Pixels whose alpha is above the threshold (default 8 of 255) are grouped with their eight neighbours into islands, and islands smaller than the minimum size (default 16 pixels) are dropped as specks of dust.

Islands are candidates, not meaning. An icon with a separate dot next to it is two islands; the merge distance (default 4 px) unions any two boxes whose gap is at most that many pixels and repeats until nothing merges, so a chain of nearby pieces becomes one element tagged merged. Two buttons that touch are a single island and stay one element whatever the merge distance.

Packing places the elements on one page of at most 4096 × 4096 px with MaxRects and leaves the padding (default 2 px) free around them. Extrude repeats each element's outermost pixels outward by N px, so a filtered or mipmapped sample that lands just outside the element still reads the element's own colour. The rect in the JSON is the element itself; the extruded ring lies outside it.

Alpha island
A group of 8-connected pixels above the alpha threshold.
Merge distance
The largest gap, in pixels, at which two boxes become one element.
Padding
Empty pixels left between packed elements.
Extrude
Copies of an element's edge pixels placed around it, outside its rect.

Example: one 256 × 128 sheet, measured

Five shapes on a transparent sheet, run through the same detection, merge and packing code the Lab uses:

sheet 256 × 128   alpha threshold 8   minimum 16 px   merge distance 4
islands  panel 64×64 @8,8   button 96×32 @96,8   icon 16×16 @200,12   dot 4×4 @218,12   arrow 20×20 @96,64
gap icon → dot = 218 − (200 + 16) = 2 px ≤ 4   → one element 22×16 @200,12, tag "merged"
result   5 islands → 4 elements  (merge distance 0 would keep 5)
pack     padding 2, extrude 1   → ui-atlas.png 102 × 108
rects    element-02 3,3 96×32   element-01 3,41 64×64   element-03 73,41 22×16   element-04 73,63 20×20

Elements are numbered top to bottom, then left to right, before packing: element-01 is the panel, element-03 the merged icon. Rename them before export, because the names become the keys under frames in the JSON.

Check the result

  • Open ui-atlas.json: frames has one entry per element you kept, and every rect lies inside meta.size.
  • Crop one rect out of ui-atlas.png in any image editor and compare it with the same element on the source sheet; they are the same pixels.
  • Look for "tag": "merged": each one should be a piece you meant to join, not two buttons that happen to sit close together.
  • If you gave an element nine-slice borders, SETUP.md has a section with its name and the four numbers.

Troubleshooting

SymptomLikely causeHow to checkFix
Two buttons came out as one elementThey touch, or the gap between them is not larger than the merge distanceThe element's box covers both buttons; the tag says merged when it came from more than one islandSet the merge distance to 0; if they touch, leave at least one transparent pixel between them in the art
A label, glow or shadow became its own elementIts pixels are separated from the button by more than the merge distance, or they are fainter than the alpha thresholdCount the elements against what you expect; zoom into the gapRaise the merge distance a few pixels; lower the alpha threshold if a soft shadow is being cut off
Tiny specks appear as elementsStray pixels form islands above the minimum sizeVery small rects in the element listRaise the minimum pixels, or erase the dust in the art
Thin lines of a neighbour appear at an element's edge in the engineThe engine filters or mipmaps across the rect border and padding 0 lets it read the neighbourZoom in on the edge in the running gameUse padding 2 and extrude 1–2, or Nearest filtering for pixel art
The atlas fails to packThe elements do not fit on one 4096 × 4096 pageThe summary shows the error instead of a sizeSplit the sheet and build two atlases; there is no multi-page UI atlas

Other ways to do it

OptionWhen it is the better choice
A packer for separate PNG files (sprite sheet packer, TexturePacker)Each element already exists as its own file: no detection is needed, and a packer writes engine-specific atlas formats. See packing without TexturePacker.
Unity's Sprite Editor slicingThe sheet is only used in Unity and you want the rects stored in Unity's own import settings.
Godot AtlasTexture resources set by handTwo or three elements: point atlas at the sheet and type each region; no extra file at all.

What this page does not cover

  • One atlas page, at most 4096 × 4096, and no rotated packing.
  • No engine resource files: Godot .tres or Unity .meta are not written, only rects and border numbers.

Versions and sources

Measured in Chromium (Playwright) on Windows 11 for docs/UI-LAB.md: a 128 × 64 sheet with one button and a transparent hole gave 4 elements that merge distance 40 joins into one; packed pixels equal their source rects and extrude 1 duplicates the edge pixel outside the rect; borders 5/5/4/4 set on an element reach ui-atlas.json; a 1024 × 1024 sheet with 40 elements was detected, merged, packed and drawn in 76 ms. Loading the atlas in Godot or Unity was not run. Engine names above follow the Godot 4.7 documentation.

Official documentation used

UI Lab

Build nine-slice panels, button states, UI atlases and bitmap fonts in one workspace, then check them at real screen sizes.

How it works

  1. Add images
  2. Adjust settings and review the result
  3. Download a new file

Supported formats

PNG / JPG / WebP / AVIF / HEIC → PNG + JSON (ZIP) — Input decoding depends on browser support and optional engines.

What this tool does

Build nine-slice panels, button states, UI atlases and bitmap fonts in one workspace, then check them at real screen sizes.

Implementation and verified quality

advanced · nine-slice draw plan / parametric state ops / measured glyph metrics / exact EDT signed distance field. Quality qualification is in progress. Pro/Flagship quality has not been established.

Before you export

Writes PNG, JSON and BMFont text only. It never writes engine resource files (.tres, .meta), and rendering inside an engine was not verified here.

Frequently asked questions

What are this tool’s limitations?

Writes PNG, JSON and BMFont text only. It never writes engine resource files (.tres, .meta), and rendering inside an engine was not verified here.

Are my files uploaded?

This tool processes the files you open on your device without uploading them. Images you explicitly attach to community posts are uploaded separately. Optional engines and models are downloaded from third parties; those requests expose connection information such as your IP address.

Will my work be saved automatically?

No. Images and editing state stay in this tab; media output can use local temporary storage. Changing language preserves your work; reloading, closing the tab, or following a link to another page can clear it.