Splot - High-performance 2D plotting library replacing Qwt in PlotJuggler. C++17, Sokol (GPU), CMake. Targets: Linux, macOS, Windows, WebAssembly. Must handle millions of points at 50 Hz with GPU acceleration.
# Native (always use RelWithDebInfo for dev/benchmarks)
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo && cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failure
# WASM (activate emsdk first: source ~/emsdk/emsdk_env.sh)
emcmake cmake -B build-wasm -DCMAKE_BUILD_TYPE=Release && cmake --build build-wasm -j$(nproc)
cd build-wasm/examples && python3 -m http.server 8080Never benchmark with Debug builds - results are meaningless (7x slower than Release).
| Rule | Details |
|---|---|
| PIMPL | Public API classes hide Sokol/GPU types. Not for value types or hot paths. |
| Implementations | In .cpp files, not headers (except one-liners/templates) |
| Naming | PlotArea, PlotAxis, canvas_width, setXEnabled()/isXEnabled(), width() (no get prefix) |
| Terminology | Canvas = full window; PlotArea = data region (canvas minus margins) |
| Clipping | applyPlotAreaClip() / clearPlotAreaClip() |
| File | Contents |
|---|---|
docs/ARCHITECTURE.md |
System design, component relationships, tech decisions |
docs/TESTING.md |
Unit tests, visual regression tests, SSIM thresholds |
docs/rendering.md |
GPU rendering pipeline (Sokol, shaders, batching) |
docs/coordinates.md |
ScaleMap, PlotArea, data-to-pixel-to-NDC transforms |
docs/curves.md |
PlotCurve API, 6 curve styles, markers |
docs/interaction.md |
Input events, zoom, pan, rectangle zoom |
docs/lines.md |
Fragment shader AA line rendering technique |
docs/decimation.md |
MinMaxTree, M4 algorithm, streaming |
docs/performance.md |
Benchmark targets and measured results |
docs/requirements.md |
Full feature requirements (from Qwt analysis) |
docs/research.md |
Backend evaluation (Sokol vs bgfx vs others) |
BUILD.md |
Platform prerequisites, build options, troubleshooting |
When the user says "commit", always run the pre-commit workflow first (same as /project:pre-commit):
- Build and check for compiler warnings
- Run
ctest- all tests must pass - Check for TODOs, debug prints, commented-out code in changed files
- Spawn a code-review agent to review all changes
- Only commit if everything passes and reviewer approves
- Never add workarounds in tests - fix the library instead
- TDD: write benchmark/test before implementation
- Visual regression: SSIM comparison against reference images (see
docs/TESTING.md) - Decimation visual test reference is ground truth - never regenerate unless test data changes
Any request to "fix a bug", "fix the issue", or similar must follow this exact sequence:
- Write a failing unit test that exposes the bug (the test must FAIL before the fix)
- Verify the test fails by building and running it
- Apply the minimal fix to the library code
- Verify the SAME test passes (unchanged from step 1, unless the fix requires an API change)
- Run the full test suite (
ctest) to ensure no regressions
For visual/rendering bugs, use /screenshot-debugging to compare before/after screenshots.
Tests written in step 1 become permanent regression tests.
WASM builds must work in browser. Use scripts/screenshot.js for automated Puppeteer testing.
Shader gotcha: #version 300 es must be on the first line of GLSL strings (no leading newline in raw string literals).
- Plan before coding (plan mode for complex tasks)
- Delegate exploration to subagents (preserves main context)
- One chat per task; use
/clearbetween tasks
| Metric | Target | Achieved |
|---|---|---|
| Points per curve | 1M+ | 10M+ |
| Frame time | <20ms | ~2ms |
| Zoom/pan latency | <20ms | <1ms |
| Streaming rate | 100K pts/sec | 88.6M pts/sec |
datoviz-analysis/ contains Datoviz source for studying GPU visualization techniques (fragment shader AA, SDF markers, dirty tracking patterns).