‹ Back to Tutorials Beginner

Roblox Luau Tutorial: Understanding Vector3

Learn what a Vector3 actually represents, how Roblox's 3D coordinate system is laid out, and how to add, scale, measure, and combine vectors to move objects and calculate distances and directions in your own scripts.


1. What is a Vector3?

A Vector3 is just three numbers — X, Y, and Z — bundled together. Roblox uses it anywhere a value needs three dimensions:

Roblox's Axis Convention

Roblox is a right-handed, Y-up coordinate system. That means:

        +Y (Up)
         |
         |
         |______ +X (Right / East)
        /
       /
    +Z (Toward the default camera / South)

2. Setting Up the Scene in Roblox Studio

  1. Insert a Part:
    • Press Ctrl + I (Windows) or Cmd + I (Mac) to open the Insert Object menu.
    • Search for Part and select it.
  2. Insert a Script inside the Part:
    • With the Part selected, press Ctrl + I / Cmd + I again.
    • Search for Script and place it inside the Part.

3. Creating Vector3 Values

Vector3.new(x, y, z) builds one from three numbers. Every argument defaults to 0 on its own, so you can omit trailing ones:

local origin = Vector3.new()          -- (0, 0, 0)
local partial = Vector3.new(5, 10)    -- (5, 10, 0) - z defaults to 0
local full = Vector3.new(5, 10, -20)  -- (5, 10, -20)

Roblox also ships a handful of ready-made constants for the values you'll reach for constantly:

local origin = Vector3.zero    -- Vector3.new(0, 0, 0)
local up = Vector3.yAxis       -- Vector3.new(0, 1, 0)
local uniform = Vector3.one    -- Vector3.new(1, 1, 1)
local doubleSize = Vector3.one * 4  -- Vector3.new(4, 4, 4)

4. Using Vector3 for Position and Size

Position and Size are both plain Vector3 properties on a Part:

local part = script.Parent

-- Move the part to (10 studs right, 5 studs up, 0)
part.Position = Vector3.new(10, 5, 0)

-- Resize it to 4x2x4 studs (width, height, depth)
part.Size = Vector3.new(4, 2, 4)

Position is actually a shortcut - under the hood every Part's real transform is a CFrame (position and rotation together), and Position just reads/writes the position part of it. You'll meet CFrame in its own tutorial once you're comfortable here.


5. Vector3 Arithmetic - Moving and Combining Positions

Vector3 supports +, -, and scalar *//, and they do exactly what you'd hope:

local part = script.Parent

-- Move the part 5 studs straight up, relative to where it already is
part.Position = part.Position + Vector3.new(0, 5, 0)

-- Move it 3 studs back (toward +Z) and shrink the offset by half
local offset = Vector3.new(0, 0, 3) / 2
part.Position = part.Position + offset

-- The midpoint between two positions - just average them
local pointA = Vector3.new(0, 0, 0)
local pointB = Vector3.new(10, 0, 10)
local midpoint = (pointA + pointB) / 2

The key habit to build: current + offset moves relative to where you are. Setting part.Position = Vector3.new(0, 5, 0) outright teleports to that exact world position instead - both are useful, but they're not the same thing.


6. Distance and Direction - Magnitude and Unit

Subtracting two positions gives you a vector that points from one to the other. Its length (Magnitude) is the distance between them, and normalizing it (Unit) gives you a pure direction with a length of exactly 1:

local partA = workspace.PartA
local partB = workspace.PartB

local offset = partB.Position - partA.Position

local distance = offset.Magnitude          -- how far apart they are, in studs
local direction = offset.Unit               -- which way to travel to go from A to B

print(("PartB is %.1f studs from PartA"):format(distance))

-- Nudge PartA one stud closer to PartB
partA.Position = partA.Position + direction * 1

This direction * distance pattern (or a fraction of it, like direction * 1 above) is how you move something toward a target step by step, rather than jumping straight there.


7. Dot and Cross Products - What They're Actually For

These two look intimidating in math class, but each has one job you'll use constantly.

:Dot(other) returns a single number that tells you how aligned two directions are:

local facing = Vector3.new(0, 0, -1)          -- facing "forward" (-Z)
local toTarget = (target.Position - part.Position).Unit

local alignment = facing:Dot(toTarget)

if alignment > 0 then
    print("The target is roughly ahead")
else
    print("The target is roughly behind")
end

:Cross(other) returns a new vector that's perpendicular to both inputs - useful for finding a "sideways" or "up" direction from two other directions:

local forward = Vector3.new(0, 0, -1)
local up = Vector3.new(0, 1, 0)

local right = forward:Cross(up)   -- the direction 90° to both - "right" relative to forward/up

8. Smooth Movement with Lerp

:Lerp(goal, alpha) blends between two vectors. alpha is 0 to 1, where 0 gives you back the start, 1 gives you the goal, and anything in between gives you a point along the straight line connecting them:

local part = script.Parent
local startPosition = part.Position
local goalPosition = startPosition + Vector3.new(20, 0, 0)

for i = 0, 1, 0.05 do
    part.Position = startPosition:Lerp(goalPosition, i)
    task.wait(0.03)
end

Run that and the part glides smoothly from its start position to 20 studs away, instead of teleporting.


9. Putting It Together - Moving Toward a Target

This combines direction, distance, and a loop into one useful pattern: move toward a target every frame until you're close enough to stop.

local part = script.Parent
local target = workspace:WaitForChild("Target")
local speed = 8 -- studs per second
local stopDistance = 1

game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
    local offset = target.Position - part.Position
    local distance = offset.Magnitude

    if distance <= stopDistance then
        return -- close enough, stop moving
    end

    local direction = offset.Unit
    part.Position = part.Position + direction * speed * deltaTime
end)

deltaTime (the time since the last frame) keeps the movement speed consistent no matter how fast or slow the game is running - multiplying by it is what turns "studs per second" into "studs this frame."


10. Try It Yourself

The CFrame Viewer tool lets you type Vector3 expressions like the ones above and see them drawn live as arrows in 3D, with sliders on every number - a fast way to build real intuition before moving on to the CFrame tutorial.


11. Verification / Testing

  1. Insert a Part named Target somewhere else in Workspace (no script needed on it).
  2. Paste the Section 9 script into a Script inside your original Part.
  3. Click Run in Roblox Studio.
  4. Watch the Explorer/viewport:
    • The Part should glide smoothly toward Target and stop about 1 stud away, rather than snapping there instantly.
  5. Try the Section 6 distance snippet in the Command Bar (View > Command Bar) with two Parts selected to sanity-check the Magnitude/Unit numbers you're seeing.