Architecture
Rhea is a modular C++ framework for building virtual worlds and interactive 3D applications. An application combines the engine runtime, selected capabilities, and the platform integrations it needs.
This page introduces the main boundaries and follows the application model used in Getting Started and Your First Project. Rhea is experimental; its interfaces and composition mechanisms may change. An editor is planned but is not included in the initial public release.
Engine and rendering layers
The SDK separates application and scene management from rendering:
Your application
|
+-- Rhea Engine
| +-- application lifecycle
| +-- scenes, objects, components, and resources
| +-- services and selected Fabrics
|
+-- RheaClient
+-- Poseidon renderer
+-- Hippios graphics backend
The diagram shows the main composition of a graphical application, rather than every library dependency. Platform, input, audio, and physics integrations support this composition.
| Library or integration | Responsibility |
|---|---|
Rhea (Rhea::Core) | Application runtime, object hierarchy, scenes, resources, and service coordination. |
RheaClient (Rhea::Client) | Connects the engine to Poseidon for the standard graphical client. |
| Poseidon | Rendering abstractions and the rendering pipeline; can also be used independently of Rhea. |
| Hippios | Graphics and platform backends used by the rendering stack. |
| Psio | Platform facilities used by the runtime, including input and I/O support. |
| Orion | Resource addressing and access to resource data. |
| RheaPhysics / RheaPhysicsBullet | Physics interfaces and the supplied Bullet integration. |
| RheaAudio | Audio integration using miniaudio. |
A graphical application normally links the engine, client, and selected Fabrics. Applications that do not need rendering can use the engine without the client and rendering layers. Linking only the core is not itself a complete headless configuration: the application must also select appropriate services and Fabrics.
Application lifecycle
Applications derive from rhea::Application. BasicApp illustrates the startup sequence:
BasicApp app;
app.setAppname("BasicApp");
app.init(argc, argv);
app.setup();
return app.loop();
This is an excerpt from the sample; BasicApp supplies the application-specific overrides.
init()prepares the runtime, registers core types, creates the application tree, and registers the selected Fabrics.setup()initializes services. BasicApp calls the base implementation before loading resources and constructing its scene.loop()processes input and I/O, runs service update phases, and invokes the application's frame callbacks.
The runtime provides onFrameBegin() and onFrameEnd() hooks. Input travels through events in the object tree; unhandled input can reach the application's onInput() override. In BasicApp, Escape sets an exit flag that onFrameEnd() returns to the runtime.
Rendering and other subsystem work are supplied through the configured services. Choose update hooks according to the subsystem's lifecycle; there is no guarantee of an ordering between unrelated services within the same update phase.
Units, scenes, and components
The runtime maintains a UnitTree. It is a hierarchy used to organize objects, find them by path, and dispatch events.
| Concept | Role |
|---|---|
Unit | A node that can contain child components, including other Units. |
UnitTree | The application's root hierarchy, with helpers for object creation and binding lookup. |
Realm | A named grouping in the hierarchy; BasicApp places its scene under a basic_app Realm. |
Scene | Groups related scene objects and provides scene readiness, visibility, and activation operations. |
Item | A scene object with a spatial role; components add behavior or visual representation. |
Component | A building block attached to an object, such as a transform, mesh association, or physics data. |
For example, BasicApp creates a scene containing a camera, lighting, and a cube Item. The cube uses a VisualComponent and MeshComponent, with a procedural mesh and material.
This is a hierarchical object and component model. Scene contents can be created directly in C++, as in BasicApp, or constructed from loaded scene definitions.
Object lifetime
The hierarchy participates in ownership: the current Unit destructor deletes its child components. Pointers retrieved from the tree are not independent owners. Avoid deleting attached children directly or giving them a second owning pointer; use the relevant attachment and removal lifecycle.
Removal and destruction are distinct operations whose behavior depends on the API. Code that stores pointers to scene objects must account for those objects being removed or destroyed. The application owns its UnitTree and registered Fabric instances through std::unique_ptr; services use a separate registration and lifecycle mechanism.
Fabrics and services
A Fabric groups the code that adds a capability to an application. It may register types, resource loaders, services, components, or other subsystem integration. Examples include geometry, asset-format support, animation, terrain, text, and GUI.
A service provides an application-level runtime function. For example, resource loading is exposed through a resource service. Services participate in initialization and frame processing and can be looked up through Application::getService().
The distinction is between assembling a capability and providing its runtime behavior. Fabrics are registered during the build; the generated registry creates selected Fabric instances, which register their capabilities when the application initializes.
Applications may add their own Fabrics or supply alternative subsystem implementations. Replacement requires compatible interfaces and registrations when other selected capabilities depend on them.
Resources and assets
Resource loading connects external asset data to runtime objects:
Resource identifier
-> resolve asset data
-> load the requested resource type
-> use the resource in the application or scene
BasicApp loads an engine shader and an application texture using identifiers such as:
//rhea/shaders/standard.shader
//basic_app/kies.png
These are resource identifiers, rather than ordinary operating-system paths. Their resolution depends on the resource configuration. In the introductory examples, the build stages assets beside the executable:
Data/
rhea/ engine assets
basic_app/ sample or application assets
Use rhea_copy_assets() to stage these directories in your own project, as described in Your First Project. Resource loading may be asynchronous; do not assume that every request finishes before the calling function returns.
Scene resources and instances
A loaded .scene resource describes a reusable object structure. A scene instance is a runtime tree created from that definition. Loading the resource alone does not place an instance in the world.
See Runtime Scene Instancing for scene definitions, references, and instantiation.
Build-time composition and runtime setup
Rhea uses CMake for integration and capability selection. The two stages have different responsibilities:
| Build time | Runtime |
|---|---|
| Select engine libraries and backend integrations. | Initialize configured services and platform facilities. |
| Register Fabrics and select a Fabric profile. | Register the capabilities supplied by selected Fabric instances. |
| Generate registries using Python. | Load assets and create scenes and objects. |
| Compile code and stage application assets. | Process input and execute update phases. |
For a consumer project using add_subdirectory, the composition sequence is:
- Set project options and, optionally,
RHEA_ENABLED_PROFILE_JSON. - Include
Rhea/cmake/rhea_project.cmake. - Add the engine and any additional packages that register Fabrics.
- Link the application to its engine libraries and
RheaFabrics. - Call
rhea_project_end()after Fabric registration is complete.
An enabled.json profile selects registered Fabrics for the generated registry. When no profile is supplied or discovered, all registered Fabrics are enabled. This mechanism assembles capabilities at build time; it is not a runtime plugin loader.
Python generates the Fabric registry and, when enabled, the type registry used by development tools. It is a build dependency, not an embedded runtime scripting language. mwpkg can help organize packages, but standard CMake integration does not require it.
Where to add your own functionality
| You want to… | Start with… |
|---|---|
| Define application startup and scene construction | An Application subclass, following BasicApp. |
| Add behavior or data to scene objects | The component model and the relevant object lifecycle. |
| Load another asset format | Resource types and resource loaders. |
| Provide an application-wide runtime function | A service and its initialization and update hooks. |
| Package reusable engine capabilities | A Fabric that registers the required types and integrations. |
| Use a different subsystem implementation | Its interface boundary and the requirements of dependent capabilities. |
Start with Your First Project for a complete integration structure. Extend one capability at a time before changing lower-level backends.