1use std::cell::RefCell;
2use web_time::{Duration, Instant};
3
4pub(crate) fn now() -> Instant {
5 CLOCK.with(|c| c.borrow().now())
6}
7
8#[derive(Clone, Copy, Debug)]
10pub struct SpringSpec {
11 pub damping_ratio: f32,
14 pub stiffness: f32,
16 pub settle_progress: f32,
19 pub settle_velocity: f32,
21}
22
23impl SpringSpec {
24 pub const fn new(damping_ratio: f32, stiffness: f32) -> Self {
25 Self {
26 damping_ratio,
27 stiffness,
28 settle_progress: 0.005,
29 settle_velocity: 0.1,
30 }
31 }
32 pub const fn gentle() -> Self {
34 Self::new(0.5, 200.0)
35 }
36 pub const fn bouncy() -> Self {
38 Self::new(0.2, 300.0)
39 }
40 pub const fn crit() -> Self {
42 Self::new(1.0, 200.0)
43 }
44 pub const fn stiff() -> Self {
46 Self::new(0.8, 600.0)
47 }
48
49 pub const fn with_settle_progress(mut self, threshold: f32) -> Self {
52 self.settle_progress = threshold;
53 self
54 }
55
56 pub const fn with_settle_velocity(mut self, threshold: f32) -> Self {
58 self.settle_velocity = threshold;
59 self
60 }
61}
62
63#[derive(Clone, Copy, Debug)]
66pub struct CubicBezier {
67 pub p1x: f32,
68 pub p1y: f32,
69 pub p2x: f32,
70 pub p2y: f32,
71}
72
73impl CubicBezier {
74 pub const fn new(p1x: f32, p1y: f32, p2x: f32, p2y: f32) -> Self {
75 Self { p1x, p1y, p2x, p2y }
76 }
77}
78
79pub const EASING_EMPHASIZED_DECELERATE: CubicBezier = CubicBezier::new(0.05, 0.7, 0.1, 1.0);
81pub const EASING_STANDARD_DECELERATE: CubicBezier = CubicBezier::new(0.2, 0.0, 0.0, 1.0);
83
84#[derive(Clone, Copy, Debug)]
85#[non_exhaustive]
86pub enum Easing {
87 Linear,
88 EaseIn,
89 EaseOut,
90 EaseInOut,
91 SpringCrit {
93 omega: f32,
94 },
95 SpringGentle,
97 SpringBouncy,
99 FastOutSlowIn,
102 Custom(CubicBezier),
104}
105
106impl Easing {
107 pub fn interpolate(&self, t: f32) -> f32 {
108 match self {
109 Easing::Linear => t,
110 Easing::EaseIn => t * t,
111 Easing::EaseOut => t * (2.0 - t),
112 Easing::EaseInOut => {
113 if t < 0.5 {
114 2.0 * t * t
115 } else {
116 -1.0 + (4.0 - 2.0 * t) * t
117 }
118 }
119 Easing::SpringCrit { omega } => {
120 let w = (*omega).max(0.0);
121 let tt = t.max(0.0);
122 1.0 - (1.0 + w * tt) * (-(w * tt)).exp()
124 }
125 Easing::SpringGentle => spring_underdamped_normalized(t, 0.5, 8.0),
126 Easing::SpringBouncy => spring_underdamped_normalized(t, 0.2, 12.0),
127 Easing::FastOutSlowIn => eval_cubic_bezier(0.4, 0.0, 0.2, 1.0, t),
128 Easing::Custom(cb) => eval_cubic_bezier(cb.p1x, cb.p1y, cb.p2x, cb.p2y, t),
129 }
130 }
131}
132
133fn eval_cubic_bezier(p1x: f32, p1y: f32, p2x: f32, p2y: f32, t: f32) -> f32 {
137 let t = t.clamp(0.0, 1.0);
138 if t <= 0.0 {
139 return 0.0;
140 }
141 if t >= 1.0 {
142 return 1.0;
143 }
144 let mut u = t;
145 for _ in 0..6 {
146 let omu = 1.0 - u;
147 let x = 3.0 * omu * omu * u * p1x + 3.0 * omu * u * u * p2x + u * u * u;
148 let dx = 3.0 * omu * omu * p1x + 6.0 * omu * u * (p2x - p1x) + 3.0 * u * u * (1.0 - p2x);
149 if dx.abs() < 1e-10 {
150 break;
151 }
152 u -= (x - t) / dx;
153 u = u.clamp(0.0, 1.0);
154 }
155 let omu = 1.0 - u;
156 3.0 * omu * omu * u * p1y + 3.0 * omu * u * u * p2y + u * u * u
157}
158
159fn hermite_interpolate(h: f32, x: f32, y1: f32, y2: f32, t1: f32, t2: f32) -> f32 {
165 let x2 = x * x;
166 let x3 = x2 * x;
167 h * t1 * (x - 2.0 * x2 + x3) + h * t2 * (x3 - x2) + y1 - (3.0 * x2 - 2.0 * x3) * (y1 - y2)
168}
169
170#[allow(dead_code)]
172fn hermite_differential(h: f32, x: f32, y1: f32, y2: f32, t1: f32, t2: f32) -> f32 {
173 let x2 = x * x;
174 h * (t1 - 2.0 * x * (2.0 * t1 + t2) + 3.0 * (t1 + t2) * x2) - 6.0 * (x - x2) * (y1 - y2)
175}
176
177#[derive(Clone, Debug)]
182pub struct MonoSpline {
183 times: Vec<f32>,
184 values: Vec<f32>,
185 tangents: Vec<f32>,
186}
187
188impl MonoSpline {
189 pub fn new(times: Vec<f32>, values: Vec<f32>) -> Self {
193 assert!(times.len() >= 2, "MonoSpline requires at least 2 keyframes");
194 assert_eq!(times.len(), values.len());
195 let n = times.len();
196 let mut tangents = vec![0.0; n];
197
198 let mut slopes = vec![0.0; n.saturating_sub(1)];
200 for i in 0..n - 1 {
201 let dt = times[i + 1] - times[i];
202 slopes[i] = (values[i + 1] - values[i]) / dt;
203 }
204
205 tangents[0] = slopes[0];
207 for i in 1..n - 1 {
208 tangents[i] = (slopes[i - 1] + slopes[i]) * 0.5;
209 }
210 tangents[n - 1] = slopes[n - 2];
211
212 for i in 0..n - 1 {
214 if slopes[i] == 0.0 {
215 tangents[i] = 0.0;
216 tangents[i + 1] = 0.0;
217 } else {
218 let a = tangents[i] / slopes[i];
219 let b = tangents[i + 1] / slopes[i];
220 let h = (a * a + b * b).sqrt();
221 if h > 9.0 {
222 let t = 3.0 / h;
223 tangents[i] = t * a * slopes[i];
224 tangents[i + 1] = t * b * slopes[i];
225 }
226 }
227 }
228
229 Self {
230 times,
231 values,
232 tangents,
233 }
234 }
235
236 pub fn evaluate(&self, t: f32) -> f32 {
239 let n = self.times.len();
240 let first = self.times[0];
241 let last = self.times[n - 1];
242
243 if t <= first {
244 return self.values[0] + (t - first) * self.tangents[0];
245 }
246 if t >= last {
247 return self.values[n - 1] + (t - last) * self.tangents[n - 1];
248 }
249
250 for i in 0..n - 1 {
251 if t >= self.times[i] && t <= self.times[i + 1] {
252 let h = self.times[i + 1] - self.times[i];
253 let x = (t - self.times[i]) / h;
254 return hermite_interpolate(
255 h,
256 x,
257 self.values[i],
258 self.values[i + 1],
259 self.tangents[i],
260 self.tangents[i + 1],
261 );
262 }
263 }
264
265 self.values[n - 1] }
267}
268
269fn spring_analytical(zeta: f32, stiffness: f32, t: f32, x0: f32, v0: f32) -> (f32, f32) {
271 if t <= 0.0 {
272 return (x0, v0);
273 }
274
275 let omega = if stiffness > 0.0 {
276 stiffness.sqrt()
277 } else {
278 return (x0 + v0 * t, v0);
279 };
280
281 let zeta = zeta.max(0.0);
282 let exp = (-zeta * omega * t).exp();
283 let a = 1.0 - x0; if (zeta - 1.0).abs() < 1e-6 {
286 let b = v0 + omega * a;
288 let progress = 1.0 - (a + b * t) * exp;
289 let velocity = (a * omega - b + b * omega * t) * exp;
290 (progress, velocity)
291 } else if zeta < 1.0 {
292 let wd = omega * (1.0 - zeta * zeta).sqrt();
294 let c = (v0 + zeta * omega * a) / wd;
295 let cos_wd = (wd * t).cos();
296 let sin_wd = (wd * t).sin();
297 let env = a * cos_wd + c * sin_wd;
298 let progress = 1.0 - exp * env;
299 let velocity =
300 exp * ((zeta * omega * a - wd * c) * cos_wd + (zeta * omega * c + wd * a) * sin_wd);
301 (progress, velocity)
302 } else {
303 let wd = omega * (zeta * zeta - 1.0).sqrt();
305 let d = (v0 + zeta * omega * a) / wd;
306 let cosh_wd = (wd * t).cosh();
307 let sinh_wd = (wd * t).sinh();
308 let env = a * cosh_wd + d * sinh_wd;
309 let progress = 1.0 - exp * env;
310 let velocity =
311 exp * ((zeta * omega * a - wd * d) * cosh_wd + (zeta * omega * d - wd * a) * sinh_wd);
312 (progress, velocity)
313 }
314}
315
316fn spring_underdamped_normalized(t: f32, zeta: f32, omega: f32) -> f32 {
317 let tt = t.max(0.0);
318 let z = zeta.clamp(0.0, 0.999);
319 let w = omega.max(0.0);
320 let wd = w * (1.0 - z * z).sqrt();
321 let exp_term = (-z * w * tt).exp();
322 let cos_term = (wd * tt).cos();
323 let sin_term = (wd * tt).sin();
324 let c = z / (1.0 - z * z).sqrt();
326 let y = 1.0 - exp_term * (cos_term + c * sin_term);
327 y.clamp(0.0, 1.0)
328}
329
330#[derive(Clone, Copy, Debug)]
331pub struct AnimationSpec {
332 pub duration: Duration,
333 pub easing: Easing,
334 pub delay: Duration,
335 pub spring: Option<SpringSpec>,
337 pub repeat: Option<RepeatableSpec>,
339}
340
341impl Default for AnimationSpec {
342 fn default() -> Self {
343 Self {
344 duration: Duration::from_millis(300),
345 easing: Easing::EaseInOut,
346 delay: Duration::ZERO,
347 spring: None,
348 repeat: None,
349 }
350 }
351}
352
353impl AnimationSpec {
354 pub fn tween(duration: Duration, easing: Easing) -> Self {
355 Self {
356 duration,
357 easing,
358 delay: Duration::ZERO,
359 spring: None,
360 repeat: None,
361 }
362 }
363 pub fn spring(spring: SpringSpec) -> Self {
365 Self {
366 duration: Duration::ZERO,
367 easing: Easing::Linear,
368 delay: Duration::ZERO,
369 spring: Some(spring),
370 repeat: None,
371 }
372 }
373 pub fn spring_gentle() -> Self {
375 Self::spring(SpringSpec::gentle())
376 }
377 pub fn spring_bouncy() -> Self {
379 Self::spring(SpringSpec::bouncy())
380 }
381 pub fn spring_crit(omega: f32) -> Self {
383 Self::spring(SpringSpec::new(1.0, omega * omega))
384 }
385
386 pub fn fast() -> Self {
387 Self {
388 duration: Duration::from_millis(150),
389 easing: Easing::EaseOut,
390 delay: Duration::ZERO,
391 spring: None,
392 repeat: None,
393 }
394 }
395
396 pub fn slow() -> Self {
397 Self {
398 duration: Duration::from_millis(600),
399 easing: Easing::EaseInOut,
400 delay: Duration::ZERO,
401 spring: None,
402 repeat: None,
403 }
404 }
405
406 pub fn repeated(mut self, repeat: RepeatableSpec) -> Self {
409 self.repeat = Some(repeat);
410 self
411 }
412}
413
414#[derive(Clone, Debug)]
419pub struct KeyframesSpec<T: Clone> {
420 pub keyframes: Vec<(f32, T, Option<Easing>)>,
423}
424
425impl<T: Clone + Interpolate> KeyframesSpec<T> {
426 pub fn new(keyframes: Vec<(f32, T)>) -> Self {
427 let with_easing = keyframes.into_iter().map(|(t, v)| (t, v, None)).collect();
428 Self {
429 keyframes: with_easing,
430 }
431 }
432
433 pub fn with_easing(mut self, easing: Easing) -> Self {
435 if let Some(last) = self.keyframes.last_mut() {
436 last.2 = Some(easing);
437 }
438 self
439 }
440
441 pub fn evaluate(&self, t: f32) -> T {
442 let t = t.clamp(0.0, 1.0);
443 let kf = &self.keyframes;
444 if kf.is_empty() {
445 panic!("KeyframesSpec must have at least one keyframe");
446 }
447
448 for i in 0..kf.len() - 1 {
450 let (t0, _, _) = kf[i];
451 let (t1, ref v1, easing) = kf[i + 1];
452 if t >= t0 && t <= t1 {
453 let segment_t = if (t1 - t0).abs() < f32::EPSILON {
454 1.0
455 } else {
456 (t - t0) / (t1 - t0)
457 };
458 let eased_t = match easing {
459 Some(e) => e.interpolate(segment_t),
460 None => segment_t,
461 };
462 return kf[i].1.interpolate(v1, eased_t);
463 }
464 }
465 kf.last().unwrap().1.clone()
466 }
467}
468
469#[derive(Clone, Debug)]
476pub struct SplineKeyframes {
477 spline: MonoSpline,
478}
479
480impl SplineKeyframes {
481 pub fn new(keyframes: Vec<(f32, f32)>) -> Self {
486 assert!(
487 keyframes.len() >= 2,
488 "SplineKeyframes requires at least 2 keyframes"
489 );
490 let times: Vec<f32> = keyframes.iter().map(|(t, _)| *t).collect();
491 let values: Vec<f32> = keyframes.iter().map(|(_, v)| *v).collect();
492 Self {
493 spline: MonoSpline::new(times, values),
494 }
495 }
496
497 pub fn evaluate(&self, t: f32) -> f32 {
499 self.spline.evaluate(t.clamp(0.0, 1.0))
500 }
501}
502
503#[derive(Clone, Copy, Debug)]
508pub struct RepeatableSpec {
509 pub iterations: Option<u32>,
511 pub reverse: bool,
513 pub delay_between: Duration,
515}
516
517impl Default for RepeatableSpec {
518 fn default() -> Self {
519 Self {
520 iterations: None,
521 reverse: false,
522 delay_between: Duration::ZERO,
523 }
524 }
525}
526
527impl RepeatableSpec {
528 pub fn new(iterations: u32) -> Self {
529 Self {
530 iterations: Some(iterations),
531 reverse: false,
532 delay_between: Duration::ZERO,
533 }
534 }
535
536 pub fn infinite() -> Self {
537 Self {
538 iterations: None,
539 reverse: false,
540 delay_between: Duration::ZERO,
541 }
542 }
543
544 pub fn reverse(mut self) -> Self {
545 self.reverse = true;
546 self
547 }
548
549 pub fn delay_between(mut self, d: Duration) -> Self {
550 self.delay_between = d;
551 self
552 }
553}
554
555#[derive(Clone, Copy, Debug)]
559pub struct DecayAnimationSpec {
560 pub friction: f32,
562 pub stop_threshold: f32,
564}
565
566impl Default for DecayAnimationSpec {
567 fn default() -> Self {
568 Self {
569 friction: 0.8,
570 stop_threshold: 1.0,
571 }
572 }
573}
574
575impl DecayAnimationSpec {
576 pub fn new(friction: f32) -> Self {
577 Self {
578 friction: friction.clamp(0.01, 1.0),
579 stop_threshold: 1.0,
580 }
581 }
582}
583
584impl AnimatedValue<f32> {
585 pub fn update_decay(&mut self, friction: f32, stop_threshold: f32) -> bool {
587 let _start = match self.start_time {
588 Some(s) => s,
589 None => return false,
590 };
591
592 let now = now();
593 let dt = match self.last_update {
594 Some(last) => now.saturating_duration_since(last).as_secs_f32().min(0.05),
595 None => 0.0,
596 };
597 self.last_update = Some(now);
598
599 if dt <= 0.0 {
600 return true;
601 }
602
603 if self.velocity.abs() < stop_threshold {
604 self.velocity = 0.0;
605 self.start_time = None;
606 return false;
607 }
608
609 self.velocity *= friction.powf(dt * 60.0);
610 let delta = self.velocity * dt;
611 let new_progress = self.progress + delta;
617 self.progress = new_progress;
618 if self.progress.abs() < 0.001 && self.velocity.abs() < stop_threshold {
623 self.progress = 0.0;
624 self.velocity = 0.0;
625 self.start_time = None;
626 return false;
627 }
628
629 self.current = self.start.interpolate(&self.target, self.progress);
630 true
631 }
632}
633
634pub trait Interpolate {
635 fn interpolate(&self, other: &Self, t: f32) -> Self;
636}
637
638impl Interpolate for f32 {
639 fn interpolate(&self, other: &Self, t: f32) -> Self {
640 self + (other - self) * t
641 }
642}
643
644impl Interpolate for crate::Color {
645 fn interpolate(&self, other: &Self, t: f32) -> Self {
646 let lerp = |a: u8, b: u8| {
647 (a as f32 + (b as f32 - a as f32) * t)
648 .round()
649 .clamp(0.0, 255.0) as u8
650 };
651 crate::Color(
652 lerp(self.0, other.0),
653 lerp(self.1, other.1),
654 lerp(self.2, other.2),
655 lerp(self.3, other.3),
656 )
657 }
658}
659
660impl Interpolate for crate::Vec2 {
661 fn interpolate(&self, other: &Self, t: f32) -> Self {
662 crate::Vec2 {
663 x: self.x.interpolate(&other.x, t),
664 y: self.y.interpolate(&other.y, t),
665 }
666 }
667}
668
669impl Interpolate for crate::Size {
670 fn interpolate(&self, other: &Self, t: f32) -> Self {
671 crate::Size {
672 width: self.width.interpolate(&other.width, t),
673 height: self.height.interpolate(&other.height, t),
674 }
675 }
676}
677
678impl Interpolate for crate::Rect {
679 fn interpolate(&self, other: &Self, t: f32) -> Self {
680 crate::Rect {
681 x: self.x.interpolate(&other.x, t),
682 y: self.y.interpolate(&other.y, t),
683 w: self.w.interpolate(&other.w, t),
684 h: self.h.interpolate(&other.h, t),
685 }
686 }
687}
688
689pub trait Clock: Send + Sync + 'static {
691 fn now(&self) -> Instant;
692}
693
694pub struct SystemClock;
695impl Clock for SystemClock {
696 fn now(&self) -> Instant {
697 Instant::now()
698 }
699}
700
701thread_local! {
702 static CLOCK: RefCell<Box<dyn Clock>> = RefCell::new(Box::new(SystemClock) as Box<dyn Clock>);
703}
704
705pub fn set_clock(clock: Box<dyn Clock>) {
707 CLOCK.with(|c| *c.borrow_mut() = clock);
708}
709pub fn ensure_system_clock() {
711 }
713
714#[derive(Clone)]
716pub struct TestClock {
717 pub t: Instant,
718}
719impl Clock for TestClock {
720 fn now(&self) -> Instant {
721 self.t
722 }
723}
724
725pub struct AnimatedValue<T: Interpolate + Clone> {
734 current: T,
735 target: T,
736 start: T,
737 spec: AnimationSpec,
738 keyframes: Option<KeyframesSpec<T>>,
739 iteration: u32,
740 start_time: Option<Instant>,
741 progress: f32,
743 velocity: f32,
744 spring_v0: f32,
746 last_update: Option<Instant>,
747}
748
749impl<T: Interpolate + Clone> AnimatedValue<T> {
750 pub fn new(initial: T, spec: AnimationSpec) -> Self {
751 Self {
752 current: initial.clone(),
753 target: initial.clone(),
754 start: initial,
755 spec,
756 keyframes: None,
757 iteration: 0,
758 start_time: None,
759 progress: 1.0,
760 velocity: 0.0,
761 spring_v0: 0.0,
762 last_update: None,
763 }
764 }
765
766 pub fn set_spec(&mut self, spec: AnimationSpec) {
767 self.spec = spec;
768 }
769
770 pub fn set_keyframes(&mut self, keyframes: KeyframesSpec<T>) {
773 self.keyframes = Some(keyframes);
774 self.start_time = Some(now());
775 self.last_update = None;
776 self.iteration = 0;
777 }
778
779 pub fn set_target(&mut self, target: T) {
780 self.keyframes = None;
785 self.start = self.current.clone();
786 self.target = target;
787 self.start_time = Some(now());
788 self.last_update = None;
789 self.iteration = 0;
790 if self.spec.spring.is_some() {
791 self.progress = 0.0;
793 self.spring_v0 = self.velocity;
794 }
795 }
796
797 pub fn snap_to(&mut self, value: T) {
799 self.current = value.clone();
800 self.target = value.clone();
801 self.start = value;
802 self.keyframes = None;
803 self.start_time = None;
804 self.progress = 1.0;
805 self.velocity = 0.0;
806 self.spring_v0 = 0.0;
807 self.last_update = None;
808 }
809
810 pub fn update(&mut self) -> bool {
811 let spring_spec = self.spec.spring;
812 let mut still = if let Some(spring) = spring_spec {
813 self.update_spring(&spring)
814 } else if self.keyframes.is_some() {
815 self.update_keyframes()
816 } else {
817 self.update_tween()
818 };
819
820 if !still {
821 if let Some(repeat) = &self.spec.repeat {
823 let maxed = repeat
824 .iterations
825 .is_some_and(|max| self.iteration + 1 >= max);
826 if !maxed {
827 self.iteration += 1;
828 if repeat.reverse {
829 std::mem::swap(&mut self.start, &mut self.target);
830 }
831 self.progress = 0.0;
832 self.velocity = 0.0;
833 self.start_time = Some(now());
834 self.last_update = None;
835 still = true;
836 }
837 }
838 }
839
840 still
841 }
842
843 fn update_keyframes(&mut self) -> bool {
844 let start = match self.start_time {
845 Some(s) => s,
846 None => return false,
847 };
848 let elapsed = now().saturating_duration_since(start);
849 if elapsed < self.spec.delay {
850 return true;
851 }
852 let animation_time = elapsed - self.spec.delay;
853 if animation_time >= self.spec.duration {
854 if let Some(ref kf) = self.keyframes {
855 self.current = kf.evaluate(1.0);
856 }
857 self.start_time = None;
858 return false;
859 }
860 let t = (animation_time.as_secs_f32() / self.spec.duration.as_secs_f32()).clamp(0.0, 1.0);
861 let eased_t = self.spec.easing.interpolate(t).clamp(0.0, 1.0);
862 if let Some(ref kf) = self.keyframes {
863 self.current = kf.evaluate(eased_t);
864 }
865 true
866 }
867
868 fn update_spring(&mut self, spring: &SpringSpec) -> bool {
869 let start = match self.start_time {
870 Some(s) => s,
871 None => return false,
872 };
873
874 let now = now();
875 let elapsed = now.saturating_duration_since(start);
876
877 if elapsed < self.spec.delay {
879 return true;
880 }
881
882 let t = elapsed.as_secs_f32().max(0.0);
883 let (progress, velocity) = spring_analytical(
884 spring.damping_ratio,
885 spring.stiffness,
886 t,
887 0.0,
888 self.spring_v0,
889 );
890 let progress = progress.clamp(-0.1, 2.0);
891
892 if (progress - 1.0).abs() < spring.settle_progress
894 && velocity.abs() < spring.settle_velocity
895 {
896 self.progress = 1.0;
897 self.velocity = 0.0;
898 self.spring_v0 = 0.0;
899 self.current = self.target.clone();
900 self.start_time = None;
901 self.last_update = None;
902 return false;
903 }
904
905 self.progress = progress;
906 self.velocity = velocity;
907 self.current = self.start.interpolate(&self.target, self.progress);
908 true
909 }
910
911 fn update_tween(&mut self) -> bool {
912 if let Some(start) = self.start_time {
913 let elapsed = now().saturating_duration_since(start);
914
915 if elapsed < self.spec.delay {
916 return true;
917 }
918
919 let animation_time = elapsed - self.spec.delay;
920
921 if animation_time >= self.spec.duration {
922 self.current = self.target.clone();
923 self.start_time = None;
924 return false;
925 }
926
927 let t =
928 (animation_time.as_secs_f32() / self.spec.duration.as_secs_f32()).clamp(0.0, 1.0);
929 let eased_t = self.spec.easing.interpolate(t);
930 let eased_t = eased_t.clamp(0.0, 1.0);
931
932 self.current = self.start.interpolate(&self.target, eased_t);
933 true
934 } else {
935 false
936 }
937 }
938
939 pub fn get(&self) -> &T {
940 &self.current
941 }
942
943 pub fn is_animating(&self) -> bool {
944 self.start_time.is_some()
945 }
946
947 pub fn has_keyframes(&self) -> bool {
948 self.keyframes.is_some()
949 }
950}