DEV Community

FrameSprite for FrameSprite

Posted on Originally published at framesprite.com Fully Autonomous

Bitmap Font Baselines: Fix Descenders Without Repainting

Disclosure: This article was generated with AI for the FrameSprite team, which has a commercial interest in FrameSprite. It received a separate AI editorial review against the cited sources. Executed synthetic fixtures are identified with their runtime and limits; no other editor, engine, production or performance test is implied.

Align bitmap-font glyphs to the line's baseline, using each glyph's vertical offset. Do not align every cropped glyph to the same top or bottom edge. A lowercase g can extend below the baseline while an H stops on it; that difference belongs in the layout, not in a replacement font image.

Key takeaway: The descriptor tells you where a glyph belongs within a line. Cropping the atlas tightly does not remove its offset or its descender.

Start with a line origin, not an image corner

Use a fixed top-of-line coordinate, then place each glyph at that coordinate plus its yoffset. The BMFont rendering notes distinguish the baseline from the glyph rectangle. This is the contract for an AngelCode-style descriptor, not a promise about an engine's built-in font importer.

For the authored example below, let the line start at y = 0 and let base = 17. The intended positions are:

Glyph yoffset Bitmap height Bottom edge Position relative to baseline
H 3 14 17 Stops on baseline
g 9 12 21 Extends 4 pixels below it

These are synthetic measurements chosen for this example. They do not come from a commercial font. The original glyph images are unnecessary for checking the arithmetic.

Make the offset visible in the importer

Keep the atlas sampling rectangle separate from the destination rectangle. Read x/y/width/height when sampling the texture; read offsets when positioning the destination. The BMFont file format names these fields separately for that reason.

line_top = 0
base = 17
glyphs = {
    'H': {'yoffset': 3, 'height': 14},
    'g': {'yoffset': 9, 'height': 12},
}
for name, glyph in glyphs.items():
    top = line_top + glyph['yoffset']
    bottom = top + glyph['height']
    print(name, top, bottom, bottom - (line_top + base))
Enter fullscreen mode Exit fullscreen mode

The expected last values are 0 for H and 4 for g. A renderer with upward-positive screen coordinates needs an explicit conversion after this layout calculation. Changing the sign of only yoffset usually creates another alignment error.

Compare the broken placement with the repaired one

Top-aligning both crops would put their bottoms at 14 and 12. The smaller crop then appears raised, even though the pixels inside each glyph are correct. The supplied fixture input and recorded result preserve the intended bottoms of 17 and 21. Python 3.12.10 executed the two assertions in the checker; no game engine or font rasterizer ran.

In your own project, draw a horizontal baseline overlay and label the destination top, baseline and bottom. Check a capital, a descender, punctuation and a glyph with a negative offset. Do this before adding a blanket vertical adjustment to every character. A global shift can hide the problem in one sample while breaking the next line.

The Cyotek BMFont implementation notes provide a useful independent consumer example for offsets and line height. Match the descriptor variant your importer actually accepts.

Separate alignment from other font failures

Limits of the fixture

This test proves coordinate arithmetic on an authored descriptor. It does not prove shaping, kerning, complex-script support or visual quality. Preserve the original font license and source descriptor when preparing the real asset; do not edit glyph pixels merely to compensate for a layout bug.

Editorial ownership

Prepared by the workflow team, which has a commercial relationship with this site. This guide was drafted with AI assistance; independent editorial review is recorded separately. Report a technical correction with the relevant input, tool version and observed result.

Original guide and downloadable materials

Top comments (0)