agentleFS
thrillmadethrillmade/agent-skills/skills/line-height-grid/SKILL.md

line-height-grid

Skill3 starsChanged 8 days agoMITView on GitHub

Use when calculating line-height for any font size in a grid-aligned design system. Names the two-track model (lh-ui = ceil(font × 1.20) snapped to the minor unit; lh-prose = ceil(font × 1.50) snapped to the minor unit), the picking heuristic per role (ui-track for headings / buttons / labels; prose-track for paragraph body), and worked examples for 4/8, 2/4, and 4/16 grids. Cite when an agent picks a unitless line-height multiplier without snapping to the system's grid.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    No token layer on disk — no grid declared, so there is nothing to snap to.

    line 22
  2. Very specific:

    When in doubt, ask: "is the user going to read multiple consecutive lines fluently?" If yes, prose.

    line 51
  3. Distinctive:

    Grid check: every lh value is a multiple of the minor unit.

    line 97
  4. Distinctive:

    If any check fails, recompute with stricter ceiling + snap-up.

    line 103

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Line-height grid

Line-height in a token-driven system is not a free multiplier — it's a snapped value on the spacing grid. UDTS uses two tracks: lh-ui (tight, for headings / labels / buttons) and lh-prose (loose, for paragraph body). Both derive from the font size and snap to the minor grid unit so adjacent paragraphs and successive lines preserve rhythm.

When to use

  • Picking line-height for any font size in a system that has a defined spacing grid.
  • Auditing line-heights that "look right but feel off" — usually a sign they're not snapped.
  • Setting up a foundation theme that needs both UI and editorial copy on the same grid.
  • Code review: flag any unitless line-height (line-height: 1.5) on a system token; replace with a snapped px value from the appropriate track.

When NOT to use

  • No token layer on disk — no grid declared, so there is nothing to snap to. A marketing splash built inside a system with a declared grid is still in scope.
  • Inline contexts where line-height inherits from the parent — the parent owns the grid alignment.

The two-track formulas

lh-ui(size)    = ceil(size × 1.20) snapped UP to nearest minor-unit multiple
lh-prose(size) = ceil(size × 1.50) snapped UP to nearest minor-unit multiple

The ratios are intentional:

  • 1.20 for UI: keeps headings, button labels, and control text tight enough that they don't take excess vertical space in dense layouts.
  • 1.50 for prose: matches the canonical typographic recommendation for fluent paragraph reading, and the same floor WCAG 1.4.12 requires products to tolerate under a user's own spacing override.

The ceil step ensures the line-height is never less than the natural typographic ratio; the snap step puts it on the grid for downstream rhythm.

When to use which track

RoleTrackWhy
Body paragraphs (long-form reading)proseFluent reading requires 1.5× space
Lead paragraphsproseSame as body
Headings (display through H6)uiTight space; headings stand on their own line
Button labels, link text, navigationuiDense, single-line; no fluent-reading constraint
Form labels, helper textuiCompact
Code blocksui (or code-tight variant)Code rows shouldn't have paragraph-style breathing room
Captions, metadatauiCompact

When in doubt, ask: "is the user going to read multiple consecutive lines fluently?" If yes, prose; if no, ui.

Worked examples

14 px font, 4/8 grid (minor unit = 4, major = 8):

lh-ui    = ceil(14 × 1.20) = ceil(16.8) = 17 → snap up to 20 (next multiple of 4)
lh-prose = ceil(14 × 1.50) = ceil(21.0) = 21 → snap up to 24 (next multiple of 4)

16 px font, 4/8 grid:

lh-ui    = ceil(16 × 1.20) = ceil(19.2) = 20 → snap up to 20 (already on grid)
lh-prose = ceil(16 × 1.50) = ceil(24.0) = 24 → snap up to 24 (already on grid)

14 px font, 2/4 grid (denser; minor = 2, major = 4):

lh-ui    = ceil(14 × 1.20) = ceil(16.8) = 17 → snap up to 18 (next multiple of 2)
lh-prose = ceil(14 × 1.50) = ceil(21.0) = 21 → snap up to 22 (next multiple of 2)

24 px font, 4/16 grid (spacious; minor = 4, major = 16):

lh-ui    = ceil(24 × 1.20) = ceil(28.8) = 29 → snap up to 32 (next multiple of 4)
lh-prose = ceil(24 × 1.50) = ceil(36.0) = 36 → snap up to 36 (already on grid)

Why "ceil then snap," not "snap to nearest"

Rounding down can put the resolved line-height below the natural ratio, which produces:

  • Diacritic clipping on larger sizes.
  • Visually cramped paragraphs in the prose track.
  • Inconsistent rhythm — sometimes you snap up, sometimes down, breaking baseline alignment.

ceil + snap-up is monotonic: line-height is always at least the ratio-derived value, and always on the grid.

Verification

After computing line-heights:

  1. Grid check: every lh value is a multiple of the minor unit.
  2. Ratio floor: lh(font) ≥ ceil(font × ratio) for both tracks. Never below.
  3. Monotonicity: lh values grow with font size (no decreases between adjacent steps).
  4. Track separation: at every font size, lh-prose > lh-ui (or equal at very small sizes where they collapse).
  5. Multi-line stack check: stack two paragraphs at the prose track. The total height = (lines × lh) + paragraph-margin lands on the major grid.

If any check fails, recompute with stricter ceiling + snap-up.

Cross-references

  • Routed here by: designing-a-design-system — the L1 dispatcher for building or extending a system.
  • REQUIRED BACKGROUND: type-scale — provides the font sizes this skill snaps line-heights for. The two skills are paired.
  • For the unit primitive that drives snapping: spacing-system — the minor / major grid is what snap up to nearest minor-unit multiple refers to.

Sources

  • The UDTS / token.design typography foundations spec.
  • Classical typography (Bringhurst, The Elements of Typographic Style) — the 1.5× rule for prose pre-dates digital systems.
  • WCAG 2.2 SC 1.4.12 — Text Spacing (AA) — the 1.5× line-height floor a product must tolerate under a user override; corroborates the prose ratio, not the UI one.
  • CSS line-height: where things go wrong — modern browser handling caveats.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.