This guide outlines the core architectural patterns, UI systems, and best practices for developing and maintaining the yaze editor.
These patterns, established during the Overworld Editor refactoring, should be applied to all new and existing editor components.
Principle: Decompose large, monolithic editor classes into smaller, single-responsibility modules.
*Renderer
classes (e.g., OverworldEntityRenderer
). The main editor class should delegate drawing calls, not implement them.MapPropertiesSystem
), which then communicate with the parent editor via callbacks.Benefit: Smaller, focused modules are easier to test, debug, and maintain. The main editor class becomes a coordinator, which is a much cleaner architecture.
Principle: Use std::function
callbacks for child-to-parent communication to avoid circular dependencies.
SetCallbacks
method) during initialization. The child component invokes these callbacks to notify the parent of events or to request actions (like a refresh).MapPropertiesSystem
receives a RefreshCallback
from OverworldEditor
. When a property is changed in the UI, it calls the function, allowing the OverworldEditor
to execute the refresh logic without the MapPropertiesSystem
needing to know anything about the editor itself.Principle: All expensive asset loading operations must be performed asynchronously to prevent UI freezes. The gfx::Arena
singleton provides a centralized, priority-based system for this.
gfx::Arena::Get().QueueDeferredTexture(bitmap, priority);
Update()
loop of an editor, process a small batch of textures each frame: auto batch = gfx::Arena::Get().GetNextDeferredTextureBatch(4, 2);
(e.g., 4 high-priority, 2 low-priority).To ensure a consistent and polished look and feel, all new UI components must adhere to the established theme and helper function system.
ImVec4
)**. All UI colors must be derived from the central theme.AgentUITheme
system (src/app/editor/agent/agent_ui_theme.h
) provides a struct of semantic color names (e.g., panel_bg_color
, status_success
, provider_ollama
). These colors are automatically derived from the application's current ThemeManager
.**Usage: Fetch the theme at the beginning of a draw call and use the semantic colors:
cpp const auto& theme = AgentUI::GetTheme(); ImGui::PushStyleColor(ImGuiCol_ChildBg, theme.panel_bg_color);
AgentUI
and gui
namespaces):AgentUI::PushPanelStyle()
/ PopPanelStyle()
AgentUI::RenderSectionHeader(icon, label, color)
AgentUI::RenderStatusIndicator()
(status dot), AgentUI::StatusBadge()
(colored text badge).AgentUI::StyledButton()
, AgentUI::IconButton()
.AgentUI::VerticalSpacing()
, AgentUI::HorizontalSpacing()
.ImGui::BeginGroup()
. Instead, manage layout with ImGui::SameLine()
and end the toolbar with ImGui::NewLine()
.ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical)
for vertical separators that do not affect item layout.toolbar.AddProperty()
method for consistent spacing and sizing of input fields within the toolbar.Renderer::Get().RenderBitmap()
for an immediate, blocking update. UpdateBitmap()
is deferred and should not be used for changes the user expects to see instantly.Load*()
method (e.g., map.LoadAreaGraphics()
) to load the new data from the ROM into memory.Small
to Large
), you must use the zelda3::Overworld::ConfigureMultiAreaMap()
method. Do not set the area_size
property directly.asm_version
byte before rendering a UI component. If the feature is not supported, display a helpful message (e.g., "This feature requires ZSCustomOverworld v3+") instead of the UI.0.85f
to ensure they are clearly visible against any background.To accelerate your debugging workflow, use command-line flags to jump directly to specific editors and open relevant UI cards:
Available Editors: Assembly, Dungeon, Graphics, Music, Overworld, Palette, Screen, Sprite, Message, Hex, Agent, Settings
Dungeon Editor Cards: Rooms List, Room Matrix, Entrances List, Room Graphics, Object Editor, Palette Editor, Room N (where N is room ID 0-319)
See debugging-startup-flags.md for complete documentation.
For a comprehensive overview of debugging tools and testing strategies, including how to use the logging framework, command-line test runners, and the GUI automation harness for AI agents, please refer to the Debugging and Testing Guide.
Decision: All binaries in the yaze project (yaze
, z3ed
, yaze_test
, etc.) will standardize on the Abseil Flags library for command-line argument parsing.
--help
generation, type safety, validation, and --flagfile
support.The project will migrate away from the legacy yaze::util::Flag
system and manual parsing in phases. All new flags should be implemented using ABSL_FLAG
.
z3ed
and yaze_emu_test
already use Abseil flags.yaze
application will be migrated from the custom util::Flag
system to Abseil flags.yaze_test
runner's manual argument parsing will be replaced with Abseil flags.util::flag
source files will be removed from the project.Developers should refer to the Abseil Flags Guide for documentation on defining, declaring, and accessing flags.
When working with bitmaps and textures, understand that two memory locations must stay synchronized:
data_
vector**: C++ std::vector<uint8_t> holding pixel datasurface_->pixels
**: SDL surface's raw pixel buffer (used for texture creation)Critical Rules:
set_data()
for bulk data replacement (syncs both vector and surface)WriteToPixel()
for single-pixel modificationsmutable_data()
for replacements (only updates vector, not surface)ProcessTextureQueue()
every frame to process pending texture operationsExample:
Graphics sheets (223 total) are managed centrally by gfx::Arena
. When modifying a sheet:
auto& sheet = Arena::Get().mutable_gfx_sheet(index);
Arena::Get().NotifySheetModified(index);
Default palettes are applied during ROM loading based on sheet index: