Every entity that lives in the game world needs a position.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/VKSFY/keel/llms.txt
Use this file to discover all available pages before exploring further.
Transform2D and Transform3D are the ECS components that provide it. The 2D renderer, physics bridge, and text system all read from these components directly — you never call a setter method, you simply write to the fields and the engine picks them up on the next tick.
Both components are registered with the @component decorator, meaning they are stored as structured NumPy arrays in the world’s archetypes. You interact with them through world.spawn(...), world.set(...), and archetype queries.
Transform2D
Transform2D represents a world-space 2D pose. Position is in pixels (the default camera maps pixels 1-to-1 to screen coordinates at zoom 1.0). Rotation is measured in radians, counterclockwise. Scale multiplies both the entity’s own dimensions (e.g. Sprite.width) and any child transforms downstream.
Fields
World-space X position in pixels. Positive X points right.
World-space Y position in pixels. Positive Y points up in world space. The default camera places (0, 0) at the bottom-left of the window.
Rotation in radians, counterclockwise from the positive X axis. The 2D renderer and physics bridge both read this field. Use
math.radians() to convert from degrees.Horizontal scale multiplier. Multiplied against
Sprite.width (or any width field) when the entity is drawn. A value of 2.0 doubles the apparent width.Vertical scale multiplier. Multiplied against
Sprite.height. A value of 0.5 halves the apparent height.Transform3D
Transform3D represents a world-space 3D pose using Euler angles. Rotations are applied in YXZ order (yaw → pitch → roll in camera terms), stored per-axis as rot_x, rot_y, rot_z. A parent field enables a lightweight scene-hierarchy — set it to the entity ID of the parent entity; 0 means no parent (root).
The 3D renderer calls
resolve_world_matrix(entity_id, world) each frame to walk the parent chain and compose the final model matrix. Deep hierarchies add per-frame parent lookups; keep chains shallow for performance.Fields
World-space X position (or local X when
parent is non-zero).World-space Y position. Positive Y is up in Keel’s right-handed coordinate system.
World-space Z position. Negative Z points into the screen in a right-handed system (camera looks toward −Z by default).
Rotation around the X axis (pitch) in radians. Applied second in the YXZ Euler decomposition.
Rotation around the Y axis (yaw) in radians. Applied first in the YXZ Euler decomposition.
Rotation around the Z axis (roll) in radians. Applied third in the YXZ Euler decomposition.
Scale multiplier along the X axis. Combined with parent scale when the world matrix is resolved.
Scale multiplier along the Y axis.
Scale multiplier along the Z axis.
Entity ID of this transform’s parent.
0 means root (no parent). When non-zero, the 3D renderer walks the chain and multiplies parent model matrices together before drawing this entity. The pybullet bridge always uses world-space position/rotation directly and ignores this field.Updating transforms at runtime
Both components live in NumPy structured arrays. The idiomatic way to move an entity is to write directly to the column in a system:world.set(entity_id, Transform2D, x=100.0).