# 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.**

- Repository: [Alexander/equilibriumengine](https://github.com/clibequilibrium/equilibriumengine)
- Tags: 
- Published: 2026-02-27

---

**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`](https://github.com/clibequilibrium/equilibriumengine/blob/main/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`](https://github.com/clibequilibrium/equilibriumengine/blob/main/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`](https://github.com/clibequilibrium/equilibriumengine/blob/main/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`](https://github.com/clibequilibrium/equilibriumengine/blob/main/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:

```c
/* 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:

```c
/* 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`](https://github.com/clibequilibrium/equilibriumengine/blob/main/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.