Scripting overview
Studz games are scripted in Lua 5.4 with an API that grew out of Roblox's. If you have written Roblox scripts, most of what you know carries over, and the Roblox spellings still run (with a warning that names the Studz one). This page covers what you need before writing your first script: where scripts run, what the language is, and the rules every script lives by.
The language
Scripts are plain Lua 5.4, not Luau. These Luau conveniences do not exist:
- compound assignment (
x += 1; writex = x + 1) continue- type annotations
- string interpolation (use
..orstring.format)
Some Luau library functions are provided anyway: math.clamp, math.sign, math.round, math.lerp, table.find, table.clone, table.clear, typeof, task.* and tick. See Globals and services.
How the API is named
The API has one official spelling for everything, in PascalCase.
| Kind of name | Examples | Notes |
|---|---|---|
| Studz names | inst:FindChild, inst:Children(), signal:On, Players:List(), humanoid.Speed, game:Service("Players"), track.Finished | The spellings the docs use. They are shorter, and read the same everywhere. |
| Studz additions | part.PlayerTouched, part.Clicked, Instance.Create, inst:GetChild, character.Animator, remote:Listen | They remove common Roblox traps. See Roblox compatibility. |
| Roblox spellings | FindFirstChild, :Connect, GetPlayers, WalkSpeed, game:GetService | Deprecated. They still work, print one warning that names the Studz spelling, and will be removed in a later release. |
| Older spellings | on_touch, world:spawn, part.pos, findFirstChild | Deprecated too, with the same warning. |
A few names are shared with Roblox on purpose and are not deprecated: Instance.new, Destroy, Clone, IsA, Touched, TweenService:Create, Raycast, CFrame, Vector3, Color3 and the other value types.
Where scripts run
There are three kinds of script. Add them from the Script ribbon or the Explorer in Polycarbonate.
| Class | Runs on | Use it for |
|---|---|---|
Script | The game server | Game rules, physics, awards, saving data, anything that must be trusted. |
LocalScript | Each player's computer | That player's interface, input, camera and sounds. |
ModuleScript | Whoever calls require on it | Code shared between scripts. |
What the server shows to everyone
Everything a server Script does to the world is replicated, so every player sees it:
- Parts it creates, moves, recolours, resizes, makes transparent or non-collidable, or destroys. This includes unanchored parts that physics moves.
- The
Lightingservice (time of day, brightness). - GUI made with
Instance.new("TextLabel"),"TextButton"or"Frame"in a server script. All players see it, and a click on a button runs its handler on the server. - Sounds started with
Sound.play, or by setting aSoundobject'sPlaying, which play on every client.
Positions a script assigns are authoritative. Setting part.Position on an unanchored part teleports its physics body there. The source of a server Script is never sent to players.
What fires on the server
Touched, TouchEnded and PlayerTouched fire on the server with the touching player's character. Clicking a part runs its ClickDetector.MouseClick or part.Clicked handler for that player, provided they are within 64 studs.
Testing
Use Test > Local Server in Polycarbonate to run the server and a player separately, the way the live game runs. LocalScripts and remotes only work there. The single-process Play (F5) playtest does not run them. See Client and server.
Errors that help
Studz turns many silent mistakes into errors that say what to fix.
Errors name the script
Scripts load under their own name, so an error in the Output window reads DoorOpener:14: attempt to .... Unnamed scripts appear as Script#<id>. A required module reports under the module's name.
Unknown members are errors
A member the object does not have raises an error with a suggestion. This is checked for each kind of object (parts, lights, value objects, sounds, GUI elements, humanoids):
part.Transparancy = 1
-- 'Transparancy' is not a valid property of Part (did you mean 'Transparency'?)
print(part.Health)
-- 'Health' is not a valid member of Part
Containers, services and players are open ended instead: workspace.Foo is nil when nothing is called Foo.
Wrong types are errors
part.Transparency = "high"
-- Part.Transparency expects a number, got string
Numbers and vectors must be finite. NaN and infinity are refused, so one bad calculation cannot corrupt a position.
Other checks
| You write | What happens |
|---|---|
Assign to a read-only member (ClassName, an event) | Error. |
game:Service("Playrs") | Error: 'Playrs' is not a service (did you mean 'Players'?). |
Instance.new("Prt") (one edit from a real class) | Error with a suggestion. |
Instance.new("Seat") (a class Studz does not have) | Makes a plain Part and warns once. |
part.Parent = part | Error (parenting loop). |
A Roblox service Studz lacks (MarketplaceService, TeleportService, Teams, ...) | Returns an inert object and warns once, so scripts that only declare it still run. |
A Roblox-only property (Archivable, Locked, Massless, CanTouch, Reflectance, BrickColor, ...) | Setting does nothing, reading gives nil, and a warning says so once. |
Limits
Game servers share a machine, so everything a script can allocate has a ceiling. Hitting one raises an error in the script that did it. Nothing else is affected.
| What | Limit |
|---|---|
| Time per event, frame or step | 0.25 s (5 s while a script starts): script exceeded its time limit. Applies to every coroutine, including task.spawn, event handlers and coroutine.wrap. |
| Lua memory | 64 MB per game server and 48 MB per player's client. All scripts of one server or client share the budget. |
| Objects in a place | 20,000. Cloning refuses to go over it. |
| GUI elements alive at once | 500 |
| Handlers on one signal | 500. Call :Off() on handlers you no longer need. |
| Output kept | The last 2,000 lines. A single line is cut at 2,048 characters. |
| Data stores | 600 requests per minute per game server, 64 waiting at once. See Saving data. |
| Remote arguments | 4 levels deep, 64 entries, about 1 KB. Clients may make 60 remote calls per second. |
Sandbox
Scripts cannot reach the machine they run on. There is no io, no package, no dofile or loadfile, no debug, no binary chunks and no collectgarbage control. os offers only os.time, os.clock, os.date and os.difftime. HttpService cannot make web requests.
Where to go next
| If you want to... | Read |
|---|---|
| React to touches, clicks and timers | Events, signals and tasks |
| Create, find and change objects and parts | Instances and parts |
| Work with players, health and outfits | Players and characters |
| Send messages between server and client | Client and server |
| Save scores and progress | Saving data |
| Raycast, tween, light, play sounds | World, tweens and effects |
| Look up a global, service or helper | Globals and services |
| Copy a working script | Examples |
