# PanoPainter Modernization Roadmap Status: live Last updated: 2026-06-01 This is the living roadmap for modernizing PanoPainter into independently testable C++23 components while retaining all existing functionality. Keep this file current as phases are implemented. Do not let shortcuts, skipped platforms, or temporary adapters live only in chat history. ## How To Keep This Roadmap Live - Update the phase status before and after each implementation pass. - When a shortcut is introduced, add it to the debt log section in this file until `docs/modernization/debt.md` exists, then move debt entries there. - When a major architectural decision is made, add an ADR under `docs/adr/` once that directory exists. - Every phase must preserve old behavior unless the roadmap explicitly says otherwise. - Each phase must leave the repo in a buildable and testable state. - Do not add stubs without a debt entry, validation command, and removal condition. ## Locked Decisions - Graphics path: keep OpenGL working first; add Vulkan and Metal after the renderer boundary exists. - Required platforms at phase gates: Windows desktop/AppX, macOS, iOS, Android standard, Quest, Focus/Wave, Linux, and WebGL. - Dependency policy: use vcpkg where reliable; keep SDK, patched, or vendor-only dependencies with documented reasons. - Test stack: Catch2, golden/approval tests, and fuzz/property tests where useful. - Automation: local reproducible matrix first; hosted CI can be added later. - Documentation: ADRs, debt log, and this living roadmap. - "vkpkg" in older notes means `vcpkg`. - Target C++ standard: C++23. - Initial Windows CMake generator target: Visual Studio 2026 when available. ## Phase Status | Phase | Name | Status | Gate | | --- | --- | --- | --- | | 0 | Inventory, Safety Rails, And Memory | Complete | No behavior changes; old builds still work | | 1 | Unified CMake Skeleton | In progress | Root CMake builds the Windows app and owns the source list | | 2 | Toolchain, Diagnostics, And Dependencies | In progress | Strict desktop library builds compile cleanly | | 3 | Test Harness And Agent-Ready Automation | In progress | `ctest --preset desktop-fast` runs headlessly | | 4 | Component Split Without Behavior Change | Started | Each extracted target builds and tests | | 5 | Renderer Boundary And OpenGL Parity | Started | OpenGL output matches golden readbacks | | 6 | Platform Alignment | Not started | Every supported platform has named validation | | 7 | Hardening, Coverage, And Breaking-Point Tests | Not started | Each component has edge/failure tests | | 8 | Future Backend Readiness | Not started | Vulkan/Metal lab targets remain non-default | ## Target Component Architecture The refactor should move toward one-way dependencies: ```text pp_foundation -> pp_assets -> pp_paint -> pp_document -> pp_renderer_api -> pp_renderer_gl -> pp_paint_renderer -> pp_ui_core -> pp_panopainter_ui -> pp_platform_* -> panopainter_app ``` Intended responsibilities: - `pp_foundation`: logging facade, math/util helpers, events, task queues, binary streams. - `pp_assets`: `Asset`, `Image`, `Settings`, serialization, ABR, PPBR, and PPI helpers. - `pp_paint`: pure `Brush`, `Stroke`, stroke sampling, and CPU reference blend math. - `pp_document`: canvas document model, layers, animation frames, and undo/redo model. - `pp_renderer_api`: renderer-neutral interfaces for textures, render targets, shaders, meshes, readback, frame capture, and tracing. - `pp_renderer_gl`: current OpenGL implementation behind renderer interfaces. - `pp_paint_renderer`: stroke rasterization, layer compositing, cube/equirect export using `pp_renderer_api`. - `pp_ui_core`: `Node`, layout, generic controls, text/image primitives. - `pp_panopainter_ui`: panels, dialogs, `NodeCanvas`, and app-specific workflows. - `pp_platform_*`: Windows, macOS/iOS, Android, Linux, and WebGL shells. - `panopainter_app`: composition root only. Rules: - Component headers must not include platform SDK or graphics API headers unless the component name includes that backend or platform. - Pure libraries must build and test without a window, GL context, network, tablet, VR headset, or filesystem outside test temp directories. - Public APIs should return explicit status/result objects. PanoPainter app code keeps exceptions disabled unless isolated SDK wrappers require them. - Singleton access should be replaced at component boundaries with context or service objects. Temporary facade shims require debt entries. ## Phase 0: Inventory, Safety Rails, And Memory Status: complete on 2026-05-31. Created this roadmap, `docs/modernization/debt.md`, `docs/modernization/capability-map.md`, `docs/modernization/build-inventory.md`, and ADR 0001. Goal: create durable project memory and prevent silent shortcuts before large refactors begin. Implementation tasks: - Add `docs/modernization/roadmap.md`, `docs/modernization/debt.md`, and `docs/adr/`. - Add a shortcut rule: every temporary adapter, fallback, skipped platform, or retained vendored dependency must have owner, reason, validation command, and removal condition. - Generate a current capability map covering: - project open/save and PPI compatibility - image import/export and thumbnails - brush presets, ABR import, PPBR export/import - layers, blend modes, alpha lock, selection mask - animation frames and MP4/timelapse recording - VR, tablet, touch, mouse, keyboard, gestures - cloud upload/download/browse - UI dialogs, panels, layout XML, settings - Windows/AppX, macOS, iOS, Android standard, Quest, Focus/Wave, Linux, WebGL - Record current build commands and known platform prerequisites. Gate: - No behavior changes. - Existing Visual Studio, platform CMake, Gradle, Apple, Linux, and WebGL paths are not removed. ## Phase 1: Unified CMake Skeleton Goal: make CMake the canonical source list without breaking existing projects. Status: in progress. Root `CMakeLists.txt`, `CMakePresets.json`, and project option targets exist. The Windows desktop app builds through CMake as `PanoPainter`; the raw Visual Studio solution/project files were removed on 2026-05-31 by user decision. Android arm64 now configures and builds headless foundation/tool targets through the root CMake/NDK path. Non-Windows platform app/package files remain during Phase 6 alignment. Implementation tasks: - Add root `CMakeLists.txt` and shared CMake modules under `cmake/`. - Add `CMakePresets.json` with at least: - `windows-vs2026-x64` - `windows-clangcl-asan` - `linux-clang` - `android-arm64` - `android-x64` - `emscripten` - `macos` - `ios-device` - `ios-simulator` - Keep Android CMake, Linux CMake, WebGL CMake, Apple project files, and AppX packaging during the transition until each consumes shared component targets. - Move version generation into a CMake custom command using `scripts/pre-build.py`. - Fix `scripts/pre-build.py` only if required to avoid unnecessary rewrites or missing-tag failures. - Add CMake options: - `PP_BUILD_APP` - `PP_BUILD_TESTS` - `PP_BUILD_TOOLS` - `PP_ENABLE_OPENGL` - `PP_ENABLE_VULKAN_EXPERIMENTAL=OFF` - `PP_ENABLE_VR` - `PP_ENABLE_CLOUD` - `PP_ENABLE_VIDEO` - Define source-list helper targets so per-platform source duplication can be reduced incrementally. Gate: - Windows desktop app builds through CMake. - New CMake can configure on Windows. - Source list differences are understood and documented. - Non-Windows platform migration is debt-tracked until Phase 6. ## Phase 2: Toolchain, Diagnostics, And Dependencies Goal: turn the build into an error-finding system before deep refactors. Status: in progress. Initial warning/sanitizer option targets, `vcpkg.json`, a validated Windows headless vcpkg preset, `pp_ui_core` support for vcpkg tinyxml2 on that preset, and a headless `panopainter_validate_shaders` target exist. `windows-clangcl-asan` now configures as a headless Ninja/clang-cl ASan preset and uses the release MSVC runtime required by clang-cl ASan, but local ASan builds are blocked by DEBT-0014 until Clang and the selected MSVC STL are compatible. Dependency migration is not complete until remaining component dependencies and mobile/Apple triplets are validated. Implementation tasks: - Set C++23 through target features, not raw compiler flags. - Add warning profiles: - MSVC: `/W4 /permissive- /Zc:__cplusplus /Zc:preprocessor`. - Optional MSVC analysis preset: `/analyze`. - Clang/GCC: `-Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wnull-dereference`. - Keep exceptions disabled for PanoPainter targets, except isolated SDK wrapper targets when unavoidable. - Add sanitizer presets: - Clang/GCC ASan and UBSan for headless libraries. - MSVC ASan where supported. - TSan only for pure/headless targets. - Add tooling hooks: - `clang-tidy` - `cppcheck` - shader validation or compile checks - CTest dashboard output - Add `vcpkg.json`. - Move reliable dependencies to vcpkg first: - `fmt` - `glm` - `tinyxml2` - `stb` - `curl` - `sqlite3` - `glad` - `Catch2` - Keep vendored until proven: - OpenVR - OVR/Wave SDKs - Wacom WinTab - AppCenter - openh264 - mp4v2 - libyuv - patched or SDK-specific libraries Gate: - Desktop library targets compile with strict diagnostics. - New warnings caused by refactor are fixed or locally justified. - No global blanket warning suppression for project code. ## Phase 3: Test Harness And Agent-Ready Automation Goal: make each component reachable by automated tools and future agents. Status: in progress. `tests/` exists, `desktop-fast` runs headlessly, and PowerShell/bash wrappers exist for configure/build/test/analyze/platform-build/package-smoke. `pano_cli` exists with JSON automation commands for creating a `pp_document` model and inspecting image signatures, PPI headers, and layout XML; full document/app integration is debt-tracked as DEBT-0010 and full PPI body parsing is debt-tracked as DEBT-0013. Implementation tasks: - Add `tests/` with one executable per component. - Register CTest labels: - `foundation` - `assets` - `paint` - `document` - `renderer` - `ui` - `platform` - `integration` - `fuzz` - `slow` - `gpu` - Add `tools/pano_cli` for headless automation. - `pano_cli` should support: - create document - load project - save project - apply scripted strokes - import/export images - inspect layers - run layout parse - emit JSON results - Add local automation wrappers under `scripts/automation/`: - configure - build - test - analyze - package smoke - All wrappers must return machine-readable logs or summaries. - Establish `tests/data/` fixtures: - tiny PPI files - corrupt/truncated PPI cases - PNG/JPEG fixtures - ABR/PPBR samples - layout XML - shader snippets - brush stroke scripts Gate: - `ctest --preset desktop-fast --build-config Debug` runs without a GL context. - Non-render components can be tested on a headless machine. ## Phase 4: Component Split Without Behavior Change Goal: split libraries while keeping current app behavior. Status: started. `pp_foundation` exists with binary stream utilities and boundary/overread tests. It also owns strict decimal `uint32` parsing used by `pano_cli`, with rejection tests for empty, signed, mixed, and overflowing input. A synchronous event dispatcher, structured logging facade, bounded FIFO task queue, and deterministic `TraceRecorder` now record component/name/thread/frame/stroke metadata with filtering, capacity, and invalid-end tests. `pp_assets` has started with PNG/JPEG signature detection, PNG IHDR metadata parsing, PPI header/project byte-layout/body-summary recognition, and a pure typed settings document model, with corrupt/truncated/unsupported, extreme-dimension, and key/value limit tests. `pp_paint` has started with pure brush parameter validation/stamp evaluation, CPU reference math for the five current shader blend modes, and deterministic stroke spacing/interpolation plus a pure text stroke-script parser. `pp_document` has started with a pure canvas/layer/frame model, layer metadata operations, frame move/duration queries, and layer/frame/undo-redo history invariant tests. `pp_renderer_api` has started with renderer-neutral texture/readback descriptors and validation tests. `pp_paint_renderer` has started with deterministic CPU layer compositing over renderer extents using the paint blend reference. `pp_ui_core` has started with XML-layout-facing length parsing, color parsing, tinyxml-backed layout XML parsing, and invalid input tests. `pano_cli inspect-image` exposes PNG IHDR metadata as JSON, `pano_cli inspect-project` reports validated PPI thumbnail/body byte layout and body summary, and `pano_cli create-document` can create simple animation documents with explicit frame count/duration, and `pano_cli simulate-stroke` exercises the pure stroke sampler for scripted-stroke automation. `pano_cli simulate-stroke-script` loads stroke script fixtures, parses them through `pp_paint`, and samples every stroke. `pano_cli parse-layout` exercises the XML layout path. Continue expanding document behavior toward legacy Canvas parity and then port OpenGL classes behind the renderer boundary. Implementation tasks: - Extract components in this order: 1. `pp_foundation` 2. `pp_assets` 3. `pp_paint` 4. `pp_document` 5. `pp_renderer_api` 6. `pp_renderer_gl` 7. `pp_paint_renderer` 8. `pp_ui_core` 9. `pp_panopainter_ui` 10. `pp_platform_*` 11. `panopainter_app` - Remove renderer/platform dependencies from pure headers first, especially: - `Brush` - document/layer model - serializer - UI core headers - Keep facade shims where needed, but debt-track every shim. - Avoid large behavioral rewrites during extraction. - Each extracted component gets a focused test suite before moving to the next. Gate: - Old app still launches. - Component tests pass after every extraction. - No undocumented stubs or shortcuts. ## Phase 5: Renderer Boundary And OpenGL Parity Goal: make OpenGL an implementation detail and establish parity tests before adding new backends. Status: started. `pp_renderer_api` exists as a headless renderer-neutral target with texture descriptor, byte-size, viewport, mesh, readback bounds, command context, render device, shader program descriptor, mesh, render target, readback, and trace interface validation. OpenGL classes are not yet behind these interfaces. Implementation tasks: - Introduce renderer interfaces: - `IRenderDevice` - `ITexture2D` - `IRenderTarget` - `IShaderProgram` - `IMesh` - `ICommandContext` - `IReadbackBuffer` - `IRenderTrace` - Port current renderer classes behind OpenGL backend types: - `RTT` - `Texture2D` - `Sampler` - `ShaderManager` - `Shape` - Preserve current shader behavior and asset paths. - Add deterministic GPU tests: - clear - blit - texture upload/download - stroke composite - erase - layer blend - equirect export - readback bounds - Add CPU reference tests for blend modes. - Compare GPU output to golden/reference data with explicit tolerances. Gate: - OpenGL readbacks match golden data on Windows and Linux. - Mobile/WebGL compile gates remain green. ## Phase 6: Platform Alignment Goal: every supported platform consumes the same component targets. Implementation tasks: - Convert these builds to shared component targets: - Windows desktop - Windows AppX - macOS - iOS - Android standard - Android Quest - Android Focus/Wave - Linux - WebGL/Emscripten - Keep platform entrypoints thin: - window lifecycle - input dispatch - clipboard - file picker/share - GL context creation - VR SDK bridge - packaging only - Add or refine CMake toolchain/preset support for: - Android NDK ABIs - iOS device - iOS simulator - macOS - Emscripten - Keep SDK-only imported libraries documented until vcpkg triplets are proven. Gate: - Every platform has a named configure/build command. - Missing local prerequisites are documented. - Each platform has at least compile or package validation. ## Phase 7: Hardening, Coverage, And Breaking-Point Tests Goal: tests should try to break components, not only confirm current happy paths. Implementation tasks: - Add property/fuzz tests for: - binary streams - serializers - PPI parsing - ABR parsing - layout XML parsing - image metadata parsing - brush parameter extremes - layer/frame operations - undo/redo invariants - Add stress tests for: - thousands of stroke samples - extreme resolutions guarded by memory limits - rapid layer/frame edits - corrupt assets - cancellation during export - concurrent render/UI task scheduling - Add coverage for headless libraries on Clang/GCC. - Require coverage reports for changed components first; do not set a global threshold until the baseline is meaningful. - Add tracing spans around: - project load/save - render passes - stroke commit - readback - export - UI layout - platform I/O - Logs must include component, thread, frame/stroke id, and timing. Gate: - No shortcut remains undocumented. - Every component has unit tests and at least one failure or edge test. ## Phase 8: Future Backend Readiness Goal: prepare Vulkan and Metal without destabilizing the OpenGL parity path. Implementation tasks: - Create non-default targets only after OpenGL backend parity: - `pp_renderer_vulkan_lab` - `pp_renderer_metal_lab` - Use `D:\Dev\vkpaint` as reference material for Vulkan painting experiments, not as direct production code. - Before integration, prove: - ping-pong compositing path - input-attachment/subpass path where applicable - feedback-loop or framebuffer-fetch-style path where supported - synchronization and layout correctness under validation layers - Keep WebGPU as an optional future portability backend, not the core renderer contract. Gate: - Vulkan/Metal lab targets are opt-in. - OpenGL production backend remains stable. ## Test Matrix | Preset/Label | Purpose | Requires | | --- | --- | --- | | `desktop-fast` | Pure component unit tests | No GPU/window | | `desktop-gpu` | OpenGL backend golden/readback tests | GPU/GL context | | `fuzz` | Parser and serializer fuzzing | Fuzzer-capable compiler | | `stress` | Large and adversarial scenarios | Longer runtime | | `platform-build` | Configure/build each supported platform | Local toolchains | | `package-smoke` | AppX/APK/Apple/WebGL package smoke | Platform SDKs | Acceptance for each phase: - Previous phase tests still pass. - New component has its own tests. - No undocumented stubs. - No skipped platform without a debt entry. - Automation command is recorded in this roadmap or linked docs. ## Verified Commands Last verified on 2026-06-01: ```powershell cmake --preset windows-msvc-default cmake --build --preset windows-msvc-default --config Debug --target pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_document_tests pp_renderer_api_tests pp_paint_renderer_compositor_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pano_cli PanoPainter ctest --preset desktop-fast --build-config Debug powershell -ExecutionPolicy Bypass -File scripts\automation\test.ps1 -Preset desktop-fast -Configuration Debug powershell -ExecutionPolicy Bypass -File scripts\automation\build.ps1 -Preset windows-msvc-default -Configuration Debug -Target pano_cli cmake --build --preset windows-msvc-default --target panopainter_validate_shaders powershell -ExecutionPolicy Bypass -File scripts\automation\analyze.ps1 -Preset windows-msvc-default -NoApp set VCPKG_ROOT=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg cmake --preset windows-msvc-vcpkg-headless powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets windows-msvc-vcpkg-headless ctest --preset desktop-fast-vcpkg --build-config Debug cmake --preset android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug cmake --fresh --preset windows-clangcl-asan ``` Results: - `pp_foundation_binary_stream_tests` passed. - `pp_foundation_event_tests` passed. - `pp_foundation_log_tests` passed. - `pp_foundation_parse_tests` passed. - `pp_foundation_task_queue_tests` passed. - `pp_foundation_trace_tests` passed. - `pp_assets_image_format_tests` passed. - `pp_assets_image_metadata_tests` passed. - `pp_assets_ppi_header_tests` passed, including PPI thumbnail/body layout and body summary validation. - `pp_assets_settings_document_tests` passed. - `pp_paint_brush_tests` passed. - `pp_paint_blend_tests` passed. - `pp_paint_stroke_tests` passed. - `pp_paint_stroke_script_tests` passed. - `pp_document_tests` passed, including frame move, duration, and history invariants. - `pp_renderer_api_tests` passed, including shader descriptor validation. - `pp_paint_renderer_compositor_tests` passed. - `pp_ui_core_color_tests` passed. - `pp_ui_core_layout_value_tests` passed. - `pp_ui_core_layout_xml_tests` passed. - `pano_cli_create_document_smoke` passed. - `pano_cli_create_animation_document_smoke` passed and reports animation duration JSON. - `pano_cli_inspect_image_rejects_unsupported` passed as an expected failure test. - `pano_cli_inspect_png_metadata_smoke` passed and reports PNG metadata JSON for the tiny IHDR fixture. - `pano_cli_inspect_project_layout_smoke` passed and reports PPI thumbnail/body byte layout and body summary JSON. - `pano_cli_parse_layout_smoke` passed. - `pano_cli_simulate_stroke_smoke` passed and reports deterministic stroke sample counts/distances. - `pano_cli_simulate_stroke_script_smoke` passed and reports deterministic aggregate stroke-script counts/distances. - `panopainter_validate_shaders` passed, validating 25 shader programs and 7 shader includes for stage markers and include graph integrity. - PowerShell analyze automation returns JSON summaries and includes the shader validation target. - `windows-msvc-vcpkg-headless` configured through the Visual Studio bundled vcpkg root, installed the manifest dependencies, built the headless component matrix, and passed `desktop-fast-vcpkg`. - `pp_ui_core` built and tested against vcpkg tinyxml2 on `windows-msvc-vcpkg-headless` and against the vendored fallback on `windows-msvc-default` and `android-arm64`. - `windows-clangcl-asan` configures headlessly with clang-cl 18.1.8 and release MSVC runtime selection; build remains blocked and debt-tracked in DEBT-0014 because the selected VS 2026-preview STL requires Clang 20 or newer. - `PanoPainter.exe` built through CMake at `out/build/windows-msvc-default/Debug/PanoPainter.exe`. - PowerShell build/test automation wrappers return JSON summaries and passed local smoke checks. - PowerShell package-smoke wrapper validates the Windows CMake app executable and runtime `data/` copy. - Android arm64 configured with NDK 29.0.14206865 through the platform-build wrapper and compiled headless foundation/tool/test targets. - Known remaining warnings: legacy project/vendor diagnostics, Visual Studio vcpkg-manifest warning, `LNK4099` missing libyuv PDBs, and `LNK4098` runtime library conflict from retained vendor binaries. ## Current Debt Log The canonical debt log is now `docs/modernization/debt.md`. Keep this section as a reminder only; do not add new debt entries here. | ID | Status | Owner | Item | Reason | Validation | Removal Condition | | --- | --- | --- | --- | --- | --- | --- | | DEBT-0001 | Open | TBD | Existing platform build files remain alongside new CMake | Required for incremental migration | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets | | DEBT-0002 | Open | TBD | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace or document permanent vendored status after vcpkg triplet evaluation | | DEBT-0003 | Open | TBD | Existing singletons remain during initial split | Avoid behavior changes while introducing boundaries | App launch and component tests | Replace singleton reaches with context/service injection at component boundaries | ## Current Capability Map Seed Use this as the starting checklist for Phase 0 inventory. - Project I/O: PPI open/save, thumbnails, version metadata, autosave/save-as flows. - Image I/O: JPEG/PNG import/export, cube faces, equirectangular export, depth export. - Brush system: ABR import, PPBR import/export, presets, tip/pattern/dual brush, pressure, jitter, blend modes. - Painting: six cube faces, temporary stroke buffers, erase, flood fill, masks, alpha lock, layer compositing. - Layers and animation: layer add/remove/move/merge, blend/opacity/visibility, frame add/remove/duplicate/duration, MP4/timelapse export. - UI: XML layout, Yoga layout, panels, dialogs, color tools, brush tools, layers, animation timeline, settings, shortcuts, manual/changelog/about. - Input: mouse, keyboard, touch, gestures, Wacom tablet, stylus pressure, VR controllers. - Platform services: clipboard, file picker, save picker, directory picker, share/display file, keyboard show/hide. - VR/platform variants: OpenVR desktop, Quest, Focus/Wave, Android standard, iOS/macOS, Linux, WebGL. - Cloud/network: upload, download, browse, license/check flows. - Recording/export: PBO readbacks, MP4 encoder, timelapse frames.