<style>
.informative-bg {
  margin: 1.5em 0 1em;
  padding: 1em;
  margin-top: 1em;
  background: #efe;
  border: green 1px dotted;
}

div.informative-bg *:last-child {
  margin-bottom: 0;
}

div.informative-bg p:first-child {
  margin-top: 0;
}

div.informative-bg h2,
div.informative-bg h3,
div.informative-bg h4 {
  background: none;
}

div.switch > dl {
  padding-left: 2em;
}

div.switch > dl > dt > p {
  display: inline;
}

div.switch > dl > dt:before {
  content: '\21AA';
  padding: 0 0.5em 0 0;
  display: inline-block;
  width: 1em;
  text-align: right;
  line-height: 0.5em;
  margin-left: -1.3em;
}

.attributes::before, .methods::before,
.parameters::before, .exceptions::before,
.constructors::before, .members::before {
  font: bold 100% sans-serif;
  text-align: left;
  margin: 1.33em 0px;
  color: #005A9C;
}

.attributes::before { content: 'Attributes' }
.methods::before { content: 'Methods' }
.parameters::before { content: 'Parameters' }
.exceptions::before { content: 'Exceptions' }
.constructors::before { content: 'Constructors' }
.members::before { content: 'Dictionary members' }

.param,
.exceptionname,
.estype,
.esvalue {
  font-weight: bold;
}

.formula {
  display: block;
  margin: .5em 2em;
}
</style>

<pre class='metadata'>
Title: Web Animations
Status: ED
Work Status: Refining
Shortname: web-animations-1
TR: https://www.w3.org/TR/web-animations-1/
ED: https://drafts.csswg.org/web-animations-1/
Previous version: https://www.w3.org/TR/2018/WD-web-animations-1-20181011/
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/
Version history: https://github.com/w3c/csswg-drafts/commits/master/web-animations-1
Level: 1

Group: csswg
!Participate: <a href="https://github.com/w3c/csswg-drafts/tree/master/web-animations-1">Fix the text through GitHub</a>
!Participate: Join the &lsquo;waapi&rsquo; 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/csswg-drafts
!Issue Tracking: <a href="https://github.com/w3c/csswg-drafts/labels/web-animations-1">GitHub</a>
!Tests: <a href="https://github.com/web-platform-tests/wpt/tree/master/web-animations">web-platform-tests web-animations/</a> (<a href="https://github.com/web-platform-tests/wpt/labels/web-animations">ongoing work</a>)

Editor: Brian Birtles 43194, Mozilla, bbirtles@mozilla.com
Editor: Robert Flack 98451, Google Inc, flackr@google.com
Editor: Stephen McGruer 96463, Google Inc, smcgruer@google.com
Editor: Antoine Quint 51377, Apple Inc, graouts@apple.com
Former Editor: Shane Stephens 47691, Google Inc, shans@google.com
Former Editor: Douglas Stockwell, Google Inc, dstockwell@google.com
Former Editor: Alex Danilo 31960, Google Inc, adanilo@google.com
Former Editor: Tab Atkins 42199, Google Inc, jackalmage@gmail.com
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, (unrestricted double or DOMString)
Link Defaults: css-transforms (property) transform
Markup Shorthands: markdown yes
</pre>
<pre class="anchors">
urlPrefix: https://heycam.github.io/webidl/#dfn-; type: dfn; spec: webidl
    text: present
    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: a new promise
    text: create a new resolved Promise; url: a-promise-resolved-with
    text: [EnforceRange]; url: EnforceRange
    text: es to dictionary
    text: es to DOMString; url: es-to-DOMString
    text: DOMString to es; url: DOMString-to-es
    text: reject a promise; url: reject
    text: resolve a promise; url: resolve
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: Type; url: ecmascript-data-types-and-values
    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: being rendered
    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/webappapis.html; type: interface; spec: html
    text: EventHandler
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
    text: transitionend
urlPrefix: https://drafts.csswg.org/css-transitions-2/; type: dfn; spec: css-transitions-2
    text: owning element (transition); url: owning-element
urlPrefix: https://drafts.csswg.org/css-animations/; type: dfn; spec: css-animations-1
    text: events from CSS animations; url: events
urlPrefix: https://drafts.csswg.org/css-animations-2/; type: dfn; spec: css-animations-2
    text: owning element (animation); url: owning-element
urlPrefix: https://drafts.csswg.org/css-writing-modes-4/; type: dfn; spec: css-writing-modes-4
    text: equivalent physical property; url: logical-to-physical
urlPrefix: https://drafts.csswg.org/css-style-attr/; type: dfn; spec: css-style-attr
    text: style attribute
urlPrefix: https://drafts.csswg.org/web-animations-2/; type: dfn; spec: web-animations-2
    text: iteration composite operation
    text: iteration composite operation accumulate
</pre>
<pre class="link-defaults">
spec:dom; type:interface; text:DocumentOrShadowRoot
spec:dom; type:interface; text:EventTarget
spec:dom; type:interface; text:Event
spec:dom; type:dfn; for:/; text:shadow root
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
spec:cssom-1;
    type: dfn;
        text: CSS declaration block
spec:infra; type:dfn; text:list
spec:infra; type:dfn; for:list; text:extend
</pre>

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({showMathMenu: false});
</script>
<script src="MathJax/MathJax.js?config=MML_SVG"></script>

Introduction {#introduction}
=======================================
<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.

Use cases {#use-cases}
----------------------------------------

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 =&gt; animation.finished)
).then(() =&gt; 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 =&gt; 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 =&gt; 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,
    &ldquo;Why is the opacity of this element changing?&rdquo;

    <div class='example'>
    <pre class='lang-javascript'>
// Print the id of any opacity animations on elem
elem.getAnimations().filter(
  animation =&gt;
    animation.effect instanceof KeyframeEffect &&
    animation.effect.getKeyframes().some(
      frame =&gt; frame.hasOwnProperty('opacity')
    )
).forEach(animation =&gt; 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 =&gt;
    animation.effect instanceof KeyframeEffect &&
    animation.effect.getKeyframes().some(
      frame =&gt; frame.hasOwnProperty('transform')
    )
).forEach(animation =&gt; {
  animation.currentTime = 0;
  animation.updatePlaybackRate(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 =&gt;
    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 =&gt; animation.finish()
);
// Wait one frame so that event handlers have a chance to run
requestAnimationFrame(() =&gt; {
  assert.strictEqual(
    getComputedStyle(document.querySelector('#loading')).display, 'none');
});
</pre></div>

Relationship to other specifications {#relationship-to-other-specifications}
----------------------------------------

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 &ldquo;requestAnimationFrame&rdquo;) [[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]].

Overview of this specification {#overview-of-this-specification}
----------------------------------------

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>

Specification conventions {#spec-conventions}
=======================================

This specification begins by describing abstract concepts such as [=animations=]
and [=animation effects=] and properties that belong to them such as their
[=playback rate=] or [=iteration duration=].
In addition to these properties, there are often specific procedures for
updating these properties such as the procedure to [=set the playback rate=] or
the procedure to [=set the start time=] of an animation.

Where this specification does not specifically link to a procedure, text
that requires the user agent to update a property such as, &ldquo;make
|animation|'s [=start time=] [=unresolved=]&rdquo;, should be understood to
refer to updating the property directly <em>without</em> invoking any related
procedure.

Further documentation conventions that are not specific to this specification
are described in [[#document-conventions]].

Web Animations model overview {#web-animations-model-overview}
=======================================

<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>

Timing model {#timing-model}
=======================================

This section describes and defines the behavior of the Web Animations
timing model.

Timing model overview {#timing-model-overview}
----------------------------------------

<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>.

### Stateless ### {#stateless}

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 ([=associated 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.

### Hierarchical ### {#hierarchical}

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>
  <img src="img/time-hierarchy.svg" width="350"
            alt="A hierarchy of timing nodes">
  <figcaption>
    A hierarchy of timing nodes.
    Each node in the tree derives its time from its parent node.
  </figcaption>
</figure>

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.

</div>

Time values {#time-value-section}
----------------------------------------

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="note">
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>.

Timelines {#timelines}
----------------------------------------

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>.

A <a>timeline</a> is <dfn export lt="monotonically increasing timeline"
local-lt="monotonically increasing">monotonically increasing</dfn> if its
reported [=timeline current time|current time=] is always greater than or equal
than its previously reported [=timeline current time|current time=].

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=] <a lt="associated
          with a timeline">associated with</a> 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.   [=Remove replaced animations=] for |doc|.

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>.

### Document timelines ### {#document-timelines}

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(2079): There must be a better term than &ldquo;origin time&rdquo;&mdash;
             it's too similar to &ldquo;time origin&rdquo;.

Prior to establishing the [=time origin=] for its associated document,
a [=document timeline=] is <a lt="inactive timeline">inactive</a>.

After a [=document timeline=] becomes [=inactive timeline|active=], it is
[=monotonically increasing=].

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=].

### The default document timeline ### {#the-documents-default-timeline}

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>

Animations {#animations}
----------------------------------------

<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>associated 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 <a>associated 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>start time</dfn> is the
<a>time value</a> of its <a>timeline</a> when its <a>associated effect</a>
is scheduled to begin playback.
An animation's start time 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]]).

### Setting the timeline of an animation ### {#setting-the-timeline}

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 [=start time=] 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 &ldquo;sticky&rdquo; but is re-evaluated
    based on its updated <a>current time</a>.

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(2080): 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="note">

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-associated-effect" oldids="setting-the-target-effect">Setting the associated effect of an animation</h4>

The procedure to <dfn>set the associated 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>associated 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>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>.
1.  If <var>new effect</var> is not <code>null</code> and
    if <var>new effect</var> is the <a>associated effect</a> of another
    <a>animation</a>, <var>previous animation</var>, run the procedure to <a>set
    the associated effect of an animation</a> (this procedure) on <var>previous
    animation</var> passing null as <var>new effect</var>.
1.  Let the <a>associated effect</a> of <var>animation</var> be <var>new
    effect</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 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.  [=Apply any pending playback rate=] on |animation|.
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> with value <var>animation</var> in the <a>relevant Realm</a> of
    <var>animation</var>.

### The current time of an animation ### {#the-current-time-of-an-animation}

<a>Animations</a> provide a <a>time value</a> to their <a>associated
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 [=start time=] 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> - [=start time=])
      &times; [=playback rate=]</code>
    </blockquote>

    Where <var>timeline time</var> is the current <a>time value</a> of
    the associated <a>timeline</a>.
    The [=playback rate=] value is defined in [[#speed-control]].

</div>

### Setting the current time of an animation ### {#setting-the-current-time-of-an-animation}

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 defined in 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
    [=start time=] 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 [=start time=]
            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 [=playback rate=] is 0,

    ::  Set <var>animation</var>'s <a>hold time</a> to <var>seek time</var>.

    :   Otherwise,
    ::  Set <var>animation</var>'s [=start time=] to the result of evaluating
        <code>|timeline time| - (|seek time| / [=playback rate=])</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 [=start time=] <a>unresolved</a>.

    <p class=note>
      This preserves the invariant that when we don't have an active timeline it
      is only possible to set <em>either</em> the [=start time=]
      <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.  [=Apply any pending playback rate=] to |animation|.
    1.  Make <var>animation</var>'s [=start time=] <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.

### Setting the start time of an animation ### {#setting-the-start-time-of-an-animation}

The procedure to <dfn>set the start time</dfn>
of <a>animation</a>, <var>animation</var>, to <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=note>
      This preserves the invariant that when we don't have an active timeline it
      is only possible to set <em>either</em> the [=start time=]
      <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.  [=Apply any pending playback rate=] on |animation|.

1.  Set <var>animation</var>'s [=start time=] 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 [=playback rate=] 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.

<h4 id="waiting-for-the-associated-effect" oldids="waiting-for-the-target-effect">Waiting for the associated effect</h4>

<div class='informative-bg'>

<em>This section is non-normative</em>

Some operations performed by an <a>animation</a> may not occur
instantaneously.
For example, some user agents may delegate the playback of an
animation to a separate process or to specialized graphics hardware
each of which may incur some setup overhead.

If such an animation is timed from the moment when the animation was
triggered there may be a significant jump between the first and second
frames of the animation corresponding to the setup time involved.

To avoid this problem, Web Animations typically begins timing
animations from the moment when the first frame of the animation is
complete.
This is represented by an <a>unresolved</a>
[=start time=] on the <a>animation</a> which becomes
resolved when the animation is <a>ready</a>.
Content may opt out of this behavior by setting the
[=start time=] to a <a lt="unresolved">resolved</a> <a>time value</a>.

</div>

An animation is <dfn>ready</dfn> at the first moment where <em>both</em> of the
following conditions are true:

*   the user agent has completed any setup required to begin the playback of
    the animation's <a>associated effect</a>
    including rendering the first frame of any <a>keyframe
    effect</a>.

*   the animation is associated with a <a>timeline</a> that is not
    <a lt="inactive timeline">inactive</a>.

### The current ready promise ### {#the-current-ready-promise}

Each <a>animation</a> has a <dfn>current ready promise</dfn>.
The <a>current ready promise</a> is initially a resolved <a>Promise</a> created
using the procedure to <a>create a new resolved Promise</a> with the animation
itself as its value and created in the <a>relevant Realm</a> of the animation.

The object is replaced with a new <a>Promise object</a> every time the animation
queues a <a>pending play task</a> or a <a>pending pause task</a> when it
previously did not have a pending task, or when the animation is canceled (see
[[#canceling-an-animation-section]]).

<div class="note">

    Note that since the same object is used for both pending play and
    pending pause requests, authors are advised to check the state of the
    animation when the <a>Promise object</a> is resolved.

    For example, in the following code fragment, the state of the animation
    will be <a lt="running play state">running</a> when the
    <a>current ready promise</a> is resolved.
    This is because the <code>play</code> operation occurs while a <a>pending
    play task</a> is still queued and hence the <a>current ready promise</a>
    is re-used.

    <div class='example'><pre class='lang-javascript'>
animation.pause();
animation.ready.then(function() {
  // Displays 'running'
  alert(animation.playState);
});
animation.play();</pre></div>

</div>

### Playing an animation ### {#playing-an-animation-section}

The procedure to <dfn>play an animation</dfn>, <var>animation</var>, given
a flag <var>auto-rewind</var>, is as follows:

Note: The <var>auto-rewind</var> flag is provided for other specifications
that build on this model but do not require the rewinding behavior, such
as CSS Animations [[CSS-ANIMATIONS-1]].

1.  Let <var>aborted pause</var> be a boolean flag that is true if
    <var>animation</var> has a <a>pending pause task</a>, and false otherwise.
1.  Let <var>has pending ready promise</var> be a boolean flag that is
    initially false.
1.  Perform the steps corresponding to the <em>first</em> matching
    condition from the following, if any:

    <div class="switch">

    :   If |animation|'s [=effective playback rate=] &gt; 0,
        the <var>auto-rewind</var> flag is true and <em>either</em>
        <var>animation</var>'s:

        *   <a>current time</a> is <a>unresolved</a>, or
        *   <a>current time</a> &lt; zero, or
        *   <a>current time</a> &ge; <a>associated effect end</a>,

    ::  Set <var>animation</var>'s <a>hold time</a> to zero.
    :   If |animation|'s [=effective playback rate=] &lt; 0,
        the <var>auto-rewind</var> flag is true and <em>either</em>
        <var>animation</var>'s:

        *   <a>current time</a> is <a>unresolved</a>, or
        *   <a>current time</a> &le; zero, or
        *   <a>current time</a> &gt; <a>associated effect end</a>,

    ::  If <a>associated effect end</a> is positive infinity,
        <a>throw</a> an "{{InvalidStateError}}" {{DOMException}} and
        abort these steps.
        Otherwise, set <var>animation</var>'s <a>hold time</a> to <a>associated
        effect end</a>.
    :   If |animation|'s [=effective playback rate=] = 0 and |animation|'s
        [=current time=] is [=unresolved=],
    ::  Set <var>animation</var>'s <a>hold time</a> to zero.

    </div>

1.  If <var>animation</var> has a <a>pending play task</a> or a
    <a>pending pause task</a>,

    1.  Cancel that task.
    1.  Set <var>has pending ready promise</var> to true.

1.  If the following three conditions are <em>all</em> satisfied:

    * |animation|'s [=hold time=] is [=unresolved=], and
    * |aborted pause| is false, and
    * |animation| does <em>not</em> have a [=pending playback rate=],

    abort this procedure.

1.  If <var>animation</var>'s <a>hold time</a> is <a lt=unresolved>resolved</a>,
    let its [=start time=] be <a>unresolved</a>.

1.  If <var>has pending ready promise</var> is false,
    let <var>animation</var>'s <a>current ready promise</a> be
    <a>a new promise</a> in the <a>relevant Realm</a> of <var>animation</var>.

1.  Schedule a task to run as soon as <var>animation</var> is <a>ready</a>.
    The task shall perform the following steps:

    1.  Assert that at least one of |animation|'s [=start time=] or [=hold
        time=] is <a lt=unresolved>resolved</a>.

    1.  Let <var>ready time</var> be the <a>time value</a> of
        the <a>timeline</a> associated with <var>animation</var> at the moment
        when <var>animation</var> became <a>ready</a>.

    1.  Perform the steps corresponding to the first matching condition below,
        if any:

        <div class="switch">

        :   If |animation|'s [=hold time=] is <a lt=unresolved>resolved</a>,

        ::  1.  [=Apply any pending playback rate=] on |animation|.

            1.  Let |new start time| be the result of evaluating
                <code>|ready time| - [=hold time=] / [=playback rate=]</code>
                for |animation|.
                If the [=playback rate=] is zero, let
                |new start time| be simply |ready time|.

            1.  Set the [=start time=] of |animation| to |new start time|.

            1.  If |animation|'s [=playback rate=] is not 0, make |animation|'s
                [=hold time=] [=unresolved=].

        :   If |animation|'s [=start time=] is resolved and |animation| has
            a [=pending playback rate=],

        ::  1.  Let |current time to match| be the result of evaluating
                <code>(|ready time| - [=start time=]) &times;
                [=playback rate=]</code> for |animation|.

            1.  [=Apply any pending playback rate=] on |animation|.

            1.  If |animation|'s [=playback rate=] is zero, let |animation|'s
                [=hold time=] be |current time to match|.

            1.  Let |new start time| be the result of evaluating
                <code>|ready time| - |current time to match| /
                [=playback rate=]</code> for |animation|.
                If the [=playback rate=] is zero, let |new start time| be simply
                |ready time|.

            1.  Set the [=start time=] of |animation| to |new start time|.

        </div>

    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 false,
        and the <var>synchronously notify</var> flag set to false.

        <div class="note">
            Note that the order of the above two steps is important
            since it means that an animation with zero-length <a>associated
            effect</a> will resolve its <a>current ready promise</a>
            before its <a>current finished promise</a>.
        </div>

    So long as the above task is scheduled but has yet to run,
    <var>animation</var> is described as having a
    <dfn>pending play task</dfn>.
    While the task is running, however, |animation| does <em>not</em> have
    a [=pending play task=].

    If a user agent determines that |animation| is immediately <a>ready</a>, it
    may schedule the above task as a microtask such that it runs at the next
    <a lt="perform a microtask checkpoint">microtask checkpoint</a>, but it must
    <em>not</em> perform the task synchronously.

    <div class="note">

    The above requirement to run the <a>pending play task</a> asynchronously
    ensures that code such as the following behaves consistently between
    implementations:

    <div class='example'><pre class='lang-javascript'>
    animation.play();
    animation.ready.then(
      () => { console.log('Playback commenced'); },
      () => { console.log('Playback was canceled'); }
    );
    // Suppose some condition requires playback to be canceled...
    animation.cancel();
    // "Playback was canceled" will be printed to the console.
    </pre></div>

    In the above code, were the [=pending play task=] run synchronously, the
    [=current ready promise=] would not be rejected.

    </div>

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.

### Pausing an animation ### {#pausing-an-animation-section}

Whenever an <a>animation</a> has an <a>unresolved</a> [=start time=],
its <a>current time</a> will be suspended.

As with <a lt="play an animation">playing an animation</a>, pausing may not
happen instantaneously (see [[#waiting-for-the-associated-effect]]).
For example, if animation is performed by a separate process, it may
be necessary to synchronize the <a>current time</a> to ensure that it
reflects the state drawn by the animation process.

The procedure to <dfn>pause an animation</dfn>, <var>animation</var>, is as
follows:

1.  If <var>animation</var> has a <a>pending pause task</a>, abort these steps.
1.  If the <a>play state</a> of <var>animation</var> is <a
    lt="paused play state">paused</a>, abort these steps.
1.  If the <var>animation</var>'s <a>current time</a> is <a>unresolved</a>,
    perform the steps according to the first matching condition from below:

    <div class="switch">

    :    If <var>animation</var>'s [=playback rate=] is &ge; 0,
    ::   Let <var>animation</var>'s <a>hold time</a> be zero.

    :    Otherwise,
    ::   If <a>associated effect end</a> for <var>animation</var> is positive
         infinity,
         <a>throw</a> an "{{InvalidStateError}}" {{DOMException}}
         and abort these steps.
         Otherwise, let <var>animation</var>'s <a>hold time</a> be
         <a>associated effect end</a>.

    </div>

1.  Let <var>has pending ready promise</var> be a boolean flag that is
    initially false.
1.  If <var>animation</var> has a <a>pending play task</a>, cancel that task
    and let <var>has pending ready promise</var> be true.
1.  If <var>has pending ready promise</var> is false,
    set <var>animation</var>'s <a>current ready promise</a> to
    <a>a new promise</a> in the <a>relevant Realm</a> of <var>animation</var>.
1.  Schedule a task to be executed at the first possible moment after
    the user agent has performed any processing necessary to suspend
    the playback of
    <var>animation</var>'s <a>associated effect</a>, if any.
    The task shall perform the following steps:

    1.  Let <var>ready time</var> be the time value of the timeline associated
        with <var>animation</var> at the moment when the user agent completed
        processing necessary to suspend playback of <var>animation</var>'s
        <a>associated effect</a>.

    1.  If <var>animation</var>'s [=start time=]
        is <a lt=unresolved>resolved</a> and its <a>hold time</a> is
        <em>not</em> resolved,
        let <var>animation</var>'s <a>hold time</a> be the result of evaluating
        <code>(<var>ready time</var> - [=start time=]) &times;
        [=playback rate=]</code>.

        Note: The <a>hold time</a> might be already set if the animation
        is <a lt="finished play state">finished</a>, or if the animation
        has a <a>pending play task</a>.
        In either case we want to preserve the <a>hold time</a> as we
        enter the <a lt="paused play state">paused</a> state.

    1.  [=Apply any pending playback rate=] on |animation|.

    1.  Make <var>animation</var>'s [=start time=] unresolved.

    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 false,
        and the <var>synchronously notify</var> flag set to false.

    So long as the above task is scheduled but has yet to run,
    <var>animation</var> is described as having a <dfn>pending pause task</dfn>.
    While the task is running, however, <var>animation</var> does
    <em>not</em> have a <a>pending pause task</a>.

    As with the [=pending play task=], the user agent must run the [=pending
    pause task=] asynchronously, although that may be as soon as the next <a
    lt="perform a microtask checkpoint">microtask checkpoint</a>.

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.

### Reaching the end ### {#reaching-the-end}

<div class='informative-bg'>

<em>This section is non-normative</em>

DVD players or cassette players typically continue playing until they reach
the end of their media at which point they stop.
If such players are able to play in reverse, they typically stop
playing when they reach the beginning of their media.
In order to emulate this behavior and to provide consistency
with HTML's <a>media elements</a> [[HTML]], the <a>current time</a> of Web
Animations' animations do not play forwards beyond the <a>end time</a> of their
<a>associated effect</a> or play backwards past time zero.

An animation that has reached the natural boundary of its playback range
is said to have <em>finished</em>.

Graphically, the effect of limiting the current time is shown below.

<figure>
  <img src="img/limiting.svg" width="500"
       alt="The effect of limiting the current time of an animation.">
  <figcaption>
    The effect of limiting the <a>current time</a> of an <a>animation</a>
    with a start time of 1s, an [=associated effect=] of length 3s, and
    a positive [=playback rate=].
    After the <a>current time</a> of the animation reaches the end of the
    associated effect, it is capped at 3s.
  </figcaption>
</figure>

It is possible, however, to <em>seek</em> the <a>current time</a> of
an <a>animation</a> to a time past the end of the <a>associated effect</a>.
When doing so, the <a>current time</a> will not progress but the
animation will act as if it had been paused at the seeked time.

This allows, for example, seeking the <a>current time</a> of
an animation with <em>no</em> <a>associated effect</a> to 5s.
If <a>associated effect</a> with an <a>end time</a> later than 5s is
later associated with the animation, playback will begin from the 5s
mark.

Similar behavior to the above scenario may arise when the
length of an animation's <a>associated effect</a> changes.

Similarly, when the [=playback rate=] is negative, the
<a>current time</a> does not progress past time zero.

</div>

### The current finished promise ### {#the-current-finished-promise}

Each animation has a <dfn>current finished promise</dfn>.
The <a>current finished promise</a> is initially a pending <a>Promise</a>
object.

The object is replaced with a new <a>promise</a> every time
the animation leaves the <a>finished play state</a>.

### Updating the finished state ### {#updating-the-finished-state}

For an animation with a positive [=playback rate=], the <a>current time</a>
continues to increase until it reaches the <a>associated effect end</a>.

The <dfn>associated effect end</dfn> of an animation is equal to the <a>end
time</a> of the animation's <a>associated effect</a>.
If the animation has no <a>associated effect</a>, the <a>associated effect
end</a> is zero.

For an animation with a negative [=playback rate=], the <a>current time</a>
continues to decrease until it reaches zero.

A running animation that has reached this boundary (or overshot it) and has a
<a lt="unresolved">resolved</a> [=start time=]
is said to be <a lt="finished play state">finished</a>.

The crossing of this boundary is checked on each modification to the
animation object using the procedure to <a>update an animation's finished
state</a> defined below. This procedure is also run as part of the [=update
animations and send events=] procedure. In both cases the <var>did seek</var>
flag, defined below, is set to false.

For each animation, the user agent maintains a <dfn>previous current
time</dfn> <a>time value</a> that is originally <a>unresolved</a>.

Whilst during normal playback the <a>current time</a> of an <a>animation</a> is
limited to the boundaries described above, it is possible to seek the <a>current
time</a> of an <a>animation</a> to times outside those boundaries using the
procedure to <a>set the current time</a> of an <a>animation</a>.

The procedure to <dfn>update an animation's finished state</dfn> for
<var>animation</var>, given a flag <var>did seek</var> (to indicate if
the update is being performed after <a lt="set the current time">setting the
current time</a>), and a flag <var>synchronously notify</var> (to indicate
the update was called in a context where we expect finished event queueing
and finished promise resolution to happen immediately, if at all) is as
follows:

1.  Let the <var>unconstrained current time</var> be the result of calculating
    the <a>current time</a> substituting an <a>unresolved</a> time value for the
    <a>hold time</a> if <var>did seek</var> is false.
    If <var>did seek</var> is true, the <var>unconstrained current time</var>
    is equal to the <a>current time</a>.

    Note: This is required to accommodate timelines that may change direction.
    Without this definition, a once-finished animation would remain finished
    even when its timeline progresses in the opposite direction.

1.  If <em>all three</em> of the following conditions are true,

    *   the <var>unconstrained current time</var> is <a
        lt=unresolved>resolved</a>, <em>and</em>
    *   <var>animation</var>'s [=start time=] is
        <a lt="unresolved">resolved</a>, <em>and</em>
    *   <var>animation</var> does <em>not</em> have a <a>pending play task</a>
        or a <a>pending pause task</a>,

    then update <var>animation</var>'s <a>hold time</a> based on the first
    matching condition for <var>animation</var> from below, if any:

    <div class='switch'>

    :   If [=playback rate=] &gt; 0 and
        <var>unconstrained current time</var> is greater than or equal to
        <a>associated effect end</a>,
    ::  If <var>did seek</var> is true, let the <a>hold time</a>
        be the value of <var>unconstrained current time</var>.

        If <var>did seek</var> is false, let the <a>hold time</a> be the maximum
        value of <a>previous current time</a> and <a>associated effect end</a>.
        If the <a>previous current time</a> is
        <a>unresolved</a>, let the <a>hold time</a> be <a>associated
        effect end</a>.
    :   If [=playback rate=] &lt; 0 and
        <var>unconstrained current time</var> is less than or equal to 0,
    ::  If <var>did seek</var> is true, let the <a>hold time</a>
        be the value of <var>unconstrained current time</var>.

        If <var>did seek</var> is false, let the <a>hold time</a> be the
        minimum value of <a>previous current time</a> and zero.
        If the <a>previous current time</a> is
        <a>unresolved</a>, let the <a>hold time</a> be zero.
    :   If [=playback rate=] &ne; 0, and
        <var>animation</var> is associated with an
        <a lt="inactive timeline">active timeline</a>,
    ::  Perform the following steps:

        1.  If <var>did seek</var> is true and the <a>hold time</a> is <a
            lt=unresolved>resolved</a>, let <var>animation</var>'s
            [=start time=] be equal to the result of evaluating
            <code>|timeline time| - ([=hold time=] / [=playback rate=])</code>
            where <var>timeline time</var> is the current <a>time value</a>
            of <a>timeline</a> associated with <var>animation</var>.

        1.  Let the <a>hold time</a> be <a>unresolved</a>.

    </div>

1.  Set the <a>previous current time</a> of <var>animation</var> be the
    result of calculating its <a>current time</a>.
1.  Let <var>current finished state</var> be true if the <a>play
    state</a> of <var>animation</var> is
    <a lt="finished play state">finished</a>.
    Otherwise, let it be false.
1.  If <var>current finished state</var> is true and the <a>current finished
    promise</a> is not yet resolved, perform the following steps:

    1.  Let <dfn>finish notification steps</dfn> refer to the following
        procedure:
        1.  If <var>animation</var>'s <a>play state</a> is not equal to <a
            lt="finished play state">finished</a>, abort these steps.
        1.  <a lt="resolve a promise">Resolve</a> <var>animation</var>'s
            <a>current finished promise</a> object with
            <var>animation</var>.
        1.  <a lt="create an event">Create</a> an {{AnimationPlaybackEvent}},
            |finishEvent|.
        1.  Set |finishEvent|'s {{Event/type}} attribute to <a lt="finish
            event">finish</a>.
        1.  Set |finishEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
            to the [=current time=] of |animation|.
        1.  Set |finishEvent|'s {{AnimationPlaybackEvent/timelineTime}}
            attribute to the <a lt="timeline current time">current time</a>
            of the [=timeline=] with which |animation| is associated.
            If |animation| is not associated with a timeline, or the timeline
            is <a lt="inactive timeline">inactive</a>, let
            {{AnimationPlaybackEvent/timelineTime}} be
            <code class=esvalue>null</code>.
        1.  If |animation| has a [=document for timing=], then append
            |finishEvent| to its [=document for timing=]'s [=pending animation
            event queue=] along with its target, |animation|.
            For the [=scheduled event time=], use the result of <a lt="animation
            time to origin-relative time">converting</a>
            |animation|'s [=associated effect end=] to an origin-relative time.

            Otherwise, [=queue a task=] to [=dispatch=] |finishEvent| at
            |animation|.
            The task source for this task is the [=DOM manipulation task
            source=].
    1.  If <var>synchronously notify</var> is true, cancel any queued
        microtask to run the <a>finish notification steps</a> for this
        <var>animation</var>, and run the <a>finish notification
        steps</a> immediately.

        Otherwise, if <var>synchronously notify</var> is false, <a>queue
        a microtask</a> to run <a>finish notification steps</a> for
        <var>animation</var> unless there is already a microtask queued to run
        those steps for <var>animation</var>.
1.  If <var>current finished state</var> is false and
    <var>animation</var>'s <a>current finished promise</a> is already
    resolved, set <var>animation</var>'s <a>current finished promise</a> to
    <a>a new promise</a> in the <a>relevant Realm</a> of <var>animation</var>.

<div class="informative-bg">

Typically, notification about the finished state of an animation is
performed asynchronously. This allows for the animation to temporarily
enter the <a lt="finished play state">finished state</a> without
triggering events to be fired or promises to be resolved.

For example, in the following code fragment, <code>animation</code> temporarily
enters the finished state. If notification of the finished state occurred
synchronously this code would cause the <a>finish event</a> to be queued
and the <a>current finished promise</a> to be resolved. However, if we
reverse the order of the two statements such that the
<code>iterationCount</code> is updated first, this would not happen.
To avoid this surprising behavior, notification about the finished state of
an animation is typically performed asynchronously.

<div class='example'><pre class='lang-javascript'>
var animation = elem.animate({ left: '100px' }, 2000);
animation.playbackRate = 2;
animation.currentTime = 1000; // animation is now finished
animation.effect.updateTiming({ iterationCount: 2 }); // animation is no longer finished
</pre></div>

The one exception to this asynchronous behavior is when the <a>finish an
animation</a> procedure is performed (typically by calling the
{{Animation/finish()}} method). In this case the author's intention to finish
the animation is clear so the notification about the finished state of the
animation occurs synchronously as demonstrated below.

<div class='example'><pre class='lang-javascript'>
var animation = elem.animate({ left: '100px' }, 1000);
animation.finish(); // finish event is queued immediately and finished promise
                    // is resolved despite the fact that the following statement
                    // causes the animation to leave the finished state
animation.currentTime = 0;
</pre></div>

Note that like the procedure to <a>finish an animation</a>, 
the procedure to <a>cancel an animation</a> similarly queues the
<a>cancel event</a> and rejects the <a>current finished promise</a> and
<a>current ready promise</a> in a <em>synchronous</em> manner.

</div>

### Finishing an animation ### {#finishing-an-animation-section}

An animation can be advanced to the natural end of its current playback
direction by using the procedure to <dfn>finish an animation</dfn>
for <var>animation</var> defined below:

1.  If |animation|'s [=effective playback rate=] is zero,
    or if |animation|'s [=effective playback rate=] &gt; 0
    and <a>associated effect end</a> is infinity,
    <a>throw</a> an "{{InvalidStateError}}" {{DOMException}} and
    abort these steps.

1.  [=Apply any pending playback rate=] to |animation|.

1.  Set <var>limit</var> as follows:

    <div class="switch">

    :   If [=playback rate=] &gt; 0,</dt>
    ::  Let <var>limit</var> be <a>associated effect end</a>.</dd>

    :   Otherwise,
    ::  Let <var>limit</var> be zero.</dd>

    </div>

1.  <a>Silently set the current time</a> to <var>limit</var>.

1.  If <var>animation</var>'s [=start time=] is
    <a>unresolved</a> and <var>animation</var> has an associated <a
    lt="inactive timeline">active</a> <a>timeline</a>, let the
    [=start time=] be the result of evaluating
    <code><var>timeline time</var> -
    (<var>limit</var> / [=playback rate=])</code>
    where <var>timeline time</var> is the current <a>time
    value</a> of the associated <a>timeline</a>.

  1.  If there is a <a>pending pause task</a> and
      [=start time=] is <a lt="unresolved">resolved</a>,

    1.  Let the <a>hold time</a> be <a>unresolved</a>.

        <div class="note">Typically the <a>hold time</a> will already be
        unresolved except in the case when the animation was previously <a
        lt="idle play state">idle</a>.</div>

    1.  Cancel the <a>pending pause task</a>.

    1.  <a lt="resolve a Promise">Resolve</a> the <a>current ready promise</a>
        of <var>animation</var> with <var>animation</var>.

1.  If there is a <a>pending play task</a> and [=start time=] is
    <a lt="unresolved">resolved</a>, cancel that task and <a lt="resolve
    a Promise">resolve</a> the <a>current ready promise</a> of
    <var>animation</var> 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 true.

### Canceling an animation ### {#canceling-an-animation-section}

An animation can be canceled which causes the <a>current time</a> to
become <a>unresolved</a> hence removing any effects caused by the
<a>associated effect</a>.

The procedure to <dfn>cancel an animation</dfn> for <var>animation</var> is
as follows:

1.  If <var>animation</var>'s <a>play state</a> is <em>not</em>
    <a lt="idle play state">idle</a>, perform the following steps:
    1.  Run the procedure to <a>reset an animation's pending tasks</a> on
        <var>animation</var>.
    1.  <a lt="reject a Promise">Reject</a> the <a>current finished promise</a>
        with a DOMException named "AbortError".
    1.  Let <a>current finished promise</a> be
        <a>a new promise</a> in the <a>relevant Realm</a> of
        <var>animation</var>.
    1.  <a lt="create an event">Create</a> an {{AnimationPlaybackEvent}},
        |cancelEvent|.
    1.  Set |cancelEvent|'s {{Event/type}} attribute to <a lt="cancel
        event">cancel</a>.
    1.  Set |cancelEvent|'s {{AnimationPlaybackEvent/currentTime}} to
        <code class=esvalue>null</code>.
    1.  Let |timeline time| be the <a lt="timeline current time">current
        time</a> of the [=timeline=] with which |animation| is associated.
        If |animation| is not associated with an <a lt="inactive
        timeline">active timeline</a>, let |timeline time| be n
        [=unresolved=] [=time value=].
    1.  Set |cancelEvent|'s {{AnimationPlaybackEvent/timelineTime}} to
        |timeline time|. If |timeline time| is [=unresolved=], set it to
        <code class=esvalue>null</code>.
    1.  If |animation| has a [=document for timing=], then append
        |cancelEvent| to its [=document for timing=]'s [=pending animation
        event queue=] along with its target, |animation|.
        If |animation| is associated with an <a lt="inactive timeline">active
        timeline</a> that defines a procedure to <a lt="timeline time to
        origin-relative time">convert timeline times to origin-relative
        time</a>, let the [=scheduled event time=] be the result of applying
        that procedure to |timeline time|.
        Otherwise, the [=scheduled event time=] is an [=unresolved=] [=time
        value=].

        Otherwise, [=queue a task=] to [=dispatch=] |cancelEvent| at
        |animation|.
        The task source for this task is the [=DOM manipulation task
        source=].

1.  Make <var>animation</var>'s <a>hold time</a> <a>unresolved</a>.
1.  Make <var>animation</var>'s [=start time=] <a>unresolved</a>.

### Speed control ### {#speed-control}

<div class="informative-bg">

The rate of play of an animation can be controlled by setting its
<em>playback rate</em>.
For example, setting a playback rate of 2 will cause the animation's
<a>current time</a> to increase at twice the rate of its <a>timeline</a>.
Similarly, a playback rate of -1 will cause the animation's <a>current
time</a> to decrease at the same rate as the <a>time values</a> from
its <a>timeline</a> increase.

</div>

<a>Animations</a> have a <dfn>playback rate</dfn>
that provides a scaling factor from the rate of change of the associated
<a>timeline</a>'s <a>time values</a> to the animation's <a>current time</a>.
The [=playback rate=] is initially 1.

Setting an animation's [=playback rate=]
to zero effectively pauses the animation (however, the <a>play state</a>
does not necessarily become <a lt="paused play state">paused</a>).

#### Setting the playback rate of an animation #### {#setting-the-playback-rate-of-an-animation}

The procedure to <dfn>set the playback rate</dfn> of
an <a>animation</a>, <var>animation</var> to <var>new playback rate</var>
is as follows:

1.  Clear any [=pending playback rate=] on |animation|.

1.  Let <var>previous time</var> be the value of the
    <a>current time</a> of <var>animation</var> before changing the
    [=playback rate=].

1.  Set the [=playback rate=] to <var>new playback rate</var>.

1.  If <var>previous time</var> is <a lt="unresolved">resolved</a>,
    <a>set the current time</a> of <var>animation</var> to
    <var>previous time</var>

#### Seamlessly updating the playback rate of an animation #### {#seamlessly-updating-the-playback-rate-of-an-animation}

For an in-flight animation that is running on another process or thread, the
procedure to <a>set the playback rate</a> may cause the animation to jump if the
process or thread running the animation is not currently synchronized with the
process or thread performing the update.

In order to produce seamless changes to the [=playback rate=] of an
[=animation=], animation's may have a <dfn>pending playback rate</dfn> that
defines a playback rate to be applied after any necessary synchronization has
taken place (for the case of animations running in a different thread or
process).

Initially the [=pending playback rate=] of an [=animation=] is unset.

The <dfn>effective playback rate</dfn> of an |animation| is
its [=pending playback rate=], if set,
otherwise it is the animation's [=playback rate=].

When an [=animation=], |animation|, is to <dfn>apply any pending playback
rate</dfn> the following steps are performed:

1.  If |animation| does not have a [=pending playback rate=], abort these steps.

1.  Set |animation|'s [=playback rate=] to its [=pending playback rate=].

1.  Clear |animation|'s [=pending playback rate=].

The procedure to <dfn>seamlessly update the playback rate</dfn> an
[=animation=], |animation|, to |new playback rate| preserving its [=current
time=] is as follows:

1.  Let |previous play state| be |animation|'s [=play state=].

    Note: It is necessary to record the play state
    before updating |animation|'s [=effective playback rate=] since,
    in the following logic,
    we want to immediately apply the [=pending playback rate=] of |animation|
    if it is <em>currently</em> <a lt="finished play state">finished</a>
    regardless of whether or not it will still be finished after we
    apply the [=pending playback rate=].

1.  Let |animation|'s [=pending playback rate=] be |new playback rate|.

1.  Perform the steps corresponding to the first matching condition from below:

    <div class="switch">

    :   If |animation| has a [=pending play task=] or a [=pending pause task=],

    ::  Abort these steps.

        Note: The different types of pending tasks will apply the [=pending
        playback rate=] when they run so there is no further action required in
        this case.

    :   If |previous play state| is <a lt="idle play state">idle</a>
        or <a lt="paused play state">paused</a>,

    ::  [=Apply any pending playback rate=] on |animation|.

    :   If |previous play state| is <a lt="finished play state">finished</a>,

    ::  1.  Let the |unconstrained current time| be the result of calculating
            the [=current time=] of |animation| substituting an [=unresolved=]
            time value for the [=hold time=].

        1.  Let |animation|'s [=start time=] be
            the result of evaluating the following expression:

             <blockquote>
               <code>|timeline time| - (|unconstrained current time|
               / [=pending playback rate=])</code>
              </blockquote>

            Where |timeline time| is the current <a>time value</a> of
            the <a>timeline</a> associated with |animation|.

            If [=pending playback rate=] is zero, let |animation|'s
            [=start time=] be |timeline time|.

        1.  [=Apply any pending playback rate=] on |animation|.

        1.  Run the procedure to [=update an animation's finished state=] for
            |animation| with the <var>did seek</var> flag set to false,
            and the <var>synchronously notify</var> flag set to false.

    :   Otherwise,

    ::  Run the procedure to [=play an animation=] for |animation| with the
        |auto-rewind| flag set to false.

    </div>

### Reversing an animation ### {#reversing-an-animation-section}

The procedure to <dfn>reverse an animation</dfn> of <a>animation</a>
<var>animation</var> is as follows:

1.  If there is no <a>timeline</a> associated with <var>animation</var>, or the
    associated <a>timeline</a> is <a lt="inactive timeline">inactive</a>
    <a>throw</a> an "{{InvalidStateError}}" {{DOMException}} and
    abort these steps.

1.  Let |original pending playback rate| be |animation|'s [=pending playback
    rate=].

1.  Let |animation|'s [=pending playback rate=] be the additive inverse of
    its [=effective playback rate=]
    (i.e. <code>-[=effective playback rate=]</code>).

1.  Run the steps to <a>play an animation</a> for <var>animation</var>
    with the <var>auto-rewind</var> flag set to true.

    If the steps to <a>play an animation</a> throw an exception, set
    |animation|'s [=pending playback rate=] to |original pending playback rate|
    and propagate the exception.

### Play states ### {#play-states}

An <a>animation</a> may be described as being in one of the following
<dfn lt="play state">play states</dfn> for each of which, a 
non-normative description is also provided:

<div class=informative-bg>

:   <a lt="idle play state">idle</a>
::  The <a>current time</a> of the animation is <a>unresolved</a> and
    there are no pending tasks.
    In this state the animation has no effect.
:   <a lt="running play state">running</a>
::  The animation has a resolved <a>current time</a> that changes on each
    <a>animation frame</a> (provided the [=playback rate=] is not zero).
:   <a lt="paused play state">paused</a>
::  The animation has been suspended and the <a>current time</a>
    is no longer changing.
:   <a lt="finished play state">finished</a>
::  The animation has reached the natural boundary of its playback range
    and the <a>current time</a> is no longer updating.

</div>

The <a>play state</a> of <a>animation</a>, <var>animation</var>, at a given
moment is the state corresponding to the <em>first</em> matching
condition from the following:

<div class="switch">

:   <em>All</em> of the following conditions are true:
    *   The <a>current time</a> of <var>animation</var> is <a>unresolved</a>,
        <em>and</em>
    *   <var>animation</var> does <em>not</em> have <em>either</em>
        a <a>pending play task</a> <em>or</em> a <a>pending pause task</a>,
::  &rarr; <dfn lt="idle play state">idle</dfn>
:   <em>Either</em> of the following conditions are true:
    *   <var>animation</var> has a <a>pending pause task</a>, <em>or</em>
    *   <em>both</em> the [=start time=] of
        <var>animation</var> is <a>unresolved</a> <em>and</em> it does
        <em>not</em> have a <a>pending play task</a>,
::  &rarr; <dfn lt="paused play state">paused</dfn>
:   For <var>animation</var>, <a>current time</a> is <a
    lt=unresolved>resolved</a> and <em>either</em> of the following conditions
    are true:
    *   |animation|'s [=effective playback rate=] &gt; 0 and
        <a>current time</a> &ge; <a>associated effect end</a>; <em>or</em>
    *   |animation|'s [=effective playback rate=] &lt; 0 and
        <a>current time</a> &le; 0,
::  &rarr; <dfn lt="finished play state">finished</dfn>
:   Otherwise,
::  &rarr; <dfn lt="running play state">running</dfn>

</div>

<div class="note">

Note that the <a>paused play state</a> effectively
&ldquo;wins&rdquo; over the <a>finished play state</a>.

However, an animation that is paused outside of its natural playback range can
be converted from a <a lt="paused play state">paused</a>
animation into a <a lt="finished play state">finished</a> animation
without restarting by setting the [=start time=] such as below:

<div class='example'><pre class='lang-javascript'>
animation.effect.updateTiming({ duration: 5000 });
animation.currentTime = 4000;
animation.pause();
animation.ready.then(function() {
  animation.effect.updateTiming({ duration: 3000 });
  alert(animation.playState); // Displays 'paused'
  animation.startTime =
    document.timeline.currentTime - animation.currentTime * animation.playbackRate;
  alert(animation.playState); // Displays 'finished'
});</pre></div>

</div>

### Animation events ### {#animation-events-section}

<dfn>Animation events</dfn> include the [=animation playback events=] defined in
this specification as well as the <a>events from CSS transitions</a>
[[CSS-TRANSITIONS-1]] and <a>events from CSS animations</a>
[[CSS-ANIMATIONS-1]].
Future specifications may extend this set with further types of [=animation
events=].

Each {{Document}} maintains a <dfn>pending animation event queue</dfn> that
stores [=animation events=] along with their corresponding event targets and
<dfn>scheduled event time</dfn>.
The [=scheduled event time=] is a [=time value=] relative to the [=time origin=]
representing when the event would ideally have been dispatched were animations
updated at an infinitely high frequency.
It is used by the procedure to [=update animations and send events=] to sort
queued [=animation events=] chronologically.
Note that this value may be [=unresolved=] if, for example, the [=animation=]'s
[=timeline=] produces values that are unrelated to the [=time origin=] (e.g.
a timeline that tracks scroll-position) or if the [=timeline=] is <a
lt="inactive timeline">inactive</a>.

#### Sorting animation events #### {#sorting-animation-events}

The following definitions are provided to assist with sorting queued events.

To <dfn lt="animation time to timeline time">convert an animation time to
timeline time</a> a [=time value=], |time|, that is relative to the [=start
time=] of an animation, |animation|, perform the following steps:

1.   If |time| is [=unresolved=], return |time|.

1.   If |time| is infinity, return an [=unresolved=] [=time value=].

1.   If |animation|'s [=playback rate=] is zero,
     return an [=unresolved=] [=time value=].

1.   If |animation|'s [=start time=] is [=unresolved=],
     return an [=unresolved=] [=time value=].

1.   Return the result of calculating:
     <code>|time| &times; (1 / |playback rate|) + |start time|</code>
     (where |playback rate| and |start time| are the [=playback rate=]
     and [=start time=] of |animation|, respectively).

To <dfn lt="animation time to origin-relative time">convert a timeline time to
an origin-relative time</dfn> a [=time value=], |time|, that is expressed in the
same scale as the [=time values=] of a [=timeline=], |timeline|, perform the
following steps:

1.   Let |timeline time| be the result of <a lt="animation time to timeline
     time">converting</a> |time| from an animation time to a timeline time.

1.   If |timeline time| is [=unresolved=],
     return |time|.

1.   If |animation| is not associated with a [=timeline=],
     return an [=unresolved=] time value.

1.   If |animation| is associated with an [=inactive timeline=],
     return an [=unresolved=] time value.

1.   If there is no procedure to <a lt="timeline time to origin-relative
     time">convert a timeline time to an origin-relative time</a> for the
     timeline associated with |animation|,
     return an [=unresolved=] [=time value=].

1.   Return the result of <a lt="timeline time to origin-relative
     time">converting</a> |timeline time| to an origin-relative time using
     the procedure defined for the [=timeline=] associated with |animation|.


#### Animation playback events #### {#animation-playback-events-section}

As <a>animations</a> play, they report changes to their status through
<dfn>animation playback events</dfn>.

<a>Animation playback events</a> are a property of the timing model. As a result
they are dispatched even when the <a>associated effect</a> of the <a>animation</a>
is absent or has no observable result.

#### Types of animation playback events #### {#animation-playback-event-types}

:   <dfn lt="finish event">finish</dfn>
::  Queued whenever an animation enters the <a>finished play state</a>.
:   <dfn lt="cancel event">cancel</dfn>
::  Queued whenever an animation enters the <a>idle play state</a> from
    another state. Creating a new <a>animation</a> that is initially
    idle does <em>not</em> generate a new <a>cancel event</a>.
:   <dfn lt="remove event">remove</dfn>
::  Queued whenever an animation is automatically removed.
    See [[#replacing-animations]].

Animation effects {#animation-effects}
----------------------------------------

An <dfn>animation effect</dfn> is an abstract term referring to an item in
the timing hierarchy.

<h4 id="animation-effects-and-animations">Relationship between animation effects
  and animations</h4>

The <a>associated effect</a> of an <a>animation</a>, if set, is a type of
<a>animation effect</a>.
The <a>associated effect</a> of an <a>animation</a> is said to be <dfn
lt="associated with an animation">associated</dfn> with that animation.
At a given moment, an <a>animation effect</a> can be <a
lt="associated with an animation">associated</a> with at most one
<a>animation</a>.

An <a>animation effect</a>, <var>effect</var>, is <dfn>associated with
a timeline</dfn>, <var>timeline</var>, if <var>effect</var> is
<a>associated with an animation</a> which, in turn, is associated with
<var>timeline</var>.

### Types of animation effects ### {#types-of-animation-effects}

This specification defines a single type of <a>animation effect</a>:
<a>keyframe effects</a>.
Subsequent levels of this specification will define further types of
<a>animation effects</a>.

All types of <a>animation effects</a> define a number of common
properties which are described in the following sections.

### The active interval ### {#the-active-interval}

<div class="informative-bg">

The period that an <a>animation effect</a> is scheduled to run is
called its <a>active interval</a>.
Each <a>animation effect</a> has only one such interval.

The lower bound of the <a>active interval</a> typically corresponds
to the [=start time=] of the <a>animation</a>
associated with this <a>animation effect</a> but may be shifted by a
<a>start delay</a> on the <a>animation effect</a>.

The upper bound of the interval is determined by the <a>active
duration</a>.

The relationship between the [=start time=], <a>start
delay</a>, and <a>active duration</a> is illustrated below.

<figure>
  <img src="img/active-interval-examples.svg" width="600"
      alt="Examples of the effect of the start delay on the endpoints
          of the active interval">
  <figcaption>
    Examples of the effect of the <a>start delay</a> on the endpoints of
    the <a>active interval</a>.<br>
    (a) An animation effect with no delay; the [=start time=] and beginning of
    the <a>active interval</a> are coincident.<br>
    (b) An animation effect with a positive delay; the beginning of the
    <a>active interval</a> is deferred by the delay.<br>
    (c) An animation effect with a negative delay; the beginning of the
    <a>active interval</a> is brought forward by the delay.
  </figcaption>
</figure>

An <a>end delay</a> may also be specified but is primarily only of
use when sequencing animations.

</div>

<a>Animation effects</a> define an <dfn>active interval</dfn> which is
the period of time during which the effect is scheduled to produce its
effect with the exception of <a>fill modes</a> which apply outside the
<a>active interval</a>.

The lower bound of the <a>active interval</a> is defined by the
<a>start delay</a>.

The <dfn>start delay</dfn> of an <a>animation effect</a> is a signed offset
from the [=start time=] of the <a>animation</a>
with which the animation effect is associated.

The length of the <a>active interval</a> is called the <a>active
duration</a>, the calculation of which is defined in
[[#calculating-the-active-duration]].

Similar to the <a>start delay</a>, an <a>animation effect</a> also has
an <dfn>end delay</dfn> which is primarily of use when sequencing animations
based on the <a>end time</a> of another <a>animation effect</a>.
Although this is typically only useful in combination with sequence effects
which are introduced in a subsequent level of this specification, it is included
here for the purpose of representing the <a
href="https://www.w3.org/TR/SVG/animate.html#MinAttribute"><code>min</code></a>
attribute in SVG ([[SVG11]], Chapter 19).

The <dfn>end time</dfn> of an <a>animation effect</a> is
the result of evaluating <code>max(<a>start delay</a> + <a>active
duration</a> + <a>end delay</a>, 0)</code>.

### Local time ### {#local-time-section}

The <dfn>local time</dfn> of an <a>animation effect</a> at a given
moment is based on the first matching condition from the following:

<div class='switch'>

:   If the <a>animation effect</a> is <a>associated with an animation</a>,
::  the local time is the <a>current time</a> of the
    <a>animation</a>.
:   Otherwise,
::  the local time is <a>unresolved</a>.

</div>

<h4 id="animation-effect-phases-and-states">Animation effect phases and
states</h4>

<div class="informative-bg"><em>This section is non-normative</em>

At a given moment, an <a>animation effect</a> may be in one of three
possible <em>phases</em>.
If an <a>animation effect</a> has an <a>unresolved</a> <a>local
time</a> it will not be in any phase.

The different phases are illustrated below.

<figure>
  <img src="img/animation-effect-phases-and-states.svg" width="700"
      alt="An example of the different phases and states used to
          describe an animation effect.">
  <figcaption>
    An example of the different phases and states used to describe
    an <a>animation effect</a>.
  </figcaption>
</figure>

The phases are as follows:

:   <a>before phase</a>
::  The <a>animation effect</a>'s <a>local time</a> falls before the
    effect's <a>active interval</a> and <a>end time</a>, <em>or</em>
    occurs during the range when a negative <a>start delay</a> is in
    effect.
:   <a>active phase</a>
::  The <a>animation effect</a>'s <a>local time</a> falls inside the
    effect's <a>active interval</a> and outside the range of any
    negative <a>start delay</a> or negative <a>end delay</a>.
:   <a>after phase</a>
::  The <a>animation effect</a>'s <a>local time</a> falls after the
    effect's <a>active interval</a> or after the <a>end time</a> if that
    comes first (due to a negative <a>end delay</a>), but <em>not</em>
    during the range when a negative <a>start delay</a> is in effect.

In addition to these phases, an <a>animation effect</a> may also be
described as being in one of several overlapping <em>states</em>.
These states are only established for the duration of a single
[=animation frame=] and are primarily a convenience for describing stative parts
of the model.

These states and their useage within the model are summarized as
follows:

:   <a>in play</a>
::  Corresponds to an <a>animation effect</a> whose <a>active time</a>
    is changing on each frame.

:   <a>current</a>
::  Corresponds to an <a>animation effect</a> that is either <a>in
    play</a> or may become <a>in play</a> in the future based on its
    [=animation=]'s current [=playback rate=].

:   <a>in effect</a>
::  Corresponds to an <a>animation effect</a> that has a resolved
    <a>active time</a>.
    This occurs when either the <a>animation effect</a> is in its
    <a>active phase</a> or outside the <a>active phase</a> but at
    a time where the effect's <a>fill mode</a> (see [[#fill-behavior]])
    causes its <a>active time</a> to be resolved.
    Only <a>in effect</a> <a>animation effects</a> apply
    a result to their target.

The normative definition of each of these states follows.

</div>

Determining the phase of an <a>animation effect</a> requires the following
definitions:

:   <dfn>animation direction</dfn>
::  &lsquo;backwards&rsquo; if the effect is <a>associated with an
    animation</a> <em>and</em> the associated <a>animation</a>'s
    [=playback rate=] is less than zero;
    in all other cases, the <a>animation direction</a> is
    &lsquo;forwards&rsquo;.
:   <dfn>before-active boundary time</dfn>
::  <code>max(min(<a>start delay</a>, <a>end time</a>), 0)</code>
:   <dfn>active-after boundary time</dfn>
::  <code>max(min(<a>start delay</a> + <a>active duration</a>,
                  <a>end time</a>), 0)</code>

An <a>animation effect</a> is in the <dfn>before phase</dfn> if the
animation effect's <a>local time</a> is not <a>unresolved</a> and
<em>either</em> of the following conditions are met:

1.  the <a>local time</a> is less than the <a>before-active boundary time</a>,
    <em>or</em>
1.  the <a>animation direction</a> is &lsquo;backwards&rsquo; and the <a>local
    time</a> is equal to the <a>before-active boundary time</a>.

An <a>animation effect</a> is in the <dfn>after phase</dfn> if the
animation effect's <a>local time</a> is not <a>unresolved</a> and
<em>either</em> of the following conditions are met:

1.  the <a>local time</a> is greater than the <a>active-after boundary
    time</a>, <em>or</em>
1.  the <a>animation direction</a> is &lsquo;forwards&rsquo; and the <a>local
    time</a> is equal to the <a>active-after boundary time</a>.

An <a>animation effect</a> is in the <dfn>active phase</dfn> if the
animation effect's <a>local time</a> is not <a>unresolved</a> and it is
not in either the <a>before phase</a> nor the <a>after phase</a>.

Furthermore, it is often convenient to refer to the case when an animation
effect is in none of the above phases as being in the <dfn>idle phase</dfn>.

An <a>animation effect</a> is <dfn>in play</dfn> if <em>all</em>
of the following conditions are met:

1.  the <a>animation effect</a> is in the <a>active phase</a>, and
2.  the <a>animation effect</a> is <a>associated with an animation</a> that is not
    <a lt="finished play state">finished</a>.

An <a>animation effect</a> is <dfn>current</dfn> if <em>any</em>
of the following conditions are true:

*   the [=animation effect=] is [=in play=], or
*   the [=animation effect=] is [=associated with an animation=] with
    a [=playback rate=] &gt; 0 and
    the [=animation effect=] is in the [=before phase=], or
*   the [=animation effect=] is [=associated with an animation=] with
    a [=playback rate=] &lt; 0 and
    the [=animation effect=] is in the [=after phase=].

An animation effect is <dfn>in effect</dfn> if its <a>active time</a>, as
calculated according to the procedure in [[#calculating-the-active-time]],
is <em>not</em> <a>unresolved</a>.

Fill behavior {#fill-behavior}
----------------------------------------

The effect of an <a>animation effect</a> when it is not <a>in play</a> is
determined by its <dfn>fill mode</dfn>.

The possible <a>fill modes</a> are:

*   none,
*   forwards,
*   backwards, and
*   both.

The normative definition of these modes is incorporated in the
calculation of the <a>active time</a> in [[#calculating-the-active-time]].

<div class=advisement>
<p>
Authors are discouraged from using [=fill modes=] to produce animations whose
effect is applied indefinitely.
[=Fill modes=] were introduced in order to represent the 'animation-fill-mode'
property defined by CSS animations [[CSS-ANIMATIONS-1]].
However, they produce situations where animation state would be accumulated
indefinitely necessitating the automatic removal of animations defined in
[[#replacing-animations]].
Furthermore, indefinitely filling animations can cause changes to specified
style to be ineffective long after all animations have completed since the
animation style takes precedence in the CSS cascade [[css-cascade-3]].
</p>

<p>
Where possible, authors should prefer to set the final state of the animation
directly in specified style.
This can be achieved by waiting for the animation to finish and then updating
the style as illustrated below:
</p>

<div class="example"><pre class="lang-javascript">
// In the first frame after the following animation finishes, the callback for
// the `finished` promise will run BEFORE style is updated and hence will NOT
// flicker.
elem.animate({ transform: 'translateY(100px)' }, 200).finished(() => {
  elem.style.transform = 'translateY(100px)';
});
</pre></div>

<p>
Alternatively, the author may set the specified style at the start of the
animation and then animate <em>from</em> the original value
as illustrated below:
</p>

<div class="example"><pre class="lang-javascript">
elem.style.transform = 'translateY(100px)';
elem.animate({ transform: 'none', offset: 0 }, 200);
</pre></div>

Complex effects involving layering many animations on top of one another may
require temporary use of forwards fill modes to capture the final value of an
animation before canceling it.
For example:

<div class="example"><pre class="lang-javascript">
elem.addEventListener('click', async evt => {
  const animation = elem.animate(
    { transform: `translate(${evt.clientX}px, ${evt.clientY}px)` },
    { duration: 800, fill: 'forwards' }
  );
  await animation.finished;
  // commitStyles will record the style up to and including `animation` and
  // update elem's specified style with the result.
  animation.commitStyles();
  animation.cancel();
});
</pre></div>
</div>

### Fill modes ### {#fill-modes}

<div class='informative-bg'><em>This section is non-normative</em>

The effect of each <a>fill mode</a> is as follows:

:   none
::  The animation effect has no effect when it is not <a>in play</a>.
:   forwards
::  When the animation effect is in the <a>after phase</a>,
    the animation effect will produce the same <a>iteration progress</a>
    value as the last moment it is scheduled to be <a>in play</a>.

    For all other times that the animation effect is not <a>in play</a>,
    it will have no effect.
:   backwards
::  When the animation effect is in the <a>before phase</a>,
    the animation effect will produce the same <a>iteration progress</a>
    value as the earliest moment that it is scheduled to be <a>in play</a>.

    For all other times that the animation effect is not <a>in play</a>,
    it will have no effect.
:   both
::  When the animation effect
    is in its <a>before phase</a>,
    <span class="prop-value">backwards</span> fill behavior is used.

    When the animation effect
    is in its <a>after phase</a>,
    <span class="prop-value">forwards</span> fill behavior is used.

Some examples of the these fill modes are illustrated below.

<figure>
  <img src="img/animation-state-and-fill-behavior.svg" width="600"
    alt="Examples of various fill modes and the states produced.">
  <figcaption>
    Examples of various fill modes and the states produced.<br>
    (a) fill mode &lsquo;none&rsquo;. The animation effect has no effect
        outside its active phase.<br>
    (b) fill mode &lsquo;forwards&rsquo;. After the active phase has
        finished, the <a>iteration progress</a> value continues to maintain
        a fill value.<br>
    (c) fill mode &lsquo;backwards&rsquo;. The animation effect produces
        a fill value until the start of the active phase.<br>
    (d) fill mode &lsquo;both&rsquo;. Both before and after the active
        phase the animation effect produces a fill value.
  </figcaption>
</figure>

Note: setting a fill mode has no bearing on the endpoints of the
    <a>active interval</a> or the boundaries between <a
    href="#animation-effect-phases-and-states">phases</a>.
    However, the fill mode <em>does</em> have an effect on various other
    properties of the timing model since the <a>active time</a> of an
    animation effect is only defined (that is, not <a>unresolved</a>) inside
    the <a>active phase</a> <em>or</em> when a fill is applied.

</div>

Repeating {#repeating}
----------------------------------------

### Iteration intervals ### {#iteration-intervals}

It is possible to specify that an animation effect should repeat
a fixed number of times or indefinitely.
This repetition occurs <em>within</em> the <a>active interval</a>.
The span of time during which a single repetition takes place is
called an <dfn>iteration interval</dfn>.

Unlike the <a>active interval</a>, an animation effect can have multiple
<a>iteration intervals</a> although typically only the interval
corresponding to the <a>current iteration</a> is of interest.

The length of a single iteration is called the <dfn>iteration
duration</dfn>.
The initial <a>iteration duration</a> of an animation effect is zero.

<div class="informative-bg"><em>This section is non-normative</em>

Comparing the <a>iteration duration</a> and the <a>active
duration</a> we have:

:   Iteration duration
::  The time taken for a single iteration of the animation effect to
    complete.
:   Active duration
::  The time taken for the entire animation effect to complete,
    including repetitions.
    This may be longer or shorter than the <a>iteration duration</a>.

The relationship between the <a>iteration duration</a> and <a>active
duration</a> is illustrated below.

<figure>
  <img src="img/iteration-intervals.svg" width="600"
      alt="Comparison of the iteration duration and active time.">
  <figcaption>
    A comparison of the <a>iteration duration</a> and <a>active
    duration</a> of an animation effect with an <a>iteration count</a> of
    2.5.
    Note that the <a>iteration duration</a> for the final iteration does
    not change, it is simply cut-off by the <a>active duration</a>.
  </figcaption>
</figure>

</div>

### Controlling iteration ### {#controlling-iteration}

The number of times an <a>animation effect</a> repeats is called its
<dfn>iteration count</dfn>.
The <a>iteration count</a> is a real number greater than or equal to
zero.
The <a>iteration count</a> may also be positive infinity to represent
that the <a>animation effect</a> repeats indefinitely.

In addition to the <a>iteration count</a>, <a>animation effects</a> also
have an <dfn>iteration start</dfn> property which specifies an offset
into the series of iterations at which the <a>animation effect</a>
should begin.
The <a>iteration start</a> is a finite real number greater than or
equal to zero.

The behavior of these parameters is defined in the calculations in
[[#core-animation-effect-calculations]].

<div class="informative-bg"><em>This section is non-normative</em>

The effect of the <a>iteration count</a> and <a>iteration start</a>
parameters is illustrated below.

<figure>
  <img src="img/iteration-count-and-start.svg" width="600"
    alt="The effect of the iteration count and iteration start parameters">
  <figcaption>
    The effect of the <a>iteration count</a> and <a>iteration start</a>
    parameters.<br>
    In the first case the <a>iteration count</a> is 2.5 resulting in the
    third iteration being cut-off half way through its <a>iteration
    interval</a>.<br>
    The second case is the same but with an <a>iteration start</a> of
    0.5.
    This causes the <a>animation effect</a> to begin half way through the
    first iteration.
  </figcaption>
</figure>

Unlike the <a>iteration count</a> parameter, the <a>iteration
start</a> parameter does not effect the length of the <a>active
duration</a>.

Note that values of <a>iteration start</a> greater than or equal to
one are generally not useful unless used in combination with an
<a>animation effect</a> that has an <a>iteration composite
operation</a> of
<a lt="iteration composite operation accumulate">accumulate</a>.

</div>

### Iteration time space ### {#iteration-time-space}

<div class="informative-bg"><em>This section is non-normative</em>

In Web Animations all times are relative to some point of reference.
These different points of reference produce different <em>time
spaces</em>.

This can be compared to coordinate spaces as used in computer
graphics.
The zero time of a time space is analogous to the origin of
a coordinate space.

We can describe animations that repeat as establishing a new time space
each time the animation repeats: the <em>iteration time space</em>.

<em>Iteration time space</em> is a time space whose zero time is the
beginning of an animation effect's current iteration.

Within the Web Animations model we also refer to <a>active
time</a> which is a time relative to the beginning of the active
interval.
This time space, however, is internal to the model and not exposed in
the programming interface or in markup.


These time spaces are illustrated below.

<figure>
  <img src="img/time-spaces.svg" width="600"
    alt="A comparison of local time, active time, and iteration time.">
  <figcaption>
    A comparison of local time, active time, and iteration time for an
    animation with a iteration duration of 1s and an iteration count of
    2.5.
  </figcaption>
</figure>

Note: While the time spaces themselves are not bounded, Web
    Animations defines <a>active time</a> and the <a>iteration
    progress</a> such that they are clamped to a set range as shown in the
    diagram.
    For example, whilst a time of -1 second is a valid time in
    <em>active time space</em>, the procedure for calculating the
    <a>active time</a> defined in [[#calculating-the-active-time]] will
    never return a negative value.

In addition to these time spaces we can also refer to the
<em>document time space</em> which is time space of the <a>time
values</a> of the <a>default document timeline</a> of the
{{Document}} of the <a>current global object</a>.

</div>

### Interval timing ### {#interval-timing}

<div class="informative-bg"><em>This section is non-normative</em>

When an animation effect repeats we must define the behavior at the
iteration boundaries.
For this, and indeed for all interval timing, Web Animations uses an
endpoint-exclusive timing model.
This means that whilst the begin time of an interval
is included in the interval, the end time time is not.
In interval notation this can written <code>[begin, end)</code>.
This model provides sensible behavior when intervals are repeated and
sequenced since there is no overlap between the intervals.


In the examples below, for the repeated effect, at local time 1s,
the iteration time is 0.
For the sequenced animations, at timeline time 1s, only animation B's
<a>associated effect</a> will be <a>in play</a>; there is no overlap.

<figure>
  <img src="img/endpoint-exclusive-timing.svg" width="600"
    alt="Illustration of end-point exclusive timing.">
  <figcaption>
    Illustration of end-point exclusive timing. For both repeated and
    sequenced animation effects there is no overlap at the boundaries
    between intervals.
  </figcaption>
</figure>

An exception to this behavior is that when performing a <a
href="#fill-behavior">fill</a>, if the fill begins at an
interval endpoint, the endpoint is used.
This behavior falls out of the algorithm given in <a
href="#calculating-the-simple-iteration-progress"
section></a> and is illustrated below.

<figure>
  <img src="img/endpoint-exclusive-timing-and-fill.svg" width="600"
    alt="Effect of iterations and fill on iteration time.">
  <figcaption>
    After one iteration, the <a>iteration progress</a> is 0, but after two
    iterations (and there onwards), the <a>iteration progress</a> is 1
    due to the special behavior defined when an animation effect fills.
  </figcaption>
</figure>

</div>

Core animation effect calculations {#core-animation-effect-calculations}
----------------------------------------

### Overview ### {#animation-effect-calculations-overview}

<div class="informative-bg"><em>This section is non-normative</em>

At the core of the Web Animations timing model is the process that
takes a <a>local time</a> value and converts it to an <a>iteration progress</a>.

The first step in this process is to calculate the bounds of the
<a>active interval</a> which is determined by the <a>active
duration</a>.

This process is illustrated below.

<figure>
  <img src="img/active-duration-calculation.svg" width="650"
    alt="Calculation of the active duration.">
  <figcaption>
    Calculation of the <a>active duration</a> is based on
    multiplying the <a>iteration duration</a> by the
    <a>iteration count</a>.
  </figcaption>
</figure>
<p>
  The process for calculating the <a>active duration</a> is normatively
  defined in <a href="#calculating-the-active-duration"
  section></a>.
</p>
<p>
  Having established the <a>active duration</a>, the process for
  transforming an <a>animation effect</a>'s <a>local time</a> into its
  <a>transformed progress</a> (<a>iteration progress</a>) is illustrated below.
</p>
<figure>
  <img src="img/time-calculations.svg" width="650"
    alt="An overview of timing model calculations.">
  <figcaption>
    An overview of timing model calculations.<br>
    (1) The <a>local time</a> is determined from the associated
    <a>animation</a>.<br>
    (2) The <a>local time</a> is converted into an <a>active time</a> by
    incorporating the <a>start
    delay</a>.<br>
    (3) The <a>active time</a> is divided by the <a>iteration duration</a>
    incorporating also the <a>iteration start</a>
    property to produce the <a>overall progress</a>.<br>
    (4) The <a>overall progress</a> time is then converted to an offset
    within a single iteration: the <a>simple iteration progress</a>.<br>
    (5) The <a>simple iteration progress</a> is converted into a <a>directed
    progress</a> by incorporating the <a>playback direction</a>.<br>
    (6) Finally, a timing function is applied to the <a>directed
    progress</a> to produce the <a>transformed progress</a>.
  </figcaption>
</figure>

The first step, calculating the <a>local time</a> is described in
[[#local-time-section]].
Steps 2 to 4 in the diagram are described in the following sections.
Steps 5 and 6 are described in [[#calculating-the-directed-progress]] and
[[#calculating-the-transformed-progress]] respectively.

</div>


### Calculating the active duration ### {#calculating-the-active-duration}

The <a>active duration</a> is calculated as follows:

<blockquote>
  <dfn>active duration</dfn> =
    <code><a>iteration duration</a> &times;
          <a>iteration count</a></code>
    <p>
      If either the <a>iteration duration</a> or <a>iteration count</a>
      are zero, the <a>active duration</a>
      is zero.
    </p>
    <p class="note">
      This clarification is needed since the result of infinity
      multiplied by zero is undefined according to IEEE 754-2008.
    </p>
</blockquote>

### Transforming the local time ### {#transforming-the-local-time}

#### Calculating the active time #### {#calculating-the-active-time}

The <dfn>active time</dfn> is based on the <a>local time</a>
and <a>start delay</a>.
However, it is only defined when the <a>animation effect</a> should
produce an output and hence depends on its <a>fill mode</a> and
phase as follows,

<div class="switch">

:   If the animation effect is in the <a>before phase</a>,
::  The result depends on the first matching condition from the
    following,

    <div class="switch">

    :   If the <a>fill mode</a> is <span
        class="prop-mode">backwards</span> or <span
        class="prop-mode">both</span>,
    ::  Return the result of evaluating
        <code>max(<a>local time</a> - <a>start delay</a>, 0)</code>.
    :   Otherwise,
    ::  Return an <a>unresolved</a> <a>time value</a>.

    </div>

:   If the animation effect is in the <a>active phase</a>,
::  Return the result of evaluating
    <code><a>local time</a> - <a>start delay</a></code>.

:   If the animation effect is in the <a>after phase</a>,
::  The result depends on the first matching condition from the
    following,

    <div class="switch">

    :   If the <a>fill mode</a> is <span
        class="prop-mode">forwards</span> or <span
        class="prop-mode">both</span>,
    ::  Return the result of evaluating
        <code>max(min(<a>local time</a> - <a>start delay</a>,
                      <a>active duration</a>),
                  0)</code>.
    :   Otherwise,
    ::  Return an <a>unresolved</a> <a>time value</a>.

    </div>

:   Otherwise (the <a>local time</a> is <a>unresolved</a>),
::  Return an <a>unresolved</a> <a>time value</a>.

</div>

#### Calculating the overall progress #### {#calculating-the-overall-progress}

The <dfn>overall progress</dfn> describes the number of iterations that
have completed (including partial iterations) and is defined as follows:

1.  If the <a>active time</a> is <a>unresolved</a>, return <a>unresolved</a>.

1.  Calculate an initial value for <var>overall progress</var> based on the
    first matching condition from below,

    <div class="switch">

    :   If the <a>iteration duration</a> is zero,
    ::  If the animation effect is in the <a>before phase</a>, let
        <var>overall progress</var> be zero, otherwise, let it be equal
        to the <a>iteration count</a>.
    :   Otherwise,
    ::  Let <var>overall progress</var> be the result of calculating
        <code><a>active time</a> / <a>iteration duration</a></code>.

    </div>

1.  Return the result of calculating <code><var>overall
    progress</var> + <a>iteration start</a></code>.


#### Calculating the simple iteration progress #### {#calculating-the-simple-iteration-progress}

The <dfn>simple iteration progress</dfn> is a fraction of the progress
through the current iteration that ignores transformations to the time
introduced by the <a>playback direction</a> or <a>timing functions</a>
applied to the effect, and is calculated as follows:

1.  If the <a>overall progress</a> is <a>unresolved</a>,
    return <a>unresolved</a>.

1.  If <a>overall progress</a> is infinity, let the <var>simple iteration
    progress</var> be
    <code><a>iteration start</a> % 1.0</code>,
    otherwise, let the <var>simple iteration progress</var> be
    <code><a>overall progress</a> % 1.0</code>.

1.  If <em>all</em> of the following conditions are true,

    * the <var>simple iteration progress</var> calculated above is zero,
        <em>and</em>
    * the animation effect is in the <a>active phase</a> <em>or</em> the
        <a>after phase</a>, <em>and</em>
    * the <a>active time</a> is equal to the <a>active duration</a>,
        <em>and</em>
    * the <a>iteration count</a> is <em>not</em> equal to zero.

    let the <var>simple iteration progress</var> be 1.0.

    <div class="note">

      The above step implements the behavior that when an animation's
      active interval ends precisely at the end of an iteration, it fills by
      holding the endpoint of the final iteration rather than the start of the
      next iteration.

      The final condition prevents this from applying when we never played
      any iterations of the animation to begin with because the
      <a>iteration count</a> was zero.

    </div>

1.  Return <var>simple iteration progress</var>.


### Calculating the current iteration ### {#calculating-the-current-iteration}

The <dfn>current iteration</dfn> can be calculated using the
following steps:

1.  If the <a>active time</a> is <a>unresolved</a>, return
    <a>unresolved</a>.

1.  If the animation effect is in the <a>after phase</a> <em>and</em>
    the <a>iteration count</a> is infinity, return infinity.

1.  If the <a>simple iteration progress</a> is 1.0,
    return <code>floor(<a>overall progress</a>) - 1</code>.

1.  Otherwise, return <code>floor(<a>overall progress</a>)</code>.


Direction control {#direction-control}
----------------------------------------

<a>Animation effects</a> may also be configured to run iterations in
alternative directions using direction control.
For this purpose, <a>animation effects</a> have a <dfn>playback
direction</dfn> parameter which takes one of the following values:

*   normal,
*   reverse,
*   alternate, or
*   alternate-reverse.

The semantics of these values are incorporated into the calculation of
the <a>directed progress</a> which follows.

<div class="informative-bg"><em>This section is non-normative</em>

A non-normative definition of these values is as follows:

:   normal
::  All iterations are played as specified.

:   reverse
::  All iterations are played in the reverse direction from the way
    they are specified.

:   alternate
::  Even iterations are played as specified, odd iterations are played
    in the reverse direction from the way they are specified.

:   alternate-reverse
::  Even iterations are played in the reverse direction from the way
    they are specified, odd iterations are played as specified.

</div>

### Calculating the directed progress ### {#calculating-the-directed-progress}

The <dfn>directed progress</dfn> is calculated from the
<a>simple iteration progress</a> using the following steps:

1.  If the <a>simple iteration progress</a> is <a>unresolved</a>, return
    <a>unresolved</a>.

1.  Calculate the <var>current direction</var> using the first
    matching condition from the following list:
    <div class="switch">

      :   If <a>playback direction</a> is <code>normal</code>,
      ::  Let the <var>current direction</var> be forwards.

      :   If <a>playback direction</a> is <code>reverse</code>,
      ::  Let the <var>current direction</var> be reverse.

      :   Otherwise,
      ::

          1.  Let <var>d</var> be the <a>current iteration</a>.

          1.  If <a>playback direction</a> is
              <code>alternate-reverse</code> increment
              <var>d</var> by 1.

          1.  If <code><var>d</var> % 2 == 0</code>, let the
              <var>current direction</var> be forwards, otherwise let
              the <var>current direction</var> be reverse.
              If <var>d</var> is infinity, let the <var>current direction</var>
              be forwards.

    </div>

1.  If the <var>current direction</var> is forwards then return
    the <a>simple iteration progress</a>.

    Otherwise, return <code>1.0 - <a>simple iteration progress</a></code>.

Time transformations {#time-transformations}
----------------------------------------

It is often desirable to control the rate at which an <a>animation
effect</a> progresses.
For example, easing the rate of animation can create a sense of
momentum and produce a more natural effect.
The CSS Easing Functions Module [[!CSS-EASING-1]] defines <a>timing
functions</a> for this purpose.

<a>Animation effects</a> have one <a>timing function</a> associated with
them.
The default <a>timing function</a> is the <a>linear timing
function</a>.

### Calculating the transformed progress ### {#calculating-the-transformed-progress}

The <dfn export>transformed progress</dfn> is calculated from the
<a>directed progress</a> using the following steps:

1.  If the <a>directed progress</a> is <a>unresolved</a>,
    return <a>unresolved</a>.

1.  Calculate the value of the <var>before flag</var> as follows:

    1.  Determine the <var>current direction</var> using the procedure
        defined in <a href="#calculating-the-directed-progress"
        section></a>.
    1.  If the <var>current direction</var> is <span
        class="prop-value">forwards</span>,
        let <var>going forwards</var> be true, otherwise it is false.
    1.  The <var>before flag</var> is set if the animation effect is
        in the <a>before phase</a> and <var>going forwards</var> is true; or if
        the animation effect is in the <a>after phase</a> and <var>going
        forwards</var> is false.

1.  Return the result of evaluating the <a>animation effect</a>'s <a>timing
    function</a> passing <a>directed progress</a> as the <a
    spec=css-easing>input progress value</a> and <var>before flag</var> as the
    <a spec=css-easing>before flag</a>.

The iteration progress {#the-iteration-progress}
----------------------------------------

The <dfn>iteration progress</dfn> of an <a>animation effect</a> is simply
its <a>transformed progress</a>.


<!-- End of timing model -->



Animation model {#animation-model}
=======================================

<div class='informative-bg'><em>This section is non-normative</em>

For some kinds of <a>animation effects</a>, the Web Animations <em>animation
model</em> takes the <a>iteration progress</a> and <a>current iteration</a>
values produced by the <em>timing model</em> and uses them to calculate
a corresponding output.

The output of each such animation effect is then combined with
that of others using an <a>effect stack</a> before being
applied to the target properties (see [[#combining-effects]]).

</div>

Introduction {#introduction-to-the-animation-model}
----------------------------------------

An <a>animation effect</a> has zero or more associated properties that
it affects in response to changes to its timing output. These properties
are referred to as the effect's <dfn lt="target property">target
properties</dfn>.

Given an <a>iteration progress</a>, a <a>current iteration</a>, and an
<a>underlying value</a>, an <a>animation effect</a> produces
an <dfn>effect value</dfn> for each <a>animatable</a> <a>target property</a>
by applying the procedures from the <a>animation type</a> appropriate to the
property.

Animating properties {#animating-properties}
----------------------------------------

Unless otherwise specified, all CSS properties are
<dfn id="concept-animatable">animatable</dfn>.
How property values combine is defined by
the <dfn export>Animation type</dfn> line
in each property's property definition table:

<dl export>
  <dt><dfn>not animatable</dfn>
  <dd>
    The property is not animatable.
    It is not processed when listed in an animation keyframe,
    and is not affected by transitions.

    Note: Properties are typically excluded from animation
    because animating them would create excessive complications.
    For example, properties defining animation parameters are <a>not animatable</a>
    since doing so would create complex recursive behavior.

    Note: An <a>animation effect</a> that targets only properties
    that are <a>not animatable</a> will still exhibit
    the usual behavior for an <a>animation effect</a>
    such as firing events and
    delaying the fulfilment of the <a>animation</a>'s
    <a>current finished promise</a>.

  <dt><dfn>discrete</dfn>
  <dd>
    The property's values cannot be meaningfully combined,
    thus it is <a>not additive</a> and <a>interpolation</a> swaps
    from <var ignore>V<sub>a</sub></var> to <var ignore>V<sub>b</sub></var>
    at 50% (<var ignore>p=0.5</var>),
    i.e.
    <div role="math" class="formula">
      <math xmlns="http://www.w3.org/1998/Math/MathML">
        <msub><mi>V</mi><mn>result</mn></msub><mo>=</mo>
        <mrow>
          <mfenced open="{" close="">
            <mtable>
              <mtr>
                <mtd columnalign="left">
                  <msub><mi>V</mi><mn>start</mn></msub>
                </mtd>
                <mtd columnalign="left">
                  <mtext>if&nbsp;</mtext><mi>p</mi>
                  <mo>&lt;</mo><mn>0.5</mn>
                </mtd>
              </mtr>
              <mtr>
                <mtd columnalign="left">
                  <msub><mi>V</mi><mn>end</mn></msub>
                </mtd>
                <mtd columnalign="left">
                  <mtext>if&nbsp;</mtext><mi>p</mi>
                  <mo>&ge;</mo><mn>0.5</mn>
                </mtd>
              </mtr>
            </mtable>
          </mfenced>
        </mrow>
      </math>
    </div>

  <dt><dfn>by computed value</dfn>
  <dd>
    Corresponding individual components of the <a>computed values</a>
    are combined (interpolated, added, or accumulated)
    using the indicated procedure for that value type
    (see [[css-values-4#combining-values]]).
    If the number of components or the types of corresponding components
    do not match,
    or if any component value uses [=discrete=] animation
    and the two corresponding values do not match,
    then the property values combine as [=discrete=].

  <dt><dfn>repeatable list</dfn>
  <dd>
    Same as <a>by computed value</a>
    except that if the two lists have differing numbers of items,
    they are first repeated to the least common multiple number of items.
    Each item is then combined <a>by computed value</a>.
    If a pair of values cannot be combined
    or if any component value uses [=discrete=] animation,
    then the property values combine as [=discrete=].

    Note: The repeatable list concept ensures that
    a list that is conceptually repeated to a certain length
    (as 'background-origin' is repeated to the length of
    the 'background-image' list)
    or repeated infinitely
    will smoothly transition between any values,
    and so that the computed value
    will properly represent the result
    (and potentially be inherited correctly).

  <dt>(See prose)
  <dd>
    Some properties have specific interpolation behavior not covered by the
    above cases;
    in this case the animation behavior will be specified explicitly
    for that property.
</dl>

The [=animation type=] of properties that do not yet include
an [=Animation type=] line in their property definition,
is defined in [[#animation-types]].

### Custom Properties ### {#custom-properties}

For <a>custom properties</a> registered
using the {{CSS/registerProperty()}} method for the <a>current global object</a>,
the <a>animation type</a> is <a>by computed value</a>,
derived from the type used to define the property's {{PropertyDescriptor/syntax}}.
Where there is no <a>computed value</a> type that corresponds
to the property's specified {{PropertyDescriptor/syntax}}
(e.g. when the syntax is "*")
or when the <a>custom property</a> is not registered,
the <a>animation type</a> is <a>discrete</a>.


Keyframe effects {#keyframe-effects}
----------------------------------------

<dfn lt="keyframe effect">Keyframe effects</dfn> are a kind of [=animation
effect=] that use the output of the timing model to update CSS properties of
an element or [=pseudo-element=] (such as `::before` or `::after` [[!select]])
referred to as the <dfn>effect target</dfn>.

In order for the [=effect target=] to have a well-defined lifecycle,
it is represented as an {{Element}} known as the <dfn>target element</dfn>
and a [=pseudo-element=] selector knows as the <dfn>target pseudo-selector</dfn>.
If the [=effect target=] is an {{Element}}, the [=target element=] is that
element and the [=target pseudo-selector=] is `null`.
If the [=effect target=] is a [=pseudo-element=], the [=target element=] is
its [=originating element=] and the [=target pseudo-selector=] is as required
to specify that particular [=pseudo-element=].

### Keyframes ### {#keyframes-section}

The <a>effect values</a> for a <a>keyframe effect</a>
are calculated by interpolating between a series of property values
positioned at fractional offsets.
Each set of property values indexed by an offset is called
a <dfn>keyframe</dfn>.

The <dfn lt="keyframe offset">offset of a keyframe</dfn> is a value
in the range [0, 1] or the special value null.
The list of <a>keyframes</a> for a <a>keyframe effect</a> must be
<dfn>loosely sorted by offset</dfn> which means that for each
<a>keyframe</a> in the list that has a <a>keyframe offset</a> that is
not null, the offset is greater than or equal to the offset of the
previous <a>keyframe</a> in the list with a <a>keyframe offset</a> that
is not null, if any.

The behavior when <a>keyframes</a> overlap or have unsupported values
is defined in <a
href="#the-effect-value-of-a-keyframe-animation-effect"
section></a>.

Each keyframe also has a <a>timing function</a> associated with it
that is applied to the period of time between the keyframe on which it
is specified and the <em>next</em> keyframe in the list.
The <a>timing function</a> specified on the last keyframe in the
list is never applied.

Each <a>keyframe</a> may have a <dfn>keyframe-specific composite
operation</dfn> that, if set, is applied to all values specified in that
<a>keyframe</a>.
The possible operations and their meanings are identical to those defined
for the <a>composite operation</a> associated with the <a>keyframe effect</a>
as a whole in [[#effect-composition]].
If the <a>keyframe-specific composite operation</a> for a <a>keyframe</a>
is not set, the <a>composite operation</a> specified for the
<a>keyframe effect</a> as a whole is used for values specified in that keyframe.

### Calculating computed keyframes ### {#calculating-computed-keyframes}

Before calculating the <a>effect value</a> of a <a>keyframe effect</a>,
the property values specified on its <a>keyframes</a> are resolved to
<a>computed values</a>, and the offset to use for any keyframes with a null
<a>keyframe offset</a> is computed. The result of resolving these values is
a set of <dfn>computed keyframes</dfn>.

The calculated <a>keyframe offsets</a> of a set of <a>keyframe</a> that
includes suitable values for each null <a>keyframe offset</a> are referred
to as the <dfn lt="computed keyframe offset">computed keyframe offsets</a>.

To produce <a>computed keyframe offsets</a>, we define a procedure to
<dfn>compute missing keyframe offsets</dfn> that takes a sequence of
<a>keyframes</a>, <var>keyframes</var>, and has the following steps:

1.  For each <a>keyframe</a>, in <var>keyframes</var>,
    let the <a>computed keyframe offset</a> of the <a>keyframe</a>
    be equal to its <a>keyframe offset</a> value.

1.  If <var>keyframes</var> contains more than one
    <a>keyframe</a> and the <a>computed keyframe offset</a> of
    the first <a>keyframe</a> in <var>keyframes</var> is null,
    set the <a>computed keyframe offset</a> of
    the first <a>keyframe</a> to 0.

1.  If the <a>computed keyframe offset</a> of the last <a>keyframe</a> in
    <var>keyframes</var> is null, set its
    <a>computed keyframe offset</a> to 1.

1.  For each pair of <a>keyframes</a> <var>A</var> and <var>B</var>
    where:

    *   <var>A</var> appears before <var>B</var> in
        <var>keyframes</var>, and
    *   <var>A</var> and <var>B</var> have a <a>computed keyframe
        offset</a> that is not null, and
    *   all <a>keyframes</a> between <var>A</var> and <var>B</var>
        have a null <a>computed keyframe offset</a>,

    calculate the <a>computed keyframe offset</a> of
    each <a>keyframe</a> between <var>A</var> and <var>B</var>
    as follows:

    1.  Let <dfn>offset<sub><var>k</var></sub></dfn> be the <a>computed
        keyframe offset</a> of a <a>keyframe</a> <var>k</var>.
    1.  Let <var>n</var> be the number of keyframes <em>between</em> and
        including <var>A</var> and <var>B</var> minus 1.
    1.  Let <var>index</var> refer to the position of
        <var>keyframe</var> in the sequence of keyframes between
        <var>A</var> and <var>B</var> such that the first keyframe
        after <var>A</var> has an <var>index</var> of 1.
    1.  Set the <a>computed keyframe offset</a> of <var>keyframe</var> to
        <a lt="offsetk">offset</a><sub><var>A</var></sub> +
        (<a lt="offsetk">offset</a><sub><var>B</var></sub> &minus;
        <a lt="offsetk">offset</a><sub><var>A</var></sub>)
        &times; <var>index</var> / <var>n</var>.

<a>Computed keyframes</a> are produced using the following procedure.
Note that this procedure is only performed on a <a>keyframe effect</a> having
an <a>effect target</a> for which computed property values can be calculated.

1.  Let <var>computed keyframes</var> be an empty list of <a>keyframes</a>.

1.  For each <var>keyframe</var> in the list of <a>keyframes</a> specified on
    this <a>keyframe effect</a>, perform the following steps:

    1.  Add a new empty <a>keyframe</a>, <var>computed keyframe</var>, to
        <var>computed keyframes</var>.

    1.  For each property specified in <var>keyframe</var>, calculate the
        computed value specified on <var>keyframe</var> using the <a>effect
        target</a> as the context for computing values and add the
        corresponding property and computed value to <var>computed
        keyframe</var>.
        For shorthand properties, add the equivalent longhand properties.
        For logical properties [[!CSS-LOGICAL-1]], add the [=equivalent physical
        properties=] [[!CSS-WRITING-MODES-4]] based on the computed value of
        'writing-mode' and/or 'direction' for the <a>effect target</a>.

        For example, if <var>keyframe</var> has a value of &lsquo;12pt&rsquo;
        for the 'border-width' property, the user agent may produce a computed
        value of &lsquo;16px&rsquo; for each of the longhand properties:
        'border-bottom-width', 'border-left-width', 'border-right-width', and
        'border-top-width'.
        As a result, <var>computed keyframe</var> would <em>not</em> have a
        value for the 'border-width' property, but would instead include
        each of the longhand properties, and each with the computed value,
        &lsquo;16px&rsquo;.

        If conflicts arise when expanding shorthand properties or replacing
        logical properties with physical properties, apply the following rules
        in order until the conflict is resolved:

        1.  Longhand properties override shorthand properties (e.g.
            'border-top-color' overrides 'border-top').
        1.  Shorthand properties with fewer longhand components override those
            with more longhand components (e.g. 'border-top' overrides
            'border-color').
        1.  Physical properties override logical properties.
        1.  For shorthand properties with an equal number of longhand
            components, properties whose IDL name (see the <a>CSS property to
            IDL attribute</a> algorithm [[!CSSOM]]) appears earlier when
            sorted in ascending order by the Unicode codepoints that make up
            each IDL name, override those who appear later.

1.  Apply the procedure to <a>compute missing keyframe offsets</a> to
    <var>computed keyframes</var>.

1.  Return <var>computed keyframes</var>.


<h4 id="the-effect-value-of-a-keyframe-animation-effect">The effect value of
  a keyframe effect</h4>

The <a>effect value</a> of a single property referenced by a <a>keyframe
effect</a> as one of its <a lt="target property">target properties</a>, for a
given <var>iteration progress</var>, <var ignore=''>current iteration</var> and
<var>underlying value</var> is calculated as follows.

1.  If <var>iteration progress</var> is <a>unresolved</a> abort this
    procedure.
1.  Let <var>target property</var> be the longhand property for which the
    <a>effect value</a> is to be calculated.
1.  If <a>animation type</a> of the <var>target property</var> is
    <a>not animatable</a> abort this procedure
    since the effect cannot be applied.
1.  Define the <dfn>neutral value for composition</dfn> as a value
    which, when combined with an <a>underlying value</a> using the <a
    lt="composite operation add">add</a> <a>composite
    operation</a>, produces the <a>underlying value</a>.
1.  Let <var>property-specific keyframes</var> be the result of
    getting the set of <a>computed keyframes</a> for this <a>keyframe
    effect</a>.
1.  Remove any <a>keyframes</a> from <var>property-specific
    keyframes</var> that do not have a property value for
    <var>target property</var>.
1.  If <var>property-specific keyframes</var> is empty, return
    <var>underlying value</var>.
1.  If there is no <a>keyframe</a> in <var>property-specific
    keyframes</var> with a <a>computed keyframe offset</a> of
    0, create a new <a>keyframe</a> with a <a>computed keyframe offset</a> of
    0, a property value set to the <a>neutral value for
    composition</a>, and a <a>composite operation</a> of <a
    lt="composite operation add">add</a>, and prepend it to the
    beginning of <var>property-specific keyframes</var>.
1.  Similarly, if there is no <a>keyframe</a> in
    <var>property-specific keyframes</var> with a <a>computed keyframe
    offset</a> of 1,
    create a new <a>keyframe</a> with a <a>computed keyframe offset</a> of 1,
    a property value set to the <a>neutral value for composition</a>,
    and a <a>composite operation</a> of <a
    lt="composite operation add">add</a>, and append it to the
    end of <var>property-specific keyframes</var>.
1.  Let <var>interval endpoints</var> be an empty sequence of
    keyframes.
1.  Populate <var>interval endpoints</var> by following the steps from
    the first matching condition from below:

    <div class="switch">

    :   If <var>iteration progress</var> &lt; 0 and there is more
        than one <a>keyframe</a> in <var>property-specific
        keyframes</var> with a <a>computed keyframe offset</a> of
        0,
    ::  Add the first <a>keyframe</a> in <var>property-specific
        keyframes</var> to <var>interval endpoints</var>.
    :   If <var>iteration progress</var> &ge; 1 and there is more
        than one <a>keyframe</a> in <var>property-specific
        keyframes</var> with a <a>computed keyframe offset</a> of
        1,
    ::  Add the last <a>keyframe</a> in <var>property-specific
        keyframes</var> to <var>interval endpoints</var>.
    :   Otherwise,
    ::

        1.  Append to <var>interval endpoints</var> the last
            <a>keyframe</a> in <var>property-specific
            keyframes</var> whose <a>computed keyframe offset</a> is less than
            or equal to <var>iteration progress</var> and less than 1.  If
            there is no such <a>keyframe</a> (because, for example,
            the <a>iteration progress</a> is negative), add the last
            <a>keyframe</a> whose <a>computed keyframe offset</a> is 0.
        1.  Append to <var>interval endpoints</var> the next
            <a>keyframe</a> in <var>property-specific keyframes</var>
            after the one added in the previous step.

    </div>

1.  For each <var>keyframe</var> in <var>interval endpoints</var>:

    1.  If <var>keyframe</var> has a <a>composite operation</a>
        that is <em>not</em> <a
        lt="composite operation replace">replace</a>, or
        <var>keyframe</var> has no <a>composite operation</a>
        and the <a>composite operation</a> of this <a>keyframe
        effect</a> is <em>not</em> <a
        lt="composite operation replace">replace</a>, then
        perform the following steps:

        1.  Let <var>composite operation to use</var> be the
            <a>composite operation</a> of <var>keyframe</var>, or if
            it has none, the <a>composite operation</a> of this
            <a>keyframe effect</a>.
        1.  Let <var>value to combine</var> be the property value of
            <var>target property</var> specified on
            <var>keyframe</var>.
        1.  Replace the property value of <var>target property</var>
            on <var>keyframe</var> with the result of combining
            <var>underlying value</var> (<var>V</var><sub>a</sub>) and
            <var>value to combine</var> (<var>V</var><sub>b</sub>)
            using the procedure for the <var>composite operation to use</var>
            corresponding to the <var>target property</var>'s
            <a>animation type</a>.

1.  If there is only one keyframe in <var>interval endpoints</var>
    return the property value of <var>target property</var> on that
    keyframe.
1.  Let <var>start offset</var> be the <a>computed keyframe offset</a> of the
    first keyframe in <var>interval endpoints</var>.
1.  Let <var>end offset</var> be the <a>computed keyframe offset</a> of
    last keyframe in <var>interval endpoints</var>.
1.  Let <var>interval distance</var> be the result of evaluating
    <code>(<var>iteration progress</var> - <var>start offset</var>) /
    (<var>end offset</var> - <var>start offset</var>)</code>.
1.  Let <var>transformed distance</var> be the result of evaluating
    the <a>timing function</a> associated with the first keyframe in
    <var>interval endpoints</var> passing <var>interval distance</var>
    as the input progress.
1.  Return the result of applying the <a
    lt="interpolation">interpolation procedure</a> defined
    by the <a>animation type</a> of the <var>target property</var>,
    to the values of the <var>target property</var> specified on the
    two keyframes in <var>interval endpoints</var> taking the first such
    value as <var>V</var><sub>start</sub> and the second as
    <var>V</var><sub>end</sub> and using <var>transformed
    distance</var> as the interpolation parameter <var ignore>p</var>.

<div class="note">

    Note that this procedure assumes the following about the list of
    <a>keyframes</a> specified on the effect:</p>

    *   Each <a>keyframe</a> has a specified <a>computed keyframe offset</a> in
        the range [0, 1].
    *   The list of <a>keyframes</a> is sorted in ascending order by
        <a>computed keyframe offset</a>.
    *   For a given property, there is at most one specified property
        value on each keyframe.

    It is the responsibility of the user of the model (for example,
    a declarative markup or programming interface) to ensure these
    conditions are met.

    For example, for the <a href="#programming-interface">programming
    interface</a> defined by this specification, these conditions are
    met by the procedure to produce the <a>computed keyframes</a> that
    become the input to this procedure.

</div>

Note: this procedure permits overlapping <a>keyframes</a>.
    The behavior is that at the point of overlap the output value jumps to
    the value of the last defined <a>keyframe</a> at that offset.
    For overlapping keyframes at 0 or 1, the output value for <a>iteration
    progress</a> values less than 0 or greater than
    or equal to 1 is the value of the first <a>keyframe</a> or the last
    <a>keyframe</a> in <var>keyframes</var> respectively.

<div class="issue">
    In the presence of certain timing functions, the input iteration
    progress to an animation effect is not limited to the range [0, 1].
    Currently, however, keyframe offsets <em>are</em> limited to the
    range [0, 1] and property values are simply extrapolated for input
    iteration progress values outside this range.

    We have considered removing this restriction since some cases exist
    where it is useful to be able to specify non-linear
    changes in property values at iteration progress values outside the
    range [0, 1].
    One example is an animation that interpolates from green to yellow
    but has an overshoot timing function that makes it temporarily
    interpolate &lsquo;beyond&rsquo; yellow to red before settling back
    to yellow.

    While this effect could be achieved by modification of the keyframes
    and timing function, this approach seems to break the model's
    separation of timing concerns from animation effects.

    It is not clear how this effect should be achieved but we note that
    allowing keyframe offsets outside [0, 1] may make the currently
    specified behavior where keyframes at offset 0 and 1 are synthesized
    as necessary, inconsistent.

    See <a
    href='http://lists.w3.org/Archives/Public/public-fx/2013AprJun/0184.html'>section
    4 (Keyframe offsets outside [0, 1]) of minuted discussion from Tokyo
      2013 F2F</a>.

    <a href="https://github.com/w3c/csswg-drafts/issues/2081">&lt;https://github.com/w3c/csswg-drafts/issues/2081&gt;</a>
</div>


Combining effects {#combining-effects}
----------------------------------------
<div class='informative-bg'><em>This section is non-normative</em>

After calculating the <a>effect values</a> for a
<a>keyframe effect</a>, they are applied to the <a>animation
effect</a>'s <a lt="target property">target properties</a>.

Since it is possible for multiple <a>in effect</a> <a>keyframe effects</a> to
target the same property it is often necessary to combine the results of several
<a>keyframe effects</a> together.
This process is called <dfn lt='composite | composition'>compositing</dfn>
and is based on establishing an <a>effect stack</a> for each property
targeted by an <a>in effect</a> <a>animation effect</a>.

After [=compositing=] the results of <a>keyframe
effects</a> together, the composited result is combined with other
values specified for the <a>target property</a>.

The arrangement is illustrated below:

<figure>
  <img src="img/animation-cascade.svg" width="500"
       alt="Overview of the application of effect values to their target properties">
  <figcaption>
    Overview of the application of <a>effect values</a> to
    their <a>target properties</a>.<br>
    The results of <a>keyframe effects</a> targeting the same property
    are composited together using an <a>effect stack</a>.<br>
    The result of this composition is then inserted into the CSS cascade
    at an appropriate point.
  </figcaption>
</figure>

For the first part of this operation&mdash;combining <a>effect values</a> that
target the same <a lt="target property">property</a>&mdash; it is necessary to
determine both
<em>how</em> <a>keyframe effects</a>
are combined with one another,
as well as the <em>order</em> in which they are applied, that is,
their relative <em>composite order</em>.

The matter of <em>how</em> <a>effect values</a> are
combined is governed by the <a>composite operation</a> of
the corresponding <a>keyframe effects</a>.

The relative <em>composite order</em> of <a>effect values</a>
is determined by an <a>effect stack</a> established for each
animated property.
</div>

### Animation classes ### {#animation-classes}

This specification provides a common animation model intended to be used
by other specifications that define markup or programming interfaces on
top of this model. The particular markup or programming interface that
generated an <a>animation</a> defines its <dfn>animation class</dfn>.

Further specifications may define specialized behavior for composite
ordering between different classes of animations or within a particular class.

<div class='informative-bg'><em>This section is non-normative</em>

For example, animations whose <a lt="animation class">class</a> is &lsquo;CSS
animation&rsquo; are defined as having a <em>higher</em> composite order than
animations whose class is &lsquo;CSS transition&rsquo; but <em>lower</em> than
other animations without a specific class.

Within the set of &lsquo;CSS animation&rsquo; objects, specialized
composite ordering is defined based on the 'animation-name' property
amongst other factors.

</div>

### The effect stack ### {#the-effect-stack}

Associated with each property <a lt="target property">targeted</a>
by one or more <a>keyframe effects</a> is an <dfn>effect
stack</dfn> that establishes the relative composite order of the <a>keyframe
effects</a>.

The relative
<dfn lt="animation composite order" local-lt="composite order" export>composite order</dfn>
of any two <a>keyframe effects</a>, <var>A</var> and <var>B</var>,
within an <a>effect stack</a> is
established by comparing their properties as follows:

1.  Let the <dfn>associated animation of an animation effect</dfn>
    be the <a>animation</a> <a
    lt="associated with an animation">associated</a> with the
    <a>animation effect</a> that affecting the property with which this
    <a>effect stack</a> is associated.
2.  Sort <var>A</var> and <var>B</var> by applying the following
    conditions in turn until the order is resolved,

    1.  If <var>A</var> and <var>B</var>'s associated animations differ by
        <a lt="animation class">class</a>, sort by any inter-class composite
        order defined for the corresponding classes.
    1.  If <var>A</var> and <var>B</var> are still not sorted,
        sort by any <a lt="animation class">class</a>-specific composite order
        defined by the common class of <var>A</var> and <var>B</var>'s
        associated animations.
    1.  If <var>A</var> and <var>B</var> are still not sorted,
        sort by their corresponding position in the <a>global animation
        list</a>.

<a>Animation effects</a> that sort earlier have <em>lower</em>
composite order.

### Calculating the result of an effect stack ### {#calculating-the-result-of-an-effect-stack}

In order to calculate the final value of an <a>effect stack</a>,
the <a>effect values</a> of each <a>keyframe effect</a> in the stack are
combined in composite order.

Each step in the process of evaluating an <a>effect stack</a> takes
an <dfn>underlying value</dfn> as input.

For each <a>keyframe effect</a> in the stack, the appropriate
<a>effect value</a> from the <a>keyframe effect</a>
is combined with the <a>underlying value</a> to produce a new value.
This resulting value becomes the <a>underlying value</a> for combining
the next <a>keyframe effect</a> in the stack.

The final value of an <a>effect stack</a>, called the
<dfn>composited value</dfn>, is simply the result of combining the
<a>effect value</a> of the final (highest composite order)
<a>keyframe effect</a> in the stack with the <a>underlying value</a>
at that point.

### Effect composition ### {#effect-composition}

The specific operation used to combine an <a>effect value</a> with an
<a>underlying value</a> is determined by the
<dfn>composite operation</dfn> of the <a>keyframe effect</a> that
produced the <a>effect value</a>.

This specification defines three <a>composite operations</a> as
follows:

:   <dfn lt="composite operation replace">replace</dfn>
::  The result of compositing the <a>effect value</a>
    with the <a>underlying value</a> is simply the <a>effect value</a>.
:   <dfn lt="composite operation add">add</dfn>
::  The <a>effect value</a> is <a
    lt="value addition">added</a> to the <a>underlying
    value</a>.
    For <a>animation types</a> where the
    <a lt="value addition">addition operation</a> is defined
    such that it is not commutative, the order of the operands is
    <code><a>underlying value</a> + <a>effect value</a></code>.
:   <dfn lt="composite operation accumulate">accumulate</dfn></dt>
::  The <a>effect value</a> is <a
    lt="value accumulation">accumulated</a>
    onto the <a>underlying value</a>.
    For <a>animation types</a> where the
    <a lt="value accumulation">accumulation operation</a> is
    defined such that it is not commutative, the order of the operands
    is <a>underlying value</a> followed by <a>effect value</a>.

### Applying the composited result ### {#applying-the-composited-result}

Applying a <a>composited value</a> to a <a>target property</a>
is achieved by adding a specified value to the CSS cascade.

The level of the cascade to which this specified value is added
depends on the <a lt="animation class">class</a> of the <a>animation</a> <a
lt="associated animation of an animation effect">associated with</a> the
effect with the highest composite order in the <a>effect stack</a> for a given
property.
By default, the specified value is added to the &lsquo;Animation
declarations&rsquo; level of the cascade ([[!css-cascade-3]]).

<div class='informative-bg'><em>This section is non-normative</em>

For example, if the effect with the highest composite order is associated with
a &lsquo;CSS transition&rsquo;-class animation, the <a>composited value</a>
will be added to &lsquo;Transition declarations&rsquo; level of the cascade.

</div>

The <a>composited value</a> calculated for a CSS <a>target
property</a> is applied using the following process.

1.  Calculate the <var>base value</var> of the property as
    the value generated for that property by computing the computed value
    for that property in the absence of animations.
2.  Establish the <a>effect stack</a> for the property (see
    [[#the-effect-stack]]).
3.  Calculate the <a>composited value</a> of the <a>effect
    stack</a> passing in the <var>base value</var> of the property
    as the initial <a>underlying value</a> (see
    [[#calculating-the-result-of-an-effect-stack]]).
4.  Insert the <a>composited value</a> into the CSS cascade at the
    level defined for the <a lt="animation class">class</a> of the
    <a>animation</a> <a
    lt="associated animation of an animation effect">associated with</a> the
    effect at the top of the <a>effect stack</a> established for the target
    property.

Replacing animations {#replacing-animations}
----------------------------------------

<div class="informative-bg"><em>This section is non-normative</em>

Using the programming interface defined in this specification, it is possible to
repeatedly trigger new animations that contribute to an element's animated style
indefinitely.

For example, consider the following code:

<div class="example"><pre class="lang-javascript">
elem.addEventListener('mousemove', evt => {
  circle.animate(
    { transform: `translate(${evt.clientX}px, ${evt.clientY}px)` },
    { duration: 500, fill: 'forwards' }
  );
});
</pre></div>

This will generate a new forwards-filling animation each time the mouse is
moved, quickly producing hundreds, even thousands of forwards-filling
animations.

If the user agent is required to retain <em>all</em> such animations,
the list of animations would grow in an unbounded fashion,
producing a memory leak.

This section defines a mechanism that causes overridden animations to be
automatically removed unless the author explicitly requests they be retained.

</div>

### Replace state ### {#animation-replace-state}

An [=animation=] maintains a <dfn>replace state</dfn> that may be one of the
following values:

* <dfn lt="active replace state">active</dfn>
* <dfn lt="removed replace state">removed</dfn>
* <dfn lt="persisted replace state">persisted</dfn>

The initial value of an [=animation=]'s [=replace state=] is
[=active replace state|active=].

The [=animation effects=] of an [=animation=]
whose [=replace state=] is [=removed replace state|removed=]
are not included in the [=effect stacks=] of their [=target properties=].

### Removing replaced animations ### {#removing-replaced-animations}

An [=animation=] is
<dfn lt="replaceable animation" local-lt="replaceable">replaceable</dfn>
if <em>all</em> of the following conditions are true:

*   The existence of the [=animation=] is <em>not</em> prescribed by markup.
    That is, it is <em>not</em>
    a CSS animation with an [=owning element (animation)|owning element=],
    nor a CSS transition with an [=owning element (transition)|owning element=].
*   The [=animation=]'s [=play state=] is [=finished play state|finished=].
*   The [=animation=]'s [=replace state=] is <em>not</em>
    [=removed replace state|removed=].
*   The [=animation=] is associated with a [=monotonically increasing=]
    [=timeline=].
*   The [=animation=] has an [=associated effect=].
*   The [=animation=]'s [=associated effect=] is [=in effect=].
*   The [=animation=]'s [=associated effect=] has an [=effect target=].

When asked to <dfn>remove replaced animations</dfn>
for a {{Document}}, |doc|,
then for every [=animation=], |animation|, that:

*   has an [=associated with an animation|associated=] [=animation effect=]
    whose [=effect target=] is a [=descendant=] of |doc|, and

*   is [=replaceable=], and

*   has a [=replace state=] of [=active replace state|active=], and

*   for which there exists for each [=target property=]
    of every [=animation effect=]
    [=associated with an animation|associated=] with |animation|,
    an [=animation effect=] associated with a [=replaceable=] [=animation=]
    with a higher [=composite order=] than |animation|
    that includes the same [=target property=]

perform the following steps:

1.   Set |animation|'s [=replace state=] to [=removed replace state|removed=].

1.   <a lt="create an event">Create</a> an {{AnimationPlaybackEvent}},
     |removeEvent|.

1.   Set |removeEvent|'s {{Event/type}} attribute to
     <a lt="remove event">remove</a>.

1.   Set |removeEvent|'s {{AnimationPlaybackEvent/currentTime}} attribute
     to the [=current time=] of |animation|.

1.   Set |removeEvent|'s {{AnimationPlaybackEvent/timelineTime}}
     attribute to the <a lt="timeline current time">current time</a>
     of the [=timeline=] with which |animation| is associated.

1.   If |animation| has a [=document for timing=], then append
     |removeEvent| to its [=document for timing=]'s
     [=pending animation event queue=] along with its target, |animation|.
     For the [=scheduled event time=], use the result of
     applying the procedure to convert
     [=timeline time to origin-relative time=] to
     the [=timeline current time|current time=] of the [=timeline=]
     with which |animation| is associated.

     Otherwise, [=queue a task=] to [=dispatch=] |removeEvent| at
     |animation|.
     The task source for this task is the [=DOM manipulation task
     source=].

Side effects of animation {#side-effects-section}
----------------------------------------

For every property targeted by at least one <a>animation effect</a> that is
<a>current</a> or <a>in effect</a>,
and which is associated with an [=animation=] whose [=replace state=]
is <em>not</em> [=removed replace state|removed=],
the user agent must act as if the
'will-change' property ([[!css-will-change-1]]) on the <a>effect target</a>
includes the property.

<div class='informative-bg'><em>This section is non-normative</em>

As a result of the above requirement, if an animation targets, for example,
the 'transform' property of an element, a <a>stacking context</a> will be
created for the <a>effect target</a> so long as the <a>animation</a> is in
the <a>before phase</a>, the <a>active phase</a> or, if it has a <a>fill
mode</a> of &lsquo;forwards&rsquo; or &lsquo;both&rsquo;, the <a>after
phase</a>.

</div>

<!-- End of animation model -->


Programming interface {#programming-interface}
=======================================

<div class='informative-bg'><em>This section is non-normative</em>

In addition to the abstract model described above, Web Animations also
defines a programming interface to the model.
This interface can be used to inspect and extend animations produced
by declarative means or for directly producing animations when
a procedural approach is more suitable.

</div>

Time values in the programming interface {#time-values-in-the-programming-interface}
----------------------------------------

<a>Time values</a> are represented in the programming interface with
the type <code>double</code>. <a>Unresolved</a> time values are
represented by the value <code>null</code>.

The <code>AnimationTimeline</code> interface {#the-animationtimeline-interface}
----------------------------------------

<a>Timelines</a> are represented in the Web Animations API by the
{{AnimationTimeline}} interface.

<pre class="idl">
[Exposed=Window]
interface AnimationTimeline {
    readonly attribute double? currentTime;
};
</pre>

<div class='attributes'>

:   <dfn attribute for=AnimationTimeline>currentTime</dfn>
::  Returns the <a lt="timeline current time">current time</a> for this timeline
    or <code>null</code> if this timeline is <a lt="inactive
    timeline">inactive</a>.

</div>

The <code>DocumentTimeline</code> interface {#the-documenttimeline-interface}
----------------------------------------

<a>Document timelines</a>, including the <a>default document
timeline</a>, are represented in the Web Animations API by the
{{DocumentTimeline}} interface.

<pre class="idl">
dictionary DocumentTimelineOptions {
  DOMHighResTimeStamp originTime = 0;
};

[Exposed=Window]
interface DocumentTimeline : AnimationTimeline {
  constructor(optional DocumentTimelineOptions options = {});
};
</pre>

<div class='members'>

:   <dfn dict-member for=DocumentTimelineOptions>originTime</dfn>
::  The <a>origin time</a> for the timeline specified as a real number of
    milliseconds relative to the [=time origin=].

</div>

<div class=constructors>

:   <dfn constructor for=DocumentTimeline
    lt="DocumentTimeline(options)">DocumentTimeline (options)</dfn>
::  Creates a new {{DocumentTimeline}}.
    The {{Document}} with which the timeline is associated is the
    {{Document}} <a lt="document associated with a window">associated</a>
    with the {{Window}} that is the <a>current global object</a>.

    <div class='parameters'>

    :   <dfn argument
        for="DocumentTimeline/DocumentTimeline(options)"
        lt="options">options</dfn>
    ::  Configuration parameters for the newly-created timeline.
        This specification defines only the
        {{DocumentTimelineOptions/originTime}} member but other specifications
        may extend this set.

    </div>

</div>

The <code>Animation</code> interface {#the-animation-interface}
----------------------------------------

<a>Animations</a> are represented in the Web Animations
API by the {{Animation}} interface.

<pre class='idl'>
[Exposed=Window]
interface Animation : EventTarget {
    constructor(optional AnimationEffect? effect = null,
                optional AnimationTimeline? timeline);
             attribute DOMString                id;
             attribute AnimationEffect?         effect;
    readonly attribute AnimationTimeline?       timeline;
             attribute double?                  startTime;
             attribute double?                  currentTime;
             attribute double                   playbackRate;
    readonly attribute AnimationPlayState       playState;
    readonly attribute AnimationReplaceState    replaceState;
    readonly attribute boolean                  pending;
    readonly attribute Promise&lt;Animation&gt;       ready;
    readonly attribute Promise&lt;Animation&gt;       finished;
             attribute EventHandler             onfinish;
             attribute EventHandler             oncancel;
             attribute EventHandler             onremove;
    void cancel();
    void finish();
    void play();
    void pause();
    void updatePlaybackRate(double playbackRate);
    void reverse();
    void persist();
    void commitStyles();
};
</pre>

<div class=constructors>

:   <dfn constructor for=Animation
      lt="Animation(effect, timeline)">Animation (effect, timeline)</dfn>
::  Creates a new {{Animation}} object using the following procedure.

    1.  Let <var>animation</var> be a new {{Animation}} object.
    2.  Run the procedure to <a>set the timeline of an animation</a> on
        <var>animation</var> passing <var>timeline</var> as the <var>new
        timeline</var> or, if a <var>timeline</var> argument is missing,
        passing the <a>default document timeline</a> of the {{Document}}
        <a lt="document associated with a window">associated</a> with the
        {{Window}} that is the <a>current global object</a>.
    3.  Run the procedure to <a>set the associated effect of an animation</a> on
        <var>animation</var> passing <var>source</var> as the <var>new
        effect</var>.

    <div class="parameters">

    :   <dfn argument for="Animation/Animation(effect, timeline)"
        lt="effect">effect</dfn>
    ::  An optional value which, if not null, specifies the <a>associated
        effect</a> to assign to the newly created <a>animation</a>.

    :   <dfn argument
        for="Animation/Animation(effect, timeline)"
        lt="timeline">timeline</dfn>
    ::  An optional value which, if present, specifies the <a>timeline</a>
        with which to associate the newly-created <a>animation</a>.
        If missing, the <a>default document timeline</a> of the
        {{Document}} <a lt="document associated with a window">associated</a>
        with the {{Window}} that is the <a>current global object</a> is used.

    </div>

</div>

<div class='attributes'>

:   <dfn attribute for=Animation>id</dfn>
::  A string used to identify the animation.
:   <dfn attribute for=Animation>effect</dfn>
::  The <a>associated effect</a> of this animation.
    Setting this attribute updates the object's <a>associated effect</a> using
    the procedure to <a>set the associated effect of an animation</a>.
:   <dfn attribute for=Animation>timeline</dfn>
::  The <a>timeline</a> associated with this animation.
:   <dfn attribute for=Animation>startTime</dfn>
::  Returns the [=start time=] of this animation.
    Setting this attribute updates the [=start time=] using
    the procedure to <a>set the start time</a> of this object
    to the new value.
:   <dfn attribute for=Animation>currentTime</dfn>
::  The <a>current time</a> of this animation.
    Setting this attribute follows the procedure to <a>set the current time</a>
    of this object to the new value.
:   <dfn attribute for=Animation>playbackRate</dfn>
::  The [=playback rate=] of this animation.
    Setting this attribute follows the procedure to <a>set the playback rate</a>
    of this object to the new value.

    <div class=note>

    Setting this attribute performs a synchronous update to the [=playback
    rate=] meaning that it does not make any attempt to synchronize with the
    playback state of animations running on a separate process or thread.
    As a result, setting the {{Animation/playbackRate}} for an in-flight
    animation may cause it to jump.

    To set the the [=playback rate=] for an in-flight animation such that it
    smoothly updates, use the asynchronous {{updatePlaybackRate()}} method.

    </div>

:   <dfn attribute for=Animation>playState</dfn>
::  The <a>play state</a> of this animation.
:   <dfn attribute for=Animation>replaceState</dfn>
::  The <a>replace state</a> of this animation.
:   <dfn attribute for=Animation>pending</dfn>
::  Returns true if this animation has a <a>pending play task</a> or
    a <a>pending pause task</a>.
:   <dfn attribute for=Animation>ready</dfn>
::  Returns the <a>current ready promise</a> for this object.
:   <dfn attribute for=Animation>finished</dfn>
::  Returns the <a>current finished promise</a> for this object.
:   <dfn attribute for=Animation>onfinish</dfn>
::  The event handler for the <a>finish event</a>.
:   <dfn attribute for=Animation>oncancel</dfn>
::  The event handler for the <a>cancel event</a>.
:   <dfn attribute for=Animation>onremove</dfn>
::  The event handler for the <a>remove event</a>.

</div>

<div class='methods'>

:   <dfn method for=Animation lt='cancel()'>void cancel()</dfn>
::  Clears all effects caused by this animation and aborts its playback
    by running the <a>cancel an animation</a> procedure for this object.
:   <dfn method for=Animation lt='finish()'>void finish()</dfn>
::  Seeks the animation to the <a>associated effect end</a> in the
    current direction by running the <a>finish an animation</a> procedure
    for this object.

    <div class='exceptions'>

    :   DOMException of type {{InvalidStateError}}
    ::  Raised if this animation's [=playback rate=] is zero, or if this
        animation's [=playback rate=] is &gt; zero and the
        <a>associated effect end</a> is infinity.

    </div>

:   <dfn method for=Animation lt='play()'>void play()</dfn>
::  Begins or resumes playback of the animation by running the procedure to
    [=play an animation=] passing true as the value of the |auto-rewind| flag.
:   <dfn method for=Animation lt='pause()'>void pause()</dfn>
::  Suspends the playback of this animation by running the procedure to
    <a>pause an animation</a> for this object.
:   <dfn method for=Animation lt='updatePlaybackRate(playbackRate)'>void updatePlaybackRate(playbackRate)</dfn>
::  Performs an asynchronous update of the [=playback rate=] of this
    animation by performing the [=seamlessly update the playback rate=]
    procedure, passing
    {{Animation/updatePlaybackRate(playbackRate)/playbackRate}} as the |new
    playback rate|.

    <div class="parameters">

    :   <dfn argument for="Animation/updatePlaybackRate(playbackRate)"
        lt="playbackRate">playbackRate</dfn>
    ::  A finite real number specifying the updated playback rate to use.

    </div>
:   <dfn method for=Animation lt='reverse()'>void reverse()</dfn>
::  Inverts the [=playback rate=] of this animation and plays it using the
    <a>reverse an animation</a> procedure for this object.
    As with <a method for=Animation lt="play()">play()</a>, this
    method unpauses the animation and, if the animation has already finished
    playing in the reversed direction, seeks to the start of the <a>associated
    effect</a>.
:   <dfn method for=Animation lt='persist()'>void persist()</dfn>
::  Sets this animation's [=replace state=] to
    [=persisted replace state|persisted=].
:   <dfn method for=Animation lt='commitStyles()'>void commitStyles()</dfn>
::  Writes the current [=effect values=]
    produced by this animation's [=animation effects=]
    to their corresponding [=effect targets=]' inline style
    using the [=commit computed styles=] procedure.

    Unlike most other methods defined on this interface, calling this method
    <em>does</em> trigger a [=style change event=] (see [[#model-liveness]]).

    <div class=note>

      Since the procedure to [=commit computed styles=] includes the
      [=effect values=] for the animation even if it is
      [=removed replace state|removed=],
      this method is useful for retaining the effect of an animation
      after it has been replaced (see [[#removing-replaced-animations]])
      without retaining the actual animation.

      Note that the values committed are the <em>computed</em> values
      produced by the [=animation effects=] at the time when this method is
      called.
      Since these values are computed values, they do not reflect to changes to
      context such as responding to changes to CSS variables or
      recalculating em units based on changes to the computed ''font-size''
      in the way the values produced by a live animation would.

      In order to retain full fidelty of a filling animation's result after it
      has been replaced (see [[#replacing-animations]]),
      the {{Animation/persist()}} method may be used,
      but note that doing so will mean the animation continues to consume
      resources.

    </div>

</div>

To <dfn>commit computed styles</dfn> for an [=animation=], |animation|:

1.   Let |targets| be the [=ordered set|set=] of all [=effect targets=]
     for [=animation effects=] [=associated with an animation|associated=]
     with |animation|.

1.   <a for=list lt=iterate>For each</a> |target| in |targets|:

     1.   If |target| is not an element capable of having a [=style
          attribute=] [[!CSS-STYLE-ATTR]]
          (for example, it is a pseudo-element or is an element in
          a document format for which style attributes are not defined)
          <a>throw</a> a "{{NoModificationAllowedError}}" {{DOMException}}
          and abort these steps.

     1.   If, after applying any pending style changes,
          |target| is not [=being rendered=],
          <a>throw</a> an "{{InvalidStateError}}" {{DOMException}}
          and abort these steps.

          <div class=issue>

          The definition of [=being rendered=] [[!HTML]] with regards to
          ''display: contents'' is still <a
          href=https://github.com/whatwg/html/issues/1837>under discussion</a>.
          For the purpose of this procedure, we assume that an
          element with ''display: contents'' that otherwise would have
          associated layout boxes (i.e. it is [=connected=] and not part of
          a ''display: none'' subtree) <em>is</em> being rendered.

          </div>

     1.   Let |inline style| be the result of getting the
          [=CSS declaration block=] corresponding to |target|'s
          [=style attribute=].
          If |target| does not [=has an attribute|have=]
          a [=style attribute=],
          let |inline style| be a new empty [=CSS declaration block=] with
          the <a for=CSSStyleDeclaration>readonly flag</a> unset and
          <a for=CSSStyleDeclaration>owner node</a> set to |target|.

     1.   Let |targeted properties| be the [=ordered set|set=]
          of physical longhand properties
          that are a [=target property=] for at least one [=animation effect=]
          [=associated with an animation|associated=] with |animation|
          whose [=effect target=] is |target|.

     1.   For each property, |property|, in |targeted properties|:

          1.   Let |partialEffectStack| be a copy of the [=effect stack=]
               for |property| on |target|.

          1.   If |animation|'s [=replace state=] is
               [=removed replace state|removed=],
               add all [=animation effects=]
               [=associated with an animation|associated=] with |animation|
               whose [=effect target=] is |target| and which include
               |property| as a [=target property=] to |partialEffectStack|.

          1.   Remove from |partialEffectStack| any [=animation effects=]
               whose [=associated with an animation|associated=] [=animation=]
               has a higher [=composite order=] than |animation|.

          1.   Let |effect value| be the result of calculating the result of
               |partialEffectStack| for |property| using |target|'s computed
               style (see [[#calculating-the-result-of-an-effect-stack]]).

          1.   [=Set a CSS declaration=] |property| for |effect value| in
               |inline style|.

     1.   [=Update style attribute for=] |inline style|.

### The <code>AnimationPlayState</code> enumeration ### {#the-animationplaystate-enumeration}

<pre class='idl'>
enum AnimationPlayState { "idle", "running", "paused", "finished" };
</pre>

:   <code>idle</code>
::  Corresponds to the <a>idle play state</a>.
:   <code>running</code>
::  Corresponds to the <a>running play state</a>.
:   <code>paused</code>
::  Corresponds to the <a>paused play state</a>.
:   <code>finished</code>
::  Corresponds to the <a>finished play state</a>.

### The <code>AnimationReplaceState</code> enumeration ### {#the-animationreplacestate-enumeration}

<pre class='idl'>
enum AnimationReplaceState { "active", "removed", "persisted" };
</pre>

:   <code>active</code>
::  Corresponds to the [=active replace state=].
:   <code>removed</code>
::  Corresponds to the [=removed replace state=].
:   <code>persisted</code>
::  Corresponds to the [=persisted replace state=].

The <code>AnimationEffect</code> interface {#the-animationeffect-interface}
----------------------------------------

<a>Animation effects</a> are represented in the Web Animations API by the
abstract {{AnimationEffect}} interface.

<pre class='idl'>
[Exposed=Window]
interface AnimationEffect {
    EffectTiming         getTiming();
    ComputedEffectTiming getComputedTiming();
    void                 updateTiming(optional OptionalEffectTiming timing = {});
};
</pre>

<div class="note">
In future, we may expose <code>any onupdate (double? progress,
double currentIteration, Animatable? target, any
underlyingValue)</code> so that the animation effects can be driven
apart from the timing model.
</div>

<div class=methods>

:   <dfn method for=AnimationEffect>getTiming()</dfn>
::  Returns the specified timing properties for this <a>animation effect</a>.

    For the correspondance between the members of the returned {{EffectTiming}}
    object and properties of the [[#timing-model|timing model]], see the
    the {{EffectTiming}} interface.

:   <dfn method for=AnimationEffect>getComputedTiming()</dfn>
::  Returns the calculated timing properties for this <a>animation
    effect</a>.

    Although some of the attributes of the object returned by
    {{AnimationEffect/getTiming()}} and {{AnimationEffect/getComputedTiming()}}
    are common, their values may differ in the following ways:

    *   {{EffectTiming/duration}} &ndash; while
        {{AnimationEffect/getTiming()}} may return the string <code>auto</code>,
        {{AnimationEffect/getComputedTiming()}} must return a number
        corresponding to the calculated value of the <a>iteration duration</a>
        as defined in the description of the {{EffectTiming/duration}} member of
        the {{EffectTiming}} interface.

        In this level of the specification, that simply means that an
        <code>auto</code> value is replaced by zero.

    *   {{EffectTiming/fill}} &ndash; likewise, while
        {{AnimationEffect/getTiming()}} may return the string <code>auto</code>,
        {{AnimationEffect/getComputedTiming()}} must return the specific <a
        enum>FillMode</a> used for timing calculations as defined
        in the description of the {{EffectTiming/fill}} member of the
        {{EffectTiming}} interface.

        In this level of the specification, that simply means that an
        <code>auto</code> value is replaced by the <code>none</code> <a
        enum>FillMode</a>.

    Note: It is likely that other timing members may be extended in future to
    include <code>auto</code>-like values. When performing timing calculations,
    authors are encouraged to use {{AnimationEffect/getComputedTiming()}} where
    possible to avoid incompatibility should the range or type of allowed
    specified values be changed.

    In addition to possible differences in the values returned,
    compared to {{AnimationEffect/getTiming()}},
    {{AnimationEffect/getComputedTiming()}} returns additional timing
    information as defined by the {{ComputedEffectTiming}} dictionary.

:   <dfn method for=AnimationEffect>updateTiming(timing)</dfn>
::  Updates the specified timing properties of this <a>animation effect</a> by
    performing the procedure to [=update the timing properties of an animation
    effect=] passing the {{AnimationEffect/updateTiming(timing)/timing}}
    parameter as |input|.

    <div class=parameters>

    :   <dfn argument for="AnimationEffect/updateTiming(timing)"
        lt="timing">optional {{OptionalEffectTiming}} timing</dfn>
    ::  The timing properties to update.
        The timing properties corresponding to any members not <a>present</a>
        on {{AnimationEffect/updateTiming(timing)/timing}} will <em>not</em>
        be modified.

    </div>

</div>

Issue(2082): The <code>remove()</code> method can be used to remove an effect
from either its parent group or animation. Should we keep it in level 1 and
define it simply as removing the animation effect from its animation?

### The <code>EffectTiming</code> and <code>OptionalEffectTiming</code> dictionaries ### {#the-effecttiming-dictionaries}

The {{EffectTiming}} dictionary represents the timing properties of an
{{AnimationEffect}}.

The {{OptionalEffectTiming}} dictionary is a variant of the {{EffectTiming}}
dictionary that allows some members to be not <a>present</a>.
This is used by the {{AnimationEffect/updateTiming()}} method of the
{{AnimationEffect}} interface to perform a delta update to the timing properties
of an [=animation effect=].

<pre class='idl'>
dictionary EffectTiming {
    double                             delay = 0;
    double                             endDelay = 0;
    FillMode                           fill = "auto";
    double                             iterationStart = 0.0;
    unrestricted double                iterations = 1.0;
    (unrestricted double or DOMString) duration = "auto";
    PlaybackDirection                  direction = "normal";
    DOMString                          easing = "linear";
};

dictionary OptionalEffectTiming {
    double                             delay;
    double                             endDelay;
    FillMode                           fill;
    double                             iterationStart;
    unrestricted double                iterations;
    (unrestricted double or DOMString) duration;
    PlaybackDirection                  direction;
    DOMString                          easing;
};
</pre>

<div class=members>

:   <dfn dict-member for=EffectTiming>delay</dfn><dfn dict-member
    for=OptionalEffectTiming lt=delay></dfn>
::  The <a>start delay</a> which represents
    the number of milliseconds from the [=start time=] of the associated
    <a>animation</a> to the start of the <a>active interval</a>.

:   <dfn dict-member for=EffectTiming>endDelay</dfn><dfn dict-member
    for=OptionalEffectTiming lt=endDelay></dfn>
::  The <a>end delay</a> which represents the number of milliseconds
    from the end of an <a>animation effect</a>'s <a>active interval</a>
    until its <a>end time</a>.

:   <dfn dict-member for=EffectTiming>fill</dfn><dfn dict-member
    for=OptionalEffectTiming lt=fill></dfn>
::  The <a>fill mode</a> which defines the behavior of the <a>animation
    effect</a> outside its <a>active interval</a>.

    When performing timing calculations the special string value
    <code>auto</code> is expanded to one of the <a>fill modes</a> recognized by
    the timing model as follows,

    <div class="switch">

    :   If the <a>animation effect</a> to which the fill mode is being is
        applied is a <a>keyframe effect</a>,
    ::  Use <span class="enum-value">none</span> as the <a>fill
        mode</a>.
    :   Otherwise,
    ::  Use <span class="enum-value">both</span> as the <a>fill
        mode</a>.

    </div>

    <div class=advisement>
    As described in [[#fill-behavior]], authors are discouraged from using
    indefinitely filling animations.
    </div>

:   <dfn dict-member for=EffectTiming>iterationStart</dfn><dfn dict-member
    for=OptionalEffectTiming lt=iterationStart></dfn>
::  The <a>animation effect</a>'s <a>iteration start</a> property which is a
    finite real number greater than or equal to zero representing the iteration
    index at which the animation effect begins and its progress through that
    iteration.

    For example, a value of 0.5 indicates that the animation effect begins half
    way through its first iteration. A value of 1.2 indicates the animation
    effect begins 20% of the way through its second iteration.

    <div class="note">
    Note that the value of {{EffectTiming/iterations}} is effectively
    <em>added</em> to the {{EffectTiming/iterationStart}} such that
    an animation effect with an {{EffectTiming/iterationStart}} of
    &lsquo;0.5&rsquo; and {{EffectTiming/iterations}} of
    &lsquo;2&rsquo; will still repeat twice however it will begin
    and end half-way through its <a>iteration interval</a>.

    {{EffectTiming/iterationStart}} values greater than
    or equal to one are typically only useful in combination with an
    animation effect that has an <a>iteration composite
    operation</a> of <span class="enum-value">accumulate</span> or when the
    <a>current iteration</a> index is otherwise significant.
    </div>

:   <dfn dict-member for=EffectTiming>iterations</dfn><dfn dict-member
    for=OptionalEffectTiming lt=iterations></dfn>
::  The <a>animation effect</a>'s <a>iteration count</a> property which is
    a real number greater than or equal to zero (including positive
    infinity) representing the number of times to the animation effect repeats.

    This may be set to <code class="esvalue">+Infinity</code> to cause
    the <a>animation effect</a> to repeat forever (unless the duration of the
    effect is zero, in which case it will finish immediately).

:   <dfn dict-member for=EffectTiming>duration</dfn><dfn dict-member
    for=OptionalEffectTiming lt=duration></dfn>
::  The <a>iteration duration</a> which is a real number greater than
    or equal to zero (including positive infinity) representing the
    time taken to complete a single iteration of the <a>animation
    effect</a>.

    In this level of this specification, the string value <code>auto</code>
    is treated as the value zero for the purpose of timing model calculations
    and for the result of the {{EffectTiming/duration}} member returned
    from {{AnimationEffect/getComputedTiming()}}.
    If the author specifies the <code>auto</code> value user agents must,
    however, return <code>auto</code> for the {{EffectTiming/duration}} member
    returned from {{AnimationEffect/getTiming()}}.

    This is a forwards-compatiblity measure since a future level of this
    specification is expected to introduce group effects where the
    <code>auto</code> value expands to include the duration of the child
    effects.

:   <dfn dict-member for=EffectTiming>direction</dfn><dfn dict-member
    for=OptionalEffectTiming lt=direction></dfn>
::  The <a>playback direction</a> of the <a>animation effect</a> which
    defines whether playback proceeds forwards, backwards, or alternates
    on each iteration.

:   <dfn dict-member for=EffectTiming>easing</dfn><dfn dict-member
    for=OptionalEffectTiming lt=easing></dfn>
::  The <a>timing function</a> used to scale the time to
    produce easing effects.

    The syntax of the string is defined by the <<easing-function>>
    production [[!CSS-EASING-1]].

</div>

### The <code>FillMode</code> enumeration ### {#the-fillmode-enumeration}

<pre class='idl'>
enum FillMode { "none", "forwards", "backwards", "both", "auto" };
</pre>

:   <code>none</code>
::  No fill.

:   <code>forwards</code>
::  Fill forwards.

:   <code>backwards</code>
::  Fill backwards.

:   <code>both</code>
::  Fill backwards and forwards.

:   <code>auto</code>
::  No fill.
    In a subsequent level of this specification, this may produce different
    behavior for other types of <a>animation effects</a>.

### The <code>PlaybackDirection</code> enumeration ### {#the-playbackdirection-enumeration}

<pre class='idl'>
enum PlaybackDirection { "normal", "reverse", "alternate", "alternate-reverse" };
</pre>

:   <code>normal</code>
::  All iterations are played as specified.

:   <code>reverse</code>
::  All iterations are played in the reverse direction from the order
    they are specified.

:   <code>alternate</code>
::  Even iterations are played as specified, odd iterations are played
    in the reverse direction from the order they are specified.

:   <code>alternate-reverse</code>
::  Even iterations are played in the reverse direction from the order
    they are specified, odd iterations are played as specified.


### Updating the timing of an <code>AnimationEffect</code> ### {#updating-animationeffect-timing}

To <dfn>update the timing properties of an animation effect</dfn>, |effect|,
from an {{EffectTiming}} or {{OptionalEffectTiming}} object, |input|, perform
the following steps:

1.  If the {{EffectTiming/iterationStart}} member of |input| is <a>present</a>
    and less than zero, <a>throw</a> a <span
    class=exceptionname>TypeError</span> and abort this procedure.

    Note: The reason for using a <span class=exceptionname>TypeError</span>
    rather than a <span class=exceptionname>RangeError</span> is to mirror
    the behavior of WebIDL's <a>[EnforceRange]</a> annotation should that
    annotation be able to be used with floating-point values in the future.

1.  If the {{EffectTiming/iterations}} member of |input| is <a>present</a>, and
    less than zero or is the value <code class=esvalue>NaN</code>, <a>throw</a>
    a <span class=exceptionname>TypeError</span> and abort this procedure.

1.  If the {{EffectTiming/duration}} member of |input| is <a>present</a>, and
    less than zero or is the value <code class=esvalue>NaN</code>, <a>throw</a>
    a <span class=exceptionname>TypeError</span> and abort this procedure.

1.  If the {{EffectTiming/easing}} member of |input| is <a>present</a>
    but cannot be parsed using the <<easing-function>> production
    [[!CSS-EASING-1]], <a>throw</a> a <span class=exceptionname>TypeError</span>
    and abort this procedure.

1.  Assign each member <a>present</a> in |input| to the corresponding timing
    property of |effect| as follows:

    *   {{EffectTiming/delay}} &rarr; [=start delay=]
    *   {{EffectTiming/endDelay}} &rarr; [=end delay=]
    *   {{EffectTiming/fill}} &rarr; [=fill mode=]
    *   {{EffectTiming/iterationStart}} &rarr; [=iteration start=]
    *   {{EffectTiming/iterations}} &rarr; [=iteration count=]
    *   {{EffectTiming/duration}} &rarr; [=iteration duration=]
    *   {{EffectTiming/direction}} &rarr; [=playback direction=]
    *   {{EffectTiming/easing}} &rarr; [=timing function=]


### The <code>ComputedEffectTiming</code> dictionary ### {#the-computedeffecttiming-dictionary}

Timing properties calculated by the timing model are exposed using
{{ComputedEffectTiming}} dictionary objects.

<pre class='idl'>
dictionary ComputedEffectTiming : EffectTiming {
    unrestricted double  endTime;
    unrestricted double  activeDuration;
    double?              localTime;
    double?              progress;
    unrestricted double? currentIteration;
};
</pre>

<div class=members>

:   <dfn dict-member for=ComputedEffectTiming>endTime</dfn>
::  The <a>end time</a> of the <a>animation effect</a> expressed
    in milliseconds since zero <a>local time</a> (that is, since
    the associated <a>animation</a>'s [=start time=] if this <a>animation
    effect</a> is <a>associated with an animation</a>).
    This corresponds to the end of the <a>animation effect</a>'s active
    interval plus any <a>end delay</a>.

:   <dfn dict-member for=ComputedEffectTiming>activeDuration</dfn>
::  The <a>active duration</a> of this <a>animation effect</a>.

:   <dfn dict-member for=ComputedEffectTiming>localTime</dfn>
::  The <a>local time</a> of this <a>animation effect</a>.

    This will be <code>null</code> if this
    <a>animation effect</a> is not
    <a>associated with an animation</a>.

:   <dfn dict-member for=ComputedEffectTiming>progress</dfn>
::  The current <a>iteration progress</a> of this <a>animation effect</a>.

:   <dfn dict-member for=ComputedEffectTiming>currentIteration</dfn>
::  The <a>current iteration</a> index beginning with zero for the first
    iteration.

    In most cases this will be a (positive) integer. However, for
    a zero-duration animation that repeats infinite times, the value
    will be positive <span class="esvalue">Infinity</span>.

    As with <a>unresolved</a> times, an unresolved <a>current iteration</a> is
    represented by a <span class="esvalue">null</span> value.

</div>

The <code>KeyframeEffect</code> interface {#the-keyframeeffect-interface}
----------------------------------------

<a>Keyframe effects</a> are represented by the {{KeyframeEffect}} interface.

<pre class='idl'>
[Exposed=Window]
interface KeyframeEffect : AnimationEffect {
    constructor(Element? target,
                object? keyframes,
                optional (unrestricted double or KeyframeEffectOptions) options = {});
    constructor(KeyframeEffect source);
    attribute Element? target;
    attribute CSSOMString? pseudoElement;
    attribute CompositeOperation             composite;
    sequence&lt;object&gt; getKeyframes();
    void             setKeyframes(object? keyframes);
};
</pre>

<div class=constructors>

:   <dfn constructor for=KeyframeEffect
     lt="KeyframeEffect(target, keyframes, options)">
    KeyframeEffect (target, keyframes, options)</dfn>
::  Creates a new {{KeyframeEffect}} object using the following procedure:

    1.  Create a new {{KeyframeEffect}} object, <var>effect</var>.</li>

    1.  Set the <a>target element</a> of <var>effect</var> to <var>target</var>.

    1.  Let <var>timing input</var> be the result corresponding to the first
        matching condition from below.

        :   If <var>options</var> is a {{KeyframeEffectOptions}} object,
        ::  Let <var>timing input</var> be <var>options</var>.

        :   Otherwise (if <var>options</var> is a <code>double</code>),
        ::  Let <var>timing input</var> be a new
            {{EffectTiming}} object with all members set to their default values
            and {{EffectTiming/duration}} set to <var>options</var>.

    1.  Call the procedure to [=update the timing properties of an
        animation effect=] of |effect| from |timing input|.

        If that procedure causes an exception to be thrown, propagate the
        exception and abort this procedure.

    1.  If <var>options</var> is a {{KeyframeEffectOptions}} object, assign
        the {{KeyframeEffect/composite}} property of <var>effect</var> to
        the corresponding value from <var>options</var>.

        When assigning this property, the error-handling defined for the
        corresponding setter on the {{KeyframeEffect}} interface is applied.
        If the setter requires an exception to be thrown for the value
        specified by <var>options</var>, this procedure must <a>throw</a>
        the same exception and abort all further steps.

    1.  Initialize the set of <a>keyframes</a> by performing the procedure
        defined for {{KeyframeEffect/setKeyframes()}} passing
        <var>keyframes</var> as the input.

    <div class="parameters">

    :   <dfn argument
        for="KeyframeEffect/KeyframeEffect(target, keyframes, options)"
        lt="target">{{Element}}? target</dfn>
    ::  The <a>target element</a>.
        This may be <code>null</code> for animations that do not target
        a specific element.

    :   <dfn argument
        for="KeyframeEffect/KeyframeEffect(target, keyframes, options)"
        lt="keyframes">object? keyframes</dfn>
    ::  The set of <a>keyframes</a> to use.
        The format and processing of this argument is defined in
        [[#processing-a-keyframes-argument]].

    :   <dfn argument
        for="KeyframeEffect/KeyframeEffect(target, keyframes, options)"
        lt="options">optional {{KeyframeEffectOptions}} options</dfn>
    ::  Either a number specifying the <a>iteration duration</a> of the effect,
        or a collection of properties specifying the timing and behavior of
        the effect.

    Examples of the usage of this constructor are given in
    [[#creating-a-new-keyframeeffect-object]].

:   <dfn constructor for=KeyframeEffect lt="KeyframeEffect(source)">KeyframeEffect (source)</dfn>
::  Creates a new {{KeyframeEffect}} object with the same properties
    as {{KeyframeEffect/constructor(source)/source}}
    using the following procedure:

    1.  Create a new {{KeyframeEffect}} object, <var>effect</var>.

    1.  Set the following properties of <var>effect</var> using the
        corresponding values of <var>source</var>:

        *    <a>effect target</a>,
        *    <a>keyframes</a>,
        *    <a>composite operation</a>, and
        *    all specified timing properties:
             *    [=start delay=],
             *    [=end delay=],
             *    [=fill mode=],
             *    [=iteration start=],
             *    [=iteration count=],
             *    [=iteration duration=],
             *    [=playback direction=], and
             *    [=timing function=].

        Note: Unlike the
        {{KeyframeEffect(target, keyframes, options)}} constructor,
        we do not need to re-throw exceptions since the timing properties
        specified on |source| can be assumed to be valid.

    <div class="parameters">

    :   <dfn argument for="KeyframeEffect/KeyframeEffect(source)"
        lt="source">{{KeyframeEffect}} source</dfn>
    ::  The <a>keyframe effect</a> from which to copy the properties
        that define the new <a>keyframe effect</a>.

    </div>

</div>

<div class="attributes">

:   <dfn attribute for=KeyframeEffect>target</dfn>
::  The [=target element=] being animated by this object
    (either the [=effect target=] if it is an {{Element}} or its
    [=originating element=] if it is a pseudo-element).
    This may be `null` for animations that do not target
    a specific element such as an animation that produces a sound
    using an audio API.

:   <dfn attribute for=KeyframeEffect>pseudoElement</dfn>
::  The [=target pseudo-selector=].
    This is `null` if the [=effect target=] is an {{Element}} or is itself `null`.
    When not `null`, this must be a [=pseudo-element=] selector with
    [[selectors-4#pseudo-element-syntax|valid syntax]].
    This will not accept invalid values and will always return the selector in
    its canonical form (i.e. `::before` instead of `:before`).

:   <dfn attribute for=KeyframeEffect>composite</dfn>
::  The <a>composite operation</a> used to composite this
    <a>keyframe effect</a> with the <a>effect stack</a>, as
    specified by one of the <a>CompositeOperation</a> enumeration
    values.

    On setting, sets the <a>composite operation</a> property of this
    <a>animation effect</a> to the provided value.

</div>

<div class="methods">

:   <dfn method for=KeyframeEffect lt="getKeyframes()">
    sequence&lt;object&gt; getKeyframes()</dfn>
::  Returns the keyframes that make up this effect along with their
    <a>computed keyframe offsets</a>.

    <div class='informative-bg'><em>This section is non-normative</em>

      The result of this method is a sequence of objects of the following
      format:

      <pre class='lang-idl'>
      dictionary ComputedKeyframe {
          // ... property-value pairs ...
          // i.e. DOMString propertyName
          double?                  offset = null;
          double                   computedOffset;
          DOMString                easing = "linear";
          CompositeOperationOrAuto composite = "auto";
      };
      </pre>

      The meaning and values of each member is as follows:

      :   <code>offset</code>
      ::  The <a>keyframe offset</a> of the <a>keyframe</a> specified as
          a number between 0.0 and 1.0 inclusive, or <code>null</code>.

          This will be <code>null</code> if the <a>keyframe</a> is to be
          automatically spaced between adjacent keyframes.

      :   <code>computedOffset</code>
      ::  The <a>computed keyframe offset</a> for this <a>keyframe</a>
          calculated as part of running the <a>compute missing keyframe
          offsets</a> procedure.

          Unlike the <code>offset</code> member, the <code>computedOffset</code>
          is never null.

      :   <code>easing</code>
      ::  The <a>timing function</a> used to transform the progress of time
          from this keyframe until the next keyframe in the series.

      :   <code>composite</code>
      ::  The <a>keyframe-specific composite operation</a> used to combine the
          values specified in this keyframe with the <a>underlying value</a>.

          This member will be {{CompositeOperationOrAuto/auto}} if the
          <a>composite operation</a> specified on the <a>keyframe effect</a> is
          being used.

    </div>

    Since <a>keyframes</a> are represented by a partially open-ended dictionary
    type that is not currently able to be expressed with WebIDL, the procedure
    used to prepare the result of this method is defined in prose below:

    1.  Let <var>result</var> be an empty sequence of objects.
    1.  Let <var>keyframes</var> be the result of applying the procedure to
        <a>compute missing keyframe offsets</a> to the <a>keyframes</a>
        for this <a>keyframe effect</a>.
    1.  For each <var>keyframe</var> in <var>keyframes</var>
        perform the following steps:

        1.  Initialize a dictionary object, <var>output keyframe</var>, using
            the following definition:

            <pre class='idl'>
             dictionary BaseComputedKeyframe {
                 double?                  offset = null;
                 double                   computedOffset;
                 DOMString                easing = "linear";
                 CompositeOperationOrAuto composite = "auto";
            };
            </pre>

        1.  Set the {{BaseComputedKeyframe/offset}},
            {{BaseComputedKeyframe/computedOffset}},
            {{BaseComputedKeyframe/easing}}, and
            {{BaseComputedKeyframe/composite}} members of
            <var>output keyframe</var> to the respective
            <a>keyframe offset</a>,
            <a>computed keyframe offset</a>,
            keyframe-specific <a>timing function</a>, and
            <a>keyframe-specific composite operation</a>
            values of <var>keyframe</var>.
        1.  For each animation property-value pair specified on
            <var>keyframe</var>, <var>declaration</var>, perform the following
            steps:

            1.  Let <var>property name</var> be the result of applying the
                <a>animation property name to IDL attribute name</a> algorithm
                to the property name of <var>declaration</var>.
            1.  Let <var>IDL value</var> be the result of serializing
                the property value of <var>declaration</var> by passing
                <var>declaration</var> to the algorithm to <a>serialize a CSS
                value</a> [[!CSSOM]].
            1.  Let <var>value</var> be the result of <a
                lt="DOMString to es">converting</a> <var>IDL value</var> to an
                ECMAScript String value.
            1.  Call the <a>\[[DefineOwnProperty]]</a> internal method on
                <var>output keyframe</var> with property name <var>property
                name</var>,
                Property Descriptor {
                \[[Writable]]: <span class=esvalue>true</span>,
                \[[Enumerable]]: <span class=esvalue>true</span>,
                \[[Configurable]]: <span class=esvalue>true</span>,
                \[[Value]]: <var>value</var> }
                and Boolean flag <span class=esvalue>false</a>.

        1.  Append <var>output keyframe</var> to <var>result</var>.

    1. Return <var>result</var>.

:   <dfn method for=KeyframeEffect lt='setKeyframes(keyframes)'>
    void setKeyframes(object? keyframes)</dfn>
::  Replaces the set of <a>keyframes</a> that make up this effect.

    <div class="parameters">

    :   <dfn argument for="KeyframeEffect/setKeyframes"
        lt="keyframes">object? keyframes</dfn>
    ::  A series of keyframes whose format and processing is defined by
        [[#processing-a-keyframes-argument]].

        This effect's set of <a>keyframes</a> is replaced with the result
        of performing the procedure to <a>process a keyframes argument</a>.
        If that procedure throws an exception, this effect's <a>keyframes</a>
        are not modified.

    </div>

</div>

### Creating a new <code>KeyframeEffect</code> object ### {#creating-a-new-keyframeeffect-object}

<div class='informative-bg'><em>This section is non-normative</em>

The {{KeyframeEffect(target, keyframes, options)|KeyframeEffect}} constructor
offers a number of approaches to creating new {{KeyframeEffect}} objects.

At its simplest, a {{KeyframeEffect}} object that changes the
&lsquo;left&rsquo; property of <code>elem</code> to 100px over three
seconds can be constructed as follows:

<div class='example'><pre class='lang-javascript'>
var effect = new KeyframeEffect(elem, { left: '100px' }, 3000);</pre></div>

The second parameter, representing the list of keyframes, may
specify multiple properties. (See <a href="#processing-a-keyframes-argument"
section></a>.)

<div class='example'>
<pre class='lang-javascript'>
// Specify multiple properties at once
var effectA = new KeyframeEffect(elem, { left: '100px', top: '300px' }, 3000);

// Specify multiple keyframes
var effectB = new KeyframeEffect(elem, [ { left: '100px' }, { left: '300px' } ], 3000);</pre></div>

The third parameter, representing the animation's timing, may
simply be a number representing the <a>iteration duration</a> in
milliseconds as above, or, to specify further timing properties such
as the <a>start delay</a>, an {{EffectTiming}} object can be used, as follows:

<div class='example'><pre class='lang-javascript'>
var effect =
  new KeyframeEffect(elem, { left: '100px' }, { duration: 3000, delay: 2000 });</pre></div>

If the duration is not specified, a value of zero is used.
It is possible to create an animation that simply sets a property
without any interpolation as follows:

<div class='example'><pre class='lang-javascript'>
var effect =
  new KeyframeEffect(elem, { visibility: 'hidden' }, { fill: 'forwards' });</pre></div>

As described in [[#fill-behavior]] however, using indefinitely filling
animations in this way is discouraged.

Having created a {{KeyframeEffect}}, it can be played by adding it to
an {{Animation}} and then playing that animation.
For simple effects, however, the <a
href="#extensions-to-the-element-interface"><code>Element.animate</code></a>
shortcut is more convenient since it performs these steps
automatically. For example,

<div class='example'><pre class='lang-javascript'>
elem.animate({ left: '100px' }, 3000);</pre></div>

</div>

### Property names and IDL names ### {#property-name-conversion}

The <dfn>animation property name to IDL attribute name</dfn> algorithm for
<var>property</var> is as follows:

1.  If <var>property</var> follows the <<custom-property-name>> production,
    return <var>property</var>.

1.  If <var>property</var> refers to the CSS 'float' property,
    return the string "cssFloat".

1.  If <var>property</var> refers to the CSS 'offset' property,
    return the string "cssOffset".

1.  Otherwise, return the result of applying the <a>CSS property to IDL
    attribute</a> algorithm [[!CSSOM]] to <var>property</var>.

The <dfn>IDL attribute name to animation property name</dfn> algorithm for
<var>attribute</var> is as follows:

1.  If <var>attribute</var> conforms to the <<custom-property-name>> production,
    return <var>attribute</var>.

1.  If <var>attribute</var> is the string "cssFloat", then return
    an animation property representing the CSS 'float' property.

1.  If <var>attribute</var> is the string "cssOffset", then return
    an animation property representing the CSS 'offset' property.

1.  Otherwise, return the result of applying the <a>IDL attribute to CSS
    property</a> algorithm [[!CSSOM]] to <var>attribute</var>.

<h4 id="processing-a-keyframes-argument">Processing a <code>keyframes</code>
argument</h4>

<div class='informative-bg'><em>This section is non-normative</em>

The following methods all accept a set of keyframes as an argument:

*   the {{KeyframeEffect(target, keyframes, options)}} constructor,
*   the {{KeyframeEffect/setKeyframes()}} method on the {{KeyframeEffect}}
    interface,
*   the {{Animatable/animate()}} method of the {{Animatable}} interface mixin.

This argument may be specified in the one of two forms as illustrated below.

<div class='example'>
<pre class='lang-javascript'>
// The following two expressions produce the same result:
elem.animate([ { color: 'blue' },
               { color: 'green' },
               { color: 'red' },
               { color: 'yellow' } ], 2000);
elem.animate({ color: [ 'blue', 'green', 'red', 'yellow' ] }, 2000);

// Likewise, for a multi-property animation, the following two
// expressions are equivalent:
elem.animate([ { color: 'blue', left: '0px' },
               { color: 'green', left: '-20px' },
               { color: 'red', left: '100px' },
               { color: 'yellow', left: '50px'} ], 2000);
elem.animate({ color: [ 'blue', 'green', 'red', 'yellow' ],
               left: [ '0px', '-20px', '100px', '50px' ] }, 2000);

// Incidentally, the following three expressions are all equivalent:
elem.animate([ { color: 'red' } ], 1000);
elem.animate({ color: [ 'red' ] }, 1000);
elem.animate({ color: 'red' }, 1000);
</pre>
</div>

The first form (the array-form) consists of an array of keyframes where each
keyframe may specify at most one value per animation property.
The second form (the object-form) consists of an object where each animation
property may specify a single animation value or an array of animation values.

The first array-form is the canonical form and is the form returned by the
{{KeyframeEffect/getKeyframes()}} method.

<a>Keyframe offsets</a> can be specified using either form as illustrated below:

<div class='example'>
<pre class='lang-javascript'>
// The keyframes without offsets will automatically have offsets computed
// as 0 for the first keyframe, 0.65 for the middle keyframe, and 1 for the
// final keyframe.
elem.animate([ { color: 'blue' },
               { color: 'green', offset: 0.5 },
               { color: 'red' },
               { color: 'yellow', offset: 0.8 },
               { color: 'pink' } ], 2000);

// The following produces the same result. Note that it is not necessary to
// specify the last value: it will automatically be treated as 'null' and then
// the automatic assignment will apply as with the previous case.
elem.animate({ color: [ 'blue', 'green', 'red', 'yellow', 'pink' ],
               offset: [ null, 0.5, null, 0.8 ] }, 2000);
</pre>
</div>

Likewise <a>timing functions</a> and <a>keyframe-specific composite
operations</a> may be specified in either form. The array-form allows
specifying different values for each <a>keyframe</a> whilst for the object-form,
the list of values will be repeated as needed until each keyframe has been
assigned a value.

<div class='example'>
<pre class='lang-javascript'>
// Since timing functions apply _between_ keyframes, even if we specify a
// a timing function on the last keyframe it will be ignored.
elem.animate([ { color: 'blue', easing: 'ease-in' },
               { color: 'green', easing: 'ease-out' },
               { color: 'yellow' } ], 2000);

// The following produces the same result.
elem.animate({ color: [ 'blue', 'green', 'yellow' ],
               easing: [ 'ease-in', 'ease-out' ] }, 2000);

// The repeating behavior makes assigning the same value to all keyframes
// simple:
elem.animate({ color: [ 'blue', 'green', 'yellow' ],
               easing: 'ease-in-out' }, 2000);
</pre>
</div>

Note that the <code>easing</code> property in either form sets the
<em>keyframe-specific </a>timing function</a></em>.
This is independent from the <a>timing function</a> that applies to the
entire <a>iteration duration</a> of the <a>keyframe effect</a> as specified
using a {{KeyframeEffectOptions}} object (or {{KeyframeAnimationOptions}}
object when using the {{Animatable/animate()}} method of the {{Animatable}}
interface mixin).

In the following example, the two statements produce different results.

<div class='example'>
<pre class='lang-javascript'>
// Here, 'ease-in-out' is applied between each color value.
elem.animate({ color: [ 'blue', 'green', 'yellow' ],
               easing: 'ease-in-out' }, 2000);

// However, in this case, 'ease-in-out' is applied across the whole span
// of the animation, that is from 'blue' to 'yellow'.
elem.animate({ color: [ 'blue', 'green', 'yellow' ] },
             { duration: 2000, easing: 'ease-in-out' });
</pre>
</div>

The type of the <code>keyframes</code> argument cannot be expressed in WebIDL
since it relies on a partially-open dictionary type.

Conceptually, the type of this argument is equivalent to the following
WebIDL-like definition:

<pre class='lang-idl'>
dictionary Keyframe {
    // ... property-value pairs ...
    // i.e. DOMString propertyName
    double?                   offset = null;
    DOMString                 easing = "linear";
    CompositeOperationOrAuto  composite = "auto";
};

dictionary PropertyIndexedKeyframes {
    // ... property-value and property-valuelist pairs ...
    // i.e. (DOMString or sequence&amp;lt;DOMString&amp;gt;) propertyName
    (double? or sequence&lt;double?&gt;)                         offset = [];
    (DOMString or sequence&lt;DOMString&gt;)                     easing = [];
    (CompositeOperationOrAuto or sequence&lt;CompositeOperationOrAuto&gt;) composite = [];
};

typedef (sequence&lt;Keyframe&gt; or PropertyIndexedKeyframes) KeyframeArgument;
</pre>

The meaning and allowed values of each argument is as follows:

:   offset
::  The <a>keyframe offset</a> of the <a>keyframe</a> specified as
    a number between 0.0 and 1.0 inclusive or <code>null</code>.

    A <code>null</code> value indicates that the <a>keyframe</a>
    should be automatically spaced between adjacent keyframes.

    Specifying an offset outside the range [0.0, 1.0] will cause
    a <span class=exceptionname>TypeError</span> to be thrown.

    Keyframes that specify an offset must be provided in increasing
    order of offset. Adjacent and equal offsets, however, are permitted.

:   easing
::  The <a>timing function</a> used to transform the progress of time
    from this keyframe until the next keyframe in the series.

    The syntax and error-handling associated with parsing this string
    is identical to that defined for the {{EffectTiming/easing}} attribute
    of the {{EffectTiming}} interface.

:   composite
::  The <a>keyframe-specific composite operation</a> used to combine the values
    specified in this keyframe with the <a>underlying value</a>.

    If {{CompositeOperationOrAuto/auto}}, the <a>composite operation</a>
    specified on the <a>keyframe effect</a> will be used.


Since this type cannot be expressed in WebIDL, its processing is defined in
prose following.
</div>

For each method that takes a <code>keyframes</code> argument, the
procedure to <a>process a keyframes argument</a> is run on the input and
the result of that procedure is retained.

First we define two supporting definitions.

The instruction, <dfn>check the completion record</dfn> of <var>result</var>,
where <var>result</var> is a <a
lt="completion record specification type">completion record</a> from calling
an ECMAScript operation, is equivalent to the following steps:

1.  If <var>result</var> is an <a
    lt="completion record specification type">abrupt completion</a>,
    <a>throw</a> the exception contained in the \[[value]] field of
    <var>result</var> and abort the procedure.

    Issue: What should we do if the \[[type]] is
    <span class=esvalue>break</span>, <span class=esvalue>continue</span>, or
    <span class=esvalue>return</span>? Can it be?

1.  Replace <var>result</var> with the value contained in the \[[value]] field
    of <var>result</var>.

The procedure to <dfn>process a keyframe-like object</dfn>, takes two
arguments:

* an ECMAScript object, <var>keyframe input</var>, and
* an <var>allow lists</var> boolean flag

and returns a map from either property names to DOMString values if <var>allow
lists</var> is false, or from property names to sequences of DOMString values
otherwise, using the following procedure:

1.  Run the procedure to <a lt="es to dictionary">convert an ECMAScript
    value to a dictionary type</a> [[!WEBIDL]] with <var>keyframe input</var>
    as the ECMAScript value, and the dictionary type depending on the value of
    the <var>allow lists</var> flag as follows:

    <div class='switch'>
    :   If <var>allow lists</var> is true,
    ::  Use the following dictionary type:

        <pre class='idl'>
        dictionary BasePropertyIndexedKeyframe {
            (double? or sequence&lt;double?&gt;)                         offset = [];
            (DOMString or sequence&lt;DOMString&gt;)                     easing = [];
            (CompositeOperationOrAuto or sequence&lt;CompositeOperationOrAuto&gt;) composite = [];
        };
        </pre>

    :   Otherwise,
    ::  Use the following dictionary type,

        <pre class='idl'>
        dictionary BaseKeyframe {
            double?                  offset = null;
            DOMString                easing = "linear";
            CompositeOperationOrAuto composite = "auto";
        };
        </pre>

    </div>

    Store the result of this procedure as <var>keyframe output</var>.

1.  Build up a list of <var>animatable properties</var> as follows:

    1.  Let <var>animatable properties</var> be a list of property
        names (including shorthand properties that have longhand sub-properties
        that are animatable) that can be animated by the implementation.
    1.  Convert each property name in <var>animatable properties</var>
        to the equivalent IDL attribute by applying the
        <a>animation property name to IDL attribute name</a> algorithm.

1.  Let <var>input properties</var> be the result of calling the
    <a>EnumerableOwnNames</a> operation with <var>keyframe input</var> as
    the object.

1.  Make up a new list <var>animation properties</var> that consists of
    all of the properties that are in <em>both</em> <var>input
    properties</var> and <var>animatable properties</var>, <em>or</em>
    which are in <var>input properties</var> and conform to the
    <<custom-property-name>> production.

1.  Sort <var>animation properties</var> in ascending order by the Unicode
    codepoints that define each property name.

1.  For each <var>property name</var> in <var>animation properties</var>,

    1.  Let <var>raw value</var> be the result of calling the <a>\[[Get]]</a>
        internal method on <var>keyframe input</var>, with <var>property
        name</var> as the property key and <var>keyframe input</var> as the
        receiver.

    1.  <a>Check the completion record</a> of <var>raw value</var>.

    1.  Convert <var>raw value</var> to a DOMString or sequence of DOMStrings
        <var>property values</var> as follows:

        <div class="switch">
        :   If <var>allow lists</var> is true,
        ::  Let <var>property values</var> be the result of converting <var>raw
            value</var> to IDL type <code>(DOMString or
            sequence&lt;DOMString&gt;)</code> using the <a
            lt="convert ECMAScript to IDL value">procedures
            defined for converting an ECMAScript value to an IDL value</a>
            [[!WEBIDL]].

            If <var>property values</var> is a single DOMString, replace
            <var>property values</var> with a sequence of DOMStrings with the
            original value of <var>property values</var> as the only element.

        :   Otherwise,
        ::  Let <var>property values</var> be the result of converting <var>raw
            value</var> to a DOMString using the <a
            lt="es to DOMString">procedure for converting an ECMAScript value to
            a DOMString</a> [[!WEBIDL]].

        </div>

    1.  Calculate the <var>normalized property name</var> as the result of
        applying the <a>IDL attribute name to animation property name</a>
        algorithm to <var>property name</var>.

    1.  Add a property to to <var>keyframe output</var> with <var>normalized
        property name</var> as the property name, and <var>property values</var>
        as the property value.

1.  Return <var>keyframe output</var>.

The procedure to <dfn>process a keyframes argument</dfn> takes a nullable
ECMAScript object, <var>object</var>, as input and returns a sequence of
keyframes using the following procedure:

1.  If <var>object</var> is null, return an empty sequence of keyframes.

1.  Let <var>processed keyframes</var> be an empty sequence of <a>keyframes</a>.

1.  Let <var>method</var> be the result of <a>GetMethod</a>(<var>object</var>,
    <a lt="well known symbols">@@iterator</a>).

1.  <a>Check the completion record</a> of <var>method</var>.

1.  Perform the steps corresponding to the first matching condition from below,

    <div class="switch">
    :   If <var>method</var> is not <span class="esvalue">undefined</span>,
    ::  1.  Let <var>iter</var> be <a>GetIterator</a>(<var>object</var>,
            <var>method</var>).

        1.  <a>Check the completion record</a> of <var>iter</var>.

        1.  Repeat:

            1.  Let <var>next</var> be <a>IteratorStep</a>(<var>iter</var>).
            1.  <a>Check the completion record</a> of <var>next</var>.
            1.  If <var>next</var> is false abort this loop.
            1.  Let <var>nextItem</var> be <a>IteratorValue</a>(next).
            1.  <a>Check the completion record</a> of <var>nextItem</var>.
            1.  If [=Type=](|nextItem|) is not Undefined, Null or Object, then
                throw a <span class=exceptionname>TypeError</span> and abort
                these steps.
            1.  Append to <var>processed keyframes</var> the result of
                running the procedure to <a>process a keyframe-like object</a>
                passing <var>nextItem</var> as the <var>keyframe input</var>
                and with the <var>allow lists</var> flag set to false.

    :   Otherwise,
    ::  1.  Let <var>property-indexed keyframe</var> be the result of
            running the procedure to <a>process a keyframe-like object</a>
            passing <var>object</var> as the <var>keyframe input</var>
            and with the <var>allow lists</var> flag set to true.

        1.  For each member, <var>m</var>, in <var>property-indexed
            keyframe</var>, perform the following steps:

            1.  Let <var>property name</var> be the key for <var>m</var>.

            1.  If <var>property name</var> is &ldquo;composite&rdquo;, or
                &ldquo;easing&rdquo;, or &ldquo;offset&rdquo;, skip the
                remaining steps in this loop and continue from the next member
                in <var>property-indexed keyframe</var> after <var>m</var>.

            1.  Let <var>property values</var> be the value for <var>m</var>.

            1.  Let <var>property keyframes</var> be an empty sequence of
                <a>keyframes</a>.

            1.  For each value, <var>v</var>, in <var>property values</var>
                perform the following steps:

                1.  Let <var>k</var> be a new <a>keyframe</a> with a null
                    <a>keyframe offset</a>.

                1.  Add the property-value pair, <var>property name</var>
                    &rarr; <var>v</var>, to <var>k</var>.

                1.  Append <var>k</var> to <var>property keyframes</var>.

            1.  Apply the procedure to <a>compute missing keyframe
                offsets</a> to <var>property keyframes</var>.

            1.  Add <a>keyframes</a> in <var>property keyframes</var> to
                <var>processed keyframes</var>.

        1.  Sort <var>processed keyframes</var> by the <a>computed
            keyframe offset</a> of each <a>keyframe</a> in increasing order.

        1.  Merge adjacent <a>keyframes</a> in <var>processed keyframes</var>
            when they have equal <a>computed keyframe offsets</a>.

        1.  Let <var>offsets</var> be a sequence of <a>nullable</a>
            <code>double</code> values assigned based on the type of the
            &ldquo;offset&rdquo; member of the <var>property-indexed
            keyframe</var> as follows:

            <div class="switch">

            :   <code>sequence&lt;double?&gt;</code>,
            ::  The value of &ldquo;offset&rdquo; as-is.

            :   <code>double?</code>,
            ::  A sequence of length one with the value of &ldquo;offset&rdquo;
                as its single item, i.e.
                &laquo;&nbsp;<code>offset</code>&nbsp;&raquo;,

            </div>

        1.  Assign each value in <var>offsets</var> to the <a>keyframe
            offset</a> of the <a>keyframe</a> with corresponding position in
            <var>processed keyframes</var> until the end of either sequence is
            reached.

        1.  Let <var>easings</var> be a sequence of <code>DOMString</code>
            values assigned based on the type of the &ldquo;easing&rdquo; member
            of the <var>property-indexed keyframe</var> as follows:

            <div class="switch">

            :   <code>sequence&lt;DOMString&gt;</code>,
            ::  The value of &ldquo;easing&rdquo; as-is.

            :   <code>DOMString</code>,
            ::  A sequence of length one with the value of &ldquo;easing&rdquo;
                as its single item, i.e.
                &laquo;&nbsp;<code>easing</code>&nbsp;&raquo;,

            </div>

        1.  If <var>easings</var> is an empty sequence, let it be a sequence
            of length one containing the single value &ldquo;linear&rdquo;, i.e.
            &laquo;&nbsp;"linear"&nbsp;&raquo;.

        1.  If <var>easings</var> has fewer items than <var>processed
            keyframes</var>, repeat the elements in <var>easings</var>
            successively starting from the beginning of the list until
            <var>easings</var> has as many items as <var>processed
            keyframes</var>.

            <div class=example>
            For example, if <var>processed keyframes</var> has
            five items, and <var>easings</var> is the sequence
            &laquo;&nbsp;"ease-in", "ease-out"&nbsp;&raquo;,
            <var>easings</var> would be repeated to become
            &laquo;&nbsp;"ease-in", "ease-out", "ease-in", "ease-out",
            "ease-in"&nbsp;&raquo;.
            </div>

        1.  If <var>easings</var> has more items than <var>processed
            keyframes</var>, store the excess items as <var>unused
            easings</var>.

        1.  Assign each value in <var>easings</var> to a property named
            &ldquo;easing&rdquo; on the <a>keyframe</a> with the corresponding
            position in <var>processed keyframes</var> until the end of
            <var>processed keyframes</var> is reached.

        1.  If the &ldquo;composite&rdquo; member of the <var>property-indexed
            keyframe</var> is <em>not</em> an empty sequence:

            1.  Let <var>composite modes</var> be a sequence of
                {{CompositeOperationOrAuto}} values assigned from the
                &ldquo;composite&rdquo; member of <var>property-indexed
                keyframe</var>.
                If that member is a single {{CompositeOperationOrAuto}} value
                operation</a>, let <var>composite modes</var> be a sequence of
                length one, with the value of the &ldquo;composite&rdquo; as its
                single item.

            1.  As with <var>easings</var>, if <var>composite modes</var>
                has fewer items than <var>processed keyframes</var>, repeat the
                elements in <var>composite modes</var> successively starting
                from the beginning of the list until <var>composite modes</var>
                has as many items as <var>processed keyframes</var>.

            1.  Assign each value in <var>composite modes</var> that is not
                {{CompositeOperationOrAuto/auto}} to the
                <a>keyframe-specific composite operation</a> on the
                <a>keyframe</a> with the corresponding position in
                <var>processed keyframes</var> until the end of <var>processed
                keyframes</var> is reached.

    </div>

1.  If <var>processed keyframes</var> is not <a>loosely sorted by
    offset</a>, <a>throw</a> a <span
    class=exceptionname>TypeError</span> and abort these steps.

1.  If there exist any <a>keyframe</a> in <var>processed keyframes</var>
    whose <a>keyframe offset</a> is non-null and less
    than zero or greater than one, <a>throw</a> a
    <span class=exceptionname>TypeError</span> and abort these steps.

1.  For each <var>frame</var> in <var>processed keyframes</var>, perform the
    following steps:

    1.  For each property-value pair in <var>frame</var>, parse the property
        value using the syntax specified for that property.

        If the property value is invalid according to the syntax for the
        property, discard the property-value pair.
        User agents that provide support for diagnosing errors in content
        SHOULD produce an appropriate warning highlighting the invalid
        property value.

    1.  Let the <a>timing function</a> of <var>frame</var> be the result of
        parsing the &ldquo;easing&rdquo; property on <var>frame</var> using the
        CSS syntax defined for the {{EffectTiming/easing}} member of the
        {{EffectTiming}} dictionary.

        If parsing the &ldquo;easing&rdquo; property fails, <a>throw</a> a
        <span class=exceptionname>TypeError</span> and abort this procedure.

        Note: Using the CSS parser in both of the above steps implies that CSS
        comments and escaping are allowed but are not retained when the value
        is successfully parsed.

        Note: In the case where the &ldquo;easing&rdquo; property fails to
        parse, it is important that the <span
        class=exceptionname>TypeError</span> is thrown <em>after</em> all
        reading the properties from <var>object</var> since failing to do so
        would be observable and will not match the behavior if partially
        open-ended dictionaries are later supported in WebIDL.

1.  Parse each of the values in <var>unused easings</var> using the CSS syntax
    defined for {{EffectTiming/easing}} member of the {{EffectTiming}}
    interface, and if any of the values fail to parse, <a>throw</a> a <span
    class=exceptionname>TypeError</span> and abort this procedure.

    <div class="note">

    This final step is required in order to provide consistent behavior such
    that a <span class=exceptionname>TypeError</span> is thrown in all of the
    following cases:

    <pre class='lang-javascript'>
elem.animate({ easing: 'invalid' });
elem.animate({ easing: ['invalid'] });
elem.animate([{ easing: 'invalid' }]);
    </pre>

    </div>

### The <code>KeyframeEffectOptions</code> dictionary ### {#the-keyframeeffectoptions-dictionary}

Additional parameters may be passed to the {{KeyframeEffect(target, keyframes,
options)}} constructor by providing a {{KeyframeEffectOptions}} object.

<pre class='idl'>
dictionary KeyframeEffectOptions : EffectTiming {
    CompositeOperation composite = "replace";
    CSSOMString?       pseudoElement = null;
};
</pre>

<div class="members">

:   <dfn dict-member for=KeyframeEffectOptions>composite</dfn>
::  The <a>composite operation</a> used to composite this
    animation with the <a>effect stack</a>, as specified by one
    of the <a>CompositeOperation</a> enumeration values.
    This is used for all <a>keyframes</a> that specify
    a {{CompositeOperationOrAuto/auto}} <a>keyframe-specific composite
    operation</a>.

:   <dfn dict-member for=KeyframeEffectOptions>pseudoElement</dfn>
::  The [=pseudo-element=] selector (which must be valid or `null`)
    used to specify the [=effect target=] given the [=target element=].

</div>

The <code>CompositeOperation</code> and <code>CompositeOperationOrAuto</code> enumerations {#the-compositeoperation-enumeration}
----------------------------------------

The possible values of an <a>keyframe effect</a>'s
composition behavior are represented by the
<dfn>CompositeOperation</dfn> enumeration.

<pre class='idl'>
enum CompositeOperation { "replace", "add", "accumulate" };
</pre>

:   <dfn enum-value for="CompositeOperation,CompositeOperationOrAuto">replace</dfn>
::  Corresponds to the <a
    lt="composite operation replace">replace</a>
    <a>composite operation</a> value such that
    the <a>animation effect</a> overrides the <a>underlying value</a> it
    is combined with.

:   <dfn enum-value for="CompositeOperation,CompositeOperationOrAuto">add</dfn>
::  Corresponds to the <a
    lt="composite operation add">add</a>
    <a>composite operation</a> value such that
    the <a>animation effect</a> is <a
    lt="value addition">added</a> to the <a>underlying value</a>
    with which it is combined.

:   <dfn enum-value for="CompositeOperation,CompositeOperationOrAuto">accumulate</dfn>
::  Corresponds to the <a
    lt="composite operation accumulate">accumulate</a>
    <a>composite operation</a> value such that
    the <a>animation effect</a> is <a
    lt="value accumulation">accumulated</a> on to the
    <a>underlying value</a>.

The possible values of a [=keyframe=]'s composition behavior share the same
values as the {{CompositeOperation}} enumeration along with the additional
{{CompositeOperationOrAuto/auto}} value.

<pre class='idl'>
enum CompositeOperationOrAuto { "replace", "add", "accumulate", "auto" };
</pre>

:   <dfn enum-value for=CompositeOperationOrAuto>auto</dfn>
::  Indicates that the [=composite operation=] of the associated [=keyframe
    effect=] should be used.

The <code>Animatable</code> interface mixin {#the-animatable-interface-mixin}
----------------------------------------

Objects that may be the target of an {{KeyframeEffect}} object implement
the {{Animatable}} interface mixin.

<pre class='idl'>
interface mixin Animatable {
    Animation           animate(object? keyframes,
                                optional (unrestricted double or KeyframeAnimationOptions) options = {});
    sequence&lt;Animation&gt; getAnimations(optional GetAnimationsOptions options = {});
};

dictionary KeyframeAnimationOptions : KeyframeEffectOptions {
    DOMString id = "";
};

dictionary GetAnimationsOptions {
    boolean subtree = false;
};
</pre>

<div class="methods">

:   <dfn method for=Animatable lt="animate(keyframes, options)">Animation animate(keyframes, options)</dfn>
::  Performs the following steps:

    1.  Let <var>target</var> be the object on which this method was called.

    1.  Construct a new {{KeyframeEffect}} object, <var>effect</var>,
        in the <a>relevant Realm</a> of <var>target</var> by using the same
        procedure as the {{KeyframeEffect(target, keyframes,
        options)}} constructor, passing <var>target</var> as the
        <var>target</var> argument, and the <var>keyframes</var> and
        <var>options</var> arguments as supplied.

        If the above procedure causes an exception to be thrown, propagate the
        exception and abort this procedure.

    1.  Construct a new {{Animation}} object, <var>animation</var>, in
        the <a>relevant Realm</a> of <var>target</var> by using the
        same procedure as the {{Animation()}} constructor, passing
        <var>effect</var> as the argument of the same name, and
        the <a>default document timeline</a> of the <a>node document</a>
        of the element on which this method was called as the
        <var>timeline</var> argument.

    1.  If <var>options</var> is a {{KeyframeAnimationOptions}} object,
        assign the value of the <code>id</code> member of <var>options</var> to
        <var>animation</var>'s {{Animation/id}} attribute.

    1.  Run the procedure to <a>play an animation</a> for
        <var>animation</var> with the <var>auto-rewind</var> flag set to true.

    1.  Return <var>animation</var>.

    <div class="informative-bg"><em>This section is non-normative</em>

    The following code fragment:

    <pre class="lang-javascript">
var animation = elem.animate({ opacity: 0 }, 2000);</pre>

    is roughly equivalent to:

    <pre class="lang-javascript">
var effect = new KeyframeEffect(elem, { opacity: 0 }, 2000);
var animation = new Animation(effect, elem.ownerDocument.timeline);
animation.play();</pre>

    </div>

    <div class="parameters">

    :   <dfn argument for="Animatable/animate(keyframes, options)"
        lt="keyframes">keyframes</dfn>
    ::  The <a>keyframes</a> to use.
        This value is passed to the {{KeyframeEffect(target, keyframes,
        options)}} constructor as the <var>keyframes</var> parameter and has the
        same interpretation as defined for that constructor.
    :   <dfn argument for="Animatable/animate(keyframes, options)"
        lt="options">options</dfn>
    ::  The timing and animation options for the created {{KeyframeEffect}}.
        This value is passed to the {{KeyframeEffect(target, keyframes,
        options)}} constructor as the <var>options</var> parameter and has the
        same interpretation as defined for that constructor.

    </div>

:   <dfn method for=Animatable lt="getAnimations(options)">
    sequence&lt;Animation&gt; getAnimations(options)</dfn>
::  Returns the set of [=relevant=] {{Animation}} objects
    that contain at least one <a>animation effect</a> whose
    [=effect target=] is this object, or,
    if an {{Animatable/getAnimations(options)/options}} parameter
    is passed with {{GetAnimationsOptions/subtree}} set to true,
    an [=inclusive descendant=] of this object or a [=pseudo-element=]
    of such a descendant.

    An [=animation=] is
    <dfn lt="relevant animation" local-lt="relevant">relevant</dfn> if:

    * Its [=associated effect=] is [=current=] <em>or</em> [=in effect=],
        <em>and</em>
    * Its [=replace state=] is <em>not</em> [=removed replace state|removed=].

    For the purposes of this method
    a [=pseudo-element=] is considered to be
    a [=child=] of its [=originating element=].

    The returned list is sorted using the composite order described
    for the associated <a>animations</a> of effects in [[#the-effect-stack]].

    Calling this method triggers a [=style change event=] for the <a>target
    element</a>.
    As a result, the returned list reflects the state <em>after</em> applying
    any pending style changes to animation such as changes to animation-related
    style properties that have yet to be processed.

    <div class="parameters">

    :   <dfn argument for="Animatable/getAnimations(options)"
        lt="options">options</dfn>
    ::  Parameters governing the set of animations returned by
        {{Animatable/getAnimations()}}.

    </div>

</div>

<div class="members">

:   <dfn dict-member for=KeyframeAnimationOptions>id</dfn>
::  The string to assign to the generated {{Animation}}'s {{Animation/id}}
    attribute.

:   <dfn dict-member for=GetAnimationsOptions>subtree</dfn>
::  If true, indicates that [=animations=] associated with an
    [=animation effect=] whose [=target element=] is a [=descendant=]
    of the object on which {{Animatable/getAnimations()}} is called should also
    be included in the result.

</div>

Extensions to the <code>Document</code> interface {#extensions-to-the-document-interface}
----------------------------------------

The following extensions are made to the {{Document}} interface defined in
[[!DOM]].

<pre class="idl">
partial interface Document {
    readonly attribute DocumentTimeline timeline;
};
</pre>

<div class="attributes">

:   <dfn attribute for=Document>timeline</dfn>
::  The {{DocumentTimeline}} object representing
    the <a>default document timeline</a>.

</div>

Extensions to the <code>DocumentOrShadowRoot</code> interface mixin {#extensions-to-the-documentorshadowroot-interface-mixin}
----------------------------------------

The following extensions are made to the {{DocumentOrShadowRoot}} interface
mixin defined in [[!DOM]].

<pre class="idl">
partial interface mixin DocumentOrShadowRoot {
    sequence&lt;Animation&gt; getAnimations();
};
</pre>

<div class="methods">

:   <dfn method for=DocumentOrShadowRoot lt='getAnimations()'>
    sequence&lt;Animation&gt; getAnimations()</dfn>
::  Returns the set of [=relevant=] {{Animation}} objects
    that have an associated <a>associated effect</a>
    whose <a>target element</a> is a <a>descendant</a> of
    the [=document=] or [=shadow root=]
    on which this method is called.

    The returned list is sorted using the composite order described
    for the associated <a>animations</a> of effects in [[#the-effect-stack]].

    Calling this method triggers a [=style change event=] for the document.
    As a result, the returned list reflects the state <em>after</em> applying
    any pending style changes to animation such as changes to animation-related
    style properties that have yet to be processed.

</div>


Extensions to the <code>Element</code> interface {#extensions-to-the-element-interface}
----------------------------------------

Since DOM Elements may be the target of an animation,
the {{Element}} interface [[!DOM]] is extended as follows:

<pre class="idl">
Element includes Animatable;
</pre>

This allows the following kind of usage.

<div class="example"><pre class="lang-javascript">
elem.animate({ color: 'red' }, 2000);</pre></div>


The <code>AnimationPlaybackEvent</code> interface {#the-animationplaybackevent-interface}
----------------------------------------

<a>Animation playback events</a> are represented using the
{{AnimationPlaybackEvent}} interface.

<pre class='idl'>
[Exposed=Window]
interface AnimationPlaybackEvent : Event {
    constructor(DOMString type, optional AnimationPlaybackEventInit eventInitDict = {});
    readonly attribute double? currentTime;
    readonly attribute double? timelineTime;
};
dictionary AnimationPlaybackEventInit : EventInit {
    double? currentTime = null;
    double? timelineTime = null;
};
</pre>

<div class="constructors">

:   <dfn constructor for=AnimationPlaybackEvent
    lt="AnimationPlaybackEvent(type, eventInitDict)">
    AnimationPlaybackEvent(type, eventInitDict)</dfn>
::  Constructs a new {{AnimationPlaybackEvent}} object using the procedure
    defined for <a>constructing events</a> [[!DOM]].

</div>

<div class="attributes">

:   <dfn attribute for=AnimationPlaybackEvent>currentTime</dfn>
::  The [=current time=] of the [=animation=] that generated the event at the
    moment the event as queued.
    This will be <code class=esvalue>null</code> if the [=animation=] was <a
    lt="idle play state">idle</a> at the time the event was generated.
:   <dfn attribute for=AnimationPlaybackEvent>timelineTime</dfn>
::  The [=time value=] of the [=timeline=] with which the [=animation=] that
    generated the event is associated at the moment the event was queued.
    This will be <code class=esvalue>null</code> if the [=animation=] was not
    associated with an <a lt="inactive timeline">active timeline</a> at the
    time the event was queued.

</div>

<div class="members">

:   <dfn dict-member for=AnimationPlaybackEventInit>currentTime</dfn>
::  See the description of the {{AnimationPlaybackEvent/currentTime}} attribute.
:   <dfn dict-member for=AnimationPlaybackEventInit>timelineTime</dfn>
::  See the description of the {{AnimationPlaybackEvent/timelineTime}}
    attribute.

</div>

Model liveness {#model-liveness}
----------------------------------------

Changes made to any part of the model, cause the entire timing model to be
updated and any dependent style.

Unless otherwise stated,
invoking the methods or constructors,
or getting or setting the members
of interfaces defined in the programming interface section of this specification
does <em>not</em> produce a [=style change event=].

Note: Other specifications that extend this specification are expected to refine
the requirements on [=style change events=] by introducing circumstances where
such events <em>are</em> triggered.
For example,
when the interfaces in this specification represent
animations defined by CSS markup,
many of their methods will need to trigger [=style change events=]
in order to reflect changes to the specified style.

<div class="informative-bg"><em>This section is non-normative</em>

Based on the above requirement and normative requirements elsewhere
in this specification, the following invariants can be observed:

:   Changes made to the Web Animations model take effect immediately

::  For example, if the {{KeyframeEffect}}
    associated with an {{Animation}} is seeked (see
    [[#setting-the-current-time-of-an-animation]]) via the programming
    interface, the value returned when querying the
    animation's <code>startTime</code> will reflect updated state of
    the model immediately.

    <div class="example">
    <pre class="lang-javascript">
// Initially animation.effect.getComputedTiming().localTime is 3000
animation.currentTime += 2000;
alert(animation.effect.getComputedTiming().localTime); // Displays &lsquo;5000&rsquo;</pre>
     </div>

:   Querying the computed style of a property affected by animation
    returns the fully up-to-date state of the animation

::  For example, if the used style of an element is queried
    immediately after applying a new {{Animation}} to that
    element, the result of the new animation will be
    incorporated in the value returned.

    <div class="example">
    <pre class="lang-javascript">
// Set opacity to 0 immediately
elem.animate({ opacity: 0 }, { fill: 'forwards' });
alert(window.getComputedStyle(elem).opacity); // Displays &lsquo;0&rsquo;</pre>
    </div>

:   Changes made within the same task are synchronized such
    that the whole set of changes is rendered together

::  As a result of changes to the model taking effect immediately
    combined with ECMAScript's run-to-completion semantics,
    there should never be a situation where, for example,
    <em>only</em> the changes to specified style are rendered without
    applying animation.

    <div class="example">
    <pre class="lang-javascript">
// Fade the opacity with fallback for browsers that don't
// support Element.animate
elem.style.opacity = '0';
elem.animate([ { opacity: 1 }, { opacity: 0 } ], 500);</pre>
    </div>

    Note, however, that in the example above, a user agent may render a
    frame with <em>none</em> of the above changes applied.
    This might happen, for example, if rendering occurs in
    a separate process that is scheduled to run shortly after
    the above task completes but before the changes
    can be communicated to the process.

:   The value returned by the <code>currentTime</code> attribute of
    a <a>document timeline</a> will not change within a task

::  Due to the requirement on <a>timelines</a> to update their <a
    lt="timeline current time">current time</a> each time the
    [=update animations and send events=] procedure is run,
    querying the <code>currentTime</code> twice within
    a long block of code that is executed in the same script block
    will return the same value as shown in the following example.

    <div class="example">
    <pre class="lang-javascript">
var a = document.timeline.currentTime;
// ... many lines of code ...
var b = document.timeline.currentTime;
alert(b - a); // Displays 0</pre>
    </div>

:   The time passed to a <code>requestAnimationFrame</code> callback
    will be equal to <code>document.timeline.currentTime</code>

::  Since HTML's <a>event loop processing model</a> defines that the procedure
    to [=update animations and send events=] is performed prior to
    <a lt="run the animation frame callbacks">running animation frame
    callbacks</a>, and since the time passed to such callbacks is the same
    |now| timestamp is passed to both procedures, the <a lt="timeline current
    time">current time</a> of a the <a>default document timeline</a> should
    match the time passed to <code>requestAnimationFrame</code>.

    <div class="example">
    <pre class="lang-javascript">
window.requestAnimationFrame(function(now) {
  // Displays 0
  alert(now - document.timeline.currentTime);
});</pre>
    </div>

:   Calling methods from this programming interface will generally
    <em>not</em> cause transitions to be triggered

::  Consider the following example:

    <div class="example">
    <pre class="lang-javascript">
// Setup transition start point
div.style.opacity = '1';
getComputedStyle(div).opacity;

// Setup transition end point
div.style.transition = 'opacity 1s';
div.style.opacity = '0';

// Fire an animation
div.animate({ opacity: [0.5, 1] }, 500);

// Wait for the transition to end -- the following will never be called!
div.addEventListener('transitionend', () => {
  console.log('transitionend');
});</pre>
    </div>

    In this case, calling {{Animatable/animate()}} will
    <em>not</em> trigger a [=style change event=].
    As a result, the pending style change will be processed at the same time
    as the style change resulting from the new animation.
    Since the animation style will override
    the [=before-change style=] and the [=after-change style=],
    no transition will be generated and
    the event handler for the [=transitionend=] event will never be called.

</div>


Integration with Media Fragments {#integration-with-media-fragments}
=======================================

The Media Fragments specification [[!MEDIA-FRAGS]] defines a means
for addressing a temporal range of a media resource.
The application of media fragments depends on the MIME type of the
resource on which they are specified.
For resources with the <a>SVG MIME type</a>
[[!SVG11]], the application of temporal parameters is defined in the <a
href="https://svgwg.org/specs/animation-elements/">
Animation Elements</a> specification.

Note: media fragments are defined to operate on resources based on
    their MIME type.
    As a result, temporal addressing may not be supported in all situations
    where Web Animations content is used.

Interaction with page display {#interaction-with-page-display}
=======================================

HTML permits user agents to store <a
lt="an entry with persisted user state">user-agent defined state</a> along with
a <a>session history entry</a> so that as a user navigates between pages, the
previous state of the page can be restored including state such as
scroll position [[HTML]].


User agents that pause and resume <a>media elements</a>
when the referencing document is unloaded and traversed,
are encouraged to apply consistent handling to documents containing Web
Animations content.
If provided, this behavior SHOULD be achieved by adjusting the <a>time
values</a> of any <a>timelines</a> that track wallclock time.

Issue(2083): Is this at odds with those <a>time values</a> being relative to
    <code>navigationStart</code> and with <code>requestAnimationFrame</code>
    using the same time as <code>document.timeline.currentTime</code>?


Implementation requirements {#implementation-requirements}
=======================================

Precision of time values {#precision-of-time-values}
----------------------------------------

The internal representation of time values is implementation dependent
however, it is RECOMMENDED that user agents be able to represent input
time values with microsecond precision so that a <a>time value</a> (which
nominally represents milliseconds) of 0.001 is distinguishable from 0.0.

Conformance criteria {#conformance-criteria}
----------------------------------------

This specification defines an abstract model for animation and, as
such, for user agents that do not support scripting, there are no
conformance criteria since there is no testable surface area.

User agents that do not support scripting, however, may implement
additional technologies defined in terms of this specification in
which case the definitions provided in this specification will form
part of the conformance criteria of the additional technology.

A <dfn export>conforming scripted Web Animations user agent</dfn> is a user
agent that implements the <abbr
title="Application Programming Interface">API</abbr> defined in
[[#programming-interface]].

Acknowledgements {#acknowledgements}
=======================================

Thank you to Steve Block, Michael Giuffrida, Ryan Seys, and Eric Willigers
for their contributions to this specification.

Thank you also to Michiel &ldquo;Pomax&rdquo; Kamermans for help with the
equations for a proposed smooth timing function although this feature
has been deferred to a subsequent specification.

Our deep gratitude goes out to <a
href="http://www.endemolshine.com.au">Southern Star
Animation</a> for their kind generosity and patience in introducing the
editors to the processes and techniques used producing broadcast
animations.

Changes since last publication {#changes-since-last-publication}
=======================================

The following changes have been made since the <a
  href="https://www.w3.org/TR/2018/WD-web-animations-1-20181011/">11 October
2018 Working Draft</a>:

*   Made the definition of a [=current=] [=animation effect=] incorporate the
    associated animation's [=playback rate=] (<a
    href="https://github.com/w3c/csswg-drafts/issues/3193">#3193</a>).
*   Updated the steps for resolving which properties to use when calculating
    [=computed keyframes=] when physical and logical properties are used.
*   Introduced steps for removing animations that have been overridden:
    [[#replacing-animations]].
    *   Added a new [=remove event=] to signal when this process occurs.
    *   Added corresponding IDL members to the {{Animation}} interface:
        {{Animation/replaceState}},
        {{Animation/onremove}},
        {{Animation/persist}}.
*   Added the {{Animation/commitStyles}} method to the {{Animation}} interface
    to allow preserving the result of an [=animation=] that has been removed.
*   Added an {{Animatable/getAnimations(options)/options}} parameter to the
    {{Animatable/getAnimations()}} method on the {{Animatable}} interface
    to allow fetching all animations on descendants of a particular element.
*   Moved the definition of {{DocumentOrShadowRoot/getAnimations()}} from the
    {{Document}} interface to the {{DocumentOrShadowRoot}} interface mixin
    so that it can be used with {{ShadowRoot}}s as well.

The <a
  href="https://github.com/w3c/csswg-drafts/commits/master/web-animations-1">changelog</a>
provides a more detailed history.


Appendix A: Animation types of existing properties {#animation-types}
=======================================

Typically the [=animation type=] of a property is included along with its
definition.
However, for some properties defined in older or very mature specifications
the [=animation type=] information is not included.
All such properties are assumed to have an [=animation type=] of
[=by computed value=] unless they are one of the exceptions listed below.

Animation of 'font-weight' {#animating-font-weight}
--------------------------

'font-weight' property values prior to level 4 are
[[css-values-4#combining-values|combined]] as follows:

*   [=Interpolated=] via discrete steps (multiples of 100).
    The interpolation happens in real number space as for <<number>>s
    and is converted to an integer by rounding to the nearest multiple of 100,
    with values halfway between multiples of 100 rounded towards positive
    infinity.

*   <a lt="value addition">Addition</a> of 'font-weight' values is defined as
    <var ignore>V<sub>result</sub></var> =
      <var ignore>V<sub>a</sub></var> + <var ignore>V<sub>b</sub></var>

Note: This definition is obsoleted by [[CSS-FONTS-4]] where
the requirement that a 'font-weight' value be a multiple of 100 is dropped.
At that point the [=animation type=] for 'font-weight' is simply
[=by computed value=].

Animation of 'visibility' {#animating-visibility}
-------------------------

For the 'visibility' property,
''visibility/visible'' is [=interpolated=] as a discrete step
where values of <var ignore>p</var> between 0 and 1
map to ''visibility/visible''
and other values of <var ignore>p</var> map to the closer endpoint;
if neither value is ''visibility/visible'' then [=discrete=] animation is used.

Animation of 'box-shadow' {#animating-shadow-lists}
-------------------------------

Animation the 'box-shadow' property follows the procedures for
[[css-values-4#combining-values|combining]]
<dfn export lt="combining shadow lists" local-lt="shadow lists">shadow lists</dfn>
as follows:

Each shadow in the list
(treating ''shadow/none'' as a 0-length list)
is interpolated component-wise as with [=by computed value=] behavior.
However, if both input shadows are ''shadow/inset''
or both input shadows are not ''shadow/inset'',
then the interpolated shadow must match the input shadows in that regard.
If any pair of input shadows has one ''shadow/inset''
and the other not ''shadow/inset'',
the entire shadow-list uses [=discrete=] animation.
If the lists of shadows have different lengths,
then the shorter list is padded at the end
with shadows whose color is ''transparent'',
all lengths are ''0'',
and whose ''shadow/inset'' (or not) matches the longer list.

<a lt="value addition">Addition</a> of two [=shadow lists=]
<var>V<sub>a</sub></var> and <var>V<sub>b</sub></var> is defined as <a>list</a>
concatenation such that <var ignore=''>V<sub>result</sub></var> is equal to
<var>V<sub>a</sub></var> <a lt="extend">extended</a> with
<var>V<sub>b</sub></var>.

<a lt="value accumulation">Accumulation</a> of [=shadow lists=] follows the
matching rules for interpolation above, performing addition on each component
according to its type, or falling back to [=discrete=] animation if the
''shadow/inset'' values do not match.
