# Engine Modules and Their Integration in Equilibrium Engine: Structure and Patterns

> Discover the flecs-based structure for Equilibrium Engine modules. Learn how to declare components and integrate modules using static or hot-reloadable import macros for efficient development.

- Repository: [Alexander/equilibriumengine](https://github.com/clibequilibrium/equilibriumengine)
- Tags: architecture
- Published: 2026-02-27

---

**Equilibrium Engine modules follow a strict flecs-based pattern requiring a header with component declarations, a source file with an import function using `ECS_MODULE`, and integration via either static `ECS_IMPORT` or runtime `ECS_IMPORT_HOT_RELOADABLE` macros.**

The clibequilibrium/equilibriumengine repository implements a modular Entity Component System (ECS) architecture built on top of the flecs library. Understanding the expected structure for engine modules and their integration is essential for extending the engine with new components, systems, or utilities while maintaining support for both static linking and runtime hot-reloading.

## Module Structure and Conventions

Every module in the Equilibrium Engine adheres to a four-part convention that separates public interfaces from implementation details.

### Header Files and Component Declarations

**Header files** located in `equilibrium/components/*.h` or `equilibrium/systems/*.h` provide the public API and forward-declare flecs components using `ECS_COMPONENT_DECLARE`. For example, [`equilibrium/components/transform.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.h) declares transform-related components and types, establishing the contract that other modules or game code will depend on.

### Source Files and Module Registration

**Source files** located in `equilibrium/components/*.c` or `equilibrium/systems/*.c` define the module implementation. They call `ECS_MODULE(world, <ModuleName>)` to register the module with the flecs world, use `ECS_IMPORT` to pull in dependencies, and create components via `ECS_COMPONENT_DEFINE`. The [`equilibrium/components/transform.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.c) file demonstrates this pattern by registering the `TransformComponents` module and defining its associated component storage.

### The Import Function Pattern

Each module must export a single **import function** named `<ModuleName>Import` that accepts a `world_t *world` parameter. This function serves as the entry point for the module. For instance, `TransformComponentsImport` in [`equilibrium/components/transform.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.c) initializes the module when called by the engine or a parent module.

### Hot-Reload Support

Modules intended for dynamic reloading implement the **HotReloadableModule** component defined in [`equilibrium/components/hot_reloadable_module.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.h). This optional marker allows the engine to track module entities and clean them up when the underlying shared library changes, enabling iterative development without restarting the application.

## Integration Patterns

The engine supports two distinct integration paths depending on whether the module is built into the binary or loaded as a plugin.

### Static Compilation and Linking

For modules compiled directly into the engine, integration occurs at engine initialization using the **`ECS_IMPORT`** macro. In [`equilibrium/engine.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/engine.c), the `engine_init()` function imports built-in modules like `FlecsMonitor` and custom engine modules before the main loop begins. This approach requires only that the module's import function be linked into the final executable.

```c
/* equilibrium/engine.c */
ECS_TAG_DEFINE(engine.world, Entity);
ECS_IMPORT(engine.world, FlecsMonitor);   // built-in flecs monitoring
ECS_IMPORT(engine.world, TransformComponents); // custom engine module

```

### Runtime Hot-Reloading

For plugin-style development, the engine provides the **`ECS_IMPORT_HOT_RELOADABLE`** macro defined in [`equilibrium/components/hot_reloadable_module.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.h). This macro performs three critical actions: it imports the specified module and the hot-reloadable helper component, creates a hidden entity storing a `HotReloadableModule` component linked to the plugin's `cr_plugin` context, and tracks the module name for cleanup during reload cycles.

```c
/* editor/editor.c */
ECS_IMPORT_HOT_RELOADABLE(ctx, ImguiBgfxSdlSystem);
ECS_IMPORT_HOT_RELOADABLE(ctx, ImguiDockspaceSystem);

```

When the plugin receives a `CR_LOAD` operation, the macro expands to call `reload_modules(ctx)`, which iterates over all `HotReloadableModule` entities, deletes their associated flecs entities to prevent stale data, and re-imports the fresh code.

## Engine Entry Points and Lifecycle

Understanding where modules fit into the engine lifecycle requires examining three key files that manage initialization, updating, and plugin bridging.

### Core Engine Initialization

The [`equilibrium/engine.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/engine.c) file defines the `engine_t` façade and contains **`engine_init()`**, which creates the flecs world, registers core tags like `Entity`, and stores the world pointer used by all subsequent module imports. The companion **`engine_update()`** function runs system queries each frame, processing all active ECS systems.

### Plugin Simulation Bridge

The [`equilibrium/engine-simulation/engine_simulation.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/engine-simulation/engine_simulation.c) file provides the glue between the engine and the **cr** plugin system. It forwards `CR_STEP` events to `engine_update()`, allowing hot-reloadable modules to participate in the frame update loop while maintaining their dynamic loading capabilities.

### Editor Integration Example

The [`editor/editor.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/editor/editor.c) file demonstrates practical hot-reloadable usage in a real application. It imports UI systems as plugins and performs cleanup routines during reload events, serving as a reference implementation for developers building their own hot-reloadable tools.

## Practical Implementation Examples

The following examples illustrate creating a new physics module and integrating it through both static and hot-reloadable paths.

### Example 1: Creating a Component Module

First, define the header in [`physics_component.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/physics_component.h):

```c
#ifndef PHYSICS_COMPONENT_H
#define PHYSICS_COMPONENT_H

#include "base.h"

ECS_COMPONENT_DECLARE(RigidBody);
EQUILIBRIUM_API void PhysicsComponentsImport(world_t *world);

#endif

```

Next, implement the module in [`physics_component.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/physics_component.c):

```c
#include "physics_component.h"

ECS_COMPONENT_DEFINE(world, RigidBody);

void PhysicsComponentsImport(world_t *world) {
    ECS_MODULE(world, PhysicsComponents);
    ECS_IMPORT(world, CglmComponents);   // reuse glm types
    ECS_COMPONENT_DEFINE(world, RigidBody);
}

```

Integrate statically in `engine_init`:

```c
ECS_IMPORT(engine.world, PhysicsComponents);

```

Or integrate as hot-reloadable in a plugin:

```c
ECS_IMPORT_HOT_RELOADABLE(ctx, PhysicsComponents);

```

### Example 2: Implementing a Dependent System

Create a system that operates on the physics component in [`physics_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/physics_system.c):

```c
#include "physics_component.h"

void SimulatePhysics(ecs_iter_t *it) {
    RigidBody *rb = ecs_field(it, RigidBody, 1);
    for (int i = 0; i < it->count; ++i) {
        /* simple Euler integration */
        rb[i].position[0] += rb[i].velocity[0] * it->delta_time;
        rb[i].position[1] += rb[i].velocity[1] * it->delta_time;
        rb[i].position[2] += rb[i].velocity[2] * it->delta_time;
    }
}

void PhysicsSystemImport(world_t *world) {
    ECS_MODULE(world, PhysicsSystem);
    ECS_IMPORT(world, PhysicsComponents);

    ECS_SYSTEM(world, SimulatePhysics, EcsOnUpdate,
               [in] physics.components.RigidBody);
}

```

## Summary

- **Module structure** requires a header with `ECS_COMPONENT_DECLARE`, a source file with `ECS_MODULE` and `ECS_COMPONENT_DEFINE`, and an import function named `<ModuleName>Import`.
- **Static integration** uses `ECS_IMPORT(world, ModuleName)` during engine initialization in [`equilibrium/engine.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/engine.c).
- **Hot-reloadable integration** uses `ECS_IMPORT_HOT_RELOADABLE(ctx, ModuleName)` to enable runtime reloading via the `HotReloadableModule` component.
- **Dependencies** between modules are resolved using `ECS_IMPORT` inside the import function before defining components or systems.
- **Key files** include [`equilibrium/components/transform.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.c) for component patterns, [`equilibrium/components/hot_reloadable_module.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.c) for reloading infrastructure, and [`editor/editor.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/editor/editor.c) for practical usage examples.

## Frequently Asked Questions

### What is the minimum required structure for a new Equilibrium Engine module?

Every module requires a header file containing `ECS_COMPONENT_DECLARE` statements and an import function prototype, plus a source file implementing the import function with `ECS_MODULE(world, ModuleName)` and `ECS_COMPONENT_DEFINE` calls. This pattern is visible in [`equilibrium/components/transform.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.h) and [`equilibrium/components/transform.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.c).

### How does hot-reloading work with engine modules?

Hot-reloading leverages the `ECS_IMPORT_HOT_RELOADABLE` macro from [`equilibrium/components/hot_reloadable_module.h`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/hot_reloadable_module.h), which creates a tracking entity with a `HotReloadableModule` component. When the plugin reloads, the engine iterates these entities, cleans up stale flecs data, and re-imports the fresh code without restarting the application.

### Can modules depend on other modules?

Yes, modules declare dependencies by calling `ECS_IMPORT(world, DependencyName)` inside their import function before using components from that dependency. For example, `PhysicsComponentsImport` imports `CglmComponents` to access math types before defining physics components that use them.

### Where is the best place to look for a complete module example?

The [`equilibrium/components/transform.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/components/transform.c) file provides the canonical pattern for component modules, while [`equilibrium/systems/transform_system.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/equilibrium/systems/transform_system.c) demonstrates system modules that import component modules. For hot-reloadable integration patterns, examine [`editor/editor.c`](https://github.com/clibequilibrium/equilibriumengine/blob/main/editor/editor.c) which imports UI systems dynamically.