Files
dpg-gauges/codex/STEPS.md
2026-07-02 12:40:20 +02:00

12 KiB

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:

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:

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:

[tool.ruff]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"]

[tool.pyright]
typeCheckingMode = "basic"

Initial checks:

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:

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
  1. Add exceptions in exceptions.py.
  2. Add shared dataclasses and types in types.py.
  3. Implement configuration normalization dataclasses in gauges.py.
  4. Implement pure scale helpers in scales.py.
  5. Implement lightweight theme/style presets in themes.py.
  6. Stub GUI-dependent public functions so imports succeed.
  7. Add tests for imports, dataclass construction, clamp/normalize math, tick generation, threshold validation, and formatting.

Checks:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:
uv add --editable ../dpg-gauges
uv run python -c "import dpg_gauges as dpgg; print(dpgg.__name__)"
  1. Bump version.

Suggested initial beta:

0.1.0b1

Final checks:

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:

git add .
git commit -m "step 7: harden docs and prepare beta"
git tag v0.1.0b1