rusting_engine 2.0.3

Vulkan 3D game engine with GPU-accelerated physics for massive physics-heavy scenes
# Agent guide

This is a Rusting game project. You can build the whole game from the command
line: scenes are JSON files, game code is plain Rust, and every `rusting`
command takes `--json` for output a program can read.

## Files

- `project.json`: project manifest; `main_scene` is the scene the game loads.
- `scenes/main.rscene`: the scene, as JSON. Edit it with `rusting scene patch`
  rather than by hand, so every change is validated before it is written.
- `src/main.rs`: game code. `update` runs once per frame.
- `assets/`: imported models, textures and sounds.
- `tests/`: scenario files for `rusting test` (create the folder when needed).
- `rusting add scenario <name>` and `rusting add system <name>` scaffold a failing scenario (and a stub function in `src/main.rs`) to fill in.

## Workflow

1. `rusting schema --json` lists every scene section and component with its
   default, fields, units and an example. Read it before writing scene JSON.
2. `rusting scene query scenes/main.rscene --json` lists the entities with
   their IDs. Patches address entities by ID or by unique name.
3. `rusting scene patch scenes/main.rscene patch.json [--dry-run]` applies a
   batch of operations: `create`, `set`, `remove`, `reparent`, `duplicate`,
   `delete` and `set_scene` (scene-level fields). Built-in sections and
   components may be partial; missing fields take their defaults.
4. `rusting check` builds the game code and validates the scene. Project
   commands default to the current folder.
5. `rusting test` runs every scenario in `tests/`, and
   `rusting test tests/name.json` runs one. A scenario presses inputs on given
   ticks, sets values, and checks values; `"exists": false` checks that an
   object is gone, and `tolerance` applies to every number in a position or
   other array. Use `set` to place the player or
   fill a counter before a check, `within` for "eventually by tick N" and
   `until` for "holds every tick through N". Both take an absolute tick,
   not a count. A `pointer` step puts the mouse cursor at a point of the
   view, given as fractions: `{"tick": 1, "pointer": [0.5, 0.5]}` is the
   center.
6. `rusting capture scenes/main.rscene shot.png --tick 60` renders a frame so
   you can look at the result. Scenario files can capture frames too.
   A working game is not done until it looks good: run the polish loop and
   checklist in `rusting docs show guide/look-and-feel` (lighting, palette,
   HUD, shapes, free CC0 models with `rusting scene add-model`).
7. `rusting run` opens the game window. `--ticks N` runs it headless and
   saves the end state to `build/final.rscene`; inspect it with
   `rusting scene query build/final.rscene --json`. Game output (`eprintln!`)
   is in the `--json` result under `game.stderr`.
8. Every error has a code such as `SCENE_CONFLICT`.
   `rusting explain SCENE_CONFLICT` prints what it means, how to fix it and
   an example; `rusting explain` lists every code. A `--json` diagnostic
   also names where the problem is: `file`, `line` and `column` for text
   that did not parse, `scene_location` (a JSON pointer into `file`, such as
   `/entities/3` or `/operations/1` of a patch) and `entity` (`id`, `name`).
   `rusting docs search <words>` and `rusting docs show <id>` read the
   manual and every command offline, for this engine version.
   `skills/rusting-game/SKILL.md` (also `rusting docs show guide/agent-skill`)
   is the full guide for building a game; read it first.
   `rusting docs show sample/<name>` prints a sample game's README and code.
   A diagnostic with a `fix` (a misspelled scene key) is certain:
   `rusting fix --dry-run` lists the fixes and `rusting fix` applies them.

9. A project that points `rusting_engine` at a local `path` builds against
   whatever is in that folder now. If the engine is being edited while you
   work, a build can fail inside the engine or a GPU state hash can change
   between two runs. Run `rusting --version` and rerun before you report a
   failure as a game bug. To hold one engine version, depend on a git `rev`
   or `tag` instead of a `path`.

## Scene basics

- +Y is up and -Z is forward. Units are metres, radians and seconds.
- A mesh is scaled by `transform.scale`, and so is its collider: a unit box
  collider on an entity scaled `[6, 1, 6]` is a 6 x 1 x 6 slab.
- Physics needs `physics_body`, `rigid_body` (`Fixed`, `Dynamic` or
  `Kinematic`) and `collider`. A `sensor` collider only reports touches.
- Gameplay components need no code: `rusting.counter`, `rusting.pickup`,
  `rusting.hud` (text with `{counter}` placeholders), `rusting.tween`,
  `rusting.sound_cue`, `rusting.burst_emitter`, `rusting.player_controller`,
  `rusting.joint`. Components with `requires` wait for that counter to reach
  its target.
- Quads are one-sided: a sprite turned more than 90 degrees about Y
  disappears. Animate 2D sprites with a `Scale` tween instead.
- Player and platformer controllers ride moving platforms (kinematic bodies
  moved by `rusting.tween` or game code).
- The player controller is kinematic: moving bodies do not push it, but it
  pushes dynamic bodies it walks into (`push_bodies`). Handle hazards in game
  code with `touching`, as below; it includes the floor and the wall the
  player stands on or pushes.
- Input actions for the player controller: `player.forward`, `player.back`,
  `player.left`, `player.right`, `player.jump`, `player.sprint`.
- Add your own actions with `rusting.input_action`, for example
  `{"action": "fire", "inputs": ["MouseLeft", "KeyF"]}`. Key names are winit
  `KeyCode` names; gamepad inputs are `PadSouth` (A), `PadEast`, `PadStart`,
  `PadDpadUp`, `PadLeftStickUp` and so on. Scenarios press the action by name. `pressed` is true
  only on the tick an action goes down; a scenario `tap` step presses and
  releases, so several taps give several edges.
- Menus use egui through `scene.ui()`. A scenario `click` step clicks a
  button by its label. Saves go through `scene.save_data` and
  `scene.load_data`. `rusting docs show guide/menus-and-ui` covers menus,
  pause, quit, saves, rebinding and their tests.
- `rusting docs show api/PlayerController` lists the controller's fields.
  `turn_speed` turns the body's non-camera children (the visible rig)
  toward the walking direction.
- A `rusting.particle_emitter` is the full particle effect (fire, smoke,
  snow, sparks); `rusting effect list` lists ready presets and
  `rusting docs show guide/effects` covers its fields.
- A `rusting.burst_emitter` with `rate` emits continuously over its `area`
  box; `stretch` makes tall particles such as rain streaks.
- A dynamic body with a `ConvexMesh` collider collides as the convex hull
  of its mesh: a `Cylinder` mesh makes a rolling barrel.
- `rusting.animation` plays keyframe clips (position, rotation, scale,
  color, emissive, visible, numeric fields) on an object and its named
  children, with `transitions` between clips driven by
  `set_animation_parameter`, 1D/2D blend spaces, masked override or
  additive `layers`, `root_motion` (`scene retarget` copies clips between
  skeletons), `rusting.ik` makes a joint look at or
  reach a target object, and `rusting.ragdoll` hands bones to physics on
  a hit or `set_ragdoll` and blends them back (`muscle` above 0 keeps
  them physical and following the clips: an active ragdoll); `rusting docs show guide/animation` covers it. `scene
  add-model` keeps a glTF's node animations as clips, and a skinned
  glTF's skin as `rusting.skin` and blend shapes as `rusting.morph` (both
  on the CPU; keep to a few characters).
  Without a rigged model, build characters from child entities and key
  them.

## Game code

```rust
use rusting_engine::prelude::*;

fn update(scene: &mut GameScene<'_>, time: &FrameTime) {
    // Objects are found by their scene name.
    let hit = scene.touching("Player").iter().any(|name| name == "Spikes");
    let mut player = scene.object("Player");
    // FrameTime: delta_seconds() and elapsed_seconds() are methods;
    // fixed_tick and frame are fields.
    player.rotate_y(1.5 * time.delta_seconds());
    if hit || player.position()[1] < -5.0 {
        player.set_position([0.0, 1.0, 0.0]);
    }
}

rusting_game!(update);
```

`GameScene` finds objects by name (`object`, `try_object`), moves them
(`set_position`, `move_by`, `set_rotation`, `set_scale`; `position`,
`rotation` and `scale` read them back), reports contacts (`touching`), reads
and changes counters (`counter`, or the shorthands `counter_value`,
`set_counter`, `add_to_counter` and `counter_complete`), reads input actions
(`pressed` for this frame, `held`), casts rays (`raycast`, and `aim` along the
active camera; `camera_ray` gives that camera's position and forward
direction, `pointer_ray` the ray through the mouse cursor), launches bodies
(`set_body_kind`, `set_linear_velocity`, `set_angular_velocity`; each wakes a
sleeping body, and a body made `Kinematic` or `Fixed` stops) and reads their
velocity (`linear_velocity`, `angular_velocity`), stops a body completely
(`reset_body`), turns a player controller (`set_look`) and reads its
state (`player`: grounded, floor, wall, velocity), reparents objects
(`reparent`), changes a light (`set_light`), removes objects
(`despawn`), shows and
hides them and their HUD text (`set_visible`), recolors one object without
touching others that share its material (`color`, `set_color`,
`set_emissive`), reloads the starting scene for a new round (`restart`;
physics after it repeats the first run exactly), reads an object's starting
transform, color and body kind (`initial`), saves and puts back the whole
scene mid-game (`snapshot`, `restore`), hashes the state of one class to
compare rounds (`state_hash`), reads
and writes `rusting.tile_map` cells under a world position (`tile`,
`set_tile`), plays sounds (`play_sound`, `play_sound_looped`,
`stop_sound`, `set_master_volume`; clips are WAV, Ogg, MP3 or FLAC paths under
`assets/`), fires sound cues and burst emitters (`trigger`), spawns shapes
(`spawn_cube`, `spawn_sphere`), copies a hidden template object with its
children (`spawn_copy`; a copied child is named `"<copy>/<child>"`), lists the
objects in a class (`in_class`), runs setup once per round (`once`; `restart`
runs it again), draws random numbers that repeat for a scenario's seed
(`random`), switches to another scene file such as a next level
(`load_scene`, with a path relative to the project folder) and draws UI (`ui`,
an egui context). `world()` gives the ECS world for anything else.
`cargo doc --open` documents the full API.