# Roadmap: chart-realtime ## Overview Build a standalone KMP real-time chart module from scaffold to polished publishable library. Six phases: module setup → core data structures → state API → rendering engine → demo validation → polish. Phases 2+3 parallelizable; Phase 4 is the critical path. ## Current Milestone **v0.1.0 — MVP** Status: Not started Phases: 0 of 6 complete ## Phases | Phase | Name | Plans | Status | Completed | |-------|------|-------|--------|-----------| | 1 | Module Scaffold | 2 | Not started | - | | 2 | Buffer + LoD | 2 | Not started | - | | 3 | State API | 2 | Not started | - | | 4 | Render Engine | 3 | Not started | - | | 5 | Demo App | 1 | Not started | - | | 6 | Polish + Docs | 2 | Not started | - | ## Phase Details ### Phase 1: Module Scaffold **Goal:** Buildable KMP module structure + Gradle config ready for code **Depends on:** Nothing **Research:** Unlikely (standard KMP module setup) **Scope:** - KMP module `:chart-realtime` with commonMain / androidMain - Version catalog entries (Compose, coroutines, kotlin.test) - Demo app module `:app` depending on `:chart-realtime` - Empty placeholder classes to confirm build passes **Plans:** - [ ] 01-01: KMP module + Gradle + version catalog - [ ] 01-02: Demo app module + dependency wiring ### Phase 2: Buffer + LoD **Goal:** Core data structures fully tested — CircularBuffer and LodDecimator **Depends on:** Phase 1 (module builds) **Research:** Unlikely (known algorithms) **Scope:** - `CircularBuffer` — pre-allocated FloatArray[timestamp, value], lock-free write, indexed read - `LodDecimator` — min/max envelope per pixel column, O(n) single pass - Unit tests for both (edge cases: empty, full, wrap-around, single point, fewer pts than pixels) **Plans:** - [ ] 02-01: CircularBuffer implementation + tests - [ ] 02-02: LodDecimator implementation + tests ### Phase 3: State API **Goal:** Public API surface complete — RealtimeChartState usable by consumers **Depends on:** Phase 2 (CircularBuffer ready) **Research:** Unlikely **Scope:** - `ChartConfig` data class (xWindowSeconds, yRange, t0, targetFps, maxBufferSeconds) - `SignalConfig` data class (name, color, strokeWidth, visible) - `YRange` sealed class (Auto, Fixed) - `T0` sealed class (FirstSample, Fixed) - `RealtimeChartState` — holds N CircularBuffers, addSignal/removeSignal, push(), collectFrom() **Plans:** - [ ] 03-01: Config models + sealed classes - [ ] 03-02: RealtimeChartState + Flow collector ### Phase 4: Render Engine **Goal:** Chart renders correctly at 200Hz with stable axes and smooth frame rate **Depends on:** Phase 2 (LoD) + Phase 3 (State) **Research:** Unlikely (Canvas API known) **Scope:** - `RenderLoop` — withFrameNanos, targetFps throttle, reads state snapshot - `AxisRenderer` — X/Y gridlines, tick interval math, labels (DrawScope) - `SignalRenderer` — FloatArray path build from LodDecimator output, drawLines - `RealtimeChart()` composable — assembles all renderers, exposes ChartConfig + RealtimeChartState **Plans:** - [ ] 04-01: RenderLoop + AxisRenderer - [ ] 04-02: SignalRenderer + path building - [ ] 04-03: RealtimeChart composable integration ### Phase 5: Demo App **Goal:** Running Android app proves 200Hz+ with 5+ signals without frame drops **Depends on:** Phase 4 (rendering complete) **Research:** Unlikely **Scope:** - Simulated sensor data source (coroutine emitting at 200Hz) - 5 signals with distinct colors on single chart - ChartConfig controls: xWindow, yRange mode, signal toggle - Verify ≥55fps sustained via Android Studio profiler **Plans:** - [ ] 05-01: Demo app with 5-signal 200Hz simulation ### Phase 6: Polish + Docs **Goal:** Publishable library with Material3 theming and minimal API docs **Depends on:** Phase 5 (demo validated) **Research:** Unlikely **Scope:** - Material3 default colors/typography for axis labels - ChartTheme override support - KDoc on all public API surface - README with usage example (3-line integration) - Maven local publish config **Plans:** - [ ] 06-01: Material3 theming + ChartTheme - [ ] 06-02: KDoc + README + publish config --- *Roadmap created: 2026-05-20*