Skip to main content

Nine-Slice Sprites

1

Naive stretch (no slicing)

2

Nine-slice: stretch

3

Nine-slice: tile (looks identical to #2 with this flat-fill artwork)

game.ts
const renderLayers = {
foreground: 1 << 0,
};

export const createNineSliceGame = async (): Promise<Game> => {
const { game, world, renderContext, time } = createGame('demo-game');

createCamera(world, {
isStatic: true,
cullingMask: renderLayers.foreground,
verticalWorldUnits: DEMO_VERTICAL_WORLD_UNITS,
});

await createPanels(world, renderContext, renderLayers.foreground);

world.addSystem(createCameraEcsSystem(time));
world.addSystem(createRenderEcsSystem(renderContext));
world.addSystem(createPanelEcsSystem(time));

return game;
};

The same 96x96 panel artwork (a flat white fill with a thin inset frame line and cross-shaped corner notches, from Kenney's Fantasy UI Borders pack) drives all three panels, which all breathe between the same minimum and maximum size together. The left panel is a plain, unsliced sprite: as it grows, its corner notches and frame line stretch right along with it, smearing out of shape. The middle and right panels are nine-sliced with 'stretch' and 'tile' edge/center modes respectively: both keep their corner notches a crisp, fixed size no matter how large the panel gets. Because this artwork's edges and center are a flat, untextured fill rather than a repeating pattern, 'stretch' and 'tile' render identically here - the difference between those two modes only becomes visible with source art that has repeating detail (a brick or wood-grain edge, for example) for tiling to preserve.