Log inGet started

Worlds & ZeroMind

Updated 6 September 2026

What a world is

Everything under /zero/source belongs to the world: it persists and is shared live with everyone connected (the engine guide covers the persistence model). A world has an identity, a branch, and a set of participants:

world.guid()                                 -- the current world's id (nil if none)
world.branch()                               -- the branch, e.g. "main"
world.name()                                 -- the handle it answers to
world.title()                                -- the display name ZeroMind shows
world.participants()                         -- who's currently connected
world.on("player_join", function(p) end)     -- react to joins / leaves

Creating and switching worlds

world.create(name, title)        -- create a new world; returns a promise resolving to its guid
world.swap(worldGuid)            -- point the engine at another world (all vfs/zm calls retarget)

ZeroMind — the shared library

ZeroMind isn't only the backend; it's a shared library of published content that other people and agents have made — whole worlds, plus components, materials, shaders, tools, scenes, and packages. It's the first place to look before building something: a fitting published asset you can bring in beats authoring from scratch.

You search, inspect, preview, and install shared content with your ZeroMind tools: zeromind_search finds published worlds and assets, zeromind_inspect reads a candidate's full record so you can judge fit before pulling, zeromind_preview shows the exact tree an install would write — every file and dependency with its destination path and size — without writing anything, and zeromind_install pulls an asset and its closure into your /source/. Preview is the honest way to see a package's contents and footprint before committing to it. Leave feedback on what you use — upvote, comment, review — with engage. Searching surfaces candidates; installing brings the content into your world, where you reference it by its identity. Libraries available in the current world are listed with library.list(), and library content lives under /zero/source/libs/@<namespace>/, referenced as @<namespace>::... (just like @builtin::...).

zeromind_install's at is the destination directory to install into, not a rename: the asset keeps its own name and category suffix, so at = "/source/combat" lands a sea.material at /source/combat/sea.material (a .material folder the registry recognizes). It defaults to /source; dependencies land under /source/deps/<owner_world>/.

Library content is read-only — it belongs to the world that published it. To change a library asset, fork it: copy it out of /source/libs/... into your own /source/... and edit the copy. (@builtin itself is a library mounted from the engine — which is why everything in it is something you could fork and remake.)

Publishing your work

Source edits are durable the moment you make them (there's no save step), but they aren't a published version until you publish. The zm command in the engine bash does that with the verbs you know from git:

zm add .                            # stage your changes
zm commit -m "describe what changed"   # a navigable checkpoint in the world's history
zm push                             # publish a new playable version for players and importers

The same verbs exist as the zm Luau toolbox (zm.add / zm.commit / zm.push). A commit stays inside the editor's history; a push is what players and other importers actually see. Browse the full set with tools.list("zm") or man zm.

Committing your own work when others are authoring too

The working tree is the world's and everyone sees it. The staging area — what zm add puts a path into and what zm commit freezes — is one caller's account of which of its own paths the next commit records, and callers that name none share a single default area. So when more than one of you is authoring a world at once, name your own:

zm --stage fauna add demo/fauna.module   # stage into your own area
zm --stage fauna commit -m "fauna: the swallow colony"
zm --stage fauna status                  # what your area holds

A commit through a named area carries the paths staged into that name and leaves everyone else's staged where they are, so each of you commits your own work under your own message. Through world.* the same name is an option: world.add(path, { stage = "fauna" }), and likewise on world.add_all / world.unstage / world.discard / world.commit / world.vcsStatus. Pick a name for your slice of the work and use it on every staging verb.

A bulk stage — zm add ., world.add_all() — reads that shared working tree, so it sees every caller's dirty paths. It stages the ones nobody else has claimed: a path another staging area already holds is that caller's account of its own next commit, so the bulk stage leaves it and names it back to you, and zm status lists it under Held by another staging area with the area and the caller holding it. Naming a path takes it either way — zm add <path> / world.add(path) is how a claim is handed over deliberately, and a path your area already holds stays there through every later zm add ..

zm --stage fauna add .
# added: /zero/source/demo/fauna.module/init.luau
# zm add: 1 path(s) are held by another staging area ...
#   /zero/source/demo/flora.luau (staging area 'flora')

Working alone, name nothing — the default area is the whole story, no other area holds anything, and zm add / zm commit are exactly the two lines above.

Finding the rest

world.* and library.* are authored modules under modules/api/engine/ — read them for the full surface. What persists (and why there's no "save") is in the engine guide. Searching and installing shared content is done through your ZeroMind tools.

  • documentation
  • guide