1use crate::{Easing, Frame, Spring, Target, Transition, value::sample_transition};
3#[cfg(feature = "gpui")]
4use std::time::Instant;
5use std::{error::Error, fmt, sync::Arc, time::Duration};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum AnimationError {
11 Keyframes,
13 Times,
15 ZeroPeriod,
17 Speed,
19 Label,
21 InfiniteSequence,
23 Index,
25}
26
27impl fmt::Display for AnimationError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "invalid animation input: {self:?}")
30 }
31}
32
33impl Error for AnimationError {}
34
35#[derive(Clone, Copy, Debug, PartialEq)]
37pub struct Keyframe {
38 at: f64,
39 target: Option<Target>,
40 easing: Easing,
41}
42
43impl Keyframe {
44 pub fn new(at: f64, target: Target) -> Self {
46 Self {
47 at,
48 target: Some(target),
49 easing: Easing::default(),
50 }
51 }
52
53 pub fn current(at: f64) -> Self {
55 Self {
56 at,
57 target: None,
58 easing: Easing::default(),
59 }
60 }
61
62 pub fn easing(mut self, easing: Easing) -> Self {
64 self.easing = easing;
65
66 self
67 }
68}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum Repeat {
73 Count(u32),
75 Forever,
77}
78
79impl Default for Repeat {
80 fn default() -> Self {
81 Self::Count(0)
82 }
83}
84
85#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
87pub enum RepeatMode {
88 #[default]
90 Loop,
91 Reverse,
93 Mirror,
95}
96
97#[derive(Clone, Debug, PartialEq)]
98struct Clip {
99 frames: Vec<Keyframe>,
100 duration: Duration,
101 spring: Option<Spring>,
102}
103
104#[derive(Clone, Debug)]
106pub struct Animation {
107 clip: Arc<Clip>,
108 delay: Duration,
109 repeat: Repeat,
110 mode: RepeatMode,
111 repeat_delay: Duration,
112}
113
114impl Animation {
115 pub fn keyframes(
117 duration: Duration,
118 frames: impl IntoIterator<Item = Keyframe>,
119 ) -> Result<Self, AnimationError> {
120 let frames: Vec<_> = frames.into_iter().collect();
121
122 if frames.len() < 2 || frames.first().unwrap().at != 0.0 || frames.last().unwrap().at != 1.0
123 {
124 return Err(AnimationError::Keyframes);
125 }
126
127 if frames
128 .iter()
129 .any(|f| !f.at.is_finite() || !(0.0..=1.0).contains(&f.at))
130 || frames.windows(2).any(|p| p[0].at >= p[1].at)
131 {
132 return Err(AnimationError::Times);
133 }
134
135 Ok(Self {
136 clip: Arc::new(Clip {
137 frames,
138 duration,
139 spring: None,
140 }),
141 delay: Duration::ZERO,
142 repeat: Repeat::default(),
143 mode: RepeatMode::Loop,
144 repeat_delay: Duration::ZERO,
145 })
146 }
147
148 pub fn to(target: Target, duration: Duration, easing: Easing) -> Self {
150 Self::keyframes(
151 duration,
152 [
153 Keyframe::current(0.0),
154 Keyframe::new(1.0, target).easing(easing),
155 ],
156 )
157 .expect("valid two-frame clip")
158 }
159
160 pub fn spring(target: Target, spring: Spring, duration: Duration) -> Self {
164 let mut animation = Self::to(target, duration, Easing::default());
165
166 Arc::make_mut(&mut animation.clip).spring = Some(spring);
167
168 animation
169 }
170
171 pub fn delay(mut self, duration: Duration) -> Self {
173 self.delay = duration;
174
175 self
176 }
177
178 pub fn repeat(
180 mut self,
181 repeat: Repeat,
182 mode: RepeatMode,
183 delay: Duration,
184 ) -> Result<Self, AnimationError> {
185 if self.clip.duration.is_zero() && repeat != Repeat::Count(0) {
186 return Err(AnimationError::ZeroPeriod);
187 }
188
189 self.repeat = repeat;
190 self.mode = mode;
191 self.repeat_delay = delay;
192
193 Ok(self)
194 }
195
196 pub fn duration(&self) -> Option<Duration> {
198 match self.repeat {
199 Repeat::Forever => None,
200 Repeat::Count(count) => Some(
201 self.delay
202 .saturating_add(
203 self.clip
204 .duration
205 .saturating_mul(count)
206 .saturating_add(self.clip.duration),
207 )
208 .saturating_add(self.repeat_delay.saturating_mul(count)),
209 ),
210 }
211 }
212
213 fn same(&self, other: &Self) -> bool {
214 Arc::ptr_eq(&self.clip, &other.clip)
215 && self.delay == other.delay
216 && self.repeat == other.repeat
217 && self.mode == other.mode
218 && self.repeat_delay == other.repeat_delay
219 }
220
221 fn resolve(&self, time: Duration, origin: Frame, force_end: bool) -> (Frame, u64, bool) {
222 let duration = self.clip.duration.as_secs_f64();
223 let period = duration + self.repeat_delay.as_secs_f64();
224 let relative = time.saturating_sub(self.delay).as_secs_f64();
225 let done = force_end || self.duration().is_some_and(|end| time >= end);
226
227 let iteration = if done {
228 match self.repeat {
229 Repeat::Count(n) => u64::from(n),
230 Repeat::Forever => 0,
231 }
232 } else if period > 0.0 {
233 (relative / period).floor().min(u64::MAX as f64) as u64
234 } else {
235 0
236 };
237
238 let local = if done {
239 duration
240 } else {
241 (relative - iteration as f64 * period).clamp(0.0, duration)
242 };
243
244 let mut progress = if duration > 0.0 {
245 local / duration
246 } else {
247 1.0
248 };
249
250 if time < self.delay && !done {
251 progress = 0.0;
252 }
253
254 let odd = !iteration.is_multiple_of(2);
255 let reverse = odd && self.mode == RepeatMode::Reverse;
256
257 if reverse {
258 progress = 1.0 - progress;
259 }
260
261 let mut from = origin.target().inherit(
262 self.clip
263 .frames
264 .last()
265 .and_then(|f| f.target)
266 .unwrap_or_default(),
267 );
268
269 from = self.clip.frames[0].target.unwrap_or(from).inherit(from);
270 let first = from;
271
272 let final_target = self.clip.frames.iter().fold(from, |previous, frame| {
273 frame.target.unwrap_or(previous).inherit(previous)
274 });
275
276 if let Some(spring) = self.clip.spring {
277 let (start, end) = if odd && self.mode == RepeatMode::Mirror {
278 (final_target, first)
279 } else {
280 (first, final_target)
281 };
282
283 let velocity = if iteration == 0 {
284 origin_velocities(origin)
285 } else {
286 [0.0; 6]
287 };
288
289 let mut values = [0.0; 6];
290 let mut velocities = [0.0; 6];
291
292 for ix in 0..6 {
293 let (v, speed, _) = sample_transition(
294 start.values()[ix],
295 velocity[ix],
296 end.values()[ix],
297 Transition::Spring(spring),
298 progress * duration,
299 );
300
301 values[ix] = if progress == 0.0 {
302 start.values()[ix]
303 } else if progress == 1.0 {
304 end.values()[ix]
305 } else {
306 v
307 };
308 velocities[ix] = if progress == 1.0 || done || time < self.delay {
309 0.0
310 } else if reverse {
311 -speed
312 } else {
313 speed
314 };
315 }
316
317 return (
318 Frame::animated(
319 Target::from_values(values, start.mask() | end.mask() | 7),
320 velocities,
321 !done,
322 false,
323 ),
324 iteration,
325 done,
326 );
327 }
328
329 let mirrored = odd && self.mode == RepeatMode::Mirror;
330 let sample_progress = if mirrored { 1.0 - progress } else { progress };
331
332 let upper = self
333 .clip
334 .frames
335 .partition_point(|frame| frame.at < sample_progress)
336 .clamp(1, self.clip.frames.len() - 1);
337
338 let mut a = first;
339
340 for frame in self.clip.frames.iter().take(upper).skip(1) {
341 a = frame.target.unwrap_or(a).inherit(a);
342 }
343
344 let mut b = self.clip.frames[upper].target.unwrap_or(a).inherit(a);
345 let lo = self.clip.frames[upper - 1].at;
346 let hi = self.clip.frames[upper].at;
347 let mut u = (sample_progress - lo) / (hi - lo);
348
349 if mirrored {
350 std::mem::swap(&mut a, &mut b);
351 u = 1.0 - u;
352 }
353
354 let span = (hi - lo) * duration;
355 let easing = self.clip.frames[upper].easing;
356 let (weight, derivative) = easing.sample(u.clamp(0.0, 1.0));
357 let av = a.values();
358 let bv = b.values();
359
360 let values = std::array::from_fn(|ix| {
361 if u <= 0.0 {
362 av[ix]
363 } else if u >= 1.0 {
364 bv[ix]
365 } else {
366 crate::value::finite(av[ix] + (bv[ix] - av[ix]) * weight)
367 }
368 });
369
370 let velocity = std::array::from_fn(|ix| {
371 if done || time < self.delay || local >= duration || span == 0.0 {
372 0.0
373 } else {
374 crate::value::finite(
375 (bv[ix] - av[ix]) * derivative / span * if reverse { -1.0 } else { 1.0 },
376 )
377 }
378 });
379
380 (
381 Frame::animated(
382 Target::from_values(values, a.mask() | b.mask() | 7),
383 velocity,
384 !done,
385 false,
386 ),
387 iteration,
388 done,
389 )
390 }
391}
392
393fn origin_velocities(frame: Frame) -> [f64; 6] {
394 let basic = frame.velocity();
395 let layout = frame.layout_velocity();
396
397 [
398 basic[0],
399 basic[1],
400 basic[2],
401 layout[0].unwrap_or(0.0),
402 layout[1].unwrap_or(0.0),
403 layout[2].unwrap_or(0.0),
404 ]
405}
406
407#[derive(Clone, Debug)]
409pub struct Playback {
410 anchor: Duration,
411 offset: f64,
412 speed: f64,
413 paused: bool,
414 last: Duration,
415}
416
417impl Default for Playback {
418 fn default() -> Self {
419 Self {
420 anchor: Duration::ZERO,
421 offset: 0.0,
422 speed: 1.0,
423 paused: false,
424 last: Duration::ZERO,
425 }
426 }
427}
428
429impl Playback {
430 pub fn time(&mut self, now: Duration) -> Duration {
432 let now = now.max(self.last);
433
434 self.last = now;
435 let seconds = self.offset
436 + if self.paused {
437 0.0
438 } else {
439 now.saturating_sub(self.anchor).as_secs_f64() * self.speed
440 };
441
442 Duration::try_from_secs_f64(seconds.max(0.0)).unwrap_or(Duration::MAX)
443 }
444
445 pub fn pause(&mut self, now: Duration) {
447 self.offset = self.time(now).as_secs_f64();
448 self.anchor = now.max(self.last).max(self.anchor);
449 self.paused = true;
450 }
451
452 pub fn play(&mut self, now: Duration) {
454 if self.paused {
455 self.anchor = now.max(self.last).max(self.anchor);
456 self.paused = false;
457 }
458 }
459
460 pub fn seek(&mut self, time: Duration, now: Duration) {
462 self.last = self.last.max(now);
463 self.offset = time.as_secs_f64();
464 self.anchor = now.max(self.last).max(self.anchor);
465 }
466
467 pub fn set_speed(&mut self, speed: f64, now: Duration) -> Result<(), AnimationError> {
469 if !speed.is_finite() {
470 return Err(AnimationError::Speed);
471 }
472
473 self.offset = self.time(now).as_secs_f64();
474 self.anchor = now.max(self.last).max(self.anchor);
475 self.speed = speed;
476
477 Ok(())
478 }
479
480 pub fn speed(&self) -> f64 {
482 self.speed
483 }
484
485 pub fn is_playing(&self) -> bool {
487 !self.paused && self.speed != 0.0
488 }
489}
490
491#[derive(Debug)]
493pub struct AnimationState {
494 clip: Option<Animation>,
495 clock: Playback,
496 origin: Frame,
497 current: Frame,
498 complete: bool,
499 force_end: bool,
500 iteration: u64,
501 observers: crate::completion::CompletionSource,
502 #[cfg(feature = "gpui")]
503 pub(crate) epoch: Instant,
504}
505
506impl Default for AnimationState {
507 fn default() -> Self {
508 Self::new(Target::default())
509 }
510}
511
512impl AnimationState {
513 pub fn new(initial: Target) -> Self {
515 Self {
516 clip: None,
517 clock: Playback::default(),
518 origin: Frame::at(initial),
519 current: Frame::at(initial),
520 complete: false,
521 force_end: false,
522 iteration: 0,
523 observers: Default::default(),
524 #[cfg(feature = "gpui")]
525 epoch: Instant::now(),
526 }
527 }
528
529 pub fn sample(&mut self, animation: &Animation, now: Duration, reduced_motion: bool) -> Frame {
532 if !self.clip.as_ref().is_some_and(|old| old.same(animation)) {
533 if let Some(old) = &self.clip {
534 self.observers.resolve(crate::CompletionStatus::Cancelled);
535 let frame = old
536 .resolve(self.clock.time(now), self.origin, self.force_end)
537 .0;
538
539 let factor = if self.clock.is_playing() {
540 self.clock.speed
541 } else {
542 0.0
543 };
544
545 self.current = Frame::animated(
546 frame.target(),
547 origin_velocities(frame).map(|v| v * factor),
548 frame.is_animating(),
549 false,
550 );
551 }
552
553 self.origin = self.current;
554 let first = self.clip.is_none();
555
556 self.clip = Some(animation.clone());
557
558 if first {
559 self.clock.anchor = now.max(self.clock.last);
560 self.clock.last = self.clock.anchor;
561 } else {
562 self.clock.seek(Duration::ZERO, now);
563 }
564
565 self.complete = false;
566
567 if !first {
568 self.force_end = false;
569 }
570 }
571
572 self.force_end |= reduced_motion;
573 let time = self.clock.time(now);
574 let (frame, iteration, finished) = animation.resolve(time, self.origin, self.force_end);
575 let backward_end = self.clock.speed < 0.0 && time.is_zero();
576 let complete = finished || backward_end;
577
578 self.current = Frame::animated(
579 frame.target(),
580 origin_velocities(frame).map(|v| {
581 v * if self.clock.is_playing() {
582 self.clock.speed
583 } else {
584 0.0
585 }
586 }),
587 !complete && self.clock.is_playing(),
588 complete && !self.complete,
589 );
590
591 if complete && !self.complete {
592 self.observers.resolve(crate::CompletionStatus::Completed);
593 }
594
595 self.complete = complete;
596 self.iteration = iteration;
597
598 self.current
599 }
600
601 pub fn pause(&mut self, now: Duration) {
603 self.clock.pause(now);
604 }
605
606 pub fn play(&mut self, now: Duration) {
608 self.clock.play(now);
609 }
610
611 pub fn stop(&mut self, now: Duration) {
613 self.pause(now);
614 }
615
616 pub fn seek(&mut self, time: Duration, now: Duration) {
618 self.clock.seek(time, now);
619 }
620
621 pub fn set_speed(&mut self, speed: f64, now: Duration) -> Result<(), AnimationError> {
623 self.clock.set_speed(speed, now)
624 }
625
626 pub fn restart(&mut self, now: Duration) {
628 self.observers.resolve(crate::CompletionStatus::Cancelled);
629 self.clock.seek(Duration::ZERO, now);
630 self.clock.play(now);
631 self.force_end = false;
632 self.complete = false;
633 }
634
635 pub fn finish(&mut self) {
637 self.force_end = true;
638 }
639
640 pub fn completion(&mut self) -> crate::Completion {
643 self.observers.subscribe(self.complete)
644 }
645
646 pub fn cancel(&mut self, now: Duration) {
649 self.pause(now);
650 self.observers.resolve(crate::CompletionStatus::Cancelled);
651 }
652
653 pub(crate) fn current_velocity(&self) -> f64 {
654 self.current.velocity()[0]
655 }
656
657 pub fn iteration(&self) -> u64 {
659 self.iteration
660 }
661
662 pub fn is_complete(&self) -> bool {
664 self.complete
665 }
666
667 pub fn is_playing(&self) -> bool {
669 self.clock.is_playing()
670 }
671}
672
673#[derive(Clone, Copy, Debug, PartialEq, Eq)]
675pub enum StaggerFrom {
676 Start,
678 End,
680 Center,
682}
683
684pub fn stagger(
686 step: Duration,
687 ix: usize,
688 count: usize,
689 from: StaggerFrom,
690) -> Result<Duration, AnimationError> {
691 if count == 0 || ix >= count {
692 return Err(AnimationError::Index);
693 }
694
695 let distance = match from {
696 StaggerFrom::Start => ix as f64,
697 StaggerFrom::End => (count - 1 - ix) as f64,
698 StaggerFrom::Center => (ix as f64 - (count - 1) as f64 / 2.0).abs(),
699 };
700
701 Ok(Duration::try_from_secs_f64(step.as_secs_f64() * distance).unwrap_or(Duration::MAX))
702}
703
704#[derive(Debug)]
705struct Track {
706 at: Duration,
707 animation: Animation,
708 state: AnimationState,
709}
710
711#[derive(Debug, Default)]
713pub struct Timeline {
714 tracks: Vec<Track>,
715 frames: Vec<Frame>,
716 clock: Playback,
717 cursor: Option<Duration>,
718 labels: Vec<(String, Duration)>,
719 active: bool,
720}
721
722impl Timeline {
723 pub fn at(&mut self, at: Duration, animation: Animation) -> usize {
725 let end = animation
726 .duration()
727 .map(|duration| at.saturating_add(duration));
728
729 self.cursor = end;
730 let mut state = AnimationState::default();
731
732 state.sample(&animation, Duration::ZERO, false);
733 self.frames.push(Frame::at(Target::default()));
734 self.tracks.push(Track {
735 at,
736 animation,
737 state,
738 });
739
740 self.tracks.len() - 1
741 }
742
743 pub fn then(&mut self, animation: Animation) -> Result<usize, AnimationError> {
745 let at = if self.tracks.is_empty() {
746 Duration::ZERO
747 } else {
748 self.cursor.ok_or(AnimationError::InfiniteSequence)?
749 };
750
751 Ok(self.at(at, animation))
752 }
753
754 pub fn label(&mut self, name: impl Into<String>) -> Result<(), AnimationError> {
756 let name = name.into();
757
758 if self.labels.iter().any(|(n, _)| *n == name) {
759 return Err(AnimationError::Label);
760 }
761
762 let at = if self.tracks.is_empty() {
763 Duration::ZERO
764 } else {
765 self.cursor.ok_or(AnimationError::InfiniteSequence)?
766 };
767
768 self.labels.push((name, at));
769
770 Ok(())
771 }
772
773 pub fn at_label(
775 &mut self,
776 name: &str,
777 offset: Duration,
778 animation: Animation,
779 ) -> Result<usize, AnimationError> {
780 let at = self
781 .labels
782 .iter()
783 .find(|(n, _)| n == name)
784 .ok_or(AnimationError::Label)?
785 .1;
786
787 Ok(self.at(at.saturating_add(offset), animation))
788 }
789
790 pub fn restart(&mut self, now: Duration) {
792 self.clock.seek(Duration::ZERO, now);
793 self.clock.play(now);
794
795 for track in &mut self.tracks {
796 track.state.restart(now);
797 }
798 }
799
800 pub fn pause(&mut self, now: Duration) {
802 self.clock.pause(now);
803 }
804
805 pub fn play(&mut self, now: Duration) {
807 self.clock.play(now);
808 }
809
810 pub fn seek(&mut self, time: Duration, now: Duration) {
812 self.clock.seek(time, now);
813 }
814
815 pub fn set_speed(&mut self, speed: f64, now: Duration) -> Result<(), AnimationError> {
817 self.clock.set_speed(speed, now)
818 }
819
820 pub fn sample(&mut self, now: Duration, reduced_motion: bool) -> &[Frame] {
822 let playhead = self.clock.time(now);
823 let playing = self.clock.is_playing() && !(self.clock.speed < 0.0 && playhead.is_zero());
824
825 self.active = false;
826
827 for (track, output) in self.tracks.iter_mut().zip(&mut self.frames) {
828 let local = playhead.saturating_sub(track.at);
829
830 track.state.seek(local, now);
831 let frame = track.state.sample(&track.animation, now, reduced_motion);
832 let pending = playhead < track.at && !reduced_motion;
833
834 self.active |= (pending || frame.is_animating()) && playing;
835 *output = Frame::animated(
836 frame.target(),
837 origin_velocities(frame).map(|v| {
838 if pending || !playing {
839 0.0
840 } else {
841 v * self.clock.speed
842 }
843 }),
844 !pending && frame.is_animating() && playing,
845 !pending && frame.just_completed(),
846 );
847 }
848
849 &self.frames
850 }
851
852 pub fn is_animating(&self) -> bool {
854 self.active
855 }
856}
857
858impl PartialEq for Animation {
859 fn eq(&self, other: &Self) -> bool {
860 self.same(other)
861 }
862}