Skip to content

Transforms & Hierarchy

The Transform places an object in space, and parenting links transforms into a hierarchy so children move with their parents. This page explains how local and world space relate, and how Awaken3D keeps it fast.

The Transform component

Every GameObject has a Transform - three fields:

FieldTypeMeaning
positionvec3Offset from the parent's origin.
rotationquatOrientation, stored as a quaternion (x, y, z, w).
scalevec3Per-axis size multiplier (defaults to (1, 1, 1)).

Rotation is stored internally as a quaternion because quaternions compose cleanly and never gimbal-lock. The Inspector shows and edits it as Euler angles (degrees) for convenience, converting to and from the quaternion under the hood. When you script a rotation you work with quaternions directly.

📸 Screenshot - save as img/world-transform-inspector.png

The Transform section of the Inspector showing Position, Rotation (as Euler XYZ degrees), and Scale fields for a selected object.

Local vs world space

A Transform is always local - it is expressed relative to the object's parent. The value you type in the Inspector for a child is its offset from the parent, not from the scene origin.

The world transform is what you actually see: the local transform composed with every ancestor's, from the root down. Awaken3D computes it two ways depending on need:

  • worldTRS returns the world position/rotation/scale as a triple - used where an exact placement is needed, for example so a nested object's collider sits on its mesh rather than back near the parent's origin.
  • World matrices (4×4) are what the renderer consumes for drawing.

Composition walks root → entity, applying at each step:

worldPos   += worldRot · (worldScale ⊙ localPos)
worldRot   ·= localRot
worldScale ⊙= localScale

Because this assumes a clean translate-rotate-scale hierarchy, non-uniform scale under a rotated parent produces shear - visible on meshes and unrepresentable by a rigid physics body. Keep scale uniform on objects that are rotated and parented, or bake scale into the mesh at import.

One subtlety: if an ancestor has no Transform, the chain breaks there - the object is rooted at that gap rather than composing past it. Both the render path and the physics path agree on this, so what you see matches what you collide with.

Building a hierarchy

Parenting is a link from child to parent. In the editor you create it by dragging one object onto another in the Hierarchy; in scripts you set go.parent. A parent can have many children; a child has exactly one parent (or none, making it a root).

Moving Player moves everything under it. Rotating Arm.R swings Hand.R and the Sword with it, because each child's world transform is rebuilt from its parent's.

Cycle rejection

A hierarchy must stay a tree - no loops. Before attaching a child to a new parent, Awaken3D walks up from the proposed parent; if it ever reaches the child, the reparent is rejected and nothing changes. So you can never accidentally make an object its own ancestor by dragging it onto one of its own descendants. The reorder and reparent editor commands honour the same guard.

How updates stay cheap

Recomputing every object's world matrix each frame would be wasteful in a large scene. Awaken3D avoids it with two mechanisms on the World:

  • structureRev - a counter bumped only on structural changes: creating/destroying an entity, adding/removing a component, or changing a parent/active/static flag. The renderer compares it frame-to-frame; unchanged means the draw topology is stable and only transforms need syncing.
  • The moved-set - when a system, physics step, or script writes a Transform, it calls markMoved(entity). Each frame the renderer recomputes world matrices only for the moved entities and their descendants, reusing every other cached matrix.

The payoff: a scene of 15,000 static props with a single rotating door recomputes one small subtree per frame, not the whole world. This is also why moving a static object is cheap - the move updates one transform slot without rebuilding any geometry.

See also

Awaken — browser-native WebGPU game engine.