Text
FastObjects draws text as sprites from a glyph atlas — each character is a
textured quad, and a whole TextBatch draws in one call. Text is built on the
same atlas/renderer as sprites, so it's fast and batched.
A font and a text batch
import fastobjects as fo
win = fo.Window(800, 600)
font = fo.Font(size=28) # built-in scalable font
labels = fo.TextBatch(font, capacity=500)
labels.write("Hello, FastObjects!", x=20, y=20)
labels.write("Acentos: ação!", x=20, y=60, color=(0.6, 0.9, 1.0, 1.0))
Font(size)rasterizes a character set into a glyph atlas once. The default character set covers printable ASCII and Latin-1 (accents like á, ç, ã, é work out of the box). Passchars="..."for a custom set.TextBatch(font, capacity)—capacityis the maximum number of glyphs across all livewrites.write(text, x, y, color=(1,1,1,1), anchor="topleft")returns aSpriteGroupover the glyph quads, so you can move or recolor the whole string:label.pos += (0, 5),label.color = (1, 0, 0, 1).
Newlines (\n) start a new line; anchor="center" centers the text block on
(x, y).
Dynamic text (score, FPS)
For text that changes every frame, clear() and write() again — no per-string
surface, no reallocation:
hud = fo.TextBatch(font, capacity=200)
@win.frame
def update(dt):
hud.clear()
hud.write(f"Score: {score}", x=20, y=20)
win.clear(0.1, 0.1, 0.1)
win.draw(hud)
Measuring
font.measure(text) returns the (width, height) of a string's block without
drawing — useful for positioning or centering yourself:
w, h = font.measure("Game Over")
label.write("Game Over", x=(800 - w) / 2, y=(600 - h) / 2)
Custom fonts
Font takes the font first, pygame-style — a .ttf/.otf path or the name
of an installed system font. None (the default) uses Pillow's built-in font.
hud = fo.Font("assets/PressStart2P.ttf", 16)
system = fo.Font("arial.ttf", 24) # searched in the system font dirs
Character sets
The atlas rasterizes one fixed set of characters, chosen at construction:
fo.Font("arial.ttf", 24) # "latin" (default): ASCII + Latin-1
fo.Font("arial.ttf", 24, charset="cyrillic") # Ѐ-џ only — no ASCII
fo.Font("arial.ttf", 24, charset=("latin", "greek", "cyrillic")) # mixed text
fo.Font("arial.ttf", 24, chars="0123456789/:") # full control (wins over charset)
Presets: "ascii", "latin", "latin-ext", "greek", "cyrillic".
Presets are independent — combine them in a tuple for mixed text. A character
the font file doesn't cover renders as that font's tofu box; a character
outside the atlas charset is skipped (drawn as a space).
Complex text: RTL, kerning, ligatures
Install the optional shaping extra and Font upgrades itself — Arabic and
Hebrew come out connected and in the right order, and kerning pairs apply:
pip install fastobjects[shaping]
font = fo.Font("arial.ttf", 24)
font.shaped # True when the extra is installed (False = simple layout)
labels.write("سلام عليكم", x=20, y=20) # correct contextual forms + RTL
With shaping active the atlas contains every glyph in the font (ligatures
and contextual forms have no character of their own), so charset/chars
only choose which characters appear in the public font.glyphs dict. A line
mixing LTR and RTL uses the dominant direction detected by HarfBuzz — full
bidi is a known limit. Without the extra, Font falls back to the simple
per-character layout (fine for Latin/Greek/Cyrillic).
A complete example
See examples/text_hud.py
(static labels + a live FPS counter).