doloro 2c3b670ab9 Add animation store for pre-made clips
aac.AnimationStore(folder) seeds a clip from an existing .anim asset and
returns a normal ClipBuilder, so pre-made clips work anywhere generated
clips do and can still be edited (looping, keyframes, toggles, blend
shapes). The Unity side clones the asset into the container and applies
the script's changes to the clone, leaving the original untouched.

- ClipData gains optional source; looping becomes Option<bool> so an
  untouched store clip keeps the asset's own looping setting.
- Add rust/examples/animation_store.rhai, a worked store example.
2026-09-18 14:52:02 +01:00
2026-09-18 14:01:10 +01:00
2026-09-18 14:01:10 +01:00
2026-09-18 14:01:10 +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
633 KiB
Languages
C# 80.8%
Rust 18.7%
Nix 0.5%