Package Exports
- blazeplot
- blazeplot/package.json
- blazeplot/plugins/interactions
- blazeplot/plugins/legend
- blazeplot/plugins/tooltip
Readme
Fast WebGL2 plotting engine for the browser 🔥
Built for people who have hit the performance ceiling of Chart.js, Plotly, and similar browser charting libraries. BlazePlot keeps the hot path GPU-native and the DOM minimal, so large streaming datasets stay interactive instead of turning into a slideshow.
Built on WebGL2 + regl.
Installation
bun install blazeplotQuick start
<div id="chart" style="width:100%;height:400px"></div>
<script type="module">
import { Chart } from "blazeplot";
const chart = new Chart(document.getElementById("chart"));
const wave = chart.addLine({ capacity: 10_000, downsample: "minmax" });
wave.append(
Float64Array.from({ length: 1000 }, (_, i) => i),
Float32Array.from({ length: 1000 }, (_, i) => Math.sin(i * 0.02)),
);
chart.setViewport({ xMin: 0, xMax: 1000, yMin: -1.5, yMax: 1.5 });
chart.start();
</script>Features
| WebGL2 rendering | GPU-accelerated plot rendering from the ground up. No Canvas2D fallback. Axis labels use lightweight DOM layers. |
| Flexible data model | Streaming ring buffer or static arrays. Bring your own data shape. |
| LOD downsampling | Min/max pyramid for efficient line rendering at any zoom level — sparse views show raw points, dense views show vertical segments. |
| Pan & zoom | Pointer/touch pan and wheel zoom via Camera2D. Customizable viewport policies. |
| Grid lines | Data-anchored grid rendered as WebGL line lists. |
| Axis labels | Smart tick generation with DOM labels. Per-axis inside/outside positioning; outside axes reserve real layout gutters. |
| Multi-series | Independent buffers, styles, and visibility per series. Line, area, scatter, and bar modes are supported. |
| Plugin-ready UI | Optional built-in legendPlugin() and tooltipPlugin() use the same public state and hover APIs available to custom plugins. |
| Benchmark overlay | Built-in fps, frame time, vertex count, draw calls. |
| ResizeObserver | Automatic DPR-aware canvas sizing. |
API
Chart
| Signature | Description |
|---|---|
new Chart(container, options?) |
Create a chart inside an HTML container element. The chart owns the plot canvas and axis layout. |
chart.addSeries(config, style?) |
Add a data series. Returns SeriesStore. |
chart.addLine(config, style?) / addArea / addScatter / addBar |
Typed helpers that set the series mode for you. |
chart.removeSeries(series) |
Remove a previously added series. |
chart.setViewport({ xMin, xMax, yMin, yMax }) |
Set the visible data range. |
chart.getViewport() |
Return the current visible data range. |
chart.pan(intent) / chart.zoom(intent) |
Plugin-facing camera interaction helpers. |
chart.clientToData(clientX, clientY) / chart.dataToPlot(x, y) |
Convert between client/plot coordinates and data coordinates. |
chart.resize(dpr?) |
Resize the internal plot canvas to match its CSS size × DPR. |
chart.start() |
Start the render loop (rAF). |
chart.stop() |
Stop the render loop. |
chart.canvas |
Read-only access to the internal plot canvas. |
chart.xAxisElement / chart.yAxisElement |
Plugin-facing access to outside axis gutter elements. |
chart.theme |
Resolved theme values used by the chart and built-in plugins. |
chart.getFrameStats(target?) |
Copy per-frame benchmark counters into a reusable object. |
chart.getSeriesState() |
Return public series metadata/state for plugins or custom UI. |
chart.setSeriesVisible(series, visible) |
Toggle visibility and notify series-state subscribers. |
chart.pick(clientX, clientY, options?) |
Raw-data hit test. Supports "nearest-x" and "nearest-point"; returned items include actual sample X/Y and plot/client coordinates for highlights. |
chart.subscribe("hover", cb) / chart.subscribe("serieschange", cb) |
Subscribe to hover or series state changes. Returns an unsubscribe function. |
await chart.screenshot(options?) |
Export the full chart as an image Blob, including the WebGL plot and built-in DOM text overlays. |
chart.dispose() |
Dispose GPU resources, observers, input handlers, and owned DOM layout. |
ChartOptions
| Property | Default | Description |
|---|---|---|
viewportPolicy? |
— | Optional beforeRender viewport hook. Pass the same policy to interactionsPlugin({ viewportPolicy }) for pan/zoom hooks. |
hover? |
{ mode: "nearest-x" } |
Default hover picking behavior. mode can be "nearest-x" or "nearest-point". |
plugins? |
[] |
Optional ChartPlugin instances, e.g. legendPlugin() and tooltipPlugin(). |
theme? |
built-in dark theme | Override chart, axis, palette, legend, and tooltip colors/fonts. |
grid? |
true |
Show grid lines. |
gridStyle? |
{ color: theme.gridColor } |
Grid line color and width; overrides the theme grid color. |
axes? |
true |
Show axis tick labels. true/false, or per-axis { x?: boolean | AxisConfig, y?: boolean | AxisConfig }. |
ChartTheme
:root {
--plot-bg: #050816;
--plot-grid: rgb(148 163 184 / 0.22);
--plot-axis: #cbd5e1;
--series-a: #38bdf8;
--series-b: oklch(70% 0.19 22);
}new Chart(container, {
theme: {
backgroundColor: "var(--plot-bg)",
gridColor: "var(--plot-grid)",
axisColor: "var(--plot-axis)",
seriesColors: ["var(--series-a)", "var(--series-b)"],
tooltipBackgroundColor: "rgb(4 8 16 / 0.85)",
legendBackgroundColor: "rgb(4 8 16 / 0.85)",
},
});WebGL-facing colors (backgroundColor, gridColor, seriesColors) accept either normalized RGBA tuples ([r,g,b,a]) or CSS colors, including CSS variables inherited by the chart container. BlazePlot resolves CSS colors internally to WebGL-compatible RGBA floats while preserving CSS strings for DOM styling where appropriate. Per-series styles and plugin options still override theme defaults.
AxisConfig
| Property | Default | Description |
|---|---|---|
visible? |
true |
Show this axis. |
position? |
"inside" |
"inside" draws labels over the plot; "outside" reserves a real DOM gutter and shrinks the plot canvas. |
// X labels outside (bottom gutter), Y labels inside
new Chart(canvas, {
axes: { x: { position: "outside" }, y: true }
});ChartFrameStats
| Field | Description |
|---|---|
fps |
Instantaneous render-loop FPS. |
frameMs |
Milliseconds spent in render(). |
pointsRendered |
Number of vertices drawn this frame. |
drawCalls |
Number of GPU draw calls this frame. |
uploadBytes |
Bytes uploaded to GPU this frame. |
renderMode |
"none" / "raw" / "minmax" / "points" / "bars" / "area" / "mixed". |
Plugins
import { Chart } from "blazeplot";
import { interactionsPlugin } from "blazeplot/plugins/interactions";
import { legendPlugin } from "blazeplot/plugins/legend";
import { tooltipPlugin } from "blazeplot/plugins/tooltip";
const chart = new Chart(container, {
hover: { mode: "nearest-x" },
plugins: [
interactionsPlugin({ axis: "xy" }),
legendPlugin(),
tooltipPlugin({ mode: "nearest-point" }),
],
});Built-in plugins are optional. interactionsPlugin() provides plain-drag box zoom, Shift+drag plot pan, wheel zoom, double-click reset, and axis: "x" | "y" | "xy". When outside axes are visible, scrolling an axis zooms that axis and dragging an axis pans that axis; the plugin also applies a subtle axis hover color/filter configurable with axisHover, axisHoverColor, and axisHoverFilter. Legend/tooltip consume public APIs (getSeriesState, setSeriesVisible, pick, and subscribe) so custom UI can use the same contract. The default tooltip updates while the cursor is still on live charts and highlights the raw sample(s) it is reporting.
SeriesStore
| Signature | Description |
|---|---|
series.append(xs, ys) |
Append typed arrays of X and Y values (streaming). |
series.clear() |
Clear all data and reset. |
series.setVisible(v) |
Toggle visibility. |
series.visible |
Current visibility state. |
series.length |
Number of samples buffered. |
SeriesConfig
| Property | Description |
|---|---|
mode |
"line" / "area" / "scatter" / "bar" / "envelope" (envelope roadmap-only). |
capacity |
Ring buffer capacity (samples). |
id? / name? |
Optional metadata exposed to plugins, legend, and tooltip rows. |
downsample |
"minmax" or "none". Min/max LOD applies to line and bar rendering; area/scatter skip LOD. |
SeriesStyle
| Property | Default | Description |
|---|---|---|
color |
[0.3, 0.6, 1.0, 1.0] |
RGBA float color. |
lineWidth |
1 |
Line width in pixels. |
pointSize |
4 |
Scatter point size in CSS pixels. |
barWidth |
0.8 |
Bar width in data-space X units. |
baseline |
0 |
Area/bar baseline in data-space Y units. |
fillColor |
line color with 25% alpha | Area fill RGBA color. |
ViewportPolicy
beforeRender is consumed by Chart; beforePan and beforeZoom are consumed by interactionsPlugin({ viewportPolicy }).
interface ViewportPolicy {
beforePan?(camera: Camera2D, intent: PanIntent): PanIntent | null;
beforeZoom?(camera: Camera2D, intent: ZoomIntent): ZoomIntent | null;
beforeRender?(camera: Camera2D): void;
}Lower-level primitives
Camera2D, RingBuffer, MinMaxPyramid, AxisController are exported for advanced use cases.
Architecture
src/
core/ # Data model — series, datasets, LOD
render/ # GPU abstraction + regl backend
interaction/ # Camera, axis ticks, interaction intent types
ui/ # Orchestrator (Chart)Development
bun install
bun run dev # Vite dev server → preview/
bun run build # Package build (JS + declarations)
bun test # Tests
bun run typecheck # TypeScript strict check