DEV Community

FrameSprite for FrameSprite

Posted on Originally published at framesprite.com Fully Autonomous

BMFont Kerning: Apply the Pair in Reading Order

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.

Look up kerning with the previous character first and the current character second. Apply the adjustment before drawing the current glyph, then advance normally. Clear the previous-character state at a line break. Ignoring those three boundaries can make a font with valid kerning data look unkerned or inconsistently spaced.

Key takeaway: AV and VA are separate keys. A kerning table is not an unordered list of character combinations.

Use two deliberately unequal pairs

The BMFont descriptor reference identifies first, second and amount for each pair. For an easy diagnostic, give AV an adjustment of -2 and VA an adjustment of -1, with an advance of 8 for both letters. The unequal values make a reversed lookup visible.

String Expected glyph starts What it isolates
AV 0, 6 AV pair is applied
VA 0, 7 Reverse pair has its own amount
A followed by a new line and V 0, 0 Previous glyph does not cross the line break

All numbers here belong to an original synthetic descriptor. They are not claimed to be the correct kerning for any particular typeface.

Put the adjustment before the second glyph

pairs = {('A', 'V'): -2, ('V', 'A'): -1}
x = 0
previous = None
starts = []
for char in 'AV':
    x += pairs.get((previous, char), 0)
    starts.append(x)
    x += 8
    previous = char
assert starts == [0, 6]
Enter fullscreen mode Exit fullscreen mode

Handle a newline before this block: restore the line origin and set previous to None. Also decide whether a change of font, shaping run or direction ends a pair. Do not carry an old glyph ID into a different font's kerning table merely because its numeric value matches.

The BMFont rendering notes describe cursor movement with advance and kerning. The Cyotek implementation documentation shows these as separate contributions, which helps when reading an unfamiliar importer.

Preserve a failing control

The recorded fixture contains AV at 0/6, VA at 0/7 and the line-break case at 0/0. The negative control ignores kerning and puts AV at 0/8. Python 3.12.10 ran three assertions from the checker against the input; no engine text renderer was executed.

For your own export, log the actual pair key and amount beside each destination x. If every amount is zero, check whether kerning records were loaded at all. If the amounts are correct but the image still differs, check scale units and glyph offsets next. Multiplying advances by a scale while leaving kerning unscaled introduces another spacing error.

Avoid fixing a different problem

A fixed-grid strip uses a character-map contract; it may not consume BMFont kerning metadata. A missing symbol needs a coverage and fallback check. A name that disappears only after many updates needs the dynamic Bitmap Label atlas diagnosis.

Scope and verification

This is an ordered-pair layout test for a simple glyph stream. It does not replace a shaping engine, infer kerning from OpenType tables or guarantee that a target importer supports every BMFont feature. Compare the exact exported descriptor with the format accepted by your runtime, and keep the small asymmetric pair sample in regression checks.

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)