Editor Module
The Editor module provides an in-engine editor built on ImGui, offering tools for scene editing, entity manipulation, and content creation. It integrates seamlessly with the runtime to provide a unified development environment.
Purpose
The Editor module provides:
- In-engine editor interface
- Scene hierarchy management
- Entity property inspection and editing
- Viewport for scene visualization
- Content browser for asset management
- Console for logging and debugging
- Editor layers and overlay system
Key Components
Editor
The main editor singleton that manages the editor initialization and runtime:
Key Methods:
init()- Initializes editor systems (EventDispatcher, Time, SystemManager, Engine, Window)start()- Starts the editorrun()- Main editor loopend()- Cleans up editor resourcesget()- Returns singleton instanceget_current_layout()- Returns current layout configuration
Editor Layers
The editor is composed of multiple layers:
- ViewportLayer - Scene rendering in ImGui window with framebuffer
- SceneHierarchyLayer - Entity tree view
- PropertiesLayer - Component inspection and editing
- ContentBrowserLayer - Asset browsing and management
- ConsoleLayer - Log messages and debugging
- DockspaceOverlay - Main dockspace, menu bar, and theme
EditorCamera
Camera controller for viewport navigation (extends Object):
class EditorCamera : public Object {
public:
EditorCamera(ENTITY_INIT_PARAMS, glm::vec3 position = glm::vec3(0.0f));
void start();
void pre_update();
void update() override;
void post_update();
void on_enable() override {};
void on_disable() override {};
};Note: Camera movement controls are currently commented out in the implementation.
LayerManager
Manages editor layers and overlays:
struct LayerContext {
EntityID selected_entity_id = -1;
bool has_selected_entity();
};
class LayerManager {
public:
static void init();
static LayerManager* get();
template<class T> void add_layer();
template<class T> void add_overlay();
LayerContext* get_layer_context();
void for_each(std::function<void(Layer*)> fn);
void for_each(std::function<void(Overlay*)> fn);
};The LayerContext tracks the currently selected entity across all panels.
Architecture
Layer System
The editor uses a layer system for UI organization:
Editor (singleton)
├── LayerSystem (ECS system)
│ └── LayerManager
│ ├── DockspaceOverlay (main dockspace + menu)
│ ├── ViewportLayer
│ ├── SceneHierarchyLayer
│ ├── PropertiesLayer
│ ├── ContentBrowserLayer
│ └── ConsoleLayer
└── WebsocketServer (optional, for remote editing)Note: Some layers are currently commented out in the LayerSystem initialization.
ImGui Integration
The editor is built on ImGui for immediate-mode UI. The DockspaceOverlay initializes ImGui and configures the main dockspace:
class DockspaceOverlay : public Overlay {
public:
void start() override; // Initializes ImGui context with OpenGL3 + GLFW
void pre_update() override; // Begins ImGui frame
void update() override; // Renders menu bar and dockspace
void post_update() override; // Ends ImGui frame
};The overlay loads fonts (OpenSans Regular/Bold 18pt) and applies a custom dark theme.
LayerContext
The editor maintains shared state across layers:
struct LayerContext {
EntityID selected_entity_id = -1;
bool has_selected_entity();
};This context is shared by all layers via LayerManager::get_layer_context() to track the currently selected entity.
Key Features
Scene Hierarchy
View and manipulate the entity tree. The SceneHierarchyLayer displays all entities in a tree view:
class SceneHierarchyLayer : public Layer {
public:
SceneHierarchyLayer() : Layer("SceneHierarchy");
void start() override;
void update() override;
};Features:
- Tree view of all entities in the active scene
- Left-click to select an entity (updates LayerContext)
- Right-click context menu for Delete and Add Component
- Window context menu for entity templates (Empty, Cube, Sphere, Capsule, Quad, Plane)
Properties Layer
Inspect and edit entity components. The PropertiesLayer displays component data for the selected entity:
class PropertiesLayer : public Layer {
public:
PropertiesLayer() : Layer("Properties");
void start() override;
void update() override;
};Supported Components:
- TransformComponent
- MaterialComponent
- MeshComponent
- CameraComponent
- RigidBodyComponent
- LightComponent
Features:
- Loads component icons (transform, camera, rigidbody, light, mesh, skybox, settings)
- Per-component header with settings button
- Components can be marked as removable
- Reads selected entity from LayerContext
Viewport Layer
Renders the engine framebuffer in an ImGui window:
class ViewportLayer : public Layer {
public:
ViewportLayer() : Layer("Viewport");
void start() override;
void update() override;
};Features:
- Displays engine framebuffer as ImGui image texture
- Dynamically resizes framebuffer based on panel size
- Tracks viewport bounds, focused state, and hovered state
- Provides viewport dimensions for rendering
Note: Gizmo system and entity manipulation tools are not currently implemented in the viewport.
Content Browser Layer
Browse and manage project assets:
class ContentBrowserLayer : public Layer {
public:
ContentBrowserLayer();
void start() override;
void update() override;
};Features:
- Two-panel layout: directory tree (aside) + file grid (main)
- Base directory:
src/assets(relative to parent of working directory) - Drag-drop support with "CONTENT_BROWSER_ITEM" payload
- Directory and file icons
- Navigation through folder hierarchy
Console Layer
Display log messages and debugging information:
class ConsoleLayer : public Layer {
public:
ConsoleLayer() : Layer("Console");
void start() override;
void update() override;
};Features:
- Loads icon textures for warn, info, and error levels
- Menu bar with log level icon buttons for filtering
- Search bar (logic not yet implemented)
- Clear button (logic not yet implemented)
- Displays log messages with color-coded severity
WebSocket Server (Optional)
For remote editor connections:
class WebsocketServer {
public:
static void init();
static WebsocketServer* get();
void start();
void update();
void publish(std::string_view topic, std::string_view message,
uWS::OpCode opCode, bool compress = true);
void publish(const char* topic, const char* message);
std::string build_message(const char* topic, const char* message);
};Features:
- SSL WebSocket server on port 9001
- Topics: "framebuffer", "scene", "logs"
- Handles keyboard and mouse input from remote clients
- Enabled via
ASTRA_EDITOR_USOCKETcompilation flag - Requires certificate files:
misc/key.pem,misc/cert.pem, passphrase "1234"
Note: Play/pause mode state machine is not currently implemented.
Integration with Other Modules
With Engine Module
The editor initializes the engine and integrates with the ECS through the LayerSystem:
class LayerSystem : public System<LayerSystem> {
public:
LayerSystem(); // Initializes LayerManager
void start() override;
void fixed_update(double fixed_dt) override;
void pre_update(double dt) override;
void update(double dt) override;
};The LayerSystem is added to the SystemManager and updates all layers during the engine loop.
With Window Module
The editor uses the Window module for input and display:
void Editor::init() {
// Initialize Time system
Time::init();
// Initialize SystemManager
SystemManager::init();
// Initialize Engine
Engine::init();
// Initialize Window
Window::create(...);
Window::start();
}Asset Management
The ContentBrowserLayer browses assets in src/assets directory. Asset paths are relative to the parent of the working directory.
Editor Controls
Current Status
Note: Many editor controls are currently in development:
- Camera movement controls are commented out in
EditorCamera - Gizmo manipulation (W/E/R shortcuts) is not implemented
- Keyboard shortcuts (Ctrl+S, Ctrl+D, Delete, F, Ctrl+Z, Ctrl+Y) are not implemented
- Undo/redo system is not implemented
Implemented Features
- Left-click entity in Scene Hierarchy to select
- Right-click entity for context menu (Delete, Add Component)
- Right-click viewport background for entity templates menu
- Drag files from Content Browser (payload: "CONTENT_BROWSER_ITEM")
File Locations
/src/modules/editor/
├── editor.hpp/cpp # Main editor singleton
├── camera.hpp/cpp # Editor camera controller
├── websocket-server.hpp/cpp # WebSocket server for remote editing
├── events/
│ ├── logs-event.hpp # Log streaming events
│ └── viewport-event.hpp # Viewport framebuffer events
├── layers/
│ ├── viewport-layer.hpp/cpp
│ ├── console-layer.hpp/cpp
│ ├── content-browser-layer.hpp/cpp
│ ├── properties-layer.hpp/cpp
│ ├── scene-hierarchy-layer.hpp/cpp
│ ├── managers/
│ │ └── layer-manager.hpp/cpp
│ └── systems/
│ └── layer-system.hpp/cpp
├── layouts/
│ ├── layout.hpp # Layout configuration struct
│ └── default-layout.hpp/cpp # Default panel layout
├── overlays/
│ └── dockspace-overlay.hpp/cpp # Main dockspace + menu + theme
├── serializers/
│ ├── editor-serializer.hpp # Empty placeholder
│ └── log-serializer.hpp/cpp # Log entry JSON serialization
└── UI/
└── imgui-widgets.hpp # Reusable ImGui UI componentsRelated Modules
- Engine - Provides ECS and SystemManager for layer integration
- Window - Handles display and input
- Streams - Serialization for logs and scene data
Best Practices
- Use Entity Templates: Create entities from templates in Scene Hierarchy context menu (Empty, Cube, Sphere, Capsule, Quad, Plane)
- Organize Scene: Keep scene hierarchy organized with descriptive entity names
- Component Icons: Use the Properties panel to visually identify component types
- Asset Organization: Keep assets organized in the
src/assetsdirectory structure
Performance Considerations
- Editor UI is rendered with ImGui (immediate mode)
- Viewport renders to framebuffer for ImGui texture display
- WebSocket mode uses hardcoded 1920x1080 resolution for framebuffer streaming
- Content browser iterates through filesystem on each update
- Multiple icon textures loaded for UI elements
- Font files (OpenSans Regular/Bold 18pt) loaded at startup
Common Patterns
Adding Custom Layers
Create a custom layer by extending the Layer base class:
class MyCustomLayer : public Layer {
public:
MyCustomLayer() : Layer("MyCustomLayer") {}
void start() override {
// Initialize resources, load icons, etc.
}
void update() override {
ImGui::Begin("My Custom Panel");
// Your ImGui UI code here
ImGui::End();
}
};
// Register in LayerSystem or LayerManager
LayerManager::get()->add_layer<MyCustomLayer>();Using LayerContext for Selection
Access the shared selection state across layers:
void MyCustomLayer::update() {
LayerContext* ctx = LayerManager::get()->get_layer_context();
if (ctx->has_selected_entity()) {
EntityID selected = ctx->selected_entity_id;
// Work with selected entity
}
}Template-Based Component UI
The editor uses a template pattern for drawing components:
// Defined in UI/imgui-widgets.hpp
template<typename T>
void draw_component(EntityID entity, std::function<void(T&)> ui_function);This allows custom UI for each component type while maintaining consistent headers and controls.