How to write your first script
Luduvo drives all gameplay behavior using scripts written in Luau, an embeddable scripting language derived from Lua 5.1 that adds gradual typing, an optimizing compiler, and a sandbox.
Rather than running as detached external programs, scripts in Luduvo act as components bound directly to entities within the place hierarchy. As soon as an entity enters the active simulation world, the engine kicks off its attached script.
The execution model#
Scripts execute within an isolated VM and an instruction budget.
Sandboxed Luau environment#
Every script runs inside a sandbox. Scripts cannot open files on the machine running them, and cannot reach the network on their own. Everything a script does to the game world goes through the Instance hierarchy and the API services the engine exposes.
The 1,000,000 instruction budget#
The simulation tick runs at a fixed 60 Hz, allocating roughly 16.6 milliseconds per
frame to update physics, execute scripts, step animations, and run replication passes.
An unyielding loop (such as while true do end) stalls the whole frame: nothing else
in the game runs while it spins.
To prevent a rogue script from locking up the game, the engine enforces a strict instruction budget of 1,000,000 virtual machine instructions per execution step. If a callback or top-level block executes more than 1,000,000 instructions in a single invocation without returning control to the engine, the runtime forcibly halts execution with an error:
script exceeded its instruction budgetThe budget is the same on every machine, so one buggy script can never hang the game.
Globals: self and handles#
Whenever a script executes, the engine injects references into the script’s global scope:
self: A direct reference to the specific Instance hosting the script. Throughself, inspect and modify the entity’s properties (likeself.Positionorself.Color) and call its member methods.handles: A lookup table that maps editor-assigned handle names straight to their target instances. Instead of searching the hierarchy for a key object,handles.Doororhandles.MainLightreturns it directly.
Alongside self and handles, the global scope provides standard Luau runtime
libraries (math, table, string, vector, buffer), logging utilities (print, warn, error), and the root game service singleton.
Attaching a script#
To attach a script to an entity:
- In the 3D Viewport or Hierarchy Panel, right-click any instance.
- Select Add Component > Script.
- Double-click the newly created script to open it inside the editor’s code tab.
Writing and running script code#
To inspect entity properties and change part color:
-- Read properties from the bound instance via 'self'print("Script initialized on instance:", self.Name)print("Initial position is:", self.Position)-- Modify instance stateself.Color = Color3.new(0.2, 0.6, 1.0)When clicking Play in the editor toolbar, the engine creates the entity and runs the script’s top level once. The output log displays the print statements, and in the viewport, the part turns light blue.
Client vs. server execution boundaries#
To maintain competitive integrity and prevent cheating, Luduvo enforces a strict client-server boundary. Where a script executes is determined entirely by its filename convention:
- Client scripts (
*.client.lua, e.g.,HUD.client.luaorCameraController.client.lua): These execute locally on each connected player’s machine. Use them to drive the local camera, render 2D user interfaces, play localized audio, and handle immediate input responsiveness. - Server scripts (any other script, such as
Door.luaorCombat.server.lua): These execute authoritatively on the central game server. The server owns the entire simulation world: it simulates rigid-body physics, tracks player health and inventories, and handles entity spawning.
The table below details how these capabilities break down across the network divide:
| Capability | Server script | Client script |
|---|---|---|
Physics forces (ApplyForce, SetLinearVelocity) | Allowed | Error: Server only |
Lifecycle destruction (instance:Destroy()) | Allowed | Error: Server only |
State mutations (Anchored, Health, Material) | Read and Write | Read only (writes error) |
Local player inputs & camera (InputMove, ViewSource) | Not applicable | Read and Write |
GUI events (Activated, Hovered, DragMoved) | Not fired | Fired |
Because the server retains ultimate authority, client scripts can never mutate global world state directly. Whenever a client script needs the server to carry out an action (such as opening a treasure chest or equipping a weapon), stream data across the network wire using EventTables. For complete details on how the engine synchronizes state changes, see Server Authority and Replication.