Manual

How it works

Tassix is a native engine in Rust with a managed layer in C# on top: the Rust side owns the process, the world and every system; the C# side is the Unity API scripts are written against.

            game scripts (MonoBehaviours, ScriptableObjects, jobs)
                                  │
   UnityEngine.CoreModule, Input System, uGUI, TextMeshPro, URP, ...   (C#, dotnet/)
                                  │  NativeApi: a table of function pointers,
                                  │  and shared views of world arrays
   tassix_script_host ─ world ─ render ─ physics ─ physics2d ─ navigation ─ audio ─ assets   (Rust, crates/)
                                  │
                     player, MCP server, headless editor   (apps/)

The native side

  • World (crates/world): GameObjects and their hierarchy in dense arrays; world transforms update in parallel once per frame, after scripts.
  • Rendering (crates/render): wgpu (Vulkan or Direct3D 12 on Windows). Physically based forward shading with shadows, HDR and post-processing, GPU culling into indirect draws, bindless materials, mesh LODs, 2D lights, particles and UI. With a window, rendering runs on its own thread one frame behind the simulation.
  • Shaders (crates/shaderlab): projects' own .shader files. ShaderLab is parsed, the HLSL programs compile through DXC (fetched by the build) to SPIR-V and naga to WGSL, against Tassix's versions of Unity's include files, and what they read is reflected for the renderer to bind. Compiled programs are kept in the asset cache, so DXC runs only for new or edited shaders.
  • Physics: PhysX for 3D (crates/physics) and Box2D 2.4 for 2D (crates/physics2d), the engines Unity's physics run on.
  • Navigation (crates/navigation): Recast and Detour, baked and queried as Unity's navigation does.
  • Audio: decoding with symphonia, output through cpal.
  • Assets (crates/import, crates/assets): glTF and FBX import, and a cache of cooked models and images (memory-mapped rkyv archives) with background streaming.
  • Jobs (crates/jobs): the worker threads the C# Job System and the engine's own parallel work share.

The managed side

dotnet/ reimplements UnityEngine and the packages most games use, as assemblies named as Unity's are, so scripts and precompiled plugins bind to them unchanged. A Unity object is a thin C# object holding a handle to native state: setting transform.position calls into Rust, while hot reads go through shared views of the world's arrays without a call. The player loop (FixedUpdate, Update, coroutines, LateUpdate, deferred destruction) runs in C#, calling scripts through callback tables a source generator writes at compile time.

Where they meet

tassix_script_host starts .NET through hostfxr (or loads a NativeAOT build of the managed side as a native library), hands it the NativeApi table (about 160 functions, versioned so a mismatched build fails at start), and calls one managed function per frame. Everything runs on the engine's main thread, as in Unity; worker threads run jobs and the engine's own parallel systems.

Tools around it

  • Player (apps/player): windowed, headless, screenshot, benchmark and conformance runs.
  • Editor core (crates/editor_core): commands with undo and redo, and change events, shared by the MCP server and the headless editor CLI.
  • MCP server (apps/mcp): the editor and a play session over MCP, with the review panel (see agents).
  • Conformance (conformance/): scenarios that run in Unity and in Tassix and must record the same traces (see the suite).
  • Benchmarks (bench/): scenes with frame-time budgets CI enforces, and the same scenes in a Unity player for comparison.

From docs/architecture.md in the repository.