Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom interpolation function #352

Closed
andreasplesch opened this issue Jul 2, 2017 · 8 comments
Closed

custom interpolation function #352

andreasplesch opened this issue Jul 2, 2017 · 8 comments

Comments

@andreasplesch
Copy link
Contributor

andreasplesch commented Jul 2, 2017

This issue is for thinking through an idea rather than for an actual issue with the library or even a feature request.

Arrays as target (to) values are allowed and the defined intervals are currently spread evenly such that each interval takes the same fraction of the total duration of the tween. For example, if there are four intervals (array length is five) and the total duration is 1000ms each interval takes 250ms. This behaviour is defined by the (linear, probably all) array interpolation function.

What I would like to have is an additional array of interpolation progress keys that make it possible to define uneven duration intervals, eg. different speeds for each interval. There would the same number of progress keys as target values. For example if there are five value array items [0, 2, 3, 3.5, 1] there would be five progress key array items [0, 0.1, 0.5, 0.9, 1]. The value 2 would be then returned as the result of the interpolation function when progress is 10% of the total duration, for example.

This is similar to chaining of tweens but has several advantages. It can be more concise, the behaviour can be exactly defined, eg. there is no question when exactly the next tween starts and is applied, it can be perhaps more efficient, and is more familiar as a key frames concept. Easing could be applied to the complete function, not just per tween.

Since this amount to modified or additional interpolation functions which take the progress key array as an additional argument, a generalization would be allowing custom interpolation functions.

@andreasplesch
Copy link
Contributor Author

andreasplesch commented Jul 2, 2017

Ok, it looks like it is possible to provide a custom interpolation function to .interpolation . Is there an example somewhere ? One could probably just follow https://github.com/tweenjs/tween.js/blob/master/src/Tween.js#L771. Indeed, here is an example:

https://clear-apparel.glitch.me/

But it could only accept the to array (end) and the progress as parameters, and not an additional parameter which actually shapes the custom function. I guess one could make a specific custom function for each tween, or the custom function could access a (global) parameter, perhaps just added to the TWEEN namespace.

@mikebolt
Copy link
Contributor

mikebolt commented Jul 2, 2017 via email

@andreasplesch
Copy link
Contributor Author

https://glitch.com/edit/#!/rightful-chopper?path=views/index.html:59:12

is more or less what I had in mind.

I do not think a custom easing function is easy to derive when you want to have exact values at given times during the interpolation ?

You would need to know to what time a certain value corresponds to for the uneased function. It becomes an inverse problem.

Let me think about the other parts of your response.

Since it seems not too cumbersome to come up with custom interpolation functions, I do not think there is an argument for expanding the library. But examples for custom functions would be helpful.

@mikebolt
Copy link
Contributor

mikebolt commented Jul 3, 2017 via email

@andreasplesch
Copy link
Contributor Author

I could think more clearly about what the corresponding easing function would need to be. It turns out that we do know exactly when the uneased function reaches the array values, since the duration is evenly divided into the intervals. I updated the glitch here to show the equivalent custom easing function:
https://rightful-chopper.glitch.me/
To superimpose one of the standard easing function, presumably it is possible to just apply it to the result of the custom easing function. It could be an additional parameter to the custom function, defaulting to linear (no-op).
The easing approach is mentally backwards and harder to figure out. But it seems cleaner and can be universally applied to any interpolation function.
So if this could be more useful for others, I am not sure now which solution (custom interpolation or custom easing) could be offered as part of the library. Both require generating per tween custom functions.

@andreasplesch
Copy link
Contributor Author

The figure below attempts to explain how a custom easing for keyed frames is constructed. The easing needs to map the current progress to ? progress in the figure. It turns out to be simply a matter of finding the fractional progress in the current segment, and then applying this fraction to the corresponding segment in the evenly spaced, regular tween segments. In the example below this works out as:
fractional progress in current segment: f=( 0.8-0.2 ) / ( 1-0.2 ) = 0.6/0.8 = 0.75
eased final progress: 0.5 + f * (1-0.5) = 0.5 + 0.75 * 0.5 = 0.875

image

@trusktr
Copy link
Member

trusktr commented Jun 3, 2020

It can be more concise, the behaviour can be exactly defined

Sidenote, there's no question when the next tween starts with chained tweens, they are perfectly aligned with the previous tween's time. See here:

tween.js/src/Tween.ts

Lines 402 to 405 in 1f85d6e

for (let i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) {
// Make the chained tweens start exactly at the time they should,
// even if the `update()` method was called way past the duration of the tween
this._chainedTweens[i].start(this._startTime + this._duration)

But true, it can be more concise.

Easing could be applied to the complete function, not just per tween.

And that would be nice!

This is similar to features CSS @keyframes has. 👍

looks like it is possible to provide a custom interpolation function to .interpolation

That's true, but this feature would make it easier and more concise.

If you do make a custom interpolation function generator, it could be used like this:

const tween = new Tween({scaleX: 0})
tween
  .to({scaleX: [0.25, 0.5, 0.75, 1]})
  .interpolation(percentInterpolation([10, 25, 75, 90]))

The equivalent in CSS would be:

@keyframes my-keyframes {
    0% { transform: scaleX(0); }
    10% { transform: scaleX(0.25); }
    25% { transform: scaleX(0.5); }
    75% { transform: scaleX(0.75); }
    100% { transform: scaleX(1); }
}

Also note, that in CSS, these key frames are saved to a my-keyframes variables, so the key frames can be re-used in any animation that can have any number of key frames with separate easing functions (i.e. they are composable onto an object's tween). We can probably borrow some concepts from CSS here.

I do not think a custom easing function is easy to derive when you want to have exact values at given times during the interpolation ?

Definitely! A declarative API (perhaps inspired by CSS, but a new chained API in Tween.js) would for sure make it easier, especially for someone who wants to focus on the experience they are making rather than the math involved with making interpolation functions.

I am not sure now which solution (custom interpolation or custom easing) could be offered as part of the library. Both require generating per tween custom functions.

I would argue let's focus on declarative APIs (taking some inspiration from CSS for example, though in the Tween.js chained syntax). However if there is anything we can do to make things easier for those people that want to make custom functions, let's think about API for them too.

The figure below attempts to explain how a custom easing for keyed frames is constructed.

Great diagram! I think that's a good idea. I haven't used interpolations in any projects yet (the need hasn't been there). If I understand correctly, an interpolation function basically sets up a "scrubber" (for all intents and purposes), and an easing function effectively scrubs across the timeline at different speeds. Is that how you imagine it @andreasplesch ?

@trusktr
Copy link
Member

trusktr commented Apr 23, 2023

I think this issue would complicate the Tween too much. Instead, I think it would be more valuable to be able to achieve these sorts of things with a higher level Timeline API: #647

@trusktr trusktr closed this as completed Apr 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants