Malena is a C++ framework built on top of SFML that emphasizes event-driven architecture, modular composition, and reusable graphical components.
The framework is designed to simplify application and UI development by wrapping common SFML workflows in higher-level systems for application management, messaging, plugins, resources, traits, and graphics. Rather than forcing logic into tightly coupled class hierarchies, Malena encourages communication through events and messages, behavior through traits, and extensibility through manifests and plugins.
At a high level, Malena can be understood as a framework with the following goals:
Malena makes SFML development feel more event-driven. Instead of requiring objects to be tightly aware of one another, the framework supports communication through two complementary systems: an event system (input and lifecycle events, fired by name) and a message system (typed, enum-keyed communication between plugins and framework objects). Together these allow interactive UIs and plugin-based architectures to be built without direct object dependencies.
Malena uses traits to compose behavior into objects. Capabilities such as messaging, flags, dragging, positioning, and customization are modeled as reusable traits rather than being repeated across unrelated classes. The With<Manifest> template pattern (e.g., UIComponentWith<Manifest>, PluginWith<Manifest>) layers manifest-declared resources, flags, and states onto any framework class cleanly.
A fundamental concern in event-driven and plugin-based systems is mutation during iteration — for example, an event callback unloading a plugin while the event system is still iterating its subscriber list. Malena addresses this through a consistent deferred operations pattern: EventsManager, MessageManager, ComponentsManager, and PluginManager all track when they are actively iterating and queue destructive operations (removals, unloads, unsubscribes) to be processed safely afterward. User code does not need to manage this manually.
SFML remains the rendering and windowing foundation, but Malena provides a higher-level structure for application flow, window ownership, graphics components, and interaction patterns.
Malena supports configurable and extensible systems through manifests, plugin metadata, and plugin management. This allows applications and modules to declare resources, states, flags, and plugin information in a structured way.
The framework is organized into the following major subsystems:
The Core module provides foundational framework abstractions shared across the rest of Malena.
Important responsibilities include:
The Core layer acts as the backbone of the framework. Many higher-level systems either inherit from or coordinate through these foundational types.
Critical constraint: Malena components cannot be safely copied or moved after they have been registered with a manager. Prefer std::unique_ptr collections when you need to manage component lifetimes manually (e.g., std::vector<std::unique_ptr<Tile>>).
The Engine module contains the main runtime infrastructure of the framework.
The Engine/App subsystem contains the main application model:
The two virtual methods that application authors implement are:
The Engine/Events subsystem contains EventsManager, which is the centralized publish-subscribe event bus for framework-level events.
How it works:
Event names fired by UIManager:
The Engine/Messaging subsystem contains MessageManager, which provides typed, enum-keyed messaging distinct from the string-based event system.
Where EventsManager handles input-driven events fired by name, MessageManager handles structured communication between framework objects — for example, a plugin signaling another plugin that loading is complete, or a game notifying the launcher to stop. Messages are keyed by enum value and carry a typed payload.
Like EventsManager, MessageManager uses the deferred operations pattern internally so that unsubscription during a message callback is safe.
The Engine/Plugins subsystem contains:
Plugin lifecycle:
Registration: Every plugin shared library must define a factory function via the REGISTER_PLUGIN(ClassName) macro, which the PluginManager looks up by convention when loading.
RTTI across dylib boundaries: Plugins loaded from separate shared libraries share only a virtual interface with the host. To query a plugin for optional interfaces (e.g., whether it is drawable), use getIf<InterfaceType>() rather than dynamic_cast across dylib boundaries.
The Engine/Window subsystem contains WindowManager, which centralizes ownership of the SFML RenderWindow. This ensures the window remains accessible across the framework without manual passing.
The Graphics module contains Malena's reusable visual and UI-oriented components built on top of SFML drawing primitives. All graphics components inherit from UIComponent, which provides the Messenger trait, auto-unsubscription on destruction, and integration with EventsManager and ComponentsManager.
The ECS module provides an entity-component-system architecture as an alternative or complement to the framework's object-oriented systems.
The ECS subsystem allows Malena to support data-oriented patterns where logic operates over entities and components through systems rather than through deep inheritance trees.
The Manifests module provides declarative configuration and metadata support.
A manifest is a nested struct inside a class that declares the resources, flags, states, and configuration data that class needs. The With<Manifest> template pattern then wires those declarations into the manager infrastructure automatically.
Key types:
Manifest hierarchy:
| Level | What it provides | Best used when |
|---|---|---|
| Individual manager (e.g., TextureManager<Manifest>) | One media type | You only need textures or only fonts |
| AssetsManager<Manifest> | All media types (textures + fonts + sounds) | Most game or UI classes |
| Context<Manifest> | Assets + configuration | Complex apps or plugins with both media and config |
The Resources module manages shared data and runtime assets.
Important managers include:
The Traits module is one of the most important architectural features of Malena. Traits provide reusable behavior that can be mixed into framework classes, supporting composition-based design and reducing duplication.
The primary trait for event-driven interaction. Provides named convenience methods over the raw EventsManager subscription API:
UIComponent inherits Messenger and auto-calls unsubscribeAll() in its destructor, preventing dangling callbacks after a component is destroyed.
Lower-level subscription infrastructure underlying Messenger.
Provides runtime boolean flag management. Flags are declared in the class manifest and can be checked, set, and cleared:
CustomFlaggable supports flags declared directly on a class's manifest without a shared enum.
Enables mouse-drag interaction for any UI component.
Provides a consistent positional API across framework objects.
Supports manifest-declared visual customization (colors, sizes, etc.).
The Utilities module contains shared helper types and functions:
Malena is built on top of SFML, not intended to replace it.
SFML provides: render windows, drawing, events, textures, fonts, sound, and low-level multimedia primitives.
Malena adds: application structure, event-driven communication patterns, reusable UI controls, plugin infrastructure, manifest-driven customization, centralized resource and state systems, and optional ECS architecture.
In practice, Malena can be understood as a framework layer that organizes SFML applications into a more modular and event-oriented design while preserving SFML idioms (e.g., window.draw() still works as expected).
A typical Malena application follows this flow:
This flow allows interactive behavior while keeping systems decoupled and safe from mutation-during-iteration crashes.
| Type | Role |
|---|---|
| Application | Framework entry point; subclassed by users |
| AppManager | Main loop coordinator |
| UIController | Control-layer abstraction; base for UI-heavy apps |
| UIComponent | Base visual class; inherits Messenger; auto-unsubscribes on destruction |
| EventsManager | Centralized string-keyed pub-sub bus with deferred removal |
| MessageManager | Typed enum-keyed messaging with deferred removal |
| PluginManager | Loads, queries, and safely unloads plugins |
| Plugin / PluginWith<M> | Plugin base; PluginWith adds manifest support |
| CoreManager / ComponentsManager | Manages registered framework objects with deferred removal |
| DeferredOperationsManager | Shared deferred-operation infrastructure used by all managers |
| Manifest / Context | Declarative resource and config metadata |
| Messenger trait | Convenience subscription API for events |
| Flaggable trait | Runtime boolean flags declared in manifests |
Malena is especially well-suited for:
When documenting Malena code, public API comments should describe each class in terms of its role in this architecture. For example:
This document should be refined over time with:
As the framework evolves, this file should remain the main architectural reference for contributors, users, and AI-assisted documentation workflows.