From 54cdc7efd51cfe0543b4425953eda5d49de50df7 Mon Sep 17 00:00:00 2001 From: Joe Blau Date: Tue, 29 Sep 2026 19:06:19 -0700 Subject: [PATCH] feat: order flow, WebGL2 rendering, and extension points Adds the order-flow stack and a WebGL2 backend to @bloxwap/chart, and rebuilds the landing-page playground around them. Library: - Extension points: series registry, host panes (stacked/docked) and pane primitives drawn behind or above the series. - Depth: DepthBook model, maintained L2 book manager (snapshot + diff deltas, gap resync, retry backoff) and the datafeed depth channel. - Inline order book: ladder or mirrored layout, docked or overlaid on the plot edge, theme-token colors, side-colored labels, bold best levels, per-row label culling and an optional true-spread label. - Liquidity heatmap with multi-stop color ramps; trade tape, trade prints, footprint series and delta/CVD indicators; session volume profile/TPO pane. - Visible-range volume profile: round-price rows sized to the screen, mirrored up/down volume, POC outline, theme tokens and tweened transitions on a frame scheduler. - WebGL2 renderer (renderer: 'webgl2') with automatic Canvas2D fallback. - chart.scale.scrollPrice and vertical plot panning while autoscale is off; new range-profile and order-book icons. - Fix: a throwing onBook no longer strands buffered depth deltas. Playground / landing page: - Controls move from the header into the left rail; a right-edge disclosure picks the volume profile, the full order book, or none. - Order book from Hyperliquid l2Book (Binance REST is geo-blocked), stitching two precisions for full depth plus the bbo feed for the true spread; WebGL2 on by default (?renderer=canvas2d to compare). - Mark, last-close and heatmap overlays are settings toggles, off by default. Test suite: 1849 tests, 100% line/branch/function coverage. Co-Authored-By: Claude Opus 5.5 --- apps/playground/index.html | 489 ++++++++++++- packages/chart/assets/icons/order-book.svg | 1 + packages/chart/assets/icons/range-profile.svg | 1 + packages/chart/bench/webgl.bench.mjs | 56 ++ packages/chart/package.json | 2 +- packages/chart/src/config.ts | 118 ++- packages/chart/src/core/chart.ts | 354 ++++++++- packages/chart/src/core/depth.ts | 22 + packages/chart/src/core/footprint.ts | 130 ++++ packages/chart/src/core/heatmap.ts | 195 +++++ packages/chart/src/core/inline-book.ts | 120 +++ packages/chart/src/core/pane.ts | 3 +- packages/chart/src/core/profile.ts | 270 +++++++ packages/chart/src/core/trade.ts | 21 + packages/chart/src/datafeed/datafeed-chart.ts | 159 +++- packages/chart/src/datafeed/depth-book.ts | 333 +++++++++ packages/chart/src/datafeed/index.ts | 22 + .../chart/src/datafeed/trade-aggregation.ts | 166 +++++ packages/chart/src/dom.ts | 276 ++++++- packages/chart/src/drawings/forecasting.ts | 35 +- packages/chart/src/index.ts | 126 +++- packages/chart/src/indicators/cvd.ts | 59 ++ packages/chart/src/indicators/delta.ts | 65 ++ packages/chart/src/indicators/index.ts | 2 + packages/chart/src/preset-theme.ts | 5 +- packages/chart/src/presets.ts | 15 +- packages/chart/src/render/gl/backend.ts | 226 ++++++ packages/chart/src/render/gl/candles.ts | 67 ++ packages/chart/src/render/heatmap.ts | 458 ++++++++++++ packages/chart/src/render/inline-book.ts | 454 ++++++++++++ packages/chart/src/render/primitive.ts | 55 ++ packages/chart/src/render/range-profile.ts | 327 +++++++++ packages/chart/src/render/renderer.ts | 118 ++- packages/chart/src/render/session-profile.ts | 377 ++++++++++ packages/chart/src/render/trade-prints.ts | 132 ++++ packages/chart/src/series/direction.ts | 4 +- packages/chart/src/series/footprint.ts | 191 +++++ packages/chart/src/series/heikin-ashi.ts | 3 +- packages/chart/src/series/index.ts | 24 +- packages/chart/src/series/registry.ts | 72 ++ packages/chart/src/ui/controller.ts | 20 +- packages/chart/src/ui/header.ts | 4 +- packages/chart/src/ui/icons.ts | 2 + packages/chart/src/ui/index.ts | 2 +- packages/chart/test/chart-header.test.ts | 14 + packages/chart/test/context-menu-core.test.ts | 28 +- packages/chart/test/controller.test.ts | 20 + packages/chart/test/depth-book.test.ts | 685 ++++++++++++++++++ packages/chart/test/dom.test.ts | 78 +- packages/chart/test/drawings.test.ts | 15 +- packages/chart/test/extension-points.test.ts | 237 ++++++ packages/chart/test/footprint.test.ts | 385 ++++++++++ .../chart/test/heatmap-customization.test.ts | 181 +++++ packages/chart/test/heatmap.test.ts | 447 ++++++++++++ packages/chart/test/inline-book.test.ts | 537 ++++++++++++++ packages/chart/test/range-profile.test.ts | 303 ++++++++ packages/chart/test/session-profile.test.ts | 394 ++++++++++ packages/chart/test/settings-polish.test.ts | 4 +- packages/chart/test/trades.test.ts | 347 +++++++++ packages/chart/test/webgl.test.ts | 429 +++++++++++ 60 files changed, 9570 insertions(+), 115 deletions(-) create mode 100644 packages/chart/assets/icons/order-book.svg create mode 100644 packages/chart/assets/icons/range-profile.svg create mode 100644 packages/chart/bench/webgl.bench.mjs create mode 100644 packages/chart/src/core/depth.ts create mode 100644 packages/chart/src/core/footprint.ts create mode 100644 packages/chart/src/core/heatmap.ts create mode 100644 packages/chart/src/core/inline-book.ts create mode 100644 packages/chart/src/core/profile.ts create mode 100644 packages/chart/src/core/trade.ts create mode 100644 packages/chart/src/datafeed/depth-book.ts create mode 100644 packages/chart/src/datafeed/trade-aggregation.ts create mode 100644 packages/chart/src/indicators/cvd.ts create mode 100644 packages/chart/src/indicators/delta.ts create mode 100644 packages/chart/src/render/gl/backend.ts create mode 100644 packages/chart/src/render/gl/candles.ts create mode 100644 packages/chart/src/render/heatmap.ts create mode 100644 packages/chart/src/render/inline-book.ts create mode 100644 packages/chart/src/render/primitive.ts create mode 100644 packages/chart/src/render/range-profile.ts create mode 100644 packages/chart/src/render/session-profile.ts create mode 100644 packages/chart/src/render/trade-prints.ts create mode 100644 packages/chart/src/series/footprint.ts create mode 100644 packages/chart/src/series/registry.ts create mode 100644 packages/chart/test/depth-book.test.ts create mode 100644 packages/chart/test/extension-points.test.ts create mode 100644 packages/chart/test/footprint.test.ts create mode 100644 packages/chart/test/heatmap-customization.test.ts create mode 100644 packages/chart/test/heatmap.test.ts create mode 100644 packages/chart/test/inline-book.test.ts create mode 100644 packages/chart/test/range-profile.test.ts create mode 100644 packages/chart/test/session-profile.test.ts create mode 100644 packages/chart/test/trades.test.ts create mode 100644 packages/chart/test/webgl.test.ts diff --git a/apps/playground/index.html b/apps/playground/index.html index 11275b0..30f7e05 100644 --- a/apps/playground/index.html +++ b/apps/playground/index.html @@ -17,6 +17,11 @@ #main { flex: 1; min-width: 0; display: flex; flex-direction: column; margin: 6px 6px 6px 0; border-radius: 12px; overflow: hidden; background: #171717; } body.light #main { background: #ffffff; } #header { flex: none; min-width: 0; } + /* Wide: the control rail carries the header's controls, so the plot starts at the top of the card. */ + @media (min-width: 600px) { #header { display: none; } } + /* Rail text toggles (timeframe, Auto / % / Log) fit the 36px buttons; a pressed toggle takes the accent. */ + #ctrl-rail .cts-btn-label { font-size: 11px; } + #ctrl-rail .rail-scale.cts-on { color: var(--cts-accent); background: var(--cts-accent-soft); } #stage { position: relative; flex: 1; min-height: 0; } #tools { flex: none; width: 52px; overflow: hidden; transition: width 240ms cubic-bezier(0.2, 0.8, 0.2, 1); } #tools.collapsed { width: 0; } @@ -26,7 +31,7 @@ canvas { display: block; width: 100%; height: 100%; touch-action: none; } /* bloxwap.pro chrome on dark for the rails, menus and dialogs: zero-stroke surfaces, #262626 hover fill, #00ff3f accent. - The header and the on-chart A / % / L strip take BLOXWAP_HEADER_THEME instead, which clears itself on light. */ + The header takes BLOXWAP_HEADER_THEME instead, which clears itself on light. */ body:not(.light) .cts-theme:not(.cts-light) { --cts-edge: transparent; --cts-panel-raised: #262626; --cts-accent: #00ff3f; --cts-accent-soft: #262626; --cts-on-accent: #0a0a0a; @@ -70,12 +75,15 @@