# 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, and a headless
`panopainter_validate_shaders` target exist. Dependency migration is not
complete until component targets consume vcpkg packages 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,
PPI header recognition, and a pure typed settings document model, with
corrupt/truncated/unsupported 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. `pp_document` has
started with a pure canvas/layer/frame model, layer metadata operations, 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 parse-layout` now exercises that 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, 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_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
```

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_ppi_header_tests` passed.
- `pp_assets_settings_document_tests` passed.
- `pp_paint_brush_tests` passed.
- `pp_paint_blend_tests` passed.
- `pp_paint_stroke_tests` passed.
- `pp_document_tests` passed.
- `pp_renderer_api_tests` passed.
- `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_inspect_image_rejects_unsupported` passed as an expected failure
  test.
- `pano_cli_parse_layout_smoke` passed.
- `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`.
- `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.
