How to Create and Manage Entities with Custom Components in Flecs

To create and manage entities with custom components in Flecs, declare a C struct for your data, register it with ECS_COMPONENT_DEFINE, then use entity_create_empty followed by ecs_set to attach component data to entities.

The EquilibriumEngine leverages the Flecs entity component system to compose game objects from reusable data structures. Understanding how to define, register, and manipulate custom components is essential for extending the engine's functionality. This guide walks through the exact patterns used in the clibequilibrium/equilibriumengine repository, referencing specific source files and function implementations.

Declaring Custom Component Types

All custom components in EquilibriumEngine follow a standardized declaration pattern using Flecs macros. The process separates the component's entity ID declaration from its underlying C struct definition.

In [equilibrium/components/transform.c](https://github.com/clibequilibrium/equilibriumengine/blob/master/equilibrium/components/transform.c), the engine declares transform-related components using:

ECS_COMPONENT_DECLARE(Position);

This macro expands to a forward declaration of the component's entity ID. The concrete data structure—typically a plain C struct using types from the cglm math library—resides in the same translation unit. For example:

typedef struct { vec3 value; } Position;
typedef struct { vec3 value; } Scale;
typedef struct { versor value; } Quaternion;

As implemented in clibequilibrium/equilibriumengine, components store primitive types, vectors (vec3), or quaternions (versor) depending on their purpose.

Registering Components with the World

Before you can attach custom components to entities, you must register them with the Flecs world during engine initialization. This maps the C struct type to the component entity ID.

The registration function in [equilibrium/components/transform.c](https://github.com/clibequilibrium/equilibriumengine/blob/master/equilibrium/components/transform.c) demonstrates this pattern:

void equilibrium_register_transform_components(void *world) {
    ECS_COMPONENT_DEFINE(world, Position);
    ECS_COMPONENT_DEFINE(world, Scale);
    ECS_COMPONENT_DEFINE(world, Rotation);
    ECS_COMPONENT_DEFINE(world, Quaternion);
    ECS_COMPONENT_DEFINE(world, Transform);
    ECS_COMPONENT_DEFINE(world, Project);
}

The ECS_COMPONENT_DEFINE macro (lines 14‑19 in the source) completes the registration process. This function is invoked from the engine's initialization routine in [equilibrium/engine.c](https://github.com/clibequilibrium/equilibriumengine/blob/master/equilibrium/engine.c) immediately after ecs_init() creates the world. Once registered, the component type is available for attachment to any entity throughout the application's lifetime.

Creating Entities and Attaching Components

Empty Entity Factory

The engine provides a convenience wrapper around ecs_new for creating bare entities. In [equilibrium/entity.c](https://github.com/clibequilibrium/equilibriumengine/blob/master/equilibrium/entity.c) (lines 5‑9), the entity_create_empty function creates an entity and tags it with the engine-wide Entity marker component:

entity_t entity_create_empty(void *world, const char *name) {
    entity_t entity = (entity_t){ecs_new(world, 0), world};
    ecs_doc_set_name(world, entity.handle,
        name == NULL || name[0] == '\0' ? "Entity" : name);
    ecs_add(entity.world, entity.handle, Entity);
    return entity;
}

The function returns an entity_t struct containing both the Flecs entity handle (ecs_entity_t) and a pointer to the world, simplifying subsequent operations.

Adding Component Data

After creation, attach custom components using one of two approaches:

  • ecs_add – Attaches a tag component (zero-sized type) with no data. The engine uses this for the Entity marker.
  • ecs_set – Attaches a component and initializes its fields in a single call.

To create a game object with custom Position and Velocity components:

entity_t obj = entity_create_empty(world, "MovingBox");
ecs_set(world, obj.handle, Position, {.value = {0.0f, 0.0f, 0.0f}});
ecs_set(world, obj.handle, Velocity, {.value = {1.0f, 0.0f, 0.0f}});

The ecs_set macro handles type safety and automatically ensures the component is added if not present, then writes the data.

Factory Function Patterns

For frequently instantiated archetypes, the engine uses "factory" functions that bundle creation and component attachment. While the repository does not expose a full camera factory, the pattern follows the entity_create_empty wrapper structure found throughout editor systems. For example, in [editor/systems/mouse_picking_system.c](https://github.com/clibequilibrium/equilibriumengine/blob/master/editor/systems/mouse_picking_system.c) (line 13 declares the component, line 130 registers it), custom components like MousePickingData are instantiated using the same workflow:

entity_t create_camera(void *world, const char *name) {
    entity_t cam = entity_create_empty(world, name);
    ecs_set(world, cam.handle, Camera, {.type = CameraPerspective});
    ecs_set(world, cam.handle, Transform, {0}); // identity matrix
    return cam;
}

Updating Component Data at Runtime

Components are mutable C structures. To modify data during the game loop, obtain a mutable pointer with ecs_get_mut, modify the fields, then notify Flecs of the change with ecs_modified:

Position *p = ecs_get_mut(world, ent.handle, Position, NULL);
p->value.x += dt * speed;
ecs_modified(world, ent.handle, Position);

The ecs_modified call is critical—it signals Flecs to invalidate caches and ensures that systems reading Position receive the updated value during the current frame. Failing to call ecs_modified after mutation can result in stale data being read by query iterators.

Destroying Entities and Cleanup

When an entity is no longer needed, the engine provides a thin wrapper around Flecs's deletion API. In [equilibrium/entity.c](https://github.com/clibequilibrium/equilibriumengine/blob/master/equilibrium/engine.c) (line 12), entity_destroy handles removal:

void entity_destroy(entity_t entity) { 
    ecs_delete(entity.world, entity.handle); 
}

All components attached to the entity are automatically cleaned up by Flecs when ecs_delete is invoked. This includes any custom components registered earlier in the session.

Summary

  • Declare custom components using ECS_COMPONENT_DECLARE in headers, defining the underlying C struct with your data fields.
  • Register components once during initialization using ECS_COMPONENT_DEFINE in functions like equilibrium_register_transform_components.
  • Create entities via entity_create_empty (defined in equilibrium/entity.c), which returns a handle-world pair.
  • Attach data components with ecs_set and tag components with ecs_add.
  • Modify data using ecs_get_mut followed by ecs_modified to ensure system visibility.
  • Destroy entities using entity_destroy, which calls ecs_delete and automatically releases all attached components.

Frequently Asked Questions

What is the difference between ecs_add and ecs_set in Flecs?

ecs_add attaches a component without initializing data, used primarily for zero-sized tag components like the Entity marker in EquilibriumEngine. ecs_set both attaches the component (if missing) and writes initial data to its fields, making it the preferred method for data-bearing components like Position or custom game logic components.

How do I ensure systems see my component updates immediately?

After modifying component data through a pointer obtained via ecs_get_mut, you must call ecs_modified(world, entity, ComponentType). This notifies Flecs that the component has changed, invalidating query caches so systems iterating over that component type receive the updated values during the current frame.

Where should I register custom components in the EquilibriumEngine codebase?

Register custom components in a dedicated registration function (following the pattern in equilibrium/components/transform.c) and invoke it from equilibrium/engine.c during world initialization. The registry must happen after ecs_init() but before any entities attempt to use the component type.

Can I create entities with multiple components in a single call?

While Flecs supports ecs_new_w_id for creating entities with an initial component, EquilibriumEngine typically uses the factory pattern: call entity_create_empty to get a bare entity, then chain ecs_set calls for each custom component. This explicit approach improves readability and allows conditional component attachment based on game logic.

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 →