breathe
The paragraph
breathes.
Each line of a paragraph oscillates its letter-spacing at a fixed phase offset from its neighbours. The result is a slow ripple — a wave of expansion and contraction moving through the text. At low amplitudes it reads as living rather than animated.
Live demo — watch the paragraph
Hold still and watch the paragraph. Each line is breathing at its own pace — expanding and contracting its letter-spacing in a slow oscillation, offset from its neighbours by a fixed phase angle. The top lines and the bottom lines never breathe together. A wave moves through the paragraph rather than a pulse. At the default amplitude the movement is almost subliminal: you notice something alive before you notice what it is. Increase the amplitude to see the mechanics. The wave shape changes the character of the motion — sine is smooth, triangle is more mechanical. The period controls how fast each line completes its cycle.
Each line oscillates at ±0.012 em, period 3.5s, phase offset 0.79 rad per line.
How it works
Phase offset per line
The algorithm detects visual lines and assigns each a phase position: line 0 is at phase 0, line 1 at phaseOffset radians, line 2 at 2× phaseOffset, and so on. Each frame, the wave function is evaluated at each line's current phase.
Letter-spacing or wdth axis
The oscillation can drive either CSS letter-spacing (for any font) or the variable font wdth axis (for variable fonts that support it). The wdth axis gives a more physical quality — the letterforms themselves change shape rather than just spacing.
Usage
Drop-in component
import { BreatheText } from '@liiift-studio/breathe'
<BreatheText amplitude={0.012} period={3.5} phaseOffset={0.785}>
Your paragraph text here...
</BreatheText>Options
| Option | Default | Description |
|---|---|---|
| amplitude | 0.012 | Peak letter-spacing change in em (or wdth units). |
| period | 3.5 | Seconds per full oscillation cycle. |
| phaseOffset | π/4 | Phase shift between adjacent lines in radians. |
| waveShape | 'sine' | 'sine' | 'triangle' |
| axis | 'letter-spacing' | 'letter-spacing' | 'wdth' (variable font axis) |