aura-anim
Typed animation primitives and Iced integration for Rust desktop interfaces.
The application stores lightweight Motion<T> handles while MotionRuntime
owns and advances the actual animation sources. Animated values remain ordinary
Rust structs, and #[derive(Animatable)] generates field-by-field
interpolation.
Application
├── explicit UI state
├── Motion<T> handles
└── event-driven transition_to / play calls
MotionRuntime
├── owns type-erased animation slots
├── ticks active slots only
├── pause / resume / seek / cancel / finish
├── generation-checked handle reuse
└── completion compaction and optional auto-removal
Animation<T>
├── Tween<T>
├── Spring<T>
├── Keyframes<T>
├── Sequence<T>
├── Parallel<T>
└── Hold<T>
Workspace Crates
aura-anim-core: runtime, handles, interpolation, animation sources and timeline composition.aura-anim-iced: Iced value integration and frame subscriptions.aura-anim: convenience facade re-exporting core and Iced APIs.aura-anim-macros:Animatablederive implementation.
Installation
For Iced applications:
[]
= "0.2.2"
= "0.14"
Use aura-anim-core directly when no Iced integration is required.
Typed Motion
use *;
let mut runtime = new;
let button = runtime.motion_with;
button.transition_to;
runtime.tick;
let visual = button.value;
transition_to retargets from the currently sampled value, so interrupted
hover, press, menu and route animations do not jump back to a stale origin.
Iced Integration
Store the runtime and typed handles in application state:
use Instant;
use *;
use ;
When no animation is active, the subscription returns Subscription::none()
and does not continue waking the application.
TickPolicy supports:
Frames
fps
interval
Iced Animatable Types
With the core iced integration enabled, these types can be fields in an
Animatable struct:
iced::Vector<T>iced::Point<T>iced::Size<T>iced::Rectangle<T>iced::Paddingiced::border::Radius
The active rgba or oklaba color feature additionally enables:
iced::Coloriced::Shadowiced::Border
Color Interpolation
RGBA component interpolation is enabled by default:
= "0.2.2"
For Oklab RGB interpolation with independently interpolated alpha:
= {
version = "0.2.2",
= false,
= ["oklaba"]
}
rgba and oklaba are mutually exclusive. Oklaba conversion follows:
Iced sRGB
→ palette sRGB
→ Oklab interpolation
→ display sRGB
Animation Sources
Tween
motion.play;
Timing supports delay, easing, finite or infinite iterations, and playback direction.
Keyframes
motion.play;
Spring
motion.play;
Spring interpolation may overshoot and can be retargeted while active.
Timeline Composition
Sequence, Parallel and Hold all implement Animation<T>, so composition
is recursive:
Sequence(
Parallel(
Sequence(Hold, Tween),
Sequence(Tween, Tween),
),
Tween,
)
Parallel branches produce complete T values. A compositor explicitly selects
which fields each branch owns:
let parallel = new
.with
.with;
Sequence propagates unused frame time into following children. Parallel completes when its longest branch completes.
Lifecycle
Normal motions retain their final value:
let motion = runtime.motion;
Completed sources are compacted to the final value, releasing keyframe and timeline trees while keeping the handle valid.
Transient animations can remove their slot automatically:
let transient = runtime.play_once;
Slots are reused with generation counters, preventing stale handles from accessing a newly allocated motion.
Examples
Run the command-line architecture example:
Run the Iced showcase:
Run the focused visual examples:
Run the interactive UI examples:
Run the showcase with perceptual color interpolation: