Most engines bolt LLMs on. forge starts there. Every editor menu, hierarchy drag, and inspector edit dispatches through the same JSON command an external agent uses over TCP / MCP / chat. No GUI-only paths, no scripting- only paths. Click and prompt are equal citizens.
# Open the studio
cargo run -p forge-studio
# In another terminal: drive the studio over TCP
echo '{"id":"1","command":{"kind":"ping"}}' | nc 127.0.0.1 7878
# Run the integration test gate (106 end-to-end flows)
cargo run -p forge-studio --example flows
# Full unit test suite
cargo test --workspace
# Connect Cursor / Claude Desktop via MCP (stdio bridge)
cargo run -p forge-mcpThe studio is a Bevy 0.18 editor. macOS / Linux / Windows; needs nothing beyond a working Rust toolchain.
The studio is the engine. There's no separate "engine" library — the editor is the runtime, the agent surface is the editor's TCP server, and every editor action is a documented JSON command.
| Pillar | What you get |
|---|---|
| Editor | Hierarchy with drag-reparent + drop-on-strip sibling reordering (8px highlight-while-dragging accent line, accent-tinted row overlay) + right-click context menu (Unity-style). Inline rename on every spawn. Multi-select + marquee + batch transform. Dual-viewport (Scene + Game both render live, not a tab swap). TRS gizmo with Ctrl-snap. Procedural billboard icons for lights / cameras. Inspector with custom cards + auto-reflected fallback for any registered component. Save / load round-trip via RON. Undo / redo (32-deep snapshot). |
| Stop / Play / Pause | Unity-equivalent semantics. Stop mode pauses every gameplay-runtime system (animator, behaviours, visual scripts, particles, nav agents, cinematics); physics is independent and tracks the toolbar gravity toggle. Pause freezes Time<Virtual> so every delta_secs-driven system halts in lockstep. Play snapshots the saveable allow-list; Stop reverts. |
| Panels | Project tree (assets/ folder browser with right-click reveal / rename / delete / new folder). Profiler (rolling FPS + frame-time + entity-count charts). Build Settings modal (background cargo build + asset copy). Lighting panel (ambient / clear / fog). Audio Mixer (Unity-style group tree with vol / mute / solo). Frame Debugger. |
| Scripting | Behaviour layer: register named Rust handlers (rotator, follow_target, bob, noop); the agent or the inspector attaches one to any entity with JSON params. Hot-attach / hot-detach without restart. |
| Animator | Unity-style state machine (named states + parameter-gated transitions). Scalar keyframe timeline per entity (linear / step / ease). All authoring + playback through MCP. |
| Tilemaps + UI | SavedTilemap (integer-coord tile grids) + SavedUiCanvas (Container / Text / Button / Image trees) with templates (main_menu, pause_menu, hud, game_over). |
| Prefabs | Save any entity-tree to assets/prefabs/<name>.prefab.ron; spawn instances by name with optional position / name override. |
| Physics | Rapier 3D wired with Unity-class per-body editing: kind / mass / drag / angular drag / gravity scale / freeze position+rotation axes / CCD on Rigidbody; friction / bounciness / density / is-trigger / collision layer + filter on Collider. Cuboid / Ball / Capsule / Cylinder / Convex Hull shapes. apply_force / apply_torque / set_velocity / physics_raycast / physics_overlap_sphere / physics_shape_cast over the agent. |
| Audio | Bevy audio integration; spawn AudioPlayer from any path under assets/, optionally parented to an entity (sound follows the entity). Audio mixer groups for vol / mute / solo. |
| Input | Action map: declare "jump" → ["Space", "Mouse:Left", …]; query state per-frame. |
| Materials | SavedMaterial sidecar with base color + metallic + roughness + emissive + base_color_texture + normal_map_texture. Texture changes round-trip through Save / Load (path-based). |
| AI surface | TCP agent server, MCP stdio bridge, two in-editor chat panels (Engine + Game) with audience-gated command sets. 150+ documented commands across Engine, Game, and Both audiences. The Game prompt sees a persisted GameRules body inlined into its system prompt each turn. Replayable transcripts persisted under ~/.forge-studio/sessions/<uuid>.jsonl. |
| Bundle 1 — Essentials | Test Runner panel, Asset Importer, 2D mode + Sprites, Visual Scripting graph, CPU Particles, NavMesh + Agent (grid A*), heightmap Terrain. |
| Bundle 2 — Rendering | Post-FX stack, Shader Graph + WGSL codegen, Reflection Probes, Decals, Lightmap-bake stub, Volumes (Global / Local / Box / Sphere). |
| Bundle 3 — Gameplay | Cinemachine-style virtual cameras, composite input axes, cinematic timelines, localization, addressables, rich text, save slots. |
Full design rationale, file-by-file architecture, and roadmap live in
BUILD_PLAN.md, context/STATE.md,
and context/NEXT.md. Every public agent command is
documented in docs/MCP_REFERENCE.md.
forge-studio opens a TCP listener on 127.0.0.1:7878 (override with
FORGE_AGENT_BIND). Each line is an AgentRequest JSON; each response
is an AgentResponse JSON.
{ "id": "1", "command": { "kind": "spawn_primitive", "primitive": "cube", "name": "Box" } }{ "status": "ok", "id": "1", "message": "spawned Cube as 'Box'", "data": { "name": "Box", "id": 4294967260 } }Errors carry the engine's full error template:
{
"status": "error",
"category": "AGENT",
"message": "rename_entity: new_name collides with another entity",
"expected": "valid scene I/O input",
"got": "Cube_1_1",
"fix": "names must be unique; pick a different name or despawn the colliding entity first"
}The MCP bridge (tools/forge-mcp) wraps the TCP
server in MCP's stdio transport. Drop it into Cursor / Claude Desktop
and the LLM sees every command as a tool with auto-generated parameters.
For the full command reference (every command, parameters, return shape,
errors), see docs/MCP_REFERENCE.md.
| Principle | What it means in code |
|---|---|
| GUI / MCP parity | Every editor click dispatches through agent_server::dispatch_local as the same AgentCommand an external agent would use. No GUI-only side doors. |
| Errors are instructions | [CATEGORY] message / expected / got / fix / context — every error tells the agent the next move. No silent no-ops, no panics on bad input. |
| Text-first | Every authored component round-trips through RON. Save / load / undo / Play snapshot all share one allow-list. Scenes are diffable. |
| One way | One canonical command per operation. RenameEntity, not three different ways to rename. |
| Defaults over config | Spawn primitives take no required parameters. Refine after via set_* commands. |
| Introspection everywhere | list_entities, describe_entity, reflect_query, list_assets, list_prefabs, list_behaviours, list_transcripts, get_diagnostics all live alongside the mutation commands. |
forge-studio is a single Rust desktop binary built on Bevy 0.18 with
the editor chrome painted in bevy_egui. There is no React frontend,
no Electron, no JS / TS / .tsx anywhere in the tree. This is intentional:
- Every editor surface (hierarchy, inspector, chat panels, viewports,
build modal, lighting modal, audio mixer, terrain brush, animator
graph, profiler, project tree, …) renders in a Bevy
EguiPlugincontext. Same process, same memory space, same render graph as the scene the user is editing. - Hot-reload, drag-to-reparent, sibling reordering, inline rename,
marquee select, gizmo drag — all are pure-Rust egui state machines.
No round-trip through a web view, no
postMessageboundary, no separate UI process to keep alive. - The agent surface (TCP
127.0.0.1:7878, MCP stdio bridge, two chat panels) is a transport choice on top of the sameAgentCommandenum the editor itself dispatches. Replacing egui with React in front of the same agent server is technically possible but explicitly not on the roadmap — the rendering / picking / gizmo paths benefit enormously from sharing the Bevy world. egui_dnd,egui_node_graph, and friends were considered for the hierarchy + visual-script + shader-graph panels. We hand-rolled the drag-strip + reorder logic because it shares state with the agent server'sReorderEntitycommand — every drop dispatches through the same MCP handler an external agent would use, which the existing libs don't make easy.
If you want to drive forge from a web app, talk to the TCP server. If you want to build it from scratch with React on top of the same agent surface, fork it — but the upstream is staying with Bevy + egui.
forge/
apps/
forge-studio/ The editor + runtime (Bevy 0.18 + bevy_egui + Rapier)
src/
agent_server.rs TCP listener + dispatch_local studio handlers
behaviours.rs Named-handler scripting layer
billboards.rs Procedural light/camera icons on RenderLayer 31
chat.rs In-editor Anthropic Claude driver
chrome.rs Top-level egui chrome (panels, dual viewport)
hierarchy.rs Tree view + context menu + inline rename
input_map.rs Action-mapped input
inspector.rs Per-component cards + reflect fallback
marquee.rs Rubber-band selection
picking.rs Closest-mesh-wins click selection
prefabs.rs SavedPrefab serialise / instantiate
saved_assets.rs Mesh / Material / Collider / RigidBody sidecars
selection.rs Multi-entity selection
transcripts.rs Per-session JSONL agent log
viewport_textures.rs Render-to-image dual viewport
...
examples/flows.rs 54 end-to-end integration tests
crates/
agent/ AgentRequest / AgentResponse + dispatcher (used by studio + tools)
core/ ForgeError + math primitives
log/ Tracing ring buffer
scene/ RON scene format
editor/ egui chrome shared types
tools/
forge-cli/ CLI agent example
forge-mcp/ Stdio MCP bridge (Cursor / Claude Desktop)
docs/
MCP_REFERENCE.md Every agent command, parameters, returns, errors
context/
STATE.md Snapshot of what's built right now
NEXT.md Priority list of what's next + roadmap
BUILD_PLAN.md Stage gates + design philosophy
Each crate / app is checkable independently with cargo check -p <name>.
Items already done:
- Tier 0 A — Hierarchy w/ drag-reparent + right-click + inline rename + dual viewport
- Tier 0 B — Multi-select + marquee + batch transform
- Tier 0 C — Textured materials + billboard icons
- Tier 0 D — MCP polish + every Unity-style edit reachable as a JSON command
- Engine pillars — Behaviours / Prefabs / Audio / Physics raycast / Input map / Transcripts / Diagnostics / Drag-drop from OS / Console autocomplete / AABB outlines + corner axis indicator
Tier 1+ on the roadmap (see context/NEXT.md):
- Asset thumbnails (textures + meshes), drag-drop preview
- Mesh import settings (per-glb meta.toml: axis, scale, material override)
- Profiler GUI (frame timeline + draw call tree)
- Streaming Claude responses + multi-LLM provider trait
- 2D mode (Camera2d + sprite picking + 2D agent commands)
- Animation tooling (XL — state machine + timeline + curve editor)
- Prefab override semantics, build pipeline, NavMesh / light bake / occlusion bake
| Engine | What it gives you | What forge gives you |
|---|---|---|
| Unity / Unreal | Industry-grade, GUI-driven | Same surface for human + agent. Every operation has a JSON command. |
| Godot | Visual editor, GDScript | No scripting VM — Rust-first; behaviours are named handlers the agent attaches by JSON. |
| Bevy | Mature ECS, plugin ecosystem | + a Unity-class editor + an MCP-first agent surface + saveable sidecars + a behaviour layer + replayable transcripts. |
| plain Cursor / Claude in a Bevy repo | LLM editing your .rs files |
LLM editing your scene at runtime, with hot-reload, undo, screenshots, and visual diffs of its own work. |
forge is aimed at the world where the LLM is the primary user. The human clicks too — both surfaces share one protocol so transcripts are replayable and audits are honest.
Paste into Cursor, Claude Code, or any agent in this repo:
Read context/STATE.md and context/NEXT.md. Pick the highest-priority
pending item from NEXT.md. Implement it; add a flow test in
apps/forge-studio/examples/flows.rs; update context/STATE.md per the
update-docs-as-you-go rule. Run cargo test --workspace, cargo clippy
--workspace --all-targets -- -D warnings, and the flows example
before committing. Follow the existing error template (ForgeError::new
with category/what/expected/got/fix) and the GUI/MCP-parity rule
(every editor click dispatches through agent_server::dispatch_local).
MIT or Apache-2.0 · Built by Ijtihed · Website