#Canvas System Guide
This guide provides a comprehensive overview of the yaze canvas system, its architecture, and best practices for integration. It reflects the state of the system after the October 2025 refactoring.
The canvas system was refactored from a monolithic class into a modular, component-based architecture. The main gui::Canvas class now acts as a façade, coordinating a set of single-responsibility components and free functions.
CanvasState and CanvasConfig hold state, which is operated on by free functions.zelda3 specifics, making it reusable for any editor.The majority of the canvas code resides in src/app/gui/canvas/.
CanvasConfig)gui::CanvasConfig struct (defined in canvas_config.h) holds all configuration for a canvas instance.CanvasState)canvas_state.h) that holds the dynamic state of the canvas, including geometry, zoom, and scroll.The canvas operates with three distinct coordinate spaces. Using the correct one is critical to avoid bugs.
ImGui::GetIO().MousePos). Never use this for canvas logic.Canvas::hover_mouse_pos() to get this. This is the correct space for entity positioning and high-level calculations.Canvas::CanvasToTile() to convert from world space.A critical fix was made to ensure Canvas::hover_mouse_pos() is updated continuously whenever the canvas is hovered, decoupling it from specific actions like painting.
The canvas supports several interaction modes, managed via the CanvasUsage enum.
kTilePainting: For painting tiles onto a tilemap.kTileSelection: For selecting one or more tiles.kRectangleSelection: For drag-selecting a rectangular area.kEntityManipulation: For moving and interacting with entities.kPaletteEditing: For palette-related work.kDiagnostics: For performance and debug overlays.Set the mode using canvas.SetUsageMode(gui::CanvasUsage::kTilePainting). This ensures the context menu and interaction handlers behave correctly.
Interaction logic is moving towards an event-driven model. Instead of inspecting canvas state directly, editors should handle events returned by interaction functions.
Example:
##4. Context Menu &Popups
The context menu system is now unified,
data - driven,
and supports persistent popups.
## #Key Features -
**Unified Item Definition ** : All menu items use
the `gui::CanvasMenuItem` struct.-
**Priority -
Based Ordering ** : Menu sections are automatically sorted based on
the `MenuSectionPriority` enum,
ensuring a consistent layout : 1. `kEditorSpecific` (
highest
priority)2. `kBitmapOperations` 3. `kCanvasProperties` 4. `kDebug` (lowest
priority) -
**Automatic Popup
Persistence ** : Popups defined declaratively will remain open until
explicitly closed by the user(ESC or close button),
rather than closing on any click outside
.
## #API Patterns
**Add a Simple Menu Item ** :
** Add a Declarative Popup Item** : This pattern automatically handles
popup registration and persistence.
For multi-section menus, mutate canvas.editor_menu() (CanvasMenuDefinition) directly or assemble CanvasMenuSection / CanvasMenuItem values in editor code.
A generic, Zelda-agnostic entity system allows editors to manage on-canvas objects.
src/app/editor/overworld/operations/entity_operations.h, such as InsertEntrance, InsertSprite, etc. These functions are designed for ZScream feature parity.OverworldEditor delegates to the MapPropertiesSystem, which in turn calls these flat functions to modify the ROM state.kEntityManipulation mode.Usage Flow:
kEntityManipulation.Insert... function.Canvas: Instantiate gui::Canvas, providing a unique ID.CanvasUsage mode via canvas.SetUsageMode(). Configure available modes and other options in the CanvasConfig struct.finish_paint.canvas.Begin(size).canvas.End(). This handles rendering the grid, overlays, and the context menu.canvas.AddContextMenuItem() or assign to canvas.editor_menu() with MenuSectionPriority::kEditorSpecific so editor actions sort to the top.CanvasState or handling events returned from interaction helpers.If you encounter issues with the canvas, check the following:
config.enable_context_menu true?CanvasMenuItem::WithPopup pattern?canvas.End() being called every frame to allow the PopupRegistry to render?canvas.hover_mouse_pos() for world coordinates instead of ImGui::GetIO().MousePos?MenuSectionPriority for your custom menu sections?The CanvasAutomationAPI provides hooks for testing and automation. It allows for programmatic control of tile operations (SetTileAt, SelectRect), view controls (ScrollToTile, SetZoom), and entity manipulation. This API is exposed via the z3ed CLI and a gRPC service.