Skip to content

No.228 · Stats

Odometer Stats

Big serif numbers built from mechanical reels — each digit spins to its value on scroll-in, the last digits arriving last.

The prompt

The design brief behind this component — reuse it to regenerate, remix, or explain it.

Design a stats band where the numbers behave like an old mechanical counter. Three cells share hairline seams (1px gaps over a hairline background inside one 14px-rounded frame). Each cell has a huge serif value (clamp 2.75–4.5rem, tabular lining numerals) above a small mono uppercase label. Build each digit as a "reel": a 0.62em-wide, 1em-tall window with overflow hidden and a soft top/bottom mask, containing a vertical strip of the digits 0–9. When the band is 40% visible (IntersectionObserver, once), each strip translates to −(digit × 10%) of its height: duration 900ms plus 90ms per digit value (so bigger digits spin longer), with cubic-bezier(0.19,1,0.22,1), and a stagger of 90ms per position and 140ms per cell so the rightmost reels land last. Non-digit characters (K, M, +, %, .) are static frost-coloured symbols. Provide the whole value to screen readers as visually hidden text and hide the reels with aria-hidden. Under reduced motion show the final values immediately.

Notes

Interaction
Plays once when scrolled into view.
Motion
Reel spin 900–1700ms ease-out-expo, staggered 90ms per digit and 140ms per stat.
Accessibility
The real value is visually-hidden text in each <dd>; reels are aria-hidden. Uses a <dl> for label/value semantics. Reduced motion shows final numbers.
Responsive
auto-fit grid (min 12rem); numerals scale with container width.

Featured

301 components