# Virtual Matter developer documentation (full text) > Every Virtual Matter developer document in one file, for agents that want a > single fetch. Generated at build time from the same sources as > https://virtualmatter.ai/developers. The website embed guide is generated by the > server: https://make.virtualmatter.ai/embed-guide.md --- Source: https://virtualmatter.ai/developers.md # Build with Virtual Matter Virtual Matter hosts live multiplayer voxel worlds. You build a world by prompting the built-in agent or by editing its SDK Lua directly - the world runs on Virtual Matter servers, hot-reloads as you edit, and has a shareable URL from minute one. The `virtualmatter` CLI connects external coding agents - Claude Code, Cursor, Codex, with your own subscription - to a live world over MCP. ## Use a world in Lovable Already have a shared world? Paste its link into Lovable and ask it to embed the world, following our [embed guide](https://virtualmatter.ai/embed-guide.md). No Virtual Matter account connection is needed for a shared link. To find your projects or create a world from a prompt, add the server below in Lovable’s Connectors → MCP server, with OAuth. Sign in or create an account in the connection window, then return to Lovable. You can ask “Embed my world” or “Create a garden world and embed it here.” ```text https://make.virtualmatter.ai/api/v1/mcp ``` VM builds use your VM credits. New worlds start privately; review yours and enable Share with friends before embedding. The website needs the response headers described in the guide. Verify the published page; Lovable’s nested editor preview may show a fallback. The website hosting the iframe must send `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` as HTTP response headers. HTML meta tags cannot set these. ## Quickstart This path is for people: start by prompting the built-in agent, and your first prompts are free. 1. **Create a world from a prompt.** Describe what you want at [virtualmatter.ai](https://virtualmatter.ai/). Your world spins up live in the browser with an agent chat beside it. 2. **[Download the native client for your OS.](https://virtualmatter.ai/downloads)** The browser client works everywhere; the native client runs the same worlds with more memory and better frame rates. 3. **Open your world in the native client.** Paste the world's URL (its /play or /g share link, or the /edit link) into the native client's connect screen. 4. **Mod it.** Chat with the built-in agent in the /edit view - it edits the SDK Lua under the project's Montage/ tree and the running world hot-reloads the changes. Virtual Matter can also publish the project's content to a GitHub repo in your account for versioning and remixing. When your free credits run out, you can buy more, or keep building the same world from your own coding agent on your own subscription. Give the CLI the world's link and continue as described in [For coding agents](https://virtualmatter.ai/developers#for-coding-agents): ```sh npx virtualmatter pull ``` ## For coding agents If you are a coding agent working from your own harness, this is your only path. Use the CLI from the first step, and do not prompt the built-in agent on the website. Point your agent at [/llms.txt](https://virtualmatter.ai/llms.txt) for a platform overview and [/AGENTS.md](https://virtualmatter.ai/AGENTS.md) for the project model and an SDK Lua cheat sheet. To build in a live world from a local harness - Claude Code, Codex, Cursor, or your own - one command is enough. It signs you in on first use, creates the world, and mirrors its files into a folder that already carries the MCP registration and briefing your agent looks for: ```sh npx virtualmatter create "My world" # or: npx virtualmatter pull cd my-world npx virtualmatter sync # live-push saves into the running world npx virtualmatter open # open it in the native client (downloaded on first use) ``` The folder's `.mcp.json` and `.cursor/mcp.json` register the MCP server for Claude Code and Cursor. It lists and creates worlds, reads and writes files, runs Lua, reports engine errors, takes screenshots, and opens the native client. Codex reads the folder's AGENTS.md but has no per-folder MCP file, so register the server for Codex once: ```sh codex mcp add virtualmatter -- npx -y virtualmatter mcp ``` In Claude Code outside a mirrored folder, register it by hand with: ```sh claude mcp add virtualmatter -- npx -y virtualmatter mcp ``` The block below is safe to ingest verbatim. ````markdown # Virtual Matter - context for coding agents ## Project model - A project ("montage") is one voxel world hosted with Virtual Matter. - A project has framings: "make" framings (editing sessions) and "play" framings (public play sessions). A framing is a running session slot on a voxel host. - Project content = SDK Lua scripts + assets under a Montage/ tree. Edits made in the live session hot-reload into the running world. The tree can be published to a maker-owned GitHub repo. ## URL shapes (make.virtualmatter.ai) - /new builder for people: create a world from a prompt (also at https://virtualmatter.ai/); coding agents use npx virtualmatter create instead - /edit/ maker session: live world + agent chat (also /edit/-; the CLI accepts both) - /play/ play session for a specific framing - /g/ share URL resolver: 302s to a live session ## APIs (unauthenticated) - GET https://make.virtualmatter.ai/api/v1/public/native-clients JSON: { iteration, clients: [{ platform, kind, url, filename, file_size, branch, commit, match }] } - per-platform native client installers (kind "download") or store links (kind "store", iOS). ## CLI + MCP (npm package "virtualmatter", Node >= 20) - npx virtualmatter create "" create a world, mirror it into ./ - npx virtualmatter pull mirror an existing world (any link shape) - npx virtualmatter list your worlds with framing ids + URLs - npx virtualmatter sync live-push saves into the running world - npx virtualmatter open open the world in the native client - npx virtualmatter mcp stdio MCP server (list_projects, create_project, select_project, list_files, read_file, write_file, run_lua, get_engine_errors, capture_screenshot, open_native_client, world_info) - Sign-in happens on first use (device code); no separate login step. - A mirrored folder carries .mcp.json, .cursor/mcp.json, AGENTS.md and CLAUDE.md, so Claude Code and Cursor register the server on their own. - Codex reads AGENTS.md but needs the server registered once: codex mcp add virtualmatter -- npx -y virtualmatter mcp ```` It is also served on its own at [/agent-briefing.md](https://virtualmatter.ai/agent-briefing.md). ## Play what others made Published worlds live in the public catalog at [play.virtualmatter.ai](https://play.virtualmatter.ai/) - no sign-in required, every card opens a live session in the browser. --- Source: https://make.virtualmatter.ai/AGENTS.md # AGENTS.md - working with a Virtual Matter project This file tells a coding agent how to think about a Virtual Matter project. The `virtualmatter` CLI drops a copy into every local project mirror it creates (`virtualmatter pull`); the canonical copy lives at https://make.virtualmatter.ai/AGENTS.md. ## The mental model - The world itself runs on Virtual Matter servers, not on the maker's machine. There is one authoritative server simulation per world session, and any number of connected clients (browser WASM or the native client). - The project's content is SDK Lua scripts plus assets (voxel data, prefabs, images, sounds) under a `Montage/` tree. Virtual Matter can publish that tree to a GitHub repo in the maker's account for versioning and remixing; pushing to that repo does not feed back into the running world today - live edits happen in the session. - Changes hot-reload. Saving a `.lua` file in the live session's Montage tree re-runs the module and its `Start()` on a fresh instance inside the running world - no restart, no build step. - Prefabs are reusable scene-graph snippets: JSON files with a `.prefab` extension in the Montage folder, instantiated at runtime via `Server:InsertPrefab(asset)`. - There is no local runtime - the world cannot run on the maker's machine. The `virtualmatter` CLI (npm) is how you reach it from a local harness, and it needs no setup: the first command that needs an account signs you in with a device code. `npx virtualmatter create "My world"` creates a world and mirrors its Montage tree into `./my-world`; `npx virtualmatter pull ` mirrors an existing one (/edit, /play, /g, /p, /projects links all work, with or without a readable slug); `npx virtualmatter list` shows your worlds; `npx virtualmatter sync` live-pushes saves into the running session (which hot-reloads them); `npx virtualmatter run-lua` / `errors` / `screenshot` drive the engine; `npx virtualmatter open` downloads the native desktop client on first use, signs it in with your account, and opens the world in it; and `npx virtualmatter mcp` serves all of it over MCP. A mirrored folder carries `.mcp.json` and `.cursor/mcp.json` (so Claude Code and Cursor register the MCP server on their own), this file, and a `CLAUDE.md` that imports it. Codex reads this file but has no per-folder MCP file: register the server for it once with `codex mcp add virtualmatter -- npx -y virtualmatter mcp`. In Claude Code outside a mirrored folder, use `claude mcp add virtualmatter -- npx -y virtualmatter mcp`. The server works before a world is selected (`list_projects`, `create_project`, `select_project`), then exposes `list_files`, `read_file`, `write_file`, `run_lua`, `get_engine_errors`, `capture_screenshot`, `open_native_client`, and `world_info`. - Work through the CLI, not the website. Do not open make.virtualmatter.ai in a browser and do not prompt the built-in agent there: it spends Virtual Matter's platform credits instead of your own subscription, an anonymous browser session cannot be steered after its first turn, and you cannot read engine errors from a rendered page. The CLI does everything that agent does, from your own harness. - Seeing your work: `virtualmatter screenshot` shoots a default overview of the world origin, `--target ` frames one object by name or id, and `--at x,y,z --rot yaw,pitch,roll` places the camera exactly. Y is up and -Z is forward, and the rotation really is yaw first: yaw 0 faces -Z, pitch -90 looks straight down, pitch 0 is the horizon. The MCP `capture_screenshot` tool takes the same arguments. Verify a change with a screenshot plus `errors` rather than assuming a write worked. - The mirrored folder's AGENTS.md is this guide followed by the engine SDK's own agent guide (the AGENTS.md that lives in every Montage tree and inside the desktop client's Data/Sdk/Montage/). The engine guide assumes an in-session agent driving the engine through `atomo`; the merged file maps each `atomo` step to the CLI or MCP equivalent, and the `Skills/*.md` references it points at are in the folder. The SDK's own tooling (`atomo`, `vm_auth.py`, the agent-log hooks) is not mirrored: it only works inside a session. Sandboxed agents need network access for every CLI command. ## SDK Lua cheat sheet The scripting language is Lua 5.4, sandboxed: `os`, `io`, `require`, `package`, `dofile`, `loadfile`, `loadstring` are nil. `math`, `string`, `table`, `coroutine` remain. No `os.time` - use `Time.time` (sim time), `Time.frame`, or `AE:GetDebugTime()` (wall clock). ### Script shape Every persistent behavior is a `.lua` file in the Montage tree returning a `self` table: ```lua local self = {} function self:Start() end function self:Update(deltaTime) end return self ``` Attach to an object with `obj:AddScript("My Folder/Example.lua", sync)` - the path is relative to the Montage root; `sync = true` replicates the script to clients. `obj:FindScript("Example")` returns the live instance. ### Server / client split The same script runs on the server and (when synced) on every client. Branch with `self.onServer` / `self.onClient`: ```lua function self:Update(dt) if self.onClient then return end -- voxel edits are server-only -- authoritative logic here end ``` Nothing replicates automatically: set `syncToClients = true` on the script or VoxelData component, and use `util:makeNetworkedTable(self, { hp = 100 })` for properties that should sync (server writes, clients read, deltas only). `obj.pos` / `obj.rot` do not auto-sync - replicate them yourself. ### RPC ```lua self:RPC("serverDoSomething", pos, dir) -- on a client: goes to the server function self:serverDoSomething(pos, dir, clientID) -- clientID auto-appended assert(self.onServer) end ``` On the server, `self:RPC(...)` fans out to all clients. Reliable, FIFO per direction. Requires `self.component.syncToClients = true`. ### Scene and objects (server) ```lua local ob = Scene:CreateObject("Name") ob.save = true ob:AddScript("Path/Script.lua") Scene:GetObjectByName("Name") Scene:CloneObject(ob) -- prefer over rebuilding ob.active = false -- prefer over destroy ob:AddTag("Enemy"); FindObjectsWithTag("Enemy") -- tags are runtime-only state ``` ### Voxel editing (server only, async) ```lua Vox:Add(Sphere(pos, 2)):Color(1, 0, 0):Run() Vox:Add(Box(Vec3(0, -1, 0), Vec3(20, 2, 20))):ForceStatic():Run() ``` Shapes: `Box(center, fullSize)`, `Sphere(center, r)`, `Capsule(p1, p2, r)`, `Cylinder(p1, p2, r1[, r2])`. `Run()` is async - chain `:OnFinished(fn)` before `:Run()` to read post-commit state. Big edits stall the frame for every client; keep in-game edits small and infrequent. ### Input (event-driven, client input reaches the server) ```lua self.component.syncToClients = true events.keyDown.addListener(self, function(key, from) self.keys[key] = true end) events.keyUp.addListener(self, function(key, from) self.keys[key] = false end) ``` Player-driven movement must be client-predicted - never gate the player's own feedback on the server round-trip. ### Physics ```lua local rb = obj:AddComponent("RigidBody") rb:AddImpulse(Vec3(0, 50, 0), obj.pos) rb.velocity; rb.mass; rb.gravityScale ``` ### Time and diagnostics ```lua Time.dt; Time.time; Time.frame; Time.timeScale AE:GetLogValue("Raycasts") -- engine counters, e.g. raycasts this frame AE:GetAssets() -- list all assets (APIs take Assets, not paths) ``` ### UI (client-side HUD) Build screen UI with the MUI builder: `UI:AddPanel|AddButton|AddLabel|AddSlider|...` chained with `:Set{...}`; flexbox-like row-wrap layout. ## Conventions - Coordinates: Y is up, -Z is forward, X is right. - Script files are named in capital case with spaces (`Character Controller.lua`). - Check whether a script is already attached before adding it - duplicates run twice. - The server is for authority (world edits, spawns, state); clients are for feel (prediction, FX, UI). ## Embed or build a world for an existing website For a shared project link, fetch `/api/v1/public/embed?target=` and follow `/embed-guide.md`. Use the returned canonical player URL, not the maker's external website URL. Keep the existing website and its design. For account discovery or prompt-based creation, connect the hosted MCP at `https://make.virtualmatter.ai/api/v1/mcp` using OAuth. Users can sign up in the connection flow. Tools: `list_projects`, `get_embed`, `create_project` (with a prompt and stable request_id), `get_build_status`. VM's agent builds using VM credits. Review and share the private world before embedding. The local CLI exposes `embed`, `build --prompt --request-id`, and `build-status`. ## Local conversation history After pulling a project, run `virtualmatter agent-logs setup` once to enable future chat history capture for local harnesses. It adds Codex, Claude Code, Cursor, and (when installed) Hermes hooks without replacing existing hooks. Keep `virtualmatter sync` or `virtualmatter agent-logs watch` running for retry and delayed transcript capture. Follow each harness's normal hook review and restart flow. Use `agent-logs status` to inspect pending uploads and `agent-logs disable` to stop capture. Other harnesses can send portable public event JSONL with `virtualmatter agent-logs upload --harness --session `, or use MCP `upload_agent_logs`. Supply stable event IDs for retries; omit private reasoning, system/developer prompts, credentials, and binary media.