# XCUI Editor Agent Guide This file documents the current editor architecture for agents working under `editor/`. It describes the code that exists in this checkout, not a desired future shape. If this file conflicts with the current code, `editor/CMakeLists.txt`, or the real directory tree, trust the code and update this file in the same change. ## Build Shape The important production targets are: - `XCUIEditorLib`: reusable XCEditor framework code from `editor/src` and `editor/include/XCEditor`, including the reusable window authority, synchronization planner, and presentation projection under `XCEditor/Windowing`. - `XCUIEditorAppWindowing`: app-internal static library for the current host contracts, content controllers, coordinators, frame transfer flow, backend-neutral runtime controllers, and window manager. It consumes render services through `editor/app/Rendering/Host` interfaces; it must not include concrete D3D12 or Win32 rendering implementation headers. - `XCUIEditorApp`: concrete editor executable. Its output name is `XCEngine`. Do not invent target boundaries that are not present in `editor/CMakeLists.txt`. Names such as `XCUIEditorAppCore`, `XCUIEditorAppLib`, and `XCUIEditorHost` are not current production library boundaries in this checkout. There is now a narrow public `editor/include/XCEditor/Windowing` layer for the generic window authority model, synchronization plan/planner, and presentation projection. App-specific window orchestration remains under `editor/app/Windowing`, render host contracts remain under `editor/app/Rendering/Host`, the concrete D3D12 renderer remains under `editor/app/Rendering/D3D12`, and the concrete Win32 host remains under `editor/app/Platform/Win32`. ## Layering Use these ownership boundaries when changing code: - `editor/include/XCEditor` and `editor/src`: reusable editor framework. Keep this layer independent from app state, Win32, D3D12 host code, and `App::*` types. - `editor/include/XCEditor/Windowing` and `editor/src/Windowing`: reusable window authority, validation, synchronization planning, commit, and presentation projection. Keep this layer generic and free of app content, host runtime, native platform, and rendering details. - `editor/app/Composition`, `Commands`, `Features`, `Project`, `Scene`, `State`, `System`, `UtilityWindows`: editor product semantics. - `editor/app/Windowing/Content`, `Coordinator`, `Frame`, `Host`, `Runtime`: app window orchestration, content ownership, frame driving, frame transfer, and per-window runtime state. Keep this layer backend-neutral; it may depend on `editor/app/Rendering/Host` contracts, but not concrete render backends. - `editor/app/Platform/Win32`: native window, message dispatch, input, lifecycle, chrome, HWND ownership, and native host adapter behavior. - `editor/app/Rendering/Host`: app rendering contracts consumed by app windowing and app content, including the render-runtime factory interface. - `editor/app/Rendering/D3D12`: concrete D3D12 window renderer, UI renderer, texture host, text system, render loop, render-runtime adapter, and render-runtime factory. The semantic dependency direction should remain: ```text XCEditor framework <- editor app semantics <- app windowing runtime / rendering host contracts <- application composition root / concrete Win32 and rendering adapters ``` ## Startup Flow The application starts through: ```text app/main.cpp -> RunXCUIEditorApp -> Application::Run -> Application::Initialize ``` The primary workspace window is initialized through: ```text EditorContext::BuildWorkspaceController() -> EditorWindowSystem::BootstrapPrimaryWindow(...) -> EditorWindowManager::CreateWorkspaceWindow(...) -> EditorWindowContentFactory::CreateWorkspaceContentController(...) -> EditorWindowRenderRuntimeFactory::CreateWindowRenderRuntime() -> EditorWindowRuntimeController(EditorContext, contentController, renderRuntime) -> EditorWindowInstance(runtimeController) -> EditorWindowHostRuntime::CreateHostWindow(windowInstance, ...) -> Win32 EditorWindow native peer ``` Keep authoritative window bootstrap in `EditorWindowSystem`; do not move it back into the Win32 host. ## Frame Runtime Ownership `EditorWindowManager` owns steady-state frame iteration and the immediate-frame callbacks used by native paint, resize, maximize/restore, and chrome actions. The Win32 host may request a frame through `EditorWindowHostCoordinator`, but it must not own the editor frame loop or fetch `EditorContext`. `EditorWindowRuntimeController` lives under `editor/app/Windowing/Runtime`. App windowing creates it from `EditorContext` plus a workspace or utility content controller plus a backend-neutral `EditorWindowRenderRuntime`, then wraps it in app-owned `EditorWindowInstance`. The Win32 host receives the instance only as an `EditorHostWindow` owner/native-peer binding; it must not store or call `EditorWindowRuntimeController` directly, create content controllers, or receive `EditorContext`. Concrete renderer selection is composed above both app windowing and the native host. `Application` creates the current `D3D12EditorWindowRenderRuntimeFactory` and passes it into `EditorWindowManager`; app windowing asks the factory for backend-neutral `Rendering::Host::EditorWindowRenderRuntime` instances. `EditorWindowInstance` owns runtime controllers that already contain their render runtime; the Win32 host must not create concrete render backends or own render runtimes. `EditorWindowRuntimeController` may call `EditorWindowRenderRuntime`, `UiTextureHost`, and `ViewportRenderHost`, but it must not include `Rendering/D3D12` headers, `windows.h`, or HWND types. The host contract direction is: ```text EditorWindowManager / coordinators -> ask EditorWindowRenderRuntimeFactory for EditorWindowRenderRuntime -> create EditorWindowRuntimeController -> wrap it in app-owned EditorWindowInstance -> EditorWindowHostRuntime::CreateHostWindow(windowInstance, ...) -> Win32 EditorWindow owns HWND/input/chrome and calls back through native-peer contract ``` ## Window Authority Model `EditorWindowSystem` owns the authoritative `UIEditorWindowWorkspaceSet` through `EditorWindowWorkspaceStore`. Normal per-frame workspace edits now use direct writes into that authoritative state: ```text EditorWorkspaceWindowContentController::UpdateAndAppend(...) -> EditorWindowSystem::TryBuildLiveWindowWorkspaceController(windowId, ...) -> UIEditorWorkspaceController::BindToState(...) -> workspace operations mutate the bound authoritative workspace/session ``` The old normal path is obsolete: ```text snapshot diff -> workspaceMutation frame request -> coordinator -> synchronization plan -> commit ``` Do not reintroduce `workspaceMutation` as the steady-state route for ordinary layout, tab, visibility, or active-panel edits inside an existing workspace window. Cross-window create, update, close, and destroyed-window reconciliation still use the planner/coordinator flow: ```text target UIEditorWindowWorkspaceSet -> EditorWindowSystem::BuildPlanForWindowSet(...) -> EditorWindowWorkspaceCoordinator::ApplySynchronizationPlan(...) -> EditorWindowSystem::CommitSynchronizationPlan(...) ``` `EditorWindowWorkspaceCoordinator::RefreshWindowPresentation(...)` refreshes each workspace window projection from authoritative state. Presentation should follow authority; it should not become a second source of truth. ## Frame Transfer Requests `EditorWindowFrameTransferRequests` is only for host-side or cross-window side effects that cannot be represented as direct in-window workspace edits. Current request fields are: - `workspace.beginGlobalTabDrag` - `workspace.detachPanel` - `utility.openUtilityWindow` There is no `workspace.workspaceMutation` field in the current frame transfer contract. Treat any doc, comment, or test name that says otherwise as stale. ## Window Categories Workspace and utility windows share the native host path but use distinct content controllers. - Workspace windows use `EditorWorkspaceWindowContentController`. - Utility windows use `EditorUtilityWindowContentController`. - App windowing creates content through `EditorWindowContentFactory`. - App windowing wraps content in `EditorWindowRuntimeController`, then owns that runtime through `EditorWindowInstance`. - The concrete host creates a native peer for an existing app-owned `EditorHostWindow`; it does not receive or validate runtime controllers. Utility windows are descriptor driven through `EditorUtilityWindowDescriptor`, `EditorUtilityWindowRegistry`, and `CreateEditorUtilityWindowPanel(...)`. Register new utility windows there rather than hard-coding them in Win32 host logic. ## Modification Rules - First decide whether the change belongs to XCEditor framework, app semantics, app windowing, Win32 host, or rendering host. - Keep public framework headers free of `App::*`, Win32, and D3D12 host types. - Do not add `editor/app` as an include directory for `XCUIEditorLib`. App-only services must cross into framework code through framework-owned interfaces and app-side adapters. - Do not compile `${XCUI_EDITOR_SHARED_SOURCES}` directly into `XCUIEditorApp`; the executable should consume shared framework code through `XCUIEditorLib`. - Use `editor/include/XCEditor/Windowing` and `editor/src/Windowing` for generic window authority, synchronization, validation, and presentation projection. - Use `editor/app/Windowing` for app-specific window runtime semantics, content, frame transfer, host contracts, runtime controllers, and coordinators. - Use `editor/app/Rendering/Host` for renderer-facing contracts that app windowing or app content may consume, including `EditorWindowRenderRuntimeFactory`. - Use `editor/app/Rendering/D3D12` for concrete D3D12 renderer ownership, swap-chain/present/capture details, UI texture/text/render systems, and the D3D12 `EditorWindowRenderRuntime` implementation and factory. - Use `editor/app/Platform/Win32` only for native host behavior and message integration. Win32 code may request frames through the host coordinator; it must not own the editor frame loop, expose `EditorContext`, or create concrete render backends. - Do not let `editor/app/Windowing` include `Platform/Win32` headers. - Do not let `editor/app/Windowing` include `Rendering/D3D12` headers, `windows.h`, or HWND types. It should consume concrete rendering only through `Rendering::Host::EditorWindowRenderRuntime` and `Rendering::Host::EditorWindowRenderRuntimeFactory`. - Do not let `editor/app/Platform/Win32` include `Rendering/D3D12` headers or implement render-runtime factory methods on the native host interfaces. - Do not spread D3D12 host types into app windowing content, coordinator, frame-transfer, runtime-controller, or public host-contract headers. - Do not let Win32 host code create workspace or utility content directly. It should receive an app-owned `EditorHostWindow`/`EditorWindowInstance` created by app windowing, not an `EditorWindowRuntimeController`. - Use direct authoritative workspace binding for ordinary in-window workspace mutations. - Use synchronization plans for operations that create, close, replace, or reconcile workspace windows. - Use frame transfer requests only for host-side or cross-window effects. ## Current Architecture Debt The highest-value windowing boundary has been hardened: `XCUIEditorLib` now owns the reusable window authority, synchronization planner, workspace store, and presentation projection under `XCEditor/Windowing`. `XCUIEditorAppWindowing` owns the app-internal content controller factory, runtime controllers, coordinators, frame transfer flow, host contracts, and manager. The Win32 host is the concrete native adapter and creates native host windows for app-owned `EditorWindowInstance` objects supplied by app windowing. The framework/app compile boundary is also enforced. `XCUIEditorLib` does not receive `editor/app` includes, and `XCUIEditorApp` does not directly compile the shared framework sources. When framework UI code needs app-provided data such as loaded icons, expose a framework-owned interface and adapt it in app composition code. The main windowing debt that was previously in the Win32 host has been cut: frame iteration, immediate frame driving, content-controller construction, and `EditorContext` ownership now live in app windowing. `EditorWindowHostCoordinator` does not expose `GetEditorContext()`, and the native host receives an app-owned `EditorWindowInstance` rather than raw workspace/utility content or a runtime controller. The native-peer ownership cut has also been made: `EditorWindowManager` owns `EditorWindowInstance` objects, each instance owns its `EditorWindowRuntimeController`, and `editor/app/Platform/Win32/Windowing` `EditorWindow` is a native peer for HWND/input/chrome/message integration. The Win32 platform code must stay free of `Windowing/Runtime/EditorWindowRuntimeController.h`. The renderer ownership cut has also been made: `XCUIEditorAppWindowing` no longer owns the concrete D3D12 window render loop or Win32 surface setup. `EditorWindowRuntimeController` consumes a backend-neutral `Rendering::Host::EditorWindowRenderRuntime`, and `EditorWindowManager` receives a backend-neutral `Rendering::Host::EditorWindowRenderRuntimeFactory`. The current D3D12 factory is composed in `Application`, not in the Win32 host. The remaining promotion debt is the app runtime surface itself. `XCUIEditorAppWindowing` is still app-internal and may depend on app semantics such as `EditorContext`, `EditorShellRuntime`, utility window descriptors, and product-specific content. Do not promote host interfaces, frame transfer, runtime controllers, content controllers, or render-runtime contracts to `XCEditor` until they are generic enough to expose. Do not move frame ownership back into `editor/app/Platform/Win32`, do not move concrete renderer ownership back into `editor/app/Windowing`, and do not move renderer factory ownership back into the Win32 host. Do not take another architecture cut just to keep carving this area. After the native-peer ownership boundary, the next default improvement should be boundary guardrails, such as checks that keep `editor/app/Windowing` free of `Rendering/D3D12`, `Platform/Win32`, `windows.h`, and HWND types, and keep `editor/app/Platform/Win32` free of `Rendering/D3D12` and `Windowing/Runtime/EditorWindowRuntimeController.h`. Consider another structural cut only when there is concrete pressure, such as another native host, another render backend, or headless editor/window tests. ## Validation Default editor validation is only the app build plus the 12-second smoke run: ```powershell cmake --build build --config Debug --target editor_ui_smoke_targets build\tests\UI\Editor\smoke\Debug\editor_ui_smoke_runner.exe build\editor\Debug\XCEngine.exe ``` Do not run `editor_windowing_phase1_tests`, `editor_ui_tests`, or broader test targets by default. Run them only when the user explicitly asks for them or a separate targeted change makes them necessary. The runner sets `XCUIEDITOR_SMOKE_TEST_DURATION_SECONDS=12`, waits for the editor to launch, lets the app auto-exit, and treats a clean editor exit as success. ## Recommended Reading Start with these files for editor/windowing work: - `editor/CMakeLists.txt` - `editor/app/Bootstrap/Application.*` - `editor/app/Composition/EditorContext.*` - `editor/app/Composition/EditorShellRuntime.*` - `editor/include/XCEditor/Workspace/UIEditorWorkspaceController.h` - `editor/src/Workspace/UIEditorWorkspaceController.cpp` - `editor/include/XCEditor/Windowing/System/EditorWindowSystem.h` - `editor/include/XCEditor/Windowing/System/EditorWindowSynchronizationPlan.h` - `editor/include/XCEditor/Windowing/System/EditorWindowSynchronizationPlanner.h` - `editor/include/XCEditor/Windowing/Presentation/EditorWorkspaceWindowProjection.h` - `editor/include/XCEditor/Windowing/Presentation/EditorWindowPresentationPolicy.h` - `editor/src/Windowing/System/EditorWindowSystem.cpp` - `editor/src/Windowing/System/EditorWindowWorkspaceStore.*` - `editor/src/Windowing/System/EditorWindowSynchronizationPlanner.cpp` - `editor/src/Windowing/Presentation/EditorWindowPresentationPolicy.cpp` - `editor/app/Windowing/Host/EditorWindowHostInterfaces.h` - `editor/app/Windowing/Content/EditorWindowContentController.h` - `editor/app/Windowing/Content/EditorWindowContentFactory.*` - `editor/app/Windowing/Content/EditorWorkspaceWindowContentController.*` - `editor/app/Windowing/Frame/EditorWindowFrameOrchestrator.*` - `editor/app/Windowing/Frame/EditorWindowTransferRequests.h` - `editor/app/Windowing/Runtime/EditorWindowRuntimeController.*` - `editor/app/Windowing/Runtime/EditorWindowScreenshotController.*` - `editor/app/Windowing/EditorWindowInstance.*` - `editor/app/Windowing/Coordinator/EditorWindowWorkspaceCoordinator.*` - `editor/app/Windowing/Coordinator/EditorUtilityWindowCoordinator.*` - `editor/app/Windowing/EditorWindowManager.*` - `editor/app/Rendering/Host/EditorWindowRenderRuntime.h` - `editor/app/Rendering/D3D12/D3D12EditorWindowRenderRuntime.*` - `editor/app/Platform/Win32/Windowing/EditorWindow.*` - `editor/app/Platform/Win32/Windowing/EditorWindowHostRuntime.*` - `editor/app/Platform/Win32/Windowing/EditorWindowMessageDispatcher.*` - `tests/UI/Editor/smoke/CMakeLists.txt` ## Recent Cuts - The framework-to-app icon dependency is sealed: `UIEditorShellCompose` uses the framework-owned `UIEditorShellIconResolver`, and the app adapts `BuiltInIcons` in `EditorShellDrawComposer`. - The framework/app compile boundary is sealed: `XCUIEditorLib` does not receive `editor/app` includes, `XCUIEditorApp` does not directly compile `${XCUI_EDITOR_SHARED_SOURCES}`, and the app consumes framework code through `XCUIEditorLib`. - The reusable window authority core lives in the framework: `EditorWindowSystem`, synchronization planning, workspace store, and presentation projection are under `editor/include/XCEditor/Windowing` and `editor/src/Windowing`. - App windowing owns the runtime cut: content controllers, `EditorWindowRuntimeController`, frame driving, frame transfer, host contracts, and `EditorWindowManager` are under `editor/app/Windowing`; Win32 remains the native adapter and no longer exposes `EditorContext`. - The native-peer ownership cut is sealed: app windowing now owns live `EditorWindowInstance` objects, those instances own `EditorWindowRuntimeController`, and Win32 `EditorWindow` only owns the native peer side for HWND/input/chrome/message work. `CreateHostWindow(...)` binds a native peer to an existing `EditorHostWindow`; it does not receive a runtime controller. - The concrete renderer cut is sealed: app windowing consumes `Rendering::Host::EditorWindowRenderRuntime` and `Rendering::Host::EditorWindowRenderRuntimeFactory`, while the current D3D12 implementation and factory live under `editor/app/Rendering/D3D12`. The factory is composed in `Application`; `editor/app/Windowing` should stay free of `Rendering/D3D12`, `windows.h`, and HWND types, and `editor/app/Platform/Win32` should stay free of `Rendering/D3D12`. - Default validation remains the editor app build plus the 12-second smoke run; run broader windowing/unit targets only for targeted coverage.