npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mip-chart

v0.3.0

Published

Google Maps for time-series data — level-of-detail charting that streams and decimates to the viewport. Framework-agnostic, uPlot-based.

Readme

mip-chart

Google Maps for time-series data.

A framework-agnostic time-series charting library with mipmap-style level of detail: like map tiles, it only ever fetches and draws the points the current viewport can actually show. Pan and zoom across millions of samples — years of high-frequency data — and the chart stays smooth because the data is streamed and decimated to the screen, not loaded all at once.

Built on uPlot. No framework dependency — hosts integrate through plain-JS callback hooks, so it drops into React, Vue, Svelte, Blazor, or no framework at all.

Why "mip"?

A mipmap is a precomputed pyramid of progressively lower-detail versions of an image — the GPU samples whichever level matches the screen. mip-chart does the same for time series: it keeps per-density tiers and serves the one that matches your zoom, so the number of points drawn stays roughly constant no matter how far you zoom out.

Features

  • Virtual level of detail — per-density tiers with on-demand fetch and eviction; only missing sub-ranges are requested, covered pans cost nothing.
  • Streaming + decimation — designed around a fragment contract: the host returns viewport-sized, downsampled fragments (LTTB / OHLC-aggregate / transition-preserving). Out-of-order fragments commit atomically.
  • Prioritised request lanes — the viewport and its two directional prefetch pads each ride a sticky, independently-conflated lane, so the visible range always paints first and a fast pan never blocks behind buffering (details).
  • Synced multi-pane — price + oscillators + state lanes share one time axis; pan/zoom in any pane mirrors the rest with no tearing.
  • Per-pane Y-autofit — tracks the visible window, log-aware, OHLC-aware.
  • Gestures — drag-pan, wheel-zoom about the cursor, double-click reset, shift-drag box zoom, velocity-projected prefetch.
  • Rendering — constant-width candles, shape-preserving (PCHIP) line curves, density-adaptive line width (thins toward a device-pixel hairline when zoomed out), causal hover values, UTC gridlines.
  • Minimap — full-extent overview scrubber driven purely by the time axis.
  • Offline snapshot export — serialize the current viewport to a self-contained HTML file that renders with no backend.

Install

npm install mip-chart

Quick start

import { ChartNavigator } from 'mip-chart';
import 'mip-chart/style.css';

const chart = new ChartNavigator(document.getElementById('chart'), {
  recipe,        // panes + series description (see ViewRecipe)
  extent,        // full time range of the data
  barMs,         // native sample cadence
  minimap: true,
  hooks: {
    // Called when the navigator needs data for a (range, density). Return
    // viewport-sized, downsampled fragments — this is where your server (or a
    // local decimator) does level-of-detail reduction.
    requestFrame: (req) => myProvider.load(req),
  },
});

See examples/ for a complete, runnable host: a synthetic OHLC provider (deterministic random walk, latency jitter, out-of-order delivery) wired to the navigator exactly the way a real backend would be.

The request contract — lanes & priority

The navigator never fires one bulk request. Each frame it splits the work across three sticky lanes — the visible viewport plus two prefetch pads (ahead / behind) — and calls requestFrame once per lane that's missing data. Each NavigationRequest carries:

  • laneId — a stable id per lane (the same three ids for the chart's life). Echo it back on every SeriesFragment so the navigator routes the response to the lane that asked.
  • priority0 for the viewport (always first); the prefetch pads are 1/2, assigned dynamically by travel direction (the pad you're panning toward outranks the trailing one). A backend draining a conflated priority queue paints the viewport first and buffers the pads behind it.
  • phaseId — monotonic within a lane. A newer phase supersedes an in-flight one on the same lane; other lanes are untouched.
  • sampleIntervalMs — the density the request was issued at; echo it back so fragments cache into the matching level-of-detail tier — even abandoned ones.

The contract is deliberately forgiving. A backend may conflate (keep only the newest phase per lane, dropping superseded ones) and load-shed (stop computing a superseded phase mid-flight and ship only what it finished, tagged cacheOnly). The navigator caches every delivered fragment — committed, stale, or cache-only — widening its tiers as you browse, and renders a phase only once all of its fragments arrive (atomically, regardless of arrival order). Zero-row fragments are left uncached so the range stays re-fetchable once data exists.

See NavigationRequest and SeriesFragment in src/types.ts for the full field-by-field contract.

Develop

npm install
npm run dev        # live example at http://localhost:8123
npm test           # vitest unit tests
npm run typecheck  # tsc --noEmit
npm run build      # bundle + type declarations into dist/

License

MIT © Mark Hammond