The year in one line
Ember Hill opened its web shop in January with one roast and a hand-labelled bag. Orders were slow through the winter, then a subscription launched in April and the line never looked back.
<motion-chart> a line that draws in when it scrolls into view Show the codeHide the code
<script type="module"> import "motion-components/motion-chart"; </script> <motion-chart style="--mc-chart-1: #2563eb" type="line" label="Orders per month in 2026" values="310, 280, 340, 520, 610, 690, 760, 740, 700, 780, 920, 1240" labels="Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec" ></motion-chart>
Small lines, big stories
Subscribers grew from 40 to 310
Show the codeHide the code
<script type="module">
import "motion-components/motion-sparkline";
</script>
<p>
Subscribers grew from 40 to 310
<motion-sparkline
style="--mc-sparkline-color: #2563eb"
values="40, 52, 61, 98, 140, 171, 198, 214, 232, 251, 280, 310"
label="Subscribers per month, from 40 to 310"
area
></motion-sparkline>
while café walk-ins stayed almost flat
<motion-sparkline
style="--mc-sparkline-color: #60608a"
values="210, 198, 220, 214, 230, 236, 241, 228, 219, 224, 232, 240"
label="Café walk-ins per week, from 210 to 240"
></motion-sparkline>
and returns kept falling
<motion-sparkline
style="--mc-sparkline-color: #a16207"
values="9, 8, 8, 6, 6, 5, 4, 4, 3, 3, 2, 2"
label="Returned orders per month, from 9 to 2"
></motion-sparkline>.
</p>Where the orders came from
The shop counter carried the first quarter. By summer, online orders had passed it, and two local restaurants started buying beans wholesale in the autumn.
<motion-chart type="bar"> three series, bars that grow in one after another Show the codeHide the code
<script type="module"> import "motion-components/motion-chart"; </script> <motion-chart style="--mc-chart-1: #2563eb; --mc-chart-2: #a16207; --mc-chart-3: #60608a" type="bar" label="Orders by channel per quarter" values="620, 460, 480, 510; 380, 1320, 2200, 2940; 0, 0, 180, 420" labels="Q1, Q2, Q3, Q4" series="Shop counter, Online, Wholesale" ></motion-chart>
Hot coffee, cold brew
Summer turned the menu upside down. Cold brew overtook hot drinks in June and handed the lead back in September, right on schedule.
<motion-chart> two lines with a legend, a tooltip and arrow-key navigation Show the codeHide the code
<script type="module"> import "motion-components/motion-chart"; </script> <motion-chart style="--mc-chart-1: #2563eb; --mc-chart-2: #a16207" type="line" label="Drinks sold per month, hot and cold" values="1900, 1820, 1760, 1500, 1240, 980, 860, 900, 1180, 1560, 1840, 2050; 120, 140, 260, 520, 890, 1260, 1480, 1390, 1010, 540, 260, 150" labels="Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec" series="Hot drinks, Cold brew" ></motion-chart>
Parts of the whole
The roaster ran 2,400 kilos of green coffee this year. Most of it went into the house blend. A bag sells for 16 euros, and the beans are the biggest part of that price.
<motion-pie donut> sweeps in, with the total in the middle Show the codeHide the code
<script type="module"> import "motion-components/motion-pie"; </script> <motion-pie style="--mc-chart-1: #2563eb; --mc-chart-2: #a16207; --mc-chart-3: #60608a; --mc-chart-4: #18181e" donut label="Coffee roasted in 2026, in kilos" values="1320, 540, 360, 180" labels="House blend, Single origin, Decaf, Espresso" total-label="kilos roasted" ></motion-pie>
<motion-pie> hover a slice and it springs outward Show the codeHide the code
<script type="module"> import "motion-components/motion-pie"; </script> <motion-pie style="--mc-chart-1: #2563eb; --mc-chart-2: #a16207; --mc-chart-3: #60608a; --mc-chart-4: #18181e; --mc-chart-5: #9db7f4" label="Where the price of a bag goes" values="6.2, 3.1, 2.4, 2.1, 2.2" labels="Green beans, Wages, Rent, Packaging, Profit" format="currency:EUR" ></motion-pie>
This year against last
Switch the year. The bars don't redraw from zero. Each one springs from its current height to the new value, so you can watch every month grow.
<motion-chart> new values spring in from wherever the bars are Show the codeHide the code
<script type="module">
import "motion-components/motion-chart";
</script>
<div role="group" aria-label="Year shown in the revenue chart">
<button type="button" data-year="2025" aria-pressed="false">2025</button>
<button type="button" data-year="2026" aria-pressed="true">2026</button>
</div>
<motion-chart
id="revenue"
style="--mc-chart-1: #2563eb"
type="bar"
label="Revenue per month"
values="8100, 7300, 8400, 11200, 12600, 14100, 15800, 15100, 13900, 14800, 17200, 21500"
labels="Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec"
format="currency:EUR"
data-2025="6200, 5400, 6100, 7000, 7600, 8100, 8800, 8300, 7900, 8600, 9900, 12400"
data-2026="8100, 7300, 8400, 11200, 12600, 14100, 15800, 15100, 13900, 14800, 17200, 21500"
></motion-chart>
<script type="module">
const chart = document.getElementById("revenue");
const buttons = [...document.querySelectorAll("[data-year]")];
for (const button of buttons) {
button.addEventListener("click", () => {
chart.values = chart.getAttribute("data-" + button.dataset.year);
for (const b of buttons) b.setAttribute("aria-pressed", String(b === button));
});
}
</script>Revenue for the year came to €160,000, two thirds more than the year before.