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.
Quick Start
Section titled “Quick Start”For a small C project, use the standalone distribution:
- Copy
distr/siecs.handdistr/siecs.cinto your project. - Include the public header.
- 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.
For a C++23 project, include the same public header and link the SIECS C runtime.
#include <siecs.h>
struct Position { float x, y;};
int main() { ecs::init(); auto entity = ecs::entity::create(); entity.set(Position{ .x = 10.0f, .y = 20.0f }); return 0;}Compile the C runtime as C, then link it with the C++ program:
cc -std=c23 -I. -c siecs.c -o siecs.oc++ -std=c++23 -I. main.cpp siecs.o -pthread -o my_appLanguage Setup
Section titled “Language Setup”The same SIECS runtime can be consumed from C or C++:
#include <siecs.h>Compile the C source with cc -std=c23.
#include <siecs.h>The C++23 API is a header-only wrapper around the C runtime. Link the SIECS C library with your application.
Bake Example
Section titled “Bake Example”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" } }}Manual Source Build
Section titled “Manual Source Build”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/sireflectsijson:https://github.com/suleymanlaarabi/sijsonsihttp:https://github.com/suleymanlaarabi/sihttp
Expose these include directories to your application:
includesireflect/includesijson/includesihttp/include
Link the public dependencies with SIECS:
sireflectsijsonsihttp
Use these compile definitions for static builds:
siecs_STATICsireflect_STATICsijson_STATICsihttp_STATIC
On Linux, link pthread.
Minimal Program
Section titled “Minimal Program”The runtime flow from the standalone example is:
- Create a world.
- Register component types.
- Create entities.
- Set or read component data.
- 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;}#include <siecs.h>
struct Position { float x, y; };
int main() { ecs::init(); auto entity = ecs::entity::create(); entity.set(Position{ .x = 10.0f, .y = 20.0f }); const bool present = entity.has<Position>(); (void)present; return 0;}Minimal System
Section titled “Minimal System”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();#include <siecs.h>
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.
Include Path
Section titled “Include Path”Applications include the public header:
#include <siecs.h>#include <siecs.h>
#include <siecs.h>The old ecs/world.h header is not part of the current public API.
Build With Bake
Section titled “Build With Bake”Bake is the maintainer build for this repository and remains supported for consuming Bake projects.
For local development in this repository:
bake rebuildbake rebuild testbake run testImportant Contracts
Section titled “Important Contracts”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.