9-Slice Editor — Nine-Patch Borders for Godot and Unity
Borders are four numbers in source pixels. The editor suggests them from the longest run of identical columns and rows, lets you drag, type or nudge them, and renders every target size with corners that never change.

- Nine-sliceMeasured· Pillow
- Bitmap fontMeasured· independent .fnt parser
- Button statesMeasured· Pillow
- Engine importUNVERIFIED
What it does
- Border suggestion from identical columns/rows, shown with the run it came from (never applied silently).
- Stretch or tile edges; tiles repeat at their natural size and the last tile is clipped.
- Corners are never scaled (checked at 100×40, 300×80, 800×200, 420×120): the same bytes in Chromium; in Firefox semi-transparent corner pixels can shift by one alpha-rounding step.
- Export: previews, nine-slice.json with pixels, normalised values, Godot patch_margin_* and Unity border (L, B, R, T), and SETUP.md.
How to do it
- Drop the panel or button PNG.
- Accept the suggested borders or drag/type them (arrow keys nudge 1 px, Shift 10 px).
- Preview at your target sizes, stretch or tile.
- Export the ZIP.
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
What order does Unity use?
Unity's Sprite Editor border is Left, Bottom, Right, Top with a bottom-left origin; the JSON writes it in that order and names it.
Was it tested inside Godot or Unity?
No. The numbers are the ones those engines document; rendering in the engines was not run.
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).