ANIMATE(1)

NAME

animate โ€” ๐ŸŽž๏ธ Animation Library for Rust

SYNOPSIS

INFO

81 stars
3 forks
0 views

DESCRIPTION

๐ŸŽž๏ธ Animation Library for Rust

README

๐ŸŽž๏ธ animate

Animation Library for Rust.

Demo

Features

  • Lightweight: Zero dependencies by default.
  • Ergonomic: Macro-driven API with minimal boilerplate.
  • Extensible: Many built-in types with support for custom interpolators.
  • Animation modes: #[once], #[cycle], and #[alternate].
  • Easing: Built-in and custom easing functions.
  • Ratatui-friendly: Interpolators for ratatui types, gated behind the ratatui feature flag.

Installation

cargo add animate

Getting started

Add #[animate] to a struct and mark the fields you want to animate:

#[animate]
pub struct MyWidget {
    #[once(duration = 300)]
    progress: f64,
#[cycle(duration = 400, easing = cubic_in)]
color: Color,

#[alternate(duration = 500, easing = quad_in_out)]
status: String,

}

By default the macro generates an update method named animate. It must be called at the top of your struct's render method.

#[animate]
pub struct MyWidget { ... }

impl MyWidget { pub fn draw(&mut self, frame: &mut Frame) { self.animate();

    // rest of your code
}

}

If the name conflicts with an existing method, rename it:

#[animate(update = "update_animations")]
pub struct MyWidget { ... }

Next, place animate::tick() before your struct's update call at the start of each frame:

let mut widget = MyWidget::new(...);

loop { animate::tick(tickrate); terminal.draw(|frame| { widget.draw(frame); })?; }

Use get() to read and set() to write animated fields.

Minimal example

use animate::animate;
use std::{io::{stdout, Write}, thread, time::Duration};

#[animate] struct Counter { #[once(duration = 400)] value: u32, }

fn main() -> std::io::Result<()> { let mut c = Counter::new(0);

loop {
    animate::tick(8);  // advance global frame time by frame delta (ms)
    c.animate();       // update all animated fields

    let v = *c.value;
    if v == 0 {
        c.value.set(100);
    }

    print!(&quot;\rCounter value: {v}&quot;);
    stdout().flush()?;

    if v == 100 {
        break;
    }

    thread::sleep(Duration::from_millis(8));
}

Ok(())

}

Animation modes

AttributeBehaviour
#[once]Animates to target once, then holds.
#[cycle]Loops continuously from start to target.
#[alternate]Ping-pongs back and forth between start and target.

Fields

All mode attributes accept the same options:

#[once(duration = 300, easing = quad_in_out, interp = my_interp_fn)]
OptionTypeDefaultDescription
durationu64 (ms)0Animation duration in milliseconds.
easingpathlinearEasing function (fn(f64) -> f64).
interppath<T as Lerp>::lerpInterpolation function (fn(&T, &T, f64) -> T).

Built-in easing functions

linear, quad_in, quad_out, quad_in_out, cubic_in, cubic_out, cubic_in_out

Custom types

Implement Lerp for any type:

impl animate::Lerp for MyColor {
    fn lerp(start: &Self, end: &Self, t: f64) -> Self {
        MyColor {
            r: u8::lerp(&start.r, &end.r, t),
            g: u8::lerp(&start.g, &end.g, t),
            b: u8::lerp(&start.b, &end.b, t),
        }
    }
}

SEE ALSO

clihub4/21/2026ANIMATE(1)