Game UI Asset Lab — Slice a UI Sheet into a Padded Atlas
One workspace for game UI art: find the elements on a sheet, pack them with padding and extrude, give panels nine-slice borders, and check them at the resolutions they will really be drawn at.

- Nine-sliceMeasured· Pillow
- Bitmap fontMeasured· independent .fnt parser
- Button statesMeasured· Pillow
- Engine importUNVERIFIED
What it does
- Element detection from alpha islands with a merge distance (a button and its glyph become one element).
- UI atlas: MaxRects packing with padding and extrude; borders set per element travel into the JSON.
- Stages for nine-slice, button states, bitmap fonts and checks (sizes and anchors, safe areas, localisation overflow, WCAG contrast).
- Settings links: every non-image setting can be shared as a URL.
How to do it
- Drop the UI sheet.
- Review the detected elements, rename them, adjust the merge distance.
- Give panels nine-slice borders.
- Export the atlas PNG + JSON.
Outputs and how each was checked
"Measured" means the downloaded file was opened again outside the page (Pillow, numpy or an independent parser) and the property was measured. Loading these files in a game engine was not tested.
| Target | Files | Check |
|---|---|---|
| Nine-slice | nine-slice.json · previews · SETUP.md | Measured PillowEvery resized preview keeps all four corner blocks unscaled: the same bytes in Chromium; in Firefox semi-transparent pixels can shift by one alpha-rounding step. 0 gaps, 0 overlaps. |
| Bitmap font | font.png · font.fnt (BMFont text) · font.json | Measured independent .fnt parserThe .fnt was read back by a parser written separately in the test: header and every glyph rect match. |
| Button states | states/*.png · strip · states.json | Measured PillowNormal equals the source (byte for byte in Chromium; in Firefox semi-transparent colour within one alpha-rounding step); every rect in states.json cuts exactly its state out of the strip. |
| Engine import | Godot NinePatchRect · Unity Sprite border · BMFont import | UNVERIFIEDNot run in Godot or Unity. |
Evidence
Nine-slice corners unscaled at 100×40, 300×80, 800×200 and 420×120; border suggestion 6·6·6·6 from a run of 12 identical columns; button states: normal equal to the source, disabled grey at alpha 128, focus ring exact; .fnt glyph records equal the JSON; missing glyphs from a .po listed exactly; black on white measured 21:1. Images pass through a browser canvas: Chromium returns the same bytes; Firefox rounds the colour of semi-transparent pixels to one premultiplied step (measured on a Kenney button: up to 4 levels at alpha 63), while alpha and opaque pixels stay exact.
Limits
- No kerning pairs, one font page, no MSDF; the SDF output is Beta.
- A TTF's cmap is not parsed, so the missing-glyph check needs a .fnt or the Lab's own font.
- One atlas page; touching elements count as one.
- Rendering inside Godot or Unity was not run: the engine numbers (patch margins, L-B-R-T border) are documented, not engine-tested.
Questions
Why are two touching buttons one element?
Elements are alpha islands; touching art is one island. Separate them in the art, or cut the result in the nine-slice stage.
Does it write Godot or Unity resources?
No. It writes PNG + JSON with the numbers each engine needs (patch margins, L-B-R-T border) and a SETUP.md; engine import was not tested.
Is it free, and do I need an account?
Everything on these pages is free and works without an account. There is no watermark and no export that is held back.
Are my sprites uploaded?
No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.
Does it need Aseprite or an engine plugin installed?
No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).