An agentic studio for 3D RPGs.
Levels, characters, quests, combat and the HUD in one native editor — and a coding agent that builds the world with you. Written in Rust on Bevy, scripted in Lua, and yours.
What's inside.
Agentic by design
Describe a change in plain words. Claude Code, Codex or Gemini CLI edits the level, the editor validates it, and ⌘Z undoes it.
Real 3D, isometric soul
Bevy's 3D renderer behind an orthographic iso camera. Physically based lights, real shadows, flickering torches.
Quests as world state
Main and Side quests whose objectives are facts about the world — defeat every enemy, reach the cave, the gate is open.
Combat and progression
Factions, weapons and skills, enemy factories, experience, and a passive skill tree in the style of Path of Exile.
Lua where it counts
Small Lua 5.4 scripts hook into triggers, hits, loot and AI responses, reading and writing the world through one path syntax.
Your HUD, your way
Life and mana bars, action bar, bag, quest tracker and minimap — pinned to the screen's edges and dragged into place.
Describe it. The agent builds it.
The editor never calls a model itself. It writes the level and an asset catalogue into the project, starts the coding agent you picked, and streams its progress back. A bundled skill teaches the agent the world format, the Lua API and the quest model, so it uses only your assets, places things near the centre of your view, and never renumbers what is already there.
- Claude Code
- Codex
- Gemini CLI
▸ reading .proscenium/agent/assets.json
▸ reading .proscenium/agent/world.json
▸ placing 4 × UAL2_Standard near cell (3,-2)
▸ labels: enemy · attackable · weapon: Bow
✓ Added four archers around the shrine.
Script it in Lua.
Hooks for triggers, hits, loot and responses. Paths like world.entity[12].life autocomplete as you type.
local enraged = false
function on_hit(hit)
if not enraged and hit.life.value <= hit.life.max // 2 then
enraged = true
self_play_clip("Roar", false)
end
if hit.life.value <= 0 then
self_set_attackable(false)
world.vars.gate_open = true
emit("boss_defeated")
end
end
Quests are data.
A level is plain JSON, and its quests live in it — readable by you, writable by the agent.
"quest_book": {
"quests": [{
"id": 1,
"title": "Kill all enemies",
"kind": "Main",
"xp": 250,
"objectives": [{
"goal": {
"kind": "Defeat",
"target": { "Label": "enemy" }
}
}]
}]
}
Rust + Bevy
Native 3D with PBR lights and shadows.
-
Iso camera
Orthographic 3D at the classic 2:1 angle.
src/camera.rs -
Painted ground
Texture layers blended by a splat map.
src/ground_splat.wgsl -
glTF models
Every animation clip, ready to play.
src/model_view.rs
egui
One native macOS window, panels docked.
-
Overlay builder
Custom HUD panels bound to live values.
src/overlay_builder.rs -
Passive tree
Nodes, links and start points.
src/passive_tree.rs -
Audio mixer
Master volume and a 3-band EQ.
src/audio_mixer.rs
Lua 5.4
Embedded through mlua, one state per object.
-
Scripting host
on_load, on_tick, on_collide and more.
src/scripting.rs -
Quests
Event-driven goals over world state.
src/quests.rs -
Agents
Headless coding-agent runs.
src/agent.rs
Help shape Proscenium
Proscenium is a work in progress. Questions, ideas or a game you'd like to build with it — get in touch.