keyframe/lib.rs
1//! A simple library for animation in Rust
2//!
3//! ## Usage
4//!
5//! Tweening between two values is done with [`ease(function, from, to, time)`](fn.ease.html).
6//! `from` and `to` can be any type that implements [`CanTween`], such as `f64` or `mint::Vector2`, while `time` needs to be a floating-point value between zero and one.
7//! `function` specifies the transition between `from` and `to` and is any type that implements [`EasingFunction`].
8//!
9//! [`AnimationSequence`] can be used to create more complex animations that keep track of keyframes, time, etc.
10//! You can create animation sequences with the [`keyframes![...]`](macro.keyframes.html) macro, from an iterator or from a vector.
11//!
12//! ## Embedded
13//!
14//! This library is embedded compatible. As default it uses the `alloc` crate for dynamic memory usage. So, if the `alloc` feature is turned off,
15//! by setting `default-features = false`, this `crate` can be used without dynamic memory usage. Keep in mind that this will disable the feature `mint_types`
16//! as well. This must be enabled by hand again.
17//!
18//! Disabled features:
19//! - [`Keyframe`]
20//! - [`AnimationSequence`]
21//!
22//!
23//! ## Examples
24//!
25//! An example visualizer is included in `examples/`. Run `cargo run --example visualizer --release` to start it. (ggez is really slow in debug mode!)
26//!
27//! Tweening:
28//!
29//! ```rust
30//! use keyframe::{ease, functions::EaseInOut};
31//!
32//! fn example() -> f64 {
33//! let a = 0.0;
34//! let b = 2.0;
35//! let time = 0.5;
36//!
37//! ease(EaseInOut, a, b, time)
38//! }
39//! ```
40//!
41//! Animation sequences:
42//!
43//! ```rust
44//! use keyframe::{keyframes, Keyframe, AnimationSequence, functions::Linear};
45//!
46//! fn example() {
47//! // (value, time) or (value, time, function)
48//! let mut sequence = keyframes![
49//! (0.5, 0.0), // <-- EaseInOut used from 0.0 to 0.3
50//! (1.5, 0.3, Linear), // <-- Linear used from 0.3 to 1.0
51//! (2.5, 1.0) // <-- Easing function here is never used, since we're at the end
52//! ];
53//!
54//! sequence.advance_by(0.65);
55//!
56//! assert_eq!(sequence.now(), 2.0);
57//! assert_eq!(sequence.duration(), 1.0);
58//! }
59//! ```
60//!
61//! Custom structures:
62//!
63//! ```rust
64//! use keyframe::mint::Point2;
65//! // This macro works with any structure as long as it only consists of types that implement "CanTween"
66//! use keyframe_derive::CanTween;
67//!
68//! #[derive(CanTween)]
69//! struct MySubStructure {
70//! a: f32
71//! }
72//!
73//! #[derive(CanTween)]
74//! struct MyStructure {
75//! a: f64,
76//! b: Point2<f64>,
77//! c: f32,
78//! d: [MySubStructure; N] // Array length matching is guaranteed by the type system
79//! }
80//!
81//! // Also works with unnamed structures
82//! #[derive(CanTween)]
83//! struct UnnamedStructure(MyStructure, f64);
84//! ```
85#![no_std]
86
87#[cfg(feature = "mint_types")]
88pub use mint;
89pub use num_traits;
90
91#[cfg(feature = "mint_types")]
92pub(crate) use mint::{Point2, Point3, Vector2, Vector3, Vector4};
93pub(crate) use num_traits::Float;
94
95#[cfg(feature = "alloc")]
96extern crate alloc;
97
98pub(crate) fn as_f64(value: impl Float) -> f64 {
99 value.to_f64().expect("Value not representable in f64")
100}
101pub(crate) fn as_t<T: Float>(value: f64) -> T {
102 match value {
103 _ if value > as_f64(T::max_value()) => T::max_value(),
104 _ if value < as_f64(T::min_value()) => T::min_value(),
105 #[cfg(feature = "alloc")]
106 _ => T::from(value).unwrap_or_else(|| panic!("{} not representable in chosen float type", value)),
107 #[cfg(not(feature = "alloc"))]
108 _ => T::from(value).expect("value not representable in chosen float type"),
109 }
110}
111
112/// Definitions for various easing functions
113///
114/// <div class="function-preview" data-function="t" data-struct="Linear"></div>
115/// <div class="function-preview" data-function="Math.sin((t - 1) * Math.PI / 2) + 1" data-struct="EaseIn"></div>
116/// <div class="function-preview" data-function="Math.sin(t * Math.PI / 2)" data-struct="EaseOut"></div>
117/// <div class="function-preview" data-function=".5 * (1 - Math.cos(t * Math.PI))" data-struct="EaseInOut"></div>
118pub mod functions;
119use functions::*;
120
121mod easing;
122pub use easing::*;
123
124#[cfg(feature = "alloc")]
125mod keyframe;
126#[cfg(feature = "alloc")]
127pub use keyframe::*;
128
129#[cfg(feature = "alloc")]
130mod sequence;
131#[cfg(feature = "alloc")]
132pub use sequence::*;