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

@krag-labs/krag-chart

v1.0.4

Published

High-performance WebAssembly candlestick chart with volume footprint, powered by ImPlot

Downloads

275

Readme

krag-chart

High-performance WebAssembly candlestick chart with volume footprint, powered by ImPlot and ImGui. Part of the KRAG Labs trading stack.


System Architecture

@startuml
!theme plain
skinparam backgroundColor #0d1117
skinparam defaultFontColor #c9d1d9
skinparam ArrowColor #8b949e
skinparam componentBorderColor #30363d
skinparam componentBackgroundColor #161b22
skinparam packageBorderColor #30363d
skinparam packageBackgroundColor #0d1117
skinparam noteFontColor #8b949e
skinparam noteBorderColor #30363d
skinparam noteBackgroundColor #161b22

package "External" {
  [Binance Exchange\n(WebSocket / REST)] as Binance #1a2332
}

package "KRAG Labs Backend" {
  [binance-collector\n(Go gRPC server)] as Collector #1a2332
  note right of Collector
    port 50051 — gRPC (backend)
    port 50052 — Connect HTTP (browser)
  end note
}

package "krag-trading-ui  (React + Vite)" {
  component "TanStack Query" as Query {
    [useCandles()] as UC
    [useFootprint()] as UF
    [useStreamTrades()] as UST
  }
  [KragChartWidget.tsx] as Widget
  [stream-store\n(Zustand)] as Store
}

package "krag-chart  (WebAssembly)" {
  [ImGui / ImPlot\nC++ → WASM] as WASM #1a2332
  note right of WASM
    bridge.cpp
    extern "C" push API
  end note
}

Binance --> Collector : WebSocket / REST
Collector --> UC     : GetCandles RPC\n(Connect JSON)
Collector --> UF     : GetFootprint RPC\n(Connect JSON)
Collector --> UST    : StreamTrades RPC\n(NDJSON stream)
UC  --> Widget : pushCandles()
UF  --> Widget : pushFootprint()
UST --> Store  : trade events
Store --> Widget : live trades
Widget --> WASM : pushCandles()\npushFootprint()\npushTrade()\nextern "C" / ccall
@enduml

Data Flow

1. Historical data (on symbol/timeframe change)

@startuml
!theme plain
skinparam backgroundColor #0d1117
skinparam defaultFontColor #c9d1d9
skinparam ArrowColor #58a6ff
skinparam sequenceParticipantBorderColor #30363d
skinparam sequenceParticipantBackgroundColor #161b22
skinparam sequenceArrowColor #8b949e
skinparam sequenceLifeLineBorderColor #30363d

participant "React\nKragChartWidget" as React
participant "binance-collector\n:50052" as Collector
participant "krag-chart.wasm\n(bridge.cpp)" as WASM
participant "ImPlot\nrenderer" as ImPlot

React -> Collector : POST /GetCandles\n{symbol, intervalMs, limit}
Collector --> React : {candles: [...]}

React -> Collector : POST /GetFootprint\n{symbol, intervalMs, tickSize}
Collector --> React : {candles: [{levels:[...]}]}

React -> WASM : pushCandles(json)\nextern "C" ccall
note right : populates TickerData\nrecalculates Bollinger Bands

React -> WASM : pushFootprint(json)\nextern "C" ccall
note right : maps to FootprintCandle[]\ndetects imbalances

WASM -> ImPlot : renders frame
@enduml

2. Live data (continuous streaming)

@startuml
!theme plain
skinparam backgroundColor #0d1117
skinparam defaultFontColor #c9d1d9
skinparam sequenceParticipantBorderColor #30363d
skinparam sequenceParticipantBackgroundColor #161b22
skinparam sequenceArrowColor #8b949e
skinparam sequenceLifeLineBorderColor #30363d

participant "binance-collector\n:50052" as Collector
participant "useStreamTrades\n(React hook)" as Hook
participant "stream-store\n(Zustand)" as Store
participant "KragChartWidget" as Widget
participant "krag-chart.wasm" as WASM

loop NDJSON server-stream
  Collector -> Hook : {"result": {trade}}
  Hook -> Store     : pushTrade(trade)
  Store -> Widget   : trades[] updated
  Widget -> WASM    : pushTrade(json)\nextern "C" ccall
  note right : accumulates into\nopen candle footprint
  WASM -> WASM      : re-renders next frame\n(~60 fps WebGL)
end

note over Collector, WASM
  On candle close: Widget calls pushCandleUpdate()
  to append the finalized candle to TickerData
end note
@enduml

3. WASM bridge (the connector layer)

The bridge lives in src/wasm/bridge.cpp. It is compiled into the WASM binary and exposes extern "C" functions that JavaScript calls via Emscripten's ccall:

// React → WASM
void pushCandles(const char* json_array);       // batch load
void pushCandleUpdate(const char* json_object); // single live candle
void pushFootprint(const char* json_array);     // pre-computed footprint
void pushTrade(const char* json_object);        // single live trade

// WASM → React (data export)
const char* getKlinesJSON();
const char* getFootprintJSON();
int getDataSize();
int getFootprintSize();

Packages

| Package | Location | Purpose | |---|---|---| | binance-collector | KRAG-Labs/binance-collector | Go gRPC server, collects from Binance | | @krag-labs/krag-chart | KRAG-Labs/krag-chart (this repo) | WASM chart, published to npmjs.com | | krag-trading-ui | KRAG-Labs/krag-trading-ui | React app, connects the two above |


npm Package Usage

Install

pnpm add @krag-labs/krag-chart

No auth required — the package is published publicly on npmjs.com. The C++ source stays private in this repo.

Basic React integration

import { useEffect, useRef } from 'react';
import KragChart from '@krag-labs/krag-chart';

function ChartContainer({ candles, footprint, trades }) {
  const containerRef = useRef(null);
  const chartRef     = useRef(null);

  useEffect(() => {
    const chart = new KragChart(containerRef.current);
    chartRef.current = chart;

    chart.ready().then(() => {
      // Hide built-in controls — React manages these
      chart.showSymbolSelector(false);
      chart.showLoadButton(false);
    });

    return () => chart.destroy();
  }, []);

  // Push historical candles when TanStack Query resolves
  useEffect(() => {
    chartRef.current?.pushCandles(candles);
  }, [candles]);

  // Push footprint data
  useEffect(() => {
    chartRef.current?.pushFootprint(footprint);
  }, [footprint]);

  // Push live trades one by one
  useEffect(() => {
    const latest = trades[trades.length - 1];
    if (latest) chartRef.current?.pushTrade(latest);
  }, [trades]);

  return (
    <div ref={containerRef} style={{ width: '100%', height: '600px', position: 'relative' }} />
  );
}

Candle data format (matches GetCandles response)

interface CandleData {
  time: number;       // Unix seconds
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
  isClosed?: boolean; // false = live/open candle
}

Footprint data format (matches GetFootprint response)

interface FootprintCandleData {
  time: number;          // Unix seconds (matches candle openTime)
  tickSize?: number;     // Price bucket size (e.g. 10.0 for BTC)
  levels: Array<{
    price: number;
    buyVol: number;
    sellVol: number;
    buyImbalance?: boolean;
    sellImbalance?: boolean;
  }>;
}

Trade data format (matches StreamTrades response)

interface TradeData {
  time: number;    // Unix seconds
  price: number;
  qty: number;
  isSell: boolean;
}

Building

Prerequisites

| Tool | Purpose | Install | |---|---|---| | Emscripten (emsdk) | Compile C++ → WASM | See below | | CMake ≥ 3.21 | Build system | sudo pacman -S cmake | | Ninja | Fast build | sudo pacman -S ninja | | vcpkg | Native C++ deps | git clone https://github.com/microsoft/vcpkg |

Install Emscripten (CachyOS / Arch)

git clone https://github.com/emscripten-core/emsdk.git ~/emsdk
cd ~/emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

Add source ~/emsdk/emsdk_env.sh to your ~/.bashrc or ~/.config/fish/config.fish.

Build WASM

# One-shot build + copy to package/dist/
./build-wasm.sh

# With clean
./build-wasm.sh --clean

# Manual (using cmake preset)
source ~/emsdk/emsdk_env.sh
cmake --preset wasm-release
cmake --build build/wasm --parallel

Build native (for testing the chart standalone)

# Requires vcpkg
export VCPKG_ROOT=~/vcpkg

cmake --preset linux-debug
cmake --build build/linux-debug

./build/linux-debug/krag-chart

Windows

call C:\emsdk\emsdk_env.bat
build-wasm.bat

Publishing to npm

The WASM binary is committed to package/dist/ or built locally. Publishing the artifact is safe — the C++ source stays private.

# Build WASM first
./build-wasm.sh

# Bump version and publish
cd package
npm version patch      # or minor / major
npm publish            # publishes @krag-labs/krag-chart publicly

Running Tests

C++ unit tests (native build)

cmake --preset linux-debug
cmake --build build/linux-debug --target test_footprint test_bridge
./build/linux-debug/test_footprint
./build/linux-debug/test_bridge

JS integration test (browser)

Open package/test/test.html in a browser after building WASM:

./build-wasm.sh
# then open package/test/test.html via a local server
npx serve package/
# → http://localhost:3000/test/test.html

What's Missing / Roadmap

| Priority | Item | Status | |---|---|---| | High | KragChartWidget.tsx in krag-trading-ui | In progress | | High | CI/CD: GitHub Actions WASM build + npm publish | Done | | Medium | Mock/demo candles when no data is pushed | Planned | | Medium | WASM memory cap (currently unbounded growth) | Planned | | Low | Dark/light theme API | Planned | | Low | Export chart as PNG via canvas | Planned |


Repository Structure

krag-chart/
├── src/
│   ├── Chart.cpp              ← Main ImGui/ImPlot chart app (from ImStocks)
│   ├── App.cpp/h              ← Window + GL setup
│   ├── BinanceTypes.cpp/h     ← TickerData, Kline structs
│   ├── FootprintData.cpp/h    ← FootprintCandle, PriceLevel, aggregation
│   ├── helpers.cpp/h          ← ImPlot formatters, rendering helpers
│   ├── wasm/
│   │   └── bridge.cpp         ← extern "C" push API (React → WASM)
│   ├── platform/
│   │   ├── native/            ← CURL + ixwebsocket (native builds)
│   │   └── web/               ← Emscripten fetch/websocket stubs
│   └── tests/
│       ├── test_footprint.cpp ← Unit tests: FootprintData aggregation
│       └── test_bridge.cpp    ← Unit tests: bridge JSON parsing
├── package/                   ← npm package (@krag-labs/krag-chart)
│   └── src/
│       ├── index.js           ← KragChart JS class
│       └── index.d.ts         ← TypeScript types
├── web/
│   └── shell.html             ← Emscripten HTML template
├── CMakeLists.txt
├── CMakePresets.json          ← linux-debug, linux-release, wasm-release, x64-*
├── vcpkg.json
├── build-wasm.sh              ← Linux/CachyOS build script
└── build-wasm.bat             ← Windows build script

Credits

Chart rendering engine adapted from ImStocks by Evan Pezent. ImGui by Omar Cornut. ImPlot by Evan Pezent.


License

Copyright (c) 2025 KRAG Labs. See LICENSE.