How the TransformSystem Manages Object Positions and Rotations in EquilibriumEngine

The TransformSystem automatically converts raw Position, Rotation, and Scale components into unified 4×4 transformation matrices, handling both local and hierarchical world-space calculations.

The transform_system serves as the spatial backbone of the EquilibriumEngine ECS architecture, bridging raw geometric components with the unified transformation matrices required for rendering and physics. By automatically managing the conversion of Position, Rotation, and Scale data into optimized 4×4 matrices, this system ensures consistent object positioning throughout the engine without manual matrix calculations.

Core Responsibilities of the TransformSystem

Automatic Transform Component Creation

The AddTransform system, defined in equilibrium/systems/transform_system.c at lines 76-80, runs during the EcsPostLoad phase. It queries all entities containing Position, Rotation, or Scale components (or any combination thereof) and automatically attaches a Transform component to each. This ensures that every spatial entity has a destination matrix for the ApplyTransform system to populate.

Matrix Composition from Local Components

The ApplyTransform system, running on EcsOnValidate, performs the actual matrix construction in tight per-entity loops for cache efficiency. Located in equilibrium/systems/transform_system.c, this system:

  1. Initializes an identity matrix in Transform.value
  2. Applies translation using glm_translate_make or glm_translate_to (lines 27-47), checking for parent transforms
  3. Applies rotation around X, Y, and Z axes using glm_rotate if a Rotation component exists (lines 49-63)
  4. Applies uniform or non-uniform scaling using glm_scale if a Scale component exists (lines 65-69)

Hierarchical Transform Support

When an entity has a parent with a Transform component tagged as parent|cascade, the system reads the parent's matrix (m_parent) and composes the child's matrix relative to it using glm_translate_to. This implementation in lines 38-47 of equilibrium/systems/transform_system.c enables scene-graph-style parenting, where transforming a parent automatically updates all children in world space.

System Registration and Performance Optimization

The TransformSystemImport function (lines 72-89 in equilibrium/systems/transform_system.c) registers both systems with the ECS world. The ApplyTransform query is marked as instanced, meaning the system runs once per matching entity rather than per frame, significantly improving cache locality and performance when processing thousands of spatial entities.

Practical Implementation Examples

Creating a basic entity with spatial components:

/* Create entity with position, rotation and scale */
ecs_entity_t e = ecs_new(world, 0);
ecs_set(world, e, Position, {.x = 1.0f, .y = 2.0f, .z = 3.0f});
ecs_set(world, e, Rotation, {.x = 0.0f, .y = M_PI_2, .z = 0.0f});
ecs_set(world, e, Scale,    {.x = 1.0f, .y = 1.0f, .z = 1.0f});

/* AddTransform automatically attaches Transform component */
/* ApplyTransform updates the matrix */
ecs_progress(world, 0.0);

/* Access the world-space matrix */
const Transform *mtx = ecs_get(world, e, Transform);
printf("World matrix: %f %f %f %f …\n", mtx->value[0][0], mtx->value[0][1], …);

Implementing hierarchical transforms:

/* Parent entity at world position (5, 0, 0) */
ecs_entity_t parent = ecs_new(world, 0);
ecs_set(world, parent, Position, {.x = 5.0f, .y = 0.0f, .z = 0.0f});

/* Child entity with parent relationship */
ecs_entity_t child = ecs_new_w_pair(world, EcsIsA, parent);
ecs_set(world, child, Position, {.x = 0.0f, .y = 2.0f, .z = 0.0f});

/* Process transforms */
ecs_progress(world, 0.0);

/* Child's world matrix combines parent translation + child offset */
const Transform *child_mtx = ecs_get(world, child, Transform);
/* Results in world position (5, 2, 0) */

Summary

  • The transform_system automatically generates 4×4 transformation matrices from Position, Rotation, and Scale components.
  • AddTransform (equilibrium/systems/transform_system.c:76-80) initializes Transform components during the EcsPostLoad phase.
  • ApplyTransform (equilibrium/systems/transform_system.c:27-69) composes matrices using GLM functions for translation, rotation, and scaling.
  • Hierarchical transforms are supported through parent matrix multiplication (lines 38-47), enabling scene-graph functionality.
  • The system uses instanced queries for cache-efficient processing of thousands of entities.

Frequently Asked Questions

How does the TransformSystem handle entities without all three spatial components?

The AddTransform system queries for entities that have any combination of Position, Rotation, or Scale components. If an entity has only a Position but no Rotation or Scale, the system still creates a Transform component and ApplyTransform handles the missing components by skipping the relevant matrix operations, resulting in a pure translation matrix.

What ECS phase does the TransformSystem use for matrix updates?

The ApplyTransform system runs during the EcsOnValidate phase, which occurs after component values are set but before the frame is rendered. This ensures that all transformation matrices are up-to-date for the rendering and physics systems that run in subsequent phases.

Can the TransformSystem handle non-uniform scaling?

Yes, the Scale component accepts a vec3 (x, y, z), allowing non-uniform scaling. The ApplyTransform system applies this using glm_scale (lines 65-69 in equilibrium/systems/transform_system.c), which supports different scale factors for each axis.

How does parent-child transform hierarchy affect performance?

The system uses instanced queries for the ApplyTransform system, meaning it processes entities in tight loops with good cache locality. While parent lookups require reading the parent's Transform component, the ECS architecture minimizes this overhead by grouping entities with similar component signatures together, making hierarchical updates efficient even with thousands of entities.

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 →