-
Notifications
You must be signed in to change notification settings - Fork 711
[web-animations-2] Add steps for transitioning to/from a scroll timeline. #5423
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
Conversation
See also web-platform-tests/wpt#24832 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this seems right but I'd like it if @ogerchikov could review.
web-animations-1/Overview.bs
Outdated
|
||
</div> | ||
|
||
: |had finite timeline| and |previous current time| is resolved, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be missing an "If" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
web-animations-1/Overview.bs
Outdated
|
||
<div class="switch"> | ||
|
||
: <em>Either</em> of the following conditions are true: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we typically prefix these conditions with "If"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
web-animations-1/Overview.bs
Outdated
<div class="switch"> | ||
|
||
: If <em>either</em> of the following conditions are true: | ||
* |previous playback rate| is 'running' or, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume it's 'previous play state'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. Fixing here and elsewhere.
web-animations-1/Overview.bs
Outdated
|
||
:: Set |animation|'s [=start time=] to |seek time|. | ||
|
||
: If <em>both</em> of the following conditions are true: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we are changing current time of paused animation if the new timeline is active and leaving unchanged otherwise.
I think it's unexpected for the paused animation to change current time.
I suggest leaving the old hold_time unchanged when setting new timeline to paused animation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't preserve current time, we cause a jump in the progress of the animation when transition from a scroll timeline to a document timeline. Here we are setting current time to preserve the current progress in the animation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to followup on my last comment. We are preserving current time if we can, and leaving it along otherwise. Transitioning between scroll timelines is handled in the previous branch. AFAIK, the only way for the document timeline to be inactive is if the animation clock has not ticked yet. If the new timeline is null, it will simply preserve the previous scroll timeline's value of hold time.
Handling in this manner, no distinction needs to be made regarding whether the animation was running at the time of the timeline change.
web-animations-1/Overview.bs
Outdated
|
||
: If |had finite timeline| and |previous current time| is resolved, | ||
|
||
:: Set the |animation|'s [=hold time=] to |previous current time|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
start_time value will be resolved here if the animation is not paused. In this case hold_time set here will be cleared in the following statement (l. 879)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, this should ahve read [=current time=] and not [=hold time=]. Making the correction.
web-animations-1/Overview.bs
Outdated
<div class="switch"> | ||
|
||
: If |animation| has an associated | ||
<a>timeline</a> that is not [=monotonically increasing=], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest adding a variable 'has finite timeline' to improve readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about hat but 'had finite timeline' and 'has finite timeline' look too similar and could be confused at a glance. Perhaps "from finite timeline' and 'to finite timeline'.
web-animations-1/Overview.bs
Outdated
<div class="switch"> | ||
|
||
: If <em>either</em> of the following conditions are true: | ||
* |previous playback rate| is 'running' or, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if it makes more sense to look at previous start/hold time instead of play states to determine what should be new start/hold time. The reason is that applying this logic on play/pause pending animations may introduce new states (see this state chart)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching the logic to rely on start and hold time, would also require factoring in the pending state. Once pending state is introduced into the equation we essentially end up replicating the functionality of calculating the play state. The new WPT tests associated with the Blink change test changing the timeline on both pending and non-pending animations.
Taking a step back to cover the options at a higher level, which should hopefully help us to reach consensus on which path to adopt. Starting with some high level design considerations:
const animation = new Animation(..., scrollTimeline); and const animation = element.animate(); Option1:
I believe the phase shift is unexpected behavior especially when using scroll timelines via CSS rules and the animation-timeline property. Nonetheless, including it here for discussion. Option 2:
Option 3:
There may be other options to consider and would welcome any feedback. Option 3 (my new preference) is not what is currently implemented in the pull request, but would like some feedback before proceeding with the next update. |
Thanks for writing this up. Sorry for my ignorance, but what is the "phase shift" we are concerned about here? Also, would it be correct that option 3 also introduces special casing for scroll timelines? Or is it a different kind of special casing to that of option 2? |
Using the term "phase shift" to indicate the progress getting out of sync with the scroll position, being either ahead or behind the scroll position by a fixed amount if the start time is not adjusted. Yes both option 2 and 3 have special casing for scroll timelines, which I should have listed under cons for option 3. In fact, for option 3, it's in 2 methods (setTimeline and play). The main difference between options 2 and 3 in terms of observable behavior is in the handling of pause/unpause. In option 2, we adjust current time to align with the scroll position when changing the timeline for either a playing or paused animation. With option 3, setting the timeline of a paused animation does not trigger a jump to sync with the scroll position. Instead, it is deferred until we resume playing the animation. A potential gotcha with option 2 is when setting the timeline of a paused animation when the new scroll timeline is inactive. In this case, we don't know what the hold time should be set to in order to align with the scroll position once the timeline becomes active once again. Deferring the decision until play resolves the issue, since even if the timeline remains inactive we know whether start should be set to 0 or effect end. This awkward edge case with option 2 is the main reason for my shift towards option 3 as a preference. |
Thanks @kevers-google for listing the options. I believe the main motivation for making this change right now is supporting scroll timeline via CSS. Do you know for which CSS scenarios updating timeline is required and what is broken if we just follow existing procedure? Perhaps we should concentrate on those since when setting timeline via Javascript user can set desired start/current time. |
One of the great things with the web animations API is that, for the most part, animations constructed via CSS behave consistently with animations created via JavaScript. Sure there is more control from JavaScript, but there is a common baseline. In fact, we can freely mix the two approaches by applying CSS style changes from JavaScript, or by fetching CSS animations via getAnimations. The primary goal with the proposed algorithm is to maintain a consistent and expected behavior between CSS and JavaScript animations. By "existing procedure" I assume that you mean the one that is currently published in web-animations-1 and not the one in this pull request. case 1: Transitioning from a document timeline to a scroll timeline @Keyframes fade-anim { ... } In this example, if an animation is created by adding the fade class and then later the animation is attached to a scrollbar via the scrolling-animation class we can wind up with some weird inconsistencies. case 1a: animation is play-pending when scroll timeline is added. case 1b: animation is pause-pending when the scroll timeline is added case 1c: animation is running when scroll timeline is added. case 1d: animation is paused when scroll timeline is added. case 1e: animation is idle when the scroll timeline is added. The question may arise, "well why can't the developer simply avoid these cases by setting the timeline in the same frame where the animation starts?" One reason might be that the scroll-timeline attachment is deferred until content is loaded to avoid jank. The developer could inadvertently change the flow by querying style during the process of attaching the timeline (e.g. querying to determine the scroll range). From the implementation side, it should not matter if the timeline is passed into the animation constructor or immediately before/after play/pause. case 2: CSS theme change triggering a change from one CSS scroll timeline to another. Since the two timelines can have different values for the start and end properties, the scroll position can translate to different values of current time. The existing procedure does not accommodate this, and current time may become out of sync with the scroll position. |
I believe it is the most common case and, I assume, the desired behavior is:
In this case initial CSS is:
Attaching the animation to scroll timeline:
For both declarations of .scrolling-animation class we want to achieve identical behavior.
Note, to achieve the above we need to change how unpause currently works for scroll animations to always keep it in sync with the scroller. Keeping current time on unpause can be controlled by setting current/start time on running animation via Javascript. To summarize, Option 4, additional to described her, is:
|
Your option 4 is essentially a subset of what I was proposing with option 3 a few comments ago:
The extra step in option 3 is to preserve current time if transitioning from a scroll timeline to a document timeline. Otherwise resetting the animation-timeline could have unexpected results. If we are converging on consensus for this approach I can quickly update the pull request and Blink CL. |
Options 3 and 4 break the following tests: scroll-animations/play-animation.html
scroll-animations/reverse-animation.html
scroll-animations/updating-the-finished-state.html
Each of the tests allow for the scroll position to get out of sync with current time for a scroll animation. |
Option 0: No special handling for scroll timelines (i.e. abandon this pull request). With this change setting the timeline on a play-pending animation gives different results than setting the animation prior to playing the animation. Will see what this breaks for animation-timeline. We can likely resolve some of the issues with pending animation by ensuring correct ordering of calls when the CSS animation in created. |
(I'll add my thoughts to this, not sure if they'll help): At a higher level, when considering how @scroll-timeline should work when timelines are switched around, we should keep the following guideline from css-animations-1 in mind:
This makes a lot of sense given how CSS works in general. We should probably try to not deviate from this without a good reason. (Some things deviate already, e.g. animation-play-state). This means that the behavior we should aim for "by default" is:
Pausing makes it more complicated. @ogerchikov seems to say that changing the current time of a paused animation is weird, and that we shouldn't do that, but instead change how the unpause procedure works. From the author's perspective, this means the timeline switch would not "take effect" until the animation is unpaused. I think that's fine ... paused animations are paused regardless of timeline. Makes sense to me. @kevers-google asked if I could test "Option 0" with some practical examples and report what doesn't work. I think the main problem is the start time is preserved when switching timelines, which doesn't work at all for ScrollTimelines:
Here's a similar issue, (that probably has the same root cause):
|
Updated the Blink CL: https://chromium-review.googlesource.com/c/chromium/src/+/2324101 with the following rules:
This implementation is very close to option 4 outlined above and should address the concerns with animation jumps during pause. No change in existing WPTs. I could be convinced either way on preserving current time when transitioning from a scroll timeline to a document timeline; however, I believe having this rule would better align with user expectations. @ogerchikov please take a look at the CL (particularly setting-timeline.tentative.html) and let me know what you think. |
(Just a drive-by comment that the reasoning and options you've generated sound great. Thank you so much @kevers-google @andruud and @ogerchikov!) |
Looks good assuming reset current time on resume flag is reset at the right places, as per the CL. |
The revised plan is to pull this into web-animations-2 rather than web-animations-1 as there are no backwards compatibility concerns. Will put up a separate pull request shortly with a link back to this one to capture the discussion, and with a few more tweaks to address Olga's comments regarding where we need to reset the resume flag. |
Moved the change to web-animations-2. Sorry for the delay. Now includes changes for resetting the "reset current time on resume" flag as required. Previous points regarding changes required for the play procedure were marked as issues to avoid them getting lost with the change or obscuring readability of the procedure. Once this lands, we should be in a good state for integrating changes for hold phase. |
Looks good. Thanks for updating the spec! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good to me, though we may want to use a better word than finite for non-monotonic timelines.
abort this procedure. | ||
1. Let |previous play state| be |animation|'s [=play state=]. | ||
1. Let |previous current time| be the |animation|'s [=current time=]. | ||
1. Let |from finite timeline| be true if |old timeline| is not null and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
finite implies that we have a maximum value and range, but the key disinction seems to be that it's not monotonic. Maybe we should say non-monotonic or unordered or flip the flag and call it from monotonic timeline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistent with naming convention in play and pause. If we change "from/to finite timeline" here, should we not also change the "finite timeline" flag in play and pause? Not opposed to the name change, but wondering if we should handle that separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this is preexisting terminology. I propose we merge as is and change this separately.
#5422
Adds the following steps: