# Spawn

> Make and run multiplayer 3D games on Spawn from a workflow. Hand Savi, Spawn's AI game builder, a task in plain words; start new games; see who is playing and read each live room's log; run read-only scripts against a game while it runs; upload models, textures and sounds; and keep a copy of any game's spec.

App · Gaming · 12 actions. Web page: https://docs.lodol.com/docs/integrations/spawn

## Actions

### Create a game

Start a new game on your Spawn account, named as you like and begun from one of Spawn's starters (3D, 2D, a UI game or voxels), and get back its world id and play link, ready for 'Send a message to Savi' to have Savi build something in it. Spawn picks the engine a new game runs on. A workflow can't delete a game, so delete one you no longer want in Spawn.

**Inputs**

- Name (`game_name`, text): The game's name. It also makes the game's @ address, so it can't be the name of another of your games. Leave blank and Spawn names it game-2, game-3 and so on.
- Start from (`starter`, text): The skeleton the new game starts as: pick the one nearest the game you have in mind. Savi, or your own changes, build on it. One of: `3d`, `2d-top` (2D, top-down), `2d-side` (2D, side-scroller), `ui-game` (UI game), `3d-voxels` (3D voxels (a block world)). Default: `3d`.

**Outputs**

- `address` (text): The game's @ address, like @you/my-game.
- `app_id` (text)
- `engine_era` (text): '6.0' for a Spawn 6 game, 'document' for an older one.
- `engine_version` (text): The Spawn engine version the game runs on, like 6.0.0.
- `git_url` (text): The address of the game's git repository, for Spawn 6.
- `name` (text): The game's name. Creating or getting a game gives it as it was written; the list of games gives the form its link uses, like sky-garden.
- `play_url` (text): The link to play the game.
- `uses_git` (true/false): Whether the game's code is a git repository (Spawn 6).
- `world_id` (text): The game's world id, which the other Spawn steps take.

**Example output**

```json
{
  "address": "@lodol-demo/sky-garden",
  "app_id": "app_7d2e41",
  "engine_era": "6.0",
  "engine_version": "6.0.0",
  "git_url": "https://git.spawn.co/lodol-demo/sky-garden.git",
  "name": "Sky Garden",
  "play_url": "https://www.spawn.co/@lodol-demo/sky-garden/play",
  "uses_git": true,
  "world_id": "3f6c2a9e-8d41-4b7a-9c5e-1a2b3c4d5e6f"
}
```

### Get a game

Look up one of your games by its name, @ address, play link or world id, and get its play link, its engine version and, for a Spawn 6 game, the address of the git repository its code lives in.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.

**Outputs**

- `address` (text): The game's @ address, like @you/my-game.
- `app_id` (text)
- `engine_era` (text): '6.0' for a Spawn 6 game, 'document' for an older one.
- `engine_version` (text): The Spawn engine version the game runs on, like 6.0.0.
- `git_url` (text): The address of the game's git repository, for Spawn 6.
- `name` (text): The game's name. Creating or getting a game gives it as it was written; the list of games gives the form its link uses, like sky-garden.
- `play_url` (text): The link to play the game.
- `uses_git` (true/false): Whether the game's code is a git repository (Spawn 6).
- `world_id` (text): The game's world id, which the other Spawn steps take.

**Example output**

```json
{
  "address": "@lodol-demo/sky-garden",
  "app_id": "app_7d2e41",
  "engine_era": "6.0",
  "engine_version": "6.0.0",
  "git_url": "https://git.spawn.co/lodol-demo/sky-garden.git",
  "name": "Sky Garden",
  "play_url": "https://www.spawn.co/@lodol-demo/sky-garden/play",
  "uses_git": true,
  "world_id": "3f6c2a9e-8d41-4b7a-9c5e-1a2b3c4d5e6f"
}
```

### Get a game's building guide

Get Spawn's guide to building a game, matched to the engine version that game runs on: how its files are laid out, the reference for the api its scripts use, and the menu of Spawn's skills. Hand it to an AI step that writes or reviews game code, or that words a task for Savi.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.

**Outputs**

- `api_reference` (text): The script api reference, in Markdown.
- `engine_era` (text)
- `engine_version` (text)
- `git_url` (text)
- `guide` (text): Markdown.
- `play_url` (text)
- `skill_count` (number)
- `skills` (list)
- `spec_version` (text)
- `warnings` (list)

**Example output**

```json
{
  "api_reference": "# Tome API\n\n## api.query(filter)...",
  "engine_era": "6.0",
  "engine_version": "6.0.0",
  "git_url": "https://git.spawn.co/lodol-demo/sky-garden.git",
  "guide": "# Building this world\n\nEvery place is a folder...",
  "play_url": "https://www.spawn.co/@lodol-demo/sky-garden/play",
  "skill_count": 1,
  "skills": [
    {
      "description": "How a HUD, menus and overlays are built.",
      "id": "game-ui",
      "name": "Game UI"
    }
  ],
  "spec_version": "3",
  "warnings": []
}
```

### Get a game's live log

Read the log of a game's live room: what its scripts printed and the errors they ran into, naming the script where Spawn does. Only a running room keeps a log, so when nobody is playing this comes back with 'live' false and nothing in it.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- Show (`level`, text): Which lines to hand on. One of: `all` (Everything), `warnings` (Warnings and errors), `errors` (Errors only). Default: `all`.
- Most lines (`limit`, number): The most lines to hand on, the latest ones. From 1 to 500. Default: `100`.

**Outputs**

- `count` (number)
- `entries` (list)
- `error_count` (number)
- `live` (true/false)
- `note` (text): Why nothing was read, when nobody is in the game; else empty.
- `text` (text): The lines as plain text, one a line.
- `warning_count` (number)

**Example output**

```json
{
  "count": 1,
  "entries": [
    {
      "count": 2,
      "level": "error",
      "message": "TypeError: Cannot read properties of undefined (reading 'score')",
      "script": "scripts/scoreboard.js",
      "source": "",
      "tick": 5120,
      "time": ""
    }
  ],
  "error_count": 1,
  "live": true,
  "note": "",
  "text": "[error] scripts/scoreboard.js: TypeError: Cannot read properties of undefined (reading 'score')",
  "warning_count": 0
}
```

### Get a game's spec

Get a game's saved spec: its whole definition, as data. Read the latest draft, the version players see, an earlier version by number, or a published update by name. Useful for keeping a copy, or for checking whether a game has changed since a workflow last looked. A Spawn 6 game's code is a git repository, and Spawn reads the spec out of it.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- Version (`version`, text): 'draft' for the latest saved version, 'published' for the one players see, a version number, or the name of a published update (the end of its play link). Default: `draft`.

**Outputs**

- `found` (true/false)
- `note` (text): Why there is no spec, when not found.
- `requested` (text): Which version was asked for.
- `size_bytes` (number)
- `spec` (object)
- `version` (number)

**Example output**

```json
{
  "found": true,
  "note": "",
  "requested": "draft",
  "size_bytes": 52,
  "spec": {
    "entities": {},
    "world": {
      "name": "Sky Garden"
    }
  },
  "version": 14
}
```

### Get a skill

Get one of Spawn's skills in full: the engine's own guide to a craft such as game UI, terrain, cameras or combat, with the techniques and code Savi builds with. Hand it to an AI step, or use its name when asking Savi for something.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- Skill (`skill_id`, text, required): The skill, from the game's menu of skills. Its id works too, like game-ui.

**Outputs**

- `characters` (number)
- `content` (text): Markdown.
- `name` (text)
- `skill_id` (text)

**Example output**

```json
{
  "characters": 39,
  "content": "# Game UI\n\nA HUD is drawn in ui.js...",
  "name": "Game UI",
  "skill_id": "game-ui"
}
```

### Get my account

Get the Spawn account this connection acts as: its username and user id.

**Inputs**: None.

**Outputs**

- `display_name` (text)
- `user_id` (text)
- `username` (text)

**Example output**

```json
{
  "display_name": "Lodol Demo",
  "user_id": "u_5b1c9e",
  "username": "lodol-demo"
}
```

### List games

List the games on your Spawn account: each one's name, world id, @ address, play link and engine version. The world id is what the other Spawn steps take.

**Inputs**: None.

**Outputs**

- `count` (number)
- `games` (list)

**Example output**

```json
{
  "count": 1,
  "games": [
    {
      "address": "@lodol-demo/sky-garden",
      "app_id": "app_7d2e41",
      "engine_era": "6.0",
      "engine_version": "6.0.0",
      "git_url": "https://git.spawn.co/lodol-demo/sky-garden.git",
      "name": "Sky Garden",
      "play_url": "https://www.spawn.co/@lodol-demo/sky-garden/play",
      "uses_git": true,
      "world_id": "3f6c2a9e-8d41-4b7a-9c5e-1a2b3c4d5e6f"
    }
  ]
}
```

### List live rooms

See a game's live rooms and how many players are in each. A room runs only while someone is in the game, so no rooms means nobody is playing right now. It can wait for someone to join first, for example after sending a player the game's link.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- Wait for a player (minutes) (`wait_minutes`, number): How long to wait for someone to join when nobody is playing, checking every ten seconds. If nobody joins in time the step still succeeds, with 'live' false. Leave at 0 to look once. From 0 to 10. Default: `0`.

**Outputs**

- `live` (true/false): Whether anyone is in the game.
- `player_count` (number): Players across every room, when Spawn says; else null.
- `room_count` (number)
- `rooms` (list)

**Example output**

```json
{
  "live": true,
  "player_count": 1,
  "room_count": 1,
  "rooms": [
    {
      "details": {
        "id": "main",
        "last_heartbeat_at": "2026-09-23T05:00:28.218Z",
        "max_players": null,
        "mode": "dev",
        "player_count": 1,
        "status": "active"
      },
      "last_seen_at": "2026-09-23T05:00:28.218Z",
      "max_players": null,
      "mode": "dev",
      "place": "",
      "player_names": [],
      "players": 1,
      "room_id": "main",
      "started_at": "",
      "status": "active"
    }
  ]
}
```

### Run a script in a live game

Run a short piece of read-only JavaScript in a game's live room and get back what it returns: how many players are in, where an object is, what a scoreboard holds. The script can look but not change anything. It needs someone in the game: when nobody is, it doesn't run, and comes back with 'live' false. A script that throws fails the step with Spawn's error.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- Script (`script`, text, required): JavaScript that returns a value, using the game's own api. 'Get a game's building guide' has the reference.

**Outputs**

- `live` (true/false)
- `logs` (list): Anything the script printed.
- `note` (text): Why nothing was read, when nobody is in the game; else empty.
- `result`: What the script returned: a number, text, true or false, a list or an object.

**Example output**

```json
{
  "live": true,
  "logs": [],
  "note": "",
  "result": 3
}
```

### Send a message to Savi

Post a message into a game's studio chat, where Savi, Spawn's AI game builder, reads it. Sent as a task, Savi takes the work on and can split it across up to eight of her own sub-agents; sent as a note, it is context for her next turn. Nothing comes back: no reply, acknowledgement or word that she has finished, so look for the change in the game itself. Only a connection made from a person's own Spawn account can message Savi; Spawn turns an agent account away.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- Message (`message`, text, required): What to tell Savi, as you would in the studio chat. For a task, describe the result broadly rather than as a list of steps: splitting it up is what Savi's sub-agents are good at.
- Send as (`mode`, text): A task asks Savi to do the work. A note is only context: Savi reads it, and does nothing about it unless asked. One of: `task` (Ask Savi to take it on), `note` (Tell Savi, as context only). Default: `task`.

**Outputs**

- `message` (text): The text posted, as Savi sees it.
- `mode` (text)
- `sent` (true/false)
- `world_id` (text)

**Example output**

```json
{
  "message": "Please take this on: Add a leaderboard next to the spawn point.\n\nFan it out across your sub-agents if it splits cleanly. This came from a Lodol workflow, which can't read a reply, so just push as each piece lands.",
  "mode": "task",
  "sent": true,
  "world_id": "3f6c2a9e-8d41-4b7a-9c5e-1a2b3c4d5e6f"
}
```

### Upload a file to a game

Put a 3D model (.glb), a texture or a sound on Spawn's CDN for a game, and get back the address it is served from and the /cdn/ path the game's code uses for it: use it in the game, or hand it to Savi, say to use an image an earlier AI step made as a texture. The file can be uploaded, come from an earlier step, or be fetched from a public address.

**Inputs**

- Game (`game`, text, required): The game: pick one of yours, or give its @ address (like @you/my-game), its play link or its world id.
- File (`file`, text, required): The file: upload one, pick one from an earlier step, or give a public address to fetch it from.
- File name (`file_name`, text): The file's name with its extension, like knight.glb, which tells Spawn what kind of file it is. Spawn serves every file under a name made from its contents, so only the extension is used. Leave blank to use the file's own name.

**Outputs**

- `already_there` (true/false): Whether the same file was uploaded before, so nothing new was stored.
- `cdn_path` (text): What the game's code refers to the file by, /cdn/ and its name.
- `content_type` (text)
- `file_name` (text): The name the file came with.
- `name` (text): The name Spawn serves the file under, made from its contents.
- `response`: Spawn's answer to the upload, as it came.
- `sha256` (text)
- `size_bytes` (number)
- `url` (text): The address the file is served from.

**Example output**

```json
{
  "already_there": false,
  "cdn_path": "/cdn/value.cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3.glb",
  "content_type": "model/gltf-binary",
  "file_name": "crystal.glb",
  "name": "value.cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3.glb",
  "response": {
    "bytes": 160,
    "name": "value.cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3.glb",
    "sha256": "cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3",
    "status": "carried",
    "url": "https://spawnfile.io/dev/magic-assets/v5/values/cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3.glb"
  },
  "sha256": "cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3",
  "size_bytes": 160,
  "url": "https://spawnfile.io/dev/magic-assets/v5/values/cfb415cffab178c3381f59f27f3c69d8b49a37e9137c143cc7002fe149b7f3b3.glb"
}
```
