UI StackLettering
Sites

What a treatment is

A treatment is one way of setting display text, written as a CSS recipe scoped by the class lt--{id}: an outline, a long shadow, a stacked hero, a word on a circle. Every treatment names the sizes it holds at (min, best and max, in px), what it needs from a font (a weight range, an italic, an axis, a class), the palette roles it paints with, and its own custom properties (--lt-stroke, --lt-angle) with defaults, so the stage's knobs, a world, or your own stylesheet can change them.

Typefaces stops at the pairing. Lettering shows what a headline in that pairing can become, on its palette, with your text. The site serves, in order: the hero of a landing page, a world's display treatment, big numbers, editorial devices, checking whether a pairing can carry a treatment, idea generation, and simple wordmarks.

The seven families

Strokes draw letters as lines; depth gives them shadows; colour fills them with gradients and Patterns (never images); axes use what a variable font can do; arrangement decides where the words go; editorial holds the devices of books and magazines; motion makes display text change, each reusing a Motion move. Each treatment also has a subject (headline, hero, numeral, initial, quote, label, wordmark) and a loudness: quiet, bold or loud, how much of the page it takes.

Requirements and matching

Typefaces knows every family's weights, italic, variable axes and subclass, so the site computes which pairings carry each treatment. The weight requirement asks whether the pairing's own heading weights include one in range; a few faces ship a single weight that Google labels 400 but that is drawn black (Archivo Black, Abril Fatface, Shrikhand and 33 more, listed in data/heavy.json), and those count at their drawn weight while the stage still sets them at 400, the only weight there is. The class requirement reads the subclass: a display sans is display and sans, a slab serif is serif and slab. Low contrast rules out didone and scotch faces, whose hairlines break under a stroke.

A pairing that passes every hard requirement scores 1, plus 0.2 for each preference it meets: its vibe words fit the treatment's loudness, its own palette is the treatment's palette, and its own heading weight already sits in range (or, for treatments with no weight range, in the loudness range: loud 700 and up, bold 500 and up, quiet 300 to 600). The stage lists the pairings that carry a treatment by score, with the rest below a line marked "will not carry it", and says why when you pick one. The Python matcher (tools/match.py) and the browser one (js/match.js) are checked against each other on every build.

Sizes and em

Every size inside a treatment is in em or a custom property, so the effect scales with the font-size the page sets: a stroke of .04em is 1.6px at 40px and 9.6px at 240px. px appears only in the record's sizes. The minimum is the smallest size at which the effect still reads; check.py renders every treatment there, in a 360px box, and fails it if the text overflows or clips.

Fallbacks and contrast

Every treatment says what the text looks like with the effect removed, and the detail page shows it: the treatment's css stripped and the pairing's fonts swapped for the system face. A treatment that makes the fill transparent sets a solid colour under @supports not and a plain colour for print, so a browser or a printer without the effect still shows the word. Contrast is measured on the rendered page: the fill, or the stroke for an outline, against the ground behind it at the first, middle and last letter, at least 3:1, and 4.5:1 for text that goes under 24px.

Stacking

The catalogue holds single treatments; the stage and the export allow two. The treatment with structure (an arrangement, lines, an SVG) stays inside and the effect wraps it, reaching its text runs by inheritance or through the .lt-t spans every template writes. Two treatments stack only when neither sets a property the other sets: an outline and a hard shadow (a stroke and a text-shadow), a stacked hero and a long shadow would not (both set the colour). Depth treatments never stack with each other, since they all set text-shadow.

Lookbooks

A lookbook starts from a pairing: lookbook.html?id=<pairing> shows the pairing's heading and body, then every treatment it carries, grouped by family, live in its faces, with one text for every cell and a palette select. Typefaces links to it from every pairing page ("What this pairing can do"). It is the page to open first when a landing page needs a hero, or when you need to know whether a pairing can carry a treatment at all; the list of what it will not carry says why.

Worlds

A world in Worlds can name a display treatment in its record (type.display: a treatment id, an optional stack partner, knob values). Its token sheet then carries the treatment's custom properties and a few display tokens (--display-fill, --display-stroke, --display-shadow, --display-track), the primitives sheet's .wp-display class applies them to any heading, and the world's brief names the treatment with a link back here. On the stage, the World select sets a world's sheet on the stage and uses the world's pairing.

The scorecard

Batch 001: strokes, depth and arrangement