30 KiB
Phase 4+ Formats, Scripts, Paths, and UI Implementation Plan
For Hermes: Use subagent-driven-development skill to implement this plan task-by-task.
Goal: Expand OpenVistaPro from its current deterministic Rust CLI renderer into a clean-room terrain visualization pipeline with open-format importers, scriptable rendering, MakePath-style camera paths, and an eventual WGPU/egui application.
Architecture: Keep the existing single Rust crate until APIs stabilize. Add small modules around the current HeightGrid, Scene, .ovp.toml scene files, CLI, CPU top-down renderer, and CPU perspective demo renderer. Keep all import/compatibility code behind explicit module boundaries and optional features so the clean internal model stays independent from source formats.
Tech Stack: Rust 2024, cargo, clap, serde, toml, image, optional importer crates/features, future glam or nalgebra for path math, future wgpu/winit/egui for the app.
Current baseline
The repository already has:
src/terrain.rs:HeightGridwith validated dimensions, row-major samples, deterministicplaneandradial_hillfixtures.src/scene.rs: serializable camera, light, water, tree-line, snow-line, and haze settings.src/scene_file.rs: project-owned.ovp.tomlfiles withschema = "openvistapro.scene",version = 1, and a serializedScenepayload.src/colormap.rs: deterministic elevation-band colors.src/render.rs: deterministic top-down PNG renderer plus spike-quality CPU perspective raymarcher.src/import.rs: open-format import boundary withovp-text, feature-gated SRTM/HGT bytes, feature-gated ESRI ASCII Grid parsing, and feature-gated GeoTIFF parsing.src/script.rsandsrc/script_exec.rs: project-owned script parsing and execution for presets, grayscale PNG heightmaps, threshold changes, and PNG render outputs.src/path.rs: deterministic MakePath-inspired camera keyframe interpolation.src/app_state.rs,src/app.rs, andsrc/bin/openvistapro_app.rs: feature-gatedappshell usingeframe/eguiwith scene controls and CPU preview rendering.src/cli.rs:info,scene export,render, andscript runcommands.README.md,docs/legal/asset-policy.md,docs/research/reference-inventory.md, anddocs/knowledgebase/*.md: clean-room context and project constraints.
Phase 4 thin slices have landed as implementation checkpoints, while this file remains a historical implementation plan for follow-on work and validation.
Non-negotiable clean-room and repository hygiene rules
- Do not read, copy, decompile, translate, track, or commit proprietary VistaPro binaries, installers, archives, ISO/7z files, screenshots, extracted program files, sample landscapes, manuals, or scratch outputs.
- Keep
reference/,.work/, andtarget/local-only and ignored. - Use open/public formats and synthetic fixtures for tests.
- Commit only original source, original documentation, tiny synthetic fixtures, and openly licensed data with attribution.
- Treat VistaPro and MakePath as workflow inspiration. Do not attempt historical file compatibility until a later, separately reviewed clean-room plan approves the scope.
- Prefer TDD for every code change: write a focused failing test, run it and confirm the expected failure, implement the smallest code, then run the targeted test and the full validation suite.
Dependency map and ordering
- Importer foundation must come first: module shape, metadata, and tiny synthetic fixtures.
- Add one importer at a time, starting with the smallest pure-Rust parser. HGT/SRTM is the best first real open-format target because the file layout is simple.
- Add importer CLI plumbing after at least one importer can return
HeightGridplus source metadata. - Evolve scene/project metadata only after imported terrain needs provenance, source units, or vertical scale.
- Add the script MVP after CLI render/import commands are stable, because scripts should drive existing commands instead of inventing parallel behavior.
- Add path generation after script commands can carry camera keyframes.
- Add WGPU/egui only after the CPU renderer, scene files, importers, script execution, and path generation have stable tests and sample commands.
Milestone A: Importer foundation
Task A1: Create an importer module skeleton
Objective: Define a stable place for open terrain importers without changing renderer behavior.
Files:
- Create:
src/import.rsorsrc/import/mod.rs - Modify:
src/lib.rs - Test: unit tests inside
src/import.rsorsrc/import/mod.rs
Step 1: Write failing test
Add a test asserting that a TerrainSourceMetadata value records source format, dimensions, and elevation units.
Expected shape:
#[test]
fn metadata_records_format_dimensions_and_units() {
let meta = TerrainSourceMetadata::new("hgt", 1201, 1201, ElevationUnit::Meters);
assert_eq!(meta.format(), "hgt");
assert_eq!(meta.width(), 1201);
assert_eq!(meta.height(), 1201);
assert_eq!(meta.elevation_unit(), ElevationUnit::Meters);
}
Step 2: Verify RED
Run: cargo test import::tests::metadata_records_format_dimensions_and_units
Expected: FAIL because import and its metadata types do not exist.
Step 3: Implement minimal code
Create the module, expose it from src/lib.rs, and add only the metadata types and accessors required by the test.
Step 4: Verify GREEN
Run: cargo test import
Expected: PASS.
Step 5: Full validation
Run: cargo fmt --check && cargo test && cargo clippy --all-targets -- -D warnings
Task A2: Define importer result and error boundaries
Objective: Return both a HeightGrid and source metadata while keeping parser errors typed and user-displayable.
Files:
- Modify:
src/import.rsorsrc/import/mod.rs - Test: unit tests in the same module
Step 1: Write failing tests
Add tests for:
ImportedTerrain::new(grid, metadata)exposes the grid and metadata.ImportError::InvalidDimensionsrenders a helpful display message.
Step 2: Verify RED
Run: cargo test import::tests::imported_terrain_exposes_grid_and_metadata import::tests::invalid_dimensions_error_is_displayable
Expected: FAIL because the types do not exist yet.
Step 3: Implement minimal code
Add ImportedTerrain, ImportError, Display, and Error impls. Do not add a parser yet.
Step 4: Verify GREEN
Run: cargo test import
Expected: PASS.
Task A3: Advertise planned importers without claiming support
Objective: Keep openvistapro info honest while pointing users to planned importer work.
Files:
- Modify:
src/cli.rs - Test: unit tests inside
src/cli.rs
Step 1: Write failing test
Add a test that info_text() contains a separate planned/importer-roadmap line or docs pointer while supported_importers() remains empty until the first parser lands.
Step 2: Verify RED
Run: cargo test cli::tests::info_text_mentions_importer_roadmap_without_enabling_importers
Expected: FAIL because no importer roadmap text exists.
Step 3: Implement minimal code
Update info_text() only. Do not list DEM/HGT/GeoTIFF as supported until real parsers exist.
Step 4: Verify GREEN
Run: cargo test cli::tests::info_text_mentions_importer_roadmap_without_enabling_importers
Expected: PASS.
Milestone B: First open terrain importer: HGT/SRTM
Task B1: Add tiny HGT parser from bytes
Objective: Parse a square HGT/SRTM-style big-endian signed 16-bit elevation grid into HeightGrid using synthetic bytes.
Files:
- Create or modify:
src/import/hgt.rsif using a directory module, otherwise addhgtsubmodule insrc/import.rs - Modify:
src/import/mod.rsorsrc/import.rs - Test: unit tests for the HGT parser
Step 1: Write failing test
Use a tiny synthetic 3x3 byte buffer. Do not use real downloaded HGT files yet.
#[test]
fn parses_tiny_hgt_big_endian_i16_grid() {
let bytes = [
0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
0x00, 0x04, 0x00, 0x05, 0x00, 0x06,
0x00, 0x07, 0x00, 0x08, 0x00, 0x09,
];
let imported = parse_hgt_bytes(&bytes, 3).expect("3x3 HGT bytes should parse");
assert_eq!(imported.grid().width(), 3);
assert_eq!(imported.grid().height(), 3);
assert_eq!(imported.grid().sample(0, 0), Some(1.0));
assert_eq!(imported.grid().sample(2, 2), Some(9.0));
}
Step 2: Verify RED
Run: cargo test hgt::tests::parses_tiny_hgt_big_endian_i16_grid
Expected: FAIL because the parser is missing.
Step 3: Implement minimal code
Read pairs with i16::from_be_bytes, convert to f32, and reject buffers whose length is not side * side * 2.
Step 4: Verify GREEN
Run: cargo test hgt
Expected: PASS.
Task B2: Reject malformed HGT buffers
Objective: Prevent silent truncation or wrong dimensions.
Files:
- Modify: HGT parser module
- Test: HGT unit tests
Step 1: Write failing tests
Add tests for:
- Odd byte count.
- Declared side length whose sample count does not match the byte count.
- Zero side length.
Step 2: Verify RED
Run: cargo test hgt::tests::rejects_malformed_hgt_buffers
Expected: FAIL for missing validation.
Step 3: Implement minimal code
Map validation failures to ImportError variants.
Step 4: Verify GREEN
Run: cargo test hgt
Expected: PASS.
Task B3: Add CLI import path for HGT to render
Objective: Let the user render a synthetic or local HGT file through the existing render pipeline.
Files:
- Modify:
src/cli.rs - Modify: importer module
- Test:
src/cli.rstests plus importer tests
Step 1: Write failing parser test
Add a CLI parsing test for a future command shape, for example:
openvistapro render --import-hgt /tmp/tiny.hgt --hgt-side 3 --output /tmp/out.png
Keep --preset mutually exclusive with importer input once implemented.
Step 2: Verify RED
Run: cargo test cli::tests::parses_render_with_hgt_import
Expected: FAIL because the flags do not exist.
Step 3: Implement minimal code
Add optional render args for HGT input and side length. Build the HeightGrid from HGT when present; otherwise use the existing preset path.
Step 4: Verify GREEN
Run: cargo test cli::tests::parses_render_with_hgt_import cargo test hgt
Expected: PASS.
Feature-specific sample command
Run after creating a tiny synthetic fixture in /tmp:
cargo run -- render --import-hgt /tmp/openvistapro-tiny.hgt --hgt-side 3 --output /tmp/openvistapro-hgt.png
Expected: PNG is created and has 3x3 dimensions unless explicit render scaling is added later.
Milestone C: DEM and GeoTIFF planning and feature gates
Task C1: Add importer feature flags without pulling heavy dependencies by default
Objective: Make optional importer capabilities visible and keep the default build lightweight.
Files:
- Modify:
Cargo.toml - Modify:
src/import.rsorsrc/import/mod.rs - Test: compile-time cfg tests where practical
Step 1: Write failing check
Add a cfg-gated unit test or compile guard showing dem and geotiff modules are not required in the default build.
Step 2: Verify RED
Run: cargo test --no-default-features
Expected: FAIL only until features are declared and module cfgs compile.
Step 3: Implement minimal code
Add feature entries such as:
[features]
default = []
import-dem = []
import-hgt = []
import-geotiff = []
Only add external dependencies when a parser needs them.
Step 4: Verify GREEN
Run: cargo test --no-default-features && cargo test --all-features
Expected: PASS.
Task C2: Add ASCII DEM parser MVP
Objective: Support a simple open DEM text fixture before attempting broad real-world DEM variants.
Files:
- Create:
src/import/dem.rs - Modify:
src/import/mod.rs - Test: DEM unit tests with tiny inline text fixtures
Step 1: Write failing test
Use a tiny project-owned text fixture that declares width, height, units, and samples. Avoid proprietary files.
Step 2: Verify RED
Run: cargo test dem::tests::parses_tiny_ascii_dem_fixture --features import-dem
Expected: FAIL because parser is missing.
Step 3: Implement minimal code
Parse only the documented tiny subset. Reject unknown or incomplete input. Document that full DEM dialect support is future work.
Step 4: Verify GREEN
Run: cargo test dem --features import-dem
Expected: PASS.
Task C3: GeoTIFF importer behind an optional feature (implemented)
Status: Done. Landed as the optional import-geotiff feature; this section
records the implemented design. The crate survey behind it is
docs/research/geotiff-import-strategy.md.
Objective: Parse single-band GeoTIFF elevation tiles into the internal
HeightGrid without making default builds fragile or pulling a native
dependency.
Outcome: A pure-Rust path was chosen over GDAL. The importer uses the
geotiff-reader crate (local feature, cog/network feature off), declared as
an optional dependency gated by the import-geotiff Cargo feature. There is no
GDAL dependency and no native toolchain requirement, so import-geotiff builds
and tests run anywhere cargo runs — the "documented skip if native GDAL is not
installed" escape hatch is not needed and is reserved for any future,
separately reviewed GDAL-backed feature.
Files:
src/import/geotiff.rs:cfg(feature = "import-geotiff")module exposingparse_geotiff_bytes(&[u8]) -> Result<ImportedTerrain, ImportError>. It reads the payload in memory, rejects non-single-band rasters, decodes the raster asf32, and builds aHeightGridplusTerrainSourceMetadata(format"geotiff"). Reader/decode failures map toImportError::MalformedSource.src/import.rs: declares thegeotiffsubmodule under the feature cfg.Cargo.toml:import-geotiff = ["dep:geotiff-reader"];geotiff-writerandndarrayare dev-dependencies used only to generate the test fixture.src/cli.rs:supported_importers()andinfo_text()listgeotiffonly when the feature is built. (Arender --import-geotiffflag mirroring the HGT path remains future work.)
Fixture hygiene: Tests do not commit any GeoTIFF binary. They generate a
tiny single-band elevation tile in memory with geotiff-writer (dev-dependency)
and parse it back, mirroring the synthetic-fixture approach used for HGT. No
proprietary data and no large real-world DEMs enter the repository; real tiles
may be used only for local manual verification under the already-ignored
reference/ and .work/ directories.
Validation
Run: cargo test --no-default-features, cargo test geotiff --features import-geotiff,
and cargo test --all-features.
Expected: default and --no-default-features builds stay GeoTIFF-free; the
feature build and --all-features exercise the parser and pass without any
native dependency.
Milestone D: Scene/project metadata evolution
Task D1: Add terrain source metadata to project-owned scene files
Objective: Preserve source provenance and vertical units without putting importer-specific details into the renderer.
Files:
- Modify:
src/scene.rs - Modify:
src/scene_file.rs - Test: scene and scene_file unit tests
Step 1: Write failing tests
Add tests that:
- Default scenes have no terrain source metadata.
- Scene file round-trips a scene with source format, original dimensions, elevation unit, and optional path display string.
- Version handling remains explicit.
Step 2: Verify RED
Run: cargo test scene_file::tests::round_trips_terrain_source_metadata
Expected: FAIL because scene metadata does not exist.
Step 3: Implement minimal code
Add serializable structs and keep fields optional. Decide whether this is backward-compatible under SCENE_VERSION = 1 or whether to bump to version 2 with an upgrade path.
Step 4: Verify GREEN
Run: cargo test scene scene_file
Expected: PASS.
Task D2: Add project file plan before implementing a new container
Objective: Decide whether .ovp.toml remains a scene-only file or grows into a project document that references terrain/import metadata.
Files:
- Create:
docs/plans/phase-4-project-file.mdif needed - No production code in this task unless the plan chooses the format
Verification:
Run: git diff --check
Expected: no whitespace errors.
Milestone E: Script language MVP
Task E1: Define a tiny project-owned script command model
Objective: Represent a script as commands over existing scene/render operations without emulating proprietary syntax.
Files:
- Create:
src/script.rs - Modify:
src/lib.rs - Test: unit tests inside
src/script.rs
Step 1: Write failing test
Start with a deliberately small, original syntax such as:
set camera.position 0 30 -20
set camera.target 16 3 16
render frame 0
Add a test that parses those lines into typed commands.
Step 2: Verify RED
Run: cargo test script::tests::parses_set_camera_and_render_frame_commands
Expected: FAIL because script does not exist.
Step 3: Implement minimal code
Add Script, ScriptCommand, parser errors, and a line-oriented parser. Do not execute commands yet.
Step 4: Verify GREEN
Run: cargo test script
Expected: PASS.
Task E2: Execute script scene mutations without rendering
Objective: Apply set commands to Scene so script behavior can be tested without image output.
Files:
- Modify:
src/script.rs - Test: script unit tests
Step 1: Write failing test
Assert that applying parsed camera and haze commands changes a Scene exactly.
Step 2: Verify RED
Run: cargo test script::tests::applies_scene_mutation_commands
Expected: FAIL because execution is missing.
Step 3: Implement minimal code
Add an executor that handles only scene mutations. Unsupported commands return typed errors.
Step 4: Verify GREEN
Run: cargo test script
Expected: PASS.
Task E3: Add CLI script dry-run
Objective: Let users validate script parsing and scene mutations before rendering frames.
Files:
- Modify:
src/cli.rs - Modify:
src/script.rs - Test: CLI parser tests and script tests
Step 1: Write failing CLI test
Target command:
openvistapro script check --input /tmp/example.ovpscript
Step 2: Verify RED
Run: cargo test cli::tests::parses_script_check_command
Expected: FAIL because command is missing.
Step 3: Implement minimal code
Add script check to parse and report command count. No rendering yet.
Step 4: Verify GREEN
Run: cargo test cli::tests::parses_script_check_command cargo test script
Expected: PASS.
Feature-specific sample command
cargo run -- script check --input /tmp/openvistapro-example.ovpscript
Expected: prints a parse summary and exits successfully for valid script text.
Task E4: Render a scripted single frame
Objective: Let a script produce one PNG through the existing CPU renderer.
Files:
- Modify:
src/cli.rs - Modify:
src/script.rs - Test: CLI/script tests
Step 1: Write failing test
Add a test that a script with one render frame 0 command produces a PNG at a requested output directory using a small synthetic HeightGrid.
Step 2: Verify RED
Run: cargo test script::tests::renders_single_scripted_frame
Expected: FAIL because render execution is missing.
Step 3: Implement minimal code
Use existing render_top_down_to_path or render_perspective_to_path. Keep camera-demo/perspective mode explicit.
Step 4: Verify GREEN
Run: cargo test script cli
Expected: PASS.
Feature-specific sample command
cargo run -- script render --input /tmp/openvistapro-example.ovpscript --preset hill --output-dir /tmp/openvistapro-frames
Expected: creates frame-0000.png for the MVP.
Milestone F: MakePath-style camera path generator
Task F1: Add camera keyframe data structures
Objective: Represent camera/target path control points in project-owned types.
Files:
- Create:
src/path.rs - Modify:
src/lib.rs - Test: unit tests inside
src/path.rs
Step 1: Write failing test
Assert that a path with two keyframes exposes start/end camera positions and frame numbers.
Step 2: Verify RED
Run: cargo test path::tests::camera_path_records_keyframes_in_order
Expected: FAIL because path types do not exist.
Step 3: Implement minimal code
Add CameraKeyframe and CameraPath. Validate monotonically increasing frame numbers.
Step 4: Verify GREEN
Run: cargo test path
Expected: PASS.
Task F2: Add linear interpolation before splines
Objective: Generate deterministic per-frame camera poses from two keyframes.
Files:
- Modify:
src/path.rs - Test: path unit tests
Step 1: Write failing test
Assert frame 5 between frame 0 and frame 10 is the midpoint for position, target, and FOV.
Step 2: Verify RED
Run: cargo test path::tests::linear_interpolation_returns_midpoint_pose
Expected: FAIL because interpolation is missing.
Step 3: Implement minimal code
Add linear interpolation only. Avoid splines until linear output is tested.
Step 4: Verify GREEN
Run: cargo test path
Expected: PASS.
Task F3: Add spline interpolation as a separate, tested behavior
Objective: Add MakePath-inspired smooth camera paths without copying its implementation or file formats.
Files:
- Modify:
src/path.rs - Test: path unit tests
Step 1: Write failing tests
Use project-owned numeric fixtures for Catmull-Rom or cubic interpolation:
- Interpolation passes through keyframes.
- Endpoints do not overshoot for a simple straight path.
- Output is deterministic.
Step 2: Verify RED
Run: cargo test path::tests::spline_path_passes_through_keyframes
Expected: FAIL because spline mode is missing.
Step 3: Implement minimal code
Implement a standard documented spline algorithm from first principles. Link to the algorithm reference in comments if useful; do not use MakePath code or data.
Step 4: Verify GREEN
Run: cargo test path
Expected: PASS.
Task F4: Export generated paths to the OpenVistaPro script MVP
Objective: Let the path generator create a script that the script renderer already understands.
Files:
- Modify:
src/path.rs - Modify:
src/script.rs - Modify:
src/cli.rs - Test: path/script/CLI tests
Step 1: Write failing test
Assert that a two-keyframe path exported for 3 frames produces 3 camera set commands and 3 render commands.
Step 2: Verify RED
Run: cargo test path::tests::exports_path_as_script_commands
Expected: FAIL because export is missing.
Step 3: Implement minimal code
Add a converter from path samples to ScriptCommands.
Step 4: Verify GREEN
Run: cargo test path script cli
Expected: PASS.
Feature-specific sample command
cargo run -- path generate --input /tmp/openvistapro-path.ovppath --frames 60 --output /tmp/openvistapro-path.ovpscript
cargo run -- script check --input /tmp/openvistapro-path.ovpscript
Expected: generated script parses successfully.
Milestone G: WGPU/egui application after CLI stability
Status: Tasks G1–G4 have landed. src/app_state.rs holds testable app state and AppAction reducers; src/app.rs and src/bin/openvistapro_app.rs provide the app-feature eframe/egui shell. The shell now docks terrain, scene/camera, render, import, script, path, and project controls around the CPU top-down/perspective preview, with a bottom status bar and backend-backed import/script/path actions.
The shell map is tracked in docs/knowledgebase/ui-panel-map.md.
Remaining UI roadmap: Task G5 (WGPU renderer backend) plus the still-open gaps — legacy menus/dialogs, richer file/project chrome, animation-frame export, deeper script/path editors, and palette import/export / texture loading. All of it stays clean-room: no proprietary VistaPro assets, menus, or screenshots enter the repository.
Task G1: Create app-state crate/module without a window
Objective: Separate UI state from rendering and file formats before adding WGPU.
Files:
- Create:
src/app_state.rs - Modify:
src/lib.rs - Test: unit tests inside
src/app_state.rs
Step 1: Write failing test
Assert default app state contains a Scene, a synthetic terrain preset selection, and no loaded source file.
Step 2: Verify RED
Run: cargo test app_state::tests::default_app_state_has_scene_and_no_loaded_file
Expected: FAIL because app state does not exist.
Step 3: Implement minimal code
Add pure data structures only. Do not add WGPU or egui yet.
Step 4: Verify GREEN
Run: cargo test app_state
Expected: PASS.
Task G2: Add egui controls as pure state mutations first
Objective: Make UI semantics testable before creating a native window.
Files:
- Modify:
src/app_state.rs - Test: unit tests in
src/app_state.rs
Step 1: Write failing tests
Add tests for operations like setting water level, moving camera target, toggling renderer mode, and selecting an importer source.
Step 2: Verify RED
Run: cargo test app_state::tests::updates_scene_controls_from_ui_actions
Expected: FAIL because action handling is missing.
Step 3: Implement minimal code
Add an AppAction enum and reducer-style apply method.
Step 4: Verify GREEN
Run: cargo test app_state
Expected: PASS.
Task G3: Add native app feature gate
Objective: Keep CLI builds fast while making room for WGPU/winit/egui.
Files:
- Modify:
Cargo.toml - Create:
src/bin/openvistapro_app.rsor a gated module - Test: compile checks
Step 1: Write failing check
Add a feature-gated binary or module that should compile only with --features app.
Step 2: Verify RED
Run: cargo check --features app
Expected: FAIL until dependencies/module stubs exist.
Step 3: Implement minimal code
Add a window stub with no GPU terrain rendering. It may display app title and basic scene values.
Step 4: Verify GREEN
Run: cargo check --features app && cargo test --all-features
Expected: PASS.
Task G4: Bridge CPU preview into the app
Objective: Display the existing deterministic CPU top-down preview in egui before adding GPU terrain rendering.
Files:
- Modify: app module/binary
- Modify:
src/render.rsonly if a reusable image buffer helper is needed - Test: app-state/render tests where possible
Step 1: Write failing test
Add a pure test that app state can request a preview image and receives dimensions matching the current terrain.
Step 2: Verify RED
Run: cargo test app_state::tests::preview_request_returns_expected_dimensions --features app
Expected: FAIL until preview bridge exists.
Step 3: Implement minimal code
Reuse render_top_down and upload/display the resulting image in the UI. Avoid duplicating renderer logic.
Step 4: Verify GREEN
Run: cargo test --features app
Expected: PASS.
Task G5: Add WGPU renderer only after CPU preview is usable
Objective: Introduce GPU rendering as a second renderer backend, not as a replacement for the tested CPU reference.
Files:
- Create:
src/gpu_renderer.rsorsrc/render/gpu.rsafter deciding whether to splitsrc/render.rs - Modify: app module/binary
- Test: compile checks and pure math tests
Step 1: Write failing checks
Start with tests for camera matrices, terrain buffer dimensions, and shader-uniform construction. Avoid screenshot tests at first.
Step 2: Verify RED
Run: cargo test gpu_renderer --features app
Expected: FAIL because GPU renderer types do not exist.
Step 3: Implement minimal code
Add resource creation and a flat/grid terrain draw path. Keep renderer API driven by HeightGrid and Scene.
Step 4: Verify GREEN
Run: cargo test --features app && cargo check --features app
Expected: PASS.
Cross-milestone validation commands
Run these before every focused commit:
cargo fmt --check
cargo test
git diff --check
Run these before pushing any code-changing branch:
cargo fmt --check
cargo test
cargo clippy --all-targets -- -D warnings
git diff --check
Run feature-specific checks when a milestone enables optional code:
cargo test --no-default-features
cargo test --all-features
cargo check --features app
cargo test --features import-dem
cargo test --features import-geotiff
Use sample commands as acceptance checks when the related CLI surface exists:
cargo run -- info
cargo run -- scene export --output /tmp/openvistapro-default.ovp.toml
cargo run -- render --preset hill --width 256 --height 256 --output /tmp/openvistapro-hill.png
cargo run -- render --preset hill --scene /tmp/openvistapro-default.ovp.toml --width 256 --height 256 --output /tmp/openvistapro-hill-from-scene.png
cargo run -- render --preset hill --camera-demo --width 256 --height 192 --output /tmp/openvistapro-perspective.png
Commit strategy
- Commit the plan itself as
docs: expand phase 4 implementation plan. - Future implementation branches should commit one RED/GREEN slice at a time.
- Keep importer fixture commits separate from parser commits when licenses or provenance need review.
- Do not push generated PNGs, local HGT/DEM/GeoTIFF samples, archives, or scratch directories.
Definition of done for Phase 4+
Phase 4 is not one large task. It is complete when:
- At least one open terrain importer can create a
HeightGridfrom a tested, legal fixture. openvistapro inforeports real importer support accurately..ovp.tomlscene/project metadata can preserve terrain provenance where needed.- A project-owned script MVP can check scripts and render at least one deterministic frame.
- A path generator can produce scriptable camera frames from project-owned keyframes.
- The interactive app has tested app state and can show a CPU preview before WGPU terrain rendering is attempted.
- Default builds remain clean:
cargo fmt --check,cargo test,cargo clippy --all-targets -- -D warnings, andgit diff --checkpass.