technique

UI and text in pixel art

How to draw menus, fonts, panels, icons, and gauges that share the game's pixel size, stay readable on a phone in sunlight, and survive translation.

Before this

This page assumes you are comfortable with:

Why you need this

The interface is on screen more than any single sprite: the health bar, the score, the dialogue box, the pause menu. It is also the part most often bolted on late, drawn at a different scale, and rendered with the engine's default smooth font. A 1x interface floating over 3x game art reads as two products stapled together, and the player notices even when they cannot say why. This page is stage 4 of the pipeline, "build the world", applied to the layer between the player and the world.

The idea

One rule governs everything else: the UI shares the game's pixel size. If the world is drawn at 1x and displayed at 3x, every pixel of every letter, panel, and icon is also a 3 by 3 block on screen, aligned to the same grid. Text rendered by the operating system, vector icons, and anti-aliased rounded corners all break this rule and all look wrong in the same way: too fine, too smooth, from somewhere else.

Pixel fonts

A pixel font is a set of letter drawings on a fixed grid. Its size is given by cap height, the height of a capital letter in pixels. The x-height is the height of a lower-case x, the baseline is the row the letters sit on, and the descender is how far g, p, and y drop below it.

Cap height x-height What it can show Where it works
5 px 3 to 4 px Capitals; lower case is barely possible (a, e, s become blobs) Scores, short labels, damage numbers
7 px 5 px Readable lower case with a 1-px stroke; a and e have open counters Dialogue, menus, most body text
9 px 6 to 7 px Lower case with room for a bold variant and true curves Titles, large-screen games

Rules that hold across sizes: strokes are 1 pixel wide, letter spacing is 1 pixel, and line height is the glyph box (cap height plus descender) plus 1 or 2 pixels of leading. For a 7-px cap with a 2-px descender the glyph box is 9 rows and the line height is 11 px.

The letters A and g at 7-px cap height, with 1 px between them. The A is 5 wide and the g is 4 wide, so different letters have different widths; that is a proportional font. A monospaced font gives every letter the same cell, which is easier to lay out and wastes room on i and l.

. # # # . . . . . .
# . . . # . . . . .
# . . . # . . . . .
# . . . # . . . . .
# # # # # . . # # #
# . . . # . # . . #
# . . . # . # . . #
. . . . . . . # # #   <- baseline is the row above this one
. . . . . . . . . #
. . . . . . # # # .

# ink, . background. Rows 0 to 6 are the cap height; rows 7 and 8 are the descender.

The g's bowl spans rows 2 to 6 (the x-height, 5 rows) and its tail drops 2 rows below the baseline. Every letter in the font must agree on those three numbers or a line of text will look like it is bouncing.

9-slice panels

A dialogue box has to be any width and any height, but a border drawn as a single image stretches its corners into smears. A 9-slice panel cuts one small source image into nine regions. The four corners are drawn at their original size, the four edges are repeated along their length, and the center is filled.

Source, 8 by 8, with 3-px corners and 2-px edges, labelled like a number pad:

1 1 1 2 2 3 3 3
1 1 1 2 2 3 3 3
1 1 1 2 2 3 3 3
4 4 4 5 5 6 6 6
4 4 4 5 5 6 6 6
7 7 7 8 8 9 9 9
7 7 7 8 8 9 9 9
7 7 7 8 8 9 9 9

The same panel drawn at 14 by 10. Corners 1 3 7 9 are untouched; edges 2 4 6 8 repeat; center 5 fills:

1 1 1 2 2 2 2 2 2 2 2 3 3 3
1 1 1 2 2 2 2 2 2 2 2 3 3 3
1 1 1 2 2 2 2 2 2 2 2 3 3 3
4 4 4 5 5 5 5 5 5 5 5 6 6 6
4 4 4 5 5 5 5 5 5 5 5 6 6 6
4 4 4 5 5 5 5 5 5 5 5 6 6 6
4 4 4 5 5 5 5 5 5 5 5 6 6 6
7 7 7 8 8 8 8 8 8 8 8 9 9 9
7 7 7 8 8 8 8 8 8 8 8 9 9 9
7 7 7 8 8 8 8 8 8 8 8 9 9 9

1 3 7 9 corners (fixed), 2 8 top and bottom edges (repeated horizontally), 4 6 left and right edges (repeated vertically), 5 center (filled).

Edges stretch by repetition, not by scaling, so an edge with a 2-px pattern should be stretched by multiples of 2 or the pattern breaks at one end. A 1-px-wide edge pattern has no such constraint and is the safe default. The panel's final width and height are whole pixels at 1x, always.

Icons at 16 px

Same order as a character: silhouette first, then 2 to 3 colors, then a 1-px outline or none, consistently across the whole icon set. A potion is a bottle shape before it is red. Test each icon by filling it black; if a sword and a wand look alike in black, they will look alike in the inventory.

. . . . . 1 1 1 . . . . . . . .
. . . . . 1 3 1 . . . . . . . .
. . . . . 1 3 1 . . . . . . . .
. . . . 1 1 3 1 1 . . . . . . .
. . . 1 2 2 2 2 2 1 . . . . . .
. . 1 2 2 3 2 2 2 2 1 . . . . .
. . 1 2 2 2 2 2 2 2 1 . . . . .
. . 1 2 2 2 2 2 2 2 1 . . . . .
. . . 1 2 2 2 2 2 1 . . . . . .
. . . . 1 1 1 1 1 . . . . . . .

. transparent, 1 outline #1a1420, 2 liquid #c7321f, 3 highlight #f2b784. Light from the upper left, so the highlight sits on the upper-left of the bottle.

Health bars and gauges

A gauge is a rectangle whose fill width is a whole number of pixels. Compute it as Math.floor(width * current / max) and never draw a fractional end: an anti-aliased end pixel is a different color from every other pixel on screen and reads as a smudge. A 20-px bar shows health in steps of 5 percent, which is fine; if the design needs finer steps, make the bar longer, not smoother.

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 1
1 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1 outline #1a1420, 2 fill #c7321f, 3 empty #3a3a3a. Inner width 20, fill 13 of 20: Math.floor(20 * 65 / 100) = 13.

Contrast on a phone in sunlight

Value is how light or dark a color is, ignoring hue. Text survives on a phone outdoors when its value is far from the panel behind it. The rule of thumb from Color basics is a contrast ratio of at least 4.5:1 between text and background; near-white text on a near-black panel clears that by a wide margin, mid-gray text on a mid-blue panel fails it and vanishes in glare. Hue contrast (red on green) does nothing for readability if the values match. If a panel must be mid-value, give the text a 1-px dark outline or drop shadow at the lower right, which is a value change without a second font.

Safe areas and touch targets

A touch target is the on-screen region that registers a tap, and the usual rule of thumb is at least 44 screen pixels on a side. Convert that to art pixels by dividing by the display scale.

Display scale 44 screen px in art px 16-px icon on screen Hit region needed
2x 22 32 px 24 by 24 art px (4 px padding per side)
3x 14.67, round up to 15 48 px 16 by 16 art px; the icon's own cell is enough
4x 11 64 px 16 by 16 art px; generous

At 3x a 16-px icon already covers 48 screen pixels, so the icon's cell is a valid target as long as the hit region is the full cell and not the drawn silhouette. At 2x the same icon needs 4 px of invisible padding on each side. A safe area is the part of the screen not covered by a notch, a rounded corner, or a system gesture bar; keep every interactive element inside it and let only decoration reach the edge.

Localization

Text length changes with language: a word that is 5 letters in English can be 12 in German and 2 characters in Japanese, and those 2 characters need a taller font than 7 px to be legible. Plan panel widths for 30 to 50 percent more text than the English draft, let 9-slice panels grow rather than fixing their size, and prefer icons with a text label under them to text alone. A font with only ASCII letters is a font that will be redrawn.

In a game's art pipeline

Stage 4, build the world. The UI's pixel size and display scale come from stage 1 (Pixel art fundamentals); the same integer scale and nearest-neighbor filtering rules from Sprite sheets and export apply to the font sheet and the panel sheet. UI colors come from the game palette (Palettes and ramps), usually one neutral ramp for panels plus one accent. Icons are tiny sprites and follow Character design for sprites in miniature.

Common mistakes

  • System font over pixel art. Smooth gray-edged letters float above crisp tiles. The font must be a pixel font drawn at the game's pixel size.
  • UI at a different scale. 2x panels over 3x world art. Everything is crisp and it still looks wrong, because the pixel sizes disagree.
  • Anti-aliased gauge ends. A single blended pixel at the end of the health bar, visible every time health changes.
  • Panels stretched by scaling. The corners of the dialogue box are blurred and the border thickness changes with the box size. Use 9-slice.
  • Text on a mid-value panel. Readable at your desk, gone in daylight. Fix the value contrast.
  • Panel widths fixed to the English strings. The German build overflows every box.

Cost

A 7-px font with upper case, lower case, digits, and punctuation is about 95 glyphs, each a few minutes: a day's work. Panels and a starting icon set are another day. File size is nothing; a whole font sheet is a few kilobytes. The expensive part is changing your mind: the cap height fixes the line height, which fixes the dialogue box height, which fixes how much text fits per page, which fixes how the writing is chunked. Switching from 5 px to 7 px after the dialogue is written means redrawing the font, resizing every panel, and re-chunking every conversation. Decide the cap height first, at the target display scale, on the target device, and then draw.

Going further

  • Color basics, for value and the contrast ratio behind the 4.5:1 rule.
  • Sprite sheets and export, for shipping the font and panel sheets at the same scale as the world.
  • Pixel art fundamentals, for picking the display scale from the screen size.
  • Anti-aliasing in pixel art, for the few places a font at 9 px or larger can use a mid-tone pixel on a curve.
  • Palettes and ramps, for a neutral panel ramp that sits behind every text color.

Back to Pixel art for games