Build ubx-monitor as the flagship showcase for XFrames — proving that a React-driven, DOM-free, ImGui-based framework can replace Electron for real-time data-heavy desktop applications. The showcase is built on XFrames + ubx-parser for sub-millisecond UBX binary protocol parsing (315+ message types).
Table (sorting, filtering, typed cells, reordering, visibility, column flags, context menus), InputText, Plotting (bar, scatter, heatmap, histogram, pie, candlestick), ProgressBar (fixed: Render now uses Yoga layout width instead of ImGui's fill-available), ColorIndicator, Tab close/reorder, ColorPicker.
Stages 1–10 complete: submodule plumbing, desktop activation, demo dashboard, tile-grid rendering, download pipeline, smooth panning, zoom, GPU texture eviction (512-tile LRU), prefetching, overlays (markers, polylines, accuracy circles), ubx-monitor integration with live GPS tracking.
-
TileCachetuning: increasemaxEntriesviaTileCache::configure()at MapView init (default 256 is low for tile-grid); exposeconfigure()via NAPI for runtime tuning from JS
Repo: ubx-monitor. ubx-parser integration, serial connection (SerialManager + useSerialConnection hook + ConnectionPanel with port/baud selection), UBX config commands (CFG-VALSET enabling NAV-PVT/NAV-SAT/NAV-DOP/MON-HW/NAV-STATUS on UART1), Console (raw data), Messages (table with filtering + rate), Navigation (fix type, position, accuracy, satellites, UTC time), Map (live position marker, accuracy overlay, GPS trail via MapView).
The panels that make the app visually compelling and demonstrate XFrames' rendering performance.
- Custom polar plot widget (azimuth/elevation projection) — JsCanvas with sky-view.js
- Satellite markers colored by constellation (GPS, GLONASS, Galileo, BeiDou)
- Satellite PRN labels
- Signal strength color coding on markers (dot radius scales with CNO)
- Used-in-fix vs tracked distinction (filled vs hollow markers)
Requires PlotBar multi-series support in XFrames (mirroring PlotLine's existing series architecture), then ubx-monitor panel rewrite.
Add PlotBarSeries struct and std::vector<PlotBarSeries> m_series to PlotBar (same pattern as PlotLineSeries in plot_line.h). Backward compatible — constructor creates default series[0].
-
plot_bar.h— AddPlotBarSeriesstruct (label + xValues/yValues vectors), replace flatm_xValues/m_yValueswithm_seriesvector, addAppendSeriesData(seriesIndex, x, y)andSetSeriesData(json), parseseriesprop inmakeWidget -
plot_bar.cpp— Loopm_seriesinRender()callingImPlot::PlotBars()per series, add"setSeriesData"and"appendSeriesData"ops inHandleInternalOp, addseriesprop handling inPatch()(grow/shrink/relabel per PlotLine pattern) -
PlotBar.tsx— Addseriesto destructured props and JSX, addsetSeriesData()andappendSeriesData()to imperative handle -
types.ts— AddPlotBarSeriesDeftype ({ label: string }), addseries?: PlotBarSeriesDef[]to PlotBar props -
widgetRegistrationService.ts— AddsetPlotBarSeriesData(id, seriesData)andappendPlotBarSeriesData(id, seriesIndex, x, y) -
ReactNativePrivateInterface.js— Add"series"toplot-barattribute list
- Rewrite
SignalStrengthPanel.tsx— split satellites into 4 quality-level series by CNO threshold: Weak (<20 dBHz), Moderate (20–30), Good (30–40), Excellent (>40). Each satellite appears in exactly one series. UsePlotBarwithseriesprop,showLegend=true. CallsetSeriesData()on each NAV-SAT update.
Per-signal CNO bars (L1/L2/L5) require UBX-NAV-SIG with per-signal cno. Blocked on upstream bug: cc.ublox.generated (commschamp/cc.ublox.commsdsl) is missing the Cno (U1) field between PrRes and QualityInd in the NavSig element definition. This causes a binary alignment bug — element size is 15 bytes instead of 16, misaligning all fields after prRes and all elements after the first. Issue filed upstream.
Once fixed:
- Update
cc.ublox.generatedsubmodule in ubx-parser, addcno: numberto NavSig list element intypes.d.ts, rebuild - Add
CFG-MSGOUT-UBX_NAV_SIG_UART1toenableUbxNavMessages()inubx-commands.ts - Create
useNavSighook — per-signal data withgnssId,svid,sigId,freqId,cno - Show per-signal bars grouped by satellite using PlotBar multi-series (L1/L2/L5 as series, offset X positions)
- Real-time position scatter plot (2D: East/North deviation from mean) — PlotScatter
- CEP (circular error probable) statistics (CEP₅₀, CEP₉₅)
- Altitude over time line plot — PlotLine
- Speed over time line plot — PlotLine
- Efficient data pipeline: serial port → native parser → JS → XFrames render loop
- Configurable update rates (throttle UI updates independently of message rate)
- Benchmark harness: measure end-to-end latency from byte arrival to pixel
- Add a live screenshot or GIF of the Dashboard demo on the homepage
- Publish benchmark: XFrames showcase vs Electron-based equivalent
- Metrics: startup time, memory footprint, CPU usage at idle, frame rate under load
- Include numbers in README and showcase repo
WASM build migrated to emsdk 5.0.2 + Dawn WebGPU. Three canvas widget engines — JsCanvas (QuickJS-NG), LuaCanvas (Sol2), JanetCanvas (Janet) — each with 19 ImDrawList draw bindings, Canvas 2D API shim, texture pipeline, setScript/setScriptFile/setData/onScriptError, and full React integration. External script file loading (desktop std::ifstream, WASM emscripten_fetch). 200+ unit tests across all engines.
Viewport culling, idle sleep (glfwWaitEventsTimeout), and scroll extent fixes are done. Stages 3–5 completed all mechanical optimizations (Table ColumnType enum, persistent filteredIndices, FormatNumberValue stack buffer, parseCSSColor bypass + color cache, canvas textureLookup moved to init, JsCanvas m_hasRenderFunc, PlotPieChart label pointer cache, StyledWidget single-traversal GetCustomColorsOrNull/GetCustomStyleVarsOrNull, Table cell data find()). Remaining items below are architectural changes — deferred until profiling shows they're the bottleneck.
- Switch all 13 NAPI event callbacks from
BlockingCalltoNonBlockingCall - Cache
m_elements[id]lookups inRenderElementById - Fix fall-through bugs in
HasStyle()/GetElementStyleParts()
- Guard
YGNodeCalculateLayoutwith dirty check - Pre-parse
ElementStyleParts::styleDefinto typed C++ struct at init time - Cache
GetChildrenMaxBottomresult - Pass layout values (left/top/width/height) through
Render()
Table ColumnType enum, persistent filteredIndices with dirty flag, FormatNumberValue stack buffer, parseCSSColor JSON bypass + DrawContext color cache, canvas textureLookup moved to init, JsCanvas m_hasRenderFunc guard, canvas dimension update guards, PlotPieChart m_labelPtrs cache, ColorIndicator/Slider string-to-bool flags, Image single find(), GetCurrentWindow hoist, StyledWidget GetCustomColorsOrNull/GetCustomStyleVarsOrNull (single traversal replacing Has+Get), Table cell data find().
- Replace
ElementOpDefJSON payload with typed discriminated union - Remove
setChildrenJSON round-trip: passvector<int>directly -
QueueAppendChild: use typed struct instead of JSON object - WASM: pass
0toemscripten_set_main_loopforrequestAnimationFrame
Removed broken prebuild-install script from @xframes/node, verified native addon loads from dist/, published 0.1.3 with all DLLs.
Refactored Node init() from 16 positional arguments to a single options object with named keys (assetsBasePath, fontDefs, theme, onInit, onTextChange, etc.). Added onBeforeExit callback — C++ calls it after the GLFW window closes and TSFNs are released, replacing std::exit(0). JS controls shutdown (default: process.exit(0)), enabling cleanup (config persistence, etc.) before exit.
- Allow plain numbers for
paddingandmargin(e.g.padding: 8as shorthand forpadding: { all: 8 }) - Restructure
@xframes/nodeinto platform-specific packages (@xframes/node-win32-x64, etc.) following the esbuild/swc pattern — each user only downloads binaries for their platform
- Additional language bindings beyond Node.js
- Mobile targets
- Accessibility (important, but not blocking the showcase)
- Full u-center 2 feature parity — this is a focused demo, not a product replacement