31. From Lua to Luau
So far the code ran in the terminal with lua. From here
on it runs inside Roblox Studio, the editor Roblox uses
to build experiences. Studio runs its own flavour of Lua, called
Luau. This chapter covers what stays the same, what
changes, and where the new ideas come from.
Luau vs Lua: what is the same
Almost everything you have learned carries over to Luau unchanged:
- Types: nil, boolean, number, string, table, function.
- All the operators: arithmetic, comparison, logical,
..,#. local,if,elseif,else,end,while,repeat,for,break,return.- Functions, multiple return values, methods, the
selfparameter, the colon syntax. - Tables as lists and dictionaries,
ipairs,pairs,table.insert,table.remove,#. - Metatables,
__index, the.new/:methodclass pattern. - Most of the
stringlibrary (string.format,string.upper,string.gmatch, etc.) and themathlibrary.
If you can write the Part 6 inventory project in plain Lua, that same
code (minus the io.* calls and terminal print)
drops straight into a Luau script.
What is different
Three things change in Roblox.
1. Where the program runs
A terminal program has one entry point: the file you handed to
lua. A Roblox experience is a tree of
Instances — Parts, Scripts, Folders, Models — with code
living inside Script and LocalScript objects
on that tree. There is no main.lua. Each script runs on its
own once its Instance exists.
There are three kinds of script object:
Script— runs on the server; can change the world for everyone.LocalScript— runs on a single player's computer. Used for UI, camera, sound — anything local to one player.ModuleScript— like a plain Lua module from chapter 25. Returns a table; other scriptsrequireit.
The book's mini-project uses one Script (server) and
nothing else.
2. Built-in objects
Luau in Roblox gives you names plain Lua does not have:
| Name | What it is |
|---|---|
game |
The root of the whole experience. |
workspace |
Shortcut for game.Workspace. Holds the world. |
game.Players |
The list of currently connected players. |
script |
The script you are inside (your own object). |
Instance.new(class) |
Create a new Instance of the given class. |
task.wait(seconds) |
Pause this script for the given duration. |
task.spawn(fn) |
Run fn in a new coroutine. |
You create objects with Instance.new:
local part = Instance.new("Part")
part.Name = "Coin"
part.Size = Vector3.new(2, 0.2, 2)
part.Position = Vector3.new(0, 5, 0)
part.BrickColor = BrickColor.new("Bright yellow")
part.Anchored = true
part.Parent = workspaceLine one creates a Part. The middle lines set its
properties. The last places it inside
workspace — which is what makes it appear in the world.
Vector3.new(x, y, z) and
BrickColor.new(name) are factory functions for Roblox value
types. Like Instance.new, they just return a value.
3. Events
In a terminal program, things happen because you ask: you call a function, it runs. In a game, they happen because the world changes: a button is pressed, a part is touched, a player joins. Roblox exposes these moments as events. Connect a function to an event, and it runs whenever the event fires.
local part = workspace.Coin
part.Touched:Connect(function(other)
print("Something touched the coin: " .. other.Name)
end)What is happening:
part.Touchedis an event on the Part.:Connect(...)registers a function to run when it fires.- The function takes one argument — the other Part that touched it.
- The script keeps running afterward (no loop needed); whenever a Part
bumps into
part, the function runs.
This is the part of Luau most unlike plain Lua. Once it clicks, most of Roblox programming is just write a function; connect it to the right event.
Side-by-side: same logic, two flavours
A function that prints a greeting, twice:
-- Plain Lua (terminal)
local function greet(name)
print("Hello, " .. name)
end
greet("Keiko")
greet("Roblox")The same function in a Roblox Script, called when a player joins:
-- Roblox Luau (Script in ServerScriptService)
local Players = game:GetService("Players")
local function greet(name)
print("Hello, " .. name)
end
Players.PlayerAdded:Connect(function(player)
greet(player.Name)
end)The greet function is identical. Only the
trigger changed: in the terminal you called greet yourself;
in Roblox the engine calls it each time a player joins.
game:GetService("Players") is the idiomatic way to reach
the Players service. game.Players works too, but
:GetService is the form Roblox docs use, and it is safer if
a service has not loaded yet.
Installing Roblox Studio
To run anything in Part 7, you need Roblox Studio, a free download:
- Go to https://create.roblox.com/.
- Sign in with the same account you use to play Roblox.
- Click Start Creating — Studio downloads and installs.
- Open Studio and pick the Baseplate template.
A flat grey plate opens. The left panel is the
Explorer (the tree of Instances), the right panel shows
the Properties of the selected item, and the bottom is
the Output panel — where print ends
up.
The next four chapters dig into Studio — Instances, events, services, leaderstats — then the Part 7 mini-projects pull them together into real, playable scenes.
Homework
Most homework so far ran in the terminal. The next few only run with Studio open, so treat them as pen-and-paper exercises: write the code, then check the solutions page.
Problem 1 — Spot the difference
Open exercises/31/homework/01-spot-the-difference.lua.
It holds two snippets separated by a comment (one plain Lua, one Roblox
Luau). List at least three differences in a multi-line comment at the
bottom of the file.
Problem 2 — Make a Part appear
Open exercises/31/homework/02-make-a-part.lua. Write a
script (no function needed) that creates a red Part of size
4 x 1 x 4 at position 0, 10, 0, anchored and
parented to workspace. In Studio this would go inside a
Script in ServerScriptService.
Problem 3 — Wire up Touched
Open exercises/31/homework/03-wire-up-touched.lua. Given
a variable part that refers to a Part, write the snippet
that connects a function to the Part's Touched event. It
should print <otherName> touched the part, where
<otherName> is the Name of the other
Part.
Challenge — Blinking part
Open exercises/31/homework/04-blink.lua. Inside a
while true do ... end loop, flip a Part's
BrickColor between two colours every second using
task.wait(1). Print a line on each change so the Output
panel shows progress.
Stuck or finished? Open the homework solutions page.