Skip to content

Getting Started

This page shows the normal user flow and the supported ways to consume SIECS.

If you are new to ECS, read ECS Theory after this page. The short version is: entities are ids, components are data, and systems run over batches of entities that match a query.

For a small C project, use the standalone distribution:

  1. Copy distr/siecs.h and distr/siecs.c into your project.
  2. Include the public header.
  3. Compile your file together with siecs.c.
#include <siecs.h>
ECS_COMPONENT_DECLARE(Position, {
float x;
float y;
});
ECS_COMPONENT_DEFINE(Position);
int main(void) {
ecs_init();
ECS_COMPONENT_REGISTER(world, Position);
ecs_entity_t entity = ecs_new();
ecs_set(entity, Position, { .x = 10.0f, .y = 20.0f });
Position *position = ecs_get(entity, Position);
position->x += 1.0f;
ecs_fini();
return 0;
}

Build it with cc -std=c23 -I. main.c siecs.c -pthread -o my_app.

The standalone distribution embeds SIECS and its public C dependencies.

The same SIECS runtime can be consumed from C or C++:

#include <siecs.h>

Compile the C source with cc -std=c23.

Use Bake if your project already uses Bake or if you want the same setup as the repository tests.

C

{
"id": "my_app",
"type": "application",
"value": {
"use": ["siecs"]
},
"lang.c": {
"c-standard": "c23"
},
"bundle": {
"repositories": {
"siecs": "https://github.com/suleymanlaarabi/siecs"
}
}
}

C++

{
"id": "my_app",
"type": "application",
"value": {
"language": "cpp",
"use": ["siecs"]
},
"lang.cpp": {
"cpp-standard": "c++23"
},
"bundle": {
"repositories": {
"siecs": "https://github.com/suleymanlaarabi/siecs"
}
}
}

For custom build systems, compile the C sources from this repository’s src/ directory and also compile the public C dependencies used by SIECS:

  • sireflect: https://github.com/suleymanlaarabi/sireflect
  • sijson: https://github.com/suleymanlaarabi/sijson
  • sihttp: https://github.com/suleymanlaarabi/sihttp

Expose these include directories to your application:

  • include
  • sireflect/include
  • sijson/include
  • sihttp/include

Link the public dependencies with SIECS:

  • sireflect
  • sijson
  • sihttp

Use these compile definitions for static builds:

  • siecs_STATIC
  • sireflect_STATIC
  • sijson_STATIC
  • sihttp_STATIC

On Linux, link pthread.

The runtime flow from the standalone example is:

  1. Create a world.
  2. Register component types.
  3. Create entities.
  4. Set or read component data.
  5. Destroy the world.
#include <siecs.h>
ECS_COMPONENT_DECLARE(Position, {
float x;
float y;
});
ECS_COMPONENT_DEFINE(Position);
int main(void) {
ecs_init();
ECS_COMPONENT_REGISTER(world, Position);
ecs_entity_t entity = ecs_new();
ecs_set(entity, Position, { .x = 10.0f, .y = 20.0f });
Position *position = ecs_get(entity, Position);
position->x += 1.0f;
ecs_fini();
return 0;
}

Most applications create systems instead of manually querying every frame:

ECS_COMPONENT(Velocity, {
    float x;
    float y;
});

static void Move(ecs_iter_t *it) {
    Position *positions = ecs_field(it, 0);
    const Velocity *velocities = ecs_field(it, 1);

    for (uint32_t i = 0; i < it->count; i++) {
        positions[i].x += velocities[i].x;
        positions[i].y += velocities[i].y;
    }
}

ecs_system({
    .name = "Move",
    .phase = EcsOnUpdate,
    .query.terms = { ecs_inout(Position), ecs_in(Velocity) },
    .callback = Move,
});

ecs_progress();

Systems own persistent queries internally, so they are the usual choice for repeated frame logic.

Applications include the public header:

#include <siecs.h>

The old ecs/world.h header is not part of the current public API.

Bake is the maintainer build for this repository and remains supported for consuming Bake projects.

For local development in this repository:

Terminal window
bake rebuild
bake rebuild test
bake run test

ecs_get() assumes the component exists on the entity. Use ecs_try_get() when the component may be absent.

ecs_set() adds the component when needed, then writes the value.

Entities passed to API functions must come from the same world.