#bevy #animation #easing #tweening


Tweening animation plugin for the Bevy game engine

11 releases (7 breaking)

0.8.0 Jul 12, 2023
0.7.0 Mar 9, 2023
0.6.0 Nov 15, 2022
0.4.0 Apr 16, 2022
0.1.0 Dec 24, 2021

#12 in Game dev

Download history 458/week @ 2023-06-04 348/week @ 2023-06-11 665/week @ 2023-06-18 760/week @ 2023-06-25 553/week @ 2023-07-02 482/week @ 2023-07-09 496/week @ 2023-07-16 566/week @ 2023-07-23 402/week @ 2023-07-30 532/week @ 2023-08-06 616/week @ 2023-08-13 427/week @ 2023-08-20 449/week @ 2023-08-27 767/week @ 2023-09-03 732/week @ 2023-09-10 670/week @ 2023-09-17

2,658 downloads per month
Used in 4 crates


2.5K SLoC

🍃 Bevy Tweening

License: MIT/Apache Doc Crate Build Status Coverage Status Bevy tracking

Tweening animation plugin for the Bevy game engine.


  • Animate any field of any component or asset, including custom ones.
  • Run multiple tweens (animations) per component/asset in parallel.
  • Chain multiple tweens (animations) one after the other for complex animations.
  • Raise a Bevy event or invoke a callback when an tween completed.



Add to Cargo.toml:

bevy_tweening = "0.8"

This crate supports the following features:

Feature Default Description
bevy_asset Yes Enable animating Bevy assets (Asset) in addition of components.
bevy_sprite Yes Includes built-in lenses for some Sprite-related components.
bevy_ui Yes Includes built-in lenses for some UI-related components.
bevy_text Yes Includes built-in lenses for some Text-related components.

System setup

Add the TweeningPlugin to your app:


Animate a component

Animate the transform position of an entity by creating a Tween animation for the transform, and adding an Animator component with that tween:

// Create a single animation (tween) to move an entity.
let tween = Tween::new(
    // Use a quadratic easing on both endpoints.
    // Animation time (one way only; for ping-pong it takes 2 seconds
    // to come back to start).
    // The lens gives the Animator access to the Transform component,
    // to animate it. It also contains the start and end values associated
    // with the animation ratios 0. and 1.
    TransformPositionLens {
        start: Vec3::ZERO,
        end: Vec3::new(1., 2., -4.),
// Repeat twice (one per way)
// After each iteration, reverse direction (ping-pong)

    // Spawn a Sprite entity to animate the position of.
    SpriteBundle {
        sprite: Sprite {
            color: Color::RED,
            custom_size: Some(Vec2::new(size, size)),
    // Add an Animator component to control and execute the animation.

Chaining animations

Bevy Tweening supports several types of tweenables, building blocks that can be combined to form complex animations. A tweenable is a type implementing the Tweenable<T> trait.

  • Tween - A simple tween (easing) animation between two values.
  • Sequence - A series of tweenables executing in series, one after the other.
  • Tracks - A collection of tweenables executing in parallel.
  • Delay - A time delay.

Most tweenables can be chained with the then() operator:

// Produce a sequence executing 'tween1' then 'tween2'
let tween1 = Tween { [...] }
let tween2 = Tween { [...] }
let seq = tween1.then(tween2);

Predefined Lenses

A small number of predefined lenses are available for the most common use cases, which also serve as examples. Users are encouraged to write their own lens to tailor the animation to their use case.

The naming scheme for predefined lenses is "<TargetName><FieldName>Lens", where <TargetName> is the name of the target Bevy component or asset type which is queried by the internal animation system to be modified, and <FieldName> is the field which is mutated in place by the lens. All predefined lenses modify a single field. Custom lenses can be written which modify multiple fields at once.

Bevy Components

Target Component Animated Field Lens Feature
Transform translation TransformPositionLens
rotation (Quat TransformRotationLens
rotation (angle)² TransformRotateXLens
rotation (angle)² TransformRotateYLens
rotation (angle)² TransformRotateZLens
rotation (angle)² TransformRotateAxisLens
scale TransformScaleLens
Sprite color SpriteColorLens bevy_sprite
Style position UiPositionLens bevy_ui
Text TextStyle::color TextColorLens bevy_text

¹ Shortest-path interpolation between two rotations, using Quat::slerp().

² Angle-based interpolation, valid for rotations over ½ turn.

See the comparison of rotation lenses for details.

Bevy Assets

Asset animation always requires the bevy_asset feature.

Target Asset Animated Field Lens Feature
ColorMaterial color ColorMaterialColorLens bevy_asset + bevy_sprite

Custom lens

A custom lens allows animating any field or group of fields of a Bevy component or asset. A custom lens is a type implementing the Lens trait, which is generic over the type of component or asset.

struct MyXAxisLens {
    start: f32,
    end: f32,

impl Lens<Tranform> for MyXAxisLens {
    fn lerp(&self, target: &mut Tranform, ratio: f32) -> f32 {
        let start = Vec3::new(self.start, 0., 0.);
        let end = Vec3::new(self.end, 0., 0.);
        target.translation = start + (end - start) * ratio;

Note that the lens always linearly interpolates the field(s) of the component or asset. The type of easing applied modifies the rate at which the ratio parameter evolves, and is applied before the lerp() function is invoked.

The basic formula for lerp (linear interpolation) is either of:

  • start + (end - start) * scalar
  • start * (1.0 - scalar) + end * scalar

The two formulations are mathematically equivalent, but one may be more suited than the other depending on the type interpolated and the operations available, and the potential floating-point precision errors.

Custom component support

Custom components are animated like built-in Bevy ones, via a lens.

struct MyCustomComponent(f32);

struct MyCustomLens {
    start: f32,
    end: f32,

impl Lens<MyCustomComponent> for MyCustomLens {
    fn lerp(&self, target: &mut MyCustomComponent, ratio: f32) -> f32 {
        target.0 = self.start + (self.end - self.start) * ratio;

Then, in addition, the system component_animator_system::<CustomComponent> needs to be added to the application. This system will extract each frame all CustomComponent instances with an Animator<CustomComponent> on the same entity, and animate the component via its animator.

Custom asset support

The process is similar to custom components, creating a custom lens for the custom asset. The system to add is asset_animator_system::<CustomAsset>. This requires the bevy_asset feature (enabled by default).


See the examples/ folder.


cargo run --example menu --features="bevy/bevy_winit"



cargo run --example sprite_color --features="bevy/bevy_winit"



cargo run --example transform_rotation --features="bevy/bevy_winit"



cargo run --example transform_translation --features="bevy/bevy_winit"



cargo run --example colormaterial_color --features="bevy/bevy_winit"



cargo run --example ui_position --features="bevy/bevy_winit"



cargo run --example sequence --features="bevy/bevy_winit"


Ease Functions

Many ease functions are available:

  • QuadraticIn
  • QuadraticOut
  • QuadraticInOut
  • CubicIn
  • CubicOut
  • CubicInOut
  • QuarticIn
  • QuarticOut
  • QuarticInOut
  • QuinticIn
  • QuinticOut
  • QuinticInOut
  • SineIn
  • SineOut
  • SineInOut
  • CircularIn
  • CircularOut
  • CircularInOut
  • ExponentialIn
  • ExponentialOut
  • ExponentialInOut
  • ElasticIn
  • ElasticOut
  • ElasticInOut
  • BackIn
  • BackOut
  • BackInOut
  • BounceIn
  • BounceOut
  • BounceInOut

Compatible Bevy versions

The main branch is compatible with the latest Bevy release.

Compatibility of bevy_tweening versions:

bevy_tweening bevy
0.8 0.11
0.7 0.10
0.6 0.9
0.5 0.8
0.4 0.7
0.2-0.3 0.6
0.1 0.5

Due to the fast-moving nature of Bevy and frequent breaking changes, and the limited resources to maintan 🍃 Bevy Tweening, the main (unreleased) Bevy branch is not supported. However the bevy_tweening crate is upgraded shortly after each new bevy release to support the newly released version.

Comparison with bevy_easings

The bevy_tweening library started as a fork of the bevy_easings library by François Mocker, with the goals to:

  • explore an alternative design based on lenses instead of generic types for each easer/animator. This reduces both the number of generic types needed, and hopefully the code size, as well as the number of systems needed to perform the interpolation.
  • improve the interpolation of assets to avoid creating many copies like bevy_easings does, and instead mutate the assets (and, by similarity, the components too) in-place without making a copy. The in-place mutation also allows a more optimal interpolation limited to modifying the fields of interest only, instead of creating a new copy of the entire component each tick.


~1M SLoC