Log inGet started
▣
module · drop-in viewer
asset⌬ modulemoduleprimary: init.luau·originates fromworld 07158574-5…

transform

Math helpers for positions, rotations, and directions on transforms. Exposed as the global `Transform` table via `--!global Transform` — no explicit require needed in user code. Functions that take an entity accept either an entity ID string or an entity proxy table from `entity(…

byzero-proxy @ DESKTOP-DB3UJOJ·posted 2mo ago
What it does

transform

Math helpers for positions, rotations, and directions on transforms. Exposed as the global Transform table via --!global Transform — no explicit require needed in user code. Functions that take an entity accept either an entity ID string or an entity proxy table from entity("id").

Exports

Look-at and entity-aware helpers:

  • Transform.lookAtQuat(fx, fy, fz, tx, ty, tz) -> (qx?, qy?, qz?, qw?) — quaternion from origin toward target. Nil when degenerate.
  • Transform.lookAt(entity, txOrTarget, ty?, tz?) -> (boolean, string?) — make an entity face a world position or another entity. Both slots read world space: the subject and an entity target are read as entity(id).position and the aim is written as entity(id).rotation, so a parent under either one still leaves the aim on the point named. Returns whether the rotation was written, and the reason when it was not.
  • Transform.distance(x1, y1, z1, x2, y2, z2) -> number — Euclidean distance between two points.
  • Transform.distanceBetween(entityA, entityB) -> number? — distance between two entities' world positions. Nil when either is unresolvable.
  • Transform.direction(fromX, fromY, fromZ, toX, toY, toZ) -> (dx, dy, dz) — unit direction vector.
  • Transform.directionBetween(entityA, entityB) -> (dx, dy, dz) — unit world-space direction between two entities' world positions.

Rotation shapes:

A quaternion constructor here returns the four components as four separate values, so a caller either names them or braces the call to make one table:

local qx, qy, qz, qw = Transform.quatFromAxisAngle(0, 1, 0, math.rad(90))
entity("cam").localRotation = { Transform.quatFromAxisAngle(0, 1, 0, math.rad(90)) }

A rotation-taking surface reads that table through Transform.toQuaternion, which also takes euler DEGREES — so { qx, qy, qz, qw }, { x =, y =, z =, w = }, { pitch, yaw, roll } and { pitch =, yaw =, roll = } all mean the same thing wherever a rotation is assigned: entity(id).rotation / .localRotation, entityOps.spawn, entityOps.transform, and the capture viewpoints.

  • Transform.toQuaternion(rotation, label?) -> { qx, qy, qz, qw } — the shared reading of a rotation a caller wrote. Raises when the value matches no form, naming what arrived; a value that is one of the shapes a quaternion helper returns is named as such along with the packing it goes in as.
  • Transform.tryQuaternion(rotation, label?) -> ({ qx, qy, qz, qw } | nil, message?) — the same reading without raising, for a surface that wants to raise the message at its own caller's line.
  • Transform.readVec3(value, label?) -> { x, y, z } — the same for a vector.
  • Transform.snapVec3(v, step) -> { x, y, z } — quantize a vector to a step grid.

Quaternion construction / conversion:

  • Transform.quatFromYaw(yaw), Transform.quatFromYawPitch(yaw, pitch), Transform.quatFromAxisAngle(ax, ay, az, angle) — quaternion constructors.
  • Transform.quatIdentity() — identity quaternion.
  • Transform.euler(qx, qy, qz, qw) -> (yaw, pitch, roll) and the named alias Transform.quatToEuler.
  • Transform.eulerToQuat(yaw, pitch?, roll?) — euler-to-quaternion in YXZ order.

Lerps and interpolation:

  • Transform.lerp(ax, ay, az, bx, by, bz, t) -> (x, y, z) — vec3 lerp.
  • Transform.lerp1(a, b, t) -> number — scalar lerp.
  • Transform.normalizeAngle(a) -> number — wrap angle into [-pi, pi].
  • Transform.lerpAngle(a, b, t) -> number — shortest-arc angle lerp.
  • Transform.slerp(ax, ay, az, aw, bx, by, bz, bw, t) -> (qx, qy, qz, qw) — quaternion slerp with shortest-path and near-parallel fallback.

Quaternion operations:

  • Transform.quatMul(...) -> (qx, qy, qz, qw) — qa * qb composition.
  • Transform.quatInverse(qx, qy, qz, qw) -> (qx, qy, qz, qw) — inverse (= conjugate for unit quats).
  • Transform.quatRotateVec(qx, qy, qz, qw, vx, vy, vz) -> (x, y, z) — rotate a vec3 by a quaternion.

Pose helpers:

  • Transform.orbit(centerX, centerY, centerZ, radius, height, angle) -> (x, y, z, qx, qy, qz, qw) — orbital pose facing the center.
  • Transform.worldToLocal(...) / Transform.localToWorld(...) — pose-space conversions.

Nested Transform.vec.* namespace (component-wise vec3):

  • Transform.vec.add, sub, scale, dot, cross, length, normalize.

Types:

  • Vec3 = { x: number, y: number, z: number }
  • EntityRef = string | { entityId: string }

Usage

-- Look-at by coordinates or by target entity:
Transform.lookAt("cam", 0, 1, 0)
-- an entity target resolves to that entity's world position
local aimed, why = Transform.lookAt("cam", "box")

-- Orbit pose around a point:
local x, y, z, qx, qy, qz, qw = Transform.orbit(0, 1, 0, 5, 2, t)
entity.find("cam").localPosition = { x, y, z }
entity.find("cam").localRotation = { qx, qy, qz, qw }

-- Quaternion math:
local qx, qy, qz, qw = Transform.quatFromYawPitch(math.pi / 4, 0)
local sx, sy, sz, sw = Transform.slerp(0, 0, 0, 1, qx, qy, qz, qw, 0.5)

-- Component-wise vec3 helpers:
local nx, ny, nz = Transform.vec.normalize(1, 1, 0)

Notes

  • The --!global Transform directive promotes the module's typed functions onto the runtime universe's globals bucket, so Transform.* is available without any per-source require.
  • Entity-aware functions (lookAt, distanceBetween, directionBetween) report a missing entity or a missing transform in their return value rather than raising: lookAt answers false, "unresolved" / "no-transform" / "incomplete-target" / "degenerate", distanceBetween answers nil, and directionBetween answers zeros.
  • Quaternion APIs operate on raw (qx, qy, qz, qw) tuples for parity with the entity proxy's localRotation.get/set. Use Transform.quatIdentity() rather than hand-rolling (0, 0, 0, 1).
  • Transform.slerp flips the second quaternion if dot < 0 to take the shortest path, and falls back to lerp+normalize when the inputs are within dot > 0.9995 to avoid 1/0 near-parallel issues.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

module Transform Math helpers for positions, rotations, and directions on transforms. Exposed as the global `Transform` table; entity-aware helpers accept an id string or an entity proxy. global Transform

eulerZyxDegToQuat(pitchDeg: number, yawDeg: number, rollDeg: number) → void

argtypedescription
pitchDegnumber
yawDegnumber
rollDegnumber

resolveEntityId(e: ?) → string

Internal: the id behind an entity reference. Accepts an EntityRef proxy, a bare id string, or an entity NAME, and answers the id of the entity that reference names. Returns nil when the reference resolves to no entity in the scene, so a caller can refuse it rather than aim at a position it never read. A string is tested as a NAME first, with `entity.find`, and then as an id, with `entity.exists`. Both stay silent for a string that matches nothing, so an unresolvable reference reaches the caller as this function's nil rather than as an error on the log — which is what `entity(id)` would leave behind.

argtypedescription
e?

getPos(entityId: string) → void

Internal: read a WORLD position via the entity proxy, given an id `resolveEntityId` already answered for. Returns (x, y, z) or (nil, nil, nil) when the entity lacks a transform. World rather than local, because every surface built on this reads two entities against each other — a distance, a direction, an aim — and the answer only holds when both are expressed in the same frame. A parent's offset moves an entity's world position and leaves its local one where it was, so a local read puts the two entities in different frames and the number that comes out belongs to neither.

argtypedescription
entityIdstring

readKeyedPoint(value: any) → void

Internal: the component reads a point table answers, taken through whatever metatable it carries. A sealed proxy answers an index outside its own members by raising, so both reads run guarded and the table reaches `pointFrom` as the point it spells or as none.

argtypedescription
valueany

readArrayPoint(value: any) → void

argtypedescription
valueany

pointFrom(value: any) → void

Internal: the three components of a point a caller wrote as one table — `{ x, y, z }`, `{ x =, y =, z = }`, or a live vec handle. Returns (nil, nil, nil) for a table that spells no point, so a target slot reading both entities and points can refuse it rather than aim at zeros.

argtypedescription
valueany

lookAtQuat(fx: number, fy: number, fz: number, tx: number, ty: number, tz: number) →

Compute quaternion to look from origin position toward a target. Returns four components `(qx, qy, qz, qw)`, or `nil` when the from and to points are too close to derive a meaningful direction.

argtypedescription
fxnumberOrigin x.
fynumberOrigin y.
fznumberOrigin z.
txnumberTarget x.
tynumberTarget y.
tznumberTarget z.

examples

local qx, qy, qz, qw = Transform.lookAtQuat(0, 0, 0, 1, 0, 1)

quatFromBasis(rx: number, ry: number, rz: number, ux: number, uy: number, uz: number, fx: number, fy: number, fz: number) →

Build the rotation whose right, up and forward ARE the given axes. Where `lookAtQuat` derives a rotation from a direction alone — yaw and pitch, with pitch clamped just short of straight up or down and no say in the roll — this states all three axes, so a view straight down has a defined image-up instead of whatever the yaw implied. The axes are expected orthonormal and are used as given: `right` and `up` are the entity's local +X and +Y, `forward` its local -Z (the direction it faces).

argtypedescription
rxnumberRight axis x.
rynumberRight axis y.
rznumberRight axis z.
uxnumberUp axis x.
uynumberUp axis y.
uznumberUp axis z.
fxnumberForward axis x.
fynumberForward axis y.
fznumberForward axis z.

examples

local qx, qy, qz, qw = Transform.quatFromBasis(1,0,0, 0,1,0, 0,0,-1) -- identity
-- looking straight down with the subject's front toward the top of frame
local qx, qy, qz, qw = Transform.quatFromBasis(1,0,0, 0,0,-1, 0,-1,0)

lookRotation(fx: number, fy: number, fz: number, tx: number, ty: number, tz: number, ux: number?, uy: number?, uz: number?) →

The rotation that aims an entity standing at one world point at another, with a world up hint deciding the roll. Where `lookAtQuat` derives the aim from yaw and pitch alone — clamping the pitch just short of vertical, so a point directly overhead comes back a twentieth of a degree off — this builds all three axes, so the aim lands on the point at any elevation and straight up and straight down are ordinary cases. The aimed axis is the entity's local -Z, the same forward `quatFromBasis`, `Transform.lookAt` and `entity(id):lookAt` state and the direction `entity(id).transform.forward` reads back. The up hint is a world direction the entity's own +Y is turned toward as far as the aim allows; it never bends the forward axis. A hint parallel to the aim leaves the roll undetermined, and a hint of no length names no direction — both fall back to a stable roll rather than a NaN. coincide, so no facing direction exists.

argtypedescription
fxnumberEye x — where the entity stands.
fynumberEye y.
fznumberEye z.
txnumberTarget x — the world point it faces.
tynumberTarget y.
tznumberTarget z.
uxnumber?Up hint x. World +Y when the hint is omitted.
uynumber?Up hint y.
uznumber?Up hint z.

examples

local qx, qy, qz, qw = Transform.lookRotation(0, 2, 10, 0, 1, 0)
entity("cam").rotation = { Transform.lookRotation(0, 2, 10, 0, 1, 0) }
-- a dutch tilt: the same aim, rolled by leaning the up hint
local q = { Transform.lookRotation(0, 2, 10, 0, 1, 0, 0.2, 1, 0) }

lookAt(entityOrId: string | EntityRef, txOrTarget: any, ty: any?, tz: number?, up: any?) →

Make an entity face a world position. The target slot accepts three explicit coordinates, one point as `{ x, y, z }` / `{ x =, y =, z = }` / a vector, or an entity — an id string, an entity NAME, or a proxy — whose WORLD position is resolved. A table carrying an entity id reads as that entity; any other table reads as the point it spells. The subject slot takes the three entity spellings. Everything here is world space: the subject and the target are read as `entity(id).position` and the aim is written as `entity(id).rotation`, so a parent under either one moves the entity and the aim still lands on the point named. Returns whether the rotation was written, so a caller that named an entity the scene does not carry learns the aim did not happen instead of reading a stale orientation back as the answer. proxy whose world position is resolved as the look-at target. `{ x =, y =, z = }` or a vector. World +Y when omitted. It never bends the aim; it only says which way is up around it. When the target slot is an entity or a point this is the third argument, and when it is coordinates the fifth. second value. The target and up slots take any value, because naming which of the shapes arrived is this call's own job: a value that is none of them comes back as a reason rather than as an error raised out of the argument check. False plus a reason otherwise: `"unresolved"` when a reference names no entity, `"no-transform"` when one carries no transform, `"incomplete-target"` when the target spells no point — coordinates with a y or z missing, or a table carrying neither three numbers nor x/y/z, `"incomplete-up"` when the up hint spells none either, `"degenerate"` when the two points coincide so no facing direction exists.

argtypedescription
entityOrIdstring | EntityRefEntity id, name, or proxy for the entity to rotate.
txOrTargetanyA number (world x), a point table, or an entity id / name /
tyany?World y of the target. Omitted when `txOrTarget` is a point or an entity.
tznumber?World z of the target. Omitted when `txOrTarget` is a point or an entity.
upany?Optional world up hint deciding the roll — `{ x, y, z }`,

examples

Transform.lookAt("cam", 0, 1, 0)
Transform.lookAt("cam", "box")  -- resolve target entity position
Transform.lookAt(cam, box)      -- entity proxies for both
Transform.lookAt("cam", { 0, 1, 0 })         -- one point table
Transform.lookAt("cam", "box", { 0, 0, 1 })  -- rolled to a +Z up

distance(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) → number

Euclidean distance between two world-space positions.

argtypedescription
x1numberFirst point x.
y1numberFirst point y.
z1numberFirst point z.
x2numberSecond point x.
y2numberSecond point y.
z2numberSecond point z.

examples

local d = Transform.distance(0, 0, 0, 1, 1, 1)

distanceBetween(entityA: string | EntityRef, entityB: string | EntityRef) → number

Distance between two entities in world space. Each entity's world position is what is measured, so a parent's offset counts toward the distance the way the scene shows it.

argtypedescription
entityAstring | EntityRefFirst entity (id string or proxy).
entityBstring | EntityRefSecond entity (id string or proxy).

examples

local d = Transform.distanceBetween("cam", "box")

direction(fromX: number, fromY: number, fromZ: number, toX: number, toY: number, toZ: number) →

Normalized direction vector from point A to point B. Returns zeros when the two points coincide (within ~0.001 units).

argtypedescription
fromXnumberFrom x.
fromYnumberFrom y.
fromZnumberFrom z.
toXnumberTo x.
toYnumberTo y.
toZnumberTo z.

examples

local dx, dy, dz = Transform.direction(0, 0, 0, 1, 0, 0)

directionBetween(entityA: string | EntityRef, entityB: string | EntityRef) →

Normalized world-space direction from one entity to another, read from their world positions. Returns zeros if either entity can't be resolved.

argtypedescription
entityAstring | EntityRefSource entity (id string or proxy).
entityBstring | EntityRefTarget entity (id string or proxy).

examples

local dx, dy, dz = Transform.directionBetween("cam", "target")

quatFromYaw(yaw: number) →

Create quaternion from yaw (Y-axis rotation) in radians. Uses the negative-yaw convention shared with `quatFromYawPitch`, `lookAtQuat`, and `T.euler` extraction — so `T.euler(T.quatFromYaw(y))` round-trips to `y`.

argtypedescription
yawnumberRotation in radians around the Y axis.

examples

local qx, qy, qz, qw = Transform.quatFromYaw(math.pi / 2)

quatFromYawPitch(yaw: number, pitch: number) →

Create quaternion from yaw and pitch in radians.

argtypedescription
yawnumberY-axis rotation in radians.
pitchnumberX-axis rotation in radians.

examples

local qx, qy, qz, qw = Transform.quatFromYawPitch(0, math.pi / 4)

quatFromAxisAngle(ax: number, ay: number, az: number, angle: number) →

Create quaternion from axis and angle (radians). Returns the identity quaternion when the axis is degenerate (length < 0.001).

argtypedescription
axnumberAxis x.
aynumberAxis y.
aznumberAxis z.
anglenumberRotation angle in radians.

examples

local qx, qy, qz, qw = Transform.quatFromAxisAngle(0, 1, 0, math.pi)

quatIdentity( ) →

Identity quaternion (`0, 0, 0, 1`).

examples

local qx, qy, qz, qw = Transform.quatIdentity()

euler(qx: number, qy: number, qz: number, qw: number) →

Convert quaternion to euler angles (yaw, pitch, roll) in radians.

argtypedescription
qxnumberQuaternion x.
qynumberQuaternion y.
qznumberQuaternion z.
qwnumberQuaternion w.

examples

local yaw, pitch, roll = Transform.euler(0, 0, 0, 1)

orbit(centerX: number, centerY: number, centerZ: number, radius: number, height: number, angle: number) →

Position + rotation for orbiting around a center point. Returns the world position followed by the orientation that faces the center.

argtypedescription
centerXnumberCenter x.
centerYnumberCenter y.
centerZnumberCenter z.
radiusnumberHorizontal distance from the center.
heightnumberVertical offset from `centerY`.
anglenumberOrbital angle in radians.

examples

local x, y, z, qx, qy, qz, qw = Transform.orbit(0, 1, 0, 5, 2, t)

lerp(ax: number, ay: number, az: number, bx: number, by: number, bz: number, t: number) →

Linearly interpolate between two positions.

argtypedescription
axnumberStart x.
aynumberStart y.
aznumberStart z.
bxnumberEnd x.
bynumberEnd y.
bznumberEnd z.
tnumberInterpolation factor `[0, 1]`.

examples

local x, y, z = Transform.lerp(0, 0, 0, 1, 1, 1, 0.5)

lerp1(a: number, b: number, t: number) → number

Linearly interpolate two scalars.

argtypedescription
anumberStart value.
bnumberEnd value.
tnumberInterpolation factor `[0, 1]`.

examples

local v = Transform.lerp1(0, 10, 0.5)

normalizeAngle(a: number) → number

Normalize an angle into `[-pi, pi]`.

argtypedescription
anumberThe angle in radians.

examples

local a = Transform.normalizeAngle(3 * math.pi)

lerpAngle(a: number, b: number, t: number) → number

Lerp between two angles via the shortest arc; returns a value in `[-pi, pi]`.

argtypedescription
anumberStart angle in radians.
bnumberEnd angle in radians.
tnumberInterpolation factor `[0, 1]`.

examples

local a = Transform.lerpAngle(0, math.pi, 0.5)

slerp(ax: number, ay: number, az: number, aw: number, bx: number, by: number, bz: number, bw: number, t: number) →

Spherical linear interpolation between two quaternions. Picks the shortest path (flips sign if dot < 0). Falls back to lerp+normalize when the two quats are very close (avoids div-by-zero on near-parallel inputs).

argtypedescription
axnumberStart quaternion x.
aynumberStart quaternion y.
aznumberStart quaternion z.
awnumberStart quaternion w.
bxnumberEnd quaternion x.
bynumberEnd quaternion y.
bznumberEnd quaternion z.
bwnumberEnd quaternion w.
tnumberInterpolation factor `[0, 1]`.

examples

local qx, qy, qz, qw = Transform.slerp(0, 0, 0, 1, 1, 0, 0, 0, 0.5)

quatMul(ax: number, ay: number, az: number, aw: number, bx: number, by: number, bz: number, bw: number) →

Quaternion multiplication: returns `qa * qb` (composition: rotate by `qb` then `qa`).

argtypedescription
axnumberLeft quat x.
aynumberLeft quat y.
aznumberLeft quat z.
awnumberLeft quat w.
bxnumberRight quat x.
bynumberRight quat y.
bznumberRight quat z.
bwnumberRight quat w.

examples

local qx, qy, qz, qw = Transform.quatMul(ax, ay, az, aw, bx, by, bz, bw)

quatInverse(qx: number, qy: number, qz: number, qw: number) →

Quaternion inverse. Equal to the conjugate for unit quaternions.

argtypedescription
qxnumberQuaternion x.
qynumberQuaternion y.
qznumberQuaternion z.
qwnumberQuaternion w.

examples

local ix, iy, iz, iw = Transform.quatInverse(qx, qy, qz, qw)

quatRotateVec(qx: number, qy: number, qz: number, qw: number, vx: number, vy: number, vz: number) →

Rotate a 3-vector by a quaternion.

argtypedescription
qxnumberQuaternion x.
qynumberQuaternion y.
qznumberQuaternion z.
qwnumberQuaternion w.
vxnumberVector x.
vynumberVector y.
vznumberVector z.

examples

local rx, ry, rz = Transform.quatRotateVec(qx, qy, qz, qw, 1, 0, 0)

eulerToQuat(yaw: number, pitch: number?, roll: number?) →

Identity-aware overload of euler-to-quaternion. Uses the negative-yaw convention shared with `quatFromYaw`, `quatFromYawPitch`, `lookAtQuat`, and `T.euler` extraction — so `T.euler(T.eulerToQuat(y, p, r))` returns `(y, p, r)`. Order is yaw (Y) then pitch (X) then roll (Z).

argtypedescription
yawnumberY-axis rotation in radians.
pitchnumber?X-axis rotation in radians. Defaults to 0.
rollnumber?Z-axis rotation in radians. Defaults to 0.

examples

local qx, qy, qz, qw = Transform.eulerToQuat(math.pi / 2)

quatToEuler(qx: number, qy: number, qz: number, qw: number) →

Convert quaternion to `(yaw, pitch, roll)`. Alias of `euler` with the explicit name so callers don't have to remember the order.

argtypedescription
qxnumberQuaternion x.
qynumberQuaternion y.
qznumberQuaternion z.
qwnumberQuaternion w.

examples

local yaw, pitch, roll = Transform.quatToEuler(qx, qy, qz, qw)

worldToLocal(px: number, py: number, pz: number, pqx: number, pqy: number, pqz: number, pqw: number, wx: number, wy: number, wz: number) →

Transform a world-space position into a parent's local space.

argtypedescription
pxnumberParent position x.
pynumberParent position y.
pznumberParent position z.
pqxnumberParent rotation x.
pqynumberParent rotation y.
pqznumberParent rotation z.
pqwnumberParent rotation w.
wxnumberWorld x.
wynumberWorld y.
wznumberWorld z.

examples

local lx, ly, lz = Transform.worldToLocal(px, py, pz, pqx, pqy, pqz, pqw, wx, wy, wz)

localToWorld(px: number, py: number, pz: number, pqx: number, pqy: number, pqz: number, pqw: number, lx: number, ly: number, lz: number) →

Transform a local-space position into world space using a parent pose.

argtypedescription
pxnumberParent position x.
pynumberParent position y.
pznumberParent position z.
pqxnumberParent rotation x.
pqynumberParent rotation y.
pqznumberParent rotation z.
pqwnumberParent rotation w.
lxnumberLocal x.
lynumberLocal y.
lznumberLocal z.

examples

local wx, wy, wz = Transform.localToWorld(px, py, pz, pqx, pqy, pqz, pqw, lx, ly, lz)

readVec3(value: Vec3Input, label: string?) →

Normalize a vector a caller wrote to a plain `{ x, y, z }` array. Accepts a positional array `{1, 2, 3}`, a keyed table `{x =, y =, z =}`, or a live vec handle. Missing components read as 0. Raises when the value is not a vector; `label` names the caller in that error.

argtypedescription
valueVec3InputThe vector to normalize.
labelstring?Name reported in the error when the value is not a vector. Defaults to "Transform".

examples

local v = Transform.readVec3({ x = 1, y = 2, z = 3 })

quaternionFrom(rotation: any, label: string) → void

Internal: the one reading of a rotation a caller wrote. Returns the canonical `{ qx, qy, qz, qw }`, or nil and the message describing what arrived. Where the value is one of the two shapes a quaternion helper produces — the four components of a multi-return, or the whole table of a single-return — the message names the call that hands it back that way and the packing the value goes in as, because the value itself is correct and only its packing is wrong. The label names the surface that read it, which is an assignment target at one call site and a function at the next, so the packing is shown on its own rather than written into an assignment.

argtypedescription
rotationany
labelstring

tryQuaternion(rotation: any, label: string?) →

Read a rotation a caller wrote WITHOUT raising: returns the canonical `{ qx, qy, qz, qw }`, or nil and the message describing what arrived. The forms are the `RotationInput` union — a quaternion (`{x,y,z,w}` or `{x=,y=,z=,w=}`) or euler DEGREES (`{pitch,yaw,roll}` or `{pitch=,yaw=,roll=}`). Takes any value because reporting on a value that is none of those forms is the whole job; a setter built on this raises the returned message itself, so the error points at the line that wrote the value rather than at the reading.

argtypedescription
rotationanyThe value to read as a rotation.
labelstring?Name reported in the message. Defaults to "Transform".

examples

local q, why = Transform.tryQuaternion(value, "myTool")

toQuaternion(rotation: any, label: string?) →

Normalize a rotation a caller wrote to a `{ qx, qy, qz, qw }` quaternion. Accepts a quaternion (`{x,y,z,w}` or `{x=,y=,z=,w=}`) or euler DEGREES (`{pitch,yaw,roll}` or `{pitch=,yaw=,roll=}`), so one call site takes whichever form the caller finds natural. This is the reading every rotation-taking surface in the engine shares, so a quaternion and euler degrees mean the same thing at all of them. Raises when the value matches no form; `label` names the caller in that error, and a value that is one of the shapes a quaternion helper returns is named as such along with the packing it goes in as.

argtypedescription
rotationanyThe rotation to normalize, in any form of the `RotationInput` union.
labelstring?Name reported in the error when the value is not a rotation. Defaults to "Transform".

examples

local q = Transform.toQuaternion({ pitch = 0, yaw = 90, roll = 0 })

snapVec3(v: { number }, step: number | Vec3Input) →

Quantize each component of a vector to the nearest multiple of `step` — a number for uniform steps, or a vector for per-axis steps. A step of 0 on an axis leaves that axis at its exact value.

argtypedescription
v{ number }The vector to quantize, as `{ x, y, z }`.
stepnumber | Vec3InputUniform step size, or a per-axis vector of step sizes.

examples

local v = Transform.snapVec3({ 1.4, 2.6, -0.4 }, 1)

q(value: number, s: number) → number

argtypedescription
valuenumber
snumber

add(ax: number, ay: number, az: number, bx: number, by: number, bz: number) →

Component-wise vec3 addition.

argtypedescription
axnumberFirst vector x.
aynumberFirst vector y.
aznumberFirst vector z.
bxnumberSecond vector x.
bynumberSecond vector y.
bznumberSecond vector z.

examples

local x, y, z = Transform.vec.add(1, 2, 3, 4, 5, 6)

sub(ax: number, ay: number, az: number, bx: number, by: number, bz: number) →

Component-wise vec3 subtraction (`a - b`).

argtypedescription
axnumberFirst vector x.
aynumberFirst vector y.
aznumberFirst vector z.
bxnumberSecond vector x.
bynumberSecond vector y.
bznumberSecond vector z.

examples

local x, y, z = Transform.vec.sub(4, 5, 6, 1, 2, 3)

scale(x: number, y: number, z: number, s: number) →

Component-wise scalar multiplication of a vec3.

argtypedescription
xnumberVector x.
ynumberVector y.
znumberVector z.
snumberScalar factor.

examples

local x, y, z = Transform.vec.scale(1, 2, 3, 2)

dot(ax: number, ay: number, az: number, bx: number, by: number, bz: number) → number

Dot product of two vec3s.

argtypedescription
axnumberFirst vector x.
aynumberFirst vector y.
aznumberFirst vector z.
bxnumberSecond vector x.
bynumberSecond vector y.
bznumberSecond vector z.

examples

local d = Transform.vec.dot(1, 0, 0, 0, 1, 0)

cross(ax: number, ay: number, az: number, bx: number, by: number, bz: number) →

Cross product `a x b`.

argtypedescription
axnumberFirst vector x.
aynumberFirst vector y.
aznumberFirst vector z.
bxnumberSecond vector x.
bynumberSecond vector y.
bznumberSecond vector z.

examples

local cx, cy, cz = Transform.vec.cross(1, 0, 0, 0, 1, 0)

length(x: number, y: number, z: number) → number

Euclidean length of a vec3.

argtypedescription
xnumberVector x.
ynumberVector y.
znumberVector z.

examples

local len = Transform.vec.length(1, 2, 3)

normalize(x: number, y: number, z: number) →

Normalize a vec3. Returns zeros when the input is degenerate (length < 1e-8).

argtypedescription
xnumberVector x.
ynumberVector y.
znumberVector z.

examples

local nx, ny, nz = Transform.vec.normalize(0, 5, 0)
⌬ Types
Vec3 = { x: number, y: number, z: number }Vec3Input = { number } | { x: number, y: number, z: number }RotationInput

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

3items
·
other · born here
▤file
▲ 0↑ born
backing path · modules/transform.module

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported. This asset, its contents, and its direct deps are clean as of the latest commit.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.