Quick answer: Use a pixel font at its design size with AA off. For variable sizes, render at integer multiples of the target.
A roguelike renders HUD text at 8pt. Anti-aliasing turns crisp glyphs into smudges. The font wasn’t designed for that size.
Pixel Fonts
Source a pixel-friendly font (Pixel Operator, NicoBold). Use at its native size (often 8, 16, 32). Disable AA:
font = pygame.font.Font("pixel.ttf", 8)
surf = font.render("HP: 100", False, (255, 255, 255)) # AA off
Crisp; designed to render exactly at this size without sub-pixel spread.
Integer Scaling
To display larger, render at 8pt then scale by integer factor:
scaled = pygame.transform.scale(surf, (surf.get_width() * 2, surf.get_height() * 2))
Nearest-neighbor preserves pixel edges. Smooth scale (smoothscale) softens; only use for non-pixel-art look.
For Vector Fonts at Small Size
If you must use a TTF at small size, consider:
- Sub-pixel AA: not directly supported in Pygame.
- Render at 2× with AA, scale down with smoothscale — SSAA pattern.
- Switch to
pygame.freetypemodule — better small-size hinting.
Freetype Module
import pygame.freetype
face = pygame.freetype.Font("font.ttf", 8)
surf, rect = face.render("HP: 100", (255, 255, 255))
Freetype has hinting support; better small-size legibility than pygame.font for vector fonts.
Verifying
HUD readable at design size. Compare side-by-side: AA on vs off. Pixel font with AA off wins for retro aesthetic.
“Pixel fonts + AA off, or vector + freetype. Two paths to crisp small text in Pygame.”
For multi-language games, find a pixel font with extended glyph coverage (Cyrillic, accents) — not all retro pixel fonts include them.