rusting_engine 1.4.0

Vulkan 3D game engine with GPU-accelerated physics for massive physics-heavy scenes
docs.rs failed to build rusting_engine-1.4.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: rusting_engine-0.1.43

RustingEngine

10,000 GPU-simulated cubes at more than 2,000 FPS on an RTX 3060. RustingEngine is built for physics-heavy scenes that can overwhelm traditional CPU-first engines long before the GPU is fully used.

10,000 cubes orbiting a planet at 2,191 FPS

The screenshot shows the current native space demo in a 1920×1080 release build. All 10,000 satellites are rendered through instancing and updated with Vulkan compute rather than 10,000 CPU-side object updates.

Benchmark Value
Scene One planet and 10,000 moving cubes
Measured result 2,191 FPS / 0.5 ms frame time
GPU NVIDIA GeForce RTX 3060 12 GB
CPU AMD Ryzen 5 7600X, 6 cores / 12 threads
Memory 16 GB RAM
Operating system CachyOS Linux
Resolution 1920×1080
Captured utilization 35% GPU / 9% CPU
Build Native Rust release build, measured with MangoHUD

This is a measurement of one deliberately GPU-friendly stress scene, not a promise that every game will run at the same speed. Performance depends on the solver, shaders, visible geometry, hardware, and gameplay work.

Why RustingEngine exists

Most game engines keep authoritative physics on the CPU. That is useful for gameplay queries, but it becomes expensive when thousands of independent bodies must be updated. RustingEngine uses a hybrid model:

  • CPU simulation is available for objects that need immediate gameplay access.
  • Vulkan compute handles large effect, debris, crowd, and simulation workloads.
  • GPU conditions return small, meaningful events to Rust without downloading every body transform—for example, when any member of a class enters an area.
  • Instanced batches keep thousands of equal meshes from becoming thousands of draw calls.

The goal is not to move everything blindly to the GPU. The game chooses which objects need CPU authority, which can stay GPU-owned, and what information must cross between them.

What is included

  • Rendering: a Vulkan renderer with PBR materials, lights, shadows, instancing, indirect drawing, and GPU frustum culling.
  • Physics: fixed-step CPU and GPU physics with built-in and custom compute shaders, stable GPU body IDs, object classes, and GPU conditions that send small events back to Rust.
  • Determinism: a per-project determinism mode, seeded random streams, a world-state hash for every tick, replays, and rusting determinism to find the first tick where two runs differ. See Determinism.
  • Game code: ordinary Rust with any Cargo dependency, ECS systems, named input actions, and your own components saved in scenes through the reflect! macro.
  • Editor: Blender-style areas, Hierarchy, a typed Inspector, asset import, a transform gizmo with snapping, in-editor Preview, native Play, a Rust and GLSL code editor, rebindable shortcuts, and a Profiler.
  • Command line: the rusting tool creates, checks, runs, tests, captures, and exports projects with no window, and edits scenes with patches. rusting schema lists every command and component field.
  • Scenes and export: versioned text scenes with field migrations, cooked runtime scenes, and self-contained game exports.
  • Linux and Windows CI and release packages.

The engine is suitable for experiments, stress scenes, and early games. The editor and physics APIs are still growing; see the changelog for each release and the roadmap for what comes next.

Quick start

You need stable Rust and a Vulkan-capable driver. Linux and Windows are the primary platforms.

New to the engine? Follow Getting started and the tutorials.

git clone https://github.com/GoingRusting/RustingEngine.git
cd RustingEngine
./scripts/run_editor.sh

To run the included 10,000-cube space project without the editor:

cd testGame
mangohud cargo run --release

To run the original renderer stress test:

cargo run --release -p rusting_engine --bin user_main

The editor creates complete Rust projects in a directory you choose. Play saves and cooks the scene, compiles the game's Rust code, and starts a separate native window. Debug mode compiles quickly during development; Release enables the settings used for performance measurements.

Headless project CLI

The rusting binary creates, checks, builds, runs, exports, and captures projects without opening the editor. Only capture uses Vulkan. Run these examples from the engine checkout:

cargo run --bin rusting -- doctor --json
cargo run --bin rusting -- new /tmp "My Game" --json
cargo run --bin rusting -- new /tmp "My Platformer" --template 2d --json
cargo run --bin rusting -- new /tmp "Coin Run" --template starter --json
cargo run --bin rusting -- project inspect "/tmp/My Game" --json
cargo run --bin rusting -- scene inspect "/tmp/My Game/scenes/main.rscene" --json
cargo run --bin rusting -- scene query "/tmp/My Game/scenes/main.rscene" --name Cube --json
cargo run --bin rusting -- scene query testGame/scenes/main.rscene --class camera --json
cargo run --bin rusting -- scene patch "/tmp/My Game/scenes/main.rscene" /tmp/patch.json --dry-run --json
cargo run --bin rusting -- validate "/tmp/My Game" --json
cargo run --bin rusting -- cook "/tmp/My Game" --json
cargo run --bin rusting -- check "/tmp/My Game" --json
cargo run --bin rusting -- run "/tmp/My Game" --ticks 120 --json
cargo run --bin rusting -- test "/tmp/My Game" /tmp/falls.json --json
cargo run --bin rusting -- export "/tmp/My Game" /tmp/exports --json
cargo run --bin rusting -- capture "/tmp/My Game/scenes/main.rscene" /tmp/shot.png --tick 60 --pick 640,360 --json
cargo run --bin rusting -- asset import "/tmp/My Game" art/crate.png --to props --license CC0-1.0 --json
cargo run --bin rusting -- asset reimport "/tmp/My Game" assets/props/crate.png --from art/crate_v2.png --json
cargo run --bin rusting -- asset list "/tmp/My Game" --json
cargo run --bin rusting -- asset generate "/tmp/My Game" icons "red crate" --to props --dry-run --json
cargo run --bin rusting -- preset apply "/tmp/My Game/scenes/main.rscene" golden_hour --json
cargo run --bin rusting -- schema --json
cargo run --bin rusting -- scene query --help

--json returns one object with schema_version, ok, data, and diagnostics; failures still print JSON and exit nonzero. Exit code 2 means invalid arguments, and exit code 1 means a project, scene, or operation error. Scene queries also accept --id, --class, and --component. Query results include full entity component data in persistent ID order. A missing Vulkan device is reported by doctor and does not block the other commands.

run reports timings: the build time, the game's own time to its first playable frame, and the command-to-first-frame total. A failed build lists each Rust or shader error as its own diagnostic with file and line (RUST_BUILD_ERROR, SHADER_BUILD_ERROR), and asset hot reload failures the game printed come back as ASSET_RELOAD_FAILED warnings. The editor's Play and Restart write the same timing and per-file errors to the Console.

check runs cargo check on the game. run cooks, builds, and starts the game; --ticks N runs N fixed ticks without a window and exits. export builds a release, packages it like the editor's Export, and then runs a copy for 60 headless ticks from a fresh temporary folder to verify it. capture renders one camera (--camera takes a persistent ID or a name) after N fixed ticks to a PNG. Each --pick X,Y returns the persistent ID, name, and world position of the object under that pixel, found by ray casting against mesh bounds. Game code does not run during a capture. Without Vulkan, capture still reports the camera and picks, with a VULKAN_UNAVAILABLE error.

schema prints a catalog of every command (usage, flag defaults, an example, and GPU/readback cost), every scene entity section and registered component (default value, an example, and each field's unit and valid range), and the scenario format. Defaults come from the engine's own Default values saved through the scene writer, and tests keep the field list, the examples, and the component registry in step.

Scene patches

scene patch <scene> <patch.json> [--dry-run] applies a batch of operations to a scene as one unit:

{
  "expected_revision": "3f0c1a2b4d5e6f70",
  "operations": [
    {"op": "set", "id": "UUID", "path": "/transform/position/1", "value": 2.0, "expected": 1.0},
    {"op": "create", "entity": {"name": "Crate", "parent": null}},
    {"op": "duplicate", "id": "UUID", "name": "Cube Copy"},
    {"op": "reparent", "id": "UUID", "parent": null},
    {"op": "remove", "id": "UUID", "path": "/collider"},
    {"op": "delete", "id": "UUID"}
  ]
}

Entities are addressed by persistent ID; paths are JSON pointers into the entity's scene form with registered components parsed, as in scenario expect paths. Either every operation succeeds and the result passes the scene loader's checks (types, unique IDs and names, parents, and built-in component values), or nothing is written. The result lists created and deleted IDs and every changed field with its old and new value. scene inspect and scene query report the file's revision; a patch whose expected_revision or per-field expected value no longer matches fails with SCENE_CONFLICT.

An open editor watches its scene file. When it has no unsaved edits it reloads an outside change behind an Undo step, so Undo reverts it. With unsaved edits it keeps them and reports the conflict, and the next Save refuses once before it overwrites the outside change.

Scenario tests

test builds the game and runs a scenario file inside it without a window. The game's own systems run, one fixed step per tick, with RandomSeed set from seed. Steps run at fixed ticks:

{
  "name": "cube falls",
  "seed": 3,
  "ticks": 60,
  "capture_size": [640, 360],
  "steps": [
    {"tick": 5, "press": "jump"},
    {"tick": 6, "release": "jump"},
    {"tick": 30, "expect": {"entity": "Cube", "path": "/transform/position/1", "less_than": 0.0}},
    {"tick": 0, "until": 60, "expect": {"entity": "Cube", "path": "/transform/position/1", "greater_than": -9.0}},
    {"tick": 60, "expect_events": {"kind": "collision", "entity": "Cube", "at_least": 1}},
    {"tick": 30, "capture": "shots/tick30.png"}
  ]
}
  • press and release act on every input bound to a named action in ActionMap. They apply before that tick's update.
  • expect reads a JSON pointer from the entity's scene form, the same JSON that scene query prints. Registered components are parsed, so paths such as /components/<type>/<field> work. Use equals (with tolerance for numbers), greater_than, or less_than. With until, the check runs on every tick through that one.
  • expect_events counts events that gameplay saw from tick 0 through this tick. collision is the only kind for now.
  • capture writes a PNG relative to the scenario file. Without Vulkan, it is skipped rather than failed.

The run stops at the first failed step. A failure exits 1 with SCENARIO_FAILED and the message tick T step S: .... The JSON report, including the value the failed check saw, is under data.scenario. Game binaries run a scenario themselves when RUSTING_TEST_SCENARIO names the file; they write the report to RUSTING_TEST_REPORT.

Small Rust gameplay API

A game project is a normal Cargo project. Simple behavior stays short, while advanced projects can use ECS systems and any compatible Rust crate directly.

use rusting_engine::prelude::*;

fn update(scene: &mut GameScene<'_>, time: &FrameTime) {
    scene.object("Planet").rotate_y(0.2 * time.delta_seconds());
}

rusting_game!(update);

The game-feel kit is plain scene data plus Rust APIs, so scene patch, scenarios, and the inspector all reach it: rusting.player_controller (a first-person body with a child camera, driven by player.* actions in ActionMap), rusting.tween (eased position, rotation, or scale), rusting.sound_cue (sends a SoundEvent on contact or trigger(); the game plays it, since the engine has no audio output yet), rusting.burst_emitter (short-lived particles on contact or trigger()), and rusting.hud (text or a button that sends HudButtonPressed). rusting schema lists their fields.

Imported assets get a <file>.rmeta sidecar with a stable ID that survives asset reimport, import settings (--max-size for images), the glTF's buffer and image dependencies, a content hash, and source/license provenance. asset list and validate report missing files and dependencies; asset list also warns about missing licenses, files changed since import, and files that were never imported. WAV and Ogg files import as audio. --dry-run previews an import or replacement without writing; the editor's Assets area uses the same preview for its Replace… action.

determinism in project.json (Off by default, Local, or CrossPlatform) asks the simulation to reproduce itself on one machine or on every device. cook copies it into the cooked scene, the game refuses to start when a solver or system does not support it, and validate names each such part. Built-in solvers support Local today. A custom compute shader states its level with a // rusting: determinism = local line, and game systems declare theirs through DeterminismSupport. docs/determinism.md lists the math rules behind CrossPlatform.

Generator hooks are optional. A project may list commands under generators in project.json, for any tool or model service:

"generators": {"icons": {"command": ["python3", "tools/make_icon.py"],
                         "license": "CC0-1.0", "settings": {"max_size": 256}}}

asset generate <project> <hook> <prompt> runs the command from the project root with RUSTING_PROMPT and an empty RUSTING_OUTPUT_DIR. The command writes a file there and prints a last line such as {"file": "icon.png", "author": "..."}. The file then goes through the normal importer (or replaces --replace ASSET), and output without a license is rejected.

preset apply writes a starter look (daylight, golden_hour, night, flat_toy) as ordinary scene data: sun, ambient and sky light, tone mapping, rusting.background, camera field of view, and HUD text size and color.

For 2D games, new --template 2d creates a side-view platformer. Sprites are MeshRenderers with the Quad primitive and an unlit material, the camera is orthographic, rusting.tile_map turns text rows into tiles with one box collider per solid run, and rusting.platformer_controller runs and jumps with the player.* actions. Physics stays 3D in the XY plane.

new --template starter creates Coin Run, a complete small 2D game built from the same scene data: five coins with rusting.pickup, a rusting.counter shown by a HUD line such as Coins {coins}/5, and a flag pickup that requires every coin before it counts as a win and shows the "You win!" HUD element. rusting capture paints HUD text over the frame. samples/starter_game/ holds the one-paragraph request and the winning scenario; the acceptance exercise replays the whole create, patch, run, capture, test, and export loop through the CLI and writes a timing report:

RUSTING_ACCEPTANCE_REPORT=/tmp/starter.json \
  cargo test --test starter_game -- --ignored --nocapture

Presets tone-map and restyle the HUD of 2D unlit art too, so the exercise corrects the background and tone mapping with a scene patch afterwards.

Procedural objects can share a class, material, mesh, and GPU physics profile. GPU rules can then watch that class and send only matching events back to Rust. See the included space project and hybrid GPU example for complete examples.

Project layout

  • crates/rusting-core — ECS app, schedule, time, input, and events, with no rendering
  • src/runtime — scenes, hierarchy, snapshots, and hybrid physics
  • src/rendering — Vulkan context, compute profiles, and scene renderer
  • src/reflect — the reflect! macro and the field descriptions that scene saving, the Inspector, and rusting schema share
  • src/editor — the editor and its shared GUI widgets
  • src/cli.rs, src/bin/rusting.rs — the rusting command-line tool
  • src/project_runner.rs — the short native Rust game API and game window
  • testGame — the 10,000-cube space project shown above
  • samples — the starter game and the vertical-slice sample
  • benchmarks — render benchmark baselines
  • docs — getting started, concepts, tutorials, and guides

More documentation:

Contributing

Bug reports, profiling results, documentation fixes, and focused pull requests are welcome. Please read CONTRIBUTING.md before opening a PR. Performance changes should include the scene, hardware, resolution, build mode, and before/after measurements so results can be reproduced.

License

RustingEngine uses the Rusting Engine License 1.0. Games and other created works may be commercial. Redistribution of the engine is subject to the license terms and attribution requirements.