Rigby2DDocs

Shipping

Runtimes

Rigby2D animations play in games and apps through the included runtimes. All of them load skeleton .json (3.8, 4.2, 4.3) or binary .skel (4.3) with an .atlas, and evaluate meshes, weights, skins, image sequences, clipping, IK, transform, path, physics and slider constraints, draw order, events and layered tracks with crossfades. They also play scenes: several characters on a stage with a moving camera and parallax.

RuntimeLanguageStatus
JavaScript (src/core) + WebGL renderer (src/webgl)JavaScript, no dependenciesComplete
Rust (runtimes/rust/rigby-runtime)Rust, no dependencies; 3 to 4× fasterComplete
Unity (RigbySkeleton, RigbyScene)C#, every platform Unity builds for; multi-core, no garbageComplete
Godot (RigbySkeleton2D, RigbyScene2D)GDExtension on the Rust corePreview

The landing page of the website plays NILA with the JavaScript runtime.

#JavaScript

Copy src/core/ into your project (and src/webgl/ for a ready-made renderer):

import { AnimationState, Pose, parseAtlas, readSkeletonJson } from './core/index.js';
import { WebGLRenderer } from './webgl/renderer.js';

const { skeleton } = readSkeletonJson(JSON.parse(jsonText), 'hero'); // hero.json
const pose = new Pose(skeleton);
const state = new AnimationState();
state.play(skeleton, 'walk', true, 0.2);              // track 0, 0.2 s crossfade
state.setAnimation(skeleton, 1, 'shoot', false, 0.1); // track 1 layers on top
state.addAnimation(skeleton, 0, 'idle', true, 0.3);   // queued after walk

const renderer = new WebGLRenderer(gl);
const textures = renderer.atlasTextures(parseAtlas(atlasText), { 'hero.png': pageImage });

function frame(dt) {
  state.update(skeleton, dt);
  state.apply(skeleton, pose);
  renderer.begin(canvas.width, canvas.height, { x: 0, y: 200, zoom: 1 });
  renderer.drawSkeleton(skeleton, pose, textures);
  renderer.end();
}

For .skel files use readSkeletonJson(readSkeletonBinary(bytes), 'hero'). With another renderer, draw pose.quads(skeleton): world-space positions (Y up), UVs, tint and blend mode per region and mesh. examples/webgl.html is a small player (npm run web:dev, then open /examples/webgl.html).

#Events

state.addListener({
  start: (entry) => {},
  complete: (entry) => {},
  event: (entry, e) => playSound(e.audio ?? e.name, e.volume), // { name, time, int, float, string, audio, volume, balance }
});

Physics simulates while AnimationState updates; pose.resetPhysics() starts it over.

#Rust

use rigby_runtime::{load_skeleton, Atlas, AnimationState, Pose, RegionLookup, RenderOutput};

let data = load_skeleton(&std::fs::read("hero.skel")?)?;
let atlas = Atlas::parse(&std::fs::read_to_string("hero.atlas")?);
let lookup = RegionLookup::new(&data, &atlas);
let (mut pose, mut state, mut out) = (Pose::new(&data), AnimationState::new(), RenderOutput::default());
state.play(&data, "walk", true, 0.2);

// Every frame:
state.update(&data, dt);
state.apply(&data, &mut pose);
out.build(&data, &pose, &lookup, [1.0; 4]);
for batch in out.batches() { /* positions, UVs, colors, indices for atlas page `batch.page` */ }

Scenes: rigby_runtime::scene::load_scene(&manifest, |file| std::fs::read(dir.join(file))) returns a ScenePlayer (play, update, draw_list).

It matches the JavaScript runtime frame by frame (golden tests, including a scene). Build and test with cargo test --release --workspace in runtimes/rust. See the runtimes README.

#Unity

The com.rigby2d.unity package for Unity 2021.3 or newer (Unity 6 included), Built-in or Universal render pipeline. In Unity: Window ▸ Package Manager ▸ + ▸ Install package from git URL…

https://github.com/jaisurya-dev-art/rigby2d.git?path=/runtimes/unity/com.rigby2d.unity

Drop an export (.skel or .json, .atlas and its .png) into Assets: the .atlas becomes a skeleton asset. Drag it into the scene, pick an animation, and it plays (in the editor too). Scenes exported with File ▸ Export ▸ Scene for runtimes import the same way and play with the RigbyScene component, which can drive a camera.

var hero = GetComponent<RigbySkeleton>();
hero.Play("walk", loop: true, mix: 0.2f);
hero.AddAnimation(0, "idle", loop: true, mix: 0.3f);
hero.AnimationEvent += (s, e) => { if (e.Name == "footstep") step.Play(); };
gun.position = hero.GetBoneWorldPosition("gun-tip");
  • Every core, no garbage: playing skeletons pose and build their meshes in parallel, and steady playback allocates nothing. 200 NILAs (39 bones, 1,002 skinned vertices each) take 5.0 ms a frame in an IL2CPP player on a 4-core laptop, upload included: 25 µs a character.
  • Tested in Unity 6.3 (Built-in and Universal render pipelines) and 2022.3, in IL2CPP and Mono players.
  • Clean edges in Gamma and Linear color space: the shader handles straight or premultiplied atlases itself, with two-color tint and every blend mode.
  • The same animation as the editor: the C# runtime is tested frame by frame against the JavaScript runtime, like the Rust one.

See the Unity guide for every component, property and event.

#Godot

The RigbySkeleton2D node for Godot 4.3+ (preview; prebuilt for Windows x64, build from source elsewhere). Install the rigby2d-godot-addon zip from the Releases into your project, add the node, and set Skeleton File, Atlas File and Animation.

@onready var hero: RigbySkeleton2D = $Hero

func _ready() -> void:
	hero.animation_event.connect(_on_event)
	hero.play("walk", true, 0.2)
	hero.queue(0, "idle", true, 0.3, -1.0)

For scenes, the RigbyScene2D node plays a .scene.json export: the stage, every character and their clips, with the stage's camera available for a Camera2D. See the Godot guide for every property and method.

#Performance

One character, one frame (apply, constraints, world transforms and vertices), median of 2,000 frames:

RigJavaScriptRust
67 bones, 276 mesh vertices50 µs14.5 µs
76 bones, 667 weighted vertices, 9 IK71 µs22 µs
143 bones, 879 vertices, 21 transform/path constraints90 µs22 µs

Edit this page on GitHub