Scripts in the editor
Gameplay is written in scripts, in Luau or AngelScript. Both see the same engine API; they differ in syntax. The examples in these pages show both: pick a language once and the tabs follow it.
Write a game’s scripts in one language. A game run uses one script language: the first script to load decides it, and scripts in the other language stay off (the Console says so).
Three kinds of script
Section titled “Three kinds of script”- Behavior: belongs to an entity, through its Script component. Most gameplay lives here: a coin that spins, a door that opens, a player that moves.
- Level: one per scene, for what concerns the whole scene: spawning, win conditions, timing.
Its class is always named
Level. - Game: one per game, running from start to quit, across scene changes: menus, lives,
scores, which level comes next. Its class is always named
Game.
Creating a script
Section titled “Creating a script”In the Assets panel, right-click and choose New, then Scripts, then the language and the kind: Luau Behavior, AngelScript Level and so on. The File menu has the same list, and opens the new script.
The new script is named NewBehavior (or NewLevel, NewGame): rename it in the Assets panel.
A behavior’s class takes its name from the asset’s name when it is created. The script’s file is
in the project’s Sources/ folder (.luau or .as); importing a .luau or .as file adds one
too.
A new behavior moves its entity slowly along X, to show that it runs (the starter’s comments are left out here):
NewBehavior = {}NewBehavior.__index = NewBehavior
function NewBehavior.new(entity) local self = setmetatable({}, NewBehavior) self.entity = entity self.speed = 1.0 return selfend
function NewBehavior:onStart() Log.info("NewBehavior started on " .. self.entity:name())end
function NewBehavior:onUpdate(dt) local p = self.entity:position() self.entity:setPosition(p.x + self.speed * dt, p.y, p.z)end
function NewBehavior:onDestroy()endclass NewBehavior{ private Entity@ self;
NewBehavior(Entity@ entity) { @self = entity; }
void onStart() { Log::info("NewBehavior started on '" + self.name() + "'"); }
void onUpdate(double dt) { Float3@ p = self.position(); self.setPosition(p.x + float(dt), p.y, p.z); }
void onDestroy() {}}Editing
Section titled “Editing”Double-click a script to open it in the editor’s script page: a code editor with highlighting and completion from the engine’s API. The API button in the page’s toolbar opens a browser beside the code with everything scripts can call in that language, as a tree of types and their members. Search it with Find a type or a member, and double-click an entry to insert it at the cursor.

The page checks the script a moment after you stop typing, and lists any problems under the code, each with its line and column and the message, and marks the lines. Choose a problem to move the cursor to it. Save (Ctrl+S) saves the script and cooks it. A script saved with errors does not replace the running one: the game keeps the last version that built until the errors are fixed.
You can also edit the file in Sources/ with another editor: the editor notices the change
within about two seconds and cooks it. An open script page does not reload the file, so close it
first; saving from the page would write over your changes.
Attaching a behavior
Section titled “Attaching a behavior”- Select the entity, click + (Add a component) at the top of the inspector, and choose Script, under Scripting.
- In the Script component, click Add on its Behaviors list. In the new behavior’s Script field, pick the script, or drag the script from the Assets panel onto the field.
An entity can have several behaviors, and they run in the order listed. To reorder them, drag a behavior by its grip, or right-click it and choose Move up or Move down. Each behavior has:
- Script, the script it runs.
- Enabled, to turn it off without removing it.
- Update Interval: seconds between
onUpdatecalls. 0, the default, is every frame; with a longer interval,dtis the time since the last call. - Its properties (below).
Setting the Level and Game scripts
Section titled “Setting the Level and Game scripts”- A scene’s Level script is set on the scene page. Select the scene’s own row at the top of the hierarchy, and the inspector shows the scene’s settings; set Level Script in the Scene Script section.
- The Game script is set in Project > Project Settings…, in the Startup section, as Startup script.
When the game starts, the Game script’s launch() runs first, and then the default scene loads.
A project with no default scene leaves it to the Game script to load the first one.
Properties
Section titled “Properties”A behavior’s properties appear in the inspector, under the behavior, so each entity can set its own values while sharing the script.
Every field the constructor sets to a number, a boolean, a string or a Float3 is a property:
function Coin.new(entity) local self = setmetatable({}, Coin) self.entity = entity self.spinSpeed = 3.0 -- a property self.label = "Gold" -- a property self.bob = Float3.new(0, 0.2, 0) -- a property return selfendWhen the script is cooked, the constructor runs without an entity (entity is nil) to find the
properties, so keep it to setting fields. Every such field is listed, including ones you only use
inside the script.
In a networked game, a list of field names in the class’s replicated field
(Coin.replicated = { "label" }) keeps those properties the same on every machine (see
Networking).
A member field is a property when it has metadata in brackets before it: a default, then optionally a description:
class Coin{ private Entity@ self; [3.0, "Spin rate in radians a second"] float spinSpeed; [null, "Who collects it"] Entity@ target; ["asset:Prefab", "What appears when it is collected"] Guid@ sparkle; private float m_time = 0.0f; // no brackets: not a property
Coin(Entity@ entity) { @self = entity; }}A property can be a float, double, an integer, bool, string, Color@, Float3@, an
Entity@ (pick one from the scene, or drag it from the hierarchy) or an asset: a Guid@ with
"asset:<Type>" as its default, such as "asset:Prefab" or "asset:Material". Color,
Float3, Entity and Guid properties must be declared as handles, with @; the cook reports
one declared without it. The description shows when you hover over the property. In a networked
game, replicated after the description keeps the property the same on every machine (see
Networking); an entity or asset property cannot
be replicated.
When a script fails
Section titled “When a script fails”An error while a behavior runs turns that behavior off and logs it in the Console under Script: the script, the line and the message, then the entity, the behavior and the method that failed. The entity and its other behaviors carry on. In the Game tab, each error also shows as a notice. Saving a fixed version of the script starts the behavior again.
Changing scripts while playing
Section titled “Changing scripts while playing”Behaviors run while the game plays in the Game tab, or while a scene page simulates. Save a behavior while it runs and it restarts with the new code: its fields start over, and its property values stay as set. For a Level or Game script, stop and play again.
To step through a script line by line, see Debugging scripts.