Optionalx: numberOptionaly: numberOptionalz: numberOptionalonOptional change hook invoked at the end of every mutator. Engine-internal: owners install it, user code normally leaves it unset. It is intentionally not copied by Vector3.copy or Vector3.clone.
Allocates a new vector with the same components. The clone has no change hook. This is the only allocating method on the type (§7b).
Copies the components of v into this vector. The change hook is not copied.
Right-handed cross product, mutating this vector to this × v (this
vector is the left operand). Reading the result requires the temporaries
below because two components are overwritten before the third is read.
Aliasing-safe: v may be this. Both operands are read into scalars
first, not just the receiver — reading v live while writing this is
the whole bug when the two are the same object, and a.cross(a) must be
the zero vector.
Component-wise approximate equality: true when every component differs by
at most epsilon (absolute tolerance).
Optionalepsilon: numberEuclidean length.
Squared length. Preferred over Vector3.length for comparisons.
Moves this vector toward target by the factor t, mutating this vector.
t = 0 leaves it unchanged, t = 1 makes it equal to target. Values
outside [0, 1] extrapolate; no clamping is applied.
Scales this vector to unit length.
Zero-length behaviour (defined here): normalizing a zero-length vector
leaves it at (0, 0, 0) rather than producing NaN or throwing — there is
no meaningful direction to pick, and poisoning a hot path with NaN is
worse than a no-op. The change hook still fires.
Range behaviour — the guard below tests the squared length, so three ranges leave this vector non-unit and none of them reports an error (measured from a consumer seat, dogfood cycle 10):
0 — every
component below about 1.57e-162 — takes the zero-length branch and is
left unchanged, non-unit. Just above that bound the square is denormal
and has lost most of its mantissa, so the result can be as far off as
0.707 in length.1.3407807929942597e+154 squares
to Infinity, so 1 / Math.sqrt(lengthSquared) is 0 and every
component is written as 0: a large finite vector normalizes to the
zero vector.NaN in that slot and
0 in the others. A NaN component leaves the vector untouched,
because NaN > 0 is false. The zero-length promise above covers a zero
input, not a non-finite one — normalize() does produce NaN here.Nothing clamps and nothing throws (§85, §61): a hot path that can see such magnitudes scales into range before normalizing.
Multiplies every component by the scalar s.
Sets all three components.
Mutable three-component vector (§7b) — the primary vector type of the engine (§7 transforms, §11 motion, §20+ physics). The world is right-handed with +Y up in both 2D and 3D (§7a).
Allocation policy (§7b, plan D7): instance methods that produce a "this-shaped" result mutate in place and return
this; only Vector3.clone allocates. Scalar queries (dot,lengthSq,length) andequalsApproxnever allocate and never mutate.Change notification (plan D3): every mutator invokes Vector3.onChanged after writing. Direct field writes (
v.x = 1) bypass the hook by design.