animato 0.2.0

Professional-grade, renderer-agnostic animation library for Rust. Zero mandatory dependencies. no_std-ready.
Documentation

Animato

Italian: animato — animated, lively, with life and movement.

Crates.io Docs.rs CI License: MIT OR Apache-2.0 v0.2.0

A professional-grade, renderer-agnostic animation library for Rust.

Zero mandatory dependencies. no_std-ready. Built as a clean Cargo workspace — use only the crates you need.

Works everywhere: TUIs, Web (WASM), Bevy games, embedded targets, CLI tools, and native desktop apps.


Why Animato?

Most Rust animation crates are either too minimal (just easing functions) or too coupled to a specific renderer or framework. Animato sits in between:

  • Computes values, never renders. You own the render loop; Animato just tells you what the value is at each frame.
  • Workspace architecture. Each concern lives in its own crate. You don't download wgpu just to animate a progress bar.
  • no_std core. The trait system, all easing functions, Tween<T>, and Spring compile without std or heap allocation.
  • Builder pattern everywhere. No positional argument confusion; every optional field has a sensible default.
  • Generic over your types. Implement Interpolate once and animate any value — f32, [f32; 3], your custom color type, anything.

Crates

Shipped in v0.2.0:

Crate Description no_std
animato-core Traits (Interpolate, Animatable, Update, Playable) + 31 easing functions yes
animato-tween Tween<T>, KeyframeTrack<T>, Loop, TweenState, TweenBuilder partial
animato-timeline Timeline, Sequence, stagger, At positioning alloc
animato-spring Spring, SpringN<T>, SpringConfig presets
animato-driver AnimationDriver, Clock, WallClock, MockClock
animato Facade crate — re-exports all of the above

Planned in future versions (see ROADMAP.md):

Crate Version Description
animato-path v0.4.0 Bezier, CatmullRom, SVG path parser, shape morph
animato-physics v0.5.0 Inertia, DragState, GestureRecognizer
animato-color v0.6.0 Perceptual color interpolation (Lab, Oklch, Linear)
animato-bevy v0.7.0 AnimatoPlugin for Bevy
animato-wasm v0.7.0 RafDriver, FLIP, SplitText, ScrollSmoother
animato-gpu v0.9.0 GpuAnimationBatch — 10K+ tweens per frame on GPU

Most users only need the facade:

[dependencies]
animato = "0.2"

Quick Start

Animate a single value

use animato::{Tween, Easing, Update};

let mut tween = Tween::new(0.0_f32, 100.0)
    .duration(1.0)
    .easing(Easing::EaseOutCubic)
    .build();

// In your update loop — pass dt (seconds since last frame):
tween.update(0.016); // ~60fps tick
println!("{}", tween.value()); // current interpolated value

Spring physics

use animato::{Spring, SpringConfig, Update};

let mut spring = Spring::new(SpringConfig::wobbly());
spring.set_target(200.0);

// Animate until settled:
while !spring.is_settled() {
    spring.update(1.0 / 60.0);
}
println!("settled at {}", spring.position());

Loop modes

use animato::{Tween, Loop, Easing, Update};

let mut tween = Tween::new(0.0_f32, 100.0)
    .duration(1.0)
    .easing(Easing::EaseInOutSine)
    .looping(Loop::PingPong)
    .build();

for _ in 0..600 {
    tween.update(1.0 / 60.0);
}
println!("{}", tween.value()); // oscillates 0 ↔ 100

AnimationDriver — manage many animations

use animato::{Tween, Easing, AnimationDriver, WallClock, Clock};

let mut driver = AnimationDriver::new();
let mut clock  = WallClock::new();

let id = driver.add(
    Tween::new(0.0_f32, 1.0).duration(2.0).easing(Easing::EaseInOutSine).build()
);

loop {
    let dt = clock.delta();
    driver.tick(dt);

    if !driver.is_active(id) { break; }
}

Multi-dimensional spring

use animato::{SpringN, SpringConfig, Update};

let mut spring: SpringN<[f32; 3]> = SpringN::new(SpringConfig::stiff(), [0.0; 3]);
spring.set_target([100.0, 200.0, 300.0]);

while !spring.is_settled() {
    spring.update(1.0 / 60.0);
}
let [x, y, z] = spring.position();

Keyframe tracks

use animato::{Easing, KeyframeTrack, Update};

let mut track = KeyframeTrack::new()
    .push_eased(0.0, 0.0_f32, Easing::EaseOutCubic)
    .push(1.0, 100.0);

track.update(0.5);
assert!(track.value().unwrap() > 50.0);

Timeline composition

use animato::{At, Timeline, Tween, Update};

let fade = Tween::new(0.0_f32, 1.0).duration(1.0).build();
let slide = Tween::new(0.0_f32, 100.0).duration(1.0).build();

let mut timeline = Timeline::new()
    .add("fade", fade, At::Start)
    .add("slide", slide, At::Label("fade"));

timeline.play();
timeline.update(0.5);
assert_eq!(timeline.get::<Tween<f32>>("slide").unwrap().value(), 50.0);

Feature Flags

[dependencies]
animato = { version = "0.2", features = ["serde"] }

v0.2.0 features:

Feature What it adds
default std + tween + timeline + spring + driver
std Wall clock, heap-backed composition types
tween Tween<T>, KeyframeTrack<T>, Loop, TweenState
timeline Timeline, Sequence, stagger
spring Spring, SpringN<T>, all presets
driver AnimationDriver, Clock variants
serde Serialize/Deserialize on all public types

Features planned for future versions:

Feature Version What it adds
path v0.4.0 Bezier, MotionPath, SVG parser
physics v0.5.0 Inertia, DragState, GestureRecognizer
color v0.6.0 Perceptual color interpolation via palette
bevy v0.7.0 AnimatoPlugin for Bevy
wasm v0.7.0 RafDriver + WASM bindings
gpu v0.9.0 GpuAnimationBatch via wgpu
tokio v0.3.0 .wait().await on Timeline completion

no_std usage

[dependencies]
animato-core   = { version = "0.2", default-features = false }
animato-tween  = { version = "0.2", default-features = false }
animato-spring = { version = "0.2", default-features = false }

Available in no_std: Easing, Tween<T>, Spring, all Interpolate blanket impls. KeyframeTrack<T>, Timeline, and SpringN<T> require allocation.


Easing Functions

31 easing functions available as Easing::EaseOutCubic (enum) or ease_out_cubic(t) (free function):

Group Variants
Linear Linear
Polynomial EaseIn/Out/InOut × Quad, Cubic, Quart, Quint (12 total)
Sinusoidal EaseIn/Out/InOutSine
Exponential EaseIn/Out/InOutExpo
Circular EaseIn/Out/InOutCirc
Back (overshoot) EaseIn/Out/InOutBack
Elastic EaseIn/Out/InOutElastic
Bounce EaseIn/Out/InOutBounce
Escape hatch Custom(fn(f32) -> f32)

Advanced variants (CubicBezier, Steps, RoughEase, etc.) are planned for v0.3.0+.


Bevy Integration

use bevy::prelude::*;
use animato_bevy::{AnimatoPlugin, TweenCompleted};
use animato::Tween;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(AnimatoPlugin)
        .add_systems(Startup, spawn_animated)
        .add_systems(Update, on_tween_done)
        .run();
}

fn spawn_animated(mut commands: Commands) {
    commands.spawn((
        SpriteBundle::default(),
        Tween::new([0.0_f32, 0.0], [300.0, 0.0])
            .duration(1.0)
            .easing(Easing::EaseOutBack)
            .build(),
    ));
}

fn on_tween_done(mut events: EventReader<TweenCompleted>) {
    for ev in events.read() {
        println!("Entity {:?} finished animating", ev.entity);
    }
}

WASM Integration

[dependencies]
animato = { version = "0.2", features = ["wasm"] }
use wasm_bindgen::prelude::*;
use animato::{Tween, Easing};
use animato::wasm::RafDriver;

#[wasm_bindgen]
pub struct App {
    tween:  Tween<f32>,
    driver: RafDriver,
}

#[wasm_bindgen]
impl App {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Self {
        Self {
            tween:  Tween::new(0.0_f32, 500.0).duration(1.5).easing(Easing::EaseOutBounce).build(),
            driver: RafDriver::new(),
        }
    }

    // Call from JavaScript requestAnimationFrame callback:
    pub fn tick(&mut self, timestamp_ms: f64) { self.driver.tick(timestamp_ms); }
    pub fn value(&self) -> f32 { self.tween.value() }
}

Build: wasm-pack build --target web --features wasm


Architecture

Animato is a focused Cargo workspace with additional planned crates through v1.0. See ARCHITECTURE.md for the full design document — crate boundaries, module specifications, type system design, data flow diagrams, and performance guidelines.


Examples

cargo run --example basic_tween
cargo run --example spring_demo
cargo run --example keyframe_track
cargo run --example timeline_sequence

# Coming in future versions:
# cargo run --example motion_path         # v0.4.0
# cargo run --example color_animation     # v0.6.0
# cargo run --example tui_progress        # v0.7.0

Running Tests

# All tests, all features:
cargo test --workspace --all-features

# no_std check:
cargo test --workspace --no-default-features

# Benchmarks:
cargo bench

# Docs:
cargo doc --workspace --all-features --open

Roadmap

See ROADMAP.md for the full versioned plan from v0.1.0 to v1.0.0.

Current status: v0.2.0 — Composition shipped

Next Milestone
v0.3.0 Control — callbacks, time scale, CubicBezier/Steps easing
v0.4.0 Paths — Bezier, SVG, motion paths

Contributing

Contributions are welcome — bug reports, feature suggestions, documentation improvements, and pull requests.

See CONTRIBUTING.md for how to set up the workspace, run tests, and submit a PR.


Support

If Animato is useful to you, consider supporting ongoing development:


License

Licensed under either of:

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.