Getting Started
Install kline-orderbook-chart, create your first candle chart, and start the render loop. From npm install to your first live candle in under five minutes.
Five steps from npm install to your first chart. The whole walkthrough takes about five minutes once you have your license key.
Prerequisites: Node.js 18+, a modern browser (Chrome 90+, Firefox 90+, Safari 15.4+, Edge 90+). For mobile: iOS 15+ Safari, Android 9+ Chrome.
1. Install the package
npm install @mrd/chart-engine
The package ships as a single ES module with the native engine bundled in. No additional loaders, no peer dependencies, no post-install scripts to run.
| What you get | Size |
|---|---|
| Full library — JS + engine | ~380 KB gzipped |
| Runtime dependencies | 0 |
| Framework dependencies | 0 |
2. Get a license key
A license key is required to run the engine.
- Free 30-day trial — full feature set, includes a small watermark. No credit card. After 30 days the engine refuses to render the chart body and shows a centred "License expired — click to purchase" CTA. Request a trial key →
- Production keys — single-domain, multi-domain, and unlimited tiers. See pricing.
Once you have a key, keep it server-side and inject it at request time. Do not commit it to a public repo.
3. Add a canvas to your HTML
The chart renders into a regular <canvas> element. The canvas needs a parent with a known size — the engine reads the parent's getBoundingClientRect() to size its internal framebuffer.
<div id="chart-container" style="width: 100%; height: 600px;">
<canvas id="chart" style="width: 100%; height: 100%; display: block;"></canvas>
</div>
Important:
display: blockon the canvas matters. Without it, the browser leaves a 4 px gap at the bottom for the descender baseline, and the engine will spend its life chasing that wrong dimension across resizes.
4. Initialise the chart
import { createChartBridge, prefetchEngine } from '@mrd/chart-engine'
// Step 1 (optional but recommended): start downloading the engine binary
// in the background as soon as your app boots. Fire-and-forget — no
// await needed. When createChartBridge() runs later, it reuses the
// already-loaded module instead of waiting on the network.
prefetchEngine()
// Step 2: create the chart. This is async — it validates the license,
// loads the engine, reads the canvas size, and returns a fully wired
// chart instance.
const canvas = document.getElementById('chart')
const chart = await createChartBridge(canvas, {
licenseKey: 'YOUR_LICENSE_KEY',
})
// Step 3: configure display settings (all optional, all have sensible
// defaults if you skip them).
chart.setTheme('dark') // 'dark' or 'light'
chart.setPrecision(2) // decimal places on the price axis
chart.setCandleInterval(3600) // candle interval in seconds (3600 = 1h)
createChartBridge(canvas, options) — options
| Option | Type | Description |
|---|---|---|
licenseKey | string | Your license key. Also accepts key as an alias. |
appId | string | Mobile app identifier for mobile-app license keys. Optional. |
The function returns a Promise that resolves to the chart instance — the object you'll call every method on for the rest of this guide. See Chart Instance for the full lifecycle reference.
5. Load candle data and start rendering
The engine expects OHLCV data as six parallel arrays. This shape avoids per-bar object overhead and matches what every crypto exchange API returns. Timestamps must be in Unix seconds (not milliseconds).
// Example: load 1000 hourly candles from your API.
const res = await fetch('/api/klines?symbol=BTCUSDT&interval=1h&limit=1000')
const raw = await res.json()
// raw is shaped like: [[openTime, open, high, low, close, volume, ...], ...]
const timestamps = new Float64Array(raw.length)
const opens = new Float64Array(raw.length)
const highs = new Float64Array(raw.length)
const lows = new Float64Array(raw.length)
const closes = new Float64Array(raw.length)
const volumes = new Float64Array(raw.length)
for (let i = 0; i < raw.length; i++) {
timestamps[i] = raw[i][0] / 1000 // ms → seconds
opens[i] = parseFloat(raw[i][1])
highs[i] = parseFloat(raw[i][2])
lows[i] = parseFloat(raw[i][3])
closes[i] = parseFloat(raw[i][4])
volumes[i] = parseFloat(raw[i][5])
}
chart.setKlines(timestamps, opens, highs, lows, closes, volumes)
chart.start()
start() boots the internal render loop. The chart now paints on every requestAnimationFrame where there's something new to draw, and stays idle otherwise.
You should see your candles on screen.
What you have so far
A live candle chart with:
- Mouse pan + scroll-wheel zoom
- Crosshair with price + time tooltip
- Auto-scaling Y axis
- Trackpad pinch zoom
- Touch pan + pinch on mobile
- All the UI affordances expected of a trading chart
What to add next
The fun part. Every advanced view layers on the same chart instance you already have.
- Append real-time candles as new ticks arrive — see Data Loading: real-time updates.
- Render an orderbook heatmap behind the candles — see Orderbook Heatmap.
- Switch to footprint chart type to show bid×ask volume inline on each candle — see Footprint Chart.
- Enable indicators like RSI, MACD, VRVP — see Indicators.
- Add markers and trendlines programmatically — see Drawing.
Framework integration
The chart instance is framework-agnostic — it just needs a <canvas> DOM node and your data. Ready-made integration recipes:
- React — see Integrating with React.
- Vue 3 — see Integrating with Vue (same page, second half).
- Svelte / vanilla — the same
createChartBridge(canvas, options)call works without modification. Mount the canvas in your component, callcreateChartBridgeinonMount, and callchart.destroy()when the component unmounts.
Common first-time issues
The canvas is blank and there are no errors.
Your canvas's parent has zero height. Check the container's computed style — if height: 0 or unset, the engine has nothing to draw into. Set an explicit height on the container or use flex: 1 inside a flex column.
License error in the console: "license expired". Your trial key is past its 14-day window. Reach out to support for an extension, or upgrade at pricing.
Candles appear shifted from the time axis.
Timestamps are in milliseconds, not seconds. Divide by 1000 before handing the array to setKlines().
Chart is sharp but the rest of my page is blurry, or vice versa.
DPR mismatch. The engine handles its own internal DPR scaling — you don't need to set canvas.width / canvas.height manually. Remove any DPR scaling code you had on the canvas before init.
What to read next
- Chart Instance — every lifecycle method (
start,stop,pause,resume,destroy) and the events your component will subscribe to. - Data Loading — real-time tick / append / prepend, infinite-scroll, and the typed-array shape.
- Events & Tooltips — render your own tooltip from the hover payload.
- Standalone side-panel engines — Orderbook · Depth Profile for single-venue order-flow signals or multi-exchange depth profile, DOM Ladder for a focused single-venue price ladder, Tick Stream for a trade-by-trade tape.
- Performance & Smoothness — keep the chart at 60 fps even with a chatty tick feed.
- Common Pitfalls — skim this before you ship; it covers ~80 % of the bugs first-time integrators hit.