Re: [csswg-drafts] [web-animations-2] Add `Animation.started` and `Animation.playing` promises (#5871)

_Thanks for taking the time to explain all that!_

_I'll create a separate proposal for `AnimationEffectEvent` next week and use this page to further discuss the potential merits of an `Animation.playing` promise._

> The Animation.ready promise fits into the "One-and-done operations" category, i.e. asynchronous operations. 

Hmm. I interpreted this category as explicitly referring to methods that "return a promise", not properties, but perhaps that's a distinction without a difference.

Anyway, I think I found a better way to articulate what I want.

### Better Explanation of `Animation.played` Promise

I want to be informed when any of these three conditions happens (and I'm hoping all three are exactly equivalent but perhaps I'm misunderstanding something):

- **I want to be informed when an animation goes from playState `idle` to either playState `running` or `paused`**
- **I want to be informed when an animation's currentTime becomes not null**
- **I want to be informed when an animation has an active timeline**

In other words, I see three state categories:

- **`idle`**
- **`playing(Bool isRunning)`** (encompasses both `running` and `paused` playStates)
- **`finished`**

```
 `played`  promise resolved
   | |
    V 

           |  ---- playing -----  |  
[idle]     | [running] / [paused] | [finished]
    | -------------------  |
    |    [effect]          |
    |      [effect]        |
    |             [effect] |
```


The `playing` state category represents when the animation has an active timeline (not sure if this is 100% accurate).

I want to know when the animation has entered this `playing` state category. This would be a one-time event (i.e. would **not** happen with every `play()` or `pause()`.

By the way, I'm not sure `played` is even the best name for this, as it implies it's directly related to the play() method. Perhaps you can suggest a better name?

The only advantage of a promise over an event is so authors can still be informed if animation is auto-played. 
In other words, if there was a `play` event instead of a promise, you could never be notified when using `element.animate()`.

Consider these three examples where the console should log "played" each time.

```javascript
let animation = new Animation(...);
animation.played.then( console.log("played") );
animation.play();
```
```javascript
let animation = new Animation(...)
animation.play();
animation.played.then( console.log("played") )
```
```javascript
let animation = element.animate()
animation.played.then( console.log("played") )
```

Obviously the third example is practically pointless, but I'm imagining a situation where animations are dynamically created, sometimes being played immediately and sometimes not, and we want a consistent way to be notified.


Next consider this example of a trivial "conditional sequence". In other words, when one animation finishes it may or may not trigger another animation. Imagine that I have a timeline UI shown on the page and whenever an animation enters the `playing` state category, I want to append a `DIV` to the timeline UI element to represent that animation. 

There's certainly work-arounds (e.g. lifting `animation1.play()` to a separate function that can handle the extra DOM work as well as trigger the animation) but these work-arounds quickly become cumbersome as the code grows in complexity.

```javascript
let box = document.querySelector("#box");

let animation1 = new Animation(new KeyframeEffect(box, 
   [{ opacity: 1 }, { opacity: 0 }], 
   { duration: 300, delay: 1000 }
))
animation1.played.then(_ => {
   console.log("animation1 played")
   // todo: add some kind of visual element to the timelineUI
});
animation1.finished.then(_ => {
   console.log("animation1 finished") 
});


let animation2 = new Animation(new KeyframeEffect(box, 
   [{ transform: "translateX(0)" }, { transform: "translateX(100px)" }], 
   { duration: 600, delay: 100 }
))
animation2.played.then(_ => {
   console.log("animation2 played")
   // todo: add some kind of visual element to the timelineUI
});
animation2.finished.then(_ => {
   console.log("animation2 finished") 
});


let animation3 = new Animation(new KeyframeEffect(box, 
   [{ transform: "rotate(0)" }, { transform: "rotate(90deg)" }], 
   { duration: 800, delay: 400 }
))
animation3.played.then(_ => {
   console.log("animation3 played");
   // todo: add some kind of visual element to the timelineUI
});
animation3.finished.then(_ => {
   console.log("animation3 finished")

   if(Math.random() > 0.5) {
      animation1.play();
   } else {
      animation2.play();
   } 
});

// kick-off the first animation
animation3.play();
```

For a more concrete example, I'm currently creating a dynamic slideshow using animations. I'm creating all of my animations ahead of time and effectively doing a bunch of SequenceAnimations and GroupAnimatons but sometimes more complex (i.e. with conditions / different pathways for the sequence part). The spacebar and arrow keys trigger certain animation groups/sequences, and the exact sequence is not predetermined ahead of time.

 It would greatly simplify my life to have custom code run whenever an animation is first played, so I can adjust the DOM as needed (or even just logging for debug purposes). Sometimes the actual effects have a significant delay so I don't want to synchronize with the effect - I'm strictly interested in when play() is actually called).

From a theoretical standpoint, clearly you can create `Animation` instances that aren't auto-played. I don't think it's too much of a stretch to imagine they occasionally might not be played immediately. I therefore think it's reasonable to offer some sort of mechanism signal the transition from `idle` to `running` / `paused`


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


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Friday, 15 January 2021 20:50:00 UTC