This repository was archived by the owner on Jun 7, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathOverview.bs
7725 lines (6143 loc) · 313 KB
/
Overview.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!-- @if LEVEL=1 -->
<h1>Web Animations</h1>
<!-- @endif -->
<!-- @if LEVEL=2 -->
<h1>Web Animations Level 2</h1>
<!-- @endif -->
<pre class='metadata'>
<!-- @if LEVEL=1 -->
Status: ED
<!-- @endif -->
<!-- @if LEVEL=2 -->
Status: UD
Warning: not ready
<!-- @endif -->
Shortname: web-animations
TR: https://www.w3.org/TR/web-animations-1/
<!-- @if LEVEL=1 -->
ED: https://w3c.github.io/web-animations/
Previous version: https://www.w3.org/TR/2016/WD-web-animations-1-20160913/
Previous version: https://www.w3.org/TR/2015/WD-web-animations-1-20150707/
Previous version: https://www.w3.org/TR/2014/WD-web-animations-20140605/
Previous version: https://www.w3.org/TR/2013/WD-web-animations-20130625/
<!-- @endif -->
<!-- @if LEVEL=2 -->
ED: https://w3c.github.io/web-animations/level-2/
<!-- @endif -->
Version history: https://github.com/w3c/web-animations/commits/master
Level: <!-- @echo LEVEL -->
Group: fxtf
!Participate: <a href="https://github.com/w3c/web-animations">Fix the text through GitHub</a>
!Participate: Join the ‘waapi’ channel on the <a href="https://damp-lake-50659.herokuapp.com/">Animation at Work</a> slack
!Participate: IRC: <a href="ircs://irc.w3.org:6667/webanimations">#webanimations</a> on W3C's IRC
Repository: w3c/web-animations
!Issue Tracking: <a href="https://github.com/w3c/web-animations/issues">GitHub</a>
!Tests: <a href="https://github.com/w3c/web-platform-tests/tree/master/web-animations">web-platform-tests web-animations/</a> (<a href="https://github.com/w3c/web-platform-tests/labels/web-animations">ongoing work</a>)
Editor: Brian Birtles 43194, Mozilla, [email protected]
Editor: Shane Stephens 47691, Google Inc, [email protected]
Editor: Douglas Stockwell, Google Inc, [email protected]
Former Editor: Alex Danilo 31960, Google Inc, [email protected]
Former Editor: Tab Atkins 42199, Google Inc, [email protected]
Abstract: This specification defines a model for synchronization and
timing of changes to the presentation of a Web page.
This specification also defines an application programming interface
for interacting with this model and it is expected that further
specifications will define declarative means for exposing these
features.
Ignored Terms: double, boolean, DOMString, unsigned long, unrestricted double, (animationeffectreadonly or effectcallback), (unrestricted double or DOMString)
Ignored Vars: RGB|A, G, t
Link Defaults: css-transforms (property) transform
</pre>
<pre class="anchors">
urlPrefix: https://heycam.github.io/webidl/#dfn-; type: dfn; spec: webidl
text: platform object
text: nullable; url: nullable-type
text: throw
text: thrown; url: throw
text: convert ecmascript to idl value
urlPrefix: https://heycam.github.io/webidl/; type: dfn; spec: webidl
text: [EnforceRange]; url: EnforceRange
text: es to dictionary
text: es to DOMString; url: es-to-DOMString
text: DOMString to es; url: DOMString-to-es
urlPrefix: http://www.ecma-international.org/ecma-262/6.0/#sec-; type: dfn; spec: ecma-262
text: code realms
text: completion record specification type
text: execution contexts
text: EnumerableOwnNames
text: GetIterator
text: GetMethod
text: IteratorStep
text: IteratorValue
text: Promise object; url: promise-objects
text: Promise; url: promise-objects
text: PromiseCapability record; url: promisecapability-records
text: Promise.resolve; url: promise.resolve
text: well known symbols
text: [[DefineOwnProperty]]; url: ordinary-object-internal-methods-and-internal-slots-defineownproperty-p-desc
text: [[Get]]; url: ordinary-object-internal-methods-and-internal-slots-get-p-receiver
urlPrefix: https://html.spec.whatwg.org/multipage/browsers.html; type: dfn; spec: html
text: active document
text: document associated with a window; url: concept-document-window
text: an entry with persisted user state
text: session history entry
urlPrefix: https://html.spec.whatwg.org/multipage/webappapis.html; type: dfn; spec: html
text: current global object
text: document.open(); url: dom-document-open
text: DOM manipulation task source
text: event loop processing model
text: queue a task
text: queue a microtask
text: relevant Realm; url: concept-relevant-realm
text: update the rendering
urlPrefix: https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html.html; type: dfn; spec: html
text: animation frame callbacks; url: animation-frames
text: run the animation frame callbacks
urlPrefix: https://html.spec.whatwg.org/multipage/embedded-content.html; type: dfn; spec: html
text: media element
urlPrefix: https://w3c.github.io/hr-time/; spec: highres-time
text: time origin; type: dfn
text: DOMHighResTimeStamp; type: interface
urlPrefix: https://dom.spec.whatwg.org/; type: dfn; spec: dom
text: create an event; url: concept-event-create
text: dispatch; url: concept-event-dispatch
text: constructing events
text: node document; url: concept-node-document
url: https://html.spec.whatwg.org/#document; type: interface; text: Document; spec: html
url: https://svgwg.org/svg2-draft/pservers.html#StopElementOffsetAttribute; type: element-attr; for: stop; text: offset; spec: svg2
url: https://svgwg.org/svg2-draft/mimereg.html#mime-registration; type: dfn; text: SVG MIME type; spec: svg2
urlPrefix: https://drafts.csswg.org/cssom/; type: dfn; spec: cssom
text: CSS property to IDL attribute
text: IDL attribute to CSS property
text: serialize a CSS value
urlPrefix: https://drafts.csswg.org/css-transitions/; type: dfn; spec: css-transitions-1
text: events from CSS transitions; url: transition-events
urlPrefix: https://drafts.csswg.org/css-animations/; type: dfn; spec: css-animations-1
text: events from CSS animations; url: events
</pre>
<pre class="link-defaults">
spec:dom; type:interface; text:EventTarget
spec:dom; type:interface; text:Event
spec:css-values-3; type:type; text:<ident>
spec:css-backgrounds-3; type:property;
text:border-width
text:border-bottom-width
text:border-left-width
text:border-right-width
text:border-top-width
text:border-top-color
text:border-top
text:border-color
</pre>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({showMathMenu: false});
</script>
<script src="MathJax/MathJax.js?config=MML_SVG" type="text/javascript"></script>
<h2 id="introduction">Introduction</h2>
<div class='informative-bg'><em>This section is non-normative</em>
Web Animations defines a model for supporting animation and
synchronization on the Web platform.
It is intended that other specifications will build on this model and
expose its features through declarative means.
In addition, this specification also defines a programming interface to
the model that may be implemented by user agents that provide support
for scripting.
<h3 id="use-cases">Use cases</h3>
The Web Animations model is intended to provide the features necessary
for expressing CSS Transitions [[CSS-TRANSITIONS-1]],
CSS Animations [[CSS-ANIMATIONS-1]], and
SVG [[SVG11]].
As such, the use cases of Web Animations model is the union of use cases for
those three specifications.
The use cases for the programming interface include the following:
: Inspecting running animations
:: Often Web applications must wait for certain animated effects to complete
before updating some state.
The programming interface in this specification allows such applications
to wait for all currently running animation to complete,
regardless of whether they are defined by CSS Transitions, CSS Animations,
SVG animations, or created directly using the programming interface.
<div class='example'>
<pre class='lang-javascript'>
// Wait until all animations have finished before removing the element
Promise.all(
elem.getAnimations().map(animation => animation.finished)
).then(() => elem.remove());
</pre>
</div>
Alternatively, applications may wish to query the playback state of
animations without waiting.
<div class='example'>
<pre class='lang-javascript'>
const isAnimating = elem.getAnimations().some(
animation => animation.playState === 'running'
);
</pre>
</div>
: Controlling running animations
:: It is sometimes useful to perform playback control on animations
so that they can respond to external inputs.
For example, it may be necessary to pause all existing animations before
displaying a modal dialog so that they do not distract the user's
attention.
<div class='example'>
<pre class='lang-javascript'>
// Pause all existing animations in the document
document.getAnimations().forEach(
animation => animation.pause()
);
</pre>
</div>
: Creating animations from script
:: While it is possible to use ECMAScript to perform animation using
<code>requestAnimationFrame</code> [[!HTML]],
such animations behave differently to declarative animation in terms of
how they are represented in the CSS cascade and the performance
optimizations that are possible such as performing the animation on a
separate thread.
Using the Web Animations programming interface, it is possible to
create animations from script that have the same behavior and performance
characteristics as declarative animations.
<div class='example'>
<pre class='lang-javascript'>
// Fade out quickly
elem.animate({ transform: 'scale(0)', opacity: 0 }, 300);
</pre>
</div>
: Animation debugging
:: In a complex application, it may be difficult to determine how an
element arrived in its present state.
The Web Animations programming interface may be used to inspect
running animations to answer questions such as,
“Why is the opacity of this element changing?”
<div class='example'>
<pre class='lang-javascript'>
// Print the id of any opacity animations on elem
elem.getAnimations().filter(
animation =>
animation.effect instanceof KeyframeEffectReadOnly &&
animation.effect.getKeyframes().some(
frame => frame.hasOwnProperty('opacity')
)
).forEach(animation => console.log(animation.id));
</pre>
</div>
Likewise, in order to fine tune animations, it is often necessary to
reduce their playback rate and replay them.
<div class='example'>
<pre class='lang-javascript'>
// Slow down and replay any transform animations
elem.getAnimations().filter(
animation =>
animation.effect instanceof KeyframeEffectReadOnly &&
animation.effect.getKeyframes().some(
frame => frame.hasOwnProperty('transform')
)
).forEach(animation => {
animation.currentTime = 0;
animation.playbackRate = 0.5;
});
</pre>
</div>
: Testing animations
:: In order to test applications that make use of animations it is often
impractical to wait for such animations to run to completion.
Rather, it is desirable to seek the animations to specific times.
<div class='example'><pre class='lang-javascript'>
// Seek to the half-way point of an animation and check that the opacity is 50%
elem.getAnimations().forEach(
animation =>
animation.currentTime =
animation.effect.getComputedTiming().delay +
animation.effect.getComputedTiming().activeDuration / 2;
);
assert.strictEqual(getComputedStyle(elem).opacity, '0.5');
// Check that the loading screen is hidden after the animations finish
elem.getAnimations().forEach(
animation => animation.finish()
);
// Wait one frame so that event handlers have a chance to run
requestAnimationFrame(() => {
assert.strictEqual(
getComputedStyle(document.querySelector('#loading')).display, 'none');
});
</pre></div>
<!-- @if LEVEL=2 -->
<h3 id="changes-since-level-1">Changes since level 1</h3>
This specification introduces the following changes compared to the
previous level of this specification:
* <a>group effects</a> and <a>sequence effects</a>,
* an <a>animation effect</a>-specific
<a lt="animation effect playback rate">playback rate</a>,
* <a>custom effects</a>.
<!-- @endif -->
<h3 id="relationship-to-other-specifications">Relationship to other specifications</h3>
CSS Transitions [[CSS-TRANSITIONS-1]], CSS Animations [[CSS-ANIMATIONS-1]], and
SVG [[SVG11]] all provide mechanisms that
generate animated content on a Web page.
Although the three specifications provide many similar features,
they are described in different terms.
This specification proposes an abstract animation model that
encompasses the common features of all three specifications.
This model is backwards-compatible with the current behavior of these
specifications such that they can be defined in terms of this model
without any observable change.
The animation features in SVG 1.1 are defined in terms of SMIL
Animation [[SMIL-ANIMATION]].
It is intended that by defining SVG's animation features in terms of
the Web Animations model, the dependency between SVG and SMIL
Animation can be removed.
As with <a>animation frame callbacks</a> (commonly referred
to as “requestAnimationFrame”) [[HTML]],
the programming interface component of this specification allows
animations to be created from script.
The animations created using the interface defined in this
specification, however, once created, are executed entirely by the
user agent meaning they share the same performance characteristics as
animations defined by markup.
Using this interface it is possible to create animations
from script in a simpler and more performant manner.
The time values used within the programming interface
correspond with those used in <a>animation frame callbacks</a> [[HTML]]
and their execution order is defined such that the two interfaces can be used
simultaneously without conflict.
The programming interface component of this specification makes
some additions to interfaces defined in HTML [[!HTML]].
<h3 id="overview-of-this-specification">Overview of this specification</h3>
This specification begins by defining an abstract model for animation.
This is followed by a programming interface defined in terms of the
abstract model.
The programming interface is defined in terms of the abstract model
and is only relevant to user agents that provide scripting support.
</div>
<h2 id="web-animations-model-overview">Web Animations model overview</h2>
<div class='informative-bg'><em>This section is non-normative</em>
At a glance, the Web Animations model consists of two largely
independent pieces, a <em>timing model</em> and an <em>animation
model</em>. The role of these pieces is as follows:
: Timing model
:: Takes a moment in time and converts it to a proportional distance
within a single iteration of an animation called the <em>iteration
progress</em>.
The <em>iteration index</em> is also recorded since some animations vary
each time they repeat.
: Animation model
:: Takes the <em>iteration progress</em> values and <em>iteration indices</em>
produced by the timing model and converts them into a series of values
to apply to the target properties.
Graphically, this flow can be represented as follows:
<figure>
<img src="img/timing-and-animation-models.svg" width="600"
alt="Overview of the operation of the Web Animations model.">
<figcaption>
Overview of the operation of the Web Animations model.<br>
The current time is input to the timing model which produces an iteration
progress value and an iteration index.<br>
These parameters are used as input to the animation model which produces
the values to apply.
</figcaption>
</figure>
For example, consider an animation that:
* starts after 3 seconds
* runs twice,
* takes 2 seconds every time, and
* changes the width of a rectangle from 50 pixels to 100 pixels.
The first three points apply to the timing model.
At a time of 6 seconds, it will calculate that the animation should be
half-way through its second iteration and produces the result 0.5.
The animation model then uses that information to calculate a width.
This specification begins with the timing model and then proceeds to
the animation model.
</div>
<h2 id="timing-model">Timing model</h2>
This section describes and defines the behavior of the Web Animations
timing model.
<h3 id="timing-model-overview">Timing model overview</h3>
<div class='informative-bg'>
<em>This section is non-normative</em>
Two features characterize the Web Animations timing model: it is
<em>stateless</em> and it is <em>hierarchical</em>.
<h4 id="stateless">Stateless</h4>
The Web Animations timing model operates by taking an input time and
producing an output iteration progress.
Since the output is based solely on the input time and is independent
of previous inputs, the model may be described as stateless.
This gives the model the following properties:
: Frame-rate independent
:: Since the output is independent of previous inputs, the rate at
which the model is updated will not affect its progress.
Provided the input times are proportional to the progress of
real-world time, animations will progress at an identical rate
regardless of the capabilities of the device running them.
: Direction-agnostic
:: Since the sequence of inputs is insignificant, the model is
directionless.
This means that the model can be updated to an arbitrary moment
without requiring any specialized handling.
: Constant-time seeking
:: Since each input is independent of the previous input, the
processing required to perform a seek operation, even far into the
future, is at least potentially constant.
There are a few exceptions to the stateless behavior of the timing
model.
Firstly, a number of methods defined in the <a
href="#programming-interface" section>programming interface</a> to the model
provide play control such as pausing an animation.
These methods are defined in terms of the time at which they are
called and are therefore stative.
These methods are provided primarily for convenience and are not part
of the core timing model but are layered on top.
Similarly, the <a href="#reaching-the-end" section>finishing behavior</a> of
animations means that dynamic changes to the end time of
the media (target effect) of an animation may produce a
different result depending on when the change occurs.
This behavior is somewhat unfortunate but has been deemed intuitive
and consistent with HTML.
As a result, the model can only truly be described as stateless
<em>in the absence of dynamic changes to its timing properties</em>.
Finally, each time the model is updated, it can be considered to
establish a temporary state.
While this temporary state affects the values returned from the <a
href="#programming-interface" section>programming interface</a>, it has no
influence on the subsequent updates and hence does not conflict with
the stateless qualities described above.
<h4 id="hierarchical">Hierarchical</h4>
The other characteristic feature of the timing model is that time is inherited.
Time begins at a timeline and cascades down a number of steps to each
animation effect.
At each step, time may be shifted backwards and forwards, scaled,
reversed, paused, and repeated.
<figure>
<!-- @ifndef INCLUDE_GROUPS -->
<img src="img/time-hierarchy-no-groups.svg" width="350"
alt="A hierarchy of timing nodes">
<!-- @endif -->
<!-- @ifdef INCLUDE_GROUPS -->
<img src="img/time-hierarchy.svg" width="600"
alt="A hierarchy of timing nodes">
<!-- @endif -->
<figcaption>
A hierarchy of timing nodes.
Each node in the tree derives its time from its parent node.
</figcaption>
</figure>
<!-- @ifndef INCLUDE_GROUPS -->
In this level of the specification the hierarchy is shallow.
A subsequent level of this specification will introduce the concept
of group effects which allows for deeper timing hierarchies.
<!-- @endif -->
<!-- @ifdef INCLUDE_GROUPS -->
A consequence of this hierarchical arrangement is that complex
animation arrangements can be reversed, scheduled, accelerated and so
on as a whole unit since the manipulations applied to the parent,
cascade down to its <a>descendants</a>.
Furthermore, since time has a common source, it is easy to synchronize
animations.
<!-- @endif -->
</div>
<h3 id="time-value-section">Time values</h3>
Timing is based on a hierarchy of time relationships between timing nodes.
Parent nodes provide timing information to their child nodes in the form
of <a>time values</a>.
A <dfn>time value</dfn> is a real number which nominally represents
a number of milliseconds from some moment.
The connection between <a>time values</a> and wall-clock milliseconds
may be obscured by any number of transformations applied to the value as
it passes through the time hierarchy.
<p class="annotation">
In the future there may be timelines that are based on scroll position
or UI gestures in which case the connection between time values and
milliseconds will be weakened even further.
</p>
A <a>time value</a> may also be <dfn>unresolved</dfn> if, for example,
a timing node is not in a state to produce a <a>time value</a>.
<h3 id="timelines">Timelines</h3>
A <dfn>timeline</dfn> provides a source of <a>time values</a> for the
purpose of synchronization.
At any given moment, a [=timeline=] has a single current [=time value=] known
simply as the timeline's <dfn lt="timeline current time">current time</dfn>.
A <a>timeline</a> may not always be able to return a meaningful <a>time
value</a>, but only an <a>unresolved</a> time value. For example, it may
be defined relative to a moment that has yet to occur, such as the firing of
a document's load event.
A <a>timeline</a> is considered to be <dfn lt="inactive timeline">inactive</dfn>
when its <a>time value</a> is <a>unresolved</a>.
Specific types of [=timelines=] may define a procedure to <dfn lt="timeline time
to origin-relative time" export>convert a timeline time to an
origin-relative time</dfn> for [=time value=] |time|, so that the [=time
values=] produced by wallclock-based timelines can be compared.
A <a>timeline</a> may be <dfn lt="timeline associated with
a document">associated with a document</dfn>.
When asked to <dfn export>update animations and send events</dfn> for
a {{Document}} |doc| at timestamp |now|, run these steps:
1. Update the <a lt="timeline current time">current time</a> of all
timelines <a lt="timeline associated with a document">associated with
|doc|</a> passing |now| as the timestamp.
<div class="note">
Due to the hierarchical nature of the timing model, updating the
<a lt="timeline current time">current time</a> of a [=timeline=] also
involves:
* Updating the [=current time=] of any [=animations=] associated with
the timeline.
* Running the [=update an animation's finished state=] procedure for any
animations whose [=current time=] has been updated.
* Queueing [=animation events=] for any such animations.
</div>
1. [=Perform a microtask checkpoint=].
Note: This is to ensure that any microtasks queued up as a result of
resolving or rejecting Promise objects as part of updating timelines in the
previous step, run their callbacks prior to dispatching animation events.
1. Let |events to dispatch| be a copy of |doc|'s [=pending animation event
queue=].
1. Clear |doc|'s [=pending animation event queue=].
1. Perform a stable sort of the [=animation events=] in |events to dispatch|
as follows:
1. Sort the events by their [=scheduled event time=] such that events
that were scheduled to occur earlier, sort before events scheduled to
occur later and events whose scheduled event time is
[=unresolved=] sort before events with a <a lt=unresolved>resolved</a>
scheduled event time.
1. Within events with equal [=scheduled event times=], sort by their
[=composite order=].
Note: The purpose of sorting events is to ensure that, as best possible,
even on devices with differing capabilities and hence different frame
rates, events are dispatched in a consistent order.
Note: The requirement for the sort to be a stable sort is because sometimes
events may be queued with the same scheduled event time. For example, a CSS
animation with a duration of zero, may dispatch both
an <code>animationstart</code> and an <code>animationend</code> event and
the order of these events should be preserved.
1. [=Dispatch=] each of the events in |events to dispatch| at their
corresponding target using the order established in the previous step.
It is often convenient to describe each time this procedure is invoked as
establishing a new <dfn export>animation frame</dfn>.
Changes to the timing properties of [=animations=] or [=animation effects=], or
the addition and removal of the objects may cause the output of the timing or
animation model to change, but these operations in themselves do not create
a new [=animation frame=], rather they merely update the current <a>animation
frame</a>.
<h4 id="document-timelines">Document timelines</h4>
A <dfn>document timeline</dfn> is a type of <a>timeline</a> that is <a
lt="timeline associated with a document">associated
with a document</a> and whose <a lt="timeline current time">current time</a>
is calculated as a fixed offset from the |now| timestamp provided each time the
[=update animations and send events=] procedure is run.
This fixed offset is referred to as the document timeline's <dfn>origin
time</dfn>.
Issue: There must be a better term than “origin time”—
it's too similar to “time origin”.
Prior to establishing the [=time origin=] for its associated document,
a [=document timeline=] is <a lt="inactive timeline">inactive</a>.
A <a>document timeline</a> that is associated with a {{Document}} which is not
an <a>active document</a> is also considered to be
<a lt="inactive timeline">inactive</a>.
To <a lt="timeline time to origin-relative time">convert a timeline
time, |timeline time|, to an origin-relative time</a> for a document timeline,
|timeline|, return the sum of the |timeline time| and |timeline|'s [=origin
time=]. If |timeline| is inactive, return an [=unresolved=] [=time value=].
<h4 id="the-documents-default-timeline">The default document timeline</h4>
Each {{Document}} has a <a>document timeline</a> called the <dfn>default
document timeline</dfn>.
The <a>default document timeline</a> is unique to each document and persists for
the lifetime of the document including calls to <a>document.open()</a> [[!HTML]].
The <a>default document timeline</a> has an <a>origin time</a> of zero.
<div class="informative-bg"><em>This section is non-normative</em>
Since no scaling is applied to the |now| timestamp values provided
to [=document timelines=], the <a>time values</a> it produces will be
proportional to wall-clock milliseconds.
Furthermore, since the <a>time values</a> of the <a>default document
timeline</a> have a zero offset from the [=time origin=],
<code>document.timeline.currentTime</code> will roughly correspond to <a
href="https://www.w3.org/TR/hr-time/#dom-performance-now">
<code>Performance.now()</code></a> [[HR-TIME]] with the exception that
<code>document.timeline.currentTime</code> does not change in between calls
to the [=update animations and send events=] procedure.
</div>
<h3 id="animations">Animations</h3>
<div class="informative-bg"><em>This section is non-normative</em>
The children of a <a>timeline</a> are called <em>animations</em>.
An animation takes an <a>animation effect</a> which is a static
description of some timed behavior and binds it to a <a>timeline</a>
so that it runs.
An animation also allows run-time control of the connection between the
<a>animation effect</a> and its <a>timeline</a> by providing pausing,
seeking, and speed control.
The relationship between an animation and an <a>animation effect</a> is
analogous to that of a DVD player and a DVD.
</div>
An <dfn id="concept-animation">animation</dfn> connects a single <a>animation
effect</a>, called its <dfn>target effect</dfn>, to a <a>timeline</a> and
provides playback control.
Both of these associations are optional and configurable such that
an <a>animation</a> may have no associated <a>target effect</a> or
<a>timeline</a> at a given moment.
An [=animation's=] <dfn>document for timing</dfn> is the {{Document}} with which
its [=timeline=] is <a lt="timeline associated with a document">associated</a>.
If an animation is not associated with a timeline, or its timeline is not
associated with a document, then it has no [=document for timing=].
An <a>animation</a>'s <dfn lt="animation start time">start time</dfn> is the
<a>time value</a> of its <a>timeline</a> when its <a>target effect</a>
is scheduled to begin playback. An animation's <a
lt="animation start time">start time</a> is initially
<a>unresolved</a>.
An <a>animation</a> also maintains a <dfn>hold time</dfn> <a>time value</a>
which is used to fix the animation's output <a>time value</a>, called its
<a>current time</a>, in circumstances such as pausing</a>.
The <a>hold time</a> is initially <a>unresolved</a>.
In order to establish the relative ordering of conflicting <a>animations</a>,
animations are appended to a <dfn>global animation list</dfn> in the order
in which they are created. Certain <a lt="animation class">classes of
animations</a>, however, may provide alternative means of ordering animations
(see [[#animation-classes]]).
<h4 id="setting-the-timeline">Setting the timeline of an animation</h4>
The procedure to <dfn>set the timeline of an animation</dfn>,
<var>animation</var>, to <var>new timeline</var> which may be null, is as
follows:
1. Let <var>old timeline</var> be the current <a>timeline</a> of
<var>animation</var>, if any.
1. If <var>new timeline</var> is the same object as <var>old timeline</var>,
abort this procedure.
1. Let the <a>timeline</a> of <var>animation</var> be <var>new timeline</var>.
1. If the <a>animation start time</a> of <var>animation</var> is <a
lt=unresolved>resolved</a>, make <var>animation</var>'s <a>hold time</a>
<a>unresolved</a>.
Note: This step ensures that the <a>finished play state</a> of
<var>animation</var> is not “sticky” but is re-evaluated
based on its updated <a>current time</a>.
<!-- @ifdef INCLUDE_CUSTOM_EFFECTS -->
1. Issue: If <var>new timeline</var> is null, we should ensure that <a>custom
effects</a> get called with an <a>unresolved</a> <a>iteration progress</a>
(unless a subsequent change in the same script execution context makes this
redundant).
<!-- @endif -->
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to false, and
the <var>synchronously notify</var> flag set to false.
<h4 id="responding-to-a-newly-inactive-timeline">Responding to a newly inactive
timeline</h4>
Issue: With the set of timelines defined in this level of this specification,
this situation is not expected to occur. As a result, this section will likely
be moved to a subsequent level of this specification.
When the <a>timeline</a> associated with an <a>animation</a>,
<var>animation</var>, becomes newly <a lt="inactive timeline">inactive</a>,
if <var>animation</var>'s <a>previous current time</a> is <a
lt="unresolved">resolved</a>, the procedure to <a>silently set the current
time</a> of <var>animation</var> to <a>previous current time</a> is run.
<div class="annotation">
This step makes the behavior when an <a>animation</a>'s <a>timeline</a> becomes
<a lt="inactive timeline">inactive</a> consistent with when it is
disassociated with a <a>timeline</a>.
Furthermore, it ensures that the only occasion on which an <a>animation</a>
becomes <a lt="idle play state">idle</a>, is when the procedure to
<a>cancel an animation</a> is performed.
</div>
<h4 id="setting-the-target-effect">Setting the target effect of an
animation</h4>
The procedure to <dfn>set the target effect of an animation</dfn>,
<var>animation</var>, to <var>new effect</var> which may be null, is as
follows:
1. Let <var>old effect</var> be the current <a>target effect</a> of
<var>animation</var>, if any.
1. If <var>new effect</var> is the same object as <var>old effect</var>,
abort this procedure.
1. If <var>new effect</var> is null and <var>old effect</var> is not null,
run the procedure to <a>reset an animation's pending tasks</a> on
<var>animation</var>.
1. If <var>animation</var> has a <a>pending pause task</a>, reschedule that
task to run as soon as <var>animation</var> is <a>ready</a>.
1. If <var>animation</var> has a <a>pending play task</a>, reschedule that task
to run as soon as <var>animation</var> is <a>ready</a> to play <var>new
effect</var>.
<!-- @ifdef INCLUDE_GROUPS -->
1. If <var>new effect</var> is not <code>null</code> and
if <var>new effect</var> has a <a>parent group</a>,
<a lt="remove an animation effect">remove</a> <var>new effect</var> from
its <a>parent group</a>.
<!-- @endif -->
1. If <var>new effect</var> is not <code>null</code> and
if <var>new effect</var> is the <a>target effect</a> of another
<a>animation</a>, <var>previous animation</var>, run the procedure to <a>set
the target effect of an animation</a> (this procedure) on <var>previous
animation</var> passing null as <var>new effect</var>.
1. Let the <a>target effect</a> of <var>animation</var> be <var>new
effect</var>.
<!-- @ifdef INCLUDE_CUSTOM_EFFECTS -->
<!-- As elsewhere, we'd like to change this comment based on whether we
support groups or not but npm preprocess doesn't support nested ifdefs so we
just assume that if we support custom effects we support groups too. -->
1. If <var>old effect</var> is not <code>null</code>, queue a task to call any
<a>custom effects</a> associated with <a>inclusive descendants</a> of
<var>old effect</var>
with an <a>unresolved</a> <a>iteration progress</a>.
<div class="issue">
This is not quite right. If <var>old effect</var> is attached to another
animation in the same task then we should probably not do an extra
callback with <a>unresolved</a>.
The definition of when <a>custom effects</a> gets called needs to be
audited and probably rewritten.
</div>
<!-- @endif -->
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to false, and
the <var>synchronously notify</var> flag set to false.
The procedure to <dfn>reset an animation's pending tasks</dfn> for
<var>animation</var> is as follows:
1. If <var>animation</var> does not have a <a>pending play task</a> or a
<a>pending pause task</a>, abort this procedure.
1. If <var>animation</var> has a <a>pending play task</a>, cancel that task.
1. If <var>animation</var> has a <a>pending pause task</a>, cancel that task.
1. <a lt="reject a Promise">Reject</a> <var>animation</var>'s <a>current ready
promise</a> with a DOMException named "AbortError".
1. Let <var>animation</var>'s <a>current ready promise</a> be the result of
<a lt="create a new resolved Promise">creating a new resolved Promise
object</a>.
<h4 id="the-current-time-of-an-animation">The current time of an animation</h4>
<a>Animations</a> provide a <a>time value</a> to their <a>target
effect</a> called the animation's <dfn>current time</dfn>.
The <a>current time</a> is calculated from the first
matching condition from below:
<div class="switch">
: If the animation's <a>hold time</a> is <a lt="unresolved">resolved</a>,
:: The <a>current time</a> is the animation's <a>hold time</a>.
: If <em>any</em> of the following are true:
1. the animation has no associated <a>timeline</a>, or
2. the associated <a>timeline</a> is
<a lt="inactive timeline">inactive</a>, or
3. the animation's <a lt="animation start time">start time</a> is
<a>unresolved</a>.
:: The <a>current time</a> is an <a>unresolved</a> time value.
: Otherwise,
::
<blockquote>
<code><a>current time</a> =
(<var>timeline time</var> - <a lt="animation start time">start time</a>)
× <a lt="animation playback rate">playback rate</a></code>
</blockquote>
Where <var>timeline time</var> is the current <a>time value</a> of
the associated <a>timeline</a>.
The <a lt="animation playback rate">playback rate</a> value is
defined in [[#speed-control]].
</div>
<h4 id="setting-the-current-time-of-an-animation">Setting the current time of an animation</h4>
The <a>current time</a> of an animation can be set to a new value to
<em>seek</em> the animation.
The procedure for setting the current time is split into two parts.
The procedure to <dfn>silently set the current time</dfn> of
an animation, <var>animation</var>, to <var>seek time</var> is as follows:
1. If <var>seek time</var> is an <a>unresolved</a> time value,
then perform the following steps.
1. If the <a>current time</a> is <a lt=unresolved>resolved</a>, then
<a>throw</a> a <span class=exceptionname>TypeError</span>.
1. Abort these steps.
2. Update either <var>animation</var>'s <a>hold time</a> or <a
lt="animation start time">start time</a> as follows:
<div class="switch">
: If <em>any</em> of the following conditions are true:
* <var>animation</var>'s <a>hold time</a> is
<a lt="unresolved">resolved</a>, or
* <var>animation</var>'s <a lt="animation start time">start time</a>
is <a lt="unresolved">unresolved</a>, or
* <var>animation</var> has no associated <a>timeline</a> or the
associated <a>timeline</a> is
<a lt="inactive timeline">inactive</a>, or
* <var>animation</var>'s
<a lt="animation playback rate">playback rate</a> is 0,
:: Set <var>animation</var>'s <a>hold time</a> to <var>seek time</var>.
: Otherwise,
:: Set <var>animation</var>'s <a lt="animation start time">start time</a>
to the result of evaluating
<code><var>timeline time</var> - (<var>seek time</var> / <a
lt="animation playback rate">playback rate</a>)</code>
where <var>timeline time</var> is the current <a>time value</a>
of <a>timeline</a> associated with <var>animation</var>.
</div>
1. If <var>animation</var> has no associated <a>timeline</a> or the associated
<a>timeline</a> is <a lt="inactive timeline">inactive</a>,
make <var>animation</var>'s <a lt="animation start time">start time</a>
<a>unresolved</a>.
<p class=annotation>
This preserves the invariant that when we don't have an active timeline it
is only possible to set <em>either</em> the <a>animation start time</a>
<em>or</em> the animation's <a>current time</a>.
</p>
4. Make <var>animation</var>'s <a>previous current time</a> <a>unresolved</a>.
The procedure to <dfn>set the current time</dfn> of an animation,
<var>animation</var>, to <var>seek time</var> is as follows:
1. Run the steps to <a>silently set the current time</a> of
<var>animation</var> to <var>seek time</var>.
1. If <var>animation</var> has a <a>pending pause task</a>, synchronously
complete the pause operation by performing the following steps:
1. Set <var>animation</var>'s <a>hold time</a> to <var>seek time</var>.
1. Make <var>animation</var>'s <a lt="animation start time">start time</a>
<a>unresolved</a>.
1. Cancel the <a>pending pause task</a>.
1. <a lt="resolve a Promise">Resolve</a> <var>animation</var>'s
<a>current ready promise</a> with <var>animation</var>.
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to true, and
the <var>synchronously notify</var> flag set to false.
<h4 id='setting-the-start-time-of-an-animation'>Setting the start time of an animation</h4>
The procedure to <dfn>set the animation start time</dfn>
of <a>animation</a>, <var>animation</var>, to
<a lt="animation start time">start time</a>, <var>new start time</var>,
is as follows:
1. Let <var>timeline time</var> be the current <a>time value</a> of the
<a>timeline</a> that <var>animation</var> is associated with.
If there is no <a>timeline</a> associated with <var>animation</var> or the
associated timeline is <a lt="inactive timeline">inactive</a>,
let the <var>timeline time</var> be <a>unresolved</a>.
1. If <var>timeline time</var> is <a>unresolved</a> and <var>new start
time</var> is <a lt="unresolved">resolved</a>, make <var>animation</var>'s
<a>hold time</a> <a>unresolved</a>.
<p class=annotation>
This preserves the invariant that when we don't have an active timeline it
is only possible to set <em>either</em> the <a>animation start time</a>
<em>or</em> the animation's <a>current time</a>.
</p>
1. Let <var>previous current time</var> be <var>animation</var>'s <a>current
time</a>.
Note: This is the <a>current time</a> after applying the changes from the
previous step which may cause the <a>current time</a> to become
<a>unresolved</a>.
1. Set <var>animation</var>'s <a lt="animation start time">start time</a> to
<var>new start time</var>.
1. Update <var>animation</var>'s <a>hold time</a> based on the first matching
condition from the following,
<div class="switch">
: If <var>new start time</var> is <a lt="unresolved">resolved</a>,
:: If <var>animation</var>'s <a lt="animation playback rate">playback
rate</a> is not zero, make <var>animation</var>'s <a>hold time</a>
<a>unresolved</a>.
: Otherwise (<var>new start time</var> is <a>unresolved</a>),
:: Set <var>animation</var>'s <a>hold time</a> to <var>previous current
time</var> even if <var>previous current time</var> is
<a>unresolved</a>.
</div>
1. If <var>animation</var> has a <a>pending play task</a> or
a <a>pending pause task</a>, cancel that task and
<a lt="resolve a Promise">resolve</a> <var>animation</var>'s
<a>current ready promise</a> with <var>animation</var>.
1. Run the procedure to <a>update an animation's finished state</a> for
<var>animation</var> with the <var>did seek</var> flag set to true, and
the <var>synchronously notify</var> flag set to false.