Files
openvistapro/docs/plans/wgpu-egui-architecture-spike.md
Hermes Agent 672a6a44b7 docs: add WGPU/egui architecture spike
Document the single-crate app architecture, WGPU integration path, module boundaries, and next steps. Also clean up the terrain_gen test assertion so clippy stays green.
2026-05-25 13:35:11 -04:00

125 lines
5.9 KiB
Markdown

# WGPU/egui Interactive App Architecture Spike
> Goal: introduce an interactive OpenVistaPro app without destabilizing the existing CLI, importer pipeline, or deterministic CPU reference renderer.
## Decision
Keep the repository as a single Rust crate for now.
The current boundary set is still moving, but it is already useful:
- `src/terrain.rs`, `src/terrain_gen.rs`, `src/import.rs`, `src/scene.rs`, `src/scene_file.rs`, `src/script.rs`, `src/script_exec.rs`, `src/path.rs`, `src/render.rs`, and `src/colormap.rs` are the clean-room core.
- `src/cli.rs` and `src/main.rs` are the command-line adapter.
- `src/app_state.rs`, `src/ui_shell.rs`, `src/app.rs`, and `src/bin/openvistapro_app.rs` are the optional interactive shell.
A workspace split into `openvistapro-core`, `openvistapro-cli`, and `openvistapro-app` would add maintenance overhead before there is a second renderer/backend boundary that truly justifies it. The better near-term move is to keep a monolith and enforce boundaries with modules, feature flags, and tests.
Revisit a workspace split only when at least one of these becomes true:
1. the GPU renderer needs materially different dependencies from the CLI/reference renderer,
2. the core API stabilizes enough that the app shell can depend on it as a published internal crate boundary, or
3. build times / dependency fanout make the single-crate layout painful.
## Integration recommendation
Use egui as the interactive shell now, and treat WGPU as the rendering backend that arrives later behind a narrow viewport abstraction.
Recommended path:
1. Keep `eframe` for the windowing / egui host while the shell is still mostly controls and state.
2. Keep the current CPU renderer as the canonical reference output for tests and CLI smoke runs.
3. Introduce a tiny viewport trait or adapter boundary before any full GPU renderer lands.
4. Add a WGPU-backed viewport only once the render pipeline actually needs GPU surfaces, textures, and custom passes.
Why this order:
- `eframe` already gives a working egui host with the least glue.
- CLI builds stay GPU-free because the app stays behind the `app` feature.
- The CPU renderer remains the reference implementation for determinism and testability.
- WGPU can then become an implementation detail of the viewport, not a rewrite of the app state model.
## Module boundaries
Keep the following responsibilities separate:
### Core domain
- `terrain.rs`: immutable height grid and sampling rules.
- `terrain_gen.rs`: deterministic procedural generation inputs and output grid creation.
- `import.rs`: import boundary and source metadata.
- `scene.rs`: camera, lighting, hydrology, and palette-linked scene state.
- `scene_file.rs`: `.ovp.toml` persistence.
- `script.rs` / `script_exec.rs`: project-owned script language and executor.
- `path.rs`: MakePath-style camera path generation.
- `render.rs`: deterministic CPU render outputs.
- `colormap.rs`: palette / band mapping.
### CLI adapter
- `cli.rs` should stay focused on argument parsing and orchestration.
- Keep it thin enough that the same core operations can be called from future automation or from the app shell.
### Interactive shell state
- `app_state.rs` should remain pure state plus reducers / actions.
- `ui_shell.rs` should own section ordering, labels, and placeholder metadata.
- Avoid leaking egui types into either file.
### egui view/controller
- `app.rs` should remain the presentation layer that turns `AppData` into panels, menus, and a preview texture.
- The shell should consume state snapshots and call backend actions, not embed render or import logic inline.
### Future GPU viewport
- Introduce a narrow backend boundary for viewport rendering before the first custom WGPU renderer lands.
- Keep surface creation, texture upload, and draw passes out of `AppData`.
- Prefer a dedicated GPU adapter module over scattering WGPU setup across the UI code.
## Minimal first app shell
The smallest durable shell is:
- a stable top command bar,
- a left or right dock for section-specific controls,
- a central viewport that can show the CPU preview now and a GPU surface later,
- a status bar for file paths, script status, and render feedback,
- a tiny about/help dialog for orientation.
That is already enough to validate layout, interaction, and state management without pretending the GPU renderer exists yet.
## Testing strategy
Keep the test surface split the same way as the code.
### Unit tests
- `AppData` reducers and state transitions.
- `UiShellState` navigation order and section metadata.
- render-mode selection and preview-state plumbing.
- scene / script / path / importer behavior.
### Smoke commands
Use existing CLI and app entry points as smoke tests for the architecture:
- `cargo run -- info`
- `cargo run -- render --preset fractal --seed 1337 --width 64 --height 64 --output /tmp/openvistapro-fractal.png`
- `cargo run --features app --bin openvistapro_app` when a display is available
### Later integration tests
Once the GPU viewport exists, add lightweight screenshot or frame-smoke coverage around the viewport adapter rather than baking WGPU assumptions into the core state model.
## Next tasks
1. Add a small viewport abstraction so the egui shell can switch between CPU preview and a future GPU backend without changing `AppData`.
2. Keep the CPU renderer as the reference implementation for deterministic validation.
3. Add a dedicated GPU adapter module only when the WGPU surface truly exists.
4. Revisit a workspace split after the GPU path forces a second hard boundary.
5. Keep `docs/knowledgebase/architecture-notes.md` and `docs/knowledgebase/ui-panel-map.md` aligned with any later shell or viewport changes.
## Recommendation summary
Stay monolithic now, keep egui as the host shell, and treat WGPU as a future viewport backend rather than the reason to split the crate today. That gives OpenVistaPro the fastest path to a usable interactive app while protecting the CLI and deterministic renderer from churn.