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

xviz-cli

v1.0.0

Published

Headless chart renderer — turn JSON, CSV, or SQL query results into PNG / PDF / HTML. Ships render / query / serve / mcp commands. Stable 1.x — see VERSIONING.md.

Readme

xviz

Headless chart renderer. Takes JSON or CSV data in, emits PNG / PDF / HTML out. Built on @minimal-viz/core + Puppeteer.

Stable 1.0 — see VERSIONING.md for the SemVer commitment.

Three modes:

  • xviz render — one-shot CLI rendering
  • xviz serve — HTTP server with POST /render
  • xviz mcp — MCP server for LLM tool-use (Claude, etc.)

Supports 39 chart types in the default build: pie bar line table big-number scatter heatmap sankey funnel gauge boxplot histogram treemap sunburst radar waterfall step tree graph timeseries-bar timeseries-line mixed-timeseries gantt big-number-total big-number-pop time-table pivot-table calendar rose parallel bullet compare partition time-pivot chord horizon paired-ttest world-map country-map.

For 13 additional deck.gl-powered map types (deck-scatter, deck-path, deck-polygon, deck-arc, deck-geojson, deck-grid, deck-hex, deck-heatmap, deck-screengrid, deck-contour, deck-multi, point-cluster-map, cartodiagram), build the renderer with the maps satellite enabled — see § Maps satellite below.

Setup

npm i -g xviz-cli

Chrome or Chromium is required at runtime — xviz uses puppeteer-core and does not bundle a browser. The CLI auto-detects these paths:

  • macOS: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
  • Linux: /usr/bin/google-chrome, /usr/bin/chromium, /usr/bin/chromium-browser

Override the path with XVIZ_CHROME=/path/to/chrome.

Or use the Docker image

docker run --rm -v "$PWD:/data" ghcr.io/caiyin-bit/xviz/xviz-cli:latest \
  render -d /data/sales.json -f /data/pie.json -o /data/out.png

# Pin to a major.minor for production
docker run --rm ghcr.io/caiyin-bit/xviz/xviz-cli:1.0 --help

The image bundles chromium (XVIZ_CHROME is pre-wired). It does not include the maps satellite — fork the Dockerfile and build with XVIZ_ENABLE_MAPS=1 to include it.

From source (contributors only)

git clone https://github.com/caiyin-bit/xviz.git
cd xviz/xviz-cli
npm ci --include=optional
npm run build        # builds the renderer bundle into dist/
node bin/xviz.mjs --help

xviz render

Render a single chart to a file.

node bin/xviz.mjs render \
  --data examples/pie-data.json \
  --form examples/pie-form.json \
  --out chart.png \
  --width 800 --height 500 \
  --theme dark

Flags:

| Flag | Default | Notes | |---|---|---| | -d, --data <file> | — | JSON array, JSON QueryData[], or .csv | | -f, --form <file> | — | JSON with chart formData (includes vizType) | | -c, --config <file> | — | Single JSON with {type, width, height, formData, data} | | -o, --out <file> | chart.png | Extension selects format: .png .jpg .pdf .html | | -w, --width <px> | 800 | | | -h, --height <px> | 500 | | | --scale <n> | 2 | Device scale factor (2 = retina) | | --theme <name> | light | light | dark | | --delay <ms> | 400 | Extra wait after render (for ECharts' canvas draw) | | --verbose | | Stream browser console to stderr |

Input data accepts three shapes:

// 1. Array of rows (most common)
[{ "region": "NA", "sales": 1200 }, ...]

// 2. Superset's QueryData
[{ "data": [{...}], "colnames": [...] }]

// 3. Single QueryData
{ "data": [...], "colnames": [...] }

xviz query

Query a database and render the result in one step. Combines SQL execution with chart rendering — no JSON / CSV intermediate needed.

node bin/xviz.mjs query \
  --db sqlite:examples/sql/sample.db \
  --sql "SELECT region, SUM(revenue) AS revenue FROM orders GROUP BY 1" \
  --form examples/sql/region-pie-form.json \
  --out /tmp/regions.png

Flags specific to query:

| Flag | Notes | |---|---| | --db <url> | Connection URL (see below). Required. | | --sql <sql> | Inline SQL query. | | --sql-file <file> | Path to a .sql file (alternative to --sql). | | --limit <n> | Max rows accepted from SQL (default 10000). |

All other flags from render apply (--form, --out, --width, --theme, …).

Supported connection URLs

| Driver | URL shape | Install | |---|---|---| | SQLite | sqlite:/abs/path.db or ./app.db | npm install better-sqlite3 | | PostgreSQL | postgres://user:pass@host:5432/db | npm install pg | | MySQL | mysql://user:pass@host:3306/db | npm install mysql2 |

Drivers are optionalxviz imports them dynamically and errors with a helpful message if the one you need isn't installed.

Example

# Build the sample SQLite database (96 rows of orders across 6 months)
node examples/sql/build-sample.mjs

# Monthly revenue stacked by category
node bin/xviz.mjs query \
  --db sqlite:examples/sql/sample.db \
  --sql "SELECT strftime('%Y-%m', placed_at) AS month,
                product_category AS category,
                SUM(revenue) AS revenue
         FROM orders GROUP BY 1, 2 ORDER BY 1, 2" \
  --form examples/sql/monthly-revenue-form.json \
  --out /tmp/monthly.png --width 800 --height 450

xviz serve

Long-lived HTTP server. Puppeteer browser stays warm between requests (~1.2s / render on an M-series Mac).

node bin/xviz.mjs serve --port 3737 --host 127.0.0.1
curl http://localhost:3737/health
# → {"status":"ok","service":"xviz","version":"0.1.0",
#    "endpoints":["POST /render"],
#    "supported":["pie","bar","line",...]}

curl -X POST http://localhost:3737/render \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "pie",
    "width": 600, "height": 400,
    "data": [
      {"region": "NA", "sales": 1200},
      {"region": "EU", "sales": 900},
      {"region": "AS", "sales": 1500}
    ],
    "formData": {
      "vizType": "pie",
      "groupby": ["region"],
      "metric": "sales",
      "donut": true, "showTotal": true
    }
  }' -o chart.png

Request body:

| Field | Required | Default | |---|---|---| | type | yes¹ | — | | formData | yes | — | | data or queriesData | yes | — | | width / height | no | 800 / 500 | | format | no | png (or jpg, jpeg, pdf, html) | | theme | no | light, dark, or partial Theme object | | scale, delay | no | 2, 400 |

¹ Derived from formData.vizType if omitted.

xviz mcp

Exposes rendering as MCP tools so Claude and other LLMs can generate charts through natural language. Communicates over stdio.

node bin/xviz.mjs mcp

Tools advertised:

  • render_chart{type, data, formData, width?, height?} → returns base64 PNG + metadata
  • list_chart_types — lists supported chart types

Add to Claude Desktop config:

{
  "mcpServers": {
    "xviz": {
      "command": "node",
      "args": ["/absolute/path/to/xviz-cli/bin/xviz.mjs", "mcp"]
    }
  }
}

Then ask Claude: "Chart these numbers as a donut: {NA: 1200, EU: 900, AS: 1500}".

Superset compatibility

The CSV parser handles Apache Superset's Export to CSV output verbatim. Tested with 16 real-world edge cases at test/csv-compat.test.mjs:

  • UTF-8 BOM (encoding="utf-8-sig")
  • Thousands-separated numbers: "9,823,456", "24,800.00"
  • CSV-injection guard: "'+12V""+12V", "'@formula""@formula"
  • Nested double quotes: """Pro"" Kit""Pro" Kit
  • Aggregate column names: SUM(confirmed), COUNT(*)
  • __timestamp columns preserved as strings
  • Scientific notation, leading-zero strings, etc.
node test/csv-compat.test.mjs   # 16 passed, 0 failed

See examples/superset-exports/ for real Superset-style CSV files you can pipe through the CLI.

Examples

The examples/ directory contains ready-to-run configs:

# JSON data
node bin/xviz.mjs render -d examples/pie-data.json   -f examples/pie-form.json   -o /tmp/pie.png
node bin/xviz.mjs render -d examples/sales-data.json -f examples/bar-form.json   -o /tmp/bar.png
node bin/xviz.mjs render -d examples/sales-data.json -f examples/line-form.json  -o /tmp/line.png
node bin/xviz.mjs render -c examples/scatter.json    -o /tmp/scatter.png
node bin/xviz.mjs render -c examples/heatmap.json    -o /tmp/heatmap.png
node bin/xviz.mjs render -c examples/sankey.json     -o /tmp/sankey.png
node bin/xviz.mjs render -c examples/funnel.json     -o /tmp/funnel.png
node bin/xviz.mjs render -c examples/gauge.json      -o /tmp/gauge.png

# Real Superset CSV exports
node bin/xviz.mjs render \
  -d examples/superset-exports/covid_states.csv \
  -f examples/superset-exports/covid-form.json \
  -o /tmp/covid.png --width 900

Maps satellite (XVIZ_ENABLE_MAPS)

The 13 deck.gl-powered map charts live in the optional @minimal-viz/maps satellite package. They are not in the default xviz-cli renderer — adding deck.gl + maplibre-gl to every CLI install would 3× the bundle. Opt in at build time:

git clone https://github.com/caiyin-bit/xviz.git
cd xviz/xviz-cli
npm ci --include=optional
npm run build:maps    # XVIZ_ENABLE_MAPS=1 vite build
node bin/xviz.mjs render \
  -d examples/deck-scatter-cities/data.json \
  -f examples/deck-scatter-cities/form.json \
  -o cities.png --width 900 --height 540

xviz serve /health reports mapsEnabled: true and includes the 13 map types alongside the 39 core types when the env var is set at CLI launch:

XVIZ_ENABLE_MAPS=1 node bin/xviz.mjs serve --port 3737
curl -s http://localhost:3737/health | jq .mapsEnabled    # → true

Bundle sizes (CI-enforced budgets in .github/workflows/ci.yml):

| Build | Raw | Gzip | |---------------|---------:|-------:| | Default | ~1.15 MB | ~374 KB | | Maps-enabled | ~3.02 MB | ~884 KB |

Performance baseline

A repeatable benchmark lives in bench/. It exercises the shared Engine over 5 representative fixtures × N runs, separating cold-start (puppeteer launch) from warm renders:

npm run build
node bench/render-bench.mjs              # default: 3 runs each, markdown out
node bench/render-bench.mjs --runs 10    # tighter signal
node bench/render-bench.mjs --json       # machine-readable

Run it locally before any change you suspect could move the perf needle. Numbers are hardware-dependent (see bench/README.md).

License

Apache 2.0