Stats Band
Headline metrics whose counters ease up exactly once when scrolled into view — with per-stat footnotes that keep the numbers honest.
motif by the numbers
0
original assets
every one with a published audit
0
a11y score median
editorial audit, bands on /quality
0
recorded prompt runs
run logs kept, failures included
0
KB median asset size
read from the catalog
counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.
Ambience is a live light wash over the preview. Full palette re-theming of every demo arrives with Theme Studio (Pro).
// Stats Band — the demo's own source, extracted verbatim.
// From src/components/demos/scenes/set-05.tsx, export StatsBand.
// Needs React 18+ and Tailwind CSS v4. The classes below include this site's
// token utilities (bg-panel, text-ink-dim, chip …); their values are served as
// CSS custom properties at /api/exports/tokens.json. The reduced-motion branch
// is part of the source, not an afterthought.
// 6 helpers the demo imports are inlined above it, verbatim.
// Catalog-dependent: the array below is a three-record sample of the site's own data.
import { useEffect, useRef, useState } from "react";
// The demo reads the site's own catalog: 362 catalogued assets. Three real
// records are inlined below — long fields trimmed — so this file runs as
// written. Replace the array with your own data, or read the full list from
// the site, where /api/search?q= returns the matching records as JSON.
const COMPONENTS = [
{"slug":"prism-switch","kind":"element","title":"Prism Switch","description":"A theme-aware toggle that sweeps a six-stop prism gradient across the track on every flip. Pure…","tags":["switch","toggle"],"behaviors":["click","hover"],"stack":["React","HTML/CSS"],"deps":[],"bundleKb":1.2,"themeable":true,"a11yScore":98,"qualityScore":96,"status":"live","license":"MIT","version":"1.2.0","author":"Motif Studio","published":"2026-06-02","demo":"prism-switch","props":[{"name":"size","label":"Size","type":"range","min":20,"max":64,"step":2,"unit":"px","defaultValue":42},{"name":"hueSpeed","label":"Gradient speed","type":"range","min":0,"max":4,"step":0.1,"unit":"s","defaultValue":1.4}],"copies":4820,"views":21400,"aliases":[],"trend":[]},
{"slug":"halo-button","kind":"element","title":"Halo Button","description":"Primary button with a mouse-tracking halo, press ripple and a springy scale. Ships as React + T…","tags":["button","magnetic"],"behaviors":["hover","click"],"stack":["React","HTML/CSS"],"deps":[],"bundleKb":2.1,"themeable":true,"a11yScore":96,"qualityScore":94,"status":"live","license":"MIT","version":"1.1.0","author":"Motif Studio","published":"2026-06-18","demo":"halo-button","props":[{"name":"magnet","label":"Magnet strength","type":"range","min":0,"max":60,"step":1,"defaultValue":24,"unit":""},{"name":"glow","label":"Halo glow","type":"range","min":0,"max":100,"step":1,"defaultValue":70,"unit":"%"}],"copies":3910,"views":17300,"aliases":["cta","call to action"],"trend":[]},
{"slug":"pulse-loader","kind":"element","title":"Pulse Loader","description":"Three-note loader with staggered radial pulse and optional progress text. Reduced-motion safe a…","tags":["loader","loading"],"behaviors":[],"stack":["HTML/CSS","React"],"deps":[],"bundleKb":0.8,"themeable":true,"a11yScore":99,"qualityScore":93,"status":"live","license":"MIT","version":"1.0.3","author":"Motif Studio","published":"2026-05-28","demo":"pulse-loader","props":[{"name":"speed","label":"Pulse speed","type":"range","min":0.2,"max":2.4,"step":0.05,"unit":"s","defaultValue":1},{"name":"dots","label":"Dots","type":"range","min":1,"max":8,"step":1,"unit":"","defaultValue":3}],"copies":5220,"views":19800,"aliases":["spinner","loading"],"trend":[]},
];
// The demo reads the site's own catalog: 184 briefs and 661 recorded model runs. Three real
// records are inlined below — long fields trimmed — so this file runs as
// written. Replace the array with your own data, or read the full list from
// the site, where /api/search?q= returns the matching records as JSON.
const PROMPTS = [
{"slug":"dark-saas-pricing-launch","title":"Dark SaaS launch page with aurora hero","titleZh":"暗色 SaaS 发布页:极光 hero","industry":"SaaS","vibe":"dark, premium, minimal","stacks":["Next.js","HTML"],"blocks":["Nav","Hero"],"status":"featured","avgFidelity":92,"bestModel":"Claude 4.6 Sonnet","runs":[{"model":"Claude 4.6 Sonnet","date":"2026-08-04","fidelity":95,"buildError":false,"notes":"Matches reference spacing almost 1:1; fonts swapped gra…"},{"model":"Codex","date":"2026-08-04","fidelity":91,"buildError":false,"notes":"Solid. Needed one nudge to enable the toggle pricing."}],"promptBody":"Build a one-page dark SaaS landing in Next.js + Tailwind.\n• Palette: near-black #07080B canvas,…","author":"Motif Studio","published":"2026-08-04","tokens":[],"estLoc":0,"relatedComponents":[],"revised":"","revisedNote":"","remixes":[],"viewport":""},
{"slug":"3d-portfolio-neon","title":"3D portfolio with neon orbit showcase","titleZh":"","industry":"Portfolio","vibe":"bold, 3D, neon","stacks":["Next.js","React"],"blocks":["Hero","Orbit gallery"],"status":"verified","avgFidelity":87,"bestModel":"Codex","runs":[{"model":"Codex","date":"2026-07-29","fidelity":91,"buildError":false,"notes":"Orbit ring implemented with spring physics — great feel."},{"model":"Claude 4.6 Sonnet","date":"2026-07-29","fidelity":85,"buildError":false,"notes":"Accurate but used heavier 3D lib than asked; suggested …"}],"promptBody":"Design a portfolio hero that feels like a neon gallery.\n• Left: name + role in large display ty…","author":"Motif Studio","published":"2026-07-29","tokens":[],"estLoc":0,"relatedComponents":[],"revised":"","revisedNote":"","remixes":[],"viewport":""},
{"slug":"fintech-trust-page","title":"Fintech trust page (compliance tone)","titleZh":"金融科技信任页(合规语气)","industry":"Fintech","vibe":"calm, trustworthy, crisp","stacks":["Next.js","HTML"],"blocks":["Hero","Security bento"],"status":"verified","avgFidelity":89,"bestModel":"Claude 4.6 Sonnet","runs":[{"model":"Claude 4.6 Sonnet","date":"2026-08-01","fidelity":92,"buildError":false,"notes":"Excellent typographic hierarchy for legal-adjacent copy."},{"model":"GLM-4.6 (CN)","date":"2026-08-01","fidelity":88,"buildError":false,"notes":"Very close; metric band needed re-spacing."}],"promptBody":"A fintech page that earns trust, not hype.\n• Off-white paper background, ink navy text, single …","author":"Motif Studio","published":"2026-08-01","tokens":[],"estLoc":0,"relatedComponents":[],"revised":"","revisedNote":"","remixes":[],"viewport":""},
];
export interface SceneMotion {
/** True when the reader asked the system for less motion. */
reduced: boolean;
/** A duration in milliseconds, collapsed to 0 when reduced. */
ms: (value: number) => number;
/** A repeat count, collapsed to 1 when reduced — an entrance plays once. */
times: (value: number) => number;
}
export function useReducedMotion(): boolean {
const [reduced, setReduced] = useState<boolean>(() =>
typeof window !== "undefined" ? window.matchMedia("(prefers-reduced-motion: reduce)").matches : false
);
useEffect(() => {
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
const on = (e: MediaQueryListEvent) => setReduced(e.matches);
mq.addEventListener("change", on);
return () => mq.removeEventListener("change", on);
}, []);
return reduced;
}
export function useSceneMotion(): SceneMotion {
const reduced = useReducedMotion();
return {
reduced,
ms: (value: number) => (reduced ? 0 : value),
times: (value: number) => (reduced ? 1 : value),
};
}
const median = (xs: number[]) => {
const s = [...xs].sort((a, b) => a - b);
const m = Math.floor(s.length / 2);
return s.length % 2 ? s[m] : Math.round(((s[m - 1] + s[m]) / 2) * 10) / 10;
};
const STATS_TARGETS = [
COMPONENTS.length,
median(COMPONENTS.map((c) => c.a11yScore)),
PROMPTS.reduce((n, p) => n + p.runs.length, 0),
median(COMPONENTS.map((c) => c.bundleKb)),
];
const STATS_ROWS = [
{ label: "original assets", note: "every one with a published audit", suffix: "" },
{ label: "a11y score median", note: "editorial audit, bands on /quality", suffix: "" },
{ label: "recorded prompt runs", note: "run logs kept, failures included", suffix: "" },
{ label: "KB median asset size", note: "read from the catalog", suffix: "" },
];
export function StatsBand() {
const ref = useRef<HTMLDivElement>(null);
const [started, setStarted] = useState(false);
const [vals, setVals] = useState<number[]>([0, 0, 0, 0]);
// #30 — count-up on view, driven by rAF. Reduced: the final numbers are
// printed straight away, no roll.
const { reduced } = useSceneMotion();
useEffect(() => {
const el = ref.current;
if (!el) return;
if (reduced) return;
const io = new IntersectionObserver(
(entries) => {
entries.forEach((en) => {
if (en.isIntersecting) setStarted(true);
});
},
{ threshold: 0.5 }
);
io.observe(el);
return () => io.disconnect();
}, [reduced]);
useEffect(() => {
if (!started) return;
if (reduced) return;
const t0 = performance.now();
let raf = 0;
const tick = (now: number) => {
const p = Math.min(1, (now - t0) / 1400);
const ease = 1 - Math.pow(1 - p, 3);
setVals(STATS_TARGETS.map((t) => (t % 1 === 0 ? Math.round(t * ease) : Math.round(t * ease * 10) / 10)));
if (p < 1) raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [started, reduced]);
const shown = reduced ? STATS_TARGETS : vals;
return (
<div className="flex h-full w-full flex-col items-center justify-center bg-[#0a0c13] px-6">
<div ref={ref} className="w-full max-w-md rounded-2xl border border-white/8 bg-white/3 px-5 py-6">
<p className="text-center text-[10px] font-bold uppercase tracking-[0.24em] text-ink-faint">motif by the numbers</p>
<div className="mt-5 grid grid-cols-2 gap-x-6 gap-y-5">
{STATS_ROWS.map((r, i) => (
<div key={r.label}>
<p className="font-mono text-2xl font-black tracking-tight text-white">
{shown[i]}
<span className="text-sm text-emerald-300">{r.suffix}</span>
</p>
<p className="mt-0.5 text-[10px] font-bold text-ink-dim">{r.label}</p>
<p className="text-[8.5px] leading-snug text-ink-faint">{r.note}</p>
</div>
))}
</div>
<div className="mt-5 h-0.5 overflow-hidden rounded-full bg-white/8">
<div className="h-full bg-gradient-to-r from-emerald-300 to-cyan-300 transition-[width] duration-200" style={{ width: started ? "100%" : "0%" }} />
</div>
<p className="mt-2 text-center text-[9px] text-ink-faint">counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.</p>
</div>
</div>
);
}
Snippet provenance
lines 1–144 · v1.0.0No changelog entry mentions “Stats Band”, so the catalog records a single version for it.
Every line above is attributed to the single version this catalog records — we keep no per-line history, so no per-line attribution is invented. See the provenance page for the rule and the gaps.
Review notes · anchored to code lines
Threads attach to a line number in this asset's snippet, so a remark about the focus trap stays next to it.
Loading notes…
The snippet on this page is 144 lines long, so anchors run 1–144. Notes are per-asset and per-browser; a shared review thread is a server feature, and this panel is the local stand-in that proves the anchoring works.
Why it works — Numbers are the fastest proof on a landing page, but only if they read as measured — footnotes and honest formatting do that work.
The idea — Count up exactly once when the band scrolls into view, then stop; metrics that re-animate on every scroll read as decorative.
When to skip it — If you can't footnote a metric, cut it — an unexplained 98% invites distrust faster than no stat at all.
Course rail — understand it before you ship it
Live variants
Variant gallery
The same Stats Band demo re-lit in three tones — no code change, three personalities.
motif by the numbers
0
original assets
every one with a published audit
0
a11y score median
editorial audit, bands on /quality
0
recorded prompt runs
run logs kept, failures included
0
KB median asset size
read from the catalog
counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.
motif by the numbers
0
original assets
every one with a published audit
0
a11y score median
editorial audit, bands on /quality
0
recorded prompt runs
run logs kept, failures included
0
KB median asset size
read from the catalog
counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.
motif by the numbers
0
original assets
every one with a published audit
0
a11y score median
editorial audit, bands on /quality
0
recorded prompt runs
run logs kept, failures included
0
KB median asset size
read from the catalog
counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.
Theme Studio preview
Theming example — two token themes
Assets are token-driven (100% design-token driven). Here the same scene runs under two theme presets from the token sheet.
motif by the numbers
0
original assets
every one with a published audit
0
a11y score median
editorial audit, bands on /quality
0
recorded prompt runs
run logs kept, failures included
0
KB median asset size
read from the catalog
counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.
--accent 262 · dark surfaces
motif by the numbers
0
original assets
every one with a published audit
0
a11y score median
editorial audit, bands on /quality
0
recorded prompt runs
run logs kept, failures included
0
KB median asset size
read from the catalog
counts ease up once (IntersectionObserver), then stay put — metrics shouldn’t re-run on every scroll.
--accent 40 · paper surfaces
90-second read
Usage recipe — where this fits
Assemble it between your own header and footer — sections are the middle of the page, where information architecture lives.
Swap the demo copy for real content first, then reduce: cut decorative blocks until the section survives on its information alone.
Cost honesty
Performance note
Cheaper alternative — the minimal variant drops the decorative layers and keeps the content hierarchy.
What it needs
Browser support strip
No polyfills ship with the asset — if a listed feature is missing in a target browser, the graceful fallback is the static layout.
prefers-reduced-motion
Reduced-motion fallback
This asset is not motion-first, so reduced-motion mainly affects its decorative extras (reveals, hovers). The content layer never depends on motion to be readable.
Pressable step-through
Keyboard walk demo
Step through what a keyboard user experiences with this asset.
Tab into the section via the skip link or heading anchor
Auto-suggested
Composition map — what pairs well
Same-family assets that compose cleanly with this one:
Aurora Hero Section
Full-viewport hero: aurora veil backdrop, scramble headline, dual CTAs and a floating product chip — the section most Prompt users ask for first.
SectionsBento Studio Grid
Six-cell bento with organic spans, an embedded mini orbit, hover expand and skeleton-safe loading. Cells accept any card content via props.
SectionsMarquee Logo Belt
Edgeless infinite logo belt with pause-on-hover and direction props. Ships with a 12-logo placeholder set you can swap via one array.
One original micro-case
Inspiration context
The pricing page that stopped lying
A pricing section with three tiers and no indication of which one people actually chose produced analysis paralysis. Adding one honest 'most chosen' chip — not a fake 'popular' badge, but a real count — lifted conversions by 8% and cut support questions about tier differences.
Written in-house — no screenshots, no borrowed imagery. The pattern, not the pixels.
Every version, why
Changelog — this asset
Current release — this page documents the asset as shipped.
Token pass: colours and radii moved to the design-token sheet; a11y score raised to the current bar.
Initial release to the library — original markup, MIT licensed.
30-day sparkline
Copy history
Sample series from this asset's usage fingerprint · last 12 days shown.
Future queue
Community remixes
Queue opens after launch. Remixes arrive as alternate versions of this asset — same job, different voice — submitted by users and audited by the studio before they appear beside the original.
Star / favourite
Save this asset
Your collection is stored in this browser (localStorage) — no account needed.
Build a page around it
Pairs well with a prompt
This asset belongs inside a bigger build — here is the prompt that would generate a page containing it:
Print-inspired web — a magazine spread that scrolls
Editorial spread · Folio rules · Ink logic
Exact tree
Bundled dependencies — disclosed
Full snippet ≈ 10.4 KB raw, ~1 KB gzip — before any framework you already load.
Download
Export as single file
Grab the asset as one file, ready to paste into your project.
Files are generated in your browser from the snippets on this page — nothing leaves the tab.
Scale, not clutter
Sizing system — three densities
Density is a token decision, not a per-page override — pick one density per product surface and hold it. Active: Default.
Runnable copy
Open in a sandbox
Opens this asset in a new tab with its stylesheet injected — a real, editable HTML document in your browser. No account, no upload.
If the tab is blocked, use the single-file export instead — same content, saved locally.
Written version first
Tutorial transcript
This asset does not have a video yet — so the written version stands in: the code line walk below narrates the snippet line by line, and the design rationale on this page explains the default decisions. When a video ships, this exact panel hosts its full transcript.
Annotated snippet
Code line walk
The lines that matter, with the reason they matter. Click one:
Trade-off, visible
Size vs. quality slider
Standard · CSS + hover states
~6 KBadds transitions, focus-visible and reduced-motion rules
The slider is honest: the slim tier has no JS, the pro tier pays for behaviour. Start slim, upgrade only the surfaces that need it.
HTML → React, priced
Stack-switch cost note
Taking the HTML/CSS version into a React component costs real work — and the cost is predictable:
Event wiring
Hover, focus and click become handlers — the CSS stays, the state appears.
Props for the knobs
Every inline value that should vary becomes a prop with a default — the defaults must match the CSS exactly.
The estimate
A clean port of this asset is 20–45 minutes for a React developer — the 180-character stylesheet is the easy half.
Find it the way you say it
Tag synonyms
Search on this site resolves synonyms globally — "dropdown", "select" and "picker" land on the same asset, so you never need to know the catalog's internal vocabulary.
When to pick which
Sibling comparison
| Compare | Stats Band | Aurora Hero Section | Bento Studio Grid |
|---|---|---|---|
| Kind | Sections | Sections | Sections |
| Bundle | 1 KB gzip | 6.2 KB gzip | 5.5 KB gzip |
| a11y | 96/100 | 97/100 | 96/100 |
| Dependencies | none | none | none |
| Copies / mo | 490 | 4,860 | 3,960 |
| Interactions | scroll | scroll, hover | hover |
The honest verdict — Stats Band is the lighter default here; reach for Aurora Hero Section when its extra weight buys an interaction this one lacks.
← Previous in the library
Pricing Table — Three Plans
Next in the library →
Team Grid with Roles Filter
Similar to this — scored on shared tags, not hand-picked
Related assets
Prism Switch
1.2 KB · a11y 98 · Q 96
Halo Button
2.1 KB · a11y 96 · Q 94
Pulse Loader
0.8 KB · a11y 99 · Q 93
Read next — two guides and a prompt
picked by tag overlap, not by handGuide
Community signals, not metrics
4 min · Intermediate · updated 2026-09-14
Guide
Recorded numbers need labels
6 min · Beginner · updated 2026-09-12
Prompt
Fintech trust page (compliance tone)
Fintech · 89% fidelity
How these three were chosen: essays scored on shared tags (1 and 1 matches), then prompt scored on block/vibe overlap (1 matches). The rule lives in src/lib/spine.ts, so the same asset always links to the same three pages and a second reader can reproduce the choice.
The counter is a note to yourself — it adds one each time you tap, in motif:remix-count:v1, and goes nowhere. A real, public remix count would need a server and accounts; this site has neither, and it would rather say that than print a number it cannot own.