# dpg-gauges Build Steps There is no Step 0. Initial setup is listed separately, then implementation starts at Step 1. ## Workflow rules 1. Use `uv` for all Python package and dependency management. 2. Always read `codex/FEATURES.md`, `codex/ARCHITECTURE.md`, and `codex/AGENTS.md` before making code changes. 3. Keep `codex/AGENTS.md` as a rolling log of what has been done, what is broken, and what comes next. 4. Update `README.md` and `docs/` whenever public behaviour or examples change. 5. After every step, update `codex/AGENTS.md`, run relevant checks, and commit if working in git. 6. Do not casually change public API once introduced. 7. Dear PyGui calls must happen on the GUI thread only. 8. Runtime gauge updates are GUI-thread-only unless explicitly documented otherwise. 9. Prefer stable, boring implementation over clever drawing tricks. 10. Keep each step shippable and tested before moving to the next. ## Initial setup instructions Run these before Step 1 when starting from a clean repository: ```bash mkdir dpg-gauges cd dpg-gauges git init uv init --package dpg-gauges uv add dearpygui uv add --dev pytest ruff pyright ``` Create this structure: ```text src/dpg_gauges/ __init__.py api.py widget.py state.py renderer.py draw_layers.py sizing.py animation.py smoothing.py scales.py themes.py gauges.py diagnostics.py types.py exceptions.py examples/ tests/ docs/ codex/FEATURES.md codex/ARCHITECTURE.md codex/STEPS.md codex/AGENTS.md README.md ``` Recommended `pyproject.toml` additions: ```toml [tool.ruff] line-length = 100 target-version = "py311" [tool.ruff.lint] select = ["E", "F", "I", "UP", "B", "SIM"] [tool.pyright] typeCheckingMode = "basic" ``` Initial checks: ```bash uv run python -c "import dpg_gauges; print(dpg_gauges.__name__)" uv run ruff check . uv run ruff format . ``` ## Step 1 - Public API contract and pure core Goal: lock the public API surface and implement pure non-DPG components first. Tasks: 1. Define public exports in `__init__.py`. Required API names: ```python configure GaugeTheme GaugeStyle AnimationConfig SmoothingConfig ThresholdBand GaugeMarker StatusState GaugeStats analog_gauge digital_gauge bar_gauge level_gauge status_light segmented_gauge compass_gauge thermometer_gauge battery_gauge multi_value_gauge gauge_panel gauge_grid set_value get_value update_gauge configure_gauge set_thresholds set_markers set_show delete_gauge get_gauge_debug_state ``` 2. Add exceptions in `exceptions.py`. 3. Add shared dataclasses and types in `types.py`. 4. Implement configuration normalization dataclasses in `gauges.py`. 5. Implement pure scale helpers in `scales.py`. 6. Implement lightweight theme/style presets in `themes.py`. 7. Stub GUI-dependent public functions so imports succeed. 8. Add tests for imports, dataclass construction, clamp/normalize math, tick generation, threshold validation, and formatting. Checks: ```bash uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - public API imports cleanly - pure gauge config can be created and validated - value clamping and formatting are tested - no Dear PyGui context is required for Step 1 tests - API names are fixed before renderer work begins Commit: ```bash git add . git commit -m "step 1: lock public api and pure core" ``` ## Step 2 - State, sizing, animation, and smoothing model Goal: build the logical model before rendering final visuals. Tasks: 1. Implement `DpgGaugesConfig` and `configure(...)`. 2. Implement `GaugeState` and global gauge registry. 3. Implement `DirtyFlags`. 4. Implement sizing helpers: - requested size vs measured size - last non-zero size preservation - square gauge rect - stretch gauge rect 5. Implement animation interpolation in `animation.py`. 6. Implement smoothing helpers in `smoothing.py`. 7. Implement runtime state functions for `set_value`, `get_value`, `update_gauge`, `set_thresholds`, `set_markers`, `set_show`, and `delete_gauge` without final drawing complexity. 8. Add tests for registry behaviour, value/clamped/displayed separation, dirty flags, sizing transitions, animation interpolation, smoothing progression, and invalid values. Checks: ```bash uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - values clamp to min/max - non-finite values do not crash pure state helpers - dirty flags distinguish value, static, dynamic, text, size, and style changes - smoothing and animation are optional and testable without Dear PyGui - hidden/zero-size state does not erase last non-zero size Commit: ```bash git add . git commit -m "step 2: add gauge state sizing and animation model" ``` ## Step 3 - Widget shell and renderer foundation Goal: create stable Dear PyGui gauge shells and a renderer that can draw placeholders without flicker. Tasks: 1. Implement gauge creation context managers in `widget.py`. 2. Create internal group/child/drawlist structures for gauge widgets. 3. Register each gauge before yielding from the context manager. 4. Implement `GaugeRenderer` foundation: - measure size - schedule frame callbacks where animation is active - draw placeholder background/frame/value text - expose debug state 5. Implement `draw_layers.py` bookkeeping. 6. Implement `gauge_panel` and `gauge_grid` as lightweight layout helpers. 7. Add examples: - `examples/basic_digital.py` - `examples/basic_analog.py` - `examples/sizing.py` - `examples/dashboard.py` 8. Add Dear PyGui context smoke tests where feasible. Manual checks: ```bash uv run python examples/basic_digital.py uv run python examples/basic_analog.py uv run python examples/sizing.py uv run python examples/dashboard.py ``` Automated checks: ```bash uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - gauge shells appear inside Dear PyGui windows - widgets respect basic width/height options - hidden/show-later layout does not permanently collapse sizes - debug state reports useful state - no flicker through empty drawlists on simple value changes Commit: ```bash git add . git commit -m "step 3: add widget shell and renderer foundation" ``` ## Step 4 - Digital, bar, level, and status gauges Goal: implement the simplest high-value gauges first. Tasks: 1. Implement `digital_gauge` rendering. 2. Implement `bar_gauge` rendering with horizontal/vertical orientation. 3. Implement `level_gauge` rendering. 4. Implement `status_light` rendering. 5. Implement threshold and marker drawing for bar/level where applicable. 6. Implement optional tooltips and callbacks. 7. Add examples: - `examples/basic_digital.py` - `examples/basic_bar.py` - `examples/basic_level.py` - `examples/basic_status.py` - `examples/thresholds_markers.py` 8. Add tests for pure geometry and runtime update state. Manual checks: ```bash uv run python examples/basic_digital.py uv run python examples/basic_bar.py uv run python examples/basic_level.py uv run python examples/basic_status.py uv run python examples/thresholds_markers.py ``` Automated checks: ```bash uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - digital values format correctly - bar/level fill fraction is correct and clamped - status states display configured colors/text - thresholds and markers render visually without events - stretchable gauges behave in resizable layouts Commit: ```bash git add . git commit -m "step 4: add digital bar level and status gauges" ``` ## Step 5 - Analog, segmented, compass, thermometer, battery, and multi-value gauges Goal: complete the first-release gauge catalogue. Tasks: 1. Implement `analog_gauge`: - arcs - ticks - tick labels - needle - redline - markers 2. Implement `segmented_gauge`. 3. Implement `compass_gauge`. 4. Implement `thermometer_gauge`. 5. Implement `battery_gauge`. 6. Implement `multi_value_gauge`. 7. Ensure square gauges maintain aspect ratio by default. 8. Add examples: - `examples/basic_segmented.py` - `examples/basic_compass.py` - `examples/basic_thermometer.py` - `examples/basic_battery.py` - `examples/basic_multi_value.py` 9. Add tests for value-to-angle math, tick generation, compass wraparound, segment activation, battery clamp, and multi-value config validation. Manual checks: ```bash uv run python examples/basic_analog.py uv run python examples/basic_segmented.py uv run python examples/basic_compass.py uv run python examples/basic_thermometer.py uv run python examples/basic_battery.py uv run python examples/basic_multi_value.py ``` Automated checks: ```bash uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - all MVP gauge types render - analog redline and markers render correctly - compass wraps heading values sensibly - segmented gauges support dense shift-light style displays - square gauges do not distort in common layouts Commit: ```bash git add . git commit -m "step 5: complete first gauge catalogue" ``` ## Step 6 - High-rate updates, animation, and stress examples Goal: prove gauges remain readable and stable under fast telemetry. Tasks: 1. Integrate animation into renderer scheduling. 2. Integrate optional smoothing into value rendering. 3. Ensure repeated GUI-thread `set_value` calls coalesce naturally to the newest target. 4. Add examples: - `examples/animations.py` - `examples/live_high_rate.py` - `examples/live_worst_case.py` 5. High-rate examples should use a producer thread for data generation and GUI-thread frame callbacks for Dear PyGui updates. 6. Add debug fields for animation/smoothing state. 7. Add tests for animation convergence, smoothing reset behaviour, and latest-target wins. Manual stress checks: ```bash uv run python examples/animations.py uv run python examples/live_high_rate.py uv run python examples/live_worst_case.py ``` While examples run: - drive updates above 60 Hz where possible - verify gauges do not flicker - verify values remain human-readable with smoothing enabled - verify animation can be disabled for immediate response - verify UI remains responsive Automated checks: ```bash uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - high-rate examples remain stable - smoothing and animation are configurable per gauge - no unbounded update queue exists - renderer only schedules continuous frames while needed Commit: ```bash git add . git commit -m "step 6: add animation and high rate update stress tests" ``` ## Step 7 - Documentation, hardening, and beta release Goal: make the package usable as a dependency in DataFlux and public projects. Tasks: 1. Write `README.md` with: - install - minimal analog/digital examples - dashboard example - GUI-thread update contract - animation/smoothing explanation - threshold/marker examples 2. Write docs: - `docs/GETTING_STARTED.md` - `docs/EXAMPLES.md` - `docs/API_REFERENCE.md` 3. Add docstrings for all public functions. 4. Review public API exports. 5. Add hardening tests for: - unknown gauge - duplicate tag - invalid range - invalid threshold - invalid marker - non-finite value - deleted gauge updates - hidden layout sizing - animation disabled/enabled 6. Run all examples manually. 7. Test local editable install from another project: ```bash uv add --editable ../dpg-gauges uv run python -c "import dpg_gauges as dpgg; print(dpgg.__name__)" ``` 8. Bump version. Suggested initial beta: ```text 0.1.0b1 ``` Final checks: ```bash uv sync uv run pytest uv run ruff check . uv run ruff format --check . uv run pyright ``` Acceptance criteria: - all examples run - local editable dependency works - docs cover all public gauge types - high-rate examples are stable - README clearly documents Dear PyGui GUI-thread expectations - `codex/AGENTS.md` accurately describes status Commit: ```bash git add . git commit -m "step 7: harden docs and prepare beta" git tag v0.1.0b1 ```