doloro c4ed44e00b
ci / Nix flake checks (push) Successful in 9s
release / Publish VPM release (push) Successful in 12s
ci: run the vpm scripts through bash
The nix runner has no /usr/bin/env, so the '#!/usr/bin/env bash' shebang
cannot resolve; invoke the scripts as arguments to bash instead.
2026-09-19 17:52:06 +01:00
2026-09-18 14:01:10 +01:00
2026-09-19 16:09:21 +01:00
2026-09-18 14:01:10 +01:00
2024-07-01 23:21:17 +02:00
2026-09-18 13:06:03 +01:00

Animator As Crab

A hard fork of Animator As Code where animator controllers are written in Rhai instead of C#.

A Rhai script is evaluated by a Rust library (libaac), which validates it and emits the whole controller as JSON. A Unity Editor window deserializes that JSON and builds a real AnimatorController through the original Animator As Code V1 library, which is left untouched.

script.rhai --> libaac (Rust) --JSON--> AacCrabWindow (Unity Editor) --> AnimatorController

Layout

Path Contents
rust/ The Rhai DSL, graph model, validator, and the libaac cdylib.
rust/examples/avatar.rhai The reference script, exercising every feature of the DSL.
csharp/dev.doloro.animator-as-crab/ The Unity package: the untouched Animator As Code V1 library and the bridge in V1/Editor/Crab/.
flake.nix Dev shell with the Rust toolchain, dotnet, mono, and jq.

Building

nix develop
cargo test --manifest-path rust/Cargo.toml
cargo run --bin aac-dump -- rust/examples/avatar.rhai    # print the generated JSON
nix build .#aac                                          # libaac.so + aac-dump

Copy libaac.so (or libaac.dll, libaac.dylib) into the Unity project's Assets/Plugins folder, and add csharp/dev.doloro.animator-as-crab to the project's packages.

Writing a script

let aac = AnimatorAsCode();
aac.system_name("MyAvatar");
aac.asset_key("AAC_");

let speed = aac.float_param("Speed", 0.0);
let ctrl = aac.new_controller();
let base = ctrl.layer("Base");

let idle = base.state("Idle", 0, 0);
let walk = base.state("Walk", 1, 0);

let walk_clip = aac.clip("walk_anim");
walk_clip.toggle("Body/Props", true);

walk.set_clip(walk_clip);
idle.transition_to(walk).when(speed > 0.1).no_exit_time().duration(0.25);

Conditions are written on the parameters themselves (speed > 0.1, is_sitting == true). There is no && or || — Rhai's are short-circuit built-ins that cannot be overloaded — so use when_all([speed < 0.05, is_sitting == false]).

See rust/examples/avatar.rhai for the full surface: parameters, clips, curves, blend trees, sub-state machines, any-state transitions, and transition settings.

Pre-made clips (animation store)

An animation store seeds clips from AnimationClip assets that already exist in the project. store.clip(name) resolves to <folder>/<name>.anim and returns a motion usable anywhere a generated clip is: as a state motion, as a blend tree child, or through add_motion_direct. A store clip can be edited like any other clip.

let store = aac.AnimationStore("Assets/Doloro/Clips");
let walk = store.clip("Walk");          // Assets/Doloro/Clips/Walk.anim
walk.looping(true);
walk.keyframe("Body/Props", "m_IsActive", 0.0, 0.0);
walk_state.set_clip(walk);
locomotion.add_motion(walk, 0.0);

The generator loads the asset with AssetDatabase.LoadAssetAtPath, clones it into the asset container, and applies the script's keyframes and looping on the clone: the pre-made asset is never modified. A store clip with no looping(...) call keeps the source asset's own looping setting. Requesting the same asset twice reuses the one reference, and a missing asset is a clear error.

Generating

Open Tools > Animator As Crab and fill in the window:

  • the path to the .rhai script (it is watched, so saving the script regenerates the controller),
  • the AnimatorController to generate into,
  • the animator root, the asset container, and the container mode,
  • whether states should write defaults.

Nothing is defaulted silently, and the controller is rebuilt with Animator As Code's modification API: the controller is cleared, and the clips and blend trees of the same asset key are removed from the container before being recreated. Animator As Code's own C# API is untouched and still usable on the same controller.

Limitations

  • The Unity side has not been run: there is no Unity project in this repository, so the bridge and the generator are verified by reading, not by executing.
  • Blend trees can only nest a blend tree that was declared earlier in the script.
  • The graph carries no avatar masks, layer weights, state behaviours, or parameter drivers yet.
S
Description
No description provided
Readme MIT
692 KiB
2026-09-19 20:52:06 +04:00
Languages
C# 79.4%
Rust 18.3%
Shell 1.3%
Nix 0.9%
Just 0.1%