typsettle

Settle,
into place.

npm ↗
GitHub
TypeScript·Zero dependencies·React + Vanilla JS

Paragraph text enters from randomised letter-spacing and transitions to optical equilibrium. A page-load animation that feels typographic rather than decorative — lines staggered, motion purposeful. Respects prefers-reduced-motion and the active option.

Live demo

Spread0.04
Duration (ms)800
Stagger (ms)80
EasingDirection

The first thing a reader notices about a text is not the words but the colour — the even grey field of the paragraph taken as a whole. Before meaning, before syntax, there is that impression: light, dark, dense, airy. The typographer works to make it even, to give the reader a surface to move across without resistance. A page-load animation that begins in chaos and resolves into order says something about the text it introduces: that it knows where it is going.

Tracking — the spacing between letters across a whole word or line — is the most delicate of the compositor's instruments. Too tight and letters close against each other; too loose and words fragment. The right amount is invisible.

Text enters from randomised tracking and settles to equilibrium. Each line is staggered by 80ms.

How it works

The entrance

Each line of text starts with a randomised letter-spacing offset — some wider, some tighter. The offset is unique per line, creating a sense of subtle chaos that reads as typographic texture rather than noise.

The resolution

A CSS transition carries each line to zero extra spacing — the optically neutral baseline. The stagger control spaces these transitions apart so lines settle in sequence rather than all at once.

Usage

Drop-in component

import { SettleText } from '@liiift-studio/typsettle'

<SettleText spread={0.04} duration={800} stagger={80}>
  Your paragraph text here...
</SettleText>

Hook

import { useSettle } from '@liiift-studio/typsettle'

const ref = useSettle({ spread: 0.04, duration: 800, stagger: 80 })
<p ref={ref}>{children}</p>

Vanilla JS

import { applySettle, getCleanHTML } from '@liiift-studio/typsettle'

const el = document.querySelector('p')
const original = getCleanHTML(el)
applySettle(el, original, { spread: 0.04, duration: 800, stagger: 80 })

Options

OptionDefaultDescription
spread0.04Max initial letter-spacing offset in em.
duration800Transition duration in milliseconds.
easing'cubic-bezier(0.25, 0.1, 0.25, 1)'CSS easing string.
stagger0Delay between lines in ms. 0 = all settle together.
activetrueSet false to skip animation entirely.
lineDetection'bcr''bcr' reads actual browser layout — ground truth, works with any font and inline HTML. 'canvas' uses @chenglou/pretext for arithmetic line breaking with no forced reflow on resize. Install pretext separately.