Typography & Text Rendering

By Pritesh Yadav 10 min read

Text is the part of a design people actually read. A logo can be vague and still work; a price, a phone number, or a paragraph of legal fine print cannot. This section teaches you how text really works inside a computer and on paper — from the letters you type, to the shapes that get drawn, to the pixels and ink that finally appear. We start with the most basic and most-confused idea: the difference between a character and a glyph.

1. Characters vs glyphs — the foundation

Character
The abstract meaning of a letter or symbol — the thing you type and store. The computer records it as a Unicode code point, a universal ID number. The capital letter A is U+0041 everywhere on Earth.
Glyph
The actual drawn shape on screen or paper. One character can be drawn many different ways depending on the font.

The relationship between characters and glyphs is not one-to-one, which trips up almost every beginner:

  • One character → many glyphs: the letter "a" can be drawn as a normal "a", a small-cap "A", or a fancy swash alternate.
  • Many characters → one glyph: the two characters "f" and "i" often join into a single ligature shape "fi".
  • One character → zero glyphs: a combining accent mark may have no standalone shape; it just modifies its neighbour.

Inside the font, a table called the cmap ("character map") translates each Unicode code point into a default glyph. Then the font's layout features can substitute or reposition glyphs from there.

Common Mistake — Assuming "the font has the letter" is enough. A code point can be mapped but the font may have no glyph for it — you then see .notdef, the "tofu" box □. A storefront brand that uses an emoji or a rare currency symbol in a font that lacks it will print a box, not the symbol.

2. Font formats — what those file extensions really mean

A font is a file full of glyph outlines plus metric tables. Over 40 years the industry settled on a family of formats:

FormatOutline mathNotes
PostScript Type 1 (.pfb/.pfm)Cubic BézierAdobe, 1984. The deprecated ancestor — end-of-life in Adobe apps since Jan 2023; these files no longer render. You'll only meet them in old archives.
TrueType (.ttf)Quadratic Bézier (B-spline)Apple + Microsoft, late 1980s. Famous for powerful "bytecode" hinting.
OpenType (.otf or .ttf)Either typeAdobe + Microsoft, 1996. The modern umbrella format.
WOFF / WOFF2EitherCompressed OpenType for the web. WOFF2 uses Brotli compression, ~30% smaller than WOFF.
Bézier curve
A smooth curve defined by a few "control points" — the math used to describe every letter outline. Cubic curves use more control points (smoother, heavier); quadratic use fewer (lighter, faster).

The key teaching point about OpenType: OpenType is a container, not a competitor to TrueType. An OpenType font wraps either outline type: TrueType/quadratic outlines (stored in a glyf table, usually saved as .ttf) or PostScript/CFF cubic outlines (Compact Font Format, usually saved as .otf). So:

Key Takeaway — .ttf vs .otf tells you the outline type inside, not "TrueType vs OpenType." Both files are OpenType. OpenType added Unicode (65,536+ glyphs, vs the old 256-glyph limit), one cross-platform file for Mac and Windows, and the advanced layout engine described next.

Variable fonts — one file, infinite weights

Added to OpenType in v1.8 (September 2016), a variable font stores a whole continuous "design space" in a single file. Instead of shipping 12 separate files (Light, Regular, Bold, …), one file interpolates between master designs along named axes (lowercase 4-character tags):

  • wght — Weight (1–1000)
  • wdth — Width (percentage)
  • ital — Italic (0 or 1)
  • slnt — Slant (degrees, typically −90 to 90)
  • opsz — Optical Size (in points)

Custom axes use UPPERCASE tags. Adoption climbed from ~11% of web pages in 2020 to ~33–34% in 2024 because one small file replaces dozens. For PF360's storefront, a variable font lets a theme nudge heading weight without downloading another file — fewer requests, faster pages.

3. The OpenType layout engine — how features work

Two tables do the clever typography, both keyed by 4-character feature tags:

GSUB (Glyph Substitution)
Decides which glyphs to use — swap "f"+"i" for the "fi" ligature, swap digits for small caps, etc.
GPOS (Glyph Positioning)
Decides where glyphs sit — kerning pairs, stacking accents onto letters.

The text shaper runs GSUB first, then GPOS (pick the glyphs, then position them). Useful tags:

  • GSUB: liga standard ligatures (fi, fl — on by default), dlig discretionary ligatures (st, ct — off by default), smcp small caps, onum/lnum oldstyle vs lining figures, frac fractions, salt/ssNN stylistic alternates/sets, swsh swashes.
  • GPOS: kern kerning, mark accent placement. Modern kerning lives in GPOS, not the old legacy kern table.

4. From outlines to pixels — the rendering pipeline

 [glyph outline]  ->  scale to size  ->  apply HINTS
   (Bézier pts)        (ppem grid)        (snap to grid)
        |                                      |
        v                                      v
   RASTERIZE  ->  anti-alias / subpixel  ->  composite
 (fill to pixels)   (ClearType RGB ~3x)      (on screen)
em / UPM (units per em)
The font's internal design grid. All measurements are in these units — typically 1000 (PostScript/CFF) or 2048 (TrueType) — then scaled by your point size.
ppem (pixels per em)
How many pixels tall the em box becomes at the chosen size. Small ppem = few pixels = hard to render cleanly.
Rasterize
Convert the vector outline into a grid of filled pixels.

Hinting

Hinting means instructions baked into the font that gently distort outlines to snap onto the pixel grid at small sizes / low resolution, so stems stay even and letters stay readable. TrueType hinting is a stack-based assembly bytecode run by an interpreter (a tiny virtual machine), stored in glyf/prep/fpgm tables — fonts like Verdana have thousands of hand-tuned lines. PostScript/CFF hinting is lighter and more automatic.

Common Mistake — Worrying about hinting for print. Hinting matters below ~24px on screens and low-DPI displays. At print resolution the rasterizer has so many pixels that hinting is nearly irrelevant. PF360's pdf-service (PDFKit + sharp at port 4000) renders at high resolution — don't burn time tuning hints there.

5. Typographic geometry — the text-tool vocabulary

ascender ---  b   d        l    <- tops above x-height
cap-height-   B   D   H         <- top of capitals
x-height ---  x   o   n  e      <- top of lowercase
baseline ===  x o n e B D b d l <- glyphs sit here
descender --      g   p   y     <- tails below baseline
Baseline
The invisible line glyphs rest on.
x-height
Height of a lowercase "x". A tall x-height reads better at small sizes.
Cap-height
Top of capital letters (usually a touch below the ascender height).
Ascender / Descender
Parts rising above x-height (b, d, h, k, l) / dropping below baseline (g, j, p, q, y).
Counter, bowl, overshoot
The enclosed space in "o"; the round stroke of "b"; the tiny amount round glyphs exceed the lines so they look optically equal to flat ones.

The classic spacing trio (clear this up once and for all)

Leading (line-spacing)
Vertical distance from one baseline to the next. Named after the lead metal strips printers slid between lines. Rule of thumb: point size + 2–4 pt, or 120–150% of size (12 pt body → ~14.4–18 pt). Longer lines need more leading.
Tracking (letter-spacing)
Uniform horizontal space across a whole run/word/line. Tighten big display headlines; add some to CAPS and small caps; never heavily track lowercase body text.
Kerning
Space between one specific pair of letters — fixing optical gaps in "AV", "To", "WA", "Ty", "Yo", "LT". Metric kerning uses the font's GPOS pairs; optical kerning is computed by the app.

Workflow order: leading → tracking → kerning (macro to micro).

Common Mistake — Calling tracking "kerning." Kerning is pairwise only. A control that spaces the whole line evenly is tracking, no matter what it's labelled.

6. Print legibility — the numbers that matter

  • Body text: 9–12 pt (10–11 pt is common). Around 8 pt is the floor where reading speed drops.
  • Line length (measure): 50–75 characters per line, 66 ideal. Too long and the eye loses the line on return.
  • Leading: 120–150% of size. Size, measure, and leading are coupled — change one, retune the others.
  • Black ink: body/small text should print as 100% K only (single-channel black), not rich 4-color black — registration misalignment fuzzes small 4-color text. Reserve rich black for large display type.
  • Avoid thin serifs and hairlines in reverse (white on dark) — ink gain fills the counters. Keep legal fine print to ~5–6 pt minimum.
  • Embed or outline all fonts in the print PDF (PDF/X) so the print engine (RIP) never substitutes a wrong font. Ligatures and kerning must survive flattening.
Real-world case — A PF360 customer types a phone number in 7 pt black using a default rich-black fill. On the proof it looks crisp (screen is RGB). At the press, the cyan/magenta/yellow/black plates are a hair out of register and the number prints fuzzy and ghosted. The fix: 100% K only, bump to 9 pt. Because the platform currently has no RGB→CMYK conversion and no preflight, nothing catches this automatically — it must be caught by design guidance and review.

7. PF360 designer text tool — the controls users see

The design studio (designer/) is built on Fabric.js. The text controls live in designer/src/views/Editor/CanvasRight/Components/ElementText.vue (toolbar) and ElementStylePanel/TextboxStylePanel.vue (style panel), with config lists in src/configs/texts.ts (FontSizeLibs, LineHeightLibs, CharSpaceLibs). Visible controls: font color picker; Font size +/−; Bold / Italic / Underline; horizontal align Left/Center/Right; vertical align Top/Middle/Bottom; and a "Spacing" row exposing line height and character spacing.

UI label / controlTypographic termImplementation note
Spacing → line heightLeadingFabric lineHeight is a unitless multiplier (default 1.16) — relative leading, not absolute points.
Spacing → char spacingTrackingFabric charSpacing is measured in 1/1000 em, not px or pt; PF360 steps it ±10. Per-character overrides are cleared (clearPerCharCharSpacing) so the global value applies uniformly.
(none)KerningNo true pairwise kerning UI — Fabric kerns by font metrics only. The "Spacing" control is tracking.
Common Mistake / UX flag — Per the project's plain-language rule, a single "Spacing" control hides two different concepts (leading and tracking) and risks being mistaken for kerning, which PF360 doesn't expose at all. Clearer labels would be "Line spacing" and "Letter spacing" — never "Kerning," since no pairwise control exists.
Best Practice — When preparing print-bound text in the designer: keep body text 9 pt+, set line spacing around 1.3–1.5, use letter spacing sparingly (tighten headlines, loosen CAPS), and choose a font with a generous x-height for small labels. Because there's no automated preflight or font-embedding guarantee in the order-to-production spine yet, treat these as manual checks before a job is sent to print.
Key takeaways —
  • Characters are meaning, glyphs are shapes — the mapping is not 1:1; a missing glyph shows a □ tofu box.
  • OpenType is the umbrella format. .ttf vs .otf = which outline math is inside (quadratic/glyf vs cubic/CFF), not "TrueType vs OpenType." PostScript Type 1 is dead since 2023.
  • Variable fonts pack many weights/widths into one file along axes (wght, wdth, ital, slnt, opsz) — fewer downloads for the storefront.
  • GSUB picks glyphs, GPOS positions them; rendering goes outline → scale → hint → rasterize → anti-alias. Hinting is a screen/low-DPI concern, not a print one.
  • Leading is vertical, tracking is uniform horizontal, kerning is pairwise. Don't confuse them; work macro to micro.
  • For print: 9–12 pt body, 50–75 chars/line, 120–150% leading, 100% K for small black text, embed fonts. PF360 has no auto RGB→CMYK or preflight — these are manual checks.
  • In the PF360 designer, "Spacing" = Fabric lineHeight (unitless leading multiplier) + charSpacing (tracking in 1/1000 em); there is no kerning control — label accordingly.

Continue reading