Re: [csswg-drafts] [web-animations-1] Make animations become idle when they have an inactive timeline (#2066)

Per @birtles suggestion [this](https://docs.google.com/document/d/108BW6PmXP_JUCKmfyNpWK4EEs5s5XpTcL3mPiQ6bEPI/edit?usp=sharing) document has 2 state charts:
1. Animation states along with play/pause/newly inactive timeline/newly active timeline transitions.
1. Animation states along with set start time/set current time transitions.

Two new states are introduced to support initial playing/pausing animations when the timeline is inactive (see the first chart). This proposal assumes the following spec changes:
1. https://drafts.csswg.org/web-animations/#responding-to-a-newly-inactive-timeline - drop this section.
1. https://drafts.csswg.org/web-animations-1/#playing-an-animation-section - add this condition to bullet 3:
    - If start time is unresolved and current time is unresolved and the timeline is inactive set start time to zero.
1. https://drafts.csswg.org/web-animations-1/#pausing-an-animation-section - add this condition to bullet 3:
    - If start time is unresolved and current time is unresolved and the timeline is inactive set start time to zero.
1. https://drafts.csswg.org/web-animations-1/#pausing-an-animation-section - add this condition to bullet 7:
    - Allow execution of pending pause task when the timeline is not inactive (similarly to pending play task).

Second state chart shows 2 undesired behaviors:
1. Setting start time of a paused animation makes the animation transition to running state. This is existing behavior, not related to inactive timelines.
1. Setting current time of running animation when the timeline is inactive makes the animation transition to paused state:

    ```
    animation = new Animation(new KeyframeEffect(...}],
                                                 { duration: 2000}), document.timeline);
    animation.play();
    await animation.ready;
    animation.timeline = null;
    animation.currentTime = 500;
    console.log(animation.playState);  // paused
    animation.timeline = document.timeline;
    console.log(animation.playState);  // paused; desired running
    ```
   - _**Potential solution**: queue pending play task that will be executed when the timeline becomes active. Similar solution can be applied to setting start time with pending pause task._

### Use cases corrected according to the current proposal:
1. An animation that is idle until its timeline starts to play
    ```
    scroller.style.overflow="none";
    scroll_timeline = new ScrollTimeline({scrollSource: scroller, ...});
    animation = new Animation(new KeyframeEffect(...}], { duration: 2000}), scroll_timeline);
    animation.play();
    // This state reflects new proposed state, see Fig1.
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // null
    console.log(animation.playState); // running (pending play task)
    // make the timeline active
    scroller.style.overflow="scroll";
    scroller.scrollTop = '50px';
    await animation.ready;
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // some number
    console.log(animation.playState); // running
    ```
1. An animation that is filling backwards until its timeline starts to play.
    - Same as bullet 1.
1. Likewise for the above at the other end of the timeline.
    - Is it playback rate < 0? If so exactly as bullet 1.
1. Set the initial playback position of an animation so that when its timeline starts to play, it picks up from that point.
    ```
    scroller.style.overflow="none";
    scroll_timeline = new ScrollTimeline({scrollSource: scroller, ...});
    animation = new Animation(new KeyframeEffect(...}], { duration: 2000}), scroll_timeline);
    animation.currentTime = 100;
    animation.play();
    console.log(animation.startTime); // null
    console.log(animation.currentTime); // 100 
    console.log(animation.playState); // running (pending play task)
    // make the timeline active
    scroller.style.overflow="scroll";
    await animation.ready;
    console.log(animation.startTime); // some number
    console.log(animation.currentTime); // 100 
    console.log(animation.playState); // running
    ```
1. Hot-swapping timelines (switch from scroll-based to time-based).
    ```
    scroller.style.overflow="scroll";
    scroll_timeline = new ScrollTimeline({scrollSource: scroller, ...});
    animation = new Animation(new KeyframeEffect(...}], { duration: 2000}), scroll_timeline);
    animation.play();
    scroller.scrollTop = '50px';
    await animation.ready;
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // some number 
    console.log(animation.playState); // running 

    animation.timeline = document.timeline;
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // some number based on the new timeline.currentTime
    console.log(animation.playState); // running or finished
    ```
1. Timeline becomes newly inactive while the animation is playing.
    ```
    scroller.style.overflow="scroll";
    scroll_timeline = new ScrollTimeline({scrollSource: scroller, ...});
    animation = new Animation(new KeyframeEffect(...}], { duration: 2000}), scroll_timeline);
    animation.play();
    scroller.scrollTop = '50px';
    await animation.ready;
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // some number 
    console.log(animation.playState); // running 
    // Make the timeline inactive
    scroller.style.overflow="none";
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // null
    console.log(animation.playState); // idle
    ```
1. Seek an animation that is not attached to an active timeline and get meaningful values out of it.
    ```
    scroller.style.overflow="scroll";
    scroll_timeline = new ScrollTimeline({scrollSource: scroller, ...});
    animation = new Animation(new KeyframeEffect(...}], { duration: 2000}), scroll_timeline);
    animation.play();
    scroller.scrollTop = '50px';
    await animation.ready;
    scroller.style.overflow="none";
    console.log(animation.startTime); // 0
    console.log(animation.currentTime); // null
    console.log(animation.playState); // idle 
    animation.currentTime = 1000;
    console.log(animation.startTime); // null
    console.log(animation.currentTime); // 1000
    console.log(animation.playState); // paused; this is undesired, see proposed solution.
    ```
1. Cont. bullet 7 - the timeline becomes active.
    ```
    scroller.style.overflow="scroll";
    console.log(animation.startTime); // null
    console.log(animation.currentTime); // 1000
    console.log(animation.playState); // paused; this is undesired, see proposed solution.
    ```






-- 
GitHub Notification of comment by ogerchikov
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/2066#issuecomment-579901039 using your GitHub account

Received on Wednesday, 29 January 2020 18:43:27 UTC