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.

Introduction

Web Animations defines a model for supporting animation and synchronization on the Web platform. It is intended that other specifications will build on this model and expose its features through declarative means. In addition, this specification also defines a programming interface to the model that may be implemented by user agents that provide support for scripting.

Use cases

The Web Animations model aims at two broad areas of application:

User interface effects

Animation can be used to give visual clues and feedback to make a user interface more readily comprehensible.

For example, a user action results in a table row being removed to represent an item being removed from a shopping cart. In such a case, fading the row to transparent and then shifting the subsequent rows up to fill the space over a few hundred milliseconds provides the user with clear feedback as to the results of their action as opposed to instantly removing the row from the DOM.

To support this scenario not only are the animated effects of fading and shifting required, but so is synchronization, both between the animations, and between animations and scripted actions (removing the table row from the DOM after the animations have completed).

Storytelling and visualisation

Another type of animation uses the animated effect to convey a story or represent some information. Unlike user interface effects which are largely a presentational adjunct to the content, these animations form an essential part of the content presented to the user.

For example, in an animated cartoon two cats fly through space to another planet leaving a rainbow trail behind them. After arriving at the planet a change of scene occurs and the user should decide whether or not the cats enter a magic mountain by selecting one of two preset destinations in the scene.

This scenario requires the following features:

  • animated effects for moving characters along a path as well as warping a path (the rainbow trail),
  • synchronization that allows some actions to happen simultaneously (the two cats moving) and others in sequence (the change of scene),
  • play control to allow rewinding the cartoon, or changing its playback rate to accommodate particular learning or accessibility needs,
  • the ability to trigger animations in response to user input

Similar use cases in this category include visualising physical phenomena such as spring motion for educational purposes, or visualising data such as the prevalence of a disease over a geographical space over a year whereby animation is used to present the time-based component of the data.

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”) [[RAF]], 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 [[RAF]] and their execution order to 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 HTML5 [[HTML5]].

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.

Web Animations model overview

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 time fraction. An iteration index is also generated for animations that vary as they repeat.
Animation model
Takes the time fractions and iteration indices produced by the timing model and converts them into a series of values to apply to the target properties and attributes.

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 a time fraction 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 for the rectangle of 75.

This specification begins with the timing model and then proceeds to the animation model.

Timing model

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

The timing model at a glance

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

Stateless

The Web Animations timing model operates by taking an input time and producing an output time fraction. 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 players means that dynamic changes to the end time of the media (source content) of a player 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.

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.

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

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

A more precise definition of when the model is updated when scripting is involved is provided in .

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

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 at the zero time.

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

The document timeline

Each document has a timeline called the document timeline. The time values of the document timeline are calculated as a fixed offset from the global clock such that the zero time corresponds to the navigationStart moment [[!NAVIGATION-TIMING]]. Prior to this moment, the document timeline is inactive.

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

Since the time values of the 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 script execution block as defined in .

Players

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

A player connects a single animation node, called its source content, to a timeline and provides playback control. Both of these associations are optional and configurable such that a player may have no associated source content or timeline at a given moment.

A player's start time is the time value of its timeline when its source content is scheduled to begin playback. A player's start time is initially unresolved.

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

When a player is created, it is assigned a globally unique sequence number called the player sequence number. This number is used to resolve the sort order of players for a variety of situations such as combining animations and returning the list of current players.

Should this actually be based on when the player is attached to a timeline?

The current time of a player

Players provide a time value to their source content called the player's current time.

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

If the player's hold time is resolved,
The current time is the player's hold time.
If any of the following are true:
  1. the player has no associated timeline, or
  2. the associated timeline is inactive, or
  3. the player'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 .

Setting the current time of a player

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

The procedure to silently set the current time of a player, player, to seek time is as follows:

  1. If seek time is an unresolved time value or is equal to positive or negative infinity, throw a "NotSupportedError".
  2. Update either player's hold time or start time as follows:
    If any of the following conditions are true:
    Set player's hold time to seek time.
    Otherwise,
    Set player'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 player.
  3. Make player's previous current time unresolved.

The procedure to set the current time of a player, player, to seek time is as follows:

  1. Run the steps to silently set the current time of player to seek time.
  2. If player has a pending pause task, cancel the task and fulfill player's current ready promise with player.
  3. Run the procedure to update a player's finished state for player.

Setting the start time of a player

The procedure to update the player start time of player, player, to start time, new start time, is as follows:

  1. If player's hold time is resolved and there is a timeline associated of player that is not inactive,
    1. Let effective start time be the result of evaluating timeline time - hold time / playback rate where timeline time is the current time value of the timeline associated with player.
    2. Let start time offset be new start timeeffective start time.
    3. Set player's hold time to hold time + start time offset.
  2. Unless player has a pending pause task, set player's start time to new start time.
  3. If player has a pending play task, cancel the task and fulfill player's current ready promise with player.
  4. Run the procedure to update a player's finished state for player.

Waiting for source content

Some operations performed by a player 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 player 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.

A player's source content is ready when the user agent has completed any setup required to begin the playback of each inclusive descendant of the source content including rendering the first frame of any animation with an associated animation effect or executing any custom effects associated with such an animation.

The current ready promise

Each player has a current ready promise. The current ready promise is initially a resolved Promise object.

The object is replaced with a new Promise object every time the player enters the pending play state as well as when the player is cancelled (see ).

Note that since the same object is used for both pending play and pending pause requests, authors are advised check the state of the player when the Promise is resolved.

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

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

Playing a player

The procedure to play a player, player, is as follows:

  1. If there is no timeline associated with player, or the associated timeline is inactive throw an "InvalidStateError" and abort these steps.
  2. Let has pending ready promise be a boolean flag that is initially false.
  3. If player has a pending play task,
    1. Cancel that task.
    2. Set has pending ready promise to true.
  4. If player has a pending pause task,
    1. Cancel that task.
    2. Restore the value of player's start time that was set before the pause a player procedure was last run to completion including if the player start time was unresolved.
    3. Set has pending ready promise to true.
  5. Perform the steps corresponding to the first matching condition from the following, if any:
    If player's pause flag is true,
    Set the pause flag to false.
    If player playback rate > 0 and either player's:
    Set player's hold time to zero.
    If player playback rate < 0 and either player's:
    Set player's hold time to source content end.
    If player playback rate = 0 and player's current time is unresolved,
    Set player's hold time to zero.
  6. If has pending ready promise is false, let player's current ready promise be a new pending Promise object.
  7. Schedule a task to run as soon as player's source content is ready. The task shall perform the following steps:
    1. Let ready time be the time value of the timeline associated with player at the moment when player's source content became ready.
    2. Let new start time be the result of evaluating ready time - hold time / player playback rate for player. If the player playback rate is zero, let new start time be simply ready time.
    3. Make player's hold time unresolved.
    4. Update the player start time of player to new start time.
    5. Queue a task here for sampling custom effects. (This should happen before we resolve the ready promise.)
    6. Fulfill player's current ready promise with player.
    7. Run the procedure to update a player's finished state for player.

      Note that the order of the above two steps is important since it means that a player with zero-length source content will resolve its current ready promise before its current finished promise.

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

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

  8. Run the procedure to update a player's finished state for player.

Pausing a player

Players maintain a boolean pause flag to indicate a player whose current time is suspended. The pause flag is initially false.

As with playing a player, pausing may not happen instantaneously (see ). 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.

For this reason, the procedure to pause a player makes the player's current time unresolved until the pause operation is complete.

The procedure to pause a player, player is as follows:

  1. If there is no timeline associated with player, or the associated timeline is inactive throw an "InvalidStateError" and abort these steps.
  2. If player's pause flag is true or if player has a pending pause task, abort these steps.
  3. Let has pending ready promise be a boolean flag that is initially false.
  4. If player has a pending play task, cancel that task and let has pending promise be true.
  5. Set player's pause flag to true.
  6. Make player's start time unresolved.
  7. Make player's hold time unresolved.
  8. If has pending ready promise is false, set player's current ready promise be a new pending Promise object.
  9. 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 player's source content, if any. The task shall perform the following steps:
    1. Set player's hold time to the time value corresponding to the value of player's current time used at the moment when the pause operation was completed, even if that value was unresolved.

      Note that since player's start time and hold time are set to unresolved earlier in this procedure, user agents will be required to maintain additional state in order to determine the appropriate value of the current time.

    2. Queue a task here for sampling custom effects with the final current time. (This should happen before we resolve the ready promise.)
    3. Fulfill player's current ready promise with player.
    4. Run the procedure to update a player's finished state for player.

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

  10. Run the procedure to update a player's finished state for player.

Reaching the end

Players in the real world such as 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 [[HTML5]], the current time of Web Animations' players do not play forwards beyond the end time of their source content or play backwards past time zero.

A player 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 a player.

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

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

This allows, for example, seeking the current time of a player with no source content to 5s. If source content with an end time later than 5s is later associated with the player, playback will begin from the 5s mark.

Similar behavior to the above scenario may arise when the length of a player's source content changes.

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

The current finished promise

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

The object is replaced with a new Promise object every time the player leaves the finished play state.

Updating the finished state

For a player with a positive playback rate, the current time continues to increase until it reaches the source content end.

The source content end of a player is equal to the end time of the player's source content. If the player has no source content, the source content end is zero.

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

A player that has reached this boundary (or overshot it) and whose pause flag is false is said to be finished.

The crossing of this boundary is checked on each modification to the player object using the procedure for updating a player's finished state defined below.

For each player, the user agent maintains a previous current time time value that is originally unresolved, and a previous finished state boolean flag that is initially false.

Mention that this gets run at the end of each sample as well. And at the end of any update to the timing of the source content.

The procedure to update a player's finished state for player is as follows:

Finishing a player

A player can be advanced to the natural end of its current playback direction by using the procedure to finish a player for player defined below:

  1. If player playback rate is zero, throw an "InvalidStateError" and abort these steps.
  2. Set limit as follows:
    If player playback rate > 0,
    Let limit be source content end.
    Otherwise,
    Let limit be zero.
  3. Set the current time to limit.

    The procedure to set the current time has the side effect of cancelling any pending pause task so we don't need to handle that here.

  4. Set player's pause flag to false.

    This is needed so that player ends up in the finished play state, not the paused play state.

  5. If there is a pending play task, cancel that task and fulfill the current ready promise of player with player.
  6. If player has an associated timeline that is not inactive, update player's start time to the result of evaluating timeline time - limit / player playback rate where timeline time is the current time value of the associated timeline.
  7. Run the procedure to update a player's finished state for player.

Cancelling a player

A player can be cancelled which causes the current time to become unresolved hence removing any effects caused by the source content.

The procedure to cancel a player for player is as follows:

  1. If there is a pending play task, cancel that task.
  2. If there is a pending pause task, cancel that task.
  3. Reject the current ready promise with a DOMException named "AbortError".
  4. Let current ready promise be a new resolved Promise object.
  5. Reject the current finished promise with a DOMException named "AbortError".
  6. Let current finished promise be a new pending Promise object.
  7. Make player's hold time unresolved.
  8. Make player's start time unresolved.
  9. Set player's pause state to false.
  10. Queue a task to call any custom effects associated with inclusive descendants of player's source content with an unresolved time fraction.

Speed control

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

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

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

Setting a player's playback rate to zero effectively pauses the player (however, the play state does not necessarily become paused).

Updating the playback rate of a player

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

The procedure to update the player playback rate of a player, player to new playback rate is as follows:

  1. Let previous time be the value of the current time of player 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 player to previous time.

The procedure to silently update the player playback rate of player, player 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.

Reversing a player

The procedure to reverse a player of player player is as follows:

  1. If there is no timeline associated with player, or the associated timeline is inactive throw an "InvalidStateError" and abort these steps.
  2. Silently update the player playback rate of player to player playback rate.

    This must be done silently or else we may end up fulfilling 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 a player for player.

Player state

A player may be described as being in one of the following play states:

idle
The current time of the player is unresolved and there are no pending tasks. In this state the player has no effect.
pending
The player is waiting on some pending task to complete.
running
The player has a resolved current time that changes on each sample.
paused
The player has been suspended and the current time is no longer changing.
finished
The player has reached the natural boundary of its playback range and the current time is no longer updating.

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

player has a pending play task or a pending pause task,
pending
The current time of player is unresolved,
idle
The paused flag of player is true,
paused
For player, player playback rate > 0 and current timesource content end; or player playback rate < 0 and current time ≤ 0,
finished
Otherwise,
running

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

However, the procedure to play a player is defined such that a player that is paused outside of its natural playback range can be converted from a paused player into a finished player without restarting as shown below.

            player.source.duration = 5000;
            player.currentTime = 4000;
            player.pause();
            player.ready.then(function() {
              player.source.duration = 3000;
              // Displays 'paused'
              alert(player.playState);
              player.play();
              return player.ready;
            }).then(function() {
              // Displays 'finished'
              alert(player.playState);
            });
          

Animation nodes

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

Relationship between animation nodes and players

The source content of a player, if set, is a type of animation node. The source content of a player is said to be directly associated with that player.

Animation nodes can be combined together into a hierarchy using animation groups (see ). Only the root animation node of such a hierarchy can be directly associated with a player. If an animation node that has a parent animation group is designated as the source content of a player, the animation node is removed from its parent animation group before being associated with the player.

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

An animation node, node, is associated with a timeline, timeline, if node is associated with a player which, in turn, is associated with timeline.

Types of animation nodes

This specification defines two types of animation nodes:

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

The active interval

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

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

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 node with no delay; the start time and beginning of the active interval are coincident.
(b) An animation node with a positive delay; the beginning of the active interval is deferred by the delay.
(c) An animation node 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 animation group.

Animation nodes define an active interval which is the period of time during which the node 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 node's start time and start delay.

An animation node's start time is the moment at which the parent animation group, if any, has scheduled the animation node to begin. It is expressed in inherited time. In most cases, including the case when the animation node has no parent animation group, the start time is zero. The singular exception is sequence animation groups which set the start times of their children as described in .

In addition to the start time, an animation node also has a start delay which is an offset from the start time. Unlike the start time which is determined by the parent animation group, the start delay is a property of the animation node itself.

The lower bound of the active interval of an animation node, 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 ) and active time.

The length of the active interval is called the active duration, the calculation of which is defined in .

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

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. Animation groups typically perform some transformations on the time values they receive from their parent or player before passing on the transformed time values to their children. Child animation nodes 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 node (a) which has a start time of 1, the local time is 1.5.
For animation node (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 node's start time only, and not on its start delay.

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

If the animation node has a parent animation group,
the inherited time is the parent animation group's current transformed time.
If the animation node is directly associated with a player,
the inherited time is the current time of the player.
Otherwise,
the inherited time is unresolved.

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

Animation node phases and states

At a given moment, an animation node may be in one of three possible phases. If an animation node 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 node.

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

The phases are as follows:

before phase
The animation node's local time falls before the node's active interval.
active phase
The animation node's local time falls inside the node's active interval.
after phase
The animation node's local time falls after the node's active interval.

In addition to these phases, an animation node 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 summarised as follows:

in play

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

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

current

Corresponds to an animation node that is either in play or may become in play in the future. This will be the case if the animation node 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 node might play again (e.g. due to repeating).

This state is used in the programming interface to identify all animations and players that are likely to be of interest.

Furthermore, the current state provides an important definition for managing the amount of memory required by implementations. Assuming a monotonically increasing timeline an implementation can safely discard all animation nodes that are not current and not referenced elsewhere provided they take care to preserve any fill values. This is because such animation nodes will no longer have any dynamic effect.

in effect
Corresponds to an animation node that has a resolved active time. This occurs when either the animation node is in its active phase or outside the active interval but at a time where the node's fill mode (see ) causes its active time to be resolved. Only in effect animations apply a result to their target.

The normative definition of each of these states follows.

An animation node is in the before phase if the animation node's local time is not unresolved and is less than the node's start delay.

An animation node is in the active phase if all of the following conditions are met:

  1. the animation node's local time is not unresolved, and
  2. the animation node's local time is greater than or equal to its start delay, and
  3. the animation node's local time is less than the sum of its start delay and active duration.

An animation node is in the after phase if the animation node's local time is not unresolved and is greater than or equal to the sum of its start delay and active duration.

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

  1. the animation node is in the active phase, and
  2. the animation node has a parent animation group that is in play or else is directly associated with a player that is not finished.

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

An animation node is in effect if its active time as calculated according to the procedure in is not unresolved.

Fill behavior

The effect of an animation node 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 .

Fill modes

The effect of each fill mode is as follows:

none
The animation node has no effect when it is not in play.
forwards
When the animation node is in the after phase, or when the animation node is in the active phase but an ancestor is in its after phase, the animation node will produce the same transformed time value as the last moment it is scheduled to be in play. For all other times that the animation node is not in play, it will have no effect.
backwards
When the animation node is in the before phase, or when the animation node is in the active phase but an ancestor is in its before phase, the animation node will produce the same transformed time value as the earliest moment that it is scheduled to be in play. For all other times that the animation node is not in play, it will have no effect.
both
When the animation node or an ancestor is in its before phase, backwards fill behavior is used. When the animation node 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 node has no effect outside its active interval.
(b) fill mode ‘forwards’. After the active interval has finished, the timed value continues to maintain a fill value.
(c) fill mode ‘backwards’. The animation node produces a fill value until the start of the active interval.
(d) fill mode ‘both’. Both before and after the active interval the animation node produces a fill value.

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

Currently timing functions that generate results outside the range [0, 1] will behave unexpectedly when applied to animation groups, 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.

Repeating

Iteration intervals

It is possible to specify that an animation node 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 node 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 node is simply its intrinsic iteration duration.

The intrinsic iteration duration of an animation node is zero, however some specific types of animation node such as animation groups override this behavior and provide an alternative intrinsic duration (see and ).

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

Comparing the iteration duration and the active duration we have:

Iteration duration
The time taken for a single iteration of the animation node to complete.
Active duration
The time taken for the entire animation node 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 node 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.

Controlling iteration

The number of times an animation node 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 node repeats indefinitely.

In addition to the iteration count, animation nodes also have an iteration start property which specifies an offset into the series of iterations at which the animation node 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 .

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

Iteration time space

We have already encountered different time spaces in describing local time and inherited time (see ). 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 node'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 that while the time spaces themselves are not bounded, Web Animations defines active time and iteration time 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 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 document timeline of the active document.

Interval timing

When an animation node 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 node, at local time 1s, the iteration time is 0. For the sequenced nodes, at inherited time 1s, only node 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 nodes 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 and is illustrated below.

Effect of iterations and fill on iteration time.

After one iteration, the iteration time is 0, but after two iterations (and thereonwards), the iteration time is equal to the iteration duration due to the special behavior defined when an animation node fills.

Animation node speed control

Like players, animation nodes also have a playback rate parameter. The playback rate of an animation node is a finite real number that acts as a multiplier when calculating the animation node's transformed time from its local time.

The effect of setting the playback rate of an animation node differs from the setting the playback rate on a player. Its behavior is defined in the timing calculations given in .

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

Core animation node calculations

Overview

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

Following this further transformations are applied before resulting at a final transformed time.

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 .

Having established the active duration, the process for transforming an animation node's inherited time into its transformed time 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 playback rate and iteration start properties are applied to the active time to produce the scaled active time.
(4) The scaled active time is then converted to an offset within a single iteration: the iteration time.
(5) The iteration time is converted into a directed time by incorporating the playback direction.
(6) Finally, a timing function is applied to the directed time to produce the transformed time.

The first step, calculating the local time is described in . Steps 2 to 4 in the diagram are described in the following sections. Steps 5 and 6 are described in and respectively.

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

Transforming the local time

Calculating the active time

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

If the animation node is in the before phase,
The result depends on the first matching condition from the following,
If the animation node has a parent animation group and that parent animation group is in the after phase,
Return an unresolved time value.
If the fill mode is backwards or both,
Return zero.
Otherwise,
Return an unresolved time value.
If the animation node is in the active phase,
The result depends on the first matching condition from the following,
If the animation node has a parent animation group and that parent animation group is in the before phase, and the fill mode of this animation node is none or forwards,
Return an unresolved time value.
If the animation node has a parent animation group and that parent animation group is in the after phase, and the fill mode of this animation node is none or backwards,
Return an unresolved time value.
Otherwise,
Return local time - start delay.
If the animation node is in the after phase,
The result depends on the first matching condition from the following,
If the animation node has a parent animation group and that parent animation group is in the before phase,
Return an unresolved time value.
If the fill mode is forwards or both,
Return the active duration.
Otherwise,
Return an unresolved time value.
Otherwise (the local time is unresolved),
Return an unresolved time value.

Calculating the scaled active time

Before the active time can be converted to an iteration time we must factor in the animation node's playback rate and iteration start. The result is called the scaled active time.

In order to calculate the scaled active time we first define the start offset as follows:

start offset = iteration start × iteration duration

If the iteration start is zero, the start offset is zero.

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

The scaled active time is calculated according to the following steps:

  1. If the active time is unresolved, return an unresolved time value.
  2. Return the scaled active time based on the playback rate as follows,
    If the playback rate is less than zero,
    Return (active time - active duration) × playback rate + start offset.
    If the playback rate is zero,
    Return start offset.
    Otherwise,
    Return active time × playback rate + start offset.

Calculating the iteration time

The iteration time is calculated according to the following steps:

  1. If the scaled active time is unresolved, return unresolved.
  2. If the iteration duration is zero, return zero.
  3. If scaled active time - start offset is equal to the repeated duration, and iteration count is not zero, and (iteration count + iteration start) % 1 is zero, return the iteration duration.
  4. Otherwise, return scaled active time % iteration duration.

Calculating the current iteration

The current iteration can be calculated using the following steps:

  1. If the scaled active time is unresolved, return unresolved.
  2. If the scaled active time is zero, return zero.
  3. If the iteration duration is zero, return ceil(iteration start + iteration count) - 1.
  4. If the iteration time equals the iteration duration, return iteration start + iteration count - 1.
  5. Return floor(scaled active time / iteration duration).

    If the iteration duration is infinite, the result of floor(scaled active time / iteration duration) will be zero as defined by IEEE 754-2008.

Direction control

Animation nodes may also be configured to run iterations in alternative directions using direction control. For this purpose, animation nodes 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 time which follows.

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.

Calculating the directed time

The directed time is calculated from the iteration time using the following steps:

  1. If the iteration time 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. There used to be a step here which seemed to be adding special handling for filling when the node ends on a repeat boundary but it seems like that is taken care of by the calcuation of iteration time and current iteration. Is anything actually needed here?

    4. If d % 2 == 0, let the current direction be forwards, otherwise let the current direction be reverse.
  3. If the current direction is forwards then return the iteration time.

    Otherwise, return the iteration duration - iteration time.

Time transformations

Scaling the time

It is often desirable to control the rate at which an animation node progresses. For example, easing the rate of animation can create a sense of momentum and produce a more natural effect. Conversely, in other situations such as when modelling a discrete change, a smooth transition is undesirable and instead it is necessary for the animation node to progress in a series of distinct steps.

For such situations Web Animations provides timing functions that scale the progress of an animation node.

Timing functions take an input time fraction and produce a scaled output time fraction.

Example of a timing function that produces an ease-in effect.

Example of a timing function that produces an ease-in effect. Given an input timing fraction of 0.7, the timing function scales the value to produce an output time fraction of 0.52.
By applying this timing function, time will appear to progress more slowly at first but then gradually progress more quickly.

Timing functions are applied to an iteration of an animation node.

Timing functions

A timing function takes an input time fraction in the range [0, 1] and produces an output time fraction whose range is unbounded (i.e. positive and negative infinity are permitted).

Animation nodes have one timing function associated with them. The default timing function is the linear timing function whose output is identical to its input. The linear timing function can be represented by the string “linear”.

The range of timing functions that may be applied to a given animation node depends on the type of the animation node.

Currently, the set of timing functions allowed on an animation group 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 animation groups is considered at risk.

Alternatives are to either restrict timing functions on animation groups 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.

Scaling using a cubic Bézier curve

A common method of producing easing effects is to use a cubic Bézier curve to scale the time. The endpoints of the curve are fixed at (0, 0) and (1, 1) while two control points P1 and P2 define the shape of the curve. Provided the x values of P1 and P2 lie within the range [0, 1] such a curve produces a function that is used to map input times (the x values) onto output times (the y values). This arrangement is illustrated below.

A cubic Bezier curve used as a timing function.

A cubic Bézier curve used as a timing function.
The shape of the curve is determined by the location of the control points P1 and P2.
Input time fractions serve as x values of the curve, whilst the y values are the output time fractions.

Some example cubic Bézier timing functions are illustrated below.

The timing functions produced by keyword values.

The timing functions produced by each of the keyword values associated with cubic Bézier timing functions accepted by the AnimationTiming.easing member from the programming interface.

A cubic Bézier timing function is a type of timing function defined by four real numbers that specify the two control points, P1 and P2, of a cubic Bézier curve whose end points are fixed at (0, 0) and (1, 1). The x coordinates of P1 and P2 are restricted to the range [0, 1].

The evaluation of this curve is covered in many sources such as [[FUND-COMP-GRAPHICS]].

A cubic Bézier timing function may be specified as a string using the following syntax (using notation from [[!CSS3-VALUES]]):

<cubic-bezier-timing-function> = ease | ease-in | ease-out | ease-in-out | cubic-bezier(<number>, <number>, <number>, <number>)

The meaning of each value is as follows:

ease
Equivalent to cubic-bezier(0.25, 0.1, 0.25, 1).
ease-in
Equivalent to cubic-bezier(0.42, 0, 1, 1).
ease-out
Equivalent to cubic-bezier(0, 0, 0.58, 1).
ease-in-out
Equivalent to cubic-bezier(0.42, 0, 0.58, 1).
cubic-bezier(<number> <number> <number> <number>)
Specifies a cubic Bézier timing function. The four numbers specify points P1 and P2 of the curve as (x1, y1, x2, y2). Both x values must be in the range [0, 1] or the definition is invalid.

It has been proposed to extend cubic-bezier to allow multiple segments, using syntax such as the following:

            cubic-bezier( [ <number>{6} ; ]* <number>{4} )
          

(i.e. the curve starts at (0, 0); each segment is defined by six numbers where the start point is the end of the previous segment and the numbers define the two control points and the end point. The last segment is defined by four numbers since the end point is fixed at (1, 1).)

This would provide a simple and compact syntax for tools trying to map arbitrary curves (e.g. bounce functions) to timing functions.

Timing in discrete steps

It is possible to scale an animation node's timing so that the animation node occurs in a series of discrete steps using a stepping function.

Some example step timing functions are illustrated below.

Example step timing functions.

Example step timing functions. In each case the domain is the input time fraction whilst the range represents the output time fraction produced by the step function.
The first row shows the function for each transition point when only one step is specified whilst the second row shows the same for three steps.

A step timing function is a type of timing function that divides the input time into a specified number of intervals that are equal in duration. The output time, starting at zero, rises by an amount equal to the interval duration once during each interval at the transition point which may be either the start, midpoint, or end of the interval.

In keeping with Web Animations' model of endpoint exclusive interval timing (see ), the output time at the transition point is the time after applying the increase (i.e. the top of the step) with the following exception.

When a transition point coincides with the end of the active interval extra care must be taken to produce the correct result when performing a fill. To achieve this, when a step timing function is applied to an animation node or applied to an animation effect associated with an animation node, an additional before flag is passed. The value of the before flag is determined as follows:

  1. If the active time of the animation node is unresolved, the before flag is not set and these steps should be aborted.
  2. Determine the current direction using the procedure defined in .
  3. If either the current direction is forwards or the animation node playback rate ≥ 0 (but not when both conditions are true), let going forwards be true, otherwise it is false.
  4. The before flag is set if the animation node is in the before phase and going forwards is true; or if the animation node is in the after phase and going forwards is false.

When a step timing function is evaluated at a transition point, if the before flag is set the result is the value before applying the increase.

A step timing function may be specified as a string using the following syntax:

<step-timing-function> = step-start | step-middle | step-end | steps(<integer>[, [ start | middle | end ] ]?)

The meaning of each value is as follows:

step-start
Equivalent to steps(1, start);
step-middle
Equivalent to steps(1, middle);
step-end
Equivalent to steps(1, end);
steps(<integer>[, [ start | middle | end ] ]?)
Specifies a step timing function. The first parameter specifies the number of intervals in the function. It must be a positive integer (greater than 0). The second parameter, which is optional, specifies the point at which the change of values occur within the interval. If the second parameter is omitted, it is given the value end.

Calculating the transformed time

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

  1. If the directed time is unresolved, return an unresolved time value..
  2. If the iteration duration is infinity, return the directed time.
  3. Let iteration fraction be the result of evaluating directed time / iteration duration unless iteration duration is zero, in which case let iteration fraction be zero.
  4. Let scaled fraction be the result of evaluating the animation node's timing function with iteration fraction as the input time fraction.
  5. Return the result of evaluating scaled fraction × iteration duration. If the scaled fraction is zero, let the result be zero.

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

Grouping and synchronization

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

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 an animation group is directly associated with a player, the animation nodes associated with the animation group can be seeked, paused, and stopped as a unit.

An animation group is a type of animation node that contains an ordered sequence of zero or more animation nodes known as child animation nodes.

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

By nesting animation groups 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 [[!DOM4]]:

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

The temporal relationship between a child animation node and its parent animation group is incorporated in the definition of inherited time (see ).

Relationship of group time to child time

The timing of the children of an animation group 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 an animation group 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 an animation group 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 nodes 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 an animation group 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 an animation group 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 node has a negative delay and an infinite iteration count.
However, when a similar animation node is placed inside an animation group with a specified iteration duration it has the effect of clipping the child animation node's active interval.

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

The start time of children of an animation group

The start time of a child animation node of an animation group is zero.

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

The intrinsic iteration duration of an animation group

The intrinsic iteration duration of an animation group is based on the time when the last child animation node completes its active interval and is calculated using the following procedure.

  1. Define the end time of an animation node as :

    end time = start time + start delay + active duration + end delay
  2. The intrinsic iteration duration depends on the number of child animation nodes as follows,

    If the group has no child animation nodes,
    the intrinsic iteration duration is zero.
    Otherwise,
    1. Let maximum end time be the maximum value after calculating the end time of each child animation node 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 animation groups.

Animation sequences

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

Compare the two arrangements illustrated below:

Animation groups and animation sequences.

Animation groups and animation sequences.
(a) is a regular animation group where all the children run simultaneously.
(b) is an animation sequence where the children run in turn.

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

Nesting of animation groups.

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

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

The start time of children of an animation sequence

The start time of a child animation node of an animation sequence 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 node 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 an animation sequence 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.

Because the start of the active interval is based on the sum of an animation node's start time and start delay, the active intervals of children of an animation sequence 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 an animation sequence 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.

The intrinsic iteration duration of an animation sequence

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

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

Animations

Animations are a kind of animation node that apply an animation effect or a custom effect to an element or pseudo-element such as ::before and ::first-line [[!SELECT]] referred to as the animation target.

Calculating the time fraction

Before passing the transformed time of an animation to its animation effect it is converted to a time fraction. The time fraction of an animation node is calculated according to the following steps:

If the iteration duration is zero,

the time fraction is as follows,

If local time < start delay,
Return the result of recalculating the transformed time using an iteration duration of 1.
Otherwise,
  1. Let normalized active duration be the result of recalculating the active duration using an iteration duration of 1.
  2. Return the result of recalculating the transformed time using a local time of start delay + normalized active duration and an iteration duration of 1.
Otherwise,
Return transformed time / iteration duration unless transformed time is unresolved, in which case return an unresolved time value.

Since timing functions are allowed to produce output times outside the range [0, 1] it is possible that the value calculated for a time fraction also lies outside this range.

Animation model

The Web Animations animation model takes the time fractions and current iteration values produced by the timing model for a given animation and applies it as the input to the animation's animation effect.

The output of each animation effect is then combined with other animation effects using an animation stack before being applied to the target properties (see ).

Animation effects

An animation effect takes a time fraction and a current iteration value and uses them to calculate an intermediate animation value for its target properties. Each animation may have at most one animation effect associated with it.

Since the result of an animation effect is based on the time fraction and current iteration value, it is updated whenever the timing model is sampled.

Target properties

Each animation effect can have zero or more associated target properties.

Target properties may be CSS properties or DOM attributes. If a given animation target has an attribute with the same name as a CSS property, any target property of that name is taken to refer to to the CSS property.

If there ever exists a situation where we need to animate an attribute with the same name as a property (other than a presentation attribute [[SVG2]]) then we will need to introduce a disambiguation strategy. Generally, however, such naming should be avoided.

Procedures for animating properties

In order to animate a target property, the following procedures must be defined.

  • interpolation — given two target property values Vstart and Vend, produces an intermediate value Vres at a distance of p along the interval between Vstart and Vend such that p = 0 produces Vstart and p = 1 produces Vend. The range of p is (−∞, ∞) due to the effect of timing functions. As a result, this procedure must also define extrapolation behavior for p outside [0, 1].
  • addition — given two target property values Va and Vb, returns the sum of the two properties, Vresult. For addition that is not commutative (for example, matrix multiplication) Va represents the first term of the operation and Vb represents the second.

    While addition can often be expressed in terms of the same weighted sum function used to define interpolation, this is not always the case. For example, interpolation of transform matrices involves decomposing and interpolating the matrix components whilst addition relies on matrix multiplication.

  • accumulation — given two target property values Va and Vb, returns the result, Vresult, of combining the two operands such that Vb is treated as a delta from Va. For accumulation that is not commutative (for example, accumulation of mismatched transform lists) Va represents the first term of the operation and Vb represents the second.

    For many types of animation such as numbers or lengths, accumulation is defined to be identical to addition.

    A common case where the definitions differ is for list-based types where addition may be defined as appending to a list whilst accumulation may be defined as component-based addition. For example, the filter list values "blur(2)" and "blur(3)", when added together may produce "blur(2) blur(3)", but when accumulated, may produce "blur(5)".

  • distance computation — given two target property values Vstart and Vend, calculates some notion of scalar distance between the values, distance.

Specific animation behaviors

The specific procedures used for animating a given target property are referred to as the property's animation behavior.

The animation behavior of CSS properties 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.

The default animation behavior for CSS properties is "as string". Should this be defined here or in CSS Animations Level 4?

For DOM attributes, the animation behavior is defined alongside the attribute definition. Unlike CSS properties, if such a definition is not provided the default animation behavior is “not animatable”.

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

For animation behaviors 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 behaviors that do not define a specific procedure for accumulation, the accumulation procedure is identical to the addition procedure for that behavior.

For animation behaviors that do not define a specific procedure for distance computation or which are defined as not paceable, the distance computation procedure is simply distance = 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 behaviors, no procedures for interpolation, addition and distance computation are defined for properties whose animation behavior 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 node such as occupying time in an animation sequence and delaying the fulfilment of a player's current finished promise

Animatable as string

A target property that is animatable as string has the following animation behavior:

  • interpolation:
    Vres= Vstart if p <0.5 Vend if p 0.5
    Vres = Vstart, if p < 0.5 or Vend, if p ≥ 0.5

Animatable as real number

A target property that is animatable as real number has the following animation behavior:

Animatable as length, percentage, or calc

A target property that is animatable as length, percentage, or calc has the following animation behavior:

Animatable as color

A target property that is animatable as color has the following animation behavior:

  • interpolation: as defined in [[CSS3-TRANSITIONS]].
  • addition: as with animatable as real number but performed on each RGBA color component in premultiplied space.

    Since negative color is not currently supported, clamping of the channel values may be performed upon each addition or once when composition is complete.

  • distance computation:
    distance= Rend - Rstart 2 + Gend - Gstart 2 + Bend - Bstart 2 + Aend - Astart 2
    sqrt((Rend
                      - Rstart)^2 + (Gend
                      - Gstart)^2 + (Bend
                      - Bstart)^2 + (Aend
                      - Astart)^2)
    where <R|G|B|Astart|end> represents the red, green, blue, or alpha channel of Vstart or Vend respectively. Each value is normalized to the [0.0, 1.0] range and expressed in premultiplied color space.

Should we call this “animatable as premultiplied RGBA additive color in sRGB color space” instead?

Animatable as transform list

A target property that is animatable as transform list has the following animation behavior:

  • interpolation: as defined in Interpolation of Transforms [[CSS3-TRANSFORMS]].
  • addition: performed by concatenating transform lists as ‘Va Vb’.
  • accumulation:
    1. Beginning at the end of each list, Va and Vb, find the largest contiguous portion of each list where the corresponding list elements from each list have the same transform type. Call the matching portions from Va and Vb, Vmatching-a and Vmatching-b respectively and likewise Vremainder-a and Vremainder-b for the non-matching parts.

      We should probably expand 2d functions to their 3d equivalents before matching?

    2. Let Vcombined be a transform list combining Vmatching-a and Vmatching-b by adding the numeric components of each corresponding function.

      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.

    3. The result of accumulation is a transform list created by adding the combined result with the non-matching portions of the two lists as follows: ‘Vremainder-a Vremainder-b Vcombined’.
  • distance computation: See issue below

For distance computation we previously defined it as follows:

  1. Look only at the first component of the two lists
  2. If both are translate → euclidean distance
  3. If both are scale → absolute difference
  4. If both are rotate → absolute difference
  5. If both match but are something else → use linear
  6. If they don't match → use matrix decomposition and euclidean distance between translate components

This seems really arbitrary, especially part 5.

Also, looking at only the first component seems odd. Going through each component, working out the distance and then getting the square of the distance also seems much more consistent with what we do elsewhere.

Other animation behaviors

The set of animation behaviors 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 [[CSS4-IMAGES]].

There are a bunch of CSS properties for which distance (and in some cases addition) is not defined or which need special handling.

For example,

  • font-stretch (an enum but handled like an integer)
  • visibility (0 or 1 depending on if endpoints match or not)
  • flex-grow and flex-shrink which allow animation only if one of the endpoints is 0)
  • value pairs, triples (use square distance)
  • rects (use square distance)
  • dash arrays (square distance but a bit weird due to percentages)
  • shadows (square distance of components)
  • filters (undefined)
  • background-position (special list handling needed)
  • pair lists

Should we define these here or in the CSS Animation 4 spec?

Intermediate animation values

Given a time fraction, a current iteration, and an underlying value, an animation effect produces an intermediate animation value for each animatable target property. The procedure for calculating this value depends on the specific type of animation effect and is defined subsequently (see and ).

Before being applied to the target properties, these intermediate animation values are composed together using the process defined in .

Combining animations

After calculating the intermediate animation values for an animation effect, they are applied to the animation effect's target properties.

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

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

For a CSS target property the arrangement is illustrated below:

Overview of the application of intermediate animation values
                to their target properties

Overview of the application of intermediate animation values to their target properties.
The results of animation effects targetting the same property are composited together using an animation stack.
The result of this composition is written to an animation stylesheet that is more important than other stylesheets but less than any !important rules.

For a target property that specifies a DOM attribute, the composited result is combined with the value of the attribute specified in the DOM or the lacuna value for that attribute if it is not specified.

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

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

The relative priority of intermediate animation values is determined by an animation stack established for each animated property.

The animation stack

Associated with each property targetted by one or more animation effects is an animation stack that establishes the relative priority of the animation effects.

The relative priority of any two animation effects, A and B, within an animation stack is established by comparing the properties of the animations applying A and B as follows:

  1. Let the associated player of an animation effect be the player associated with the animation that is applying the animation effect to the property with which this animation stack is associated.
  2. Sort A and B by applying the following conditions in turn until the order is resolved,
    1. Sort A and B using any custom player priority specified for the associated player of each of A and B so that lower priorities sort first.
    2. Sort by the player sequence number so that lower sequence numbers sort first.
    3. Sort A and B in tree order. (By this point, A and B must have the same player since otherwise the order would have been resolved in the previous step.)

Animation effects that sort earlier have lower priority.

The custom player priority

Each player has an associated numeric custom player priority that is used to provide high-level control of animation priority for specifications layered on top of Web Animations. The initial value of the custom player priority is zero.

Note that the custom player priority is primarily intended to be used to prioritize animations at a high-level, such as to prioritize animations by type. For example, it can be used to ensure that CSS Animations always override CSS Transitions.

It is possible to control animation priority at a lower-level by setting the player start time appropriately, (possibly after making compensatory adjustments to the start delay of the source content) or influencing the player sequence number by controlling when players are created.

Calculating the result of an animation stack

In order to calculate the final value of an animation stack, the intermediate animation values of each animation effect in the stack are combined in order of priority from lowest to highest priority.

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

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

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

Animation composition

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

This specification defines three composite operations as follows:

replace
The result of compositing the intermediate animation value with the underlying value is simply the intermediate animation value.
add

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

accumulate

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

Applying the composited result

The process for a applying a composited value depends on if the target property refers to a CSS property or a DOM attribute.

Applying the result to a CSS property

Applying a composited value to a CSS target property depends on establishing an animation stylesheet.

The animation stylesheet contains composited animation values and acts with a higher priority than all other stylesheets. However, !important rules from all other stylesheets act with a higher priority than the animation stylesheet. The animation stylesheet is regenerated each time the animation model is updated (see ).

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 used value [[!CSS21]] for that property in the absence of the animation stylesheet.
  2. Establish the animation stack for the property (see ).
  3. Calculate the composited value of the animation stack passing in the base value of the property as the initial underlying value (see ).
  4. Insert the composited value into the animation stylesheet.

Applying the composited result to a DOM attribute

DOM attributes are, unless otherwise specified, not animatable. For each attribute that has a specific animation behavior associated with it, an attribute value to use when the attribute is not specified or in error must be defined, referred to as the lacuna value. For example, SVG2 ([[SVG2]]) defines lacunae values for its attributes.

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

  1. Let the base value of the property be the value specified for attribute in the DOM or, if the attribute value is not specified in the DOM, the lacuna value for that attribute.
  2. Establish the animation stack for the property (see ).
  3. Calculate the composited value of the animation stack passing in the base value of the attribute as the initial underlying value (see ).
  4. Record the composited value as the animated attribute value of the attribute.

The animated attribute value does not replace the value of the attribute in the DOM although it may be accessible via some other interface. For all intents and purposes other than interaction with DOM interfaces, user agents must treat the animated attribute value as the attribute value.

Animation accumulation

Similar to the compositing performed between intermediate animation values (see ), the iteration composite operation determines how values are combined between successive iterations of the same animation.

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 intermediate animation value for each type of animation effect.

Keyframe animation effects

A keyframe animation effect is an animation effect that produces intermediate animation values for its target properties 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 animation effect is 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 .

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.

In addition to the composite operation specified on the animation effect, each keyframe may also have an associated composite operation that is applied to all values specified in that keyframe. If no composite operation is specified for a keyframe, the composite operation specified for the animation effect is used.

Spacing keyframes

It is often useful to be able to provide a series of property values without having calculate the keyframe offset of each value in time but instead to rely on some automatic spacing.

For example, rather than typing:

elem.animate([ { color: 'blue', offset: 0 },
               { color: 'green', offset: 1/3 },
               { color: 'red', offset: 2/3 },
               { color: 'yellow', offset: 1 } ], 2000);
          

It should be possible to type the following and allow the user agent to calculate the offset of each keyframe:

elem.animate([ { color: 'blue' },
               { color: 'green' },
               { color: 'red' },
               { color: 'yellow' } ], 2000);
          

Web Animations provides spacing modes for this purpose. The default spacing mode for keyframe animation effects is “distribute” which produces the result described above.

The other spacing mode, “paced”, is useful when it is desirable to maintain an even rate of change such as for motion path animation.

For example, consider the following animation:

elem.animate([ { left: '0px' },
               { left: '-20px' },
               { left: '100px' },
               { left: '50px' } ], 1000);
          

The resulting value of the left property is illustrated below:

The animated value of the left property over time when applying the distribute spacing mode.
The values are evenly spaced in time but the rate of change differs for each segment as indicated the varying slope of the graph.

The animated value of the left property over time when applying the distribute spacing mode. The values are evenly spaced in time but the rate of change differs for each segment as indicated the varying slope of the graph.

We can use the paced spacing mode as follows:

elem.animate(
  new KeyframeEffect([ { left: '0px' },
                       { left: '-20px' },
                       { left: '100px' },
                       { left: '50px' } ], { spacing: "paced" }), 1000);
          

The result is illustrated below:

The animated value of the left property over time when applying the paced spacing mode.
The absolute value of the slope is graph is equal for all segments of the animation indicating a constant rate of change.

The animated value of the left property over time when applying the paced spacing mode. The absolute value of the slope is graph is equal for all segments of the animation indicating a constant rate of change.

It is also possible to combine fixed keyframe offsets with spacing modes as follows:

elem.animate(
  new KeyframeEffect([ { left: '0px' },
                       { left: '-20px' },
                       { left: '100px', offset: 0.5 },
                       { left: '50px' } ], { spacing: "paced" }), 1000);
          

The result is illustrated below:

The animated value of the left property over time when applying the paced spacing mode and a fixed offset that puts the 100px value at 0.5.
The slope of the graph is equal for the first two segments but changes for the last segment in order to accommodate the fixed offset.

The animated value of the left property over time when applying the paced spacing mode and a fixed keyframe offset that puts the 100px value at 0.5. The slope of the graph is equal for the first two segments but changes for the last segment in order to accommodate the fixed offset.

Before calculating animation values from a keyframe animation effect, an absolute value must be computed for the keyframe offset of each keyframe with a null offset. The values computed depend on the keyframe spacing mode specified for the keyframe animation effect. The keyframe spacing modes are:

distribute
Indicates that keyframes with a null keyframe offset null are positioned so that the difference between subsequent keyframe offsets are equal.
paced
Indicates that keyframes with a null keyframe offset null are positioned so that the distance between subsequent values of a specified paced property are equal. The distance is calculated using the distance computation procedure defined by the animation behavior associated with the paced property.

Applying spacing to keyframes

We define a generic procedure for evenly distributing a keyframe, keyframe, between two reference keyframes, start and end, whose keyframe offsets are not null, as follows:

  1. Let offsetk be the keyframe offset of a keyframe k.
  2. Let n be the number of keyframes between and including start and end minus 1.
  3. Let index refer to the position of keyframe in the sequence of keyframes between start and end such that the first keyframe after start has an index of 1.
  4. Set the keyframe offset of keyframe to offsetstart + (offsetendoffsetstart) × index / n.

The computed keyframe offset values of each keyframe with a null keyframe offset are determined using the following procedure.

  1. Let keyframes refer to the list of keyframes associated with the keyframe animation effect.
  2. If keyframes contains more than one keyframe and the keyframe offset of the first keyframe in keyframes is null, set the keyframe offset of the first keyframe to 0.
  3. If the keyframe offset of the last keyframe in distributed keyframes is null, set its keyframe offset to 1.
  4. For each pair of keyframes A and B where:

    calculate the keyframe offset of each keyframe between A and B depending on the keyframe spacing mode as follows:

    If the spacing mode is paced,
    1. Define a keyframe as paceable if it contains a value for the paced property.
    2. Let paced A be the first keyframe in the range [A, B] that is paceable, if any.
    3. Let paced B be the last keyframe in the range [A, B] that is paceable, if any.
    4. If there is no paced A or paced B let both refer to B. Note that in this case, the spacing behavior degenerates to distribute spacing.
    5. For each keyframe in the range (A, paced A] and [paced B, B), apply the procedure for evenly distributing a keyframe using A and B as the start and end keyframes respectively.
      Yes, this is correct. We want, index and n in that procedure to reflect all the keyframes between A and B, not just the keyframes between, for example, A and spaced A.
    6. For each keyframe in the range (paced A, paced B) that is paceable:
      1. Let distk represent the cumulative distance to a keyframe k from paced A as calculated by applying the distance computation defined by the animation behavior of the paced property to the values of the paced property on each pair of successive paceable keyframes in the range [paced A, k].
      2. Set the offset of k to offsetpaced A + (offsetpaced Boffsetpaced A) × distk / distpaced B
    7. For each keyframe in the range (paced A, paced B) that still has a null keyframe offset (because it is not paceable), apply the procedure for evenly distributing a keyframe using the nearest keyframe before and after the keyframe in question in keyframes that has a keyframe offset that is not null, as the start and end keyframes respectively.
    Otherwise,
    Apply the procedure for evenly distributing a keyframe to each keyframe in the range (A, B) using A and B as the start and end keyframes respectively.

Note that although the above procedure defines computing keyframe offsets in terms of overwriting null values, user agents that implement the programming interface are required to maintain the original null values as well as calculating the computed offsets. This is because the getFrames method of the KeyframeEffect interface returns keyframe offsets both before and after applying spacing.

The above algorithm is quite complex. It attempts to cover all possible combinations of input where keyframe offsets and or paced property values may be missing. Furthermore, it attempts to do this in a way that degenerates consistently and also allows the author to combine fixed offsets with either pacing or distribute spacing. We await implementation experience to determine if the complexity is justified.

The intermediate animation value of a keyframe animation effect

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

  1. Let target property be the property for which the intermediate animation value is to be calculated.
  2. If animation behavior of the target property is not animatable abort this procedure since the effect cannot be applied.
  3. 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.
  4. Let property-specific keyframes be a copy of the list of keyframes specified on the effect.
  5. Remove any keyframes from property-specific keyframes that do not have a property value for target property.
  6. If property-specific keyframes is empty, return underlying value.
  7. If there is no keyframe in property-specific keyframes with a keyframe offset of 0, create a new keyframe with a 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.
  8. Similarly, if there is no keyframe in property-specific keyframes with a keyframe offset of 1, create a new keyframe with a 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.
  9. Let interval endpoints be an empty sequence of keyframes.
  10. Populate interval points by following the steps from the first matching condition from below:
    If time fraction < 0 and there is more than one keyframe in property-specific keyframes with a keyframe offset of 0,
    Add the first keyframe in property-specific keyframes to interval endpoints.
    If time fraction ≥ 1 and there is more than one keyframe in property-specific keyframes with a 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 keyframe offset is less than or equal to time fraction and less than 1. If there is no such keyframe (because, for example, the time fraction is negative), add the last keyframe whose keyframe offset is 0.
    2. Append to interval endpoints the next keyframe in property-specific keyframes after the one added in the previous step.
  11. 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 animation 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 animation 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 behavior.
    2. If this keyframe animation 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 (Va) with the property value on the final keyframe in property-specific keyframes (Vb) using the accumulation procedure defined for target property.

      It seems like this could be done as a separate step at the end and applied to all types of animation effects consistently.

  12. If there is only one keyframe in interval endpoints return the property value of target property on that keyframe.
  13. Let start offset be the keyframe offset of the first keyframe in interval endpoints.
  14. Let end offset be the keyframe offset of last keyframe in interval endpoints.
  15. Let interval distance be the result of evaluating (time fraction - start offset) / (end offset - start offset)
  16. Return the result of applying the interpolation procedure defined by the animation behavior 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 interval distance as the interpolation parameter p.

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

  • Each keyframe has a specified keyframe offset in the range [0, 1].
  • The list of keyframes is sorted in ascending order by keyframe offset.
  • Each specified property value is a valid and supported value.
  • For a given property, there is a most one specified property value on each keyframe.

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

For example, for the programming interface defined by this specification, these conditions are met by applying the normalization defined in and resolving null keyframe offsets by applying spacing behavior.

Note that 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 frames at 0 or 1, the output value for time fractions 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 time fraction 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 time fractions 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 time fractions 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.

Motion path animation effects

A motion path animation effect is an animation effect that produces animation values for the transform target property of an animation target such that it follows a geometric curve commonly referred to as a “motion path”.

The motion path of a motion path animation effect is defined by an SVG Path, as specified by SVG [[!SVG2]]. A motion path consists of a list of path commands (see path data [[!SVG2]]).

Amongst the different types of path commands, we define orientation path commands as moveto commands and bearing commands. All types of path commands that are not orientation path commands are referred to as drawing path commands.

The automatic rotation flag of a motion path animation effect, if set, specifies that the intermediate animation value generated by the motion path animation effect produces a rotation that matches the directional tangent vector of the motion path.

The rotation angle parameter of a motion path animation effect specifies a constant rotation that applies to the target transform in addition to any rotation generated by setting the automatic rotation flag.

Distance along a path

The procedure used for calculating the length of a path or a subsection is provided by the definition of distance along a path in SVG [[!SVG2]].

Spacing motion paths

The following properties control the rate of progress of a motion path animation effect:

spacing mode

Specifies the strategy used for determining the offset of each spacing point or path command when not specified by a point offset. The possible spacing modes are identical to those defined for keyframe animation effects (see ).

Note that a spacing mode of distribute has no effect if point offsets are specified. This is because spacing between point offsets always uses paced spacing mode.

spacing points

An optional sequence of real numbers in the range [0.0, 1.0] that correspond to fractions of the total path length. The animation effect produces animation values such that the animation target moves backwards and forwards along the motion path following the sequence indicated by these points.

Furthermore, the point on the motion path indicated by each such number forms a handle that may be associated with a point offset or positioned by the spacing mode.

point offsets

An optional ordered sequence of real numbers in the range [0.0, 1.0] that specifies the time fraction when the corresponding spacing point, or, if spacing points are not provided, drawing path command, should be visited.

If specified, the first value in the sequence must be 0.0 and the last value must be 1.0. There must be as many items in the sequence of point offsets as in the sequence of spacing points, if provided. If a sequence of spacing points is not provided, the number of items in point offsets must equal the number of drawing path commands in the motion path plus one.

point easing

An optional ordered sequence of timing functions that specify the easing behavior between each pair of spacing points, or, if spacing points are not provided, between each pair of drawing path commands.

If specified, there must be as many items as in the sequence of spacing points minus one, if provided. If a sequence of spacing points is not provided, the number of items in point easing must equal the number of drawing path commands in the motion path.

Note that the above descriptions of the length of each list represent the requirements of the model. Users of the model such as markup or programming interfaces may fulfill these requirements, for example, by defining padding behavior or error handling.

Need a diagram here showing how the different combinations work.

Applying spacing to motion paths

The end result of applying spacing is:

The sequence of effective spacing points is determined by following the steps associated with the first matching condition from below:

If there are no drawing path commands,
Let effective spacing points be an empty sequence.
If spacing points is specified,
Let effective spacing points refer to spacing points.
Otherwise,
Perform the following steps:
  1. Let effective spacing points be a sequence consisting of the single element 0.
  2. For each drawing path command in path commands, append to effective spacing points a number equal to the distance along a path up to the point at the end of the given path command, divided by the total path length.

Having determined the effective spacing points, the sequence of effective point offsets is determined by following the steps associated with the first matching condition from below:

If there are no drawing path commands,
Let effective point offsets be an empty sequence.
If point offsets is specified,
Let effective point offsets refer to point offsets.
If the spacing mode is distribute,
Perform the following steps:
  1. Let effective point offsets be a sequence of equal length to effective spacing points.
  2. Let n be the number of elements in effective point offsets minus one.
  3. Let k represent an index in the range [0, n].
  4. Set the value of each point in effective point offsets so that the point at index k is equal to k / n.
Otherwise,
Perform the following steps:
  1. Let effective point offsets be a sequence of equal length to effective spacing points.
  2. Let n be the number of elements in effective point offsets minus one.
  3. Let k represent an index in the range [0, n].
  4. Let point(k) represent the value of effective spacing points at index k.
  5. Set the value of each point in effective point offsets so that the value at index k is defined by the following formula:
    • For k = 0, offset = 0
    • For k = 1..n, offset =
      Σ i = 1 k point i - point i - 1 Σ i = 1 n point i - point i - 1
      [ \sum_{i=1}^k | point(i)-point(i-1) | ] / [ \sum_{i=1}^n | point(i)-point(i-1) | ]
When effective spacing points is a sequence of monotonically increasing points beginning with 0 and ending with 1 (or, in fact, any time the sum of distances between effective spacing points is equal to 1), effective point offsets will mirror effective spacing points.

The effective point easing is simply the specified point easing. If point easing is not set, the effective point easing is a sequence of linear timing functions equal in length to the number of drawing path commands in the motion path.

Determining the path fraction

The path fraction for a given time fraction, progress, is determined using the following procedure:

  1. If effective point offsets is empty, let path fraction equal time fraction and abort these steps.
  2. If effective point offsets has only one item, let path fraction equal the value of the one item in effective spacing points and abort these steps.
    Effective point offsets can only have one item if spacing points has exactly one item. In this case, the effective points offsets will always be a list containing just the value 0.
  3. If progress ≥ 1, let the path fraction equal the value of the last item in effective point offsets and abort these steps.
  4. If progress < 0, let the path fraction equal the value of the first item in effective point offsets and abort these steps.
  5. Let start index and end index represent the zero-based indices of the last pair of successive values in effective point offsets such that start offsetprogressend offset.
  6. Let interval fraction be the ratio of the difference between progress and the offset at start index, and the difference between the offset at end index and the offset at start index.
  7. Let scaled interval fraction be the result of applying the timing function from effective point easing at index start index with interval fraction as the input.
  8. Let segment start and segment end be the values in effective spacing points at the indicies start index and end index respectively.
  9. Let the path fraction be the result of evaluating the following formula: scaled interval fraction * (segment end - segment start) + segment start.

The intermediate animation value of a motion path animation effect

The intermediate animation value of a motion path animation effect for a given time fraction, current iteration, and underlying value is given by the following process:

  1. Let distance be the path fraction for the given time fraction.
  2. Let displacement be the point located distance along the motion path using the definition for distance along a path.

    If distance indicates a point on the path that is coincidental with one or more orientation path commands, displacement is the point after all orientation path commands (this will be the start of the next drawing path command if there is one).

  3. Let the translation component be the translation transform required to transform the point at the start of motion path to displacement.
  4. Calculate the rotation component according to the first match condition from the following:
    If the automatic rotation flag is set,
    the rotation component is a transform representing the sum of:
    • the angle of the tangent vector at displacement, and
    • the rotation angle.
    Otherwise,
    the rotation component is a transform representing the rotation angle.

    When calculating the angle of the tangent vector, if there are no drawing path commands in the motion path, the the angle should be taken to be zero.

    The original text for this section contained the following qualifications but I'm not sure how meaningful they are:

    • For continuous path commands (all elements except moveto), the angle of the tangent vector for the purpose of these calculations is defined to be an integer multiple of 2π different from the value given by standard mathematical formulae for tangents to curves in 2 dimensional space.
    • For moveto path commands, which are discontinuous, the angle of the tangent vector for the purpose of these calculations is always an integer multiple of 2π.
    • The initial value of the angle of the tangent vector is computed using the first element of the curve, and is always in the range [0, 2π).
    • Single continuous path commands must never produce tangent vector angles that are discontinuous over their defined region. This implies that a single unique solution is available for all points on continuous path commands.
    • When computing angles after discontinuous or non-smooth jumps, multiple possible solutions may be available. These solutions will differ by integer multiples of 2π. In such cases the solution that lies closest to the previous tangent angle is used.
  5. Let the transform value be the result of by constructing a transform list consisting of the translation component followed by the rotation component.
    What's the value in keeping these separate? Shouldn't we collapse them?
  6. Let the unaccumulated value be the result of combining the underlying value (Va) with the transform value (Vb) using the composite operation of the effect.
  7. Let the intermediate animation value be unaccumulated value.
  8. If the iteration composite operation of this motion path animation effect is accumulate, perform the following steps:
    1. Let the final transform value be the value calculated for the transform value when performing the first five steps of this procedure using a time fraction of 1.
    2. Perform the following step current iteration times:
  9. Return the intermediate animation value.
Need to describe how transform-origin is applied.

Custom effects

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 a time fraction 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.

Sampling custom effects

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

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

    Call the callback passing an null time fraction and the animation target from the previous sample as parameters to the callback.

  2. Call the callback for the current animation target based on the first matching condition from the following:
    If the animation referencing the custom effect is not in effect but was in effect in the previous sample,
    Call the callback passing a null time fraction and the current animation target as parameters to the callback.
    Otherwise, if the animation referencing the custom effect:
    Call the callback passing with the referencing animation's current time fraction and animation target 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:

  • Additional calling conditions could be defined to accommodate zero-width custom effects. For example, it could be required that the callback be called if (given infinite precision) there was a time between the previous and current sample times that aligned with the custom effect.
  • Instead of adding special calling conditions to custom effects, a new type of animation node, Trigger, could be introduced. The trigger would only ever act as a zero-width custom effect as described above, its constructor would take a callback function, but not require a target or timing. It could also specify other calling conventions, for example whether it should only trigger in a specific playback direction.

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.

Custom effects are executed after all animation effects have completed and applied their result to their targets (see ).

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 . Items sorted earlier are executed before those sorted later.

Programming interface

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.

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.

The AnimationTimeline interface

Timelines, including the document timeline are represented in the Web Animations API by the AnimationTimeline interface.

readonly attribute double? currentTime

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

AnimationPlayer play()

Creates a new AnimationPlayer object associated with this timeline that is scheduled to start at currentTime.

The timeline attribute of the newly-created AnimationPlayer object will be set to this object.

Similarly, the start time of the newly created player will be set to the value of this object's currentTime attribute at the moment the method was called.

The setting of the source attribute is described below under the description of the source parameter.

The currentTime attribute of the AnimationPlayer object is a calculated value described in .

The playbackRate and paused attributes take on their default values as described in the definitions of the playback rate and paused state properties of player objects.

optional AnimationNode? source = null

The source content to assign to the newly-created AnimationPlayer object.

The source attribute of the created AnimationPlayer is set by following the procedure defined for updating that attribute. As a result, if source is already associated with a player, it will be disassociated first before being associated with the new AnimationPlayer.

sequence<AnimationPlayer> getAnimationPlayers()

Returns the set of AnimationPlayer objects associated with this timeline that have associated source content which is current.

The returned list is sorted in increasing order by player sequence number.

The AnimationPlayer interface

Players are represented in the Web Animations API by the AnimationPlayer interface.

attribute AnimationNode? source

The source content associated with this player.

A player can only be associated with at most one animation node, and likewise, an animation node can only be associated with at most one player. In order to maintain these invariants, on setting this value, the following procedure is performed:

  1. Let old value be the current value of the source attribute.
  2. Let new value be the value to set.
  3. If new value is the same object as old value, return.
  4. If old value is not null, disassociate old value from this player.
  5. If new value is not null, perform the steps associated with the first matching condition of the following:
    If new value has no parent group and is associated with a player,
    disassociate new value from its player.
    If new value has a parent group,
    remove new value from its parent group by calling new value.remove().
    Otherwise,
    do nothing.
  6. Associate new value with this player.
  7. Set the source attribute to new value.
readonly attribute AnimationTimeline timeline
The timeline associated with this player.
attribute double? startTime
Returns the start time of this player. Setting this attribute updates the player start time using the procedure to update the start time of this object to the new value.
attribute double? currentTime
The current time of this player. Setting this attribute follows the procedure to set the current time of this object to the new value.
attribute double playbackRate
The playback rate of this player. Setting this attribute follows the procedure to update the player playback rate of this object to the new value.
readonly attribute AnimationPlayState playState
The play state of this player.
readonly attribute Promise ready
Returns the current ready promise for this object.

This should be Promise<AnimationPlayer> but this version of respec doesn't support that.

readonly attribute Promise finished
Returns the current finished promise for this object.

This should be Promise<AnimationPlayer> but this version of respec doesn't support that.

void cancel()
Clears all effects caused by this player and aborts it playback by running the cancel a player for this object.
void finish()
Seeks the player to the end of the source content in the current direction by running the finish a player procedure for this object.
void play()
Unpauses the player and rewinds if it has finished playing by running the procedure to play a player for this object.
void pause()
Suspends the playback of this player by running the procedure to pause a player for this object.
void reverse()
Inverts the playback rate of this player and seeks to the start of the source content if it has finished playing in the reversed direction by running the reverse a player procedure for this object.

The AnimationPlayState enumeration

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.

The AnimationNode interface

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

// Timing
readonly attribute AnimationTiming timing

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

readonly attribute ComputedAnimationTiming computedTiming

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

Although several of the attributes of the this object are common to the timing AnimationTiming object they have the following differences:

  • duration – returns the calculated value of the iteration duration. If timing.duration is the string auto or any unsupported value, this attribute will return the current calculated value of the intrinsic iteration duration.
  • fill – the auto value is replaced with the specific FillMode depending on the type of animation node (see ).
  • easing – unrecognised or unsupported values are replaced with the string linear.
// Timing hierarchy
readonly attribute AnimationGroup? parent

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

Should this be parentGroup?
readonly attribute AnimationNode? previousSibling
The previous sibling of this animation node.
readonly attribute AnimationNode? nextSibling
The next sibling of this animation node.
void before (AnimationNode... nodes)

Inserts nodes before this animation node.

  1. If there is no parent animation group, terminate these steps.
  2. If any of the animation nodes in nodes is an inclusive ancestor of this animation node throw a HierarchyRequestError exception and terminate these steps.
  3. Insert nodes before this animation node.

Note that this definition precludes the following usage since node is an inclusive ancestor of itself:

                node.before(node); // throws HierarchyRequestError
              
void after (AnimationNode... nodes)

Inserts nodes after this animation node.

  1. If there is no parent animation group, terminate these steps.
  2. If any of the animation nodes in nodes is an inclusive ancestor of this animation node throw a HierarchyRequestError exception and terminate these steps.
  3. Let reference child be the next sibling of this animation node not in nodes.
  4. Insert nodes before reference child.
void replace (AnimationNode... nodes)

Replaces this AnimationNode with the passed in nodes.

  1. If there is no parent animation group, terminate these steps.
  2. If any of the animation nodes in nodes is an inclusive ancestor of the parent animation group throw a HierarchyRequestError exception and terminate these steps.
  3. Let reference child be the next sibling of this animation node not in nodes.
  4. Remove this animation node from its parent animation group.
  5. Insert nodes before reference child.
void remove ()
Removes this animation node from its parent animation group or player.
// Associated player
readonly attribute AnimationPlayer? player

The player with which this animation node is associated, if any. This object can be used to perform play control such as pausing or rewinding on this animation node and all other animation nodes in the same hierarchy.

This will be null if this animation node is not associated with a player.

Feedback has been provided that suggests this reference causes the relationship between AnimationPlayers and AnimationNodes to be circular, which confuses the model. The player attribute should be considered at risk unless a strong use case for the reference arises.

The AnimationTimingReadOnly interface

class="idl">
readonly attribute double delay

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

Now that we have endDelay, should we change this back to startDelay?

readonly attribute double endDelay

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

readonly attribute FillMode fill

The fill mode as specified by one of the FillMode enumeration values.

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 node to which the fill mode is being is applied is an animation,
Use none as the fill mode.
Otherwise,
Use both as the fill mode.
readonly attribute double iterationStart

The animation node's iteration start property.

A finite real number greater than or equal to zero representing the number of iterations into the animation node at which to begin.

readonly attribute unrestricted double iterations

The animation node's iteration count property.

A real number greater than or equal to zero (including positive infinity) representing the number of times to repeat the animation node.

readonly attribute (unrestricted double or DOMString) duration

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

The string value auto is used to indicate that the iteration duration reflects the animation node's intrinsic iteration duration.

readonly attribute double playbackRate

The animation node's playback rate property.

This is a multiplier applied to the local time potentially causing the node to run at a different rate to its natural speed.

readonly attribute PlaybackDirection direction

The playback direction of the animation node as specified by one of the PlaybackDirection enumeration values.

readonly attribute DOMString easing

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

The syntax of the string is defined by the following production:

In future we may extend this so that it is possible to query the individual functions in the string. It may be possible to do this by extending this attribute using some stringifier magic, or else we could just add easingList similar to HTML's classList.

The AnimationTiming interface

The AnimationTiming interface is a writeable subclass of AnimationTimingReadOnly used for an AnimationNode's timing attribute.

inherit attribute double delay
See the delay member of the AnimationTiming interface.
inherit attribute double endDelay
See the endDelay member of the AnimationTiming interface.
inherit attribute FillMode fill
See the fill member of the AnimationTiming interface.
inherit attribute double iterationStart

See the iterationStart member of the AnimationTiming interface.

Values less than zero are clamped to zero for the purpose of timing model calculations.

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

Setting the iterationStart to a value greater than or equal to one is typically only useful in combination with an animation effect that has an iteration composite operation of ‘accumulate’.

inherit attribute unrestricted double iterations

See the iterations member of the AnimationTiming interface.

Values less than zero and NaN values are treated as the value 1.0 for the purpose of timing model calculations.

inherit attribute (unrestricted double or DOMString) duration

See the duration member of the AnimationTiming interface.

Real numbers less than zero, NaN values, and strings other than the lowercase value auto are treated the same as auto for the purpose of timing model calculations.

inherit attribute double playbackRate
See the playbackRate member of the AnimationTiming interface.
inherit attribute PlaybackDirection direction
See the direction member of the AnimationTiming interface.
inherit attribute DOMString easing

See the easing member of the AnimationTiming interface.

Unrecognized string values or values that correspond to a timing function that is not supported for the type of animation node to which this property is applied are treated as if the linear keyword was specified for the purpose of timing model calculations.

The ComputedAnimationTiming interface

Timing parameters calculated by the timing model are exposed using the ComputedAnimationTiming interface.

readonly attribute double startTime

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

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

readonly attribute unrestricted double endTime
The end time of the animation node expressed in milliseconds in inherited time space. This corresponds to the end of the animation node's active interval plus any end delay.
readonly attribute unrestricted double activeDuration
The active duration of this animation node.
readonly attribute double? localTime

The local time of this animation node.

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

readonly attribute unrestricted double timeFraction
The current time fraction of this animation node.
readonly attribute unsigned long? currentIteration
The current iteration index beginning with zero for the first iteration.

The AnimationTimingInput dictionary

The AnimationTimingInput dictionary is used as a convenience for specifying the timing properties of an AnimationNode in bulk.

double delay = 0

The specified start delay.

See the description of the delay attribute on the AnimationTiming interface.

double endDelay = 0

The specified end delay.

See the description of the endDelay attribute on the AnimationTiming interface.

FillMode fill = "auto"

The fill mode as specified by one of the FillMode enumeration values.

double iterationStart = 0.0

The animation node's iteration start property.

See the description of the iterationStart attribute on the AnimationTiming interface.

unrestricted double iterations = 1.0

The animation node's iteration count property.

See the description of the iterations attribute on the AnimationTiming interface.

(unrestricted double or DOMString) duration = "auto"

The iteration duration of the animation node.

See the description of the duration attribute on the AnimationTiming interface.

double playbackRate = 1.0

The animation node's playback rate property.

See the description of the playbackRate attribute on the AnimationTiming interface.

PlaybackDirection direction = "normal"

The playback direction of the animation node.

See the description of the direction attribute on the AnimationTiming interface.

DOMString easing = "linear"

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

See the description of the easing attribute on the AnimationTiming interface.

The FillMode enumeration

none
No fill.
forwards
Fill forwards.
backwards
Fill backwards.
both
Fill backwards and forwards.
auto
Fill backwards and forwards when applied to an AnimationGroup and no fill when applied to an Animation.

The PlaybackDirection enumeration

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.

The AnimationGroup interface

Animation groups are represented by the AnimationGroup interface.

Constructor ()

Creates a new AnimationGroup object using the following procedure:

  1. Create a new AnimationGroup object, group.
  2. Set timing input as follows,
    If timing is an AnimationTimingInput object,
    Let timing input refer to timing.
    If timing is a double,
    Let timing input be a new AnimationTimingInput object with all members set to their default values and duration set to timing.
    Otherwise (timing is undefined),
    Let timing input be a new AnimationTimingInput object with all members set to their default values.
  3. Set group.timing to a new AnimationTiming object whose attributes are assigned the value of the member of the same name on timing input.

    The above two steps are identical with the constructor for Animation and should be factored out somewhere.

  4. Insert children before null.

Note that since AnimationTiming objects have the same member names as AnimationTimingInput dictionaries, it is also possible to pass the timing member of another AnimationNode as the timing parameter.

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

sequence<AnimationNode>? children

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

These children are appended in sequence using the same semantics as the AnimationGroup.append method.

optional (unrestricted double or AnimationTimingInput) timing

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

readonly attribute AnimationNodeList children
The list of child animation nodes in the group.
readonly attribute AnimationNode? firstChild
The first child of this animation group.
readonly attribute AnimationNode? lastChild
The last child of this animation group.
void prepend (AnimationNode... nodes)
  1. If any of the animation nodes in nodes is an inclusive ancestor of this animation node throw a HierarchyRequestError exception and terminate these steps.
  2. Insert nodes before the first child.
void append (AnimationNode... nodes)
  1. If any of the animation nodes in nodes is an inclusive ancestor of this animation node throw a HierarchyRequestError exception and terminate these steps.
  2. Insert nodes before null.
AnimationGroup clone ()

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

  1. Let source be this AnimationGroup object, the object to be cloned.
  2. Let cloned timing be a new AnimationTimingInput 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 AnimationNode objects.
  4. For each child in source.children, append the result of calling child.clone() to cloned children.
  5. Return a new AnimationGroup object created by calling the AnimationGroup constructor with parameters AnimationGroup(cloned children, cloned timing).

Definitions for manipulating hierarchies

The next sibling of node not included in a set of animation nodes, nodes is determined using the following steps:

  1. Let context node be node.
  2. While the next sibling of context node is not null perform the following steps:
    1. Let context node be the next sibling of context node.
    2. If context node is not in nodes return context node and terminate these steps.
  3. Return null.

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

If node has a parent animation group,
Remove node from the parent animation group's list of child animation nodes.
If node is directly associated with a player,
Disassociate node from the player.

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

  1. Remove node from its parent.
  2. Insert node to parent's list of child animation nodes before reference child.

The AnimationNodeList interface

A list of animation nodes 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.

readonly attribute unsigned long length
The number of animation nodes in the list.
getter AnimationNode? item(unsigned long index)

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

The AnimationSequence interface

Animation sequences are represented by the AnimationSequence interface.

Constructor (sequence<AnimationNode>? children, optional (unrestricted double or AnimationTimingInput) timing)
The meaning and handling of each of the parameters in this constructor is identical to the constructor for AnimationGroup.
AnimationSequence clone ()

Creates a deep copy of this AnimationSequence object using the same procedure as defined for AnimationGroup.clone except that a new AnimationSequence object is created.

The Animation interface

Animations are represented by the Animation interface.

Constructor ()

Creates a new Animation object using the following procedure:

  1. Create a new Animation object, animation.
  2. Set timing input as follows,
    If timing is an AnimationTimingInput object,
    Let timing input refer to timing.
    If timing is a double,
    Let timing input be a new AnimationTimingInput object with all members set to their default values and duration set to timing.
    Otherwise (timing is undefined),
    Let timing input be a new AnimationTimingInput object with all members set to their default values.
  3. Set animation.timing to a new AnimationTiming object whose attributes are assigned the value of the member of the same name on timing input.
  4. Set animation.effect to the result of applying the procedure for converting an effect to an IDL value to effect.

Examples of the usage of this constructor are given in .

Note that as with the constructor for AnimationGroups it is possible to pass in an AnimationTiming object here (e.g. the timing member of another AnimationNode) in which case it will be cloned.

Animatable? target
The animation target or target pseudo-element. This may be null for animations that do not target a specific element.
object? effect

The animation effect used to set the effect attribute of the newly-created Animation object.

The processing of this parameter is defined normatively in . Following is a non-normative summary of this handing.

effect may be one of the following:

If this parameter is an AnimationEffect object or EffectCallback object, it will be shared with any other Animation objects referring to the same AnimationEffect or EffectCallback object. It will not be copied.

If this parameter is of type Keyframe or sequence<Keyframe>, the animation effect of the newly-created Animation will be a newly-created KeyframeEffect object initialized by using this object as the list of keyframes and with all other parameters set to their default values.

If this parameter is null, the newly-created Animation will also have a null animation effect.

optional (unrestricted double or AnimationTimingInput) timing

The timing properties or iteration duration of the new animation.

attribute (AnimationEffect or EffectCallback)? effect

The animation effect or custom effect to apply. May be null in which case the animation will produce no observable effect.

On setting, if the previous value was an EffectCallback, we should call the old callback with a null time fraction so it can clear its result.

attribute Animatable? target

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.

Animation clone ()

Creates a copy of this Animation object using the following procedure.

  1. Let source be the Animation object to clone, that is, this object.
  2. Let cloned timing be a new AnimationTimingInput object whose members are assigned the value of the attribute with the same name on source.timing.
  3. The AnimationEffect is cloned depending on the type of source.effect as follows,
    If source.effect is an Animation object,
    Let cloned effect be the result of calling source.effect.clone().
    If source.effect is an EffectCallback object,
    Let cloned effect be source.effect.
    Otherwise,
    Let cloned effect be null.
  4. Return a new Animation object created by calling the Animation constructor with parameters Animation(source.target, cloned effect, cloned timing).

Processing the effect parameter

The effect parameter, an ECMAScript value passed to the Animation constructor or to the animate operation of the Animatable interface, may specify an EffectCallback, an AnimationEffect, a Keyframe a sequence of Keyframes, or null. However, since callback functions and dictionaries are not distinguishable in WebIDL, we define the processing of this parameter for ECMAScript here in prose.

The procedure for converting an effect to an IDL value with parameter effect is as follows:

If effect is null,
Return null.
If effect is a platform object that implements AnimationEffect,
return the IDL value that is a reference to the that platform object.
If IsCallable(effect) is true,
Return the result of applying the procedure for converting an ECMAScript value to an IDL callback function type to effect using EffectCallback as the callback function type.
Otherwise,
Return a new KeyframeEffect object constructed passing effect as the frames parameter.

Note that since the processing of this parameter is defined in prose, the above steps will take place after any coercion is applied to other parameters passed to the same operation.

Creating a new Animation object

The Animation constructor offers a number of approaches to creating a new Animation object. At its simplest, an Animation object that changes the ‘left’ property of elem to 100px over three seconds can be achieved as follows:

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

The second parameter, representing the animation effect, may specify multiple properties, an AnimationEffect object, or even a callback function.

// Specify multiple properties at once
var animA = new Animation(elem, { left: '100px', top: '300px' }, 3000);

// Specify multiple frames
var animB = new Animation(elem, [ { left: '100px' }, { left: '300px' } ], 3000);

// Share the animation effect of another animation
var animC = new Animation(elem, animB.effect, 3000);

// Supply a specialized animation effect
var animD = new Animation(elem,
                          new MotionPathEffect("M100 250C100 50 400 50 400 250"),
                          3000);

// Supply a custom script-based animation effect
var animE = new Animation(elem, function(time) { 
    // (Normally we should check for time===null, but in this case it produces
    //  the correct result anyway)
    document.documentElement.currentScale = 1.0 + time * 2.0;
  }, 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 playback rate, an AnimationTimingInput object can be used as follows:

var anim =
  new Animation(elem, { left: '100px' }, { duration: 3000, playbackRate: 2 });
          

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

new Animation(elem, { display: 'none' }, { fill: 'forwards' });
          

This is particularly useful in combination with other animations or animation nodes. For example, fading an element before switching ‘display’ to ‘none’ can be achieved as follows,

new AnimationSequence(
  [
    new Animation(elem, { opacity: 0 }, 1000),
    new Animation(elem, { display: 'none' }, { fill: 'forwards' })
  ]
);
          

Having created an Animation, it can be played using document.timeline.play(anim). For simple effects, however, the Element.animate shortcut is more convenient since it performs this last step automatically. For example,

elem.animate({ left: '100px' }, 3000);
          

The Animatable interface

Objects that may be the target of an Animation implement the Animatable interface.

AnimationPlayer animate()

Creates a new Animation object whose animation target is the object on which the method is called, and calls the play method of the AnimationTimeline object of the document timeline of the node document [[!DOM4]] of the element passing the newly created Animation as the argument to the method.

The following code fragment:

              var anim = elem.animate({ opacity: 0 }, 2000);
            

is equivalent to:

              var anim = new Animation(elem, { opacity: 0 }, 2000);
              elem.ownerDocument.timeline.play(anim);
            

Returns the AnimationPlayer object returned by the play method of the AnimationTimeline.

object? effect
The effect to apply. This value is passed to the Animation constructor as the effect parameter and has the same interpretation as defined for that constructor.
optional (double or AnimationTimingInput) timing
The timing parameters of the animation. This value is passed to the Animation constructor as the timing parameter and has the same interpretation as defined for that constructor.
sequence<Animation> getCurrentAnimations()

Returns the set of current Animation objects that have an animation effect whose animation target is this object.

The returned list of Animation objects is sorted by their associated animation effect using the procedure defined for sorting animation effects in .

Note that the definition of a current animation does not include those animations whose local time falls after the active interval but which are still in effect due to a fill mode. As a result such animations are not returned by this method.

This is because in order to return such animations, user agents would be required to maintain all animations with a forwards fill indefinitely. As a result the resources consumed by an animated document would steadily accumulate over time.

Note that when called on Element objects, the list of returned Animations will not include those animations whose target is a PseudoElement associated with the Element since PseudoElement and Element are treated as independent Animatable objects.

Feedback has been provided that suggests direct references from AnimationNode objects to AnimationPlayers generate circular reference and confuse the model. Without this reference, getCurrentAnimations is not very useful, as the returned AnimationNodes can't be used to effect play control. In the absence of a strong use case for a reference from AnimationNode to AnimationPlayer, this feature should be considered at risk.

sequence<AnimationPlayer> getAnimationPlayers()

Returns the set of AnimationPlayer objects whose source content is current and contains at least one animation whose animation target is this object.

If this object is the animation target of two or more animations which are associated with the same player, the corresponding AnimationPlayer object will still only appear in the returned list once.

The returned list is sorted in increasing order by player sequence number.

The AnimationEffect interface

Animation effects are represented by the AnimationEffect interface. AnimationEffect is an abstract interface of which several concrete subinterfaces are provided.

attribute IterationCompositeOperation iterationComposite

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

attribute CompositeOperation composite

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

AnimationEffect clone ()

Creates and returns a new object of the same type as this object's most-derived interface such that it will produce the same output as this object.

We either need a more rigorous definition here or (probably better) a sets of steps on a per-subclass basis.

In future, we may expose any sample (double? timeFraction, double currentIteration, Animatable? target, any underlyingValue) so that the animation effects can be driven apart from the timing model.

The IterationCompositeOperation enumeration

The possible values of an animation effect's iteration composite operation are represented by the IterationCompositeOperation enumeration.

replace
Corresponds to the replace iteration composite operation value such that the intermediate animation value produced is independent of the current iteration.
accumulate
Corresponds to the accumulate iteration composite operation value such that subsequent iterations of an animation build on the final value of the previous iteration.

The CompositeOperation enumeration

The possible values of an animation effect's composition behavior are represented by the CompositeOperation enumeration.

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.

The KeyframeEffect interface

Keyframe animation effects are represented by the KeyframeEffect interface.

Constructor ()

Creates a new KeyframeEffect object for the given set of keyframes.

object frames
A Keyframe object or sequence of Keyframe objects used for calculating animation values for this animation effect. The constraints on this parameter and its processing are identical to those for setFrames.
optional KeyframeEffectOptions options
A KeyframeEffectOptions dictionary defining other aspects of the animation effect's behavior. If this parameter is not provided, the default values of the dictionary are used.
attribute DOMString spacing

The spacing mode to use for this animation effect.

Recognized values are defined by the following grammar:

distribute | paced({ident}) | paced

{ident} here is an identifier as defined by CSS3 Values [[!CSS3-VALUES]].

The meaning of each value is as follows:

distribute
Use the distribute keyframe spacing mode.
paced({ident})

Use the paced keyframe spacing mode with the property name indicated by {ident} as the paced property.

For example, paced(transform) would indicate that the keyframes should be spaced such that changes to the transform property occur at a constant rate.

paced

Use the paced keyframe spacing mode.

The paced property to use is the first property specified in the first keyframe in the list of keyframes associated with this animation effect when sorting the CSS property names in ascending order by Unicode codepoint.

As a result, changes to the keyframes may cause the paced property to change.

Note that this behavior is generally not useful for keyframes specifying more than one property. It is provided for consistency with MotionPathEffect and as a convenience for keyframe animation effects that specify only one property.

All other values are treated as "distribute" for the purpose of animation model calculations.

sequence<ComputedKeyframe> getFrames()

Returns the keyframes that make up this effect as a sequence of ComputedKeyframe objects.

The value returned differs from the frames parameter passed into setFrames or the constructor for this interface in the following ways:

  • The normalization defined in is applied to frames which may result in some frames being removed or re-ordered and some properties being removed. This normalization will also cause a single Keyframe object to be replaced with a sequence.
  • The result of computing the keyframe offset of each keyframe as defined in is stored in the computedOffset member of each frame.
void setFrames(object frames)

A Keyframe object or sequence of Keyframe objects used to replace the set of keyframes that make up this effect.

The processing of the frames parameter is defined in . Subsequently, the resulting sequence of Keyframe objects is normalized using the procedure in before storing.

Processing a sequence of Keyframe objects or a single item

WebIDL does not currently make a dictionary and a sequence distinguishable but it was felt that allowing both was important for useability of the animate operation on Animatable. Therefore, we define the processing for handling a parameter that may be either a single Keyframe dictionary object, or a sequence of such objects.

The procedure for converting an ECMAScript value into an IDL keyframe or sequence of keyframes with parameter keyframeOrKeyframeList is as follows:

If, using the canonical definition of Array.isArray [[!ECMA-262]], Array.isArray(keyframeOrKeyframeList) is true,
Return the result of following the steps for converting an ECMAScript value into an IDL sequence using the procedure for converting an ECMAScript value to an IDL Keyframe object as the procedure for converting E to an IDL value of type T.
Otherwise,
Return the result of applying the procedure for converting an ECMAScript value to an IDL Keyframe object to keyframeOrKeyframeList.

Should this be defined in terms of IsIterable instead?

The KeyframeEffectOptions dictionary

Additional parameters may be passed to the KeyframeEffect constructor by providing a KeyframeEffectOptions object.

IterationCompositeOperation iterationComposite = "replace"
The iteration composite operation used to define the way animation values build from iteration to iteration.
CompositeOperation composite = "replace"
The composite operation used to composite this animation with the animation stack, as specified by one of the CompositeOperation enumeration values. This is used for all keyframes that do not specify a composite operation.
DOMString spacing = "distribute"

The spacing mode to apply to this animation effect's keyframes.

See the description of the spacing attribute of the KeyframeEffect interface for the recognized values and their meaning are described

Unrecognized values are set on the created KeyframeEffect object, but are treated as "distribute" for the purpose of animation model calculations.

Normalizing a sequence of keyframes

For each call to setFrames or the KeyframeEffect constructor, the following normalization is performed on the passed in frames parameter before storing its value.

Note that the processing of the ECMAScript value into a suitable IDL value defined in is performed before this operation is initiated.

  1. If frames is a single Keyframe object, replaces frames with a new sequence with a single item that is the previous value of frames.
  2. If frames is not loosely sorted by offset, then,
    If each Keyframe has a non-null offset,
    Sort frames in ascending order by offset.
    Otherwise,
    Throw a DOMException of type InvalidModificationError.
  3. If there exist any Keyframe objects in frames whose offset member is non-null and less than zero, remove all keyframes objects from the start of frames up to and including the keyframe with the largest non-null offset that is still less than zero.
  4. Likewise, if there exist any Keyframe objects in frames whose offset member is non-null and greater than one, remove all keyframes from the keyframe with the smallest non-null offset that is still greater than one until the end of frames.
  5. Remove all property values in frames that are invalid or not supported by the implementation.

    Need to define what invalid means here.

The Keyframe dictionary

Individual keyframes are represented by a special kind of Keyframe dictionary type whose members map to the properties to be animated. At the time of writing, this kind of open-ended dictionary cannot be represented using WebIDL and hence special ECMAScript-specific handling for this type is defined in . No handling is defined for other languages.

// ... property-value pairs ...
double? offset = null

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

Keyframes with offsets outside the range [0.0, 1.0] are ignored when calculating animation values as defined in .

A null value indicates that the keyframe should be positioned using the keyframe animation effect's keyframe spacing mode.

DOMString easing = "linear"

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

CompositeOperation? composite = null

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

If null, the composite operation specified on the AnimationEffect will be used.

Processing a Keyframe object

Since accessing the properties of an ECMAScript user object can have side effects, the manner in which these properties is accessed is important. In light of this consideration the procedure for converting an ECMAScript object into an IDL Keyframe object has the following properties:

  • Each property that is read, is read only once.
  • Properties are read in a well-defined order.
  • Properties corresponding to unsupported target properties or attributes are not read.

The procedure for converting an ECMAScript value to an IDL Keyframe object with parameter keyframe input is as follows:

  1. Let keyframe result be a Keyframe object with the offset, easing and composite attributes set to the default dictionary values.
  2. Create a list, supported properties, of property names and attribute names that can be animated by the implementation.
  3. Convert each property name in supported properties to the equivalent IDL attribute by applying the CSS property to IDL attribute algorithm [[!CSSOM]].
  4. If the user agent supports animation of the float CSS property, replace 'float' in supported properties with 'cssFloat'.
  5. Let animation properties be an empty sequence.
  6. Use the internal [‌[Enumerate]] operation on keyframe input to iterate over its properties. For each property perform the step corresponding to the first matching condition from below, if any.
    If property is a case-sensitive match for the string 'offset',
    Set the offset member of keyframe result to the result of applying the procedure for converting an ECMAScript value into an IDL double [[!WEBIDL]] to the result of calling the [‌[Get]] internal method on keyframe input with property name 'offset'.
    If property is a case-sensitive match for the string 'easing',

    Set the easing member of keyframe result to the result of applying the procedure for converting an ECMAScript value to an IDL DOMString value [[!WEBIDL]] with the [TreatNullAs=EmptyString] annotation in effect, to the result of calling the [‌[Get]] internal method of keyframe input with property name 'easing'.

    If the resulting string does not conform to the grammar defined for the easing attribute of the AnimationTiming interface or is not supported by the implementation, then set the easing of keyframe result to the string “linear”.

    If property is a case-sensitive match for the string 'composite',
    Set the composite member of keyframe result to the result applying the procedure for converting an ECMAScript value to an IDL enumeration type [[!WEBIDL]] with CompositeOperation as the enumeration type, to the result of calling the [‌[Get]] internal method on keyframe input with property name 'composite'.
    Otherwise, if property also exists in supported properties based on a case-sensitive comparison,
    append property to animation properties.
  7. For user agents that support both a prefixed and an unprefixed version of some CSS properties, remove all prefixed properties from animation properties where the corresponding unprefixed version is also present in animation properties.

    I'd like to remove this step. Prefixes are history.

  8. Sort animation properties lexicographically by the Unicode codepoints that define each element.
  9. Iterate over animation properties from beginning to end and for each name in animation properties add a new member pair to keyframe result as follows:
    • member name: the result of applying the the IDL attribute to CSS property algorithm [[!CSSOM]] to name unless name is a case-sensitive match for the string 'cssFloat' in which case use the string 'float'.
    • member value: the result of calling ToString on the value returned from the [‌[Get]] method of keyframe input with property name, name. If [‌[Get]] returns null or undefined, let the member value be an empty string.
  10. Return keyframe result.

The above algorithm gives special meaning to the property names 'offset', 'computedOffset', 'easing', and 'composite'. If a CSS property called 'offset' or 'composite' is ever introduced it will clash with the meaning here.

We have a few options:

  • Add special handling at that time to allow addressing the property of the same name, e.g. cssOffset.
  • Rename these keywords now to reduce risk of a later clash, e.g. 'keyframeOffset'.

The ComputedKeyframe dictionary

Keyframes returned by KeyframeEffect.getFrames are represented using ComputedKeyframe dictionary objects.

double computedOffset
The keyframe offset calculated for this keyframe as a result of applying the spacing procedure defined in .

The MotionPathEffect interface

Motion path animation effects are represented by the MotionPathEffect interface.

Constructor ()

Creates a new MotionPathEffect object with the specified parameters.

(DOMString or SVGPathSegList) path

The motion path which defines the course the animation target follows.

A string may be provided specifying the path using the syntax for SVG path data [[!SVG2]].

If a string is provided, it is converted into an SVGPathSegList using the procedure defined for parsing path data in [[!SVG2]]. Any errors encountered in the path data cause parsing to cease and the path data processed up to that point to be used.

The resulting SVGPathSegList is assigned to the path attribute of the generated object without copying.

optional MotionPathEffectOptions options
A MotionPathEffectOptions dictionary defining other aspects of the animation effect's behavior. If this parameter is not provided, the default values of the dictionary are used.
attribute SVGPathSegList segments
The list of segments that make up the motion path.
attribute AutoRotationMode autoRotate
The automatic rotation flag of the motion path animation effect.
attribute double angle
The rotation angle of the motion path animation effect.
attribute DOMString spacing

The motion path spacing mode to use for this animation effect.

Recognized values are defined by the following grammar:

distribute | paced

The meaning of each value is as follows:

distribute
Use the distribute spacing mode.
paced
Use the paced spacing mode.

All other values are treated as "paced" for the purpose of animation model calculations.

The MotionPathEffectOptions dictionary

Additional parameters may be passed to the MotionPathEffect constructor by providing a MotionPathEffectOptions object.

AutoRotationMode autoRotate = "none"
The automatic rotation flag setting for the generated effect.
double angle = 0
The rotation angle for the generated effect.
IterationCompositeOperation iterationComposite = "replace"
The iteration composite operation used to define the way animation values build from iteration to iteration.
CompositeOperation composite = "replace"
The composite operation used to composite this animation effect with the animation stack, as specified by one of the CompositeOperation enumeration values.
DOMString spacing = "paced"

The spacing mode to apply to this motion path animation effect.

See the description of the spacing attribute of the MotionPathEffect interface for the recognized values and their meaning are described

Unrecognized values are set on the created MotionPathEffect object, but are treated as "paced" for the purpose of animation model calculations.

The AutoRotationMode enumeration

The values of the automatic rotation flag of a motion path animation effect are represented by the AutoRotationMode enumeration.

auto-rotate
Corresponds to setting the automatic rotation flag.
none
Corresponds to clearing the automatic rotation flag.

The EffectCallback callback function

Custom effects can be defined in script by providing an EffectCallback callback function.

An EffectCallback is called each time an Animation with which it is associated is sampled.

double? timeFraction
The time fraction for which to produce an effect. When this is null, the function SHOULD remove the effect.
Animatable currentTarget

The animation target on which this callback is expected to operate.

Note that currentTarget may differ from animation.target.

If the animation target of animation is changed between samples, this method will be called once with a null timeFraction and the previous animation target as the currentTarget, then again with the current timeFraction and the updated animation target as the currentTarget. This allows the animation effect to be removed from the old animation target.

Animation animation
The Animation object that is being sampled.

Extensions to the Document interface

The following extensions are made to the Document interface defined in [[!DOM4]].

readonly attribute AnimationTimeline timeline
The AnimationTimeline object representing the document timeline.

Extensions to the Element interface

Since DOM Elements may be the target of an animation, the Element interface [[!DOM4]] is extended as follows:

This allows the following kind of usage.

            elem.animate({ color: 'red' }, 2000);
          

Extensions to the PseudoElement interface

Since animations may also target pseudo-elements, the PseudoElement interface [[!CSSOM]] is also defined to be animatable.

This interface is marked at-risk in the 5 December 2013 WD of CSSOM. If it is removed, we will need to provide an equivalent definition here.

Script execution and live updates to the model

The interaction between script execution and the state and effects of the Web Animations model is as follows:

Integration with Media Fragments

The Media Fragments specification [[!MEDIA-FRAGMENTS]] 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 that media fragments are defined to operate on resources based on their MIME type. As a result, temporal addressing may not be supported in all situations where Web Animations content is used.

Interaction with page display

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 [[HTML5]].

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?

Implementation requirements

Precision of time values

The internal representation of time values is implementation dependant however, it is RECOMMENDED that user agents be able to represent input time values with microsecond precision so that 0.000001 is distinguishable from 0.0.

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 .

Interface summary

Acknowledgements

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

Changes since last publication

The following changes have been made since the 5 June 2014 Working Draft:

Changes since the 25 June 2013 Working Draft are included in Appendix C of the 5 June 2014 Working Draft.

The changelog provides a more detailed history.