Log inGet started

The engine

Working in Zero means working inside a live, shared world. Three things make up the engine's model, and understanding them up front saves a lot of confusion: the world is live and persistent, it runs…

A live, shared world

Every world is a multi-user session. Everything you do is live — your edits sync to everyone else in the world as you make them, and you see theirs. There is no single-player or offline mode, and there is no "save" step: writes are durable the moment you make them (more on persistence next). The world's filesystem is the source of truth; "what you see is what exists."

Publishing a playable version for players is a separate, deliberate act (commit/push) — covered in the worlds guide. Saving and publishing are different things.

What persists

The filesystem boundary is the whole story:

  • /zero/source/... — durable. Anything you write here persists (it's stored in the backend and synced to everyone). This is where all authored content lives. No save step.
  • /zero/runtime/... — live runtime state. Never persists; it's rebuilt as the world runs.
  • /source/tmp — local scratch that does not sync to other clients. Use it for throwaway working state.

So "will this survive a reload / be seen by others?" has a simple answer: yes if it's under /zero/source (outside tmp), no otherwise.

Edit vs play

engine.mode is "edit" or "play", and you flip it directly:

engine.mode                 -- "edit" or "play"
engine.mode = "play"        -- enter play
engine.mode = "edit"        -- back to edit
engine.onModeChange(function(newMode, oldMode) end)   -- react to flips
  • Edit is where you author. Component update(dt) / fixedUpdate(dt) do not run; editorUpdate(dt) does. Writes to /zero/source are durable.
  • Play is where gameplay runs. update / fixedUpdate tick.

Entering play doesn't just "start ticking": the engine snapshots the edit state, re-initialises a fresh play world (so components re-run awake/start in play), and writes during play land on a throwaway runtime copy. Leaving play discards that play world and restores the edit snapshot — which is why play-mode changes can never touch your authored source. (The exact component lifecycle across the flip is in the components guide.)

Entering play is also gated on your scripts being healthy: while any user script under /zero/source (library content under /source/libs is exempt) carries an error-severity diagnostic, engine.mode = "play" raises instead of flipping — refusing to enter play — N script error(s) in user content: followed by the offending path:line — message entries. Run lsp.checkAll({ scope = "user" }) to list them yourself, fix them, and flip again. The gate is calibrated by the lsp.strict world setting: "strict" (the default) blocks on any error, "soft" blocks only structural errors (syntax, unresolved require, broken lifecycle-callback signatures), and "off" logs a warning and proceeds. Returning to edit is never gated — you can always get back to fix the error. The override does not carry to publishing: zm.push refuses unconditionally while user-script errors exist (see the development guide).

Paused vs running

Pause is a separate axis from edit/play. engine.paused gates the gameplay tick:

engine.paused = true        -- freeze gameplay
engine.timeScale = 0.5      -- or slow it down (1.0 real, 0.0 frozen, 2.0 double)

When paused, update(dt) / fixedUpdate(dt) stop — but editorUpdate(dt) keeps firing, so the authoring loop stays live. engine.timeScale scales time without fully stopping it. Both are orthogonal to engine.mode: edit/play and paused/running are independent.

World lifecycle

engine.profile        -- "editor" or "runtime" (read-only; the boot profile)
engine.worldLoaded    -- true once the world's entrypoint has finished loading
engine.onWorldReady(function() end)    -- content synced into the VFS
engine.onWorldLoaded(function() end)   -- the world entrypoint has run (latched: fires immediately if already loaded)

A world boots: content syncs (onWorldReady), then /source/.world_entrypoint.luau runs (onWorldLoaded), which loads the startup scene and seeds defaults.

Finding the rest

engine is an authored module — read it at modules/api/engine/engine.module. Publishing and the shared library are in the worlds guide; how components behave across edit/play is in the components guide; how a loaded world surfaces players and the camera is in the scenes guide.

  • documentation
  • guide