Skip to content

Ijtihed/forge

forge.

An engine where the LLM is the user. Not LLM-assisted. LLM-first.

Built with Rust 453+ tests MCP-first MIT OR Apache-2.0

forge-ten-sigma.vercel.app


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.

Quick Start

# 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-mcp

The studio is a Bevy 0.18 editor. macOS / Linux / Windows; needs nothing beyond a working Rust toolchain.


What's in the Box

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.


The MCP / Agent Surface

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.


Design Principles

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.

Tech stack

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 EguiPlugin context. 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 postMessage boundary, 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 same AgentCommand enum 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's ReorderEntity command — 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.

Repo Layout

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>.


What's Next

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

Why Not X?

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.


Let AI Set It Up

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

About

Rust + Vulkan, agentic-first game engine. Private; in-progress.

Resources

License

Unknown and 2 other licenses found

Licenses found

Unknown
LICENSE
Unknown
LICENSE-APACHE
MIT
LICENSE-MIT

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors