Skip to content

Guide Animation

MeowLynxSea edited this page Feb 16, 2026 · 5 revisions

Animation

A unified animation system providing preset animations, easing functions, constants, and orchestration capabilities for UI components.

Overview

The animation module provides a comprehensive set of tools for creating smooth, performant UI animations. It builds on top of gpui's Animation and Transition APIs, offering:

  • Easing functions: Mathematical easing functions for natural motion
  • Preset animations: Ready-to-use common animation patterns
  • Animation configuration: Configurable animation settings with duration, easing, delay, and repeat options
  • Animation state: State tracking for complex animations
  • Orchestration: Sequence, parallel, and staggered animation playback
  • Helper utilities: Interpolation functions and extension traits

Quick Start

use yororen_ui::animation::{
    fade_slide_in,
    constants::duration::MENU_OPEN,
};

// Apply preset animation to a gpui element
div.with_animation(
    "menu-open",
    Animation::new(MENU_OPEN),
    fade_slide_in(MENU_OPEN),
)

When to Use

  • Menu/dropdown open/close animations
  • Modal dialog transitions
  • Loading states (pulse, spin)
  • Hover/focus state transitions
  • Page/component entrance animations

Not a good fit:

  • Complex physics-based animations (use custom implementation)
  • Frame-by-frame procedural animations

Modules

Easing Functions (easing.rs)

Provides mathematical easing functions for controlling animation timing. All functions take a normalized time value (0.0 to 1.0) and return the eased progress value.

Linear

Function Description
ease_linear No easing, linear progression

Quadratic (Power 2)

Function Description
ease_in_quad Starts slow, accelerates
ease_out_quad Starts fast, decelerates
ease_in_out_quad Slow start and end, fast middle

Cubic (Power 3)

Function Description
ease_in_cubic Starts slow, accelerates
ease_out_cubic Starts fast, decelerates
ease_in_out_cubic Slow start and end, fast middle

Quartic (Power 4)

Function Description
ease_in_quart Starts slow, accelerates
ease_out_quart Starts fast, decelerates
ease_in_out_quart Slow start and end, fast middle

Quintic (Power 5)

Function Description
ease_in_quint Starts slow, accelerates
ease_out_quint Starts fast, decelerates
ease_in_out_quint Slow start and end, fast middle

Sine

Function Description
ease_in_sine Starts slow, accelerates
ease_out_sine Starts fast, decelerates
ease_in_out_sine Slow start and end, fast middle

Exponential

Function Description
ease_in_expo Very slow start, accelerates sharply
ease_out_expo Fast start, decelerates sharply
ease_in_out_expo Very slow start and end, fast middle

Circular

Function Description
ease_in_circ Starts slow, accelerates
ease_out_circ Starts fast, decelerates
ease_in_out_circ Slow start and end, fast middle

Back (Overshoot)

Creates a slight overshoot effect before settling.

Function Description
ease_out_back Overshoots target, then settles
ease_in_out_back Overshoots at both ends

Elastic

Creates a spring-like bouncing effect.

Function Description
ease_in_elastic Bounces at the start
ease_out_elastic Bounces at the end
ease_in_out_elastic Bounces at both ends

Bounce

Creates a bouncing effect like a ball hitting the ground.

Function Description
ease_in_bounce Bounces at the start
ease_out_bounce Bounces at the end
ease_in_out_bounce Bounces at both ends

Basic Easing (Matching gpui)

Simple quadratic easing functions that match gpui's built-in easing.

Function Description
ease_in Quadratic ease in
ease_out Quadratic ease out
ease_in_out Quadratic ease in-out

Type Alias

pub type EasingFn = fn(f32) -> f32;

Preset Animations (preset.rs)

Provides ready-to-use animation functions that can be applied directly to gpui elements.

Animation Types

pub enum AnimationType {
    FadeIn,
    FadeOut,
    SlideIn(SlideDirection),
    SlideOut(SlideDirection),
    ScaleIn,
    ScaleOut,
    BounceIn,
    BounceOut,
    ElasticIn,
    ElasticOut,
    FadeSlideIn(SlideDirection),
    FadeScaleIn,
}

pub enum SlideDirection {
    Left,
    Right,
    Up,
    Down,
}

Preset Functions

Function Description
fade_slide_in(duration) Fade + slide up for menus (opacity 0→1, translate 10px→0)
fade_slide_out(duration) Reverse of fade_slide_in (opacity 1→0, translate 0→10px)
pulse(duration) Loading pulse animation (opacity 0.55→0.95)
fade_slide_in_left(distance) Slide from left with fade
fade_slide_in_right(distance) Slide from right with fade
fade_slide_in_up(distance) Slide from top with fade
fade_slide_in_down(distance) Slide from bottom with fade

Fade Structs

Struct Description
FadeIn Fade in animation builder with custom easing support
FadeOut Fade out animation (opacity 1→0)

Duration Constants (preset module)

use yororen_ui::animation::preset::duration;

duration::VERY_FAST  // 100ms
duration::FAST      // 150ms
duration::NORMAL    // 200ms
duration::SLOW      // 300ms
duration::VERY_SLOW // 400ms
duration::INSTANT   // 0ms

Animation Configuration (config.rs)

Provides configuration and state tracking for animations.

AnimationConfig

Configurable animation settings:

pub struct AnimationConfig {
    pub duration: Duration,
    pub easing: EasingFn,
    pub delay: Duration,
    pub repeat: bool,
    pub reverse: bool,
}

Example:

use yororen_ui::animation::AnimationConfig;
use std::time::Duration;

let config = AnimationConfig::new()
    .with_duration(Duration::from_millis(300))
    .with_easing(ease_out_cubic)
    .with_delay(Duration::from_millis(100))
    .with_repeat()
    .with_reverse(); // yoyo effect

AnimationState

Track animation progress and status:

pub struct AnimationState {
    pub progress: f32,      // 0.0 to 1.0
    pub is_running: bool,
    pub is_paused: bool,
}

Example:

use yororen_ui::animation::AnimationState;

let mut state = AnimationState::new();
state.update(0.5);  // Set progress to 50%
state.reset();      // Reset to initial state

Animation Constants (constants.rs)

Provides timing constants for consistent animation timing across the library.

Cursor

Constant Duration
CURSOR_BLINK_INTERVAL 500ms

Menu / Dropdown

Constant Duration
duration::MENU_OPEN 160ms
duration::MENU_OPEN_FAST 100ms
duration::MENU_OPEN_SLOW 250ms

Navigator / Slider

Constant Duration
duration::NAVIGATOR_SLIDER 200ms
duration::TAB_SWITCH 150ms

Loading / Skeleton

Constant Duration
duration::SKELETON_PULSE_1 1100ms
duration::SKELETON_PULSE_2 1200ms

Progress / Spinner

Constant Duration
duration::PROGRESS_SPINNER 850ms
duration::PROGRESS_CIRCLE 900ms
duration::PROGRESS_BAR 1500ms

Modal / Dialog

Constant Duration
duration::MODAL_FADE_IN 200ms
duration::MODAL_SLIDE_UP 250ms

Tooltip

Constant Duration
duration::TOOLTIP_SHOW 150ms
duration::TOOLTIP_HIDE 100ms

General Purpose

Constant Duration
duration::VERY_FAST 100ms
duration::FAST 150ms
duration::NORMAL 200ms
duration::SLOW 300ms
duration::VERY_SLOW 400ms

Orchestration (orchestrator.rs)

Provides capabilities for sequencing and parallelizing multiple animations.

AnimationSequence

Run animations one after another:

use yororen_ui::animation::{AnimationSequence, sequence};
use yororen_ui::animation::constants::duration::*;

// Builder pattern
let seq = AnimationSequence::new()
    .then(MODAL_FADE_IN)
    .then(MODAL_SLIDE_UP);

// Or use convenience function
let seq = sequence(&[MODAL_FADE_IN, MODAL_SLIDE_UP]);

// Query sequence info
let total = seq.total_duration();  // Total duration of all animations
let count = seq.len();             // Number of animations in sequence

// Calculate progress for specific animation
let (anim_index, anim_progress) = seq.calculate_progress(0.5);  // At 50% overall progress

AnimationParallel

Run animations simultaneously:

use yororen_ui::animation::{AnimationParallel, parallel};
use yororen_ui::animation::constants::duration::*;

// Builder pattern
let par = AnimationParallel::new()
    .with(FAST)
    .with(FAST);

// Or use convenience function
let par = parallel(&[FAST, FAST]);

// Query parallel info
let max_duration = par.max_duration();  // Longest animation duration
let count = par.len();                 // Number of parallel animations

// Calculate progress for specific animation
let progress = par.calculate_progress(0.5, 0);  // At 50% overall progress

Staggered Animations

Create staggered delays for list animations:

use yororen_ui::animation::Staggered;
use std::time::Duration;

let base_duration = Duration::from_millis(200);
let delay = Duration::from_millis(50);

// Create staggered delays for 5 items
let delays: Vec<Duration> = base_duration.stagger(5, delay);
// Result: [200ms, 250ms, 300ms, 350ms, 400ms]

Helper Traits and Functions (helpers.rs)

AnimateExt Trait

Extension trait for animating gpui elements directly:

use yororen_ui::animation::AnimateExt;

// Fade animation
div.animate_fade("fade-id", Duration::from_millis(200), 0.5);

// Slide animation
div.animate_slide(
    "slide-id",
    SlideDirection::Up,
    px(10.0),
    Duration::from_millis(200),
    0.5,
);

// Scale animation
div.animate_scale("scale-id", Duration::from_millis(200), 0.5);

SlideDirection

pub enum SlideDirection {
    Left,
    Right,
    Up,
    Down,
}

Interpolation Helpers

lerp

Linear interpolation between two values:

use yororen_ui::animation::lerp;

let start = 0.0;
let end = 100.0;
let value = lerp(start, end, 0.5);  // 50.0
lerp_color

Linear interpolation between two colors:

use yororen_ui::animation::lerp_color;
use gpui::Hsla;

let start = Hsla { h: 0.0, s: 1.0, l: 0.5, a: 1.0 };
let end = Hsla { h: 0.33, s: 1.0, l: 0.5, a: 1.0 };
let color = lerp_color(start, end, 0.5);
animation_id

Create animation IDs for stateful animations:

use yororen_ui::animation::animation_id;

let id = animation_id("menu", OpenState::Open);
// Result: "menu:Open"

Best Practices

1. Use Preset Durations

Stick to the defined constants for consistency across the UI:

// Good
use yororen_ui::animation::constants::duration::MENU_OPEN;

// Avoid
let duration = Duration::from_millis(160);

2. Choose Appropriate Easing

Animation Type Recommended Easing
Entrance animations ease_out_* (fast start, smooth end)
Exit animations ease_in_* (smooth start, fast end)
Equal emphasis ease_in_out_*
Loading/continuous ease_in_out or ease_linear
Attention-grabbing ease_out_back or ease_out_elastic

3. Keep Animations Short

Most UI animations should be 100-300ms:

  • Very fast (100ms): Hover states, tooltips
  • Fast (150ms): Simple toggles, tab switches
  • Normal (200ms): Most transitions, fades
  • Slow (300ms): Complex animations, modals

4. Consider Accessibility

Some users prefer reduced motion. Check for user preferences before applying animations.


Migration Guide

Import Path Changes

Before (old):

use crate::constants::animation::MENU_OPEN;

After:

use yororen_ui::animation::constants::duration::MENU_OPEN;

Using with gpui's with_animation

use yororen_ui::animation::{
    Animation, AnimationExt,
    fade_slide_in,
    constants::duration::MENU_OPEN,
};

menu.with_animation(
    "popover-menu",
    Animation::new(MENU_OPEN),
    fade_slide_in(MENU_OPEN),
)

Complete Example

use yororen_ui::animation::{
    Animation, AnimationExt,
    fade_slide_in, fade_slide_out,
    AnimationSequence, AnimationConfig,
    AnimateExt, SlideDirection,
    constants::duration::*,
    easing::{ease_out_quint, ease_in_out},
    lerp,
};

fn animate_menu_open(menu: gpui::Div) -> gpui::Div {
    menu.with_animation(
        "menu-open",
        Animation::new(MENU_OPEN).with_easing(ease_out_quint()),
        fade_slide_in(MENU_OPEN),
    )
}

fn animate_list_items(items: &[gpui::Div]) {
    use yororen_ui::animation::Staggered;

    let delays = FAST.stagger(items.len(), Duration::from_millis(30));

    for (item, delay) in items.iter().zip(delays) {
        // Apply staggered animation to each item
        item.with_animation(
            "list-item",
            Animation::new(delay).with_easing(ease_out_quint()),
            fade_slide_in(delay),
        );
    }
}

Clone this wiki locally