Skip to main content

aura_anim_iced/
lib.rs

1//! Iced-first animation primitives.
2//!
3//! `aura-anim-iced` models advanced animation as sampled Iced UI properties
4//! that can be applied from normal `update`, `subscription`, and `view` code.
5//! The public API is Iced-first: user-facing values use Iced types and Iced's
6//! animation primitives wherever they already exist.
7//!
8//! The foundation layer covers typed Iced UI properties, timing, property
9//! keyframes, timelines, a small runtime, and Iced integration helpers. The
10//! v0.2 behavior layer adds property-change transitions, state-driven
11//! transitions, retargeting, interruption, and route screen transitions on top
12//! of that base.
13//!
14//! Runtime integration follows a simple loop:
15//!
16//! 1. Store an [`AnimationRuntime`] in application state.
17//! 2. Register keyframes or timelines when `update` receives user events.
18//! 3. Subscribe to ticks only while the runtime is active.
19//! 4. Sample snapshots on each tick and apply them while building `view`.
20//!
21//! Runnable examples live under `examples/`:
22//!
23//! - `animated_button.rs` for hover, press, focus, scale, color, and shadow
24//!   animation.
25//! - `keyframes_popup.rs` for opacity and scale keyframes.
26//! - `timeline_toast.rs` for enter, hold, exit, and cleanup sequencing.
27//! - `behavior_width.rs` for property-change animation from the current visual
28//!   value.
29//! - `route_transition.rs` for outgoing and incoming screen transition flow.
30
31pub(crate) mod animatable;
32pub mod behavior;
33pub mod iced_ext;
34pub mod keyframes;
35pub mod prelude;
36pub mod property;
37pub mod route;
38pub mod runtime;
39pub mod state;
40pub mod timeline;
41pub mod timing;
42
43pub use behavior::{
44    ActivePropertyTransition, BehaviorRule, PropertyTransition, PropertyTransitionProgress,
45    PropertyTransitionRegistration, TransitionValueKind,
46};
47pub use iced_ext::{EffectSnapshot, effect_snapshot, tick_effect_snapshot_for};
48pub use keyframes::{Keyframe, Keyframes, KeyframesBuilder};
49pub use property::{
50    BACKGROUND, BORDER_COLOR, HEIGHT, OPACITY, PADDING, PropertyKey, PropertySnapshot,
51    PropertySpec, PropertyValue, RADIUS, SCALE, SHADOW, TEXT_COLOR, TRANSLATE, TransformValue,
52    WIDTH,
53};
54pub use route::{
55    ActiveRouteScreenTransition, ActiveRouteTransition, RouteAnimator, RouteIncomingMotion,
56    RouteScreenTargets, RouteScreenTransition, RouteScreenTransitionRegistration, RouteTransition,
57    RouteTransitionRegistration, RouteTransitionSet,
58};
59pub use runtime::{
60    AnimationHandle, AnimationPlaybackState, AnimationRegistration, AnimationRuntime,
61    AnimationTargetId, AnimationTick, TargetedPropertySnapshot, TickPolicy,
62};
63pub use state::{
64    ActiveStateTransition, StateAnimator, StateTransition, StateTransitionProgress,
65    StateTransitionRegistration, StateTransitionSet,
66};
67pub use timeline::{
68    Hold, Parallel, PropertyTrackBuilder, Sequence, Timeline, TimelineMarker, TimelineStep, Track,
69};
70pub use timing::{
71    Delay, Direction, Duration, Easing, FillMode, IterationCount, NormalizedTiming, Timing,
72    TimingPhase, TimingSampleState,
73};
74
75use crate::animatable::Animatable;
76
77const EPSILON_F32: f32 = 1e-5;
78const EPSILON_F64: f64 = 1e-10;
79
80pub(crate) fn nearly_equal_f64(a: f64, b: f64) -> bool {
81    (a - b).abs() < EPSILON_F64
82}
83
84pub(crate) fn nearly_equal_f32(a: f32, b: f32) -> bool {
85    (a - b).abs() < EPSILON_F32
86}
87
88fn interpolate_value(
89    from: PropertyValue,
90    to: PropertyValue,
91    progress: f32,
92) -> Option<PropertyValue> {
93    match (from, to) {
94        (PropertyValue::Scalar(from), PropertyValue::Scalar(to)) => {
95            Some(PropertyValue::Scalar(f32::interpolate(from, to, progress)))
96        }
97        (PropertyValue::Vector2(from), PropertyValue::Vector2(to)) => Some(PropertyValue::Vector2(
98            iced::Vector::interpolate(from, to, progress),
99        )),
100        (PropertyValue::Size(from), PropertyValue::Size(to)) => Some(PropertyValue::Size(
101            iced::Size::interpolate(from, to, progress),
102        )),
103        (PropertyValue::Rectangle(from), PropertyValue::Rectangle(to)) => Some(
104            PropertyValue::Rectangle(iced::Rectangle::interpolate(from, to, progress)),
105        ),
106        (PropertyValue::Transform(from), PropertyValue::Transform(to)) => Some(
107            PropertyValue::Transform(TransformValue::interpolate(from, to, progress)),
108        ),
109        (PropertyValue::Color(from), PropertyValue::Color(to)) => Some(PropertyValue::Color(
110            iced::Color::interpolate(from, to, progress),
111        )),
112        (PropertyValue::Shadow(from), PropertyValue::Shadow(to)) => Some(PropertyValue::Shadow(
113            iced::Shadow::interpolate(from, to, progress),
114        )),
115        _ => None,
116    }
117}