Common Entity Components in Equilibrium Engine: Transform, GUI, and Input Guide

Equilibrium Engine uses the flecs ECS framework where Transform, GUI, and Input are the three core entity components that store spatial matrix data, ImGui interface state, and peripheral input respectively.

The Equilibrium Engine (clibequilibrium/equilibriumengine) implements a pure entity component system (ECS) architecture using the flecs library. In this design, game objects are entities—empty containers identified by unique IDs—while data lives in entity components: plain C structs that attach to entities and drive rendering, input handling, and UI logic. Understanding how the Transform, GUI, and Input components work is essential for building any application with this engine.

What Are Entity Components?

In the Equilibrium Engine source code, a component is a plain C struct registered with the ECS world via boilerplate macros. Components contain no logic—only state—making them lightweight and cache-friendly. The engine organizes these definitions in the equilibrium/components directory and exposes import functions that register the structs with the flecs world during initialization.

Every piece of data that can be attached to an entity follows this pattern:

  • A core struct (e.g., Transform, Input)
  • A registration macro (ECS_COMPONENT_DECLARE)
  • An import function (TransformComponentsImport, GuiComponentsImport, InputComponentsImport)

The Three Core Entity Components

The engine provides three foundational components that appear in nearly every application: Transform for spatial data, GUI for ImGui-based interfaces, and Input for keyboard and mouse state.

Transform Component

The Transform component stores an entity’s position, rotation, and scale as a 4×4 matrix (mat4) ready for the rendering pipeline. Defined in equilibrium/components/transform.h, this struct is attached to any renderable entity including meshes, lights, and cameras.

Key implementation details:

  • Core struct: Transform containing mat4 value
  • Registration: ECS_COMPONENT_DECLARE(Transform)
  • Import function: TransformComponentsImport(world_t *world)

The rendering system reads this matrix during the update loop in equilibrium/systems/transform_system.c to compute world-space transformations.

GUI Component

The GUI component group manages ImGui integration and window handling. Rather than a single struct, this module registers several related components including GuiSystem, GuiContext, AppWindow, AppWindowHandle, and Renderer. These are defined in equilibrium/components/gui.h and imported via GuiComponentsImport(world_t *world).

The GuiSystem struct contains:

  • Update callback pointer for ImGui frame logic
  • Context pointer for ImGui state
  • Window handle references
  • Renderer backend type

Typically attached to a singleton UI entity, this component drives the immediate-mode interface rendered by systems like editor/systems/imgui_overlay_system.c.

Input Component

The Input component aggregates raw SDL events into queryable keyboard and mouse state. Defined in equilibrium/components/input.h, the Input struct contains:

  • KeyState keys[128] array for keyboard buttons
  • MouseState mouse struct with position and button states
  • InputEventCallback callback for custom event handling

Import this component using InputComponentsImport(world_t *world). The equilibrium/systems/sdl_system.c file populates this component each frame, while gameplay systems query it to respond to user actions.

Registering and Using Entity Components

Before attaching components to entities, you must import their definitions into the flecs world. This registration typically happens during engine initialization.

Importing Component Modules

#include "equilibrium/components/transform.h"
#include "equilibrium/components/gui.h"
#include "equilibrium/components/input.h"

world_t *world = ecs_init();

/* Register the three common component groups */
TransformComponentsImport(world);  // Registers Transform, Position, Scale, Rotation
GuiComponentsImport(world);        // Registers GuiSystem, GuiContext, AppWindow, Renderer
InputComponentsImport(world);      // Registers Input with KeyState and MouseState

Source references: equilibrium/components/transform.h, equilibrium/components/gui.h, equilibrium/components/input.h

Attaching Components to Entities

Once imported, create entities and attach components using flecs API functions:

Adding a Transform:

ecs_entity_t player = ecs_new(world, 0);
ecs_add(world, player, Transform);

/* Initialize matrix to identity (no transform) */
Transform *t = ecs_get_mut(world, player, Transform, NULL);
glm_mat4_identity(t->value);

Setting up GUI:

ecs_entity_t ui = ecs_new(world, GuiSystem);
GuiSystem *gui = ecs_get_mut(world, ui, GuiSystem, NULL);
gui->Update = MyImGuiDrawFunction;

Capturing Input:

ecs_entity_t input_entity = ecs_new(world, Input);
Input *in = ecs_get_mut(world, input_entity, Input, NULL);

/* Query specific keys */
bool is_jumping = in->keys[ECS_KEY_SPACE].pressed;
float cursor_x = in->mouse.wnd.x;

Combining Components in Systems

The ECS architecture shines when systems query multiple components simultaneously. A player entity can possess both Transform and Input components, allowing movement systems to update position based on key presses:

void MovePlayerSystem(ecs_iter_t *it) {
    Transform *t = ecs_field(it, Transform, 1);
    Input *in = ecs_field(it, Input, 2);
    
    for (int i = 0; i < it->count; i++) {
        if (in->keys[ECS_KEY_W].pressed) {
            /* Move forward along Z axis */
            t[i].value[3][2] += 0.1f;
        }
    }
}

System Integration

These entity components connect to engine systems that process their data each frame:

Because components are plain data, they impose no inheritance overhead, allowing the engine to batch process thousands of entities with identical component signatures efficiently.

Summary

  • Equilibrium Engine uses the flecs ECS where entity components are pure C structs attaching data to entity IDs
  • Transform components store 4×4 matrices in equilibrium/components/transform.h and attach to all renderable objects
  • GUI components defined in equilibrium/components/gui.h manage ImGui state through GuiSystem and related structs
  • Input components in equilibrium/components/input.h encapsulate keyboard and mouse state via the Input struct with KeyState keys[128]
  • Import components using TransformComponentsImport(), GuiComponentsImport(), and InputComponentsImport() before creating entities
  • Combine components freely on entities and query them in systems using ecs_field() for data-driven gameplay logic

Frequently Asked Questions

What ECS framework does Equilibrium Engine use?

Equilibrium Engine uses the flecs ECS framework, a fast and portable entity component system written in C. The engine extends flecs by defining domain-specific entity components like Transform and Input in the equilibrium/components directory and registering them via import functions during world initialization.

How do I add a Transform component to an entity?

First import the component module with TransformComponentsImport(world), then create an entity and attach the component using ecs_add(world, entity, Transform). Access the matrix data with ecs_get_mut() to set position, rotation, or scale values using standard GLM matrix functions like glm_mat4_identity().

Can multiple components exist on a single entity?

Yes. The ECS architecture allows unlimited component composition. For example, a player entity can simultaneously hold Transform, Input, and custom gameplay components. Systems query specific combinations using ecs_field() to process only entities possessing the required component set.

Where are component definitions located in the source code?

Component structs and their registration macros reside in equilibrium/components/transform.h, equilibrium/components/gui.h, and equilibrium/components/input.h. Systems that process these components live in equilibrium/systems/ and editor/systems/, with transform_system.c, sdl_system.c, and imgui_overlay_system.c serving as primary examples.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →