Skip to content

Developer Guide

You've cloned the repo and want to understand or extend chartjs2img. This page points you to the right spot for each kind of change.

What this project is

A thin service around Chart.js rendered inside headless Chromium:

chartjs2img architecture overview: CLI and HTTP server both invoke renderer.ts, which uses puppeteer to drive headless Chromium with Chart.js and its plugins.

Everything on the Node side is written so it can run unchanged under bun --compile — there's no build step required for development.

Repo layout

chartjs2img/
├── src/
│   ├── index.ts         # CLI entry point: argv parser, subcommand dispatch
│   ├── cli.ts           # `render` + `examples` CLI implementations
│   ├── server.ts        # `serve` HTTP server (Bun.serve)
│   ├── renderer.ts      # Puppeteer + Chromium lifecycle, screenshot pipeline
│   ├── template.ts      # Static HTML template loaded in the browser
│   ├── cache.ts         # In-memory LRU + TTL cache
│   ├── semaphore.ts     # Tiny async semaphore for concurrency control
│   ├── examples.ts      # Built-in chart examples (used by CLI + gallery)
│   ├── version.ts       # Single source of truth for VERSION
│   └── llm-docs/        # Per-module LLM-oriented Markdown snippets
│       ├── index.ts     # Aggregates + exports getLlmDocs()
│       ├── usage.ts
│       ├── chartjs-core.ts
│       ├── plugin-*.ts
│       ├── chart-*.ts
│       └── adapter-*.ts
├── examples/            # JSON inputs + PNG outputs (regenerable)
├── docs/                # VitePress bilingual documentation site
├── .github/workflows/   # CI
├── Dockerfile
├── package.json
└── README.md

The code base is intentionally small (~2000 LOC excluding llm-docs) — all the heavy lifting happens inside Chromium. When you're reading, the interesting file is usually renderer.ts.

Common contribution flows

"I want to add another Chart.js plugin"

See Adding a Chart.js plugin.

"I want to document a plugin for LLMs"

See Adding LLM docs.

"I want to tune concurrency / cache / browser behavior"

See Architecture for the moving parts, then check Modules for which file to edit. Most knobs are env vars — no rebuild needed.

"I hit a bug in rendering"

Check the browser console first. In renderer.ts, page.on('console', …) and window.__chartMessages capture both Chromium-side and Chart.js-side errors. They surface to the caller via X-Chart-Messages (HTTP) or stderr (CLI) — see Error handling.

Running from source

bash
bun install
bun run dev              # HTTP server on :3000
bun run cli -- help      # CLI help
bun run cli -- llm       # LLM reference output

bun run prepends the project's local binaries and doesn't need a compiled binary. Type check with bun run typecheck.

Running the full site locally

bash
bun run docs:dev         # VitePress dev server on :5173

The docs site has no backend. It reads docs/en/** and docs/ja/**, plus the sidebar/nav defined in docs/.vitepress/config.ts.

Where to go next

Edit this pageLast updated: