Open ydaniv opened 1 year ago
Had a talk with @andruud regarding using the last_progress
for this and seems this is possible technically.
cc @bramus
This is a creative interpretation of playback rate which I can see how at a high level fits. However, playback rate already has a very specific definition of how it affects animation timing which is heavily used in many of the calculations. A negative playback rate is also used to reverse animations. All of this currently works as spec'd on scroll animations. This would make playback rate have special behavior for non-time based animations, and it would be really hard to avoid unexpected issues when other timing related properties change at the same time - as the proposed behavior is based on the previous state. E.g. what happens if you change the start time of the animation, or the duration, does it slowly progress towards the new time value?
it's effectively a linear interpolation on each frame between current progress and last progress
Naively, this would make the speed of the adjustment depend on the frame rate the browser is able to render or particular device framerates. I would think that if we have a mechanism for doing this it should be framerate independent, i.e. based on the time that had passed. Also while the progress per frame is a linear interpolation, the progress over time will be non-linear, e.g. it'll make 0.5, then 0.75, then 0.875 progress never technically getting to the current time value.
I do feel like this is the same high level feature as issue #7059, just approaching it from a different direction.
However, playback rate already has a very specific definition of how it affects animation timing which is heavily used in many of the calculations
Right, so effectively when calculating current time for ScrollTimeline:
current time = scroll offset ÷ (scrollable overflow size − scroll container size)
You get:
current time = = last current time × (1 - playback rate) + scroll offset ÷ (scrollable overflow size − scroll container size) × playback rate
Where last current time
is the last cached value for current time.
And of course it follows that:
A negative playback rate is also used to reverse animations
That still holds true.
This would make playback rate have special behavior for non-time based animations
Yes, but not something we don't already have.
and it would be really hard to avoid unexpected issues when other timing related properties change at the same time - as the proposed behavior is based on the previous state.
I tried to see how, I think the we can infer the rest of the properties from the above formula.
E.g. what happens if you change the start time of the animation, or the duration, does it slowly progress towards the new time value?
Yes. After reflow the next frame should calculate the new progress, according to the cached value and new layout, and produce the next frame. So you'll get an interpolation towards the new progress value.
Naively, this would make the speed of the adjustment depend on the frame rate the browser is able to render or particular device framerates. I would think that if we have a mechanism for doing this it should be framerate independent, i.e. based on the time that had passed.
Yes, for sure. I think one way to make it framerate independent could be normalizing the frame rate to 60fps (or the timeline's frame rate according to #7196), but I think this requires something that's not a trivial division. Otherwise, yes, we'd need to base that on timestamp deltas.
Also while the progress per frame is a linear interpolation, the progress over time will be non-linear, e.g. it'll make 0.5, then 0.75, then 0.875 progress never technically getting to the current time value.
Exactly. The result creates a nice some-sort-of-bezier curve movement. This is expected. But I think using linear interpolation for the core calculation is pretty straight forward to reason with, and the result is quite nice (: It's also a quite common method in games dev/graphic tools/etc.
I do feel like this is the same high level feature as issue https://github.com/w3c/csswg-drafts/issues/7059, just approaching it from a different direction.
Yes, the result is quite similar, but different. Some libraries use that transition method, like GSAP's scrub option, while other use lerping like locomotive scroll's lerp.
A common pattern in animations based on scroll/hover is adding interpolation from last position to current position, so that a smooth movement is achieved even on abrupt progress changes, e.g. clicking on the scrollbar in a different location.
I proposed adding this effect by defining the interaction of
Animation.playbackRate
with non time-based animations here: https://github.com/w3c/csswg-drafts/issues/7059#issuecomment-1415913052.The Web Animations API 1 spec of Animation's playbackRate:
If we translate that into non time-based (non-monotonic timelines) it's effectively a linear interpolation on each frame between current progress and last progress, so on each frame the progress' update becomes:
And this maintains an effectively paused animation on
playbackRate == 0
and a flipped progress forplaybackRate == -1
.In respect to Scroll-driven timelines progress is described as:
I've created a demo that I hopes at least captures the nature of this feature: https://codepen.io/ydaniv/pen/VwBojoN Notice that the effect is mostly prominent from
playbackRate=~0.1
and below, because of its exponential nature.I think this feature is orthogonal to the Transition delays feature suggested in #7059, although it creates a similar effect.
cc @birtles @flackr @fantasai @smfr