Toolkitly

9-Slice Editor

Mark the four slice lines on a panel or a button, see it at any size with the middle tiled rather than stretched, and take away the PNG, a .9.png, or the numbers your engine asks for. Free, no sign-up, and every pixel stays in your browser.

Nothing is uploaded — the image is sliced and redrawn inside your browser.

How to set up a 9-slice

Four numbers, and one setting that decides whether the border survives.

  1. 1Load the panelDrag a PNG, WebP, GIF or JPEG onto the drop area, pick a file, or paste an image straight from the clipboard.
  2. 2Put the lines just inside what must not deformDrag them, or type the four numbers. Past a decorated corner; one or two pixels past a rounded border. The dashed rectangle between them is the part that repeats.
  3. 3Leave it on tileThen switch to stretch and back. On pixel art the difference is not subtle, and it is the reason this tool exists.
  4. 4Take the numbers or the fileThe four insets go straight into Godot or Unity. If you would rather ship a file, export the resized PNG or the .9.png.

Why the middle should tile, not stretch

Both do the same job: fill the space between the corners. They differ in what they do to the pixels while filling it.

Stretching maps the destination back onto the source and samples. A three-pixel border stretched across forty pixels has to make forty pixels out of three, and since the mapping is not a whole ratio, some source pixels become two destination pixels wide and others three. With smoothing on the border goes blurry; with smoothing off — which is what a pixel art pipeline uses — it stays sharp but its thickness visibly wobbles.

Tiling repeats the middle at its original scale. Every pixel is the size the artist drew it, always. The cost is that the middle must be something that survives repetition — a flat fill, or a pattern whose period divides evenly into the region.

CSS border-image stretches unless you say border-image-repeat: repeat. Godot's NinePatchRect stretches unless you set Axis Stretch Mode to Tile. Unity's sliced sprite stretches unless you pick Tiled. All three default to the wrong one for pixel art, which is why so many pixel UIs have a border that thickens as the panel grows.

The four numbers, per engine

Every implementation of this needs the same four distances, and they disagree only about what to call them and what order to write them in.

Godot puts them on a NinePatchRect as patch_margin_left, patch_margin_top, patch_margin_right and patch_margin_bottom. Named, so there is nothing to get wrong.

Unity puts them on the sprite: Sprite Editor → Border. The field is a Vector4 and its order is left, bottom, right, top. That is not the order anything else uses, and swapping the middle two produces a panel that looks nearly right until the top and bottom margins differ.

CSS writes them as border-image-slice in the order top, right, bottom, left — the same order as margin — with fill if you want the middle drawn.

Android and LibGDX do not take numbers at all: they read the one-pixel guide border of a .9.png, which is why that export exists.

When you need this

Dialogue boxes and panels

One 24×24 panel serves every size of window in the game, at a fraction of the texture memory of drawing each one.

Buttons that fit their label

A button whose width follows its text needs a border that does not thicken. This is the standard answer.

Health and progress bars

Rounded caps that stay the same size while the middle grows — a 9-slice with the top and bottom insets at zero.

Checking artwork before it ships

See what a panel does at 3× before it is in the engine, rather than discovering the border wobble in a screenshot.

Export formats

PNG at the previewed size — the sliced result as a flat image, for when the size is fixed and you would rather not do this at runtime.

.9.png — the artwork with a one-pixel guide border, the format Android and LibGDX read. The border is generated, so it does not have the stray pixel that gets hand-made ones rejected.

JSON — the four insets, plus the same numbers already arranged in Godot's names and Unity's order, so there is nothing to reorder by hand.

Setting it up in your engine

The margins are half of it; the stretch mode is the other half.

Godot

NinePatchRect, four patch margins, and Axis Stretch Mode → Tile on both axes. Leave the texture's filter on Nearest as well.

Unity

Sprite Editor → Border, then an Image with Image Type Sliced — or Tiled for pixel art. Filter Mode Point, Compression None.

CSS

border-image-slice with fill, border-image-repeat: repeat, and image-rendering: pixelated.

Frequently asked questions

What is 9-slice scaling?

A way of resizing an image so that its corners keep their original size while the edges and middle grow to fill the rest. It is how a dialogue box, a button or a health bar can be any size without its border thickening. The four numbers that define it are the distances from each edge to the slice line — everything else follows from them.

Why does my pixel art border look wrong when it stretches?

Because stretching resamples. A 3px border drawn by hand, stretched across 40px, becomes bands of two, three and four pixels — nothing is blurred, but the thickness is visibly uneven. Tiling repeats the middle at the size it was drawn at instead, so every pixel keeps its original dimensions. This tool tiles by default; CSS border-image and most engines stretch by default, which is where the problem usually comes from.

What numbers do I put into Godot?

A NinePatchRect has patch_margin_left, patch_margin_top, patch_margin_right and patch_margin_bottom, and they are exactly the four insets shown here. Also set Axis Stretch Mode to Tile for pixel art — the default is Stretch. The tool shows the four values in Godot's own order.

What about Unity?

Unity puts the same idea on the sprite itself: open the Sprite Editor and set Border. The catch is the order — Unity's border Vector4 is left, bottom, right, top, which is not the order Godot, CSS or Android use. Getting it wrong swaps your top and bottom margins, which looks almost right and is not. The tool prints the values in Unity's order so you can copy them straight across.

What is a .9.png?

The Android NinePatch format: the same artwork with a one-pixel border around it, where black pixels on the top and left edges mark which columns and rows may stretch. LibGDX reads them too. The border must be otherwise fully transparent — a stray pixel is read as a second stretch region, which is the usual reason a hand-made .9.png is rejected as malformed. The one this tool exports is generated, so it does not have that problem.

Where should I put the slice lines?

Just inside whatever must not deform. For a panel with a decorated corner, put them past the decoration. For a plain rounded border, one or two pixels past the curve. The middle region is what repeats, so it should be the part of the artwork that reads the same when it is doubled — a flat fill, or a pattern whose period fits inside it.

Are my images uploaded to a server?

No. The image is decoded, sliced and redrawn with the Canvas API inside your browser. Nothing leaves your machine, and the tool keeps working offline once the page has loaded.

Related guides

Related tools