cap x base desc advance
a field guide

how to make a pure typeface

Think of a font as a stack of layers, each referring only to the one above it. You can't do layer N properly until layer N−1 is settled. Let's walk down.

Layer 0 — the ruler

the unit grid

Before anything, pick units per em (UPM). Usually 1000 or 2048. Every coordinate in the entire font is in these units. The em is a conceptual square; at font-size 16px, 1 em = 16px, and 1 UPM unit = 16/1000 px.

Everything below is measured in UPM. Change it late and every number in the font gets rescaled. Pick once, early.

Layer 1 — what varies

the designspace

Decide what is allowed to vary. Each axis is a named dimension with a min, max, and default:

wght
100–900, default 400
opsz
16–48, default 16
more
could add wdth, slnt, custom axes

That's it — your font lives inside an N-dimensional rectangle. Every glyph, every metric, every kern value will exist at every point in this rectangle, by interpolation.

Layer 2 — anchor points

masters

A master is a coordinate in the designspace, e.g. (100, 16), where you commit to hand-authoring everything. At each master you provide outlines, widths, anchors, a full kerning table, vertical metrics, and export-level OS/2 values — for every glyph.

Minimum masters = enough to span the space. One axis = 2 masters (the ends). Two axes = 4 masters (the corners). Extra masters correct non-linearity, so 400 isn't just a blend of the extremes.

Each master is a full parallel copy of the font. That's the cost of interpolation.

Layer 3 — drawing guides

per-master vertical metrics

Inside each master, set horizontal lines that act as reference rails for drawing:

baseline
0, always, by convention
x-height
top of lowercase x, o, n
cap height
top of uppercase H, E
ascender
top of h, l, k
descender
bottom of g, p, y — negative
overshoot
how much curves exceed caps to look visually equal

These are guides for you, the designer. They don't render directly; they exist so outlines align across glyphs and across masters. Keep them pinned so weights and optical sizes stay compatible.

Layer 4 — the drawing

outlines

Finally, the letter itself. For each glyph × master: nodes, curves, components. This is the part everyone thinks of as font design, but it's actually layer 4. The canvas above was drawn in the previous three.

contours
nodes you draw directly
components
reference another glyph — Aacute = A + acutecomb. Edit once, update everywhere.

Invariant: all masters must have compatible outlines for a glyph — same contours, same nodes, same order. Otherwise interpolation breaks. This is the single biggest ongoing chore.

Layer 5 — rhythm

horizontal spacing

Per glyph × master, three related numbers: the left sidebearing (x=0 to the leftmost point), the right sidebearing (rightmost point to the advance), and the advance width — their sum, the total space the glyph consumes.

Sidebearings are rhythm. n n n n should look evenly spaced. Tune n once, then derive other letters from it via metric keys. Spacing scales with weight — Black needs tighter sidebearings than Thin, because thicker stems occupy more room. That's why spacing is per-master.

Layer 6 — exceptions

kerning

Sidebearings give average spacing. Some pairs still look wrong: AV, To, Yo — the shapes lean into each other. Kerning is an adjustment applied only when two glyphs are adjacent.

It lives per master, and interpolates across the space — a Thin may barely kern, a Black may need −400 on AV. Groups let you kern classes instead of individual pairs, so you don't write ten thousand rules.

Layer 7 — runtime rules

OpenType features

Substitutions and positioning that fire at render time:

liga
fi → fi ligature
smcp
lowercase → small caps
kern
the kerning table, compiled
ss01–20
stylistic sets — alternate a, alternate g
locl
language-specific forms

Written in feature code, a tiny DSL. Often auto-generated from naming conventions, then hand-tuned.

Layer 8 — named outputs

instances & export metrics

An instance is a pin in the designspace with a name: Regular lives at (400, 16). No drawings, just a coordinate and a label. Exports produce one static file per instance, or the variable font uses them as named stops.

Separately, export-level metrics decide line height in apps. typoAscender, hheaAscender, winAscent — apps add ascent + descent + lineGap for the default. If a font has weird line spacing in Word, you fix it here, not in the drawings.

the waterfall, compressed

  1. UPMsets the ruler
  2. axessets what varies
  3. mastersanchor points in that variation
  4. vertical guideswhere letters sit
  5. outlinesthe letter shapes
  6. spacingrhythm between letters
  7. kerningpairwise exceptions
  8. featuresruntime rules
  9. instancesnamed outputs
  10. export metricshow apps render the result

Work top-down, edit bottom-up.
Establish layers 0–3 before you draw seriously. Then spacing. Then kerning. Every layer assumes the one above is stable.