Table of contents
Editor Workbench And Dock
Purpose
Use this workflow when adding or changing an editor surface, dock tab, workbench controller, or detached tool window. The editor dock is descriptor-driven: tab identity, chrome, draw/status providers, demand, detached-window behavior, layout migration, and performance labels all live in contracts that other systems can inspect.
Workbench internals should follow the model/projection/reducer pattern. UI code stays thin, projection builds deterministic display models, reducers translate typed UI actions into state changes or command intents, and side effects live in action modules or systems.
Steps
-
Add or update the tab descriptor in
src/editor/dock.rs.EditorDockTabDescriptorowns the tab id, title, summary, search keywords, tool-window visibility, detachability, chrome policy, demand, detached draw mode, default anchor, layout version, presets, and UI profile scenario. Keep tab metadata out of ad hoc UI branches. -
Wire drawing and status through descriptor behavior.
EditorDockTabBehaviorDescriptorpoints at draw providers, status providers, detached render policy, scroll hosting, repaint budgets, and perf labels.src/editor/ui/dock/core.rsdispatches tab drawing through the descriptor and uses status providers for chrome badges. -
Register demand explicitly. Descriptor demand tells the editor which scene snapshot lanes, preview caches, prefab data, tilesets, character assets, scene NPCs, UI skins, or chat emotes a tab needs.
sync_editor_workbench_demand_registry_systemderives active demand from visible dock tabs plus detached tabs, so do not load everything globally just because one workbench might need it. -
Follow the workbench contract. Use
modelfor typed state, caches, and commands;projectionfor pure read models;reducerfor typed UI actions;actionsfor side effects;uifor rendering and event emission; andtestsfor contract coverage. Register controller ownership throughsrc/editor/workbench_controller.rswhen the surface participates in the shared workbench registry. -
Define detached-window behavior through descriptors and dock actions. Detach requests, reattach requests, focus, reset placement, dock presets, and reattach-all behavior flow through dock resources and reducers. Detached render plans should skip inactive windows unless the descriptor or focus state requires rendering.
-
Handle layout persistence and migration. The persisted dock layout file is
aether_editor_dock_layout.json; descriptor layout versions and anchors are used to sanitize and migrate older layouts. If a new tab becomes default, changes anchor behavior, or changes detached behavior, add migration/test coverage rather than relying on users to reset their layout. -
Add performance checks. Tab draw paths should have stable profiling labels. Detached windows should use descriptor repaint budgets and perf labels, and slow spans should report under the detached editor perf category. If a workbench builds projections from large catalogs, cache signatures or projection models instead of rebuilding inside the draw call.
-
Verify the surface. Run focused unit tests for descriptor coverage, controller ownership, demand registration, reducer/projection behavior, detached render planning, and layout migration. Run
cargo run -p xtask -- docs-check --root .after changing this page or adding a new wiki entry.
Expected Outputs
A complete editor surface has descriptor metadata, a draw provider, a status provider when it needs chrome state, explicit demand registration, context capabilities, focused model/projection/reducer tests where applicable, detached-window policy if detachable, layout migration coverage when defaults change, and stable perf labels/budgets.
Authors should be able to open the tab from the dock, detach and reattach it if allowed, switch layouts without losing it, and see validation/status badges without the tab rebuilding unrelated editor data.
Common Mistakes
Forgetting descriptor demand is the most common failure: the tab may work in a warm editor but fail after restart because the needed cache was never requested. Another common mistake is rebuilding projections inside UI draw code, which makes performance depend on frame rate rather than content changes.
Avoid tab-specific dirty/status policy outside descriptors. Avoid adding default tabs without layout migration tests. Avoid making detached windows render every frame unless the descriptor has a clear repaint budget. Avoid bypassing reducer/actions boundaries by mutating model state directly from widget code.
Recovery Paths
If a tab does not appear, check the descriptor id, default layout anchor, layout version migration, and whether the user layout needs a reset or preset application. If a detached window disappears or stays stale, reattach all detached windows, reset detached placement, then inspect the detached render plan and descriptor draw mode.
If data is missing, inspect the demand registry first, then the tab context capabilities and cache inputs. If the editor becomes slow, compare the tab perf label and detached perf budget against projection/cache signatures, then move heavy work out of draw code.
After fixing the descriptor, reducer, migration, or demand contract, rerun the focused unit tests and the wiki docs check. The page must remain linked from docs/wiki/authoring/README.md so reachability checks can find it.