Skip to content
Back to skills

Pretext

ASecurity

Pretext by Cheng Lou. Pure JavaScript/TypeScript library for fast, accurate multi-line text measurement and layout without DOM reflow. Use when text dimensions drive a layout decision: button or label overflow checks, text height before render, shrink-wrap or balanced text, virtualized lists and masonry, input autosizing, or layout-shift prevention on async text loads.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 16, 2026
ai-agentsjavascripttypescriptjavanodegitapi

Works with

  • cursor
  • cli
  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 16, 2026

npx -y skills add tommylower/cortex --skill pretext --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pretext?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Pretext
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tommylower-pretext/badge)](https://www.skillsdirectory.com/skills/tommylower-pretext)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pretext
description: "Pretext by Cheng Lou. Pure JavaScript/TypeScript library for fast, accurate multi-line text measurement and layout without DOM reflow. Use when text dimensions drive a layout decision: button or label overflow checks, text height before render, shrink-wrap or balanced text, virtualized lists and masonry, input autosizing, or layout-shift prevention on async text loads."
author: Cheng Lou (https://github.com/chenglou/pretext)
---

# pretext

Pure JavaScript/TypeScript library for multi-line text measurement and layout. Fast, accurate, language-aware, render-agnostic (DOM, Canvas, SVG, server-side). Side-steps DOM measurements (`getBoundingClientRect`, `offsetHeight`) which trigger layout reflow.

The library implements its own text measurement using the browser's font engine as ground truth. Measurements are pure arithmetic over precomputed widths. Highly AI-friendly: agents can verify "does this label fit?" without spinning up a headless browser.

## The text rule

> **Never trigger DOM reflow for text measurement. Precompute heights and widths in pure arithmetic. Keep text layout deterministic and verifiable without a browser.**

This rule applies whenever the project has:
- buttons / tags / chips with dynamic labels (verify they don't overflow)
- inputs with autosizing height
- virtualized lists or masonry layouts
- balanced-text heroes (binary-search a nicer wrap point)
- async text loads where layout shift would otherwise occur
- shrink-wrap text containers (tightest container width that fits the actual text content)

When one of those needs exact text dimensions before render, pretext is the implementation backbone: CSS alone cannot give them. The limits under "Don't reach for it when" still apply.

## When to reach for it

Reach for pretext when:
- you need text height BEFORE rendering (preallocate space, prevent layout shift)
- you need shrink-wrap (CSS `width: min-content` is wrong for multi-line; pretext gives the actual narrowest width that fits)
- you're building a virtualized list and need accurate per-item heights without rendering them
- you need balanced text wrapping (e.g., two-line headlines that don't have one orphan word)
- you need dev-time / agent-time verification that a label fits in a container at a given width
- you're rendering to Canvas, SVG, WebGL, or server-side (browsers' DOM measurement is unavailable)

Don't reach for it when:
- text is single-line and CSS `white-space: nowrap` + `text-overflow: ellipsis` solves the problem
- container width is fluid and you're fine with whatever wrapping the browser produces
- the text is decorative and exact measurements don't drive any layout decision

## Install (when adding to a project)

1. **Check if already installed.** Look for `@chenglou/pretext` in package.json dependencies. If found, report and exit.

2. **Install.**
   ```sh
   npm install @chenglou/pretext
   # or: bun add @chenglou/pretext
   # or: pnpm add @chenglou/pretext
   ```

3. **Add a measurement helper** at `src/lib/text-measure.ts` (or your project's lib path):
   ```ts
   import { prepare, layout, prepareWithSegments, measureLineStats, walkLineRanges, type LayoutCursor } from '@chenglou/pretext'

   // Sync font + letterSpacing string with your CSS exactly.
   // font follows canvas font shorthand: "500 16px Inter"
   // letterSpacing in CSS px

   export function measureTextHeight(text: string, font: string, maxWidth: number, lineHeight: number) {
     const prepared = prepare(text, font)
     return layout(prepared, maxWidth, lineHeight)
   }

   export function shrinkWrapWidth(text: string, font: string, maxWidth: number) {
     const prepared = prepareWithSegments(text, font)
     let widest = 0
     walkLineRanges(prepared, maxWidth, line => {
       if (line.width > widest) widest = line.width
     })
     return widest
   }

   export function fitsInOneLine(text: string, font: string, maxWidth: number) {
     const prepared = prepareWithSegments(text, font)
     const { lineCount } = measureLineStats(prepared, maxWidth)
     return lineCount === 1
   }
   ```

4. **Sync the font and letter-spacing strings with the project's tokens.** If `references/tokens.md` defines `--text-body: 16px / 24px / 0em / 400`, the pretext call must be `prepare(text, '400 16px <font-family>')` with `letterSpacing: 0`. If they drift, measurements drift.

5. **Confirm setup.** Tell the user pretext is installed and the helper is at `src/lib/text-measure.ts`.

## Project rule fold-in (which references file gets which rule)

When a project that uses pretext has a design-system package, fold these rules into the matching `references/*.md` files that exist. State each rule abstractly, without citing pretext (the client split in the `asbuilt` skill's package format: encode rules, not suppliers):

### `references/tokens.md` (typography section)

Add a rule near the type scale table:

> **Text dimensions are computed via a deterministic measurement helper, not via DOM reflow.** Components that depend on text height or width must call the project's text-measure helper, not `getBoundingClientRect` or `offsetHeight`. Sync font, weight, size, line-height, and letter-spacing exactly between CSS tokens and the measurement helper.

### `references/components.md`

For atoms with dynamic labels (button, tag, chip, input):

> **Label overflow check.** Dynamic labels are verified at dev time / agent time using the text-measure helper. Buttons and tags must not silently wrap to two lines.

For autosizing inputs / textareas:

> **Autosizing height.** Computed via measurement helper. Set the textarea height to the precomputed value before render.

### `references/primitives.md`

For virtualized lists, masonry, or balanced-text primitives:

> **Item heights are precomputed via the measurement helper.** Virtualization buffers are sized from precomputed heights, not from rendered measurements. Masonry placement uses precomputed heights to avoid layout thrash.

### `references/responsive.md`

> **Shrink-wrap pattern.** When a container should be the tightest width that fits multi-line text, use the measurement helper's shrink-wrap function rather than CSS `min-content` (which is wrong for multi-line). Set the container to the returned width.

### `references/animation.md`

> **Layout-shift prevention on async text.** When text loads asynchronously and triggers layout, precompute the final height via the measurement helper before the text inserts. Reserve space, then fade text in.

### `references/platform-mapping.md`

> **Text measurement helper.** Project includes `@chenglou/pretext` and a wrapper at `src/lib/text-measure.ts` exposing `measureTextHeight`, `shrinkWrapWidth`, `fitsInOneLine`. Components import from there, not from `@chenglou/pretext` directly, to keep font strings centralized.

## Anti-patterns

- **`getBoundingClientRect()` for layout decisions.** Triggers reflow. Use the measurement helper.
- **`offsetHeight` / `offsetWidth` for sizing.** Same problem.
- **Hidden DOM nodes used to measure text** (the classic "render in an offscreen div, read its height"). Pretext makes this obsolete and avoids the reflow.
- **Out-of-sync font strings.** If CSS says `500 16px "Inter"` and pretext gets called with `400 16px Inter`, the measurements are wrong. Always centralize through the wrapper helper.
- **Pretext for text that doesn't drive layout.** If the text is decorative and you don't need its dimensions, don't measure it. Pretext's job is precision where precision matters.
- **CSS `width: min-content` for multi-line shrink-wrap.** It picks the longest single word, not the longest wrapped line. Use `shrinkWrapWidth()`.

## Forward compatibility

When new pretext APIs land (server-side rendering, automatic hyphenation, etc.), update `src/lib/text-measure.ts` first, then update the project rules in `references/*.md` to reflect new capabilities. Don't add raw `@chenglou/pretext` imports scattered across components — the wrapper is the contract.

## See also

- repo: https://github.com/chenglou/pretext
- live demos: https://chenglou.me/pretext/
- the underlying principle: pure-arithmetic text measurement is one of those infrastructure-level inversions that unlocks correctness in places web has been wrong about for years (virtualization, balanced text, shrink-wrap, dev-time verification)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.