engine
The engine namespace — 36 functions.
globals/engine/discardPlayChanges
engine.discardPlayChanges() -> ()
Arm the leave-play safeguard's deliberate discard for the play session this is called from, so that session's play to edit flip proceeds and discards its unaccepted changes.
Returns ()
globals/engine/gameplayReady
engine.gameplayReady -> boolean
Whether gameplay simulation is running: not paused, and the play scene materialized. Read-only.
Returns boolean
globals/engine/gpuCompute
engine.gpuCompute -> boolean
Whether this process holds a live GPU device, so compute dispatch is available. Read-only.
Returns boolean
globals/engine/headless
engine.headless -> boolean
Whether this boot renders offscreen with no window a person can see. Content that only serves someone at a display stands down when it reads true. Read-only.
Returns boolean
globals/engine/markScriptingBaseline
engine.markScriptingBaseline() -> number
Record the scripting registries — world-event subscriptions, the
four lifecycle-watcher lists, and the require cache — as they stand
right now, and make that the point engine.resetScriptingState()
restores to. Replaces any previous mark. Returns the new mark's
generation, counting from 1.
Mark once the engine is serving rather than while it boots: the
registries keep growing as the prelude subscribes, the world
entrypoint runs and the startup scene loads, so a mark taken partway
through sits below the rest of that work and the first reset would
remove it.
Returns number
engine.markScriptingBaseline()
world.on("player_join", function() end)
engine.resetScriptingState() -- the subscription above is gone
globals/engine/mode
engine.mode -> "edit" | "play"
The engine mode this process is in, edit or play. Assigning it takes the flip, side effects and all.
Returns "edit" | "play"
globals/engine/offDeviceRebuilt
engine.offDeviceRebuilt(id: number) -> boolean
Remove an engine.onDeviceRebuilt subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it named
none — already removed, or never registered.
Parameters
idnumber— Watcher id returned byengine.onDeviceRebuilt.
Returns boolean
local id = engine.onDeviceRebuilt(function() end)
engine.offDeviceRebuilt(id)
globals/engine/offModeChange
engine.offModeChange(id: number) -> boolean
Remove an engine.onModeChange subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it
named none — already removed, or never registered.
Parameters
idnumber— Watcher id returned byengine.onModeChange.
Returns boolean
local id = engine.onModeChange(function() end)
engine.offModeChange(id)
globals/engine/offPauseChange
engine.offPauseChange(id: number) -> boolean
Remove an engine.onPauseChange subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it
named none.
Parameters
idnumber— Watcher id returned byengine.onPauseChange.
Returns boolean
globals/engine/offWorldLoaded
engine.offWorldLoaded(id: number) -> boolean
Remove an onWorldLoaded subscriber by its watcher id.
Parameters
idnumber
Returns boolean
globals/engine/offWorldReady
engine.offWorldReady(id: number) -> boolean
Remove an engine.onWorldReady subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it
named none.
Parameters
idnumber— Watcher id returned byengine.onWorldReady.
Returns boolean
globals/engine/offWorldUnloading
engine.offWorldUnloading(id: number) -> boolean
Remove an engine.onWorldUnloading subscriber by its watcher
id. Returns true when a live watcher carried that id, false when it
named none.
Parameters
idnumber— Watcher id returned byengine.onWorldUnloading.
Returns boolean
globals/engine/onDeviceRebuilt
engine.onDeviceRebuilt(callback: (number) -> ()) -> number
Register a callback that fires after the engine has answered a lost render device by building another one. The callback receives the new device generation — a number that counts the devices this session has run on, and moves exactly once per rebuild. Returns a watcher id.
A device is lost when the driver resets, when the GPU is taken away, or when a browser reclaims a WebGPU context. Everything the engine can re-derive by itself it does: meshes, materials, shaders, render passes and the UI are all back on the new device before this fires. What it cannot re-derive is what YOUR content made and only the GPU held — a texture uploaded from pixels a script computed, a compute buffer it filled, a render target it created. Make those again here.
Content that owns no GPU resource of its own needs no subscriber: asset handles re-materialise on their next use.
Parameters
callback(number) -> ()— Function invoked as(generation: number).
Returns number
engine.onDeviceRebuilt(function(generation)
-- the noise field lived only on the GPU, so it is computed again
regenerateNoiseTexture()
end)
globals/engine/onModeChange
engine.onModeChange(callback: (string, string) -> ()) -> number
Register a callback that fires synchronously whenever
engine.mode changes. Callback receives (newMode, oldMode) as
strings. Returns a watcher id for future removal. Consumers
(player_spawner, camera_spawner, editor-UI bootstrap, world
entrypoint top-level onModeChange, etc.) all subscribe through
this single API — there is no other fire path. Mode is engine
state, so the watcher hangs off the engine module.
Parameters
callback(string, string) -> ()— Function invoked as(newMode: string, oldMode: string).
Returns number
local id = engine.onModeChange(function(new, old)
print("flipped " .. old .. " -> " .. new)
end)
globals/engine/onPauseChange
engine.onPauseChange(callback: (boolean, boolean) -> ()) -> number
Register a callback that fires synchronously whenever the gameplay
pause flag flips via an explicit engine.paused write. Callback
receives (newPaused, oldPaused) as booleans. Returns a watcher id.
Pause is independent of engine.mode: pausing play mode returns the
editor authoring surface (free camera + EditorOnly entities) over the
frozen play world, and resuming hides it again. Mode-driven pause
resets (the edit=paused / play=running defaults applied on a mode flip)
are delivered through onModeChange, not this hook.
Parameters
callback(boolean, boolean) -> ()— Function invoked as(newPaused: boolean, oldPaused: boolean).
Returns number
local id = engine.onPauseChange(function(paused)
print(paused and "frozen" or "running")
end)
globals/engine/onWorldLoaded
engine.onWorldLoaded(callback: () -> ()) -> number
Register a callback fired (no args) when the world is fully
LOADED — its .world_entrypoint.luau ran AND its onWorldLoad
returned (the startup scene loaded, defaults seeded, editor UI
mounted). This is strictly AFTER onWorldReady (content synced):
ready = "bytes are in the VFS"; loaded = "the entrypoint has run".
LATCHED — a callback registered after the world is already loaded
fires immediately, so a late consumer never misses it and never has
to poll. Read the same state synchronously via engine.worldLoaded.
Parameters
callback() -> ()— Function invoked with no arguments.
Returns number
globals/engine/onWorldReady
engine.onWorldReady(callback: () -> ()) -> number
Register a callback fired (no args) when the bound world's
content has been synced into the VFS and the world is ready to
load. This is the race-free, user-space hook that drives the whole
world-VM lifecycle: the builtin world-entrypoint loader subscribes
to it and, when it fires, loadstring(vfs.read(...))s
/source/.world_entrypoint.luau and runs its onWorldLoad —
exactly the way a scene entrypoint loads. The trusted VM fires this
(via world.markReady()) ONLY once the bytes are in the VFS, so a
subscriber never sees a half-synced world. Returns a watcher id.
Parameters
callback() -> ()— Function invoked with no arguments.
Returns number
globals/engine/onWorldUnloading
engine.onWorldUnloading(callback: () -> ()) -> number
Symmetric teardown of engine.onWorldReady: register a callback
fired (no args) when the bound world is unbinding/swapping out. The
builtin loader runs the world entrypoint's onWorldUnload here, so
the world entrypoint has the same load/unload parity a scene
entrypoint has. Returns a watcher id.
Parameters
callback() -> ()— Function invoked with no arguments.
Returns number
globals/engine/paused
engine.paused -> boolean
Whether gameplay is paused: update(dt) component callbacks are gated off while editorUpdate(dt) keeps firing in edit mode.
Returns boolean
globals/engine/profile
engine.profile -> "editor" | "runtime"
The boot profile this process started under, editor or runtime. Read-only.
Returns "editor" | "runtime"
globals/engine/resetScriptingState
engine.resetScriptingState() -> { [string]: number }
Drop every world-event subscription, lifecycle watcher and
cached module registered since the last
engine.markScriptingBaseline(), leaving everything registered
before it in place — including the builtin world-entrypoint loader,
which subscribes at VM boot and so always sits below any mark.
Raises when no mark has been taken. Returns per-registry counts of
what was removed: worldEvents, modeWatchers,
worldReadyWatchers, worldUnloadingWatchers, pauseWatchers,
modules, and total.
Returns { [string]: number }
globals/engine/scriptingRegistryCounts
engine.scriptingRegistryCounts() -> { [string]: number }
How many subscriptions each scripting registry holds right now,
plus the size of the require cache and the generation of the mark in
force. Keys: worldEvents, modeWatchers, worldReadyWatchers,
worldUnloadingWatchers, pauseWatchers, modules, and
baselineGeneration (nil when no mark has been taken).
Returns { [string]: number }
globals/engine/setMode
engine.setMode(mode: string, options: { strict: boolean? }?) -> { mode: string, bypassed: { any } }
Change the engine mode with per-call control over the play gate, and
read back what the change went past. engine.mode = value is the same
flip with the defaults.
options.strict = false lets THIS call enter play while your own content
carries error-severity diagnostics. It settles with the call: the world's
lsp.strict_mode is untouched, so no other session and no later session
of the world sees a different gate. The returned bypassed array holds
the diagnostics the call went past — each { path, line, col, code, message, severity } — and the engine log carries the same list. An
error in content another session wrote never gates the flip, so it never
appears here; a push still refuses to publish while any of them stands.
Parameters
modestring—"edit"or"play".options{ strict: boolean? }(optional) —{ strict: boolean? }.strict = falsewaives the play gate for this call;trueor omitted honours the world'slsp.strict_mode.
Returns { mode: string, bypassed: { any } } — { mode, bypassed } — the mode now in force and the diagnostics this call entered play past (empty when it went past none).
local report = engine.setMode("play", { strict = false })
for _, d in ipairs(report.bypassed) do
print(("entered play past %s:%d — %s"):format(d.path, d.line, d.message))
end
globals/engine/timeScale
engine.timeScale -> number
The global time scale applied to the fixed-timestep accumulator and to update(dt): 1.0 is real time, 0.0 frozen, 2.0 double speed.
Returns number
globals/engine/vertexStride
engine.vertexStride -> number
Byte stride of the engine's standard GPU Vertex layout, which a mesh built from a compute buffer sizes and strides its writes to. Read-only.
Returns number
globals/engine/worldLoaded
engine.worldLoaded -> boolean
Whether the world entrypoint's onWorldLoad has run to completion. Read-only.
Returns boolean
typed/builtin//modules/api/engine/engine/engine/discardPlayChanges
engine.discardPlayChanges() -> ()
Arm the leave-play safeguard's deliberate discard for the play session this is called from, so that session's play to edit flip proceeds and discards its unaccepted changes.
Returns ()
typed/builtin//modules/api/engine/engine/engine/gameplayReady
engine.gameplayReady -> boolean
Whether gameplay simulation is running: not paused, and the play scene materialized. Read-only.
Returns boolean
typed/builtin//modules/api/engine/engine/engine/gpuCompute
engine.gpuCompute -> boolean
Whether this process holds a live GPU device, so compute dispatch is available. Read-only.
Returns boolean
typed/builtin//modules/api/engine/engine/engine/headless
engine.headless -> boolean
Whether this boot renders offscreen with no window a person can see. Content that only serves someone at a display stands down when it reads true. Read-only.
Returns boolean
typed/builtin//modules/api/engine/engine/engine/mode
engine.mode -> "edit" | "play"
The engine mode this process is in, edit or play. Assigning it takes the flip, side effects and all.
Returns "edit" | "play"
typed/builtin//modules/api/engine/engine/engine/paused
engine.paused -> boolean
Whether gameplay is paused: update(dt) component callbacks are gated off while editorUpdate(dt) keeps firing in edit mode.
Returns boolean
typed/builtin//modules/api/engine/engine/engine/profile
engine.profile -> "editor" | "runtime"
The boot profile this process started under, editor or runtime. Read-only.
Returns "editor" | "runtime"
typed/builtin//modules/api/engine/engine/engine/timeScale
engine.timeScale -> number
The global time scale applied to the fixed-timestep accumulator and to update(dt): 1.0 is real time, 0.0 frozen, 2.0 double speed.
Returns number
typed/builtin//modules/api/engine/engine/engine/vertexStride
engine.vertexStride -> number
Byte stride of the engine's standard GPU Vertex layout, which a mesh built from a compute buffer sizes and strides its writes to. Read-only.
Returns number
typed/builtin//modules/api/engine/engine/engine/worldLoaded
engine.worldLoaded -> boolean
Whether the world entrypoint's onWorldLoad has run to completion. Read-only.
Returns boolean