The narrative drives the visualization. As you scroll, the chart on the left morphs between states — provisioning, fleet activity, geographic distribution, anomaly detection. The same shell adapts to IoT telemetry, Arduino sensor data, infovis essays, or any project where the right way to read a chart is in sequence, not all at once.
Replace the STEPS array in the script with your own narrative. Each step has a state name; renderState() takes that name and morphs the visualization. The chart below uses an IoT fleet provisioning story as the example — swap in sensor data, model performance over time, deployment maps, or any sequenced argument.
A single edge device — a sensor, a router, a payment terminal — needs to come online. Manual provisioning takes 14 minutes: SKU lookup, network configuration, certificate install, activation handshake. Fine when you're shipping a handful. Catastrophic at fleet scale.
An enterprise IoT contract isn't ten devices — it's a fleet. 12,000 units across 240 sites, deploying over a four-month window. Manual provisioning would take 2,800 person-hours; the math fails before any of the interesting design problems show up.
The dashboard needs to show fleet posture at a glance. We modeled four states: provisioning, online, degraded, offline. Each gets its own color, but more importantly its own action affordance — degraded and offline route to different remediation flows.
A snapshot of fleet status is useless. What the operator actually needs is the derivative — is the degraded count rising, are offline devices recovering, how does this week's rollout compare to last quarter's. Time-series became the primary view; the snapshot became a detail.
A degraded cluster in one region is operationally different from the same count distributed across the country. The geographic view doesn't replace status or time — it complements them, and operators jump between all three depending on what they're trying to diagnose.
The last view layers anomaly detection on the time-series. Statistical bounds (rolling p95) define the expected envelope; deviations highlight in oxblood. The operator's first question — "is this normal?" — gets answered before they have to ask it.
Every chart answers a question. Every caption states the decision. The patterns below are the ones the scrollytelling shell uses; each can be re-rendered with different data without rewriting the scroll logic.
Question: how does this metric spread across the population?
Question: what share of the total falls into which category?
Question: is the derivative positive, negative, or noisy?
Question: does X move with Y, against Y, or independently?
Question: where in this 2D space does activity concentrate?
Question: how do parallel series compare side-by-side?
The template is intentionally small. Three things change between projects: the STEPS array, the renderState() function, and the chart's underlying dataset. Everything else — sticky behavior, scroll triggers, progress rail, mobile fallback — is shared infrastructure.
Parent case study spanning discovery, design system, AI tooling, and operations.
Read parent → 04 / 2020Lab software studied across four countries. Friction ranking + severity × frequency matrix.
Read study → 03 / 2018–2019Dual-path checkout across two brands from a single spec.
Read case →