Files
XCEngine/editor/AGENTS.md

9.5 KiB

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.
  • XCUIEditorAppWindowing: app-internal static library for the current window authority, planner, store, presentation policy, host contracts, content controllers, coordinators, frame transfer flow, and window manager.
  • 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 no public editor/include/XCEditor/Windowing layer yet. Windowing is currently an app-internal architecture under editor/app/Windowing plus the concrete Win32 host 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/app/Composition, Commands, Features, Project, Scene, State, System, UtilityWindows: editor product semantics.
  • editor/app/Windowing/System: authoritative window set, validation, synchronization planning, and commit.
  • editor/app/Windowing/Presentation: projection policy derived from authoritative state.
  • editor/app/Windowing/Content, Coordinator, Frame, Host: platform neutral app window orchestration.
  • editor/app/Platform/Win32: native window, message dispatch, input, lifecycle, chrome, and concrete host runtime.
  • editor/app/Rendering: editor rendering host and D3D12 integration.

The semantic dependency direction should remain:

XCEditor framework
  <- editor app semantics
  <- app windowing
  <- Win32 host / rendering host

Startup Flow

The application starts through:

app/main.cpp
  -> RunXCUIEditorApp
  -> Application::Run
  -> Application::Initialize

The primary workspace window is initialized through:

EditorContext::BuildWorkspaceController()
  -> EditorWindowSystem::BootstrapPrimaryWindow(...)
  -> EditorWindowManager::CreateWorkspaceWindow(...)
  -> EditorWindowContentFactory::CreateWorkspaceContentController(...)
  -> EditorWindowHostRuntime::CreateHostWindow(...)

Keep authoritative window bootstrap in EditorWindowSystem; do not move it back into the Win32 host.

Window Authority Model

EditorWindowSystem owns the authoritative UIEditorWindowWorkspaceSet through EditorWindowWorkspaceStore.

Normal per-frame workspace edits now use direct writes into that authoritative state:

EditorWorkspaceWindowContentController::UpdateAndAppend(...)
  -> EditorWindowSystem::TryBuildLiveWindowWorkspaceController(windowId, ...)
  -> UIEditorWorkspaceController::BindToState(...)
  -> workspace operations mutate the bound authoritative workspace/session

The old normal path is obsolete:

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:

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.
  • The concrete host validates EditorWindowContentCapabilities when a native host window is created.

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.
  • Use editor/app/Windowing for window semantics that are not inherently Win32.
  • Use editor/app/Platform/Win32 only for native host behavior and message integration.
  • Do not let editor/app/Windowing include Platform/Win32 or D3D12 concrete host headers.
  • Do not let Win32 host code create workspace or utility content directly. It should receive content through the app-windowing host contract.
  • 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.
  • Do not describe XCEditor/Windowing as an existing framework/public layer.

Current Architecture Debt

The highest-value windowing boundary has been hardened: XCUIEditorAppWindowing now owns the app-internal window authority, presentation, content controller factory, coordinators, frame transfer flow, host contracts, and manager. The Win32 host is the concrete native adapter and creates native host windows from content supplied by app windowing.

The main remaining debt is promotion discipline. 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 this surface to XCEditor until the authority model, host interfaces, frame transfer contract, and presentation projection are stable and generic enough to expose.

Do not paper over this debt by documenting a public windowing framework that does not exist.

Validation

Useful local targets for editor/windowing changes:

  • cmake --build build --config Debug --target XCUIEditorApp
  • cmake --build build --config Debug --target editor_windowing_phase1_tests
  • cmake --build build --config Debug --target editor_ui_tests

Useful test executables when they are present in the configured build tree:

  • build/tests/UI/Editor/unit/Debug/editor_windowing_phase1_tests.exe
  • build/tests/UI/Editor/unit/Debug/editor_ui_tests.exe

xcui_editor_app_smoke is a useful supplemental smoke test when the app target and smoke test are configured, but it is not the default windowing unit-test entry point. In the current Debug build, the direct 12-second smoke command is:

build\tests\UI\Editor\smoke\Debug\editor_ui_smoke_runner.exe build\editor\Debug\XCEngine.exe

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.

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/app/Windowing/System/EditorWindowSystem.*
  • editor/app/Windowing/System/EditorWindowWorkspaceStore.*
  • editor/app/Windowing/System/EditorWindowSynchronizationPlanner.*
  • editor/app/Windowing/Presentation/EditorWindowPresentationPolicy.*
  • 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/Coordinator/EditorWindowWorkspaceCoordinator.*
  • editor/app/Windowing/Coordinator/EditorUtilityWindowCoordinator.*
  • editor/app/Windowing/EditorWindowManager.*
  • editor/app/Platform/Win32/Windowing/EditorWindow.*
  • editor/app/Platform/Win32/Windowing/EditorWindowHostRuntime.*
  • editor/app/Platform/Win32/Windowing/EditorWindowMessageDispatcher.*
  • tests/UI/Editor/unit/test_editor_window_synchronization_planner.cpp
  • tests/UI/Editor/unit/CMakeLists.txt
  • tests/UI/Editor/smoke/CMakeLists.txt