Graphite field sketch of a mechanical beetle familiar with a landscape inside its shell, plus a shell-fragment study.
Plate S02Familiar studies, model views and light

Our game engine is called Vishnu, and the games that run on it are cartridges. The first one is a cozy, darkly funny colony game: two humans, Rowan and Sedge, stuck serving a hungry goblin guest. Fell trees, raise walls, brew the ale before the goblin gets cranky.

Back in September, all of that game’s props, the benches, bottles, kettles and bookcases, were little procedural Three.js builders: code that draws a kettle. Then we baked them down into pixel art for the game.

We wanted an agent to use those same builders. Not a description of them. Not a screenshot. The actual code that makes the kettle. So we put them behind an MCP server, which is the standard way to hand an AI agent a set of tools.

(If an agent vanishes halfway through using a tool, that’s the restart note.)

Six tools, one owner

The server had six tools. Two came first:

  • hive_asset_catalog returns the settings and defaults for every prop.
  • hive_build_scene takes up to 24 configured props and returns a scene.

Four more work on a scene document with a version number:

  • hive_scene_create, hive_scene_edit, hive_scene_inspect and hive_scene_export.

Every tool went through one shared scene owner. The game, the browser editor and the MCP server all used the same original geometry. None of them kept its own copy of what a bench is.

Here’s an agent adding a bench to an empty scene:

hive_scene_edittool call

sent

{
  "document": {
    "version": 1,
    "revision": 0,
    "name": "front porch",
    "nodes": []
  },
  "expectedRevision": 0,
  "operations": [
    {
      "type": "add",
      "node": {
        "id": "bench-1",
        "parentId": null,
        "transform": {
          "position": [0, 0, 0],
          "rotation": [0, 0.4, 0],
          "scale": [1, 1, 1]
        },
        "geometry": {
          "kind": "original",
          "pack": "hive-brewhouse-v1",
          "asset": {
            "builder": "bench",
            "parameters": {
              "width": 1.6
            }
          }
        },
        "material": null
      }
    }
  ]
}

returned

              {
  "document": {
    "version": 1,
    "revision": 1,
    "name": "front porch",
    "nodes": [
      {
        "id": "bench-1",
        "…": "the node exactly as added"
      }
    ]
  }
}
            
Field names match the server’s Zod schema. Bench width, depth and height change the real procedural geometry.

What we tried first, and what we kept

We checked it the boring way. A real MCP client over stdio and another over Streamable HTTP listed the tools, called them, and compared the exported geometry against a separate Three.js loader. Then a browser loaded the exact exported bytes, spun them around, and downloaded byte-identical files.

Where the art went next

The part of this that stuck is the bake: one step that turns 3D into the pixel art the game shows. Three.js is for making and baking art. The live game draws the baked sprites in Pixi, on top of a simulation that holds the real state.

At the end of September, Levi made a bigger call: switch every game’s source models to Quaternius, a big library of free CC0 3D models, and keep the pixel pipeline exactly as it is. So it’s a change of ingredients, not of recipe.

That’s how it landed. A SourceModel names an FBX or glTF file, its scale and facing, which of its animations play each of our rig’s animations, and which of our materials each of its materials becomes. All of that gets checked in one place. Then the imported model goes through the same camera, outline and packer as everything else. The old path for rig-built characters didn’t change at all. We checked it byte for byte against two games, Colony and Pirates.

Two more things came along with it:

  • Licences travel with the art. Every Quaternius pack in our library keeps its licence, a credits file and a provenance file: author, CC0 licence, source page, and a SHA-256 hash for every part. A sprite you can’t trace back to where it came from is a sprite you can’t fix, or defend.
  • The library is layered, not per game. There’s a base world of shared art for any cartridge, shared effects, and theme packs on top, organised from small parts up to bigger pieces. A new game should mostly be picking from the shelf.

And a game can still look pixel-y even when the models are full colour. A cartridge can name a palette, and the art gets baked into that palette as it loads.

If you make games with 3D-to-pixel art and you’d use this, I’d love to hear what you’d feed it. That tells us what to open up first.