Animated KPI cards that look like money
A KPI card that animates its value, with the easing and typography choices that make a number feel like a result.
A KPI card is one number, one label, and one trend indicator. It is the most overrepresented widget in modern dashboards and the most overpaid-for asset in revenue marketing. The good version costs zero dollars and renders in 40 lines.
Here is what makes a KPI card feel like a result instead of a cell.
The four parts
- The big number. Tabular numerals, heavy weight, oversized relative to the card.
- The label. Small, tracked-out, all caps, quiet.
- The delta. Up or down, with an arrow, in the brand-positive or brand-negative color.
- The sparkline. Tiny, abstract, supporting.
Get those four right and the card carries weight. Get them wrong and it looks like a Bootstrap demo.
The count-up
The single feature that separates "data widget" and "story." The number animates from 0 to its final value as the card enters. The easing must be the settle curve — anything linear feels mechanical, anything bouncy feels childish.
function countUp(target, duration, el) {
const start = performance.now();
function tick(now) {
const t = Math.min(1, (now - start) / duration);
const ease = 1 - Math.pow(1 - t, 3);
el.textContent = (target * ease).toFixed(1);
if (t < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}If this lives in a deterministic render pipeline, rewrite it as render(t) and the renderer will drive the time. The CSS animation runs at 60fps in the browser; the renderer captures frames at the requested intervals.
The typography
Two non-negotiable CSS declarations:
.number {
font-variant-numeric: tabular-nums;
font-feature-settings: 'tnum';
}Without these, the digits dance during the count-up — 7 is narrower than 1, the layout reflows, the eye reads it as broken. With them, every digit has identical width, the count-up reads as a single block of numbers.
The font weight matters too. KPI numbers want 800 or 900, not 600. The weight communicates importance. A semi-bold KPI looks tentative.
The delta indicator
A small chip above or beside the number: ↑ 24.6%. Two rules:
- Color is signal. Green for up-and-good, red for down-and-bad, but watch your context — a "bounce rate is down" delta should be green, not red. The semantic mapping is "is this the desired direction," not "is this an increase."
- The arrow is part of the type. Use the Unicode glyphs (
↑ ↓) and the same font as the number. Bolted-on SVG arrows fight the type.
The delta animates in after the number has settled. 200ms gap; the eye lands on the number, then reads the context. Reverse this and the eye splits.
The sparkline
Tiny chart inside the card, typically 60-80px wide and 24-32px tall. It does not need to be legible at a data-point level; it needs to communicate trend. SVG <polyline> with three points works fine:
<svg viewBox="0 0 100 30">
<polyline fill="none" stroke="currentColor" stroke-width="2"
points="0,25 25,18 50,22 75,8 100,5" />
</svg>For real data, downsample to ~10 points; more is visual noise at that scale.
The variable preview
The four knobs that turn the card into your brand:
Compare: static vs animated
Same data, two treatments. The animated one earns more attention for the same number.
A note on "make number go up"
A KPI card with a down delta is the harder case. The temptation is to soften it visually — gray instead of red, no arrow, smaller font. Don't. If the number is down, the card should make that clear. The whole point of a KPI card is fast read; obscuring the bad news makes the card lie.
The respectful design move is to color the delta red, keep the arrow, and let the next element in the layout (a callout, a context note) explain why. Honesty > comfort in dashboards.
When the count-up is wrong
A specific case worth flagging: very large numbers count up too slowly. If the value is $2.4M, animating from $0.0M → $2.4M over a second is fine. If the value is 1,247,392, animating digit-by-digit looks bizarre. Round during the count-up: animate the rounded value (1.2M → 1.25M) and reveal the precise number at the end.
This is the same principle as the easing cheatsheet — pick a representation that fits the moment, not the data.
Render to MP4
Once the card looks right at the dimensions you need (1920×1080 for hero animations, 1200×630 for OG images, 1080×1080 for social), render. Same pipeline as everything else: open the playground, pick dimensions, render. See the use-cases page for the surfaces these end up on.
A KPI card is the smallest unit of revenue marketing. It is the cheapest thing to make well and the most expensive thing to make badly — bad ones get screenshotted and shared internally as "do not do this." The 40 lines above are the cheap, good version. Use them.
Cite this postBibTeX · APA · Markdown
@misc{park2026animated,
author = {Ren Park},
title = {Animated KPI cards that look like money},
year = {2026},
url = {https://hyperframes.video/blog/animated-kpi-stat-cards},
note = {HyperFrames blog}
}Ren Park. (2026, May 13). Animated KPI cards that look like money. HyperFrames. https://hyperframes.video/blog/animated-kpi-stat-cards
[Animated KPI cards that look like money](https://hyperframes.video/blog/animated-kpi-stat-cards) — Ren Park, 2026
Ren writes guides, runs workshops, and breaks the CLI on purpose so you do not have to. Previously dev rel at a CI company; before that, an actual filmmaker.
Animated heatmap visualization, rendered to MP4
Build an animated heatmap in plain HTML and CSS — a 12×7 grid where cells fade in with intensity-based color values, scrubbing left-to-right. Deterministic MP4 from JSON.
CSS animated pie chart (and donut) — no JavaScript required
Build animated pie and donut charts with pure CSS conic-gradient and stroke-dashoffset. Two techniques, full source, MP4 export.
Animate a bar chart from JSON in 10 minutes
From a tiny JSON file to a 16:9 animated bar chart you can render to MP4. CSS, no charting library.
Building with HyperFrames? Come hang out.
We're on GitHub, in Discord, and the playground is one click away. Bring weird ideas — we collect them.