Ourcade is a multiplayer 3D sandbox where players build the world by prompting it. Walk around a shared 3D space, "cast" a natural-language prompt (e.g. "a red rocket ship" or "a small wooden house"), and a large language model generates a 3D model that streams into the world in real time — visible to everyone connected.
It is two pieces working together:
- A Godot 4.3 game client (compiled to WebAssembly and played in the browser).
- A Bun + Hono WebSocket server that drives LLMs to turn prompts into 3D geometry and broadcasts the results to every connected player.
Player types a prompt in the Godot client
│ (WebSocket / JSON-RPC)
▼
Bun server runs a content filter, then an LLM "agent"
│ the model streams a list of editor actions:
│ addBox, addSphere, setMaterial, addOmniLight, addParticles, …
▼
Server broadcasts each action as a game event to all players
▼
Every Godot client applies the actions incrementally,
building the model live in the shared world
Rather than asking the model for a mesh file, the server asks it for a sequence of editor actions — primitive operations like "add a box", "add a cone", "apply this material", "add a spotlight", "emit these particles". These are defined as strict Zod schemas in server/tools.ts and streamed token-by-token, so objects appear to assemble themselves piece by piece. The same world is kept in sync across clients by broadcasting and replaying these action events.
- Prompt to create — manifest new 3D objects from text.
- Re-prompt to modify — select an existing object and prompt a change ("make it bigger", "paint it blue").
- Move, duplicate, and delete objects you've created.
- Real-time multiplayer — see other players' avatars, names, positions, and a shared chat log.
- Event replay — players who join late have the existing world rebuilt for them from stored events.
- Content moderation — prompts are screened by a lightweight model before generation.
- Materials, lighting, and particle effects — the model can apply PBR materials (glass, metal, car paint, skin, etc.), add lights, and create particle systems.
- Mobile controls, fall respawn, animated avatars, and a casting "energy beam" effect.
ourcade/
├── server/ # Bun + Hono WebSocket backend
│ ├── index.ts # HTTP/WS entrypoint, static serving, Supabase auth
│ ├── service.ts # JSON-RPC methods called by the game client
│ ├── game-session.ts # Authoritative session state, broadcast & replay
│ ├── events.ts # Game event type definitions
│ ├── connections.ts # WebSocket connection registry
│ ├── model.ts # LLM model configuration (heavy / light)
│ ├── tools.ts # Zod schemas for editor actions (the LLM's toolset)
│ └── agents/
│ ├── new-prompt.ts # "Create" agent — generates a model from a prompt
│ ├── re-prompt.ts # "Modify" agent — edits an existing model
│ └── content-filter.ts # Screens prompts for inappropriate content
│
├── game/ # Godot 4.3 project (the playable client)
│ ├── game.tscn / game.gd # Main scene
│ ├── entities/ # player, avatar, prompt_spawner, energy_beam
│ ├── systems/ # event_bus, server_api, presence, prompt_handler
│ │ └── prompt_handler/ # Applies streamed editor actions to the scene
│ ├── ui/ # hud, chat, prompt input
│ └── assets/ music/ # Art and audio
│
├── frontend/ # Login/landing web app (git submodule)
├── static/ # Static assets served by the server
├── Dockerfile # Bun production image
├── fly.toml # Fly.io deployment config
└── Makefile # Godot web export + frontend build + deploy
Note:
frontend/is a git submodule pointing at the separate3d-prompt-playgroundrepo (the React/Vite login & landing site). Rungit submodule update --init --recursiveto populate it.
| Layer | Technology |
|---|---|
| Game client | Godot 4.3 (GL Compatibility renderer, exported to Web/WASM) |
| Server runtime | Bun + Hono |
| Realtime | WebSockets with JSON-RPC (typed-rpc) |
| LLM integration | Vercel AI SDK (OpenRouter, Anthropic, Google, Bedrock) |
| Schema / parsing | Zod, zod-to-json-schema, best-effort-json-parser |
| Auth | Supabase (session cookie validation) |
| Frontend | React + Vite (submodule) |
| Deployment | Docker + Fly.io |
The server uses two model roles, configured in server/model.ts:
- Heavy model (default: Claude 3.7 Sonnet via OpenRouter) — generates and modifies models.
- Light model (default: Claude 3.5 Haiku via OpenRouter) — fast content filtering.
- Bun (server)
- Godot 4.3 (game client)
- API credentials for your chosen model provider (e.g. an OpenRouter API key)
bun install
bun run dev # watch mode (or `bun run start`)The server listens on port 3000, serves WebSocket connections at /ws, and
serves the game client and static assets over HTTP.
Set provider credentials via environment variables (e.g. OPENROUTER_API_KEY,
ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY). To bypass Supabase
authentication during local development, set NOAUTH=true.
Open the game/ folder in Godot 4.3 and run the main scene (game.tscn).
When running outside the browser, the client connects to ws://localhost:3000/ws.
To play the web build, export the Godot project to the build/ directory (see
the Makefile) and open the app served by the Bun server.
| Input | Action |
|---|---|
| W / A / S / D | Move |
| Mouse | Look around |
| Space | Jump |
| F | Cast a prompt to create an object |
| Q | Cancel a cast in progress |
| Enter | Open / send chat |
| Escape | Pause / toggle mouse capture |
Selecting an existing object lets you re-prompt, move, duplicate, or delete it. Touch controls are available on mobile.
The project deploys to Fly.io as a Bun Docker image
(see Dockerfile and fly.toml). The Makefile
automates the full build:
make deploy # godot web export → build frontend → fly deployIndividual targets:
make release— export the Godot project for web (release).make debug— export the Godot project for web (debug).make web— install and build the frontend submodule.make deploy— runrelease,web, thenfly deploy.
