Web Animations Level 2

Unofficial Proposal Draft,

This version:
https://w3c.github.io/web-animations/level-2/
Latest published version:
https://www.w3.org/TR/web-animations-1/
Version History:
https://github.com/w3c/web-animations/commits/master
Issue Tracking:
Inline In Spec
GitHub
Editors:
(Mozilla)
(Google Inc)
(Google Inc)
(Google Inc)
Participate:
Fix the text through GitHub
Join the ‘waapi’ channel on the Animation at Work slack
IRC: #webanimations on W3C’s IRC
Not Ready For Implementation

This spec is not yet ready for implementation. It exists in this repository to record the ideas and promote discussion.

Before attempting to implement this spec, please contact the editors.


Abstract

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.

Status of this document

1. Introduction

This section is non-normative

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.

1.1. Use cases

The Web Animations model is intended to provide the features necessary for expressing CSS Transitions [CSS3-TRANSITIONS], CSS Animations [CSS3-ANIMATIONS], 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.

// Wait until all animations have finished before removing the element
Promise.all(
  elem.getAnimations().map(animation => animation.finished)
).then(() => elem.remove());

Alternatively, applications may wish to query the playback state of animations without waiting.

const isAnimating = elem.getAnimations().some(
  animation => animation.playState === 'running'
);
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.

// Pause all existing animations in the document
document.getAnimations().forEach(
  animation => animation.pause()
);
Creating animations from script

While it is possible to use ECMAScript to perform animation using requestAnimationFrame [ANIMATION-TIMING], 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.

// Fade out quickly
elem.animate({ transform: 'scale(0)', opacity: 0 }, 300);
Animation debugging

In a complex application, it may be difficult to determine how an element arrived in its present state. The Web Animations programming interface may be used to inspect running animations to answer questions such as, “Why is the opacity of this element changing?”

// Print the id of any opacity animations on elem
elem.getAnimations().filter(
  animation =>
    animation.effect instanceof KeyframeEffectReadOnly &&
    animation.effect.getKeyframes().some(
      frame => frame.hasOwnProperty('opacity')
    )
).forEach(animation => console.log(animation.id));

Likewise, in order to fine tune animations, it is often necessary to reduce their playback rate and replay them.

// Slow down and replay any transform animations
elem.getAnimations().filter(
  animation =>
    animation.effect instanceof KeyframeEffectReadOnly &&
    animation.effect.getKeyframes().some(
      frame => frame.hasOwnProperty('transform')
    )
).forEach(animation => {
  animation.currentTime = 0;
  animation.playbackRate = 0.5;
});
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.

// Seek to the half-way point of an animation and check that the opacity is 50%
elem.getAnimations().forEach(
  animation =>
    animation.currentTime =
      animation.effect.getComputedTiming().delay +
      animation.effect.getComputedTiming().activeDuration / 2;
);
assert.strictEqual(getComputedStyle(elem).opacity, '0.5');

// Check that the loading screen is hidden after the animations finish elem.getAnimations().forEach( animation => animation.finish() ); // Wait one frame so that event handlers have a chance to run requestAnimationFrame(() => { assert.strictEqual( getComputedStyle(document.querySelector('#loading')).display, 'none'); });

1.2. Changes since level 1

This specification introduces the following changes compared to the previous level of this specification:

1.3. Relationship to other specifications

CSS Transitions [CSS3-TRANSITIONS], CSS Animations [CSS3-ANIMATIONS], 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 Timing control for script-based animations (commonly referred to as “requestAnimationFrame”) [ANIMATION-TIMING], 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 Timing control for script-based animations [ANIMATION-TIMING] 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].

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

2. Web Animations model overview

This section is non-normative

At a glance, the Web Animations model consists of two largely independent pieces, a timing model and an animation model. 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 iteration progress. The iteration index is also recorded since some animations vary each time they repeat.

Animation model

Takes the iteration progress values and iteration indices 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:

Overview of the operation of the Web Animations model.
Overview of the operation of the Web Animations model.
The current time is input to the timing model which produces an iteration progress value and an iteration index.
These parameters are used as input to the animation model which produces the values to apply.

For example, consider an animation that:

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.

3. Timing model

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

3.1. The timing model at a glance

This section is non-normative

Two features characterize the Web Animations timing model: it is stateless and it is hierarchical.

3.1.1. 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 sampled 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 sampled in reverse or even in a backwards and forwards pattern 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 programming interface 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 finishing behavior of animations means that dynamic changes to the end time of the media (target effect) of an animation may produce a different result depending on when the change occurs. This behavior is somewhat unfortunate but has been deemed intuitive and consistent with HTML. As a result, the model can only truly be described as stateless in the absence of dynamic changes to its timing properties.

Finally, each time the model is sampled, it can be considered to establish a temporary state. While this temporary state affects the values returned from the programming interface, it has no influence on the subsequent samples and hence does not conflict with the stateless qualities described above.

3.1.2. Hierarchical

The other characteristic feature of the Web Animations timing model is that time is inherited. Time begins with a monotonically increasing time source and cascades down a number of steps to each animation. At each step, time may be shifted backwards and forwards, scaled, reversed, paused, and repeated.

A hierarchy of timing nodes
A hierarchy of timing nodes. Each node in the tree derives its time from its parent node. At the root of the tree is the global clock.

A consequence of this hierarchical arrangement is that complex animation arrangements can be reversed, scheduled, accelerated and so on as a whole unit since the manipulations applied to the parent, cascade down to its descendants. Furthermore, since time has a common source, it is easy to synchronize animations.

3.2. Timing model concepts

In Web Animations, 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 time values. A time value is a real number which nominally represents a number of milliseconds from some moment. The connection between time values and wall-clock milliseconds may be obscured by any number of transformations applied to the value as it passes through the time hierarchy.

In the future we may have timelines that are based on UI gestures in which case the connection between time values and milliseconds will be weakened even further.

A time value may also be unresolved if, for example, a timing node is not in a state to produce a time value.

Periodically, the user agent will update the timing model in a process called sampling. On each sample the time values of each timing node are updated.

Further requirements on the frequency and sequencing of sampling are specified by HTML’s event loop processing model [HTML].

Note: HTML currently refers to a “run CSS animations and send events” operation but this should be understood to include sampling all animations covered by this specification, not only CSS animations. Furthermore, the now parameter passed to this operation is ignored in this specification since we define a more general model that supports timelines whose time origin is not relative to navigationStart.

3.3. The global clock

At the root of the Web Animations timing hierarchy is the global clock.

The global clock is a source of monotonically increasing time values unaffected by adjustments to the system clock. The time values produced by the global clock represent wall-clock milliseconds from an unspecified historical moment. Because the zero time of the global clock is not specified, the absolute values of the time values produced by the global clock are not significant, only their rate of change.

Note: The global clock is not exposed in the programming interface and nor is it expected to be exposed by markup. As a result, the moment from which global clock time values are measured, that is, the zero time of the clock, is implementation-dependent. One user agent may measure the number of milliseconds since the user agent was loaded whilst another may use the time when the device was started. Both approaches are acceptable and produce no observable difference in the output of the model.

3.4. Timelines

A timeline provides a source of time values for the purpose of synchronization.

Typically, a timeline is tied to the global clock such that its absolute time is calculated as a fixed offset from the time of the global clock. This offset is established by designating some moment as the timeline’s zero time and recording the time value of the global clock at that moment. At subsequent moments, the time value of the timeline is calculated as the difference between the current time value of the global clock and the value recorded as the zero time.

On each sample, the time value of the global clock at the beginning of the sample is recorded and this recorded value is used as the time value of the global clock until the next sample.

Note: We anticipate that other types of timelines may be introduced in the future that are not tied to the global clock. For example, a timeline whose time values are related to the progress of a scroll container or UI gesture.

Since a timeline may be defined relative to a moment that has yet to occur, it may not always be able to return a meaningful time value, but only an unresolved time value. A timeline is considered to be inactive when its time value is unresolved.

3.4.1. Document timelines

A document timeline is a type of timeline that is associated with a Document.

The time values of a document timeline are calculated as a fixed offset from the global clock such that the zero time corresponds to the navigationStart moment [NAVIGATION-TIMING] plus a signed delta known as the origin time. Prior to establishing the navigationStart moment, the document timeline is inactive.

A document timeline that is associated with a Document which is not an active document is also considered to be inactive.

3.4.2. The default document timeline

Each Document has a document timeline called the default document timeline. The default document timeline is unique to each document and persists for the lifetime of the document including calls to document.open() [HTML].

The default document timeline has an origin time of zero.

This section is non-normative

Since the document timelines are tied to the global clock by a fixed offset, time values reported by document timelines increase monotonically. Furthermore, since no scaling is applied, these time values are proportional to wall-clock milliseconds.

Since the time values of the default document timeline are relative to the navigationStart time, document.timeline.currentTime will roughly correspond to Performance.now() [HR-TIME] with the exception that document.timeline.currentTime does not change within a sample.

3.5. Animations

This section is non-normative

The children of a timeline are called animations. An animation takes an animation effect which is a static description of some timed behavior and binds it to a timeline so that it runs. An animation also allows run-time control of the connection between the animation effect and its timeline by providing pausing, seeking, and speed control. The relationship between an animation and an animation effect is analogous to that of a DVD player and a DVD.

An animation connects a single animation effect, called its target effect, to a timeline and provides playback control. Both of these associations are optional and configurable such that an animation may have no associated target effect or timeline at a given moment.

An animation’s start time is the time value of its timeline when its target effect is scheduled to begin playback. An animation’s start time is initially unresolved.

An animation also maintains a hold time time value which is used to fix the animation’s output time value, called its current time, in circumstances such as pausing. The hold time is initially unresolved.

In order to establish the relative ordering of conflicting animations, animations are appended to a global animation list in the order in which they are created. Certain classes of animations, however, may provide alternative means of ordering animations (see §4.5.1 Animation classes).

3.5.1. Setting the timeline of an animation

The procedure to set the timeline of an animation, animation, to new timeline which may be null, is as follows:

  1. Let old timeline be the current timeline of animation, if any.

  2. If new timeline is the same object as old timeline, abort this procedure.

  3. Let the timeline of animation be new timeline.

  4. If the animation start time of animation is resolved, make animation’s hold time unresolved.

    Note: This step ensures that the finished play state of animation is not “sticky” but is re-evaluated based on its updated current time.

  5. If new timeline is null, we should ensure that custom effects get called with an unresolved iteration progress (unless a subsequent change in the same script execution context makes this redundant).

  6. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.

3.5.2. Responding to a newly inactive timeline

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 timeline associated with an animation, animation, becomes newly inactive, if animation’s previous current time is resolved, the procedure to silently set the current time of animation to previous current time is run.

This step makes the behavior when an animation’s timeline becomes inactive consistent with when it is disassociated with a timeline. Furthermore, it ensures that the only occasion on which an animation becomes idle, is when the procedure to cancel an animation is performed.

3.5.3. Setting the target effect of an animation

The procedure to set the target effect of an animation, animation, to new effect which may be null, is as follows:

  1. Let old effect be the current target effect of animation, if any.

  2. If new effect is the same object as old effect, abort this procedure.

  3. If new effect is null and old effect is not null, run the procedure to reset an animation’s pending tasks on animation.

  4. If animation has a pending pause task, reschedule that task to run as soon as animation is ready.

  5. If animation has a pending play task, reschedule that task to run as soon as animation is ready to play new effect.

  6. If new effect is not null and if new effect has a parent group, remove new effect from its parent group.

  7. If new effect is not null and if new effect is the target effect of another animation, previous animation, run the procedure to set the target effect of an animation (this procedure) on previous animation passing null as new effect.

  8. Let the target effect of animation be new effect.

  9. If old effect is not null, queue a task to call any custom effects associated with inclusive descendants of old effect with an unresolved iteration progress.

    This is not quite right. If old effect is attached to another animation in the same task then we should probably not do an extra callback with unresolved.

    The definition of when custom effects gets called needs to be audited and probably rewritten.

  10. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.

The procedure to reset an animation’s pending tasks for animation is as follows:

  1. If animation does not have a pending play task or a pending pause task, abort this procedure.

  2. If animation has a pending play task, cancel that task.

  3. If animation has a pending pause task, cancel that task.

  4. Reject animation’s current ready promise with a DOMException named "AbortError".

    If cancelable promises materialize, we should probably cancel here instead of rejecting.

  5. Let animation’s current ready promise be the result of creating a new resolved Promise object.

3.5.4. The current time of an animation

Animations provide a time value to their target effect called the animation’s current time.

The current time is calculated from the first matching condition from below:

If the animation’s hold time is resolved,

The current time is the animation’s hold time.

If any of the following are true:

  1. the animation has no associated timeline, or

  2. the associated timeline is inactive, or

  3. the animation’s start time is unresolved.

The current time is an unresolved time value.

Otherwise,
current time = (timeline time - start time) × playback rate

Where timeline time is the current time value of the associated timeline. The playback rate value is defined in §3.5.17 Speed control.

3.5.5. Setting the current time of an animation

The current time of an animation can be set to a new value to seek the animation. The procedure for setting the current time is split into two parts.

The procedure to silently set the current time of an animation, animation, to seek time is as follows:

  1. If seek time is an unresolved time value, then perform the following steps.

    1. If the current time is resolved, then throw a TypeError.

    2. Abort these steps.

  2. Update either animation’s hold time or start time as follows:

    If any of the following conditions are true:

    Set animation’s hold time to seek time.

    Otherwise,

    Set animation’s start time to the result of evaluating timeline time - (seek time / playback rate) where timeline time is the current time value of timeline associated with animation.

  3. If animation has no associated timeline or the associated timeline is inactive, make animation’s start time unresolved.

    This preserves the invariant that when we don’t have an active timeline it is only possible to set either the animation start time or the animation’s current time.

  4. Make animation’s previous current time unresolved.

The procedure to set the current time of an animation, animation, to seek time is as follows:

  1. Run the steps to silently set the current time of animation to seek time.

  2. If animation has a pending pause task, synchronously complete the pause operation by performing the following steps:

    1. Set animation’s hold time to seek time.

    2. Make animation’s start time unresolved.

    3. Cancel the pending pause task.

    4. Resolve animation’s current ready promise with animation.

  3. Run the procedure to update an animation’s finished state for animation with the did seek flag set to true, and the synchronously notify flag set to false.

3.5.6. Setting the start time of an animation

The procedure to set the animation start time of animation, animation, to start time, new start time, is as follows:

  1. Let timeline time be the current time value of the timeline that animation is associated with. If there is no timeline associated with animation or the associated timeline is inactive, let the timeline time be unresolved.

  2. If timeline time is unresolved and new start time is resolved, make animation’s hold time unresolved.

    This preserves the invariant that when we don’t have an active timeline it is only possible to set either the animation start time or the animation’s current time.

  3. Let previous current time be animation’s current time.

    Note: This is the current time after applying the changes from the previous step which may cause the current time to become unresolved.

  4. Set animation’s start time to new start time.

  5. Update animation’s hold time based on the first matching condition from the following,

    If new start time is resolved,

    If animation’s playback rate is not zero, make animation’s hold time unresolved.

    Otherwise (new start time is unresolved),

    Set animation’s hold time to previous current time even if previous current time is unresolved.

  6. If animation has a pending play task or a pending pause task, cancel that task and resolve animation’s current ready promise with animation.

  7. Run the procedure to update an animation’s finished state for animation with the did seek flag set to true, and the synchronously notify flag set to false.

3.5.7. Waiting for the target effect

This section is non-normative

Some operations performed by an animation 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 unresolved start time on the animation which becomes resolved when the animation is ready. Content may opt out of this behavior by setting the start time to a resolved time value.

An animation is ready at the first moment where both of the following conditions are true:

3.5.8. Promise objects

Promise objects are defined by [ECMA-262].

To resolve a Promise with value, call the [[Call]] internal [[Resolve]] method on the PromiseCapability record for the promise, passing undefined as thisArgument and (value) as argumentsList.

To reject a Promise with reason, call the [[Call]] internal [[Reject]] method on the PromiseCapability record for the promise, passing undefined as thisArgument and (reason) as argumentsList.

To create a new resolved Promise with value, call Promise.resolve, passing value as x.

3.5.9. The current ready promise

Each animation has a current ready promise. The current ready promise is initially a resolved Promise created using the procedure to create a new resolved Promise.

The object is replaced with a new Promise object every time the animation enters the pending play state as well as when the animation is canceled (see §3.5.16 Canceling an animation).

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 Promise object is resolved.

For example, in the following code fragment, the state of the animation will be running when the current ready promise is resolved. This is because the animation does not leave the pending play state in between the calls to pause and play and hence the current ready promise does not change.

animation.pause();
animation.ready.then(function() {
  // Displays 'running'
  alert(animation.playState);
});
animation.play();

3.5.10. Playing an animation

The procedure to play an animation, animation, given a flag auto-rewind, is as follows:

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

  1. Let aborted pause be a boolean flag that is true if animation has a pending pause task, and false otherwise.

  2. Let has pending ready promise be a boolean flag that is initially false.

  3. Perform the steps corresponding to the first matching condition from the following, if any:

    If animation playback rate > 0, the auto-rewind flag is true and either animation’s:

    Set animation’s hold time to zero.

    If animation playback rate < 0, the auto-rewind flag is true and either animation’s:

    If target effect end is positive infinity, throw an InvalidStateError and abort these steps. Otherwise, set animation’s hold time to target effect end.

    If animation playback rate = 0 and animation’s current time is unresolved,

    Set animation’s hold time to zero.

  4. If animation has a pending play task or a pending pause task,

    1. Cancel that task.

    2. Set has pending ready promise to true.

  5. If animation’s hold time is unresolved and aborted pause is false, abort this procedure.

  6. If animation’s hold time is resolved, let its start time be unresolved.

  7. If has pending ready promise is false, let animation’s current ready promise be a new (pending) Promise object.

  8. Schedule a task to run as soon as animation is ready. The task shall perform the following steps:

    1. Let ready time be the time value of the timeline associated with animation at the moment when animation became ready.

    2. If animation’s start time is unresolved, perform the following steps:

      1. Let new start time be the result of evaluating ready time - hold time / animation playback rate for animation. If the animation playback rate is zero, let new start time be simply ready time.

      2. If animation’s playback rate is not 0, make animation’s hold time unresolved.

      3. Set the animation start time of animation to new start time.

    3. We should queue a task here for sampling custom effects. (This should happen before we resolve the ready promise.)

    4. Resolve animation’s current ready promise with animation.

    5. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.

      Note that the order of the above two steps is important since it means that an animation with zero-length target effect will resolve its current ready promise before its current finished promise.

      So long as the above task is scheduled but has yet to run, animation is described as having a pending play task.

      A user agent MAY execute the above task immediately (if it determines animation is immediately ready) thereby bypassing the pending play state altogether.

  9. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.

3.5.11. Pausing an animation

Whenever an animation has an unresolved start time, its current time will be suspended.

As with playing an animation, pausing may not happen instantaneously (see §3.5.7 Waiting for the target effect). For example, if animation is performed by a separate process, it may be necessary to synchronize the current time to ensure that it reflects the state drawn by the animation process.

The procedure to pause an animation, animation, is as follows:

  1. If animation has a pending pause task, abort these steps.

  2. If the play state of animation is paused, abort these steps.

  3. If the animation’s current time is unresolved, perform the steps according to the first matching condition from below:

    If animation’s playback rate is ≥ 0,

    Let animation’s hold time be zero.

    Otherwise,

    If target effect end for animation is positive infinity, throw an InvalidStateError and abort these steps. Otherwise, let animation’s hold time be target effect end.

  4. Let has pending ready promise be a boolean flag that is initially false.

  5. If animation has a pending play task, cancel that task and let has pending ready promise be true.

  6. If has pending ready promise is false, set animation’s current ready promise to a new (pending) Promise object.

  7. 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 any animations that are inclusive descendants of animation’s target effect, if any. The task shall perform the following steps:

    1. Let ready time be the time value of the timeline associated with animation at the moment when the user agent completed processing necessary to suspend playback of animation’s target effect.

    2. If animation’s start time is resolved and its hold time is not resolved, let animation’s hold time be the result of evaluating ready time - (start time / playback rate).

      Note: The hold time might be already set if the animation is finished, or if the animation is pending, waiting to begin playback. In either case we want to preserve the hold time as we enter the paused state.

    3. Make animation’s start time unresolved.

    4. We should queue a task here for sampling custom effects with the final current time. (This should happen before we resolve the ready promise).

    5. Resolve animation’s current ready promise with animation.

    6. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.

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

  8. Run the procedure to update an animation’s finished state for animation with the did seek flag set to false, and the synchronously notify flag set to false.

3.5.12. Reaching the end

This section is non-normative

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 media elements [HTML], the current time of Web Animations' animations do not play forwards beyond the end time of their target effect or play backwards past time zero.

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

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

The effect of limiting the current time of an animation.
The effect of limiting the current time of an animation with a start time of 1s, a target effect of length 3s, and a positive animation playback rate. After the current time of the animation reaches the end of the target effect, it is capped at 3s.

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

This allows, for example, seeking the current time of an animation with no target effect to 5s. If target effect with an end time 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 target effect changes.

Similarly, when the animation playback rate is negative, the current time does not progress past time zero.

3.5.13. The current finished promise

Each animation has a current finished promise. The current finished promise is initially a pending Promise object.

The object is replaced with a new (pending) Promise object every time the animation leaves the finished play state.

3.5.14. Updating the finished state

For an animation with a positive playback rate, the current time continues to increase until it reaches the target effect end.

The target effect end of an animation is equal to the end time of the animation’s target effect. If the animation has no target effect, the target effect end is zero.

An animation with a negative playback rate, the current time continues to decrease until it reaches zero.

A running animation that has reached this boundary (or overshot it) and has a resolved animation start time is said to be finished.

The crossing of this boundary is checked on each modification to the animation object using the procedure to update an animation’s finished state defined below. This procedure is also run on each sample and each time the timing properties of the target effect associated with an animation are updated. In both cases the did seek flag, defined below, is set to false.

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

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

The procedure to update an animation’s finished state for animation, given a flag did seek (to indicate if the update is being performed after setting the current time), and a flag synchronously notify (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 unconstrained current time be the result of calculating the current time substituting an unresolved time value for the hold time if did seek is false. If did seek is true, the unconstrained current time is equal to the current time.

    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.

  2. If all three of the following conditions are true,

    then update animation’s hold time based on the first matching condition for animation from below, if any:

    If animation playback rate > 0 and unconstrained current time is greater than or equal to target effect end,

    If did seek is true, let the hold time be the value of unconstrained current time.

    If did seek is false, let the hold time be the maximum value of previous current time and target effect end. If the previous current time is unresolved, let the hold time be target effect end.

    If animation playback rate < 0 and unconstrained current time is less than or equal to 0,

    If did seek is true, let the hold time be the value of unconstrained current time.

    If did seek is false, let the hold time be the minimum value of previous current time and zero. If the previous current time is unresolved, let the hold time be zero.

    If animation playback rate ≠ 0, and animation is associated with an active timeline,

    Perform the following steps:

    1. If did seek is true and the hold time is resolved, let animation’s start time be equal to the result of evaluating timeline time - (hold time / playback rate) where timeline time is the current time value of timeline associated with animation.

    2. Let the hold time be unresolved.

  3. Set the previous current time of animation be the result of calculating its current time.

  4. Let current finished state be true if the play state of animation is finished. Otherwise, let it be false.

  5. If current finished state is true and the current finished promise is not yet resolved, perform the following steps:

    1. Let finish notification steps refer to the following procedure:

      1. If animation’s play state is not equal to finished, abort these steps.

      2. Resolve animation’s current finished promise object with animation.

      3. Queue a task to fire a finish event at animation. The task source for this task is the DOM manipulation task source.

    2. If synchronously notify is true, cancel any queued microtask to run the finish notification steps for this animation, and run the finish notification steps immediately.

      Otherwise, if synchronously notify is false, queue a microtask to run finish notification steps for animation unless there is already a microtask queued to run those steps for animation.

  6. If current finished state is false and animation’s current finished promise is already resolved, set animation’s current finished promise to a new (pending) Promise object.

Typically, notification about the finished state of an animation is performed asynchronously. This allows for the animation to temporarily enter the finished state without triggering events to be fired or promises to be resolved.

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

var animation = elem.animate({ left: '100px' }, 2000);
animation.playbackRate = 2;
animation.currentTime = 1000; // animation is now finished
animation.effect.timing.iterationCount = 2; // animation is no longer finished

The one exception to this asynchronous behavior is when the finish an animation procedure is performed (typically by calling the 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.

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;

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

3.5.15. Finishing an animation

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

  1. If animation playback rate is zero, or if animation playback rate > 0 and target effect end is infinity, throw an InvalidStateError and abort these steps.

  2. Set limit as follows:

    If animation playback rate > 0,

    Let limit be target effect end.

    Otherwise,

    Let limit be zero.

  3. Silently set the current time to limit.

  4. If animation’s start time is unresolved and animation has an associated active timeline, let the start time be the result of evaluating timeline time - (limit / playback rate) where timeline time is the current time value of the associated timeline.

  5. If there is a pending pause task and start time is resolved,

    1. Let the hold time be unresolved.

      Typically the hold time will already be unresolved except in the case when the animation was previously idle.
    2. Cancel the pending pause task.

    3. Resolve the current ready promise of animation with animation.

  6. If there is a pending play task and start time is resolved, cancel that task and resolve the current ready promise of animation with animation.

  7. Run the procedure to update an animation’s finished state animation with the did seek flag set to true, and the synchronously notify flag set to true.

3.5.16. Canceling an animation

An animation can be canceled which causes the current time to become unresolved hence removing any effects caused by the target effect.

The procedure to cancel an animation for animation is as follows:

  1. If animation’s play state is not idle, perform the following steps:

    1. Run the procedure to reset an animation’s pending tasks on animation.

    2. Reject the current finished promise with a DOMException named "AbortError".

      If cancelable promises materialize, we should cancel here instead of rejecting.

    3. Let current finished promise be a new (pending) Promise object.

    4. If animation is not idle, queue a task to fire a cancel event at animation. The task source for this task is the DOM manipulation task source.

      The event current time for the dispatched cancel event is unresolved and the event timeline time is the current time value of the timeline associated with animation at the moment the task is queued.

  2. Make animation’s hold time unresolved.

  3. Make animation’s start time unresolved.

  4. Queue a task to call any custom effects associated with inclusive descendants of animation’s target effect with an unresolved iteration progress.

    The procedures for calling custom effects need to be reworked. Currently they probably involve calling too often for changes that could be coalesced.

3.5.17. Speed control

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

Note that animation effects also have a playback rate associated with them that behaves differently to that defined here.

Animations have a playback rate that provides a scaling factor from the rate of change of the associated timeline’s time values to the animation’s current time. The playback rate is initially 1.

Setting an animation’s playback rate to zero effectively pauses the animation (however, the play state does not necessarily become paused).

3.5.17.1. Updating the playback rate of an animation

Changes to the playback rate trigger a compensatory seek so that that the animation’s current time is unaffected by the change to the playback rate.

The procedure to set the animation playback rate of an animation, animation to new playback rate is as follows:

  1. Let previous time be the value of the current time of animation before changing the playback rate.

  2. Set the playback rate to new playback rate.

  3. If previous time is resolved, set the current time of animation to previous time.

The procedure to silently set the animation playback rate of animation, animation to new playback rate is identical to the above procedure except that rather than invoking the procedure to set the current time in the final step, the procedure to silently set the current time is invoked instead.

3.5.18. Reversing an animation

The procedure to reverse an animation of animation animation is as follows:

  1. If there is no timeline associated with animation, or the associated timeline is inactive throw an InvalidStateError and abort these steps.

  2. Silently set the animation playback rate of animation to animation playback rate.

    This must be done silently or else we may end up resolving the current ready promise when we do the compensatory seek despite the fact that we are most likely not exiting the pending play state.
  3. Run the steps to play an animation for animation with the auto-rewind flag set to true.

    If the steps to play an animation throw an exception, restore the original animation playback rate by re-running the procedure to silently set the animation playback rate with the original animation playback rate.

3.5.19. Play states

An animation may be described as being in one of the following play states for each of which, a non-normative description is also provided:

idle

The current time of the animation is unresolved and there are no pending tasks. In this state the animation has no effect.

pending

The animation is waiting on some pending task to complete.

running

The animation has a resolved current time that changes on each sample (provided the animation playback rate is not zero).

paused

The animation has been suspended and the current time is no longer changing.

finished

The animation has reached the natural boundary of its playback range and the current time is no longer updating.

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

animation has a pending play task or a pending pause task,

pending

The current time of animation is unresolved,

idle

The start time of animation is unresolved,

paused

For animation, animation playback rate > 0 and current timetarget effect end; or
animation playback rate < 0 and current time ≤ 0,

finished

Otherwise,

running

Note that the paused play state effectively “wins” over the finished play state.

However, an animation that is paused outside of its natural playback range can be converted from a paused animation into a finished animation without restarting by setting the animation start time such as below:

animation.effect.timing.duration = 5000;
animation.currentTime = 4000;
animation.pause();
animation.ready.then(function() {
  animation.effect.timing.duration = 3000;
  alert(animation.playState); // Displays 'paused'
  animation.startTime =
    document.timeline.currentTime - animation.currentTime * animation.playbackRate;
  alert(animation.playState); // Displays 'finished'
});

3.5.20. Animation events

As animations play, they report changes to their status through animation events.

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

3.5.20.1. Types of animation events
finish

Queued whenever an animation enters the finished play state.

cancel

Queued whenever an animation enters the idle play state from another state. Creating a new animation that is initially idle does not generate a new cancel event.

3.5.20.2. Event parameters

Animation events have an associated event current time and event timeline time.

The event current time is the current time of the animation that generated the event at the moment the event is queued. This will be unresolved if the animation was idle at the time the event was generated.

The event timeline time is the time value of the timeline with which the animation that generated the event is associated at the moment the event is queued. This will be unresolved if the animation was not associated with a timeline at the time the event was generated or if the associated timeline was inactive.

3.6. Animation effects

An animation effect is an abstract term referring to an item in the timing hierarchy.

3.6.1. Relationship between animation effects and animations

The target effect of an animation, if set, is a type of animation effect. The target effect of an animation is said to be directly associated with that animation.

Animation effects can be combined together into a hierarchy using group effects (see §3.13 Grouping and synchronization). Only the root animation effect of such a hierarchy can be directly associated with an animation. If an animation effect that has a parent group is designated as the target effect of an animation, the animation effect is removed from its parent group before being associated with the animation.

An animation effect is associated with an animation if it is directly associated with an animation or if it has an ancestor group effect that is directly associated with an animation.At a given moment, an animation effect can be associated with at most one animation.

An animation effect, effect, is associated with a timeline, timeline, if effect is associated with an animation which, in turn, is associated with timeline.

3.6.2. Types of animation effects

This specification defines two types of animation effects:

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

3.6.3. The active interval

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

The lower bound of the active interval is determined by the start time of the animation effect but may be shifted by a start delay on the animation effect.

The upper bound of the interval is determined by the active duration.

The relationship between the start time, start delay, and active duration is illustrated below.

Examples of the effect of the start delay on the endpoints
          of the active interval
Examples of the effect of the start delay on the endpoints of the active interval.
(a) An animation effect with no delay; the start time and beginning of the active interval are coincident.
(b) An animation effect with a positive delay; the beginning of the active interval is deferred by the delay.
(c) An animation effect with a negative delay; the beginning of the active interval is brought forward by the delay.

An end delay may also be specified but is primarily only of use when sequencing animations such as by using a sequence effect.

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

The lower bound of the active interval is defined by the combination of the animation effect’s start time and start delay.

An animation effect’s start time is the moment at which the parent group, if any, has scheduled the animation effect to begin. It is expressed in inherited time.

In most cases, including the case when the animation effect has no parent group, the start time is zero. The singular exception is sequence effects which set the start times of their children as described in §3.13.4.1 The start time of children of a sequence effect.

In addition to the start time, an animation effect also has a start delay which is an offset from the start time.

Unlike the start time which is determined by the parent group, the start delay is a property of the animation effect itself.

The lower bound of the active interval of an animation effect, expressed in inherited time space, is the sum of the start time and the start delay.

These definitions are incorporated in the calculation of the local time (see §3.6.4 Local time and inherited time) and active time. The length of the active interval is called the active duration, the calculation of which is defined in §3.10.2 Calculating the active duration.

Similar to the start delay, an animation effect also has an end delay which may be used to delay the start time of the next sibling in a sequence effect.

The end time of an animation effect is the result of evaluating max(start time + start delay + active duration + end delay, 0).

3.6.4. Local time and inherited time

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

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.

Just as with coordinate spaces, time spaces can also be nested. Group effects typically perform some transformations on the time values they receive from their parent or animation before passing on the transformed time values to their children. Child animation effects then operate within that transformed time space.

Children take the transformed time values from their parent—called the inherited time—and add their start time to establish their own local time space as illustrated below.

Inherited time and local time.
Inherited time and local time.
At time t, the inherited time is 2.5.
For animation effect (a) which has a start time of 1, the local time is 1.5.
For animation effect (b) which has a start time of 1 and a start delay of 1, the local time is also 1.5 since local time is based on an animation effect’s start time only, and not on its start delay.

For an animation effect, the inherited time at a given moment is based on the first matching condition from the following:

If the animation effect has a parent group,

the inherited time is the parent group’s current transformed time.

If the animation effect is directly associated with an animation,

the inherited time is the current time of the animation.

Otherwise,

the inherited time is unresolved.

The local time of an animation effect is the animation effect’s inherited time minus its start time. If the inherited time is unresolved then the local time is also unresolved.

3.6.5. Animation effect phases and states

This section is non-normative

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

The different phases are illustrated below.

An example of the different phases and states used to
          describe an animation effect.
An example of the different phases and states used to describe an animation effect.

The phases are as follows:

before phase

The animation effect’s local time falls before the effect’s active interval and end time, or occurs during the range when a negative start delay is in effect.

active phase

The animation effect’s local time falls inside the effect’s active interval and outside the range of any negative start delay or negative end delay.

after phase

The animation effect’s local time falls after the effect’s active interval or after the end time if that comes first (due to a negative end delay), but not during the range when a negative start delay is in effect.

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

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

in play

Corresponds to an animation effect whose active time is changing on each sample. This occurs when the animation effect and all its ancestors are in the active phase. Animation effects only “move” when they are in play.

It is possible for an animation effect to be in the active phase but not in play. For example, if an animation effect has a parent group that causes the animation effect’s active interval to be clipped and both parent and child apply the same fill mode, the child animation effect may be effectively be snapshotted within the active phase despite no longer being in play.

current

Corresponds to an animation effect that is either in play or may become in play in the future. This will be the case if the animation effect is in play or in its before phase, or it has an ancestor for which this is true thereby opening up the possibility that this animation effect might play again (e.g. due to repeating).

in effect

Corresponds to an animation effect that has a resolved active time. This occurs when either the animation effect is in its active phase or outside the active phase but at a time where the effect’s fill mode (see §3.7 Fill behavior) causes its active time to be resolved. Only in effect animation effects apply a result to their target.

The normative definition of each of these states follows.

Determining the phase of an animation effect requires the following definitions:

animation direction

‘backwards’ if the effect is associated with an animation and the associated animation’s playback rate is less than zero; in all other cases, the animation direction is ‘forwards’.

before-active boundary time

max(min(start delay, end time), 0)

active-after boundary time

max(min(start delay + active duration, end time), 0)

An animation effect is in the before phase if the animation effect’s local time is not unresolved and either of the following conditions are met:

  1. the local time is less than the before-active boundary time, or

  2. the animation direction is ‘backwards’ and the local time is equal to the before-active boundary time.

An animation effect is in the after phase if the animation effect’s local time is not unresolved and either of the following conditions are met:

  1. the local time is greater than the active-after boundary time, or

  2. the animation direction is ‘forwards’ and the local time is equal to the active-after boundary time.

An animation effect is in the active phase if the animation effect’s local time is not unresolved and it is not in either the before phase nor the after phase.

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

An animation effect is in play if all of the following conditions are met:

  1. the animation effect is in the active phase, and

  2. the animation effect has a parent group that is in play or else the animation effect is directly associated with an animation that is not finished.

An animation effect is current if any of the following conditions is true:

An animation effect is in effect if its active time, as calculated according to the procedure in §3.10.3.1 Calculating the active time, is not unresolved.

3.7. Fill behavior

The effect of an animation effect when it is not in play is determined by its fill mode.

The possible fill modes are:

The normative definition of these modes is incorporated in the calculation of the active time in §3.10.3.1 Calculating the active time.

3.7.1. Fill modes

This section is non-normative

The effect of each fill mode is as follows:

none

The animation effect has no effect when it is not in play.

forwards

When the animation effect is in the after phase, or when the animation effect is in the active phase but an ancestor is in its after phase, the animation effect will produce the same iteration progress value as the last moment it is scheduled to be in play.

For all other times that the animation effect is not in play, it will have no effect.

backwards

When the animation effect is in the before phase, or when the animation effect is in the active phase but an ancestor is in its before phase, the animation effect will produce the same iteration progress value as the earliest moment that it is scheduled to be in play.

For all other times that the animation effect is not in play, it will have no effect.

both

When the animation effect or an ancestor is in its before phase, backwards fill behavior is used.

When the animation effect or an ancestor is in its after phase, forwards fill behavior is used.

Some examples of the these fill modes are illustrated below.

Examples of various fill modes and the states produced.
Examples of various fill modes and the states produced.
(a) fill mode ‘none’. The animation effect has no effect outside its active phase.
(b) fill mode ‘forwards’. After the active phase has finished, the iteration progress value continues to maintain a fill value.
(c) fill mode ‘backwards’. The animation effect produces a fill value until the start of the active phase.
(d) fill mode ‘both’. Both before and after the active phase the animation effect produces a fill value.

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

Currently timing functions that generate results outside the range [0, 1] will behave unexpectedly when applied to group effects, as children will increase iterations or enter into fill mode rather than continuing to extrapolate along their defined behavior (which is what they would do if the timing function applied to them directly).

To fix this it is possible we will wish to introduce ‘overflow’ fill modes that respond to time values larger than or smaller than the active time range by extrapolating rather than filling.

See section 15 (Overflowing fill) of minuted discussion from Tokyo 2013 F2F.

3.8. Repeating

3.8.1. Iteration intervals

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

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

The length of a single iteration is called the iteration duration. The initial iteration duration of an animation effect is simply its intrinsic iteration duration.

The intrinsic iteration duration of an animation effect is zero, however some specific types of animation effect such as group effects override this behavior and provide an alternative intrinsic duration (see §3.13.3 The intrinsic iteration duration of a group effect and §3.13.4.2 The intrinsic iteration duration of a sequence effect).

The iteration duration of an animation effect may be set by the author to represent a value other than the intrinsic iteration duration.

This section is non-normative

Comparing the iteration duration and the active duration 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 iteration duration.

The relationship between the iteration duration and active duration is illustrated below.

Comparison of the iteration duration and active time.
A comparison of the iteration duration and active duration of an animation effect with an iteration count of 2.5. Note that the iteration duration for the final iteration does not change, it is simply cut-off by the active duration.

3.8.2. Controlling iteration

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

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

The behavior of these parameters is defined in the calculations in §3.10 Core animation effect calculations.

This section is non-normative

The effect of the iteration count and iteration start parameters is illustrated below.

The effect of the iteration count and iteration start parameters
The effect of the iteration count and iteration start parameters.
In the first case the iteration count is 2.5 resulting in the third iteration being cut-off half way through its iteration interval.
The second case is the same but with an iteration start of 0.5. This causes the animation effect to begin half way through the first iteration.

Unlike the iteration count parameter, the iteration start parameter does not effect the length of the active duration.

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

3.8.3. Iteration time space

This section is non-normative

We have already encountered different time spaces in describing local time and inherited time (see §3.6.4 Local time and inherited time). Repetition introduces yet another time space: the iteration time space.

Iteration time space 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 active time 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.

A comparison of local time, active time, and iteration time.
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.

Note: While the time spaces themselves are not bounded, Web Animations defines active time and the iteration progress 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 active time space, the procedure for calculating the active time defined in §3.10.3.1 Calculating the active time will never return a negative value.

In addition to these time spaces we can also refer to the document time space which is time space of the time values of the default document timeline of the Document of the current global object

3.8.4. Interval timing

This section is non-normative

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 [begin, end). 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 effects, at inherited time 1s, only effect B will be in play; there is no overlap.

Illustration of end-point exclusive timing.
Illustration of end-point exclusive timing. For both repeated and sequenced animation effects there is no overlap at the boundaries between intervals.

An exception to this behavior is that when performing a fill, if the fill begins at an interval endpoint, the endpoint is used. This behavior falls out of the algorithm given in §3.10.3.3 Calculating the simple iteration progress and is illustrated below.

Effect of iterations and fill on iteration time.
After one iteration, the iteration progress is 0, but after two iterations (and there onwards), the iteration progress is 1 due to the special behavior defined when an animation effect fills.

3.9. Animation effect speed control

Like animations, animation effects also have a playback rate parameter. The playback rate of an animation effect is a finite real number that acts as a multiplier when calculating the animation effect’s transformed time from its local time.

The effect of setting the playback rate of an animation effect differs from the setting the playback rate on an animation. Its behavior is defined in the timing calculations given in §3.10 Core animation effect calculations.

This section is non-normative

In summary, the behavior of the playback rate of an animation effect is as follows:

3.10. Core animation effect calculations

3.10.1. Overview

This section is non-normative

At the core of the Web Animations timing model is the process that takes an inherited time value and converts it to an iteration progress.

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

This process is illustrated below.

Calculation of the active duration.
Calculation of the active duration is based on multiplying the iteration duration by the iteration count and then dividing by the playback rate.

The process for calculating the active duration is normatively defined in §3.10.2 Calculating the active duration.

Having established the active duration, the process for transforming an animation effect’s inherited time into its transformed progress (iteration progress) is illustrated below.

An overview of timing model calculations.
An overview of timing model calculations.
(1) The inherited time is converted into a local time by incorporating the start time.
(2) The local time is converted into an active time by incorporating the start delay.
(3) The active time is divided by the iteration duration incorporating also the iteration start property and the playback rate property to produce the overall progress.
(4) The overall progress time is then converted to an offset within a single iteration: the simple iteration progress.
(5) The simple iteration progress is converted into a directed progress by incorporating the playback direction.
(6) Finally, a timing function is applied to the directed progress to produce the transformed progress.

The first step, calculating the local time is described in §3.6.4 Local time and inherited time. Steps 2 to 4 in the diagram are described in the following sections. Steps 5 and 6 are described in §3.11.1 Calculating the directed progress and §3.12.1 Calculating the transformed progress respectively.

3.10.2. Calculating the active duration

In order to calculate the active duration we first define the repeated duration as follows:

repeated duration = iteration duration × iteration count

If either the iteration duration or iteration count are zero, the repeated duration is zero.

This clarification is needed since the result of infinity multiplied by zero is undefined according to IEEE 754-2008.

The active duration is calculated according to the following steps:

  1. If the playback rate is zero, return Infinity.

  2. Otherwise, return repeated duration / abs(playback rate).

3.10.3. Transforming the local time

3.10.3.1. Calculating the active time

The active time is based on the local time and start delay. However, it is only defined when the animation effect should produce an output and hence depends on its fill mode and phase as well as the phase of its parent group, if any, as follows,

If the animation effect is in the before phase,

The result depends on the first matching condition from the following,

If the animation effect has a parent group and that parent group is in the after phase,

Return an unresolved time value.

If the fill mode is backwards or both,

Return the result of evaluating max(local time - start delay, 0).

Otherwise,

Return an unresolved time value.

If the animation effect is in the active phase,

The result depends on the first matching condition from the following,

If the animation effect has a parent group and that parent group is in the before phase, and the fill mode of this animation effect is none or forwards,

Return an unresolved time value.

If the animation effect has a parent group and that parent group is in the after phase, and the fill mode of this animation effect is none or backwards,

Return an unresolved time value.

Otherwise,

Return the result of evaluating local time - start delay.

If the animation effect is in the after phase,

The result depends on the first matching condition from the following,

If the animation effect has a parent group and that parent group is in the before phase,

Return an unresolved time value.

If the fill mode is forwards or both,

Return the result of evaluating max(min(local time - start delay, active duration), 0).

Otherwise,

Return an unresolved time value.

Otherwise (the local time is unresolved),

Return an unresolved time value.

3.10.3.2. Calculating the overall progress

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

  1. If the active time is unresolved, return unresolved.

  2. Calculate an initial value for overall progress based on the first matching condition from below,

    If the iteration duration is zero,

    If the animation effect is in the before phase, let overall progress be zero, otherwise, let it be equal to the iteration count.

    Otherwise,

    Calculate the overall progress following the first matching condition from below:

    If the animation effect playback rate is less than zero,

    Let overall progress be (active time - active duration) × playback rate / iteration duration.

    If the animation effect playback rate is zero,

    Let overall progress be zero.

    Otherwise,

    Let overall progress be (active time × playback rate) / iteration duration.

  3. Return the result of calculating overall progress + iteration start.

3.10.3.3. Calculating the simple iteration progress

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

  1. If the overall progress is unresolved, return unresolved.

  2. If overall progress is infinity, let the simple iteration progress be iteration start % 1.0, otherwise, let the simple iteration progress be overall progress % 1.0.

  3. If all of the following conditions are true,

    let the simple iteration progress be 1.0.

    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 two conditions prevent this from applying when we never played any iterations of the animation to begin with because either (a) the iteration count was zero, or (b) the playback range of the active interval was clipped to zero using a negative end delay. In detecting if the active interval’s playback range was clipped to zero, we check for a zero active time in the after phase, but if the iteration duration was zero to begin with then we say that the animation was not clipped.

  4. Return simple iteration progress.

3.10.4. Calculating the current iteration

The current iteration can be calculated using the following steps:

  1. If the active time is unresolved, return unresolved.

  2. If the animation effect is in the after phase and the iteration count is infinity, return infinity.

  3. If the simple iteration progress is 1.0, return floor(overall progress) - 1.

  4. Otherwise, return floor(overall progress).

3.11. Direction control

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

The semantics of these values are incorporated into the calculation of the directed progress which follows.

This section is non-normative

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.

3.11.1. Calculating the directed progress

The directed progress is calculated from the simple iteration progress using the following steps:

  1. If the simple iteration progress is unresolved, return unresolved.

  2. Calculate the current direction using the first matching condition from the following list:

    If playback direction is normal,

    Let the current direction be forwards.

    If playback direction is reverse,

    Let the current direction be reverse.

    Otherwise,
    1. Let d be the current iteration.

    2. If playback direction is alternate-reverse increment d by 1.

    3. If d % 2 == 0, let the current direction be forwards, otherwise let the current direction be reverse. If d is infinity, let the current direction be forwards.

  3. If the current direction is forwards then return the simple iteration progress.

    Otherwise, return 1.0 - simple iteration progress.

3.12. Time transformations

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

Animation effects have one timing function associated with them. The default timing function is the linear timing function.

Currently, the set of timing functions allowed on a group effect is not restricted. This has raised concern about complexity of implementation and also complexity of behavior with regards to fill modes. As a result, allowing the full set of timing functions on group effects is considered at risk.

Alternatives are to either restrict timing functions on group effects to the linear timing function or to a set of “simple” timing functions that have properties that alleviate some of the concerns with the more complex timing functions.

See section 2 of the discussion from August 2013.

3.12.1. Calculating the transformed progress

The transformed progress is calculated from the directed progress using the following steps:

  1. If the directed progress is unresolved, return unresolved.

  2. Calculate the value of the before flag as follows:

    1. Determine the current direction using the procedure defined in §3.11.1 Calculating the directed progress.

    2. If either the current direction is forwards or the animation effect playback rate ≥ 0 (but not when both conditions are true), let going forwards be true, otherwise it is false.

    3. The before flag is set if the animation effect is in the before phase and going forwards is true; or if the animation effect is in the after phase and going forwards is false.

  3. Return the result of evaluating the animation effect’s timing function passing directed progress as the input progress value and before flag as the before flag.

3.12.2. Calculating the transformed time

The transformed time of an animation effect is simply the transformed progress multiplied by the iteration duration.

If the transformed progress is unresolved, then the transformed time is also unresolved.

If the transformed progress is zero and the iteration duration is infinity, then the transformed time is zero.

3.13. Grouping and synchronization

This section is non-normative

While it is possible to set the timing properties of animation effects individually, it is often useful to synchronize animation effects so that they share common timing properties and maintain their temporal relationship. This is achieved using an group effect.

A simple example is illustrated below.

Using groups to share common timing properties.
Using groups to share common timing properties.
(a) Shows setting a delay of 5 seconds on individual animations.
(b) Produces the same effect by setting the delay on the group.

When a group effect is directly associated with an animation, the animation effect associated with the group effect can be seeked, paused, and stopped as a unit.

A group effect is a type of animation effect that contains an ordered sequence of zero or more animation effects known as child effects.

At a given moment, an animation effect may be a child effect of at most one group effect known as the parent group. The parent group cannot be the same animation effect as the child effect itself.

By nesting group effects it is possible to create hierarchical tree structures. The following terms are used to describe the parts and properties of such structures and are defined in [DOM]:

Note: in applying these definitions to animation effects, the term parent refers exclusively to a parent group and does not include the animation which with an animation effect may be directly associated despite the fact that conceptually the animation acts as a parent time source.

The temporal relationship between a child effect and its parent group is incorporated in the definition of inherited time (see §3.6.4 Local time and inherited time).

3.13.1. Relationship of group time to child time

This section is non-normative

The timing of the children of a group effect is based on the timing of the group. Specifically, times for the children are based on the parent’s transformed time. With regards to repetition, this means the children operate inside an iteration of the parent.

For example, if a group effect has an iteration count of 2, then the children of of the group will all play twice since they effectively play inside the group’s iterations.

The effect of multiple iterations on the children of a group.
Since children of a group effect base their timing on the group’s transformed time, when the group repeats, the children play again.

Note that even in this case, the child animation effects still have only one active interval. However, as a result of the parent’s timing, the active interval is played twice.

If an iteration count is specified for the children of a group as well as for the group itself, the effect is as if the iteration count of the group was multiplied with the iteration count of the children.

Iteration counts are multiplicative.
Specifying an iteration count of 2 on a group effect and an iteration count of 3 on one of its children results in that child playing 6 times.

A further result of the children of a group effect basing their timing on the group’s transformed time is that they cannot animate outside of the group’s active interval. This is because the transformed time of a group will not change outside its active interval. This allows groups to clip the playback of their children.

Groups clip the active interval of contained children.
In the first instance, an animation effect has a negative delay and an infinite iteration count.
However, when a similar animation effect is placed inside a group effect with a specified iteration duration it has the effect of clipping the child animation effect’s active interval.

Some further consequences of group effect children basing their timing on their parent group’s transformed time are:

3.13.2. The start time of children of a group effect

The start time of a child effect of a group effect is zero.

Note that specific types of group effects may override this definition to provide other kinds of synchronization behavior.

3.13.3. The intrinsic iteration duration of a group effect

The intrinsic iteration duration of a group effect is based on the time when the last child effect completes its active interval and depends on the number of child effects as follows.

If the group has no child effects,

the intrinsic iteration duration is zero.

Otherwise,
  1. Let maximum end time be the maximum value after calculating the end time of each child effect in the group.

  2. The intrinsic iteration duration is the result of evaluating max(0, maximum end time).

This definition of the intrinsic iteration duration may be overridden by specific types of group effects.

3.13.4. Sequence effects

This section is non-normative

Specific types of group effects can be used to provide different kinds of synchronization behavior for their children. This specification defines one additional type of group effect: a sequence effect. Sequence effects arrange the start times of their children so that they run one at a time, in turn.

Compare the two arrangements illustrated below:

Group effects and sequence effects.
Group effects and sequence effects.
(a) is a regular group effect where all the children run simultaneously.
(b) is a sequence effect where the children run in turn.

Since group effects can also contain other group effects, complex synchronization is possible by combining different types of groups as illustrated below.

Nesting of group effects.
A sequence effect that contains a regular group effect as a child.
The group effect waits for the previous child of the sequence effect to finish, and then the children of the group effect play simultaneously. After they have finished the next child of the sequence effect plays.

A sequence effect is a type of group effect that schedules its child effects such that they play in turn following their order in the group. This sequencing is achieved by adjusting the start time of each child effect in the group.

3.13.4.1. The start time of children of a sequence effect

The start time of a child effect of a sequence effect is the end time of the child’s previous sibling. If the child has no previous sibling the start time is zero.

When the active duration is positive infinity the behavior for calculating the end time of an animation effect and the start time of subsequent children follows the usual behavior defined by IEEE 754-2008. As a result, if any of the children of a sequence effect has an infinite active duration, any children that occur later in the sequence will not play.

Similarly, the above definition does not restrict start times to positive values and hence some children may not play due to a negative start delay on children that occur earlier in the group since their active interval may end before the group’s start time.

This section is non-normative

Because the start of the active interval is based on the sum of an animation effect’s start time and start delay, the active intervals of children of a sequence effect need not run in strict sequence but can be shifted back and forth by using the start delay as shown in the following diagram.

Using negative start delays to overlap children of seq
        groups
Example of using the start delay on children of a sequence effect to shift their timing so that they overlap (a negative delay) or are spaced apart (a positive delay).

A negative start delay can be used to cause the active interval of two children to overlap. Note that the start delay affects the start time of subsequent children in the group.

3.13.4.2. The intrinsic iteration duration of a sequence effect

The intrinsic iteration duration of a sequence effect is equivalent to the start time of a hypothetical child effect appended to the group’s children calculated according to the definition in §3.13.4.1 The start time of children of a sequence effect unless that produces a negative value, in which case the intrinsic iteration duration is zero.

As a result, if the sequence effect has no child effects the intrinsic iteration duration will be zero.

3.14. The iteration progress

The iteration progress of an animation effect is simply its transformed progress.

4. Animation model

This section is non-normative

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

The output of each such animation effect is then combined with that of others using an effect stack before being applied to the target properties (see §4.5 Combining effects).

4.1. Introduction

An animation effect may have 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 target properties.

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

4.2. Procedures for animating properties

Unless specifically defined otherwise, all CSS properties are considered animatable. In order to animate a property, the following procedures must be defined.

Note that the above procedures apply to CSS computed property values (see §4.4.2 Calculating computed keyframes). As a result, it is not necessary to define, for example, how to add a length value of "15pt" with "5em" since such values will be resolved to pixel values before being passed to any of the above procedures.

4.3. Animation types

The specific procedures used for animating a given property are referred to as the property’s animation type.

The animation type of each CSS property is defined by the "Animatable:" line in the summary of the property’s definition or in [CSS3-TRANSITIONS] for properties that lack a such a line. For custom properties registered using the registerProperty() method for the current global object, the animation type is derived from the type used to define the property’s syntax. Where there is no animation type that corresponds to the property’s specified syntax (e.g. when the syntax is "*") the animation type is discrete. The animation type of all other custom properties is discrete.

The above doesn’t explain the animation type to use for of syntax such as "<length>+". We will fix this once the definition of animation types has moved to CSS Values and Units where we should define generic handling for list types etc.

Following is a series of pre-defined animation types. [CSS3-TRANSITIONS] provides further CSS-specific animation types.

For animation types that do not define a specific procedure for addition or which are defined as not additive, the addition procedure is simply Vres = Vb.

For animation types that do not define a specific procedure for accumulation, the accumulation procedure is identical to the addition procedure for that type.

4.3.1. Not animatable

Some properties are specifically defined as not animatable. For example, properties defining animation parameters are not animatable since doing so would create complex recursive behavior.

Unlike other animation types, no procedures for interpolation, addition and accumulation are defined for properties whose animation type is not animatable since these properties should not be modified.

An animation effect that targets a property that is not animatable will still exhibit the usual behavior for an animation effect such as occupying time in a sequence effect and delaying the fulfilment of an animation’s current finished promise.

4.3.2. Discrete

A property whose animation type is discrete has the following behavior:

4.3.3. Real number

A property whose animation type is real number has the following behavior:

4.3.4. Length, percentage, or calc

A property whose animation type is length, percentage, or calc has the following behavior:

4.3.5. Color

A property whose animation type is color has the following behavior:

4.3.6. Transform list

A property whose animation type is transform list has the following behavior:

4.3.7. Other animation types

The set of animation types defined here may be extended by other specifications. For example, properties with using the <image> type are animated using the interpolation behavior defined in CSS Image Values and Replaced Content [CSS3-IMAGES].

4.4. Keyframe effects

Keyframe effects are a kind of animation effect that use the output of the timing model to update CSS properties for an element or pseudo-element such as ::before or ::after [SELECT] referred to as the target element.

4.4.1. Keyframes

The effect values for a keyframe effect 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 keyframe.

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

The behavior when keyframes overlap or have unsupported values is defined in §4.4.3 The effect value of a keyframe effect.

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

Each keyframe may also have a keyframe-specific composite operation that is applied to all values specified in that keyframe. The possible operations and their meanings are identical to those defined for the composite operation associated with the keyframe effect as a whole in §4.5.4 Effect composition. If no keyframe-specific composite operation is specified for a keyframe, the composite operation specified for the keyframe effect as a whole is used for values specified in that keyframe.

4.4.2. Calculating computed keyframes

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

The calculated keyframe offsets of a set of keyframe that includes suitable values for each null keyframe offset are referred to as the computed keyframe offsets.

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

  1. For each keyframe, in keyframes, let the computed keyframe offset of the keyframe be equal to its keyframe offset value.

  2. If keyframes contains more than one keyframe and the computed keyframe offset of the first keyframe in keyframes is null, set the computed keyframe offset of the first keyframe to 0.

  3. If the computed keyframe offset of the last keyframe in keyframes is null, set its computed keyframe offset to 1.

  4. For each pair of keyframes A and B where:

    calculate the computed keyframe offset of each keyframe between A and B as follows:

    1. Let offsetk be the computed keyframe offset of a keyframe k.

    2. Let n be the number of keyframes between and including A and B minus 1.

    3. Let index refer to the position of keyframe in the sequence of keyframes between A and B such that the first keyframe after A has an index of 1.

    4. Set the computed keyframe offset of keyframe to offsetA + (offsetBoffsetA) × index / n.

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

  1. Let computed keyframes be an empty list of keyframes.

  2. For each keyframe in the list of keyframes specified on this keyframe effect, perform the following steps:

    1. Add a new empty keyframe, computed keyframe, to computed keyframes.

    2. For each property specified in keyframe, calculate the computed value specified on keyframe using the target element as the context for computing values and add the corresponding property and computed value to computed keyframe. For shorthand properties, add the equivalent longhand properties.

      For example, if keyframe has a value of ‘12pt’ for the border-width property, the user agent may produce a computed value of ‘16px’ for each of the longhand properties: border-bottom-width, border-left-width, border-right-width, and border-top-width. As a result, computed keyframe would not have a value for the border-width property, but would instead include each of the longhand properties, and each with the computed value, ‘16px’.

      If conflicts arise when expanding shorthand properties due to shorthand properties overlapping with existing longhand properties or other with other shorthand 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).

      2. Shorthand properties with fewer longhand components override those with more longhand components (e.g. border-top overrides border-color).

      3. For shorthand properties with an equal number of longhand components, properties whose IDL name (see the CSS property to IDL attribute algorithm [CSSOM]) appears earlier when sorted in ascending order by the Unicode codepoints that make up each IDL name, override those who appear later.

  3. Apply the procedure to compute missing keyframe offsets to computed keyframes.

  4. Return computed keyframes.

4.4.3. The effect value of a keyframe effect

The effect value of a single property referenced by a keyframe effect as one of its target properties, for a given iteration progress, current iteration and underlying value is calculated as follows.

  1. If iteration progress is unresolved abort this procedure.

  2. Let target property be the longhand property for which the effect value is to be calculated.

  3. If animation type of the target property is not animatable abort this procedure since the effect cannot be applied.

  4. Define the neutral value for composition as a value which, when combined with an underlying value using the add composite operation, produces the underlying value.

  5. Let property-specific keyframes be the result of getting the set of computed keyframes for this keyframe effect.

  6. Remove any keyframes from property-specific keyframes that do not have a property value for target property.

  7. If property-specific keyframes is empty, return underlying value.

  8. If there is no keyframe in property-specific keyframes with a computed keyframe offset of 0, create a new keyframe with a computed keyframe offset of 0, a property value set to the neutral value for composition, and a composite operation of add, and prepend it to the beginning of property-specific keyframes.

  9. Similarly, if there is no keyframe in property-specific keyframes with a computed keyframe offset of 1, create a new keyframe with a computed keyframe offset of 1, a property value set to the neutral value for composition, and a composite operation of add, and append it to the end of property-specific keyframes.

  10. Let interval endpoints be an empty sequence of keyframes.

  11. Populate interval endpoints by following the steps from the first matching condition from below:

    If iteration progress < 0 and there is more than one keyframe in property-specific keyframes with a computed keyframe offset of 0,

    Add the first keyframe in property-specific keyframes to interval endpoints.

    If iteration progress ≥ 1 and there is more than one keyframe in property-specific keyframes with a computed keyframe offset of 1,

    Add the last keyframe in property-specific keyframes to interval endpoints.

    Otherwise,
    1. Append to interval endpoints the last keyframe in property-specific keyframes whose computed keyframe offset is less than or equal to iteration progress and less than 1. If there is no such keyframe (because, for example, the iteration progress is negative), add the last keyframe whose computed keyframe offset is 0.

    2. Append to interval endpoints the next keyframe in property-specific keyframes after the one added in the previous step.

  12. For each keyframe in interval endpoints:

    1. If keyframe has a composite operation that is not replace, or keyframe has no composite operation and the composite operation of this keyframe effect is not replace, then perform the following steps:

      1. Let composite operation to use be the composite operation of keyframe, or if it has none, the composite operation of this keyframe effect.

      2. Let value to combine be the property value of target property specified on keyframe.

      3. Replace the property value of target property on keyframe with the result of combining underlying value (Va) and value to combine (Vb) using the composite operation to use procedure defined by the target property’s animation type.

    2. If this keyframe effect has an iteration composite operation of accumulate, apply the following step current iteration times:

      • replace the property value of target property on keyframe with the result of combining the property value on the final keyframe in property-specific keyframes (Va) with the property value on keyframe (Vb) using the accumulation procedure defined for target property.

      Note: The order of arguments here is important. In the case where the animation type of the target property does not define a procedure for accumulation or addition, the default definition for these procedures result in Vb being returned. When performing iteration composition on propreties that do not support accumulation, the result should be the initial property value of target property on keyframe, hence we we make this Vb in the above step.

  13. If there is only one keyframe in interval endpoints return the property value of target property on that keyframe.

  14. Let start offset be the computed keyframe offset of the first keyframe in interval endpoints.

  15. Let end offset be the computed keyframe offset of last keyframe in interval endpoints.

  16. Let interval distance be the result of evaluating (iteration progress - start offset) / (end offset - start offset).

  17. Let transformed distance be the result of evaluating the timing function associated with the first keyframe in interval endpoints passing interval distance as the input progress.

  18. Return the result of applying the interpolation procedure defined by the animation type of the target property, to the values of the target property specified on the two keyframes in interval endpoints taking the first such value as Vstart and the second as Vend and using transformed distance as the interpolation parameter p.

Note that this procedure assumes the following about the list of keyframes specified on the effect:

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 programming interface defined by this specification, these conditions are met by the procedure to produce the computed keyframes that become the input to this procedure.

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

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 are 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 ‘beyond’ 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 section 4 (Keyframe offsets outside [0, 1]) of minuted discussion from Tokyo 2013 F2F.

4.5. Combining effects

This section is non-normative

After calculating the effect values for a keyframe effect, they are applied to the animation effect’s target properties.

Since it is possible for multiple in effect keyframe effects to target the same property it is often necessary to combine the results of several keyframe effects together. This process is called compositing and is based on establishing an effect stack for each property targeted by an in effect animation effect.

After compositing the results of keyframe effects together, the composited result is combined with other values specified for the target property.

The arrangement is illustrated below:

Overview of the application of effect values to their target properties
Overview of the application of effect values to their target properties.
The results of keyframe effects targeting the same property are composited together using an effect stack.
The result of this composition is then inserted into the CSS cascade at an appropriate point.

For the first part of this operation—combining effect values that target the same property— it is necessary to determine both how keyframe effects are combined with one another, as well as the order in which they are applied, that is, their relative composite order.

The matter of how effect values are combined is governed by the composite operation of the corresponding keyframe effects.

The relative composite order of effect values is determined by an effect stack established for each animated property.

4.5.1. 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 animation defines its animation class.

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

This section is non-normative

For example, animations whose class is ‘CSS animation’ are defined as having a higher composite order than animations whose class is ‘CSS transition’ but lower than other animations without a specific class.

Within the set of ‘CSS animation’ objects, specialized composite ordering is defined based on the animation-name property amongst other factors.

4.5.2. The effect stack

Associated with each property targeted by one or more keyframe effects is an effect stack that establishes the relative composite order of the keyframe effects.

The relative composite order of any two keyframe effects, A and B, within an effect stack is established by comparing their properties as follows:

  1. Let the associated animation of an animation effect be the animation associated with the animation effect that affecting the property with which this effect stack is associated.

  2. Sort A and B by applying the following conditions in turn until the order is resolved,

    1. If A and B’s associated animations differ by class, sort by any inter-class composite order defined for the corresponding classes.

    2. If A and B are still not sorted, sort by any class-specific composite order defined by the common class of A and B’s associated animations.

    3. If A and B are still not sorted, sort by their corresponding position in the global animation list.

    4. Sort A and B in tree order. (By this point, A and B must have the same animation since otherwise the order would have been resolved in the previous step.)

Animation effects that sort earlier have lower composite order.

4.5.3. Calculating the result of an effect stack

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

Each step in the process of evaluating an effect stack takes an underlying value as input.

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

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

4.5.4. Effect composition

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

This specification defines three composite operations as follows:

replace

The result of compositing the effect value with the underlying value is simply the effect value.

add

The effect value is added to the underlying value. For animation types where the addition operation is defined such that it is not commutative, the order of the operands is underlying value + effect value.

accumulate

The effect value is accumulated onto the underlying value. For animation types where the accumulation operation is defined such that it is not commutative, the order of the operands is underlying value followed by effect value.

4.5.5. Applying the composited result

Applying a composited value to a target property 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 class of the animation associated with the effect with the highest composite order in the effect stack for a given property. By default, the specified value is added to the ‘Animation declarations’ level of the cascade ([css-cascade-3]).

This section is non-normative

For example, if the effect with the highest composite order is associated with a ‘CSS transition’-class animation, the composited value will be added to ‘Transition declarations’ level of the cascade.

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

  1. Calculate the base value 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 effect stack for the property (see §4.5.2 The effect stack).

  3. Calculate the composited value of the effect stack passing in the base value of the property as the initial underlying value (see §4.5.3 Calculating the result of an effect stack).

  4. Insert the composited value into the CSS cascade at the level defined for the class of the animation associated with the effect at the top of the effect stack established for the target property.

4.6. Effect accumulation

Similar to the compositing performed between effect values (see §4.5.4 Effect composition), the iteration composite operation determines how values are combined between successive iterations of the same keyframe effect.

This specification defines two iteration composite operations as follows:

replace

Each successive iteration is calculated independently of previous iterations.

accumulate

Successive iterations of the animation are accumulated with the final value of the previous iteration.

The application of the iteration composite operation is incorporated in the calculation of the effect value in §4.4.3 The effect value of a keyframe effect.

4.7. Side effects of animation

For every property targeted by at least one animation effect that is current or in effect, the user agent must act as if the will-change property ([css-will-change-1]) on the target element includes the property.

This section is non-normative

As a result of the above requirement, if an animation targets, for example, the transform property of an element, a stacking context will be created for the target element so long as the animation is in the before phase, the active phase or, if it has a fill mode of ‘forwards’ or ‘both’, the after phase.

4.8. Custom effects

This whole feature needs to be revisited. The current thinking is that rather than having custom effects, we should simply have an onsample callback on each animation effect. That would allow, for example, augmenting an existing effect with a function that performs logging or triggers additional actions at certain times. With the current arrangement, doing this would require adding a parent group just to achieve this.

This section is non-normative

In some situations the animation effects provided by Web Animations may be insufficient. For example, the animation effects defined here are only able to target certain CSS properties. They are unable, therefore, to modify the currentScale property of an SVG element to smoothly zoom the viewport without affecting the document content.

In such cases, where the provided animation effects do not provide needed functionality, an effect defined by script may be used. Such custom effects receive an iteration progress and current iteration from the timing model and are responsible for producing an effect corresponding to the specified time.

Using an effect defined in script it is possible to animate not only otherwise un-animatable attributes and properties, but potentially anything that is accessible via script, including even producing audio or creating vibrations.

For example, using a custom effect that draws to a canvas element, it is possible to produce a complex animated effect featuring patterns that may be difficult to create using CSS or SVG. Compared to using Timing control for script-based animations, this approach ensures the animation is frame-rate independent and can be paused, reversed, eased with timing effects, accelerated, synchronized with other animations, and be controlled in the same manner as any other Web Animations animation without any additional programming.

A custom effect is an author-defined programming callback that is passed timing information when sampling is performed.

4.8.1. Sampling custom effects

Custom effects are called for each referencing animation effect when a sample is performed based on the following criteria.

  1. If, on the previous sample, the animation effect referencing the custom effect:

    Call the callback passing an unresolved iteration progress and the target element from the previous sample as parameters to the callback.

  2. Call the callback for the current target element based on the first matching condition from the following:

    If the animation effect referencing the custom effect is not in effect but was in effect in the previous sample,

    Call the callback passing an unresolved iteration progress and the current target element as parameters to the callback.

    Otherwise, if the animation effect referencing the custom effect:

    Call the callback passing with the referencing animation effect’s current iteration progress and target element as parameters to the callback.

There may be use cases where an action needs to be triggered at a specific point in an animation tree. In many cases this can be achieved by inserting a custom effect with a step-start easing that spans the period during which the action should be triggered. However, this can impose additional layout requirements on the content which might be cumbersome to accomodate.

Some alternatives under consideration:

4.8.2. Execution order of custom effects

Since custom effects, unlike animation effects, are not limited to a single target property, the steps for assessing their order of execution differs from animation effects.f

Custom effects are executed after all animation effects have completed and applied their result to their targets (see §4.5.5 Applying the composited result).

Need to define this more precisely. Are styles flushed? Presumably they are. Can we suspend reflow for the duration of executing the script-based animation effects and just do it once afterwards?

Within the set of custom effects, the order of execution is the same as that defined for animation effects in §4.5.2 The effect stack. Items sorted earlier are executed before those sorted later.

5. Programming interface

This section is non-normative

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.

5.1. Time values in the programming interface

Time values are represented in the programming interface with the type double. Unresolved time values are represented by the value null.

5.2. The AnimationTimeline interface

Timelines are represented in the Web Animations API by the AnimationTimeline interface.

interface AnimationTimeline {
    readonly attribute double? currentTime;
    Animation           play (optional AnimationEffectReadOnly? effect = null);
};
currentTime, of type double, readonly, nullable

Returns the time value for this timeline or null if this timeline is inactive.

Animation play(optional AnimationEffectReadOnly? effect = null)

Creates a new Animation object associated with this timeline that begins playback as soon as it is ready.

If effect is specified, it will be used as the animation’s target effect.

It has been suggested this method be renamed, or even removed (see TAG feedback).

Need to define the start behavior when effect is null.

The new Animation object is created using the Animation() constructor passing this AnimationTimeline object as the timeline parameter and effect as the effect parameter.

Following construction of the Animation object, the procedure to play an animation is performed on the newly constructed object with the auto-rewind flag set to true.

effect

the target effect to assign to the newly-created Animation object.

5.3. The DocumentTimeline interface

Document timelines, including the default document timeline, are represented in the Web Animations API by the DocumentTimeline interface.

dictionary DocumentTimelineOptions {
  DOMHighResTimeStamp originTime = 0;
};

[Constructor (optional DocumentTimelineOptions options)]
interface DocumentTimeline : AnimationTimeline {
};
originTime, of type DOMHighResTimeStamp, defaulting to 0

The zero time for the timeline specified as a real number of milliseconds relative to navigationStart moment [NAVIGATION-TIMING] of the document with which the timeline is associated.

DocumentTimeline (options)

Creates a new DocumentTimeline. The Document with which the timeline is associated is the Document associated with the Window that is the current global object.

options

Configuration parameters for the newly-created timeline. This specification defines only the originTime member but other specifications may extend this set.

5.4. The Animation interface

Animations are represented in the Web Animations API by the Animation interface.

[Constructor (optional AnimationEffectReadOnly? effect = null,
              optional AnimationTimeline? timeline)]
interface Animation : EventTarget {
             attribute DOMString                id;
             attribute AnimationEffectReadOnly? effect;
             attribute AnimationTimeline?       timeline;
             attribute double?                  startTime;
             attribute double?                  currentTime;
             attribute double                   playbackRate;
    readonly attribute AnimationPlayState       playState;
    readonly attribute Promise<Animation>       ready;
    readonly attribute Promise<Animation>       finished;
             attribute EventHandler             onfinish;
             attribute EventHandler             oncancel;
    void cancel ();
    void finish ();
    void play ();
    void pause ();
    void reverse ();
};
Animation (effect, timeline)

Creates a new Animation object using the following procedure.

  1. Let animation be a new Animation object.

  2. Run the procedure to set the timeline of an animation on animation passing timeline as the new timeline or, if a timeline argument is not provided, passing the default document timeline of the Document associated with the Window that is the current global object.

  3. Run the procedure to set the target effect of an animation on animation passing source as the new effect.

effect

An optional value which, if not null, specifies the target effect to assign to the newly created animation.

timeline

An optional value which, if provided, specifies the timeline with which to associate the newly-created animation. If not provided, the default document timeline of the Document associated with the Window that is the current global object is used.

id, of type DOMString

A string used to identify the animation.

effect, of type AnimationEffectReadOnly, nullable

The target effect associated with this animation. Setting this attribute updates the object’s target effect using the procedure to set the target effect of an animation.

timeline, of type AnimationTimeline, nullable

The timeline associated with this animation. Setting this attribute updates the object’s timeline using the procedure to set the timeline of an animation.

startTime, of type double, nullable

Returns the start time of this animation. Setting this attribute updates the animation start time using the procedure to set the animation start time of this object to the new value.

currentTime, of type double, nullable

The current time of this animation. Setting this attribute follows the procedure to set the current time of this object to the new value.

playbackRate, of type double

The playback rate of this animation. Setting this attribute follows the procedure to set the animation playback rate of this object to the new value.

playState, of type AnimationPlayState, readonly

The play state of this animation.

ready, of type Promise<Animation>, readonly

Returns the current ready promise for this object.

This should become a cancelable promise when (if) such things exist.

finished, of type Promise<Animation>, readonly

Returns the current finished promise for this object.

This should become a cancelable promise when (if) such things exist.

onfinish, of type EventHandler

The event handler for the finish event.

oncancel, of type EventHandler

The event handler for the cancel event.

void cancel()

Clears all effects caused by this animation and aborts its playback by running the cancel an animation procedure for this object.

void finish()

Seeks the animation to the end of the target effect in the current direction by running the finish an animation procedure for this object.

DOMException of type InvalidStateError

Raised if this animation’s playback rate is zero, or if this animation’s playback rate is > zero and the end time of this animation’s target effect is infinity.

void play()

Unpauses the animation and rewinds if it has finished playing using the procedure to play an animation for this object with the auto-rewind flag set to true.

void pause()

Suspends the playback of this animation by running the procedure to pause an animation for this object.

void reverse()

Inverts the playback rate of this animation and plays it using the reverse an animation procedure for this object. As with play(), this method unpauses the animation and, if the animation has already finished playing in the reversed direction, seeks to the start of the target effect.

5.4.1. The AnimationPlayState enumeration

enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
idle

Corresponds to the idle play state.

pending

Corresponds to the pending play state.

running

Corresponds to the running play state.

paused

Corresponds to the paused play state.

finished

Corresponds to the finished play state.

5.5. The AnimationEffectReadOnly interface

Animation effects are represented in the Web Animations API by the AnimationEffectReadOnly interface.

Interfaces that inherit from AnimationEffectReadOnly that are intended to be mutable must also implement the additional AnimationEffectMutable interface.

interface AnimationEffectReadOnly {
    readonly attribute AnimationEffectTimingReadOnly timing;
    ComputedTimingProperties getComputedTiming();
    // Timing hierarchy
    readonly attribute GroupEffectReadOnly?     parent;
    readonly attribute AnimationEffectReadOnly? previousSibling;
    readonly attribute AnimationEffectReadOnly? nextSibling;
};
[NoInterfaceObject]
interface AnimationEffectMutable {
    void before (AnimationEffectReadOnly... effects);
    void after (AnimationEffectReadOnly... effects);
    void replace (AnimationEffectReadOnly... effects);
    void remove ();
};
In future, we may expose any sample (double? progress, double currentIteration, Animatable? target, any underlyingValue) so that the animation effects can be driven apart from the timing model.
timing, of type AnimationEffectTimingReadOnly, readonly

Returns the input timing properties specified for this animation effect. This is comparable to the specified style on an Element, elem.style.

getComputedTiming()

Returns the calculated timing properties for this animation effect. This is comparable to the computed style of an Element, window.getComputedStyle(elem).

Although many of the attributes of the returned object are common to the AnimationEffectTimingReadOnly object returned by the timing attribute, the values returned by this object differ in the following ways:

parent, of type GroupEffectReadOnly, readonly, nullable

The parent group of this animation effect or null if this animation effect does not have a parent group.

Should this be parentGroup?

previousSibling, of type AnimationEffectReadOnly, readonly, nullable

The previous sibling of this animation effect.

nextSibling, of type AnimationEffectReadOnly, readonly, nullable

The next sibling of this animation effect.

void before (AnimationEffectReadOnly... effects)

Inserts effects before this animation effect.

  1. If there is no parent group, abort these steps.

  2. If any of the animation effects in effects is an inclusive ancestor of this animation effect, throw a HierarchyRequestError exception and abort these steps.

  3. Insert effects before this animation effect.

Note that this definition precludes the following usage since effect is an inclusive ancestor of itself:
effect.before(effect); // throws HierarchyRequestError
void after(AnimationEffectReadOnly... effects)

Inserts effects after this animation effect.

  1. If there is no parent group, abort these steps.

  2. If any of the animation effects in effects is an inclusive ancestor of this animation effect, throw a HierarchyRequestError exception and abort these steps.

  3. Let reference child be the next sibling of this animation effect not in effects.

  4. Insert effects before reference child.

void replace(AnimationEffectReadOnly... effects)

Replaces this AnimationEffectReadOnly with the passed in effects.

  1. If there is no parent group, abort these steps.

  2. If any of the animation effects in effects is an inclusive ancestor of the parent group throw a HierarchyRequestError exception and abort these steps.

  3. Let reference child be the next sibling of this animation effect not in effects.

  4. Remove this animation effect from its parent group.

  5. Insert effects before reference child.

void remove()

Removes this animation effect from its parent group or animation.

5.6. The AnimationEffectTimingReadOnly interface

This interface needs a constructor.

interface AnimationEffectTimingReadOnly {
    readonly attribute double                             delay;
    readonly attribute double                             endDelay;
    readonly attribute FillMode                           fill;
    readonly attribute double                             iterationStart;
    readonly attribute unrestricted double                iterations;
    readonly attribute (unrestricted double or DOMString) duration;
    readonly attribute double                             playbackRate;
    readonly attribute PlaybackDirection                  direction;
    readonly attribute DOMString                          easing;
};
delay, of type double, readonly

The start delay which represents the number of milliseconds from an animation effect’s start time to the start of the active interval.

endDelay, of type double, readonly

The end delay which represents the number of milliseconds from the end of an animation effect’s active interval until the start time of any animation effect that may follow, for example, in a sequence effect. until its end time.

fill, of type FillMode, readonly

The fill mode which defines the behavior of the animation effect outside its active interval.

When performing timing calculations the special value auto is expanded to one of the fill modes recognized by the timing model as follows,

If the animation effect to which the fill mode is being is applied is a keyframe effect,

Use none as the fill mode.

Otherwise,

Use both as the fill mode.

iterationStart, of type double, readonly

The animation effect’s iteration start 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.

Note that the value of iterations is effectively added to the iterationStart such that an animation effect with an iterationStart of ‘0.5’ and iterations of ‘2’ will still repeat twice however it will begin and end half-way through its iteration interval.

iterationStart values greater than or equal to one are typically only useful in combination with an animation effect that has an iteration composite operation of accumulate or when the current iteration index is otherwise significant.

iterations, of type unrestricted double, readonly

The animation effect’s iteration count 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.

A value of positive infinity indicates that the animation effect repeats forever.

duration, of type (unrestricted double or DOMString), readonly

The iteration duration 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 animation effect. The string value auto is used to indicate that the iteration duration reflects the animation effect’s intrinsic iteration duration.

playbackRate, of type double, readonly

The animation effect’s playback rate property which is a multiplier applied to the local time potentially causing the effect to run at a different rate to its natural speed.

direction, of type PlaybackDirection, readonly

The playback direction of the animation effect which defines whether playback proceeds forwards, backwards, or alternates on each iteration.

easing, of type DOMString, readonly

The timing function used to scale the time to produce easing effects.

The syntax of the string is defined by the <single-timing-function> production [CSS-TIMING].

5.7. The AnimationEffectTiming interface

The AnimationEffectTiming interface is a mutable subclass of AnimationEffectTimingReadOnly returned for the timing attribute of a mutable animation effect such asKeyframeEffect, GroupEffect, or SequenceEffect.

This interface needs a constructor.

interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
    inherit attribute double                             delay;
    inherit attribute double                             endDelay;
    inherit attribute FillMode                           fill;
    inherit attribute double                             iterationStart;
    inherit attribute unrestricted double                iterations;
    inherit attribute (unrestricted double or DOMString) duration;
    inherit attribute double                             playbackRate;
    inherit attribute PlaybackDirection                  direction;
    inherit attribute DOMString                          easing;
};
delay, of type double

See the delay attribute of the AnimationEffectTimingReadOnly interface.

endDelay, of type double

See the endDelay attribute of the AnimationEffectTimingReadOnly interface.

fill, of type FillMode

See the fill attribute of the AnimationEffectTimingReadOnly interface.

iterationStart, of type double

See the iterationStart attribute of the AnimationEffectTimingReadOnly interface.

If an attempt is made to set this attribute to a value less than zero, a TypeError must be thrown and the value of the iterationStart attribute left unchanged.

Note: The reasoning for using a TypeError rather than a RangeError is to mirror the behavior of WebIDL’s [EnforceRange] annotation should that annotation be able to be used with floating-point values in the future.

iterations, of type unrestricted double

See the iterations attribute of the AnimationEffectTimingReadOnly interface.

This may be set to +Infinity to cause the animation effect to repeat indefinitely.

If an attempt is made to set this attribute to a value less than zero or a NaN value, a TypeError must be thrown and the value of the iterations attribute left unchanged.

duration, of type (unrestricted double or DOMString)

See the duration attribute of the AnimationEffectTimingReadOnly interface.

If an attempt is made to set this attribute to a value less than zero, a NaN value, or a string other than the lowercase value auto, a TypeError must be thrown and the value of the duration attribute left unchanged.

playbackRate, of type double

See the playbackRate attribute of the AnimationEffectTimingReadOnly interface.

direction, of type PlaybackDirection

See the direction attribute of the AnimationEffectTimingReadOnly interface.

easing, of type DOMString

See the easing attribute of the AnimationEffectTimingReadOnly interface.

If an attempt is made to set this attribute to an invalid value, a TypeError must be thrown and the value of the easing attribute left unchanged.

5.8. The AnimationEffectTimingProperties dictionary

The AnimationEffectTimingProperties dictionary encapsulates the timing properties of an AnimationEffectReadOnly so that they can be set in bulk (as with the Animation() constructor) or returned as a readonly snapshot (as with the getComputedTiming() method of the AnimationEffectReadOnly interface).

AnimationEffectTimingProperties is simply a dictionary-equivalent of the AnimationEffectTiming interface. The meaning and acceptable values for each of its members are identical.

dictionary AnimationEffectTimingProperties {
    double                             delay = 0;
    double                             endDelay = 0;
    FillMode                           fill = "auto";
    double                             iterationStart = 0.0;
    unrestricted double                iterations = 1.0;
    (unrestricted double or DOMString) duration = "auto";
    double                             playbackRate = 1.0;
    PlaybackDirection                  direction = "normal";
    DOMString                          easing = "linear";
};
delay, of type double, defaulting to 0

See the delay attribute of the AnimationEffectTiming interface.

endDelay, of type double, defaulting to 0

See the endDelay attribute of the AnimationEffectTiming interface.

fill, of type FillMode, defaulting to "auto"

See the fill attribute of the AnimationEffectTiming interface.

iterationStart, of type double, defaulting to 0.0

See the iterationStart attribute of the AnimationEffectTiming interface.

iterations, of type unrestricted double, defaulting to 1.0

See the iterations attribute of the AnimationEffectTiming interface.

duration, of type (unrestricted double or DOMString), defaulting to "auto"

See the duration attribute of the AnimationEffectTiming interface.

playbackRate, of type double, defaulting to 1.0

See the playbackRate attribute of the AnimationEffectTiming interface.

direction, of type PlaybackDirection, defaulting to "normal"

See the direction attribute of the AnimationEffectTiming interface.

easing, of type DOMString, defaulting to "linear"

See the easing attribute of the AnimationEffectTiming interface.

5.9. The ComputedTimingProperties dictionary

Timing parameters calculated by the timing model are exposed using ComputedTimingProperties dictionary objects.

dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
    double               startTime;
    unrestricted double  endTime;
    unrestricted double  activeDuration;
    double?              localTime;
    double?              progress;
    unrestricted double? currentIteration;
};
startTime, of type double

The start time of this animation effect in milliseconds. This is the time at which the parent group, if any, has scheduled this child to run within its transformed time space, that is, the animation effect’s inherited time space.

The start of the active interval is based on the sum of the start time and start delay.

endTime, of type unrestricted double

The end time of the animation effect expressed in milliseconds in inherited time space. This corresponds to the end of the animation effect’s active interval plus any end delay.

activeDuration, of type unrestricted double

The active duration of this animation effect.

localTime, of type double, nullable

The local time of this animation effect.

This will be null if this animation effect is not associated with an animation or if it has a parent group that is not in effect.

progress, of type double, nullable

The current iteration progress of this animation effect.

currentIteration, of type unrestricted double, nullable

The current iteration 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 Infinity.

As with unresolved times, an unresolved current iteration is represented by a null value.

5.9.1. The FillMode enumeration

enum FillMode { "none", "forwards", "backwards", "both", "auto" };
none

No fill.

forwards

Fill forwards.

backwards

Fill backwards.

both

Fill backwards and forwards.

auto

Fill backwards and forwards when applied to an GroupEffectReadOnly and no fill when applied to an KeyframeEffectReadOnly.

5.9.2. The PlaybackDirection enumeration

enum PlaybackDirection { "normal", "reverse", "alternate", "alternate-reverse" };
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.

5.10. The GroupEffectReadOnly and GroupEffect interfaces

Group effects are represented by the GroupEffectReadOnly interface. Mutable group effects are represented by the GroupEffect interface.

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface GroupEffectReadOnly : AnimationEffectReadOnly {
    readonly attribute AnimationNodeList      children;
    readonly attribute AnimationEffectReadOnly? firstChild;
    readonly attribute AnimationEffectReadOnly? lastChild;
    GroupEffect clone ();
};

[NoInterfaceObject]
interface GroupEffectMutable {
  void prepend (AnimationEffectReadOnly... effects);
  void append (AnimationEffectReadOnly... effects);
};

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface GroupEffect : GroupEffectReadOnly {
};
GroupEffect implements AnimationEffectMutable;
GroupEffect implements GroupEffectMutable;
GroupEffectReadOnly ()

Creates a new GroupEffectReadOnly object using the following procedure:

  1. Create a new GroupEffectReadOnly object, group.

  2. Let timing input be the result of applying the procedure to process a timing argument to timing.

  3. Set group.timing to a new AnimationEffectTimingReadOnly object created in the current realm (that is, the same realm used to create effect) whose attributes are assigned the value of the member of the same name on timing input.

  4. Insert children before null.

children

A sequence of animation effects to add as children of this group.

These children are appended in sequence using the same semantics as the append() method of the GroupEffectMutable interface.

timing

The timing properties or iteration duration of the new group effect.

GroupEffect ()

Creates a new GroupEffect object using the same procedure as with the GroupEffectReadOnly() constructor with the following differences:

children, of type AnimationNodeList, readonly

The list of child effects in the group.

firstChild, of type AnimationEffectReadOnly, readonly, nullable

The first child of this group effect.

lastChild, of type AnimationEffectReadOnly, readonly, nullable

The last child of this group effect.

void prepend (AnimationEffectReadOnly... effects)
  1. If any of the animation effects in effects is an inclusive ancestor of this animation effect, throw a HierarchyRequestError exception and abort these steps.

  2. Insert effects before the first child.

void append (AnimationEffectReadOnly... effects)
  1. If any of the animation effects in effects is an inclusive ancestor of this animation effect, throw a HierarchyRequestError exception and abort these steps.

  2. Insert effects before null.

GroupEffect clone ()

Creates a deep copy of this GroupEffectReadOnly object using the following procedure.

  1. Let source be this GroupEffectReadOnly object, the object to be cloned.

  2. Let cloned timing be a new AnimationEffectTimingProperties object whose members are assigned the value of the attribute with the same name on source.timing.

  3. Let cloned children be an empty sequence of AnimationEffectReadOnly objects.

  4. For each child in source.children, append the result of calling child.clone() to cloned children.

  5. Return a new GroupEffect object created by calling the GroupEffect() constructor with parameters GroupEffect(cloned children, cloned timing).

5.10.1. Processing a timing argument

The timing parameter passed to the GroupEffectReadOnly(), GroupEffect(), SequenceEffectReadOnly(), or SequenceEffect() constructor may be an AnimationEffectTimingProperties object, a double representing the duration of the animation effect in milliseconds, or undefined.

The following procedure to process a timing argument, timing, normalizes the above inputs into a AnimationEffectTimingProperties object.

If timing is an AnimationEffectTimingProperties object,

Return timing.

If timing is a double,

Return a new AnimationEffectTimingProperties object with all members set to their default values and duration set to timing.

Otherwise (timing is undefined),

Return a new AnimationEffectTimingProperties object with all members set to their default values.

Note that since AnimationEffectTimingReadOnly objects have the same member keys as AnimationEffectTimingProperties dictionaries, it is also possible to pass the timing member of another AnimationEffectReadOnly to the any of the methods that invoke this method as the timing parameter.

Doing so will cause the AnimationEffectTimingReadOnly object to be treated as an AnimationEffectTimingProperties dictionary and thus it will effectively be cloned, not shared.

For example, the timing of two animations may be aligned as follows:

var effectA = elem.animate({ opacity: 0 }, 1000).effect;
var effectB = elem.animate({ width: '0px' }, effectA.timing).effect;
alert(effectA.timing !== effectB.timing); // Displays 'true'
alert(effectA.timing.duration === effectB.timing.duration); // Displays 'true'

5.10.2. Definitions for manipulating hierarchies

The next sibling of effect not included in a set of animation effects, effects is determined using the following teps:

  1. Let context effect be effect.

  2. While the next sibling of context effect is not null perform the following steps:

    1. Let context effect be the next sibling of context effect.

    2. If context effect is not in effects return context effect and abort these steps.

  3. Return null.

To remove a effect from its parent group or animation, perform the steps corresponding to the first matching condition from below, if any:

If effect has a parent group,

Remove effect from the parent group’s list of child effects.

If effect is directly associated with an animation,

Disassociate effect from the animation.

To insert a series of zero or more animation effects, effects, to parent’s list of child effects before reference child perform the following steps for each effect in effects:

  1. Remove effect from its parent.

  2. Insert effect to parent’s list of child effects before reference child

5.11. The AnimationNodeList interface

A list of animation effects may be represented by an AnimationNodeList.

The AnimationNodeList interface supports indexed properties with indices in the range 0 ≤ index < length.

The only reason this interface exists is to provide a familiar experience for authors familiar with DOM interfaces where child nodes are accessed via a children member.

interface AnimationNodeList {
    readonly attribute unsigned long length;
    getter AnimationEffectReadOnly? item (unsigned long index);
};
length, of type unsigned long, readonly

The number of animation effects in the list.

getter AnimationEffectReadOnly? item(unsigned long index)

Returns the animation effect at index. If index is greater than or equal to length returns null.

5.12. The SequenceEffectReadOnly and SequenceEffect interfaces

Sequence effects are represented by the SequenceEffectReadOnly interface. Mutable sequence effects are represented by the SequenceEffect interface.

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface SequenceEffectReadOnly : GroupEffectReadOnly {
    SequenceEffect clone ();
};

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface SequenceEffect : SequenceEffectReadOnly {
};
SequenceEffect implements AnimationEffectMutable;
SequenceEffect implements GroupEffectMutable;
Constructor (sequence<AnimationEffectReadOnly>? children, optional (unrestricted double or AnimationEffectTimingProperties) timing)

The meaning and handling of each of the parameters in this constructor is identical to the GroupEffect() constructor.

SequenceEffect clone ()

Creates a deep copy of this SequenceEffectReadOnly object using the same procedure as defined for the clone() method of the GroupEffectReadOnly interface except that a new SequenceEffect object is created.

5.13. The KeyframeEffectReadOnly and KeyframeEffect interfaces

Keyframe effects are represented by the KeyframeEffectReadOnly interface. Mutable keyframe effects are represented by the KeyframeEffect interface.

[Constructor ((Element or CSSPseudoElement)? target,
              object? keyframes,
              optional (unrestricted double or KeyframeEffectOptions) options),
 Constructor (KeyframeEffectReadOnly source)]
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
    readonly attribute (Element or CSSPseudoElement)? target;
    readonly attribute IterationCompositeOperation    iterationComposite;
    readonly attribute CompositeOperation             composite;
    sequence<object> getKeyframes ();
};

[Constructor ((Element or CSSPseudoElement)? target,
              object? keyframes,
              optional (unrestricted double or KeyframeEffectOptions) options),
 Constructor (KeyframeEffectReadOnly source)]
interface KeyframeEffect : KeyframeEffectReadOnly {
    inherit attribute (Element or CSSPseudoElement)? target;
    inherit attribute IterationCompositeOperation    iterationComposite;
    inherit attribute CompositeOperation             composite;
    void setKeyframes (object? keyframes);
};
KeyframeEffect implements AnimationEffectMutable;
KeyframeEffectReadOnly (target, keyframes, options)

Creates a new KeyframeEffectReadOnly object using the following procedure:

  1. Create a new KeyframeEffectReadOnly object, effect.

  2. Set the target element of effect to target.

  3. Let timing input be the result corresponding to the first matching condition from below.

    If options is a KeyframeEffectOptions object,

    Let timing input be options.

    If options is a double,

    Let timing input be a new AnimationEffectTimingProperties object with all members set to their default values and duration set to options.

    Otherwise (options is undefined),

    Let timing input be a new AnimationEffectTimingProperties object with all members set to their default values.

  4. Set effect.timing to a new AnimationEffectTimingReadOnly object created in the current realm (that is, the same realm used to create effect) whose attributes are assigned the value of the member of the same name on timing input.

    When assigning the attributes, apply the same error-handling as defined for setters on the AnimationEffectTiming interface. If any of those setters require an exception to be thrown, the same exception must be thrown by this procedure, aborting all further steps.

    For example, the setter for the duration attribute on the AnimationEffectTiming interface requires that a TypeError be thrown if an attempt is made to set the duration to a value less than zero. Likewise, if the duration specified on timing input is less that zero, this procedure too must throw a TypeError and abort all further steps.

    Attributes must be assigned in the order in which they appear in the AnimationEffectTimingReadOnly interface.

    Make a constructor for AnimationEffectTimingReadOnly and call that here.

  5. If options is a KeyframeEffectOptions object, assign the iterationComposite, and composite, properties of effect to the corresponding value from options.

    As with timing input, when assigning these properties the error-handling defined for the corresponding setters on the KeyframeEffect interface is applied. As such, if any of those setters require an exception to be thrown for the values specified by options, this procedure must throw the same exception and abort all further steps.

  6. Initialize the set of keyframes by performing the procedure defined for setKeyframes() passing keyframes as the input.

(Element or CSSPeudoElement)? target

The target element or target pseudo-element. This may be null for animations that do not target a specific element.

object? keyframes

The set of keyframes to use. The format and processing of this argument is defined in §5.13.3 Processing a keyframes argument.

optional KeyframeEffectOptions options

Either a number specifying the iteration duration of the effect, or a collection of properties specifying the timing and behavior of the effect.

KeyframeEffectReadOnly (source)

Creates a new KeyframeEffectReadOnly object with the same properties as source using the following procedure:

  1. Create a new KeyframeEffectReadOnly object, effect.

  2. Set the following properties of effect using the corresponding values of source:

    If source is using a SharedKeyframeList should we continue to share it?

  3. Set effect’s timing member to a new AnimationEffectTimingReadOnly object created in the current realm (that is, the same realm used to create effect) whose attributes are assigned the value of the member of the same name on source’s timing object.

    Note: Unlike the KeyframeEffectReadOnly(target, keyframes, options) constructor, we do not need to re-throw exceptions or specify the order in which members are assigned since the values specified on source’s timing can be assumed to be valid.

KeyframeEffectReadOnly source

The keyframe effect from which to copy the various properties that define the new keyframe effect.

This method is largely provided for consistency with KeyframeEffect(source).

KeyframeEffect (target, keyframes, options)

Creates a new KeyframeEffect object using the same procedure as with the KeyframeEffectReadOnly(target, keyframes, options) constructor with the following differences:

Examples of the usage of this constructor are given in §5.13.1 Creating a new KeyframeEffect object.

KeyframeEffect (source)

Creates a new KeyframeEffect object using the same procedure as with the KeyframeEffectReadOnly(source) constructor with the following differences:

This section is non-normative

This constructor is provided so that authors can take the animations generated by declarative markup, which are returned in a read-only format, and produce a mutable copy.

For example, it is possible to define an animation using CSS and subsequently replace its animation effect as follows:

// Create and get a CSSAnimation
elem.style.animation = 'swellMargin 2s';
const animation = elem.getAnimations().find(
  animation => animation.animationName == 'swellMargin');
console.log(animation.effect.constructor.name); // "KeyframeEffectReadOnly"

// Make a mutable copy
animation.effect = new KeyframeEffect(animation.effect);
console.log(animation.effect.constructor.name); // "KeyframeEffect"

// It is now possible to manipulate the effect
// e.g. apply 'add' composite mode
animation.effect.composite = 'add';

// Note that changing 'animation-*' properties will not affect the
// new effect.
elem.style.animationDuration = '3s';
console.log(animation.effect.timing.duration); // 2000

// However, 'animation-*' properties still affect the /Animation/
elem.style.animationPlayState = 'paused';
console.log(animation.playState); // "pending" (waiting to pause)

// Likewise:
elem.style.animation = '';
console.log(animation.playState); // "idle" (animation has been cancelled)
target, of type (Element or CSSPseudoElement), readonly, nullable

The element or pseudo-element being animated by this object. 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.

iterationComposite, of type IterationCompositeOperation, readonly

The iteration composite operation property of this keyframe effect as specified by one of the IterationCompositeOperation enumeration values.

On setting, sets the iteration composite operation property of this animation effect to the provided value.

composite, of type CompositeOperation, readonly

The composite operation used to composite this keyframe effect with the effect stack, as specified by one of the CompositeOperation enumeration values.

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

sequence<object> getKeyframes()

Returns the keyframes that make up this effect along with their computed keyframe offsets.

This section is non-normative

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

dictionary ComputedKeyframe {
    // ... property-value pairs ...
    // i.e. DOMString propertyName
    double?             offset = null;
    double              computedOffset;
    DOMString           easing = "linear";
    CompositeOperation? composite;
};

The meaning and values of each member is as follows:

offset

The keyframe offset of the keyframe specified as a number between 0.0 and 1.0 inclusive, or null.

This will be null if the keyframe is to be automatically spaced between adjacent keyframes.

computedOffset

The computed keyframe offset for this keyframe calculated as part of running the compute missing keyframe offsets procedure.

Unlike the offset member, the computedOffset is never null.

easing

The timing function used to transform the progress of time from this keyframe until the next keyframe in the series.

composite

The keyframe-specific composite operation used to combine the values specified in this keyframe with the underlying value.

This member will be absent if the composite operation specified on the keyframe effect is being used.

Since keyframes 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 result be an empty sequence of objects.

  2. Let keyframes be the result of applying the procedure to compute missing keyframe offsets to the keyframes for this keyframe effect.

  3. For each keyframe in keyframes perform the following steps:

    1. Initialize a dictionary object, output keyframe, using the following definition:

      dictionary BaseComputedKeyframe {
           double?            offset = null;
           double             computedOffset;
           DOMString          easing = "linear";
           CompositeOperation composite;
      };
      
    2. Set offset, computedOffset, easing members of output keyframe to the respective values keyframe offset, computed keyframe offset, and keyframe-specific timing function of keyframe.

    3. If keyframe has a keyframe-specific composite operation, set composite to that value.

    4. For each animation property-value pair specified on keyframe, declaration, perform the following steps:

      1. Let property name be the result of applying the animation property name to IDL attribute name algorithm to the property name of declaration.

      2. Let IDL value be result of serializing the the property value of declaration by passing declaration to the algorithm to serialize a CSS value [CSSOM].

      3. Let value be the result of converting IDL value to an ECMAScript String value.

      4. Call the [[DefineOwnProperty]] internal method on output keyframe with property name property name, Property Descriptor { [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true, [[Value]]: value } and Boolean flag false.

    5. Append output keyframe to result.

  4. Return result.

void setKeyframes(object? keyframes)

Replaces the set of keyframes that make up this effect.

object? keyframes

A series of keyframes whose format and processing is defined by §5.13.3 Processing a keyframes argument.

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

5.13.1. Creating a new KeyframeEffect object

This section is non-normative

The KeyframeEffectReadOnly and KeyframeEffect constructors offer a number of approaches to creating new KeyframeEffectReadOnly and KeyframeEffect objects.

At its simplest, an KeyframeEffect object that changes the ‘left’ property of elem to 100px over three seconds can be constructed as follows:

var effect = new KeyframeEffect(elem, { left: '100px' }, 3000);

The second parameter, representing the list of keyframes, may specify multiple properties. (See §5.13.3 Processing a keyframes argument.)

// 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);

The third parameter, representing the animation’s timing, may simply be a number representing the iteration duration in milliseconds as above, or, to specify further timing properties such as the start delay, an AnimationEffectTimingProperties object can be used, as follows:

var effect =
  new KeyframeEffect(elem, { left: '100px' }, { duration: 3000, delay: 2000 });

If the duration is not specified, the intrinsic iteration duration is used which, for a keyframe effect, is zero. It is possible to create an animation that simply sets a property without any interpolation as follows:

var effect = new KeyframeEffect(elem, { visibility: 'hidden' }, { fill: 'forwards' });

This is particularly useful in combination with other animation effects. For example, fading an element before switching visibility to ‘hidden’ can be achieved as follows,

new SequenceEffect(
  [
    new KeyframeEffect(elem, { opacity: 0 }, 1000),
    new KeyframeEffect(elem, { visibility: 'hidden' }, { fill: 'forwards' })
  ]
);
Having created a KeyframeEffect, it can be played by adding it to an Animation and then playing that animation. For simple effects, however, the Element.animate shortcut is more convenient since it performs these steps automatically. For example,
elem.animate({ left: '100px' }, 3000);

5.13.2. Property names and IDL names

The animation property name to IDL attribute name algorithm for property is as follows:

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

  2. If property refers to the CSS float property, return the string "cssFloat".

  3. If property refers to the CSS offset property, return the string "cssOffset".

  4. Otherwise, return the result of applying the CSS property to IDL attribute algorithm [CSSOM] to property.

The IDL attribute name to animation property name algorithm for attribute is as follows:

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

  2. If attribute is the string "cssFloat", then return an animation property representing the CSS float property.

  3. If attribute is the string "cssOffset", then return an animation property representing the CSS offset property.

  4. Otherwise, return the result of applying the IDL attribute to CSS property algorithm [CSSOM] to attribute.

5.13.3. Processing a keyframes argument

This section is non-normative

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

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

// 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);

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 getKeyframes() method.

Keyframe offsets and keyframe-specific composite operations can only be specified using the array-form as illustrated below:

// 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);

// An SVG-style to-animation
elem.animate([ { left: '0px', composite: 'add' },
               { left: '200px' } ], 2000);

Timing functions may be specified in either form. The array-form allows specifying different timing functions for each keyframe whilst the object-form allows specifying a timing function that will be applied to all keyframes.

// Each keyframe can have a different timing function.
// The timing function specified for the last keyframe is not used.
elem.animate([ { color: 'blue', easing: 'ease-in' },
               { color: 'green', easing: 'ease-out' },
               { color: 'yellow' } ], 2000);

// Each keyframe will have a timing function of 'ease-in-out'
elem.animate({ color: [ 'blue', 'green', 'yellow' ],
               easing: 'ease-in-out' }, 2000);

Note that the easing property in either form sets the keyframe-specific timing function. This is independent from the timing function that applies to the entire iteration duration of the keyframe effect as specified using a KeyframeEffectOptions object (or KeyframeAnimationOptions object when using the animate() method of the Animatable interface).

The type of this 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:

dictionary Keyframe {
    // ... property-value pairs ...
    // i.e. DOMString propertyName
    double?             offset = null;
    DOMString           easing = "linear";
    CompositeOperation  composite;
};

dictionary PropertyIndexedKeyframes {
    // ... property-value and property-valuelist pairs ...
    // i.e. (DOMString or sequence<DOMString>) propertyName
    DOMString           easing = "linear";
};

typedef (sequence<Keyframe> or
         PropertyIndexedKeyframes or
         SharedKeyframeList) KeyframeArgument;

The meaning and allowed values of each argument is as follows:

offset (Keyframe only)

The keyframe offset of the keyframe specified as a number between 0.0 and 1.0 inclusive or null.

A null value indicates that the keyframe should be automatically spaced between adjacent keyframes.

Specifying an offset outside the range [0.0, 1.0] will cause a TypeError 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 timing function 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 easing attribute of the AnimationEffectTiming interface.

composite (Keyframe only)

The keyframe-specific composite operation used to combine the values specified in this keyframe with the underlying value.

If absent, the composite operation specified on the keyframe effect will be used.

Since this type cannot be expressed in WebIDL, its processing is defined in prose following.

For each method that takes a keyframes argument, the procedure to process a keyframes argument is run on the input and the result of that procedure is retained.

First we define two supporting definitions.

The instruction, check the completion record of result, where result is a completion record from calling an ECMAScript operation, is equivalent to the following steps:

  1. If result is an abrupt completion, throw the exception contained in the [[value]] field of result and abort the procedure.

    What should we do if the [[type]] is break, continue, or return? Can it be?

  2. Replace result with the value contained in the [[value]] field of result.

The procedure to process a keyframe-like object, takes two arguments:

and returns a map from either property names to DOMString values if allow lists is false, or from property names to sequences of DOMString values otherwise, using the following procedure:

  1. Run the procedure to convert an ECMAScript value to a dictionary type [WEBIDL] with keyframe input as the ECMAScript value, and the dictionary type depending on the value of the allow lists flag as follows:

    If allow lists is true,

    Use the following dictionary type:

    dictionary BasePropertyIndexedKeyframe {
        DOMString          easing = "linear";
        CompositeOperation composite;
    };
    
    Otherwise,

    Use the following dictionary type,

    dictionary BaseKeyframe {
        double?            offset = null;
        DOMString          easing = "linear";
        CompositeOperation composite;
    };
    

    Do we need null offsets or is it enough to just test for the absence of the property?

    Store the result of this procedure as keyframe output.

  2. Build up a list of animatable properties as follows:

    1. Let animatable properties be a list of property names (including shorthand properties that have longhand sub-properties that are animatable) that can be animated by the implementation.

    2. Convert each property name in animatable properties to the equivalent IDL attribute by applying the animation property name to IDL attribute name algorithm.

  3. Let input properties be the result of calling the EnumerableOwnNames operation with keyframe input as the object.

  4. Make up a new list animation properties that consists of all of the properties that are in both input properties and animatable properties, or which are in input properties and conform to the <custom-property-name> production.

  5. Sort animation properties in ascending order by the Unicode codepoints that define each property name.

  6. For each property name in animation properties,

    1. Let raw value be the result of calling the [[Get]] internal method on keyframe input, with property name as the property key and keyframe input as the receiver.

    2. Check the completion record of raw value.

    3. Convert raw value to a DOMString or sequence of DOMStrings property values as follows:

      If allow lists is true,

      Let property values be the result of converting raw value to IDL type (DOMString or sequence<DOMString>) using the procedures defined for converting an ECMAScript value to an IDL value [WEBIDL].

      If property values is a single DOMString, replace property values with a sequence of DOMStrings with the original value of property values as the only element.

      Otherwise,

      Let property values be the result of converting raw value to a DOMString using the procedure for converting an ECMAScript value to a DOMString [WEBIDL].

    4. Calculate the normalized property name as the result of applying the IDL attribute name to animation property name algorithm to property name.

    5. Add a property to to keyframe output with normalized property name as the property name, and property values as the property value.

  7. Return keyframe output.

The procedure to process a keyframes argument takes a nullable ECMAScript object, object, as input and returns either a sequence of keyframes or a SharedKeyframeList object using the following procedure:

  1. If object is null, return an empty sequence of keyframes.

  2. If object is a platform object that implements SharedKeyframeList, return object.

  3. Let processed keyframes be an empty sequence of keyframes.

  4. Let method be the result of GetMethod(object, @@iterator).

  5. Check the completion record of method.

  6. Perform the steps corresponding to the first matching condition from below,

    If method is not undefined,
    1. Let iter be GetIterator(object, method).

    2. Check the completion record of iter.

    3. Repeat:

      1. Let next be IteratorStep(iter).

      2. Check the completion record of next.

      3. If next is false abort this loop.

      4. Let nextItem be IteratorValue(next).

      5. Check the completion record of nextItem.

      6. If nextItem is not an object, throw a TypeError and abort these steps.

      7. Append to processed keyframes the result of running the procedure to process a keyframe-like object passing nextItem as the keyframe input and with the allow lists flag set to false.

    4. If processed keyframes is not loosely sorted by offset, throw a TypeError and abort these steps.

    5. If there exist any keyframe in processed keyframes whose keyframe offset is non-null and less than zero or greater than one, throw a TypeError and abort these steps.

    Otherwise,
    1. Let property-indexed keyframe be the result of running the procedure to process a keyframe-like object passing object as the keyframe input and with the allow lists flag set to true.

    2. Let easing be the value of the “easing” member of property-indexed keyframe.

    3. For each member, m, in property-indexed keyframe, perform the following steps:

      1. Let property name be the key for m.

      2. If property name is “composite” or “easing” skip the remaining steps in this loop and continue from the next member in property-indexed keyframe after m.

      3. Let property values be the value for m.

      4. Let property keyframes be an empty sequence of keyframes.

      5. For each value, v, in property values perform the following steps:

        1. Let k be a new keyframe with a null keyframe offset.

        2. Let k have a property, “easing” with the value of easing.

        3. Add the property-value pair, property namev, to k.

        4. Append k to property keyframes.

      6. Apply the procedure to compute missing keyframe offsets to property keyframes.

      7. Add keyframes in property keyframes to processed keyframes.

    4. Sort processed keyframes by the computed keyframe offset of each keyframe in increasing order.

    5. Merge adjacent keyframes in processed keyframes when they have equal computed keyframe offsets.

  7. For each frame in processed keyframes, perform the following steps:

    1. For each property-value pair in frame, 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.

    2. Let the timing function of frame be the result of parsing the “easing” property on frame using the CSS syntax defined for the easing property of the AnimationEffectTimingReadOnly interface.

      If parsing the “easing” property fails, let the timing function of frame be “linear”.

      User agents that provide support for diagnosing errors in content SHOULD produce an appropriate warning highlighting the unrecognized timing function in this case.

      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.

5.13.4. The KeyframeEffectOptions dictionary

Additional parameters may be passed to the KeyframeEffectReadOnly(target, keyframes, options) and KeyframeEffect(target, keyframes, options) constructors by providing a KeyframeEffectOptions object.

dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
    IterationCompositeOperation iterationComposite = "replace";
    CompositeOperation          composite = "replace";
};
iterationComposite, of type IterationCompositeOperation, defaulting to "replace"

The iteration composite operation used to define the way animation values build from iteration to iteration.

composite, of type CompositeOperation, defaulting to "replace"

The composite operation used to composite this animation with the effect stack, as specified by one of the CompositeOperation enumeration values. This is used for all keyframes that do not specify a keyframe-specific composite operation.

5.14. The IterationCompositeOperation enumeration

The possible values of an animation effect’s iteration composite operation are represented by the IterationCompositeOperation enumeration.

enum IterationCompositeOperation {"replace", "accumulate"};
replace

Corresponds to the replace iteration composite operation value such that the effect value produced is independent of the current iteration.

accumulate

Corresponds to the accumulate iteration composite operation value such that subsequent iterations of an animation effect build on the final value of the previous iteration.

5.15. The CompositeOperation enumeration

The possible values of an animation effect’s composition behavior are represented by the CompositeOperation enumeration.

enum CompositeOperation {"replace", "add", "accumulate"};
replace

Corresponds to the replace composite operation value such that the animation effect overrides the underlying value it is combined with.

add

Corresponds to the add composite operation value such that the animation effect is added to the underlying value with which it is combined.

accumulate

Corresponds to the accumulate composite operation value such that the animation effect is accumulated on to the underlying value.

5.16. The SharedKeyframeList interface

The SharedKeyframeList interface represents a sequence of keyframes that can be shared between KeyframeEffect objects.

This section is non-normative

By using SharedKeyframeList objects, multiple KeyframeEffect objects can re-use the same keyframes without paying the cost of parsing them multiple times.

For example:

var keyframes = new SharedKeyframeList([
 { left: '100px', backgroundColor: 'red' },
 { left: '200px', backgroundColor: 'green', offset: 0.4 },
 { left: '400px', backgroundColor: 'blue' } ]);
var player1 = element1.animate(keyframes, 1000);
var player2 = element2.animate(keyframes, { duration: 1000, delay: 1000 });
[Constructor (object? keyframes)]
interface SharedKeyframeList {
};
SharedKeyframeList(keyframes)

Creates a new SharedKeyframeList object.

keyframes

The keyframes to be shared. This argument is processed using the procedure defined in §5.13.3 Processing a keyframes argument.

5.17. The EffectCallback callback function

Custom effects can be defined in script by providing an EffectCallback callback function.

callback EffectCallback = void (double? progress,
                                (Element or CSSPseudoElement) currentTarget,
                                Animation animation);

An EffectCallback is called each time an KeyframeEffectReadOnly object with which it is associated is sampled.

double? progress

The iteration progress value for which to produce an effect. When this is null, the function SHOULD remove the effect.

(Element or CSSPseudoElement) currentTarget

The target element on which this callback is expected to operate.

Note that currentTarget may differ from animation.target.

If the target element of animation is changed between samples, this method will be called once with a null progress and the previous target element as the currentTarget, then again with the current progress and the updated target element as the currentTarget. This allows the animation effect to be removed from the old target element.

Animation animation

The Animation object that is being sampled.

5.18. The Animatable interface

Objects that may be the target of an KeyframeEffectReadOnly object implement the Animatable interface.

[NoInterfaceObject]
interface Animatable {
    Animation           animate (object? keyframes,
                                 optional (unrestricted double or KeyframeAnimationOptions) options);
    sequence<Animation> getAnimations ();
};
dictionary KeyframeAnimationOptions : KeyframeEffectOptions {
    DOMString id = "";
};
Animation animate(keyframes, options)

Performs the following steps:

  1. Let target be the object on which this method was called.

  2. Construct a new KeyframeEffect object, effect, in the relevant Realm of target by using the same procedure as the KeyframeEffect(target, keyframes, options) constructor, passing target as the target argument, and the keyframes and options arguments as supplied.

    If the above procedure caused an exception to be thrown, propagate the exception and abort this procedure.

  3. Construct a new Animation object, animation, in the relevant Realm of target by using the same procedure as the Animation() constructor, passing effect as the argument of the same name, and the default document timeline of the node document of the element on which this method was called as the timeline argument.

  4. Assign the value of the id member of options to animation’s id attribute.

  5. Run the procedure to play an animation for animation with the auto-rewind flag set to true.

  6. Return animation.

This section is non-normative

The following code fragment:

var animation = elem.animate({ opacity: 0 }, 2000);

is roughly equivalent to:

var effect = new KeyframeEffect(elem, { opacity: 0 }, 2000);
var animation = new Animation(effect, elem.ownerDocument.timeline);
animation.play();
keyframes

The keyframes to use. This value is passed to the KeyframeEffect(target, keyframes, options) constructor as the keyframes parameter and has the same interpretation as defined for that constructor.

options

The timing and animation options for the created KeyframeEffect. This value is passed to the KeyframeEffect(target, keyframes, options) constructor as the options parameter and has the same interpretation as defined for that constructor.

sequence<Animation> getAnimations()

Returns the set of Animation objects whose target effect is current or in effect and contains at least one animation effect whose target element is this object.

If this object is the target element of two or more animation effects which are associated with the same animation, the corresponding Animation object will still only appear in the returned list once. The returned list is sorted using the composite order described for the associated animations of effects in §4.5.2 The effect stack.

The returned list reflects the state after applying any pending changes to animation such as changes to animation-related style properties that have yet to be processed.

id, of type DOMString, defaulting to ""

The string to assign to the generated Animation's id attribute.

5.19. Extensions to the Document interface

The following extensions are made to the Document interface defined in [DOM].

partial interface Document {
    readonly attribute DocumentTimeline timeline;
    sequence<Animation> getAnimations();
};
timeline, of type DocumentTimeline, readonly

The DocumentTimeline object representing the default document timeline.

sequence<Animation> getAnimations()

Returns the set of Animation objects that have an associated target effect which is current or in effect and whose target element is a descendant of the document.

The returned list is sorted using the composite order described for the associated animations of effects in §4.5.2 The effect stack.

The returned list reflects the state after applying any pending changes to animation such as changes to animation-related style properties that have yet to be processed.

Both this method and getAnimations() on the Animatable interface require retaining forwards-filling animation effects and their animations such that a document that repeatedly produces forwards-filling animations will consume memory in an unbounded fashion. We may need to revise this definition (previously these methods only returned animations whose target effect was current) or provide a loophole for implementations to discard old animations in such conditions.

5.20. Extensions to the Element interface

Since DOM Elements may be the target of an animation, the Element interface [DOM] is extended as follows:

Element implements Animatable;

This allows the following kind of usage.

elem.animate({ color: 'red' }, 2000);

5.21. Extensions to the CSSPseudoElement interface

Since keyframe effects may also target pseudo-elements, the CSSPseudoElement interface [css-pseudo-4] is also defined to be animatable.

CSSPseudoElement implements Animatable;

5.22. The AnimationPlaybackEvent interface

Animation events are represented using the AnimationPlaybackEvent interface.

[Constructor (DOMString type, optional AnimationPlaybackEventInit eventInitDict)]
interface AnimationPlaybackEvent : Event {
    readonly attribute double? currentTime;
    readonly attribute double? timelineTime;
};
dictionary AnimationPlaybackEventInit : EventInit {
    double? currentTime = null;
    double? timelineTime = null;
};
AnimationPlaybackEvent(type, eventInitDict)

Constructs a new AnimationPlaybackEvent object using the procedure defined for constructing events [DOM].

currentTime, of type double, readonly, nullable

The event current time.

timelineTime, of type double, readonly, nullable

The event timeline time.

currentTime, of type double, nullable, defaulting to null

The event current time.

timelineTime, of type double, nullable, defaulting to null

The event timeline time.

5.23. Model liveness

Changes made to any part of the model, cause the entire timing model to be updated and any dependent style.

This section is non-normative

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 §3.5.5 Setting the current time of an animation) via the programming interface, the value returned when querying the animation’s startTime will reflect updated state of the model immediately.

// Initially animation.effect.getComputedTiming().localTime is 3000
animation.currentTime += 2000;
alert(animation.effect.getComputedTiming().localTime); // Displays ‘5000’

The same concept applies to more complex modifications of the Web Animations model such as adding and removing children from an GroupEffect.

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.

// Set opacity to 0 immediately
elem.animate({ opacity: 0 }, { fill: 'forwards' });
alert(window.getComputedStyle(elem).opacity); // Displays ‘0’
Changes made to the model using the programming interface do not cause any EffectCallback functions to be called

For example, in the following code, the callback function will not be called until after the script block has completed during regular sampling.

var timesCalled = 0;
elem.animate(function() {
  timesCalled++;
}, 10000);
alert(timesCalled); // Displays ‘0’

Note: Need to spec this properly somewhere.

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, only the changes to specified style are rendered without applying animation.

// Fade the opacity with fallback for browsers that don’t
// support Element.animate
elem.style.opacity = '0';
elem.animate([ { opacity: 1 }, { opacity: 0 } ], 500);

Note, however, that in the example above, a user agent may render a frame with none 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 currentTime attribute of a document timeline will not change within a task

Due to the requirement on timelines to store the time value of the global clock at the start of a sample (see §3.4 Timelines), querying the currentTime 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.

var a = document.timeline.currentTime;
// ... many lines of code ...
var b = document.timeline.currentTime;
alert(b - a); // Displays 0
The time passed to a requestAnimationFrame callback will be equal to document.timeline.currentTime

For user agent that support Timing control for script-based animations [ANIMATION-TIMING], HTML’s event loop processing model defines that animations are updated prior to running animation frame callbacks.

Furthermore, the time passed to such callbacks is the stored value of the Performance object’s now() method as recorded at the beginning of the sample.

Since both performance.now() and time values from the default document timeline are measured from the navigationStart moment, and since both timelines and animation frame callbacks use the time recorded at the start of the sample, they should be equivalent.

window.requestAnimationFrame(function(sampleTime) {
  // Displays ‘0’
  alert(sampleTime - document.timeline.currentTime);
});

6. 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 SVG MIME type [SVG11], the application of temporal parameters is defined in the Animation Elements 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.

7. Interaction with page display

HTML permits user agents to store user-agent defined state along with a session history entry 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 media elements 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 time values of any timelines bound to the global clock.

Is this at odds with those time values being relative to navigationStart and with requestAnimationFrame using the same time as document.timeline.currentTime?

8. Implementation requirements

8.1. 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 time value (which nominally represents milliseconds) of 0.001 is distinguishable from 0.0.

8.2. 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 conforming scripted Web Animations user agent is a user agent that implements the API defined in §5 Programming interface.

9. Acknowledgements

Thank you to Steve Block, Michael Giuffrida, Ryan Seys, and Eric Willigers for their contributions to this specification.

Thank you also to Michiel “Pomax” 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 Southern Star Animation for their kind generosity and patience in introducing the editors to the processes and techniques used producing broadcast animations.

The changelog provides a more detailed history.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <strong class="advisement">, like this: UAs MUST provide an accessible alternative.

This specification defines a number of procedures. User agents are not required to implement these procedures as specified but may alter the steps and data structures freely provided the observable result is equivalent.

Some procedures assert an invariant condition. Such assertions are intended to clarify the expected behavior and do not constitute implementation requirements.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-ANIMATIONS-1]
CSS Animations Module Level 1 URL: https://www.w3.org/TR/css3-animations/
[CSS-BACKGROUNDS-3]
CSS Backgrounds and Borders Module Level 3 URL: https://www.w3.org/TR/css3-background/
[CSS-CASCADE-3]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 3. URL: https://www.w3.org/TR/css-cascade-3/
[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 4. URL: https://www.w3.org/TR/css-cascade-4/
[CSS-POSITION-3]
Rossen Atanassov; Arron Eicholz. CSS Positioned Layout Module Level 3. URL: https://www.w3.org/TR/css-position-3/
[CSS-PROPERTIES-VALUES-API-1]
Tab Atkins Jr.; et al. CSS Properties and Values API Level 1. URL: https://www.w3.org/TR/css-properties-values-api-1/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-TIMING]
Brian Birtles; et al. CSS Timing Functions Level 1. 2017. ED. URL: https://drafts.csswg.org/css-timing/
[CSS-TIMING-1]
Brian Birtles; et al. CSS Timing Functions Level 1. URL: https://www.w3.org/TR/css-timing-1/
[CSS-VARIABLES-1]
Tab Atkins Jr.. CSS Custom Properties for Cascading Variables Module Level 1. URL: https://www.w3.org/TR/css-variables-1/
[CSS-WILL-CHANGE-1]
Tab Atkins Jr.. CSS Will Change Module Level 1. URL: https://www.w3.org/TR/css-will-change-1/
[CSS22]
Bert Bos. Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification. URL: https://www.w3.org/TR/CSS22/
[CSS3-TRANSFORMS]
Simon Fraser; et al. CSS Transforms Module Level 1. URL: https://www.w3.org/TR/css-transforms-1/
[CSS3VAL]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. URL: https://www.w3.org/TR/css-values-3/
[CSSOM]
Simon Pieters; Glenn Adams. CSS Object Model (CSSOM). URL: https://www.w3.org/TR/cssom-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMA-262]
ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[MEDIA-FRAGS]
Raphaël Troncy; et al. Media Fragments URI 1.0 (basic). 25 September 2012. REC. URL: https://www.w3.org/TR/media-frags/
[MOTION-1]
Dirk Schulze; Shane Stephens. Motion Path Module Level 1. URL: https://www.w3.org/TR/motion-1/
[NAVIGATION-TIMING]
Zhiheng Wang. Navigation Timing. 17 December 2012. REC. URL: https://www.w3.org/TR/navigation-timing/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SELECT]
Tantek Çelik; et al. Selectors Level 3. 29 September 2011. REC. URL: https://www.w3.org/TR/css3-selectors/
[SVG11]
Erik Dahlström; et al. Scalable Vector Graphics (SVG) 1.1 (Second Edition). 16 August 2011. REC. URL: https://www.w3.org/TR/SVG11/
[SVG2]
Nikos Andronikos; et al. Scalable Vector Graphics (SVG) 2. URL: https://www.w3.org/TR/SVG2/
[WEBIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. URL: https://heycam.github.io/webidl/

Informative References

[ANIMATION-TIMING]
James Robinson; Cameron McCormack. Timing control for script-based animations. URL: https://www.w3.org/TR/animation-timing/
[CSS3-ANIMATIONS]
Dean Jackson; et al. CSS Animations. 19 February 2013. WD. URL: https://www.w3.org/TR/css3-animations/
[CSS3-IMAGES]
Elika Etemad; Tab Atkins Jr.. CSS Image Values and Replaced Content Module Level 3. 17 April 2012. CR. URL: https://www.w3.org/TR/css3-images/
[CSS3-TRANSITIONS]
Dean Jackson; et al. CSS Transitions. URL: https://www.w3.org/TR/css3-transitions/
[HR-TIME]
Jatinder Mann. High Resolution Time. 17 December 2012. REC. URL: https://www.w3.org/TR/hr-time/
[SMIL-ANIMATION]
Patrick Schmitz; Aaron Cohen. SMIL Animation. 4 September 2001. REC. URL: https://www.w3.org/TR/smil-animation/

IDL Index

interface AnimationTimeline {
    readonly attribute double? currentTime;
    Animation           play (optional AnimationEffectReadOnly? effect = null);
};

dictionary DocumentTimelineOptions {
  DOMHighResTimeStamp originTime = 0;
};

[Constructor (optional DocumentTimelineOptions options)]
interface DocumentTimeline : AnimationTimeline {
};

[Constructor (optional AnimationEffectReadOnly? effect = null,
              optional AnimationTimeline? timeline)]
interface Animation : EventTarget {
             attribute DOMString                id;
             attribute AnimationEffectReadOnly? effect;
             attribute AnimationTimeline?       timeline;
             attribute double?                  startTime;
             attribute double?                  currentTime;
             attribute double                   playbackRate;
    readonly attribute AnimationPlayState       playState;
    readonly attribute Promise<Animation>       ready;
    readonly attribute Promise<Animation>       finished;
             attribute EventHandler             onfinish;
             attribute EventHandler             oncancel;
    void cancel ();
    void finish ();
    void play ();
    void pause ();
    void reverse ();
};

enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };

interface AnimationEffectReadOnly {
    readonly attribute AnimationEffectTimingReadOnly timing;
    ComputedTimingProperties getComputedTiming();
    // Timing hierarchy
    readonly attribute GroupEffectReadOnly?     parent;
    readonly attribute AnimationEffectReadOnly? previousSibling;
    readonly attribute AnimationEffectReadOnly? nextSibling;
};
[NoInterfaceObject]
interface AnimationEffectMutable {
    void before (AnimationEffectReadOnly... effects);
    void after (AnimationEffectReadOnly... effects);
    void replace (AnimationEffectReadOnly... effects);
    void remove ();
};

interface AnimationEffectTimingReadOnly {
    readonly attribute double                             delay;
    readonly attribute double                             endDelay;
    readonly attribute FillMode                           fill;
    readonly attribute double                             iterationStart;
    readonly attribute unrestricted double                iterations;
    readonly attribute (unrestricted double or DOMString) duration;
    readonly attribute double                             playbackRate;
    readonly attribute PlaybackDirection                  direction;
    readonly attribute DOMString                          easing;
};

interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
    inherit attribute double                             delay;
    inherit attribute double                             endDelay;
    inherit attribute FillMode                           fill;
    inherit attribute double                             iterationStart;
    inherit attribute unrestricted double                iterations;
    inherit attribute (unrestricted double or DOMString) duration;
    inherit attribute double                             playbackRate;
    inherit attribute PlaybackDirection                  direction;
    inherit attribute DOMString                          easing;
};

dictionary AnimationEffectTimingProperties {
    double                             delay = 0;
    double                             endDelay = 0;
    FillMode                           fill = "auto";
    double                             iterationStart = 0.0;
    unrestricted double                iterations = 1.0;
    (unrestricted double or DOMString) duration = "auto";
    double                             playbackRate = 1.0;
    PlaybackDirection                  direction = "normal";
    DOMString                          easing = "linear";
};

dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
    double               startTime;
    unrestricted double  endTime;
    unrestricted double  activeDuration;
    double?              localTime;
    double?              progress;
    unrestricted double? currentIteration;
};

enum FillMode { "none", "forwards", "backwards", "both", "auto" };

enum PlaybackDirection { "normal", "reverse", "alternate", "alternate-reverse" };

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface GroupEffectReadOnly : AnimationEffectReadOnly {
    readonly attribute AnimationNodeList      children;
    readonly attribute AnimationEffectReadOnly? firstChild;
    readonly attribute AnimationEffectReadOnly? lastChild;
    GroupEffect clone ();
};

[NoInterfaceObject]
interface GroupEffectMutable {
  void prepend (AnimationEffectReadOnly... effects);
  void append (AnimationEffectReadOnly... effects);
};

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface GroupEffect : GroupEffectReadOnly {
};
GroupEffect implements AnimationEffectMutable;
GroupEffect implements GroupEffectMutable;

interface AnimationNodeList {
    readonly attribute unsigned long length;
    getter AnimationEffectReadOnly? item (unsigned long index);
};

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface SequenceEffectReadOnly : GroupEffectReadOnly {
    SequenceEffect clone ();
};

[Constructor (sequence? children,
              optional (unrestricted double or AnimationEffectTimingProperties) timing)]
interface SequenceEffect : SequenceEffectReadOnly {
};
SequenceEffect implements AnimationEffectMutable;
SequenceEffect implements GroupEffectMutable;

[Constructor ((Element or CSSPseudoElement)? target,
              object? keyframes,
              optional (unrestricted double or KeyframeEffectOptions) options),
 Constructor (KeyframeEffectReadOnly source)]
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
    readonly attribute (Element or CSSPseudoElement)? target;
    readonly attribute IterationCompositeOperation    iterationComposite;
    readonly attribute CompositeOperation             composite;
    sequence<object> getKeyframes ();
};

[Constructor ((Element or CSSPseudoElement)? target,
              object? keyframes,
              optional (unrestricted double or KeyframeEffectOptions) options),
 Constructor (KeyframeEffectReadOnly source)]
interface KeyframeEffect : KeyframeEffectReadOnly {
    inherit attribute (Element or CSSPseudoElement)? target;
    inherit attribute IterationCompositeOperation    iterationComposite;
    inherit attribute CompositeOperation             composite;
    void setKeyframes (object? keyframes);
};
KeyframeEffect implements AnimationEffectMutable;

dictionary BaseComputedKeyframe {
     double?            offset = null;
     double             computedOffset;
     DOMString          easing = "linear";
     CompositeOperation composite;
};

dictionary BasePropertyIndexedKeyframe {
    DOMString          easing = "linear";
    CompositeOperation composite;
};

dictionary BaseKeyframe {
    double?            offset = null;
    DOMString          easing = "linear";
    CompositeOperation composite;
};

dictionary KeyframeEffectOptions : AnimationEffectTimingProperties {
    IterationCompositeOperation iterationComposite = "replace";
    CompositeOperation          composite = "replace";
};

enum IterationCompositeOperation {"replace", "accumulate"};

enum CompositeOperation {"replace", "add", "accumulate"};

[Constructor (object? keyframes)]
interface SharedKeyframeList {
};

callback EffectCallback = void (double? progress,
                                (Element or CSSPseudoElement) currentTarget,
                                Animation animation);

[NoInterfaceObject]
interface Animatable {
    Animation           animate (object? keyframes,
                                 optional (unrestricted double or KeyframeAnimationOptions) options);
    sequence<Animation> getAnimations ();
};
dictionary KeyframeAnimationOptions : KeyframeEffectOptions {
    DOMString id = "";
};

partial interface Document {
    readonly attribute DocumentTimeline timeline;
    sequence<Animation> getAnimations();
};

Element implements Animatable;

CSSPseudoElement implements Animatable;

[Constructor (DOMString type, optional AnimationPlaybackEventInit eventInitDict)]
interface AnimationPlaybackEvent : Event {
    readonly attribute double? currentTime;
    readonly attribute double? timelineTime;
};
dictionary AnimationPlaybackEventInit : EventInit {
    double? currentTime = null;
    double? timelineTime = null;
};

Issues Index

If new timeline is null, we should ensure that custom effects get called with an unresolved iteration progress (unless a subsequent change in the same script execution context makes this redundant).
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.
This is not quite right. If old effect is attached to another animation in the same task then we should probably not do an extra callback with unresolved.

The definition of when custom effects gets called needs to be audited and probably rewritten.

If cancelable promises materialize, we should probably cancel here instead of rejecting.
We should queue a task here for sampling custom effects. (This should happen before we resolve the ready promise.)
We should queue a task here for sampling custom effects with the final current time. (This should happen before we resolve the ready promise).
If cancelable promises materialize, we should cancel here instead of rejecting.
The procedures for calling custom effects need to be reworked. Currently they probably involve calling too often for changes that could be coalesced.
Currently timing functions that generate results outside the range [0, 1] will behave unexpectedly when applied to group effects, as children will increase iterations or enter into fill mode rather than continuing to extrapolate along their defined behavior (which is what they would do if the timing function applied to them directly).

To fix this it is possible we will wish to introduce ‘overflow’ fill modes that respond to time values larger than or smaller than the active time range by extrapolating rather than filling.

See section 15 (Overflowing fill) of minuted discussion from Tokyo 2013 F2F.

Currently, the set of timing functions allowed on a group effect is not restricted. This has raised concern about complexity of implementation and also complexity of behavior with regards to fill modes. As a result, allowing the full set of timing functions on group effects is considered at risk.

Alternatives are to either restrict timing functions on group effects to the linear timing function or to a set of “simple” timing functions that have properties that alleviate some of the concerns with the more complex timing functions.

See section 2 of the discussion from August 2013.

The above doesn’t explain the animation type to use for of syntax such as "<length>+". We will fix this once the definition of animation types has moved to CSS Values and Units where we should define generic handling for list types etc.
We should probably expand 2d functions to their 3d equivalents before matching?
This needs to be more specific, e.g. when combining translate(20px) and translate(30px 10px) we have to expand the first function to translate(20px 0px) first. Probably need to define unit conversion too.
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 are 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 ‘beyond’ 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 section 4 (Keyframe offsets outside [0, 1]) of minuted discussion from Tokyo 2013 F2F.

This whole feature needs to be revisited. The current thinking is that rather than having custom effects, we should simply have an onsample callback on each animation effect. That would allow, for example, augmenting an existing effect with a function that performs logging or triggers additional actions at certain times. With the current arrangement, doing this would require adding a parent group just to achieve this.
There may be use cases where an action needs to be triggered at a specific point in an animation tree. In many cases this can be achieved by inserting a custom effect with a step-start easing that spans the period during which the action should be triggered. However, this can impose additional layout requirements on the content which might be cumbersome to accomodate.

Some alternatives under consideration:

Need to define this more precisely. Are styles flushed? Presumably they are. Can we suspend reflow for the duration of executing the script-based animation effects and just do it once afterwards?
It has been suggested this method be renamed, or even removed (see TAG feedback).
Need to define the start behavior when effect is null.
This should become a cancelable promise when (if) such things exist.
This should become a cancelable promise when (if) such things exist.
Should this be parentGroup?
This interface needs a constructor.
This interface needs a constructor.
Make a constructor for AnimationEffectTimingReadOnly and call that here.
If source is using a SharedKeyframeList should we continue to share it?
What should we do if the [[type]] is break, continue, or return? Can it be?
Do we need null offsets or is it enough to just test for the absence of the property?
Both this method and getAnimations() on the Animatable interface require retaining forwards-filling animation effects and their animations such that a document that repeatedly produces forwards-filling animations will consume memory in an unbounded fashion. We may need to revise this definition (previously these methods only returned animations whose target effect was current) or provide a loophole for implementations to discard old animations in such conditions.
Is this at odds with those time values being relative to navigationStart and with requestAnimationFrame using the same time as document.timeline.currentTime?