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

5.9 KiB

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.