Professional, framework-agnostic depth chart for web trading interfaces.
Institutional-grade order-book depth visualization without a heavy charting runtime.
![]() | ![]() |
@rekurt/depth renders cumulative order-book liquidity on a canvas with a
small TypeScript API, deterministic book math, and no charting runtime
dependency. It is built for product teams that need a serious market-depth
primitive they can wrap in React, Vue, Svelte, or plain DOM code without pulling
in a full exchange UI.
Most depth-chart widgets are either demo-level SVG toys or large charting packages with order-book math bolted on. This package keeps the core narrow: normalize the book, compute the view and metrics, render a restrained canvas chart, and expose the state you need for a professional trading UI.
- Framework-agnostic
DepthChartclass with a stable imperative API. - Canvas renderer with separate interaction layer for hover/crosshair state.
- Typed-array render view for predictable memory layout and fast redraws.
- Deterministic aggregation for duplicate prices and zero-volume deletion.
- Correct cumulative depth direction for bids and asks.
- Centered price domain by default so the midpoint stays visually centered.
- Optional fit-domain mode for full-range inspection.
- Dark and light themes tuned for institutional fintech surfaces.
- ESM and CommonJS builds with TypeScript declarations.
The demo is intentionally styled as a dense institutional trading surface: graphite/ink dark mode, cold premium light mode, muted liquidity fills, neutral spread treatment, and bid/ask color used only as signal. The renderer avoids decorative gradients and exchange-clone glow so the chart can sit inside a serious SaaS or brokerage product without visual noise.
npm install @rekurt/depthimport{DepthChart}from'@rekurt/depth';constchart=newDepthChart({container: document.getElementById('depth')!,theme: 'auto',maxLevels: 80,priceDomainMode: 'centered',shape: 'step',showSpread: true,showMidLine: true,showLabels: true,data: {bids: [{price: 99,volume: 2},{price: 98,volume: 4},],asks: [{price: 101,volume: 3},{price: 102,volume: 5},],},onHover(level){console.log(level);},});chart.setData(nextOrderBookSnapshot);chart.updateOptions({maxLevels: 120,shape: 'linear'});constmetrics=chart.getMetrics();console.log(metrics.spread,metrics.spreadBps,metrics.imbalance);chart.fitAll();chart.destroy();The package does not ship a framework wrapper. In React/Vue/Svelte, mount the
chart once, feed snapshots through setData, and call destroy on unmount.
interfaceDepthSnapshot{bids: DepthLevel[];asks: DepthLevel[];midPrice?: number;timestamp?: number;sequence?: number|string;}interfaceDepthLevel{price: number;volume: number;}Validation rules:
pricemust be a finite positive number.volumemust be a finite non-negative number.- Duplicate prices are merged by summing volume.
- Merged zero-volume levels are removed from the render view.
Book view rules:
- Bids are selected as the best
Nlevels by descending price, then returned in ascending price order for left-to-right rendering. - Asks are selected as the best
Nlevels by ascending price and returned in ascending price order. - Bid cumulative depth is computed from best bid outward.
- Ask cumulative depth is computed from best ask outward.
maxLevelsis applied before cumulative values are computed.
Metrics:
spread=bestAsk-bestBidmidPrice=explicitMidPrice??(bestBid+bestAsk)/2spreadBps=spread/midPrice*10000imbalance=(bidTotal-askTotal)/(bidTotal+askTotal)For an empty book, imbalance is 0. For one-sided books without an explicit
midpoint, midPrice, spread, and spreadBps are null.
The default domain mode is centered.
newDepthChart({
container,
data,priceDomainMode: 'centered',});When both sides are present, the chart expands symmetrically around midPrice.
That keeps the spread/midline visually centered even when one side has a wider
price range.
Use fit when you want the smallest domain that contains all visible levels:
chart.updateOptions({priceDomainMode: 'fit'});constchart=newDepthChart(options);Methods:
setData(snapshot)validates and renders a new order-book snapshot.updateOptions(options)changes render/data options without rebuilding DOM.setTheme(theme)accepts'dark','light','auto', or explicit colors.fitAll()resets the viewport domain to the current snapshot.resize(width, height)manually resizes the canvas layers.destroy()removes DOM/event resources and is idempotent.getSnapshot()returns a defensive copy of the latest raw snapshot.getView()returns the typed-array render view.getMetrics()returns best bid/ask, spread, bps, totals, and imbalance.
Useful options:
maxLevels: keep only the bestNmerged levels per side.priceDomainMode:'centered'or'fit'.shape:'step'or'linear'.showGrid,showSpread,showMidLine,showLabels: chart chrome toggles.emptyMessage: no-data state text.priceFormat,volumeFormat: format axes, labels, and tooltip values.onHover: receives the nearest visible level ornull.onError: receives validation/render/interaction errors.
Use a built-in theme:
chart.setTheme('dark');chart.setTheme('light');chart.setTheme('auto');Or pass explicit colors:
chart.setTheme({background: '#090e13',grid: '#17232c',axis: '#2a3945',text: '#d8e2ea',mutedText: '#748594',bidLine: '#4fb783',bidFill: 'rgba(79, 183, 131, 0.12)',askLine: '#d96a6a',askFill: 'rgba(217, 106, 106, 0.12)',midLine: '#9aa7b2',crosshair: '#aeb8c2',});The renderer intentionally uses restrained solid translucent fills instead of heavy gradients. Spread is rendered as a neutral band, not as a red/green decorative separator.
The repository includes a vanilla Vite demo with synthetic BTC/ETH/SOL books, desktop/mobile layouts, a centered order-book ladder, hover inspection, and dark/light themes.
npm run dev:examplenpm install
npm test
npm run typecheck
npm run lint
npm run build
npm run build:example
npm pack --dry-runnpm pack --dry-run verifies that the published tarball contains README.md,
ESM/CJS builds, sourcemaps, and TypeScript declarations.
The public package intentionally stays small:
DepthChartDepthBufferDepthViewportDepthRenderer- TypeScript types for snapshots, levels, metrics, themes, and options.
The core API is DOM/canvas-based and framework-independent.
MIT


