Files
dpg-gauges/codex/STEPS.md

505 lines
12 KiB
Markdown

# 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 the completed step when 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.
11. Do not start the next step while the previous completed step is still uncommitted.
## 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
```