Charts that stay inside the frame.

Time-series on plain Canvas 2D, with no dependencies and no build step. Under 15 KB gzipped, and lean on memory: 4 bytes per retained sample, so it scales to large datasets. A million points go from raw array to painted chart in  ms — measured in this tab, just now.

this page, ms per frame 16.7 ms — one frame at 60 Hz
$npm install minichart

One call turns data into a chart.

Hand it series and labels — MiniChart draws the axes, the gaps, the decimation and the hover tooltip. No ceremony, no build step.

const chart = new MiniChart(canvas, {
  series: [
    { label: 'cpu',    data: cpu, color: '#0057ff' },
    { label: 'memory', data: mem, color: '#00857d' },
  ],
  labels,                 // epoch seconds, ascending
});

That chart is the call above, run on 720 recorded samples — no stream, no timers. The break near the middle is a run of nulls: a gap lifts the pen instead of drawing a false line across the missing span.

Hover for the per-point tooltip; click the legend to toggle a series. The same call scales to a million points — denser series decimate to a per-column min/max.

For a live feed, push() appends one sample in O(1) — it writes into a single pixel-column bucket instead of re-running the O(n) recalculation that update() pays on every batch swap. The cost is flat in n: ten thousand points and ten million both measure about 0.10 ms per sample.

import MiniChart from 'minichart';

const chart = new MiniChart(canvas, {
  series: [{ label: 'cpu', data, color: '#0057ff' }],
  labels,                                // epoch seconds, not indices
});

chart.push(value, Date.now() / 1000);   // O(1), flat in n

Every option runs live in the demo and the streaming dashboard; the full reference is in the docs. TypeScript declarations ship inside the package.