Skip to content

Commit

Permalink
Enable non-linear easing (#42)
Browse files Browse the repository at this point in the history
It seems to me that most of the work to get non-linear easing is already
done.

In order to check what is left to be done I removed the linear-only
enforcement, created a simple example with 3 key frames and compared the
results with lottielab.com editor:

![easing_compare_before](https://github.com/user-attachments/assets/0e7a5df6-f10f-4c45-a31f-f15c75cc8ff2)

I have found that:
- only the easing curves from first two key frames seem to affect the
animation as rendered in lottielab.
- [Lottie
spec](https://lottie.github.io/lottie-spec/latest/specs/properties/)
mentions that: "_All keyframes MUST have an i and o value, unless It is
the last keyframe in the sequence OR ..._"
- This comment mentions that the last one is unused:
airbnb/lottie-web#2620 (comment)

The way I understand it is that while we are moving into position
described by next key frame, we still should be using `o` and `i`
parameters from the previous one.

After changing the `Time::frames_and_weight` to use the easing from
current key frame, positions seem to match pretty well:


![easing_compare_after](https://github.com/user-attachments/assets/d2a563d8-66b4-40d5-a49e-f67fd7dee529)

What do you think? Is there anything else missing to enable non-linear
easing?

Thanks for creating an amazing library!

---------

Co-authored-by: Spencer C. Imbleau <spencer@imbleau.com>
  • Loading branch information
atoktoto and simbleau authored Nov 11, 2024
1 parent c61a290 commit 7c102b0
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# Match Identifier - Case Sensitive
[default.extend-identifiers]
t1_iy = "t1_iy"
t0_iy = "t0_iy"
tranform_before_mask_deprecated = "tranform_before_mask_deprecated"

# Match Inside a Word - Case Insensitive
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ Subheadings to categorize changes are `added, changed, deprecated, removed, fixe

This release has an [MSRV][] of 1.75.

## [0.3.1] - 2024-11-11

This release has an [MSRV][] of 1.75.

### Fixed

- Non-linear easing is now correctly interpolated ([#42] by [@atoktoto])

## [0.3.0] - 2024-07-04

This release has an [MSRV][] of 1.75.
Expand Down Expand Up @@ -52,10 +60,12 @@ This release has an [MSRV][] of 1.75.
[@luke1188]: https://github.com/luke1188
[@MarijnS95]: https://github.com/MarijnS95
[@simbleau]: https://github.com/simbleau
[@atoktoto]: https://github.com/atoktoto

[#16]: https://github.com/linebender/velato/pull/16
[#17]: https://github.com/linebender/velato/pull/17
[#19]: https://github.com/linebender/velato/pull/19
[#42]: https://github.com/linebender/velato/pull/42

[Unreleased]: https://github.com/linebender/velato/compare/v0.3.0...HEAD
[0.3.0]: https://github.com/linebender/velato/compare/v0.2.0...v0.3.0
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ members = ["examples/with_winit", "examples/run_wasm", "examples/scenes"]

[workspace.package]
edition = "2021"
version = "0.3.0"
version = "0.3.1"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/linebender/velato"
# Keep in sync with RUST_MIN_VER in .github/workflows/ci.yml, with the relevant README.md files
Expand Down
28 changes: 12 additions & 16 deletions src/runtime/model/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ impl Time {
let t0 = times[ix0];
let t1 = times[ix1];
let (t0_ox, t0_oy) = t0.out_tangent.map(|o| (o.x, o.y)).unwrap_or((0.0, 0.0));
let (t1_ix, t1_iy) = t1.in_tangent.map(|i| (i.x, i.y)).unwrap_or((1.0, 1.0));
let (t0_ix, t0_iy) = t0.in_tangent.map(|i| (i.x, i.y)).unwrap_or((1.0, 1.0));
let easing = Easing {
o: EasingHandle { x: t0_ox, y: t0_oy },
i: EasingHandle { x: t1_ix, y: t1_iy },
i: EasingHandle { x: t0_ix, y: t0_iy },
};
let hold = t0.hold;
let t = (frame - t0.frame) / (t1.frame - t0.frame);
Expand Down Expand Up @@ -160,20 +160,16 @@ pub trait Tween: Clone + Default {
}

impl Tween for f64 {
fn tween(&self, other: &Self, t: f64, _easing: &Easing) -> Self {
// TODO: We are enforcing linear interpolation for now, but a decent amount of work is done for easings.
keyframe::ease(keyframe::functions::Linear, *self, *other, t)

// FIXME: Hopefully we can finish this up one day!
//keyframe::ease(
// keyframe::functions::BezierCurve::from(
// keyframe::mint::Vector2::from_slice(&[easing.o.x, easing.o.y]),
// keyframe::mint::Vector2::from_slice(&[easing.i.x, easing.i.y]),
// ),
// *self,
// *other,
// t,
//)
fn tween(&self, other: &Self, t: f64, easing: &Easing) -> Self {
keyframe::ease(
keyframe::functions::BezierCurve::from(
keyframe::mint::Vector2::from_slice(&[easing.o.x, easing.o.y]),
keyframe::mint::Vector2::from_slice(&[easing.i.x, easing.i.y]),
),
*self,
*other,
t,
)
}
}

Expand Down

0 comments on commit 7c102b0

Please sign in to comment.