4. Easing

Why some animations feel natural and others feel robotic — and how to choose.

Loading live preview…

Source of learn_04_easing — edit in the playground
//! Lesson 4 — Easing: how an animation speeds up and slows down.
//!
//! By default animations start slowly, speed up and end slowly. `.ease(..)`
//! picks another curve. Watch the three balls: same distance, same time,
//! different feel.

use oxframe::prelude::*;

#[oxframe::scene]
pub async fn easing(view: View) {
    let lane = |y: f64, name: &str| {
        view.add(
            Txt::new()
                .text(name)
                .family(MONO)
                .font_size(28.0)
                .position((-620.0, y))
                .fill(Color::WHITE.with_alpha(0.6)),
        );
        view.add(
            Circle::new()
                .size(70.0)
                .position((-400.0, y))
                .fill(color!("#68abdf")),
        )
    };
    let linear = lane(-150.0, "LINEAR");
    let smooth = lane(0.0, "default");
    let bouncy = lane(150.0, "OUT_BACK");

    all((
        linear.x().to(500.0, 1.5).ease(presets::LINEAR),
        smooth.x().to(500.0, 1.5),
        bouncy.x().to(500.0, 1.5).ease(presets::OUT_BACK),
    ))
    .await;
    wait_for(0.5).await;
}

// Try: `presets::IN_OUT_EXPO`, `presets::OUT_CUBIC`, or the functions
// `bounce_out` and `elastic_out` (as `.ease(oxframe::bounce_out)`).

pub fn project() -> Project {
    Project::new("easing").scene(easing())
}

All three balls travel the same distance in the same time. The difference is easing: how the speed changes along the way.

  • LINEAR moves at a constant speed. It looks mechanical.
  • The default starts slowly, speeds up, and settles in. Real objects move like this, which is why it is the default.
  • OUT_BACK overshoots a little and comes back — playful, good for things popping in.
ball.x().to(500.0, 1.5).ease(presets::OUT_BACK).await;

presets has the common curves (IN_OUT_CUBIC, OUT_EXPO, IN_OUT_SINE, …). There are also bouncy ones: .ease(oxframe::bounce_out) and .ease(oxframe::elastic_out).