KMPCharts/.paul/PROJECT.md
dtrentin b9ee5ddfa3 Initial commit: chart-realtime KMP library v0.4.1-SNAPSHOT
- RealtimeChart composable with Canvas-based rendering
- TieredBuffer: 3-tier ring buffer (5min full-rate, 10min @10Hz, 45min @1Hz) for 1h data support with ~5MB footprint
- LodDecimator: MEAN / MIN_MAX / MIN_MAX(default) / LTTB render-time decimation
- AxisRenderer: X/Y axis with INSIDE/BESIDE/HIDDEN label modes, T0-relative timestamps, scientific notation
- SignalRenderer: clipRect-bounded path rendering with LoD
- ChartTheme: Material3-compatible dynamic theming (light/dark)
- package: dev.dtrentin.chart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 01:48:51 +02:00

106 lines
4.3 KiB
Markdown

# chart-realtime
## What This Is
Standalone KMP module (Android-first) providing a high-performance Compose-based real-time line chart for sensor data visualization. Renders N simultaneous signals at 200Hz+ using Canvas with FIFO circular buffers and Level-of-Detail decimation. Packaged as a dependency consumable by any Android/KMP app.
## Core Value
Android developers can plot multiple high-frequency sensor signals (200Hz+) on a single chart without dropping frames or overloading the device.
## Current State
| Attribute | Value |
|-----------|-------|
| Type | Application (library module) |
| Version | 0.0.0 |
| Status | Initializing |
| Last Updated | 2026-05-20 |
## Requirements
### Core Features
- **Multi-signal real-time rendering** — N signals on same chart, each with own color/style, added/removed dynamically
- **FIFO circular buffer** — pre-allocated, lock-free write (data thread) / safe read (render thread), maxBufferSeconds configurable by caller
- **Level-of-Detail decimation** — min/max envelope per pixel column when buffer > pixel width; O(pixels) render cost regardless of buffer size
- **Flexible axis control** — X axis: seconds from t0 (T0.FirstSample or T0.Fixed); Y axis: YRange.Auto(padding) or YRange.Fixed(min, max)
- **Render rate decoupling** — data ingestion at any rate; rendering via withFrameNanos at display refresh rate (throttleable via targetFps param)
- **Flow-based API** — addSignal(name, flow, config) + manual push(name, timestampMs, value)
### Validated (Shipped)
None yet.
### Active (In Progress)
None yet.
### Planned (Next)
- Phase 1: KMP module scaffold + Gradle config
- Phase 2: CircularBuffer + LodDecimator + unit tests
- Phase 3: RealtimeChartState + Flow integration
- Phase 4: Canvas rendering engine (RenderLoop, AxisRenderer, SignalRenderer)
- Phase 5: Demo Android app (5+ signals at 200Hz)
- Phase 6: Material3 polish + API documentation
### Out of Scope
- iOS support (deferred to future milestone)
- Touch interaction / zoom / pan
- SciChart/paid-lib integration
- Network data sources (consumer provides Flow)
## Target Users
**Primary:** Android/KMP developers building sensor dashboards (IoT, medical, industrial)
- Need 200Hz+ real-time plotting
- Want drop-in Compose composable
- Expect Material3 visual consistency
## Constraints
### Technical Constraints
- KMP commonMain for all rendering logic (Compose Multiplatform Canvas)
- No object allocation in draw loop (pre-allocated FloatArray paths)
- Single draw call per signal (drawLines with FloatArray)
- Lock-free circular buffer (data thread != render thread)
- maxBufferSeconds: caller responsibility, no hard cap enforced by lib
### Business Constraints
- Standalone publishable module (Maven local / GitHub Packages)
- No paid/commercial dependencies
## Key Decisions
| Decision | Rationale | Date | Status |
|----------|-----------|------|--------|
| Canvas custom rendering over existing libs | Vico/MPAndroidChart cannot handle 200Hz+ without axis jumps or FPS drops | 2026-05-20 | Active |
| Render/data rate decoupling via withFrameNanos | 200Hz data != 60fps display; buffer absorbs delta | 2026-05-20 | Active |
| LoD min/max decimation | 1h buffer at 200Hz = 720k pts; screen = ~800px; must reduce O(n)→O(px) | 2026-05-20 | Active |
| maxBufferSeconds configurable, user responsibility | Avoid arbitrary caps; user knows their memory budget | 2026-05-20 | Active |
| Android-first, iOS deferred | Reduce scope, ship faster | 2026-05-20 | Active |
## Success Metrics
| Metric | Target | Current | Status |
|--------|--------|---------|--------|
| Sustained FPS at 200Hz, 5 signals | ≥55fps | - | Not started |
| Memory per signal per hour at 200Hz | ≤3MB | - | Not started |
| Demo app compiles and runs | Yes | - | Not started |
| API: add signal in ≤3 lines of code | Yes | - | Not started |
## Tech Stack
| Layer | Technology | Notes |
|-------|------------|-------|
| Language | Kotlin (KMP) | commonMain + androidMain |
| UI | Jetpack Compose / Compose Multiplatform | Canvas DrawScope |
| Build | Gradle + Version Catalog | Convention plugin if needed |
| DI | None (library, no DI framework) | Consumer wires state |
| Testing | kotlin.test + JUnit5 (androidTest) | Buffer + LoD unit tests |
| Demo | Android app module | 5+ signals, 200Hz simulation |
---
*PROJECT.md — Updated when requirements or context change*
*Last updated: 2026-05-20*