Skip to content

Builtins

Tecs provides various builtin plugins, components, and events. These builtins are registered with every World by default.

Components

ComponentDescription
NameProvides a name for an entity
ChildOfParent/child relationship between entities
TransformPosition, rotation, scale, and layer
RelativeTransformTransform relative to parent entity
TTLAutomatically despawn after time expires
DisabledExcludes entity from all queries
PausedExcludes from gameplay queries, keeps rendering

Name component

Provides a name for an entity. Stored as a scalar component of kind string, so the column holds the raw string and world:get(id, Name) returns a string directly.

Teal type:

teal
Name: tecs.ScalarComponent<string>

Example:

teal
local tecs = require("tecs")

local entity = world:spawn(
    tecs.builtins.Name("Phreddy")
)

local name = world:get(entity, tecs.builtins.Name) -- "Phreddy"

To update an existing entity's name, prefer the 3-arg form of world:set:

teal
world:set(entity, tecs.builtins.Name, "Greg")

ChildOf relationship component

Defines an exclusive parent-child relationship between two entities. Uses sparse storage with cascade delete: despawning a parent automatically despawns all children (and grandchildren, recursively).

Registered with: exclusive = true, sparse = true, reverseIndex = true, cascadeDelete = true

Example:

teal
local parent = world:spawn()
local child = world:spawn(tecs.builtins.ChildOf(parent))

-- Find all children of a parent
world:targets(parent, tecs.builtins.ChildOf, function(childId: integer)
    print("Child:", childId)
end)

-- Despawning the parent cascades to children
world:despawn(parent)

See Relationships for details on sparse storage and cascade delete.

Transform component

Provides the position, rotation, scale, and layer of an entity. You can use this component if it works for your game, or ignore it if not.

Teal type:

teal
record Transform is components.Component
    --- The x coordinate of the entity.
    x: number

    --- The y coordinate of the entity.
    y: number

    --- The z coordinate of the entity.
    z: number

    --- The layer of the entity (or nil if you don't use layers).
    layer: integer

    --- The rotation of the entity in radians (default: 0).
    rotation: number

    --- The horizontal scale of the entity (default: 1).
    scaleX: number

    --- The vertical scale of the entity (default: 1).
    scaleY: number

    --- Creates a new Transform component.
    ---
    --- @param xOrValue The x position or full transform data if passing a table.
    --- @param y The y position.
    --- @param z The z position.
    --- @param layer The layer.
    --- @return the created transform component.
    metamethod __call: function(
        self,
        xOrValue?: Transform | number,
        y?: number,
        z?: number,
        layer?: integer
    ): Transform
end

Examples:

You can create a Transform component using positional arguments. This is ideal for performance:

teal
local entity = world:spawn(
    tecs.builtins.Transform(10, 11, 1, 2) -- x, y, z, layer
)

Alternatively, you can pass a table of named arguments. This generates garbage due to the table input, but it's more readable.

teal
world:spawn(
    tecs.builtins.Transform.new({
        x = 10,
        y = 11,
        z = 1,
        layer = 2
    })
)

After the component is created, you can modify anything inside of it as needed, like rotation and scale.

teal
local transform = world:get(entity, tecs.builtins.Transform)
transform.rotation = math.pi / 4  -- Rotate 45 degrees
transform.scaleX = 2              -- Scale 2x horizontally
transform.scaleY = 2              -- Scale 2x vertically

Auto-sync

Modifying anything in the Transform component automatically syncs to all builtin GPU systems in Tecs. No dirty tracking needed.

RelativeTransform component

Defines an entity's transform relative to its parent entity. Requires the ChildOf component to be present on the same entity. A builtin system automatically composes the parent's transform with the relative transform to compute the final world-space position, rotation, and scale.

This component:

  • Can position an entity relative to another, allowing use cases like GUI elements
  • Causes child entities to hierarchically inherit the position, scaling, and rotation of a parent entity
  • Automatically adds a Transform component if one is not present when added to an entity

Parameters:

  • x: The x offset from the parent (default: 0)
  • y: The y offset from the parent (default: 0)
  • z: The z offset from the parent (default: 0)
  • rotation: The rotation offset in radians from the parent (default: 0)
  • scaleX: The x scale multiplier relative to the parent (default: 1)
  • scaleY: The y scale multiplier relative to the parent (default: 1)
  • originX: Origin as a fraction (0-1) of the entity's width; 0 = left, 0.5 = center, 1 = right (default: 0)
  • originY: Origin as a fraction (0-1) of the entity's height; 0 = top, 0.5 = center, 1 = bottom (default: 0)

Teal type:

teal
record RelativeTransform is components.Component
    x: number
    y: number
    z: number
    rotation: number
    scaleX: number
    scaleY: number
    --- Origin as a fraction (0-1) of the entity's width: 0 = left, 0.5 = center, 1 = right.
    originX: number
    --- Origin as a fraction (0-1) of the entity's height: 0 = top, 0.5 = center, 1 = bottom.
    originY: number

    metamethod __call: function(
        self,
        x?: number,
        y?: number,
        z?: number,
        rotation?: number,
        scaleX?: number,
        scaleY?: number,
        originX?: number,
        originY?: number
    ): RelativeTransform
end

Examples:

Create a child entity positioned relative to its parent:

teal
local parent = world:spawn(
    tecs.builtins.Transform(100, 100, 0)
)

local child = world:spawn(
    tecs.builtins.ChildOf(parent),
    tecs.builtins.RelativeTransform(50, 30)  -- 50px right, 30px down
)

The child's world-space position is automatically calculated as (150, 130) and updated each frame as the parent moves.

TTL component

Automatically despawns an entity when the TTL, or "time to live", reaches zero. Tecs automatically adds a system that tracks entities with a TTL and despawns them.

Teal type:

teal
--- Despawns an entity when the TTL reaches zero.
record TTL is components.Component
    --- The total amount of time the entity had to live.
    startingTime: number

    --- The remaining time the entity has to live.
    remaining: number

    --- Compute the percentage of completion as a number between 0 and 1.
    percentComplete: function(self): number

    --- Create a new TTL component.
    ---
    --- @param remaining The amount of time the entity has to live.
    --- @return the created TTL component.
    metamethod __call: function(self, remaining: number): TTL
end

Example:

teal
world:spawn(
    -- Despawn the entity after 10 seconds.
    tecs.builtins.TTL(10)
)

Disabled component

A tag component that marks an entity as disabled, causing it to be excluded from all queries by default. This is useful for temporarily hiding entities without despawning them.

Usage:

teal
-- Spawn a disabled entity (won't appear in queries by default)
local entity = world:spawn(
    tecs.builtins.Disabled
)

See also

See Disabled entities for more on how disabled entities work with queries.

Paused component

A tag component that marks an entity as paused. Unlike Disabled, Paused is not auto-excluded from queries. Paused entities should still render; only gameplay systems that need to skip them should use exclude = {Paused}.

This is typically managed automatically by the state stack when a state's onBlur policy is set to "pause". You can also add it manually:

teal
-- Pause an entity (excluded from gameplay queries, still renders)
world:set(entity, tecs.builtins.Paused)

-- Unpause
world:remove(entity, tecs.builtins.Paused)

When Paused is added to an entity with a Sprite component, the sprite animation is automatically frozen at the current frame. When Paused is removed, the animation resumes from where it left off.

See also

See Paused entities for more on how paused entities work with queries.

Events

EventDescription
ArchetypeCreatedEmitted when a new archetype is created
OnSpawnEmitted when an entity is spawned
OnDespawnEmitted when an entity is despawned

ArchetypeCreated event

An event emitted when a new archetype is created in the world. Observe this event at address 0 (world-level) to discover new archetypes as entities with new component combinations are spawned.

Teal type:

teal
--- An event emitted when a new archetype is created.
record ArchetypeCreated is events.Event
    archetype: Archetype

    --- Create a new ArchetypeCreated event.
    metamethod __call: function(self, archetype: Archetype): ArchetypeCreated
end

Usage:

teal
world:observe(0, tecs.builtins.ArchetypeCreated, function(event: tecs.builtins.ArchetypeCreated)
    local archetype = event.archetype
    if archetype:get(Position) and archetype:get(Velocity) then
        -- Inspect or introspect newly-created archetypes here.
    end
end)

Advanced feature

This event is primarily used internally by queries to track matching archetypes. For normal "react when entities match a component signature" use cases, prefer query callbacks (onEntitiesAdded / onEntitiesRemoved).

OnSpawn event

An event emitted when an entity is spawned. The event is emitted globally (address 0). Observe this event to react when entities are created.

Event timing

The OnSpawn event is emitted at spawn time (when world:spawn is called), before the entity is committed:

  • The entity is not yet placed in an archetype or visible to queries
  • world:isAlive(entity) returns false until commit
  • You can stage further mutations on the entity ID between spawn and commit

Teal type:

teal
--- An event emitted when a specific entity is spawned.
record OnSpawn is events.Event
    entity: integer

    --- Create a new OnSpawn event.
    metamethod __call: function(self, entity: integer): OnSpawn
end

Usage:

Observe globally to react to all spawns:

teal
world:observe(0, tecs.builtins.OnSpawn, function(event: tecs.builtins.OnSpawn)
    print("Entity spawned: " .. event.entity)
end)

OnDespawn event

An event emitted when an entity is despawned. The event is emitted both globally (address 0) and to the entity's address. Observe this event to clean up resources, spawn effects, or react to entity removal.

Event timing

The OnDespawn event is emitted during the despawn call, before the entity is physically removed at commit. When this event fires:

  • world:isAlive(entity) still returns true (the entity index entry is intact)
  • Entity components are still accessible via world:get()
  • The entity has not yet been removed from queries
  • After all observers complete, all observers on the entity's address are automatically cleaned up

Teal type:

teal
--- An event emitted when a specific entity is despawned.
record OnDespawn is events.Event
    entity: integer

    --- Create a new OnDespawn event.
    metamethod __call: function(self, entity: integer): OnDespawn
end

Usage:

Observe a specific entity:

teal
world:observe(entityId, tecs.builtins.OnDespawn, function(e: tecs.builtins.OnDespawn)
    -- Entity is no longer "alive" but components are still accessible
    local pos = world:get(e.entity, Position)
    if pos then
        spawnExplosionAt(pos.x, pos.y)
    end
    print("Entity " .. e.entity .. " was despawned")
end)

Observe globally to react to all despawns:

teal
world:observe(0, tecs.builtins.OnDespawn, function(e: tecs.builtins.OnDespawn)
    print("Entity " .. e.entity .. " was despawned")
end)