Why Wednesday

Nine-Slice Sprites, Explained: How One Small Image Stretches Into a Panel of Any Size

What a nine-slice sprite is, how the nine regions stretch differently, and how to set it up in Unity 6, plus what to watch for when it goes wrong.

Concepts · By Game Design Jar · · P.18

A nine-slice sprite is one small image that can stretch into a panel of pretty much any size without the corners going blurry or the edges looking smeared. It’s how a dialogue box, a health bar frame, or a button can be one tiny piece of art in your project and still fill whatever space your UI needs while the game is running.

What a nine-slice sprite is

Take a small image, like a rounded rectangle panel with a border, and cut it into a 3x3 grid: four corners, four edges, and one center piece. When you resize the whole thing, the corners stay exactly as you drew them. The top and bottom edges only stretch sideways, the left and right edges only stretch up and down, and the center stretches both ways to fill whatever’s left over.

You’ll also hear it called nine-patch, especially if you’ve done any Android UI work, since that’s the name the format has had there for years. It’s the same idea with a different label depending on which engine or platform you’re using.

The problem it solves

If you take a flat image of a UI panel and just scale the whole thing up, the corners scale with it. A nice crisp 4-pixel rounded corner turns into a blurry 16-pixel blob, because you’re stretching art that was never meant to stretch. With pixel art it’s even worse, since the border thickness changes with the panel size. A health bar might have a hairline border at one size and look like it was outlined with a marker at another.

Before nine-slicing, the fix was drawing a separate panel for every size you needed. That’s manageable if you only have a handful of fixed UI elements, but it gets miserable as soon as a panel has to resize based on what’s inside it, like a dialogue box that needs to fit one line of text one moment and six the next.

Nine-slicing gets around this by only stretching the parts of the image that can handle it (the flat edges and the flat middle) and leaving the parts that give the panel its shape (the corners) alone.

How the nine regions actually work

Picture that 3x3 grid again:

  • Four corners: never scaled. They’re drawn pixel for pixel, every time.
  • Top and bottom edges: stretched (or tiled) horizontally to fill the width, but they keep their height.
  • Left and right edges: stretched (or tiled) vertically, but they keep their width.
  • Center: stretched or tiled both ways to fill whatever space the borders don’t take.

The lines that decide what counts as a corner, an edge, or the center are called the slice borders, and they’re measured in pixels in from each side of the image. If you set them wrong, you’ll either drag part of your border art into the stretchy middle, or you’ll leave a sliver of the middle stuck inside a corner that’s supposed to stay fixed.

Setting the borders in Unity 6

In Unity 6 you set this up in the Sprite Editor (it comes with the 2D Sprite package, which the 2D templates already include). Select your sprite in the Project window, set its Sprite Mode to Single (or Multiple if it’s part of a sheet), and click Sprite Editor. You’ll see small green handles on each side of the sprite. Drag them inward to set the left, right, top, and bottom borders, or type the numbers into the Border fields in the Sprite panel if you’d rather be exact. Whatever’s left in the middle becomes your stretchy center.

How you use it next depends on where the sprite lives:

  • On a SpriteRenderer (in the game world), change Draw Mode from Simple to Sliced or Tiled. There’s one catch I wish someone had told me: go back to the sprite’s import settings and set Mesh Type to Full Rect. With the default Tight setting, Unity shows a warning and the slicing doesn’t work.
  • On a UI Image (inside a Canvas), the same setting is called Image Type, and you set it to Sliced or Tiled.

Sliced stretches the edges and center to fill the new size, while Tiled repeats them instead. Tiled is the one you want for pixel art borders with a repeating pattern, like a row of dots or little rivets, since stretching a pattern squishes it.

The setting that tripped me up for a while is Pixels Per Unit Multiplier on the UI Image, which appears once Image Type is Sliced or Tiled. It changes how thick the borders show up on screen without touching the sprite’s import settings. Raising it makes the borders thinner and lowering it makes them chunkier, which feels backwards at first. If your panel’s border looks thicker or thinner than the rest of your pixel art, check this value along with the sprite’s base Pixels Per Unit. If PPU in general is still a bit fuzzy, my Pixels Per Unit explainer goes over why it controls how big and how crisp things look.

A small code sketch: resizing at runtime

The two places I end up resizing a nine-slice panel in code are a SpriteRenderer out in the world (like a floating name plate) and a UI Image (like a dialogue box or menu panel). They get resized in different ways.

For a SpriteRenderer set to Sliced, you set the size property directly, in world units:

// Unity 6, SpriteRenderer with Draw Mode set to Sliced
SpriteRenderer panel = GetComponent<SpriteRenderer>();
panel.size = new Vector2(3.5f, 1.2f); // width, height in world units

For a UI Image, you resize its RectTransform, and the Image (with Image Type set to Sliced) picks up the borders from the sprite on its own:

// Unity 6, UI Image with Image Type set to Sliced
RectTransform rect = GetComponent<RectTransform>();
rect.sizeDelta = new Vector2(320f, 96f); // width, height in canvas units

A heads up on that second one: sizeDelta is only the actual width and height when the anchors are all at the same point. If your anchors are spread out to stretch with the parent, sizeDelta becomes an offset from the parent’s size, and the numbers won’t mean what you expect.

Neither snippet touches the border values, because those live on the sprite asset and stay put no matter how big the panel gets. You resize the container and the nine regions sort themselves out inside it.

Drawing the source art in Aseprite

Aseprite does know about nine-slicing. If you draw a slice with the Slice tool and open its properties, there’s a “9-Slices” option that marks the center area, and that info gets saved in the JSON data when you export. As far as I know, though, Unity doesn’t read those borders by itself, so I still end up setting them in the Sprite Editor. For me the real value of doing it in Aseprite is drawing the art with slicing in mind from the start.

A few habits that help:

  • Keep the border the same thickness in whole pixels on every side, like 4 pixels all the way around, not 4 on the left and 5 on the right.
  • Keep the stretchy part of each edge actually flat. Diagonal lines or gradients running across it will look stretched or skewed once Unity scales that strip.
  • Keep any decoration that needs to hold its shape, like a little flourish on a corner, fully inside the corner area instead of hanging over into the edge.

It’s a lot like setting up tiles for a tilemap, where the seams need to disappear at every size and not just the one you drew. If you’re getting your sheets into Unity, my post on Aseprite features I ignored for two years covers the export and padding settings that avoid a lot of import headaches.

What the same idea is called elsewhere

In Godot 4 it’s a NinePatchRect, a UI node where you set the patch margins (left, top, right, bottom) right in the inspector, along with settings for whether the edges stretch or tile.

In Unreal Engine’s UMG, you set an Image widget’s brush to draw as Box, and the margins are fractions of the image (between 0 and 1) rather than pixel counts. Everything else works the same way: corners fixed, edges stretching one way, center stretching both ways.

So if you ever switch engines, the settings line up pretty closely once you know the name to look for.

When to reach for it

Any UI element that has to resize to fit its content is a good fit: dialogue boxes, tooltips, inventory slots, bordered health or mana bars, and buttons with labels of different lengths. Basically anywhere a fixed-size image would leave you either drawing ten versions of the same panel or living with one that’s always a bit too big or too small.

One thing to know for health bars in Unity: the Filled image type ignores slice borders, so a bar that drains by fill amount will squish its end caps. For a bordered bar, I resize the width of a Sliced image instead, or put a separate fill image inside the frame.

When not to

A few cases where nine-slicing isn’t the right tool:

  • Pixel art UI that gets scaled by odd amounts. Stretching a flat edge by a weird number of pixels is fine, but if the whole panel gets scaled by something like 1.5x (a Canvas Scaler set to scale with screen size will do this), the corners get scaled too and end up with uneven pixels. Test at the resolutions you’re actually targeting.
  • Detailed ornaments along the edges. If your border has gems or rivets that need to line up perfectly, Tiled mode helps, but drawing a separate panel for each size might honestly look better.
  • Art that only ever shows up at one size. If a panel never resizes, nine-slicing is extra setup for nothing, and a plain sprite is simpler.
  • Plain repeating backgrounds. If there’s no border and you just need a pattern to fill a space, a tiling texture is the simpler choice.
  • Bars that only grow sideways. A simple health bar often only needs fixed end caps and a stretchy middle. In Unity that’s just a nine-slice with the top and bottom borders set to 0.

How to tell it’s gone wrong

These are the problems I’ve run into most:

  • Stretched or smeared corners. The borders are usually set too small, so part of the corner art is sitting in an edge region and getting stretched.
  • Visible seams between regions. On pixel art, Filter Mode is often set to Bilinear, which blends pixels across the slice lines. Switch it to Point (no filter). If that doesn’t fix it, set Compression to None, and if the sprite is in an atlas, add a little padding so it doesn’t pick up its neighbors’ pixels.
  • Edges that shimmer or crawl while the panel animates or resizes. The panel is landing on in-between pixel positions or sizes on some frames. For UI, try the Pixel Perfect checkbox on the Canvas first. For world-space sprites it’s the same snapping issue as a jittery camera, and the fix is similar to what keeps a pixel-perfect camera from doing it to your whole screen.

So, if a nine-slice panel looks off, it’s most likely one of those three things.

nine-sliceunityuipixel-artasepritegame-design-theory

Registration card

Register to receive one focused post every weekday — engine tutorials, marketing tactics, and design craft. Free, unsubscribe anytime.

No spam. We never share your address. No purchase necessary — it's free.