Skip to content

Anchor

Positions entities relative to viewport bounds using anchor percentages and pixel offsets. Automatically resolves the correct viewport dimensions based on the entity's layer coordinate space (screen, virtual, or world).

Basic Usage

teal
local ui = require("tecs2d.ui")
local Anchor = ui.Anchor

-- Bottom-left corner, 20px from edges
world:spawn(
    Transform(0, 0, 0, HUD_LAYER),
    Anchor(0, 1, 20, -20),
    Text(font, "Score: 0"),
    Pivot(0, 1)
)

-- Centered on screen
world:spawn(
    Transform(0, 0, 0, HUD_LAYER),
    Anchor(0.5, 0.5, 0, 0),
    Text(font, "PAUSED")
)

-- Top-right corner with offset
world:spawn(
    Transform(0, 0, 0, HUD_LAYER),
    Anchor(1, 0, -20, 20),
    Text(font, "HP: 100"),
    Pivot(1, 0)
)

Fields

FieldTypeDescription
anchorXnumberHorizontal anchor (0-1). 0=left, 0.5=center, 1=right
anchorYnumberVertical anchor (0-1). 0=top, 0.5=center, 1=bottom
offsetXnumberPixel offset from anchor X
offsetYnumberPixel offset from anchor Y

Constructor

teal
Anchor(anchorX, anchorY)              -- No offset
Anchor(anchorX, anchorY, offsetX, offsetY)  -- With offset

How It Works

Each frame, the ui.ComputeAnchor system resolves viewport bounds from the entity's layer, then writes to Transform.x and Transform.y:

transform.x = vpLeft + anchorX * vpWidth + offsetX
transform.y = vpTop  + anchorY * vpHeight + offsetY

The viewport bounds depend on the layer's coordinate space:

SpaceLeft/TopWidth/Height
"screen"0, 0screenWidth, screenHeight
"virtual"0, 0virtualWidth, virtualHeight
"world"camera visX1, visY1visX2 - visX1, visY2 - visY1

For world-space layers, the anchor tracks the camera; as the camera moves or zooms, anchored entities reposition automatically.

Anchored Parent with Children

Anchor works well with ChildOf + RelativeTransform to create groups of elements anchored together:

teal
-- Parent anchored to bottom-left
local hudRoot = world:spawn(
    Transform(0, 0, 0, HUD_LAYER),
    Anchor(0, 1, 20, -180)
)
world:commit()

-- Children positioned relative to parent
world:spawn(
    Transform(0, 0, 0, HUD_LAYER),
    ChildOf(hudRoot),
    RelativeTransform(0, 0),
    Text(font, "Line 1")
)
world:spawn(
    Transform(0, 0, 0, HUD_LAYER),
    ChildOf(hudRoot),
    RelativeTransform(0, 30),
    Text(font, "Line 2")
)

System Order

ui.ComputeAnchor runs in PostUpdate after layout systems and before RelativeTransform:

PostUpdate:
  ui.ComputeLayoutBox
  ui.ComputeFitContent
  ui.ComputeAnchor        -- resolves anchor → Transform.x/y
  ui.RelativeTransform     -- composes parent + child transforms

This means Anchor sets the parent position, then RelativeTransform offsets children from that position.

Requirements

  • Anchor only requires Transform on the same entity. No LayoutBox needed.
  • The ui.plugin is auto-installed by tecs2d.run. If not using tecs2d.run, install it manually: world:addPlugin(ui.plugin)
  • The render pipeline must be available as a world resource (created by tecs2d.run or gfx.newPipeline).