typsettle
Settle,
into place.
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
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 its natural letter-spacing baseline — the element's existing CSS tracking, if any, or zero if none is set. 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, replay } = useSettle({ spread: 0.04, duration: 800, stagger: 80 })
return <p ref={ref}>{children}</p>Vanilla JS
import { applySettle, removeSettle, replaySettle, getCleanHTML } from '@liiift-studio/typsettle'
const el = document.querySelector('p')
const original = getCleanHTML(el)
applySettle(el, original, { spread: 0.04, duration: 800, stagger: 80 })
// Replay the animation on a settled element (e.g. on a button click):
// replaySettle(el)
// Restore original markup:
// removeSettle(el, original)Options
| Option | Default | Description |
|---|---|---|
| spread | 0.04 | Max initial letter-spacing offset in em. |
| duration | 800 | Transition duration in milliseconds. |
| easing | 'cubic-bezier(0.25, 0.1, 0.25, 1)' | CSS easing string. |
| stagger | 0 | Delay between lines in ms. 0 = all settle together. |
| active | true | Set false to skip animation entirely. |
| targetTracking | — | Letter-spacing each line settles to, in em. When omitted, lines settle to 0em (the element's natural spacing). Pass a number for a consistent loose or tight equilibrium. 'auto' measures per-line optical density and adjusts each line's target to equalise density across the paragraph — dense lines get more tracking, sparse lines less, clamped to ±0.05em. |
| direction | 'expand' | 'expand' — lines start wide and ease to natural. 'compress' — lines start at zero tracking and ease outward. |
| intersect | false | When true, re-runs the animation each time the element scrolls into view. |
| quietReplay | false | When true, replays stagger each line individually (offset then settle) instead of flashing all lines simultaneously. Has no effect when stagger is 0. |
| 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. |