Skip to main content

Vector3

3-component float vector. Used everywhere positions, sizes, velocities or world-space directions appear (entity.Position, :GetBonePosition, game.CameraPosition, BasePart.Size, etc.).

Static functions12 (1 constructor + 11 utilities)
Static constants5 (zero, one, xAxis, yAxis, zAxis)
Instance fieldsX, Y, Z, Magnitude, Unit
Instance methods11 (same set as static utilities, both call styles supported)
Operators+, -, *scalar, /scalar, unary -

Aliases. Most methods have two forms (PascalCase + lowercase): Vector3.Dot / Vector3.dot. Only new is single-form. See Overview / Naming convention.

== is identity-only. Vector3.new(1,2,3) == Vector3.new(1,2,3) returns false. The metatable's __eq does not implement value-equality. Use :FuzzyEq(other) for value comparison. The pre-allocated singletons (Vector3.zero, .one, .xAxis, .yAxis, .zAxis) are identity-equal to themselves: Vector3.zero == Vector3.zero is true, but Vector3.zero == Vector3.new(0, 0, 0) is false because new() always returns a fresh userdata.

Quick reference

Static Vector3.*

NameSignatureNotesStatus
new(x?, y?, z?) → Vector3construct from up to 3 numbers, missing args default to 0verified
zeroVector3 constant (0, 0, 0)identity for additionverified
oneVector3 constant (1, 1, 1)verified
xAxisVector3 constant (1, 0, 0)verified
yAxisVector3 constant (0, 1, 0)verified
zAxisVector3 constant (0, 0, 1)verified
Dot(a, b) → numberscalar dot productverified
Cross(a, b) → Vector3right-handed cross productverified
Lerp(a, b, t) → Vector3component-wise linear interpolationverified
Floor(v) → Vector3component-wise math.floorverified
Ceil(v) → Vector3component-wise math.ceilverified
Abs(v) → Vector3component-wise math.absverified
Sign(v) → Vector3component-wise sign (-1, 0, +1)verified
Min(a, b) → Vector3component-wise minimumverified
Max(a, b) → Vector3component-wise maximumverified
Angle(a, b) → numberunsigned angle between vectors (radians)verified
FuzzyEq(a, b [, eps]) → boolepsilon-tolerant value equalityverified

Instance v.* and v:*

MemberTypeNotes
v.X, v.Y, v.Znumberthe three components
v.Magnitudenumbersqrt(X*X + Y*Y + Z*Z), recomputed each access
v.UnitVector3the same vector divided by Magnitude (zero vector returns NaN-equivalent, do not access on a zero vector)
v:Dot(other), :Cross, :Lerp, :Floor, :Ceil, :Abs, :Sign, :Min, :Max, :Angle, :FuzzyEqvariousmethod-call form, equivalent to the static call with v as first argument

new

Vector3.new(x?: number, y?: number, z?: number) → Vector3

Constructs a vector. Missing arguments default to 0. Verified return shapes:

CallResult
Vector3.new()(0, 0, 0)
Vector3.new(1)(1, 0, 0)
Vector3.new(1, 2)(1, 2, 0)
Vector3.new(1, 2, 3)(1, 2, 3)
Vector3.new(1, 2, 3, 4)(1, 2, 3) (extra args silently ignored)
Vector3.new(nil)(0, 0, 0) (nil treated as 0)
Vector3.new("s")error: "bad argument #1 to '?' (number expected, got string)"
local up    = Vector3.new(0, 1, 0)
local point = Vector3.new(120.5, 30, -88.2)
print(point.X, point.Y, point.Z, point.Magnitude)

Constants

Vector3.zero   → (0, 0, 0)
Vector3.one → (1, 1, 1)
Vector3.xAxis → (1, 0, 0)
Vector3.yAxis → (0, 1, 0)
Vector3.zAxis → (0, 0, 1)

These are pre-allocated immutable userdata. Use them instead of constructing fresh Vector3.new(0, 0, 0) on hot paths.

local pos = entity.GetLocalPlayer().Position
if pos == Vector3.zero then

end
== is identity-only

The metatable does not implement value equality. Vector3.new(1, 2, 3) == Vector3.new(1, 2, 3) returns false. Use :FuzzyEq for value comparison.


Operators

OpBehaviorVerified
a + bcomponent-wise add(1,2,3) + (4,5,6) = (5,7,9)
a - bcomponent-wise sub(1,2,3) - (4,5,6) = (-3,-3,-3)
a * kscalar multiply(1,2,3) * 2 = (2,4,6)
k * ascalar multiply (right)2 * (1,2,3) = (2,4,6)
a / kscalar divide(1,2,3) / 2 = (0.5, 1, 1.5)
-aunary negate-(1,2,3) = (-1,-2,-3)
tostring(a)"%.6f, %.6f, %.6f"(1,2,3) → "1.000000, 2.000000, 3.000000"
Vector3 * Vector3 silently returns zero

Vector3.new(1,2,3) * Vector3.new(4,5,6) returns (0, 0, 0), not the component-wise product (4, 10, 18). The metatable's __mul does not support vector-times-vector. Use Vector3.Dot(a, b) for scalar product or implement component multiplication manually:

local function v_mul(a, b) return Vector3.new(a.X*b.X, a.Y*b.Y, a.Z*b.Z) end

Dot

Vector3.Dot(a: Vector3, b: Vector3) → number
a:Dot(b) → number

Standard dot product a.X*b.X + a.Y*b.Y + a.Z*b.Z. Verified: Vector3.new(1,2,3):Dot(Vector3.new(4,5,6)) returns 32.

local fwd  = (target_pos - my_pos).Unit
local face = camera_lookvec
local dot = fwd:Dot(face)
if dot > 0.95 then

Cross

Vector3.Cross(a: Vector3, b: Vector3) → Vector3
a:Cross(b) → Vector3

Right-handed cross product. Verified: Vector3.new(1,2,3):Cross(Vector3.new(4,5,6)) returns (-3, 6, -3).

local right = up:Cross(forward)

Lerp

Vector3.Lerp(a: Vector3, b: Vector3, t: number) → Vector3
a:Lerp(b, t) → Vector3

Linear interpolation a + (b - a) * t. t = 0 returns a, t = 1 returns b, no clamping for values outside [0, 1].

Verified: Vector3.new(1,2,3):Lerp(Vector3.new(4,5,6), 0.5) returns (2.5, 3.5, 4.5).

local mid = start_pos:Lerp(end_pos, 0.5)

Floor

Vector3.Floor(v: Vector3) → Vector3
v:Floor() → Vector3

Component-wise math.floor. Verified: Vector3.new(-1.7, 2.3, -3.9):Floor() returns (-2, 2, -4).


Ceil

Vector3.Ceil(v: Vector3) → Vector3
v:Ceil() → Vector3

Component-wise math.ceil. Verified: Vector3.new(-1.7, 2.3, -3.9):Ceil() returns (-1, 3, -3).


Abs

Vector3.Abs(v: Vector3) → Vector3
v:Abs() → Vector3

Component-wise math.abs. Verified: Vector3.new(-1.7, 2.3, -3.9):Abs() returns (1.7, 2.3, 3.9).


Sign

Vector3.Sign(v: Vector3) → Vector3
v:Sign() → Vector3

Component-wise sign function: returns -1, 0, or +1 for each axis. Verified: Vector3.new(-1.7, 0, 3.9):Sign() returns (-1, 0, 1).


Min / Max

Vector3.Min(a: Vector3, b: Vector3) → Vector3
Vector3.Max(a: Vector3, b: Vector3) → Vector3
a:Min(b) / a:Max(b)

Component-wise minimum / maximum. Useful for AABB clipping.

local lo = Vector3.Min(corner1, corner2)
local hi = Vector3.Max(corner1, corner2)
local size = hi - lo

Angle

Vector3.Angle(a: Vector3, b: Vector3) → number
a:Angle(b) → number

Returns the unsigned angle in radians between two vectors. Verified: Vector3.xAxis:Angle(Vector3.yAxis) returns 1.5707963705063 (= π/2).

local angle_deg = math.deg(my_dir:Angle(target_dir))

FuzzyEq

Vector3.FuzzyEq(a: Vector3, b: Vector3 [, eps: number]) → bool
a:FuzzyEq(b)

Epsilon-tolerant value equality. Use this instead of ==, which is identity-only. Verified: a:FuzzyEq(a) returns true.

if v:FuzzyEq(Vector3.zero) then

end

Patterns

Distance between two world points

local function dist(a, b) return (a - b).Magnitude end

local me = entity.GetLocalPlayer():GetBonePosition("HumanoidRootPart")
for _, p in ipairs(entity.GetPlayers(true)) do
local their = p:GetBonePosition("HumanoidRootPart")
print(p.Name, dist(me, their))
end

Aim-direction angle to target

local function angle_to(target_pos)
local cam = game.CameraPosition
local fwd = (game.GetService("Workspace").CurrentCamera and
game.GetService("Workspace").CurrentCamera.CFrame.LookVector)
or Vector3.zAxis
local to_tgt = (target_pos - cam).Unit
return fwd:Angle(to_tgt)
end

Snap a position onto a 1-stud grid

local function snap(v) return v:Floor() end

Component-wise multiply (operator does not work)

local function v_scale(a, s) return Vector3.new(a.X*s.X, a.Y*s.Y, a.Z*s.Z) end

Test "did the player move this frame"

local last_pos = Vector3.zero
cheat.register("onUpdate", function()
local pos = entity.GetLocalPlayer():GetBonePosition("HumanoidRootPart")
if not pos:FuzzyEq(last_pos) then

end
last_pos = pos
end)