This is the abstract for your specification.

Introduction

Web Animations defines features for supporting animation and synchronization on the Web platform by means of a programming interface. This interface is intended to be used both directly to easily produce animations using script, as well as a foundation for other specifications whose behavior can be defined in terms of these features.

Relationship to other specifications

CSS Transitions [[CSS3-TRANSITIONS]], CSS Animations [[CSS3-ANIMATIONS]], and SVG [[SVG112]] all provide mechanisms that generate animated content on a web page. Although the three specifications provide similar functionality, the syntaxes are incompatible and the animations cannot be interchanged. Furthermore, the interfaces available for interacting with animations from script are largely general-purpose interfaces with few features tuned specifically to the creation and manipulation of animations.

This specification proposes an abstract animations model that encompasses the abilities of both CSS and SVG, and additionally provides a programming interface to expose these features to script.

This specification is accompanied by a CSS embedding specification, which describes how CSS features can be implemented in terms of Web Animations primitives, and an SVG embedding specification, which describes how SVG features can be implemented in terms of Web Animations primitives.

As a result, this specification does not directly alter the behavior of CSS Transitions, CSS Animations, or SVG. However, Web Animations is intended to replace the SMIL Animation [[SMIL-ANIMATION]] specification where it is currently used to define the behavior of SVG's animation features.

This specification makes some additions to some interfaces defined in HTML5 [[HTML5]].

Web Animations overview

At a glance, Web Animations 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.
Animation model
Takes the time fractions 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 Web Animations.
The current time is input to the timing model which produces a time fraction.
This distance is 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.

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 entirely 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 two apparent exceptions to the stateless behavior of the timing model.

Firstly, events are fired when, for example, one sample falls on the opposite side of an animation's interval boundary to the previous sample. This is certainly stative behavior. However, events should be considered as a layer added on top of the core timing model. In the case where no event listeners are registered, the model is stateless.

The other exception to this stateless behavior is that a number of methods such as pause and reverse 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, like events, are layered on top.

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 API, 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. In effect, time begins with real world time (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.

Need diagram here.

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

Despite this notion of inherited time, some features are implemented outside of the time hierarchy. In particular, synchronisation with HTML's media controllers (see ) requires mirroring changes to pause state between items in different branches of the time hierarchy.

The first step in this hierarchy is the animation timeline.

The animation timeline

Each document contains a timeline to which animations may be added. These animations have an interval during which they are scheduled to animate.

At time t animations A and B are animating. Animation C has finished animating. Animation D has yet to begin and is not animating.

The start time of the timeline is defined in .

Animations in the timeline

Animations in the timeline are represented by Animation objects.

The Animation interface

Constructor ()

Creates a new Animation object.

Examples of the usage of this constructor are given in .

Element? elem
The target element. This may be null for animations that do not target a specific element.
object? effect
The animation effect used to set the effect property of the newly created Animation object.

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

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

Otherwise, if this parameter is any other type of object, it will be passed to AnimationEffect.createFromProperties and the resulting AnimationEffect object used as the animation effect.

optional (double or TimingDictionary or Timing)? timing
The timing properties of the new animation.

If this parameter is a double, then it specifies the duration of a single iteration of the animation, that is, the iteration duration, in seconds. In this case, the timing property of the new Animation object is set to a new Timing object constructed from a TimingDictionary object with the duration property set to the double value specified here, and all other properties set to their default values.

Similarly, if this parameter is null, the timing property is set to a new Timing object constructed from a TimingDictionary object with all properties set to their default values.

If this parameter is of type TimingDictionary, then the passed-in dictionary is used to construct a new Timing object which is then assigned to the timing property of the new Animation object.

If this parameter is a Timing object, it is directly assigned to the timing property of the new Animation object. It is not copied. In this way Timing objects can be shared between Animation objects.

Finally, if this parameter is not specified, it is as if a value of null were specified.

optional AnimationGroup? parentGroup
The group to which the newly created animation should be appended as a child. If not specified, the animation will be appended to the document timeline. If null, the animation will not be appended to any group.
optional double startTime
The start time of the newly generated animation expressed in seconds in the iteration time space of the AnimationGroup to which it is (or will be) appended.

If not specified, the current iteration time of the AnimationGroup to which the animation is appended (as determined by the parentGroup parameter) will be used. If parentGroup is null, and the startTime is not specified, a time of zero will be used.

NamedConstructor = LinkedAnimation(Element? elem, AnimationTemplate template, optional double startTime)
TBD
NamedConstructor = ClonedAnimation(Element? elem, Animation cloneSource, AnimationGroup? parentGroup, optional double startTime)
TBD
attribute (AnimationEffect or CustomAnimationEffect)? effect

The animation effect to apply (see ). May be null in which case the animation will produce no noticeable effect other than dispatching events.

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is linked to a template (i.e. template is not null).
attribute AnimationTemplate? template

For linked animations (see ), the AnimationTemplate object from which this object derives its values. For animations that are not linked to a template, this property is null.

Setting this property has the following effect:

  1. Let new template be the value to assign to the template property.
  2. If new template is null,
    1. Call unlink().
  3. Otherwise,
    1. Set timing to new template.timing.clone().
    2. Set effect to new template.effect.clone().
    3. Set template to new template.
readonly attribute Element? targetElement

The element being animated by this object. This may be null for animations that do not target a Element such as an animation that produces a sound using an audio API.

AnimationTemplate templatize()

If this object is not already linked to a template, creates a new AnimationTemplate object based on this object and links this object to it (see ).

What is the more useful behavior? To always create a template? Or to only create one if it doesn't already have one?

The effect is equivalent to the following steps:

  1. Let source be the object on which templatize is called.
  2. If source.template is not null, return.
  3. Create a new AnimationTemplate object, template.
  4. Set template.timing to source.timing.clone().
  5. Set template.effect to source.effect.clone().
  6. Set source.template to template.
  7. Return template.
AnimationTemplate? unlink()

Makes this animation independent of the template with which it is associated if any (see )

After setting template to null the previous value of template is returned.

The effect is equivalent to the following steps:

  1. If template is null, return null.
  2. Let old template be template.
  3. Set timing to template.timing.clone().
  4. Set effect to template.effect.clone().
  5. Set template to null (but do not recursively call this function).
  6. Return old template.

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 100 over three seconds can be achieved as follows:

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

To specify further timing properties such as the playback rate, a TimingDictionary can be used as follows:

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

To share or re-used timing properties with another animation, a Timing object can be directly passed in as follows:

// Share the timing properties of animB with animA
var animA = new Animation(elem, { left: '100px' }, animB.timing);

// Re-use the timing properties of animB in animC without sharing
var animC = new Animation(elem, { left: '100px' }, animB.timing.clone());
          

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

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

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

// Supply a specialized animation effect
var animC = new Animation(elem, new PathAnimationEffect( ... ), 3);

// Supply a custom script-based animation effect
var animC = new Animation(elem,
  { 
    sample: function(time) { 
      if (time !== null) {
        document.documentElement.currentScale = 1.0 + time * 2.0;
      } else {
        document.documentElement.currentScale = 1.0;
      }
    },
    clone: function { return this; }
  }, 3);
          

Fill in the parameters for PathAnimationEffect above once we have decided on them.

Add examples of specifying the parent group and start time once we resolve the behavior of those.

Timing animations

The animation interval

The period that an animation is animating is called the animation interval. Each animation has only one such interval.

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

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

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

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

Animation fill behavior

Outside of the animation interval, an animation may still affect its target depending on its fill mode. The different modes are as follows:

none
The animation does not affect its target outside of the animation interval.
forwards
For times that occur later than the animation interval, the animation will continue to apply to its target the animation value that was used at the end of the animation interval. For times that occur before the animation interval, the animation will not affect its target.
backwards
For times that occur before the animation interval, the animation will apply the same animation value that will be used at the start of the animation interval. For times that occur later than the animation interval, the animation will not affect its target.
both
For times that occur before the animation interval, the backwards fill behavior is used. For times that occur after the animation interval, the forwards fill behavior is used.

Some examples of the these fill modes are illustrated below.

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

At a given time, it is possible to describe an animation as in effect if either (a) the time falls within the animation's animation interval, or (b) the fill mode of the animation causes it to apply a fill mode to its target at the given time.

The normative definition of fill behavior is incorporated in the calculation of the animation time in .

Note that setting a fill mode has no bearing on the endpoints of the animation interval. However, the fill mode does have an effect on the calculation of the animation time and consequently the iteration time since these are defined only when the animation is in effect.

Animation repeat behavior

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

Unlike the animation interval, an animation 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. Comparing the iteration duration and the animation duration we have:

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

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

A comparison of the iteration and animation durations for an animation 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 animation duration.

Time spaces

Times in Web Animations 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.

Within Web Animations, some of the common time spaces are:

Document time space
A time space whose zero time is the start time of the document timeline as defined in .
Item time space
A time space whose zero time is the start of the animation's start time.
Animation time space
A time space whose zero time is the beginning of the animation's animation interval.
Iteration time space
A time space whose zero time is the beginning of the current iteration.

In addition to these time spaces, when animation groups are used (see ) we can talk about the parent iteration time space. The zero time of parent iteration time space is the beginning of the parent animation group's current iteration. When animation groups are not used, this is equivalent to document time space.

Typically, item time space is used for operations confined to a single animation such as seeking and pausing whilst parent iteration time space is used to synchronize animations in a group and hence is the time space used to represent an animation's start and end time. Animation time space is not used directly in the Web Animations interfaces.

Some of these time spaces are illustrated below.

A comparison of item time, animation 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 animation 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 animation time space, the procedure for calculating the animation time defined in will never return a negative value.

Interval timing

For intervals of time, 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 animation, at animation time 1s, the iteration time is 0. For the sequenced animation, in the absence of any fill mode, at parent iteration time 1s, only animation B can affect its target; there is no overlap.

Illustration of end-point exclusive timing. For both repeated and sequenced animations 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.

After one iteration, the first frame of the animation is shown, but after two iterations (and thereonwards), the last frame is shown due to the special behavior defined when an animation fills.

Specifying timing properties

Timing properties are collected under the Timing interface.

If this object is attached to a linked Animation or AnimationGroup (see ) then it is readonly and attempting to set any of its properties will result in a DOMException of type NoModificationAllowedError being thrown. In order to modify the properties of a readonly object, it is necessary to first call the unlink method on the corresponding Animation or AnimationGroup object.

When throwing a DOMException as a result of attempting to set a readonly property, user agents that provide debugging feedback SHOULD also provide feedback indicating the reason that this object is readonly and the remedy described above.

The Timing interface

Constructor ()

Creates a new Timing object using the supplied parameters.

In most cases the members of the params TimingDictionary can be assigned directly to the property in the Timing interface of the same name.

The one exception is the timingFunction member which in a TimingDictionary value can also be set to a DOMString. In this case, the DOMString is first passed to TimingFunction.createFromString and the returned TimingFunction is assigned to the timingFunction property of the new Timing object.

Should we make this fail silently here? Which is better from a forwards compatibility standpoint?

For example:

If any of the values specified on params is invalid such that setting the corresponding Timing property would trigger an exception, the property is set to the default value as specified on the TimingDictionary definition. User agents that provide a debugging feedback SHOULD indicate that an unrecognized or invalid value was encountered.

Exceptions:

DOMException of type IndexSizeError
Raised if any of the values specified on params is out of range.
DOMException of type SyntaxError
Raised if params.timingFunction is set to a string that it not recognized by Timing.createFromString as indicated by a null return value.
TimingDictionary params
The properties to set on the new Timing object. Unspecified members take on the default values specified in the TimingDictionary dictionary definition.
attribute double startDelay

The number of seconds which, when added to the timed item's startTime, defines the lower bound of the timed item's animation interval.

A non-normative description of the effect of this property on timing is given in .

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
attribute unrestricted double? duration

The duration in seconds of a single iteration. This may be null in which case the intrinsic duration will be used. If set, it must be greater than or equal to zero (including positive infinity).

This property corresponds to the iteration duration defined in and described non-normatively in .

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
DOMException of type IndexSizeError
Raised on setting if the value to set is a real number less than zero.
attribute unrestricted double iterationCount

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

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
DOMException of type IndexSizeError
Raised on setting if the value to set is a real number less than zero.
attribute double iterationStart

A finite real number greater than or equal to zero representing the number of iterations into the animation at which to begin. For example, a value of 0.5 would cause the animation to begin half-way through the first iteration.

The iterationCount is effectively added to the iterationStart such that an animation with an iterationStart of ‘0.5’ and iterationCode of ‘2’ would still repeat twice however it would begin and end half-way through the animation'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 accumulateOperation other than ‘replace’.

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
DOMException of type IndexSizeError
Raised on setting if the value to set is a real number less than zero.
attribute double playbackRate

A real number that acts as a multiplier on the item's rate of play. For example, a value of 2.0 will cause the item to run at twice its usual speed. A value of -1.0 will cause the item to play backwards. The playbackRate is applied to the item's animation time and hence has no effect on the start time (see ).

Setting this attribute will affect the item's intrinsic animation duration.

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
attribute PlaybackDirection direction

Direction behavior as specified by one of the PlaybackDirection enumeration values.

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
attribute TimingFunction? timingFunction
An optional timing function used to scale input time to produce timing effects such as easing behavior. See .
attribute FillMode fillMode

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

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is readonly.
Timing clone ()

Creates a new Timing object with each of its properties set to the same value as this object with the exception of the timingFunction property which is set to timingFunction.clone().

The FillMode enumeration

A non-normative description of these modes is given in .

none
No fill.
forwards
Fill forwards.
backwards
Fill backwards.
both
Fill backwards and forwards.

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

To simplify creation of Timing objects a TimingDictionary can be used.

Except where otherwise noted, the acceptable values for each property and their meanings are defined in the Timing interface.

double startDelay = 0

The number of seconds from a timed item's startTime to the start of the animation interval. See startDelay on the Timing interface.

unrestricted double? duration = null

The duration in seconds of a single iteration, that is, the iteration duration. See duration on the Timing interface.

unrestricted double iterationCount = 1.0

The number of times to repeat the item. See iterationCount on the Timing interface.

double iterationStart = 0.0

The number of iterations into the item at which to begin. See iterationStart on the Timing interface.

double playbackRate = 1.0

A multiplier applied to the inherited time potentially causing the item to run at a different rate to its natural speed. See playbackRate on the Timing interface.

PlaybackDirection direction = "normal"

The direction in which animation proceeds, e.g. "reverse". See direction on the Timing interface.

(DOMString or TimingFunction)? timingFunction = null

An optional timing function used to scale the time to produce easing effects and the like.

Unlike the Timing interface, the member here may be set to either a TimingFunction object or a DOMString corresponding to one of the values recognized by Timing.createFromString.

FillMode fillMode = "forwards"

The fill mode of the animation. See fillMode on the Timing interface.

Note that in both CSS Animations [[CSS3-ANIMATIONS]] and SVG [[SVG112]] the default fill mode is "none". Web Animations differs in this regard since it was determined that when generating animations from script forwards filling is the more commonly-desired behavior.

The TimedItem interface

The application of the timing properties specified in a Timing object to an actor in the animation timeline is represented by the TimedItem interface.

attribute Timing timing

The timing parameters for this item.

Exceptions:

DOMException of type NoModificationAllowedError
Raised on setting if this object is linked to a template (see ).
attribute double? currentTime

Returns the effective item time of the timed item.

This differs from the definition of item time used elsewhere in the model in that when the parent iteration time is null (e.g. because parentGroup is null, or because the parent is not in effect) a parent time of zero is used. This allows the item to be seeked prior to being attached to a group.

The value returned is calculated as follows:

currentTime = effective parent time - startTime - timeDrift

Setting this value performs a seek operation according to the steps described in described in .

attribute unrestricted double animationDuration

The length in seconds of the animation interval.

Initially, this attribute will reflect the intrinsic animation duration. Changes to the model that cause the intrinsic animation duration to change are reflected in the value returned here.

The instrinsic animation duration may be overridden by setting this attribute to any real number. Setting this attribute to undefined has the effect of clearing the override value so that the attribute returns to reflecting the intrinsic animation duration.

Exceptions:

DOMException of type IndexSizeError
Raised on setting if the value to set is a real number that is less than zero.
readonly attribute double? iterationTime

The time in seconds representing the offset into the iteration duration using the steps described in . As a result of that definition, this property will be non-null if and only if the animation is in in effect.

This property corresponds to the iteration time described in .

This is not writeable since doing so would basically require doing a reverse conversion from the value to set into to item time space and then updating the currentTime accordingly. However, that's not possible since timing functions may be applied and some of them are not invertible.

readonly attribute unsigned long? currentIteration
The current iteration index beginning with zero for the first iteration as described in .
readonly attribute unrestricted double duration

The iteration duration calculated for this item. If timing.duration is set and greater than or equal to zero, this will match timing.duration. Otherwise, this will reflect the calculated intrinsic duration.

This property corresponds to the iteration duration defined in and described non-normatively in .

attribute double startTime

The time which, when combined with the timing.startDelay, defines the lower bound of the animation interval. It is expressed in seconds in the iteration time space of parentGroup.

When the parent animation group is a sequence group, any previously set value set for startTime is ignored and instead the value of this property is determined by the procedure defined in . Furthermore, attempts to set this property will raise an DOMException of type InvalidStateError. If this item is later made the child of a parallel animation group, any previously set value will be restored.

This property corresponds to the start time described in .

Exceptions:

DOMException of type InvalidStateError
Raised on setting if parentGroup is a sequence animation group (see ).
readonly attribute unrestricted double endTime

The upper bound of the animation interval expressed in seconds relative to the iteration time space of parentGroup.

The endTime is calculated as follows:

If locallyPaused is true,
The endTime is positive infinity.
Otherwise,
The endTime is the result of evaluating startTime + timing.startDelay + animationDuration + timeDrift.

Note that while the endTime is read-only, it can be set indirectly by overriding the animationDuration property. For example, to set endTime to time t in item time space, set animationDuration to t - startTime - timing.startDelay.

readonly attribute AnimationGroup parentGroup
The parent animation group.
readonly attribute double timeDrift

The number of seconds that the actual item time of this item lags behind its scheduled time as a result of pausing and seeking this item.

The timeDrift property is both a stored and a calculated value. When this timed item is paused, the value is calculated from the pause start time. When the timed item is not paused, the value stored for the property is used. The stored value is initially zero, and is updated when the item is unpaused or seeked.

The value returned is as follows:

If locallyPaused is false,
Return the stored value for this property.
If locallyPaused is true,
Return the result of effective parent time - startTime - pause start time.
attribute boolean locallyPaused

The pause state of this timed item. Initially false except for the document timeline where it is initially true (see ).

When setting the following procedure is used:

  1. Let new value be the value to set.
  2. If new value equals locallyPaused, return.
  3. The next step depends on the current value of locallyPaused as follows,
    If locallyPaused is true,
    Record the current value of currentTime as pause start time.
    If locallyPaused is false,
    Set the stored value of timeDrift to the result of evaluating effective parent time - startTime - pause start time.
  4. Set locallyPaused to new value.

Should this be writeable? Once we integrate with media controllers we might want to make this writeable only when not associated with a media controller much like things currently work in HTML5.

readonly attribute boolean paused
Indicates if this element or one of its ancestors is paused. This will be true if an only if the locallyPaused property of this object or one of its ancestor animation groups is true.
void pause ()
Sets the locallyPaused property to true by following the procedure described for setting that property.

This method is intended to behave in a comparable manner to HTMLMediaElement's pause method.

void play ()

Unpauses this item and, if the item is not currently animating, seeks to the beginning of the animation interval by taking the following steps.

  1. If currentTime > timing.startDelay + animationDuration and timing.playbackRate ≥ 0, set currentTime to timing.startDelay.
  2. Set locallyPaused to false.

To unpause the item without seeking, set locallyPaused to false.

This method is intended to behave in a comparable manner to HTMLMediaElement's play method.

void changePlaybackRate (double playbackRate)

Updates the speed of the timed item such that it produces a smooth change.

In particular:

  • the adjusted animation time will not change,
  • if the direction changes, timing.fillMode will be inverted to prevent sudden jumps in output, and
  • if the current item time is outside the animation interval the distance from the interval is scaled according to the change in speed.

The smooth change is achieved using the following steps:

  1. Let previous rate be the value of timing.playbackRate prior to updating it.
  2. Update timing.playbackRate to the passed-in playbackRate parameter.
  3. Let new rate be the updated value of timing.playbackRate.
  4. If either previous rate or new rate are zero, return.

    This isn't great. If you set the playback rate to zero at a given time, you expect it to act as if paused at that time. Currently, the only way to get that behavior out of the model is to set the iterationStart and that seems pretty intrusive.

  5. Invert the fill mode as follows:
    If timing.fillMode is "forwards",
    Set timing.fillMode to "backwards".
    If timing.fillMode is "backwards",
    Set timing.fillMode to "forwards".
    Otherwise,
    Leave timing.fillMode as is.
  6. If item time is null, return.
  7. Update the value of animationDuration if necessary (that is, if animationDuration reflects the intrinsic animation duration), applying the updated value for timing.speed.
  8. Calculate the seek adjustment according to the following formula: seek adjustment = (item time - timing.startDelay) * (1 - previous rate / new rate).
  9. If the sign of new rate and previous rate differs, subtract from the updated value for the animationDuration.
  10. Let seek time be the result of the following formula: item time - seek adjustment.
  11. Set currentTime to seek time.

Exceptions:

DOMException of type NoModificationAllowedError
Raised if this item is a linked item, that is, if template is not null (see ).
void reverse ()

Reverses this animation such that the reverse animation immediately begins reversing from its current point. Note that this means that an animation that has yet to begin, calling reverse will mean that it never starts.

  • Calculate seek time as follows:
  • If currentTime is null,
    Let seek time be zero.
    If currentTime < timing.startDelay,
    Let seek time be timing.startDelay + animationDuration.
    If currentTime > timing.startDelay + animationDuration,
    Let seek time be timing.startDelay.
    Otherwise,
    Let seek time be animationDuration - currentTime - startDelay.
  • Call changePlaybackRate(-timing.playbackRate).
  • Set currentTime to seek time.
  • Exceptions:

    DOMException of type NoModificationAllowedError
    Raised if this item is a linked item, that is, if template is not null (see ).
    void cancel ()

    Removes the timed item from its parent group. As a result, the timed item will no longer affect its target.

    Exceptions:

    DOMException of type NoModificationAllowedError
    Raised if this item is a linked item, that is, if template is not null (see ).

    Is this exception necessary? It will depend how we approach group templates.

    Do we need a means for getting the startTime etc. in document time (i.e. in terms of the root time container)?

    Timing model common definitions

    In order to calculate various properties of the timing model the following common definitions are used.

    Calculating the iteration duration

    The iteration duration is calculated according to the following steps:

    If the timing.duration timing property is set to a numerical value greater than or equal to zero (including positive infinity),
    return timing.duration.
    Otherwise,
    return the item's intrinsic duration.

    The value of an item's intrinsic duration depends on the type of the item.

    For animations the intrinsic duration is zero. The intrinsic duration for animation groups and media items is described under , , and .

    Since the intrinsic duration of an animation is zero, and the default fillMode when constructing an Animation is forwards, it is possible to create animations that simply set a property without any interpolation as follows,

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

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

    new SeqGroup(
      [
        new Animation(elem, { opacity: '0%' }, 1),
        new Animation(elem, { display: 'none' })
      ]
    );
              

    Calculating the intrinsic animation duration

    In order to calculated the intrinsic animation duration we first define the repeated duration as follows:

    repeated duration = iteration duration * timing.iterationCount

    The intrinsic animation duration is calculated according to the following steps:

    1. If timing.playbackRate is zero, return Infinity.
    2. Otherwise, return repeated duration / abs(timing.playbackRate).

    Calculating the item time

    The item time is calculated according to the following equation:

    item time = parentGroup.iterationTime - startTime - timeDrift

    If either parentGroup or parentGroup.iterationTime is null, the item time is null.

    Need to define this for the document timeline.

    Calculating the animation time

    The animation time is based on the item time and start delay. It is defined only when the timed item is in effect and is calculated according to the following steps:

    1. If item time is null, return null.
    2. If item time < timing.startDelay the result depends on the fill mode as follows,
      If the fill mode is backwards or both,
      return zero.
      Otherwise,
      return null.
    3. If item time < timing.startTime + animationDuration, return item time - timing.startDelay.
    4. Otherwise, the result depends on the fill mode as follows,
      If the fill mode is forwards or both,
      return animationDuration.
      Otherwise,
      return null.

    Calculating the iteration time

    The iteration time is calculated by first applying the animation's playbackRate and iterationStart properties to produce the adjusted animation time The adjusted animation time is then divided into intervals resulting in the unscaled iteration time. Following this, timing manipulations specified on the timed item are applied to the unscaled iteration time to produce the iteration time.

    Calculating the adjusted animation time

    Before the animation time can be converted to an iteration time we must factor in the animation's playback rate and iteration start. This is called the adjusted animation time.

    In order to calculate the adjusted animation time we first define the start offset as follows:

    start offset = iterationStart * iteration duration

    The adjusted animation time is calculated according to the following steps:

    1. If the animation time is null, return null.
    2. Return the adjusted animation time based on the timing.playbackRate as follows,
      If timing.playbackRate is negative,
      Return (animation time - animationDuration) * timing.playbackRate + start offset.
      Otherwise,
      Return animation time * timing.playbackRate + start offset.

    Calculating the unscaled iteration time

    The unscaled iteration time is calculated according to the following steps:

    1. If the item time is null, return null.
    2. If the iteration duration is zero, return zero.
    3. If adjusted animation time - start offset is equal to the repeated duration, timing.iterationCount is not zero, and (timing.iterationCount + timing.iterationStart) % 1 is zero, return the iteration duration.
    4. Otherwise, return adjusted animation time % iteration duration.

    Applying time manipulations

    The unscaled iteration time is converted into the iteration time using the following steps:

    1. If the unscaled iteration time is null, return null.
    2. Scale the time as follows:
      If timing.timingFunction is a TimingFunction object,

      Let scaled iteration time be unscaled iteration time * timing.timingFunction.scaleTime(unscaled iteration time / iteration duration))).

      Otherwise,
      Let scaled iteration time be unscaled iteration time.
    3. Calculate the current direction using the first matching condition from the following list:
      If the direction is normal,
      Let the current direction be forwards.
      If the direction is reverse,
      Let the current direction be reverse.
      Otherwise,
      1. Let d be the current iteration.
      2. If the direction is alternate-reverse increment d by 1.
      3. If the animation is not animating, and the animationDuration is a positive multiple of the iteration duration increment d by 1.
      4. If d % 2 == 0, let the current direction be forwards, otherwise let the current direction be reverse.
    4. If the current direction is forwards then return the scaled iteration time.

      Otherwise, return the iteration duration - scaled iteration time.

    Applying the reverse behavior after applying the timing function means that ease-in becomes ease-out on reverse, however it avoids jumps in values when reversing part-way.

    Calculating the time fraction

    The time fraction is calculated according to the following steps:

    If the iteration duration is zero,

    the time fraction is as follows.

    If item time < timing.startDelay,
    Return the result of recalculating the iteration time using an item time of zero and an iteration duration of 1.
    Otherwise,
    Return the result of recalculating the iteration time using an item time of timing.iterationCount and an iteration duration of 1.
    Otherwise,
    Return iteration time / iteration duration.

    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.

    Calculating the current iteration

    The current iteration can be calculated from the following steps:

    1. If the item time is null, return null.
    2. If the adjusted animation time is zero, return zero.
    3. If the iteration duration is zero, return floor(timing.iterationStart + timing.iterationCount).
    4. If the unscaled iteration time equals the iteration duration, return timing.iterationStart + timing.iterationCount - 1.
    5. Return floor(adjusted animation time / iteration duration).

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

    Pausing a timed item

    Timed items may be paused and resumed independently of the parent animation group they belong to. The effect is that the time of the item lags behind that of its parent. This lag is called the time drift and acts as an additional delay added to the start time of the item.

    Timed elements that do not have a parent animation group may still be paused and resumed. However, except for the case of the document timeline, there will be no observable effect until the element is attached to a parent animation group.

    Pausing and seeking are realised using two additional inputs to the timing model, the time drift which is exposed as the timeDrift property on the TimedItem interface, and the pause start time which is internal to the model. Both the time drift and pause start time are initially zero.

    The pausing behavior is realised through the specific steps defined for calculating and updating the locallyPaused and timeDrift properties of the TimedItem interface.

    Seeking a timed item

    Seeking, like pausing, has the effect of causing a timed item's time to drift from that of its parent animation group. Consequently, it is also uses the time drift and pause start time concepts on which pausing is based.

    Seeking is performed in response to a change to a timed item's currentTime property and is realised by adjusting the timeDrift property or the internal pause start time of the item as follows:

    1. Let seek time be the new value to which currentTime should be set.
    2. The steps for adjusting the item time depend on the state of the locallyPaused property as follows:
      If locallyPaused is true,
      Set pause start time to seek time.
      If locallyPaused is false,
      Set the stored value for timeDrift to the result of evaluating effective parent time - startTime - seek time.

    Note that the currentTime property is not actually set directly but is updated to the seek time as a result of the calculation outlined in the decsription of the currentTime property on the TimedItem interface.

    The animation events dispatched when a seek is performed are described in .

    Scaling the time

    It is often desirable to control the rate at which an animation 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 to progress in a series of distinct steps.

    For such situations Web Animations provides a variety of timing functions that scale the progress of an animation. In situations where the timing functions defined here are insufficient, it is possible to provide a custom script-based timing function.

    In all cases, timing functions take an input time and produce a scaled output time.

    Diagram

    Such timing functions can be applied to an iteration of an animation as a whole via the TimedItem interface or to a segment of a keyframe animation via the KeyframeAnimationEffect interface.

    The TimingFunction interface

    The timing functions provided by Web Animations share a common TimingFunction interface as defined below.

    double scaleTime()

    Takes an input time fraction in the range [0, 1] and applies some transformation on the value to produce an output time fraction (typically, but not necessarily, also in the range [0, 1]).

    double time
    The input time fraction.
    TimedItem? item

    The TimedItem for which the time scaling operation is being performed.

    Some timing functions, for example, may produce different results depending on the animation values involved to produce an even rate of change.

    This may be null, for example, when invoked directly by user code for the purpose of testing or re-using the scaling operation in another context.

    Implementations of this interface for which there is no meaningful result in the absence of a TimedItem will simply return time unchanged when item is null.

    TimingFunction clone()

    For implementations of this interface that have local state, produces an identical but independent copy of this object. For implementations without local state, returns the same object.

    static TimingFunction? createFromString(DOMString spec)

    Creates a new TimingFunction object based on a string-based specification (e.g. "ease-in").

    The acceptable values and their meanings are those defined for the transition-timing-function property in CSS Transitions [[!CSS3-TRANSITIONS]].

    In addition to the values defined in CSS Transitions, this method extends the steps() function notation to allow ‘middle’ as a transition point keyword (e.g. steps(3, middle)) corresponding to the ‘middle’ StepPosition value. Similarly, the keyword ‘steps-middle’ is recognized by and given the meaning steps(1, middle).

    Strings that specify a cubic-bezier timing function result in a new SplineTimingFunction being returned. Strings that specify a stepping function produce a new StepTimingFunction.

    If spec is unrecognized, null is returned. User agents that provide debugging feedback SHOULD report the unrecognized value.

    So the string cubic-bezier(...) produces a SplineTimingFunction. That's a bit confusing. But CubicBezierTimingFunction is a lot to type and not very user-friendly.

    Should we make the ‘linear’ keyword return null as well? If we do, we need to be careful to update the constructor for Timing so that it doesn't throw an exception in that case (or report anything to the console).

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

    The curves produced by the keywords accepted by the Timing.createFromString method are illustrated below.

    The timing functions produced by each of the keyword values.

    The SplineTimingFunction interface

    Cubic bézier curve based timing functions are represented using the SplineTimingFunction interface defined below.

    Constructor (sequence<double> points)

    Creates a new SplineTimingFunction object and initializes the points member to the passed in list of points.

    It would be more convenient for authors if the passed in list of points could be longer than four items and we simply read the first four items and ignored the rest. However, applications may begin to depend on that behavior and we could not easily allow this object to take longer lists (to represent more complex curves) in the future without adding a separate constructor for that purpose.

    Exceptions:

    DOMException of type IndexSizeError
    Raised if any of the x values in points is outside the range [0, 1] or if the length of points is not 4 items.
    attribute sequence<double> points

    A sequence of four real numbers representing the coordinates of the two control points in the following sequence <p1-x> <p1-y> <p2-x> <p2-y>.

    Each of the x values (i.e. p1-x and p2-x) must be in the range [0, 1].

    Exceptions:

    DOMException of type IndexSizeError
    Raised on setting if an x value is outside the range [0, 1].
    DOMException of type InvalidModificationError
    Raised on attempting to alter the length of points.
    double scaleTime(double time, TimedItem? item)
    Applies the timing function produced by the cubic Bézier curve with points (0,0), (points[0], points[1]), (points[2], points[3]), (1, 1). Returns the resulting y value when the x value is max(0, min(1, time)).
    TimingFunction clone()
    Returns a copy of this object.

    Timing in discrete steps

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

    A stepping function 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 Animation's model for 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).

    Some example step timing functions are illustrated below.

    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.

    The StepPosition enumeration

    The point within a step interval at which the change in value occurs is specified using one of the StepPosition enumeration values.

    start
    The change in value occurs at the beginning of the interval.
    middle
    The change in value occurs at the midpoint of the interval.
    end
    The change in value occurs at the end of the interval.

    The StepTimingFunction interface

    Step timing functions are represented by the StepTimingFunction interface.

    Constructor (unsigned integer numSteps, optional StepPosition position = 'end')

    Creates a new StepTimingFunction with the specified number of steps and transition point.

    Exceptions:

    DOMException of type IndexSizeError
    Raised if numSteps is zero.
    attribute unsigned integer numSteps

    A number greater than or equal to one representing the number of steps in the function.

    Exceptions:

    DOMException of type IndexSizeError
    Raised on setting if the number of steps is zero.
    attribute StepPosition position
    The point within each interval at which the change in value occurs.
    double scaleTime(double time, TimedItem? item)
    Returns the value of applying the step function defined by numSteps and position with input time. The behavior of the step function is described in .
    TimingFunction clone()
    Returns a copy of this object.

    The SmoothTimingFunction interface

    Need help from someone who knows math. We'd like to be able to have a function with many extrema. Ideally, something like Catmull-Rom curves would be great where you could just say:

    [ 0: 0, 0.7: 1, 0.8: 0.9, 1: 1 ]

    And you'd get a smooth curve that goes to the full value and bounces back a bit then finishes.

    The trouble is that Catmull-Rom curves won't necessarily give you a function even if you sort the x values.

    attribute sequence<double> points
    TBD

    Grouping and synchronization

    While it is possible to set the timing properties of animations individually, it is often useful to bundle animations together and control their timing as a group.

    This can be used to share common timing properties as illustrated below:

    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.

    As well as sharing timing information, by grouping animations together they can be seeked, paused, and stopped as a unit.

    Relationship of group time to child time

    The timing of the children of a group is based on the timing of the group. Specifically, times for the children are based on the parent's iteration time. That is, the children animate inside an iteration of the parent.

    As an example, consider repetition. If a 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.

    Since children of an animation group base their timing on the group's iteration time, when the group repeats, the children play again.

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

    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 a group basing their timing on the group's iteration time is that they cannot animate outside of the group's animation interval. This is because the iteration time of a group will not change outside its animation interval. This allows groups to clip the playback of their children.

    In the first instance, an animation has a negative delay and an infinite iteration count.
    However, when a similar animation is placed inside a group with a specified duration it has the effect of clipping the animation's duration.

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

    Types of groups

    Groups can be used to provide synchronization behavior for its children. For example, one type of group runs its children in parallel, whilst another type runs the children in sequence.

    Compare the two arrangements illustrated below:

    Two types of animation groups.
    (a) is a parallel group where all the children run simultaneously.
    (b) is a sequence group where the children run in turn.

    Groups can also contain other groups which allows for more sophisticated synchronization.

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

    Web Animations defines two types of animation groups.

    Parallel groups
    Children of the group play simultaneously. The start time of children is taken as relative to the start of the current iteration of the group, that is, it is in the group's iteration time space.
    Sequence groups
    Children of the group play in turn beginning with the first child and proceeding to the last. Any start time specified on children is ignored and replaced with the time calculated using the procedure in .

    The document timeline

    Move all this to its own section later on.

    We have previously referred to the document timeline as the context in which animation takes places. Likewise we have referred to the document time space as the master time space which contains other time spaces. The document timeline is, in fact, a parallel animation group with the following special properties:

    Move/copy exception behavior to the relevant properties / methods.

    Initial state of the document timeline

    Unlike other timed items, the document timeline is initially paused. The moment at which the timeline becomes unpaused is defined in .

    On creating an AnimationGroupInstance corresponding to the document timeline, the following steps are performed.

    1. Set the start time to the current parent iteration time (i.e. the number of seconds since 00:00:00 UTC on 1 January 1970).
    2. Set the pause state to true.

    By setting the start time to the parent iteration time and then pausing the timeline, the start time is always well-defined. Furthermore, seeking the timeline before it is unpaused provides intuitive results without special casing the algorithm for seeking (see ).

    Start of the timeline

    The time at which the timeline will be automatically unpaused is determined by the timelineStart property on the Document object (see ). It can have the following values:

    onload

    The moment immediately prior to dispatching the "load" event for the document.

    For HTML documents, this is the moment after the current document readiness has changed to "complete" but before dispatching the load event. In terms of the timings defined in NAVIGATION-TIMING (Need to add NAVIGATION-TIMING to the biblio), this occurs between the domComplete and loadEventStart timings.

    This is the default value.

    onstart

    The moment after the user agent stops parsing but before running scripts that are designated to execute when parsing finishes.

    For HTML documents, this occurs after updating the current document readiness to "interactive" (see the specified behavior for the end of parsing), that is, after the domInteractive timing.

    manual
    A moment infinitely distant in the future. That is, animation will not begin until unpause is called on the timeline.

    For the onload and onstart values, it is not sufficient to simply the record the appropriate time and seek the animations accordingly at a later moment. Rather, the timeline must be actually unpaused at the appropriate moment such that scripts that execute during page loading (for example, in response to the load event) can make assumptions about the pause state of the timeline.

    Any call to pause or unpause on the timeline disables the automatic unpause behavior defined by the timelineStart property on the document. It is as if the timelineStart property were set to manual.

    The ability for script to override the timelineStart property by calling pause to indefinitely postpone the start of animation is necessary for backwards compatibility with SVG.

    This override behavior applies even if the timeline has already been unpaused since changing the timelineStart property could return the timeline to a state where the automatic unpause behavior would otherwise apply.

    Changing the timeline start

    The timelineStart property may be changed at any time. The result of changing this property is as follows:

    1. If pause or unpause has been called on the timeline, return immediately.
    2. Let autostart be the moment at which the timeline would be unpaused corresponding to the new value of timelineStart as defined in .
    3. Let now be the parent iteration time.
    4. If autostartnow, set the pause state to false.
    5. If autostart > now, set the start pause state to true.
    6. If the pause state is newly true seek the timeline to autostart - now.
    7. If the pause state is newly false seek the timeline to 0.

    Extensions to the Document interface

    To provide access to the document timeline the following extensions to the Document interface are required.

    readonly attribute ParGroup animationTimeline
    The animation group corresponding to the root of the document. This group exhibits the special behavior described for the root animation group in .
    attribute AnimStartType timelineStart
    Sets the time at which the animation timeline will begin animating unless it is overridden by script as defined in . Changes to this property are defined in . Initialized to "onload".

    Timeline of document resources

    Documents may include external animated resources, for example, via the <object> or <use> elements. These external resources will often have their own Document object and their own timeline. In order to synchronize these timelines the same approaches can be applied as with described under .

    The AnimationGroup interface

    Represents a list of timed items.

    The AnimationGroup interface supports indexed properties with indices in the range 0 ≤ index < group.size.

    readonly attribute unsigned long length
    The number of timed items in the group.
    readonly attribute AnimationGroupTemplate? template

    For linked animation groups (see ), the AnimationGroupTemplate object from which this object derives its values. For animations that are not linked to a template, this property is null.

    Make this writeable?

    void clear ()

    Removes all child timed items from the group.

    Exceptions:

    DOMException of type NoModificationAllowedError
    Raised if this group is a linked group, that is, if template is not null (see ).
    getter TimedItem? (unsigned long index)

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

    setter TimedItem (unsigned long index, TimedItem newItem)

    Replaces the item at index with newItem by calling splice(index, 1, newItem).

    No attempt is made to check if the item at index is already newItem. In such a case, newItem will be removed from this group and re-added as per the usual operation of slice.

    Returns newItem.

    Exceptions:

    DOMException of type HierarchyRequestError
    Raised if newItem is the timeline for a document (see ).
    DOMException of type IndexSizeError
    Raised if index is outside of the range 0 ≤ index < group.length.
    DOMException of type NoModificationAllowedError
    Raised if this group is a linked group, that is, if template is not null (see ).

    Whilst splice allows negative indices, WebIDL requires index property setters to take an index of type unsigned long and hence index is restricted to the range 0 ≤ index < group.length.

    sequence<TimedItem> add (TimedItem newItem, TimedItem... otherItems)

    Add newItem and each otherItems as the last item(s) in the group by calling splice(group.length, 0, newItem, otherItem1, ... otherItemN).

    Returns a sequence containing the added items: [newItem, otherItem1, ... otherItemN].

    Exceptions:

    DOMException of type HierarchyRequestError
    Raised if any of the items to add is the timeline for a document (see ). If this exception is thrown none of the newItem objects will be added to the group.
    DOMException of type NoModificationAllowedError
    Raised if this group is a linked group, that is, if template is not null (see ).
    sequence<TimedItem> remove ( long index, optional unsigned long count = 1)

    Removes the item(s) at index by calling splice(index, count).

    Returns the removed items.

    Exceptions:

    DOMException of type NoModificationAllowedError
    Raised if this group is a linked group, that is, if template is not null (see ).
    sequence<TimedItem> splice ()

    Modifies the list of children of this group by first removing deleteCount items from start followed by adding newItems at the same point.

    The operation of slice is based on ECMAScript 5's Array.prototype.splice.

    Returns a sequence of the items removed from group during the removal step (regardless of whether these items were re-added during the addition step).

    long start
    The index at which items should be removed and inserted. Negative indices represent an offset from the end of the list of items. This value is clamped to the range [-length, length].
    unsigned long deleteCount
    The number of items to remove from the group beginning at start. Negative values are clamped to zero, and all other values are clamped such that 0 < start + deleteCount ≤ length.
    sequence<TimedItem> newItems
    The items to be added at start. Each item, if it already has a parent group (including this group), is first removed from its parent group before being added to this group.

    Exceptions:

    DOMException of type HierarchyRequestError
    Raised if any of the items in newItem is the timeline for a document (see ).
    DOMException of type NoModificationAllowedError
    Raised if this group is a linked group, that is, if template is not null (see ).
    sequence<TimedItem> splice (long start, unsigned long deleteCount, TimedItem... newItem)
    An overload of splice to take a variadic list of items rather than requiring a sequence. The operation is identical to splice(unsigned long start, unsigned long deleteCount, sequence<TimedItem> newItems).
    long indexOf (TimedItem item)
    Returns the index of item within the group. If item is not in the group, returns -1.
    AnimationGroupTemplate? unlink()

    Makes this group independent of the template with which it is associated if any. See . Does this recurse through children and unlink them too?

    After this method returns, the template property will be null.

    Returns the previous value of template.

    sequence<Animation> getActiveAnimations ()
    Returns all descendent Animation objects that are in effect. The returned sequence is a snapshot (i.e. not live) representing the state of animations that corresponds to the time returned by the iterationTime property of this AnimationGroup object when this method was called.
    sequence<Animation> getAnimationsForElement (Element elem)
    Returns all descendent Animation objects whose targetElement is elem. As with getActiveAnimations, the returned sequence is a snapshot (i.e. not live) representing the state of animation when this method was called.

    Parallel animation groups

    Parallel animation group run their children such they potentially play simultaneously. The start time of each child depends on its own startTime property.

    The intrinsic duration of a parallel animation group

    The intrinsic duration of a parallel animation group is the maximum of the endTime properties of each child TimedItem.

    If the group has no children then the intrinsic duration is zero.

    The ParGroup interface

    Parallel animation groups are represented by ParGroup objects.

    Constructor ()
    sequence<TimedItem>? children

    A sequence of timed items to add as children of this group.

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

    optional (double or TimingDictionary or Timing)? timing

    The timing properties of the new animation group.

    If this parameter is a double, then it specifies the duration of a single iteration of the animation group, that is, the iteration duration, in seconds. In this case, the timing property of the new ParGroup object is set to a new Timing object constructed from a TimingDictionary object with the duration property set to the double value specified here, and all other properties set to their default values.

    Similarly, if this parameter is null, the timing property is set to a new Timing object constructed from a TimingDictionary object with all properties set to their default values.

    If this parameter is of type TimingDictionary, then the passed-in dictionary is used to construct a new Timing object which is then assigned to the timing property of the new ParGroup object.

    If this parameter is a Timing object, it is directly assigned to the timing property of the new ParGroup object. It is not copied. In this way Timing objects can be shared between TimedItem objects.

    Finally, if this parameter is not specified, it is as if a value of null were specified.

    optional AnimationGroup? parentGroup
    The group to which the newly created animation group should be appended as a child. If not specified, the animation will be appended to the document timeline. If null, the animation group will not be appended to any group.
    optional double startTime

    The start time of the newly generated animation group expressed in seconds in the iteration time space of the AnimationGroup to which it is (or will be) appended.

    If not specified, the current iteration time of the AnimationGroup to which the animation is appended (as determined by the parentGroup parameter) will be used. If parentGroup is null, and the startTime is not specified, a time of zero will be used.

    Sequence animation groups

    Sequence animation groups run their children in turn following their order in the group. This ordering is achieved by adjusting the start time of each child in the group.

    Since the start delay is added to the start time, it can be used to adjust the timing of the animation interval relative to calculated start time as shown in the following diagram.

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

    The start time of children of a sequence animation group

    The start time for the children of a sequence animation group is calculated according to the following procedure:

    1. Let the accumulated start time be zero.
    2. Iterate over each child in the group beginning with the first item in the group and proceeding to the last. For each child perform the following steps:
      1. Let child be the current child.
      2. Let child.startTime be accumulated start time.
      3. Let accumulated start time be child.endTime.

    When animationDuration is positive infinity the behavior is defined by IEEE 754-2008. As a result, if any of the children of a sequence animation group has an infinite animation duration, any children that occur later in the sequence will not play.

    The intrinsic duration of a sequence animation group

    The instrinsic duration of a sequence animation group is equivalent to the start time of a hypothetical child appended to the group's children using the procedure described in .

    The SeqGroup interface

    Sequence animation groups are represented by SeqGroup objects.

    Constructor (sequence<TimedItem>? children, optional (double or TimingDictionary or Timing)? timing, optional AnimationGroup? parentGroup, optional double startTime)
    The meaning and handling of each of the parameters in this constructor is identical to the constructor for ParGroup.

    Animation values

    The Web Animations animation model takes the time fractions produced by the timing model for a given Animation and applies it as the input to the animation effect defined for the Animation object. The output of each animation effect is then combined using a global animation stack before being applied to the target property (see ).

    The entry-point to the animation model is the AnimationEffect or CustomAnimationEffect object associated with each Animation. These objects describe how animation values should be calculated for the Animation for any given time. AnimationEffect serves as an abstract interface of which several concrete subclasses are provided.

    The AnimationEffect interface

    attribute CompositeOperation operation

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

    This value defaults to "replace"

    attribute CompositeOperation accumulateOperation

    The operation used to composite each iteration of this animation with the result of compositing the previous animation, as specified by one of the CompositeOperation constants defined in this interface.

    This value defaults to "replace".

    any sample (double? timeFraction, double currentIteration, Element? target, any underlyingValue)

    Define this here?
    Potentially this should be an interface that script could provide its own object for.

    Implementations of the function would be expected to produce the same result given the same parameters so the implementation could cache the result and not call the function when the parameters were the same.

    timeFraction would be a number typically in the range [0.0, 1.0]. null values indicate the function should no longer affect the target.

    Pass in isSeeking as a flag? Tempting to pass in aPreviousTimeFraction but I think functions that need that can track it themselves? Although that requires a new instance of the function for each target.

    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.

    static AnimationEffect? createFromProperties ()

    Creates an AnimationEffect representing the passed-in collection of properties.

    Note that this method requires handling the passed in parameter in a manner not yet supported by Web IDL and hence this method is ECMAScript-specific.

    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 following procedure has the following properties:

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

    The interpretation of the passed-in properties object can be described in three parts.

    Part 1 – Determine the set of animation properties

    1. Create a list, supported properties, of property names and attribute names that can be animated by the implementation.
    2. Let animation properties be an empty sequence.
    3. Iterate through the properties of properties. For each property in properties, if property also exists in supported properties based on a case-sensitive comparison, append property to animation properties.

      Whilst the iteration order for properties of an ECMAScript object is implementation-dependent, the order here is not significant to the outcome as animation properties will be sorted before being iterated over.

      How do we handle operation and compositeOperation? We'd like to be able to list them in the same property bag but that would mean we could never animate properties of the same name.

    Part 2 – Create the AnimationEffect objects

    The AnimationEffect object produced depends on the length of animation properties as follows:

    If animation properties is of zero length,
    return null.

    This behaviour of returning null allows alternative animation effects to be provided based on the capabilities of the user agent as follows:

    elem.animate(
      AnimationEffect.createFromProperties({ transform: 'translate(-100px)' }) ||
      AnimationEffect.createFromProperties({ top: '-100px' }),
      3);
                      
    If animation properties has only one element,
    1. Let name be the value of the element in animation properties.
    2. Let value be the value of properties.name.
    3. Return a new KeyframeAnimationEffect object according to the steps in part 3 below based on name and value.
    Otherwise,
    1. Let group be a newly constructed GroupedAnimationEffect.
    2. Sort animation properties lexicographically by the Unicode codepoints that define each property name.
    3. 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.
    4. Iterate through animation properties. For each name in animation properties:
      1. Let value be the value of properties.name.
      2. Create a new KeyframeAnimationEffect, effect object according to the steps in part 3 below based on name and value.
      3. Append effect to group.
    5. Return group.

    Part 3 – Create each KeyframeAnimationEffect object

    Based on a given name and value, a new KeyframeAnimationEffect is created as follows:

    If value is not of type (DOMString or sequence<(KeyframeDictionary or DOMString)>),
    Throw a TypeError as defined by [[!ECMA-262]].
    Otherwise,
    Construct a new KeyframeAnimationEffect by calling KeyframeAnimationEffect(name, value).
    object properties
    An object whose object properties represent the CSS properties or element attributes to be animated. The values corresponding to these properties are the animation values to be applied as described above.

    The CompositeOperation enumeration

    replace
    The animation should replace the value it is composited with.
    accumulate
    The animation should add to the value it is composited with. The meaning of addition is dependent on the type of animation.
    merge
    The animation should merge with the value it is composited with. The meaning of merge is dependent on the type of animation. The duration of the merge is the calculated animation duration of the AnimationTemplate containing this AnimationEffect.

    The KeyframeAnimationEffect interface

    Constructor (DOMString property, (DOMString or sequence<(KeyframeDictionary or DOMString)>) frames, optional CompositeOperation operation = "replace", optional CompositeOperation compositeOperation = "replace")

    Creates a new KeyframeAnimationEffect object for the specified property from the given list of keyframes.

    The list of keyframes may be a sequence of KeyframeDictionary dictionaries, a sequence of DOMStrings, a combination of both, or a single DOMString.

    DOMStrings are used to create keyframes with an offset of 1. When the list of keyframes is a sequence consisting entirely of DOMStrings the offsets of the newly created Keyframes are distributed evenly from 0 to 1.

    The property, operation and compositeOperation arguments are assigned to the attributes of the same names.

    The frames argument is processed as follows:

    1. Let effect be the KeyframeAnimationEffect currently under construction.
    2. The processing of frames depends on its type as follows:

      If frames is a DOMString,
      1. Let frame be a new Keyframe constructed from a KeyframeDictionary whose value member is set to frames and whose other members are set to their default values.
      2. Call effect.frames.add(frame).
      If frames is a sequence of (DOMString or KeyframeDictionary),
      1. Set a flag all strings to true.
      2. For each item in frames:
        1. If item is a DOMString,
          Let frame be a new Keyframe constructed from a KeyframeDictionary whose value member is set to item and whose other members are set to their default values.
          Otherwise (item is a KeyframeDictionary),
          1. Let frame be a new Keyframe constructed by calling Keyframe(item).
          2. Set all strings to false.
        2. Call effect.frames.add(frame).
      3. If flag all strings is true call effect.frames.distribute().
    attribute DOMString property
    The name of the target property or attribute.
    readonly attribute KeyframeList frames
    The series of values that make up this effect sorted by their offset within the iteration duration of the animation.

    The KeyframeList interface

    The KeyframeList object is a collection of Keyframe objects sorted by the offset of each Keyframe.

    readonly attribute unsigned long length
    The number of frames in the list.
    void clear ()
    Removes all frames from this list.
    getter Keyframe? (unsigned long index)
    Returns the frame at index if it exists or null otherwise.
    Keyframe add((Keyframe or KeyframeDictionary) frame)

    Adds frame to the list such that the list remains sorted by the offset of the frames.

    If frame is of type KeyframeDictionary then a Keyframe object is first constructed by calling Keyframe(frame) before adding the newly constructed Keyframe to the list.

    If there already exists a frame in this list with offset frame.offset, the newly added frame will appear in the list after the already existing frames in the list with the same offset.

    If frame is already part of another KeyframeList it is first removed from that list before being added to this list.

    Exceptions:

    DOMException of type IndexSizeError
    Raised if frame is a KeyframeDictionary whose offset is outside the range [0,1] or missing.
    Keyframe? remove(unsigned long index)
    Removes the frame at position index and returns it. If index is outside the range [0, length), then null is returned.
    long indexOf(Keyframe frame)
    Returns the index of frame within the list. If frame is not a member of the list, returns -1.
    KeyframeList distribute()

    Adjusts the offsets of the frames in the list such that the offsets are spaced equidistantly whilst maintaining their current order and such that the first frame (when there are multiple frames) has offset 0 and the last frame (if any) has offset 1.

    For frame at position i in the list where 0 ≤ i < length, an offset will be assigned equal to i / (length - 1) unless length is 1 in which case it will be given offset 1.

    After applying the changes, this list is returned.

    The Keyframe interface

    A Keyframe represents a moment within an animation that has a specified value to be applied to the target property or attribute. In between such moments values may be interpolated or filled based on the TimingFunction specified on the TimedItem where the Keyframe is used, or on the previous Keyframe.

    Currently a Keyframe can only target a single property which is defined on the KeyframeAnimationEffect. This is different to CSS. Is this something we want to change? It would complicate the API, of course, but is it worth it?

    Constructor (KeyframeDictionary dictionary)

    Creates a new Keyframe object using the parameters specified in dictionary.

    dictionary.offset is clamped to the range [0, 1] before setting.

    attribute DOMString value
    The value to assign to the target attribute or property at the given offset.
    attribute double offset

    A value between 0 and 1 inclusive representing the offset within the iteration duration of the animation where this value should appear.

    If this keyframe belongs to a KeyframeList, changes to this value cause the KeyframeList to be immediately re-sorted using a stable sort such that all children are ordered by their offset but children with identical offsets retain their relative position in the list.

    Exceptions:

    DOMException of type IndexSizeError
    Raised on setting a value outside the range [0,1].
    attribute TimingFunction? timingFunction

    The timing function to apply between this keyframe and the next keyframe in any KeyframeList in which this object appears.

    May be null in which case linear interpolation will be used.

    The KeyframeDictionary dictionary

    To simplify creation of Keyframe objects a KeyframeDictionary can be used.

    The members of the dictionary correspond to attributes in the Keyframe interface which provides a more complete description of their meaning and usage.

    DOMString value = ""
    The value to assign to the target attribute or property at the given offset.
    double offset = 1
    A value between 0 and 1 (inclusive) representing the offset within the iteration duration of the animation where this value should appear.
    TimingFunction? timingFunction = null
    The timing function to apply between this keyframe and the next keyframe in any KeyframeList in which this object appears.

    The PathAnimationEffect interface

    attribute SVGPathSegList segments
    The list of segments that make up this path.
    attribute boolean rotate
    True if objects animating along this path should be rotated such that their positive x axis is aligned with the direction of movement along the path.

    The GroupedAnimationEffect interface

    The GroupedAnimationEffect interface represents a set of animation effects that share the same AnimationTemplate parent.

    If the group contains multiple effects that target the same property does order in the group matter? If so, we need to add a means for re-ordering the group other than popping and pushing. For example, insertBefore.

    Constructor (object properties)

    TBD whilst we decide whether we need this interface or whether we can merge it with KeyframeAnimationEffect somehow.

    readonly attribute unsigned long length
    The number of animation effects in the group.
    void clear()
    Removes all effects from this group.
    getter AnimationEffect? (unsigned long index)
    Returns the effect at index if it exists, or null otherwise.
    AnimationEffect add(AnimationEffect effect)

    Appends effect to the end of the group such that group.indexOf(effect) equals group.length - 1.

    I'm assuming that AnimationEffects can be shared amongst animations and groups. Or does effect need to be removed from any previous AnimationEffects or Animations first?

    AnimationEffect? remove(unsigned long index)
    Removes the effect at index and returns it. If index is outside the range [0, length), then null is returned.
    long indexOf(AnimationEffect effect)
    Returns the index of effect within the group. If effect is not a member of the group, returns -1.

    Calculating animation values

    This section needs more detail on when sampling is done. It also needs to be specified that an Animation with a null AnimationEffect still fires events.

    Calculating the animation value from an iteration value

    If the current iteration is zero, or the accumulateOperation is "replace", then the animation value is simply the iteration value, as defined below.

    When the animation time equals the iteration duration for the first time for an animation, the current animation value should be retained as the end value for the animation.

    Need to revise this definition since we can't assume the time at the end of the first iteration will be visited (we might be playing backwards, or have a iteration start greater than 1).

    If the current iteration is not zero and the accumulateOperation is "accumulate" then the animation value is the end value accumulated current iteration times, with the iteration value accumulated on top.

    If the current iteration is not zero and the accumulateOperation is "merge" then the animation balue is the end value merged with the iteration value, with an interpolation parameter equal to the current time fraction

    Need to review the following algorithms to check they still make sense now that the iteration fraction is not necessarily in the range [0, 1].

    Calculating the iteration value for a KeyframeAnimationEffect

    When an AnimationTemplate contains a pointer to a KeyframeAnimationEffect keyframes, the animation value for that animation at given current time t is calculated according to the following steps:

    1. Convert t to the time fraction (see ).
    2. Generate a sorted frame list by sorting the list of Keyframe objects contained within the KeyframeList object stored in keyframes.frames by their offset. If there are no frames in the sorted frame list then no animation occurs and the iteration value is just the base value of the property being animated.
    3. Otherwise, find the after frame by iterating through the sorted frame list until the last Keyframe with an offset larger than the time fraction is encountered.
    4. If the after frame is the first frame in the sorted frame list, then construct a before frame with an offset of 0 and a value equal to the base value of the property being animated.
    5. If the after frame does not exist (i.e. all frames have an offset less than the time fraction) then construct an after frame with an offset of 1 and a value equal to the base value of the property being animated, and Set the before frame to the last frame in the sorted frame list.
    6. Otherwise (the after frame exists and is not the first frame in the sorted frame list) set the before frame to the frame immediately prior to the after frame in the sorted frame list.
    7. The local time function is the timingFunction of the before frame, if it exists; otherwise the timingFunction of the Animation interface's timing attribute.
    8. Find the local time fraction by subtracting the offset of the before frame from the time fraction, then dividing the result by the difference between the offset of the after frame and the offset of the before frame.
    9. Calculate the effective time fraction by applying the local time function to the local time fraction.
    10. Calculate the animation value by linearly interpolating the values of the before frame and after frame, using the effective time fraction as interpolation parameter (see ).

    Calculating the iteration value for a PathAnimationEffect

    When an AnimationTemplate contains a pointer to a PathAnimationEffect and rotate is set to false, the animation value for that animation at given current time t is the transform defined by a translation equal to the location on the path at t.

    When rotate is set to true, the animation value is the transform defined by the above translation followed by a rotation defined by the following process:

    1. Calculate the normal to the path at t (see ).
    2. Determine the normal rotation, which is given by atan2(normal.y, normal.x).
    3. The rotation is the transform that rotates by the normal rotation.

    Calculating the iteration value for a GroupedAnimationEffect

    When an AnimationTemplate contains a pointer to a GroupedAnimationEffect, the animation value for that animation at given current time t is calculated by following the procedure outlined in , treating the list of AnimationEffect objects contained within the GroupedAnimationEffect as the animation stack and using an initial animation value of 0 for all simple properties and id for transform.

    Custom animation 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 and DOM attributes. 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 provided needed functionality, an animation effect defined by script may be used. Such animation effects receive a time fraction from the timing model and are responsible for producing the animation effect corresponding to the specified time.

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

    For example, using an animation 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 the WindowAnimationTiming interface, 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.

    I think we want two types of custom animation effects. Following is the general-purpose animate-anything kind of effect. The other type, which is not defined here, is the one that can participate in the animation sandwich just like any other.

    This, second, native-like animation effect, would have the following features:

    • Shares the same function signature as AnimationEffect.sample
    • Gets passed the underlying value and passes out the animated value.
    • Has a target property and is sorted against other AnimationEffect objects (including platform objects)
    • Can be added as a child of a GroupedAnimationEffect.

    That's a bit more difficult since you have to be careful that the custom effect doesn't do anything naughty while you're in the middle of compositing the animation sandwich. I think we should postpone this until Web Animations 2.

    Execution order of custom animation effects

    Custom animation effects allow authors to define animation effects using script. Such animation effects are not limited to a single CSS property or DOM attribute and therefore the steps for assessing their order of execution differs from regular animation effects.

    Custom animation effects are executed after all other AnimationEffect objects have completed and applied their effects to their targets.

    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 animation effects, the order of execution is mostly the same as that for other animation effects and is defined in . However, custom animation effects may also override this ordering through the priority attribute, which, if defined, specifies the priority of the effects with lower numbers are executed sooner.

    In deciding which of two CustomAnimationEffect objects, A and B, should be executed the following rules are applied.

    1. Sort A and B based on their priority such that lower priorities are sorted first. If either does not have a defined priority, then treat the priority as being positive infinity for the purposes of sorting.
    2. If A and B have the same priority, sort according to the startTimes of the TimedItems with which A and B are associated such that earlier start times are sorted first.
    3. If A and B have the same priority and start time, sort by the position of the corresponding Animation objects occur within the animation tree (see issue below).

    Items sorted earlier, are executed first.

    That last point is quite wrong. I don't think we've specified exactly what script order is in . But I wonder if it makes more sense to effectively enumerate all the script-based nodes in the animation tree using some well-defined order and use that index. Can that be done efficiently?

    The CustomAnimationEffect callback interface

    Custom animation effects can be defined in script using the CustomAnimationEffect interface.

    Should this be a dictionary? I'd like to make clone optional.

    attribute unsigned integer priority
    The order in which this animation effect will be executed in relation to other custom animation effects such that items with a lower priority are executed earlier as defined in .
    void sample ()
    The callback used to produce the animation effect corresponding to the sample time determined by the timing model.
    double? timeFraction
    The distance within a single iteration of the animation effect of the current sample. When this is null, the callback object SHOULD remove the animation effect.
    double currentIteration
    The current iteration index beginning with zero for the first iteration.
    Element? target
    The element to which the effect should be applied if any. When this method is called as a result of this object being associated with an Animation object, it will be Animation.targetElement
    CustomAnimationEffect clone ()
    Creates an independent copy of this object.

    Do we need to pass in the TimedItem as well? If possible I'd prefer not to but it may necessary for some types of effect. Might be an additional parameter to add later if it proves necessary?

    I think we will also need to pass the previous time fraction. Animations will often use this to check if they are paused, playing in reverse etc. They can track this themselves but then you need a separate object everywhere you use it.

    Primitive animation operations

    Linear interpolation

    Linear interpolation of paths

    Write me

    Linear interpolation of transforms

    Write me

    Linear interpolation of primitive values

    Write me

    Calculating the normal to a path

    Write me

    Combining animations

    The Global Animation Stack

    When multiple in effect animations target the same element, the animations are ordered into a stack which resolves how those animations combine. This stack is sorted by animation start time. Where multiple animations have the same start time, those animations are sorted in document order (for animations from the DOM) and script order (for animations from the API). Script animations are always sorted after DOM animations.

    Other operations also generate animation stacks - for example, grouping multiple animations using a GroupedAnimationEffect.

    An animation stack may be thought of as a single stack with all animations sorted into it, or a stack per animating element, as animations on one element cannot effect the course of animations on another element.

    The start time of an animation refers to the time when the animation is specified to begin as recorded in the TimedItem.startTime property, that is, before applying any start delay.

    The stacking order of animations is independent of the current play direction of individual animations and animation groups.

    Resolving Animation Stacks

    In order to resolve an animation stack, an initial animation value is required for each element and property animated by the stack. To calculate a current animation value for elements and properties from an animation stack, an animation value is generated for each animation in the stack (see ). The cumulative animation result for each element and property is first initialised to the relevant initial animation value. Starting at the bottom of the stack (i.e. earliest start time) and working up, as animation results are encountered for an element and property, these are merged into the cumulative animation result using the animation combinator stored in the AnimationEffect that generated the result. Once all animation results in the stack are processed, the resulting cumulative animation values are the current animation values for each property of each element that is animated.

    Animation combinators

    When an animation applies to a target and property that animations earlier in the animation stack have already applied to, the cumulative animation result from the stack is composited with the new animation to produce a new cumulative animation result. The possible combinators are defined by the CompositeOperation enumeration.

    The REPLACE combinator

    When an animation a is composited over a cumulative animation result c using the REPLACE combinator, the new cumulative animation result is always a.

    The ACCUMULATE combinator

    When a path animation a is composited over a cumulative animation result c using the ACCUMULATE combinator, the effective transform of a is calculated. This transform is then post-multiplied to the cumulative animation result to generate a new cumulative animation result.

    When a transform animation a is composited over a cumulative animation result c using the ACCUMULATE combinator, a is post-multiplied to the cumulative animation result to generate a new cumulative animation result.

    When a simple animation (i.e. an animation which is not a path animation nor a transform animation) a is composited over a cumulative animation result c using the ACCUMULATE combinator, the new cumulative animation result is the sum of a and c, clipped if necessary to the appropriate domain.

    The MERGE combinator

    All MERGE operators are governed by an interpolation parameter p that is calculated as the ratio of (currentTime - parent.startTime) / parent.animationDuration, where parent is the AnimationTemplate which references the AnimationEffect that is being composited.

    When a path animation a is composited over a cumulative animation result c using the MERGE combinator, the effective transform of a is calculated. This transform is then interpolated with c using the rules provided in [[!CSS3-2D-TRANSFORMS]] to provide the new cumulative animation result.

    When a transform animation a is composited over a cumulative animation result c using the MERGE combinator, a is interpolated with c using the rules provide in [[!CSS3-2D-TRANSFORMS]] to provide the new cumulative animation result.

    When a simple animation a is composited over a cumulative animation result c using the MERGE combinator, the new cumulative animation result is calculated as the weighted sum of a and c, with weights of (1-p) and p respectively.

    Current values, animation values, and the override stylesheet

    Current values

    The current value of a given property and object is the value generated for that property by computing a current style for that object without taking the override stylesheet into account.

    The override stylesheet

    The override stylesheet contains output 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 override stylesheet. The override stylesheet is regenerated for each timepoint in a document using the process described below.

    Animation values

    We already have a section with the heading "animation values". Ideally they should be unique so they're easy to target by named anchor.

    Animation values for all animated properties are generated at each time point according to the following process, then inserted into the override stylesheet.

    1. A global animation stack is generated as described in .
    2. An initial animation value is generated by taking the current style for each object (ignoring the override stylesheet) and extracting a value for each animated property.
    3. The global animation stack is resolved using the initial animation value and the process in .
    4. The current animation values generated by this process are inserted into the override stylesheet.
    5. Do we need to work out how to use the override stylesheet for elements that don't have an id but are targetted for animations?

    Animation templates

    It is sometimes necessary to apply the same animation effect to a series of targets. Animation templates provide a means for the same set of animation properties to be applied repeatedly to a number of targets whilst maintaining a link such that changes to the template are reflected at each place where the template is applied.

    In concrete terms, an AnimationTemplate object is used to create multiple Animation objects each of which maintains a link back to the template via its template property. Such Animation objects are said to be linked to a template.

    The timing and animation parameters of linked animations cannot be modified directly. Rather, changes are made to the template which is then echoed to all animations linked to the same template. In order to modify the timing and animation parameters of a linked animation directly, it must first be unlinked using the unlink method.

    Note that run-time properties of a linked animation such as its start time and time drift can still be modified. Only those properties attached to the timing and effect properties of a linked Animation object are read-only.

    Unlinked animations can be linked to a template by:

    Provide some javascript sample here demonstrating?

    The AnimationTemplate interface

    attribute (AnimationEffect or CustomAnimationEffect) effect
    The animation effect to apply.

    The TimedTemplate interface

    Both the timing of an AnimationTemplate and the methods for creating an Animation from an AnimationTemplate are specified on the TimedTemplate since this behavior is shared with animation groups (see ).

    Should we allow live lists to be passed in? i.e. selectors etc.?

    attribute Timing timing
    The timing parameters to use for generated timed items.
    TimedItem animate ()

    Creates an independent TimedItem and appends it to element.ownerDocument.animationTimeline.

    This allows the following sort of usage:

                  anim.animate(document.getElementById("a"));
                

    The specific steps for instantiating a TimedTemplate depends on its concrete type and is described in and .

    Element target
    The Element to be targetted.
    optional double startTime

    The start time for the generated animations expressed in seconds in the iteration time space of the AnimationGroup to which it is appended (see ).

    If this parameter is not specified it will default to the current iteration time of the AnimationGroup to which it is appended if it is not null, otherwise it will default to zero.

    sequence<TimedItem> animate ()

    Creates a series of independent TimedItem objects, one for each element in target. As with animate(Element target, double startTime) each such TimedItem object is appended to element.ownerDocument.animationTimeline.

    This allows the following sort of usage:

      anim.animate([document.getElementById("a"), document.getElementById("b")]);
      anim.animate(document.querySelectorAll("div.warning"));
      anim.animate(document.getElementsByTagName("button"));
      anim.animate(document.getElementById("group").childNodes);
                

    The specific steps for instantiating a TimedTemplate depends on its concrete type and is described in and .

    sequence<Node> targets
    An sequence of Nodes to be animated. Any nodes in the sequence that are not of type ELEMENT_NODE will be ignored.
    optional double startTime
    As with animate(Element target, optional double startTime).
    TimedItem animateWithParent ()

    Similar to animate, this method creates independent TimedItem object(s) for the elements in target. However, the resulting items are appended to the given parentGroup, if provided. If parentGroup is null, the TimedItem objects will not be added to any group.

    Element target
    As with animate.
    AnimationGroup? parentGroup
    The animation group to which animations should be appended.
    optional double startTime

    The start time for the generated animations expressed in seconds in the iteration time space of the AnimationGroup to which it is appended (see ).

    If this parameter is not specified it will default to the current iteration time of parentGroup. If parentGroup is null, this parameter will default to zero.

    sequence<TimedItem> animateWithParent ( sequence<Node> targets, AnimationGroup? parentGroup, optional double startTime)
    As with animateWithParent(Element target, AnimationGroup? parentGroup, optional double startTime) except one TimedItem is created for each Node in target that is of type ELEMENT_NODE.
    TimedItem animateLive (Element target, optional double startTime)
    As with animate with the exception that the TimedItem objects generated by this method are live.
    sequence<TimedItem> animateLive ( sequence<Node> targets, optional double startTime)
    As with animate with the exception that the TimedItem objects generated by this method are live.
    TimedItem animateLiveWithParent (Element target, AnimationGroup? parentGroup, optional double startTime)
    As with animateWithParent with the exception that the animations generated by this method are live.
    sequence<TimedItem> animateLiveWithParent (sequence<Node> targets, AnimationGroup? parentGroup, optional double startTime)
    As with animateWithParent with the exception that the animations generated by this method are live.

    Instantiating an AnimationTemplate

    The procedure for instantiating an AnimationTemplate, template, given a list of target elements and an optional parent group, is as follows:

    1. Create an empty sequence of Animation objects.
    2. For each element in the list of target elements:
      1. Create a new Animation object, anim.
      2. Set the timing and effect properties of anim to copies template.timing and template.effect.
      3. If parentGroup is not specified, let parentGroup be element.ownerDocument.animationTimeline.
      4. Append element to parentGroup.
      5. Append element to the sequence of Animation objects.
    3. Return the sequence of Animation objects.

    Group templates

    As with animations, templates can also be created for animation groups.

    Lots of questions here about how this should work.

    The AnimationGroupTemplate interface

    TBD

    void clear ()
    Removes all child items from the group.
    getter TimedTemplate? (unsigned long index)
    Returns the template item at index. If index is greater than or equal to length returns null.
    setter TimedTemplate (unsigned long index, TimedTemplate newItem)

    Replaces the item at index with newItem by calling splice(index, 1, newItem).

    Returns newItem.

    The behavior of this method is identical to the equivalent setter in AnimationGroup except that DOMExceptions of type HierarchyRequestError are not thrown.

    sequence<TimedTemplate> add ( TimedTemplate newItem, TimedTemplate... otherItems)

    Add newItem and each otherItems as the last item(s) in the group by calling splice(group.length, 0, newItem, otherItem1, ... otherItemN).

    Returns a sequence containing the added items: [newItem, otherItem1, ... otherItemN].

    sequence<TimedTemplate> remove ( long index, optional unsigned long count = 1)

    Removes the item(s) at index by calling splice(index, count).

    Returns the removed items.

    sequence<TimedTemplate> splice ()

    Modifies the list of children of this group by first removing deleteCount items from start followed by adding newItems at the same point.

    Returns a sequence of the items removed from group during the removal step (regardless of whether these items were re-added during the addition step).

    As with AnimationGroup.slice the operation of slice is based on ECMAScript 5's Array.prototype.splice.

    The operation of this method is identical to that of AnimationGroup.slice with the notable difference that DOMExceptions of type HierarchyRequestError are not thrown since there is no AnimationGroupTemplate corresponding to a document timeline.

    long start
    The index at which items should be removed and inserted. Negative indices represent an offset from the end of the list of items. This value is clamped to the range [-length, length].
    unsigned long deleteCount
    The number of items to remove from the group beginning at start. Negative values are clamped to zero, and all other values are clamped such that 0 < start + deleteCount ≤ length.
    sequence<TimedTemplate> newItems
    The items to be added at start. Each item, if it already has a parent group (including this group), is first removed from its parent group before being added to this group.
    sequence<TimedTemplate> splice (long start, unsigned long deleteCount, TimedTemplate... newItem)
    An overload of splice to take a variadic list of items rather than requiring a sequence. The operation is identical to splice(unsigned long start, unsigned long deleteCount, sequence<TimedTemplate> newItems).
    long indexOf (TimedTemplate item)
    Returns the index of item within the group. If item is not in the group, returns -1.

    The ParGroupTemplate interface

    ParGroup objects can be created from ParGroupTemplate objects.

    The SeqGroupTemplate interface

    SeqGroup objects can be created from SeqGroupTemplate objects.

    Instantiating an AnimationGroupTemplate

    TBD. This is probably all wrong.

    The procedure for creating an AnimationGroup from an AnimationGroupTemplate, template, given a list of target elements, and optionally given a parent group follows.

    Note that ParGroupTemplate objects produce ParGroup objects and likewise SeqGroupTemplate objects produce SeqGroup objects. In the following description the AnimationGroupTemplate and AnimationGroup types should be substituted with the concrete types in use.

    1. Create an empty sequence to hold the generated AnimationGroup objects.
    2. For each element in the list of target elements:
      1. Create a new AnimationGroup object, group.
      2. Set the timing property of group to a copy of template.timing.
      3. For each child in template, call child.animateWithParent(element, group, startTime) or child.animateLiveWithParent(element, group, startTime) depending on whether this procedure was invoked with animate or animateLive.
      4. If parentGroup is not specified, let parentGroup be element.ownerDocument.animationTimeline.
      5. Append group to parentGroup.
      6. Append group to the sequence of AnimationGroup objects.
    3. Return the sequence of AnimationGroup objects.

    Synchronizing with media

    Currently investigating integration with HTML5's MediaController object.

    The MediaItem interface

    attribute HTMLMediaElement element
    A pointer to the element?

    Animation events

    Need to consider how to align with existing TransitionEvents, AnimationEvents and TimeEvents. It might make sense to have our events inherit from one or more of these interfaces or have implementations dispatch both (especially if their synchronization properties differ).

    I think we might also want a seek event? It seems like a lot of applications will want to do bookkeeping when there's a seek—especially a backwards seek. It might also be necessary for the SVG bindings so you can clear certain events on a backwards seek as required by SMIL.

    Talk about what events are dispatched on a seek. It's probably important that we don't dispatch intermediate events during a seek as then implementations will be required to step through each interval and it breaks the fact that skipping around the model is constant time. It's also not what SVG does, i.e. SVG skips events during a seek. I think you just want to record the animating vs non-animating state of each item before the seek, then compare to after the seek and fire the appropriate event. (Do groups fire events?)

    Synchronizing event handlers

    The proposal to-date is as follows. Requirements for dispatch of animation events:

    1. Animations triggered by an event handler appear to have started at the time the event was scheduled to be triggered.
    2. No effect of an animation for any time 't' can be reflected in style, DOM or animation object until any animation event handlers associated with dispatch times at or before 't' have returned from execution.

    In effect this is roughly the same as saying:

    When event handlers due to animation events run, the state of the world (DOM properties etc.) so far as it is influenced by animation, is as if the current time was the time when the event was scheduled to be triggered.

    There may be many ways to realise this, including:

    • dispatching animation events synchronously
    • careful updating of the animation time (after waiting for corresponding animation events to return)
    • pausing the world

    Shane and Tab feel that this approach is not very webby, and might be going to too much effort in order to support a programming model that should be discouraged.

    In the current model, the animation timeline is essentially static unless modified by script, which means that interrogating this timeline for information should be safe even in the absence of enforced synchronization. So if correct handling of an event requires precise knowledge about which animations have started or finished, then the timeline can be inspected at the time given in the event.

    Furthermore, triggering animations off complex functions involving current animation state is probably not the right way to go - instead some kind of model of the state should be used and the animations derived from that.

    In short, in the absence of strong use cases for synchronous events we feel we should go with a simpler model.

    Some alternative approaches are:

    • Standard asynchronous events with no guarantees about the state of the world when event handlers are called.
    • Event logs like those proposed to replace DOM events.

    Animation of common data types

    Need to describe how to interpolate/add both:

    1. Integers, floats, strings etc.
    2. CSS and SVG types (colors etc.)

    For transforms I think it's defined elsewhere so we can either just point to that spec, or just refer to the fact that other specs should define how their types should be supported (or not) for animation.

    Need to provide facility for smooth interpolation of arbitrary paths.

    Integration with Media Fragments

    The Media Fragments specification [[MEDIA-FRAGMENTS]] defines a means for addressing a temporal range of a media resource. For resources containing content animated with Web Animations the application of the temporal parameters is as follows:

    1. If a begin time is specified, perform a seek on the document timeline passing in the specified begin time as the seek time (see ).

      Note that seeking behavior is well-defined even when the document has yet to start and hence the seek can be performed regardless of the setting of the timelineStart property (see ).

    2. If an end time is specified... we need a way to say, "play this range", or "stop at this point" but in such a way that you can still seek beyond that range. (In order to be consistent with how hyperlinks work elsewhere such as document anchors, svg views, etc.) Perhaps we just make it an interal thing for now and in a future version add some means of playing a range, or better still, a series of ranges; something compatible with what we have for video.

    Interaction with page display

    What should be the behavior here? Should we pause on unload/pagehide? What does video do?

    Making animation accessible

    TBD. If we have triggers represented in the API, need a way to make these available to accessibility agents.

    TBD. Need a way to expose speed control etc.?

    TBD. Describe how to integrate with the Timed Text API and give examples of how to author content so it is accessible.

    Implementation requirements

    Discarding past animations

    If implementations are required to preserve all state associated with animations then the resources required by an animation could continue to increase without limit over time. For long-running animations, and particularly those where animations are added dynamically, this could lead to degraded performance and eventual failure.

    I'm not sure how to define this. We could say all animations with end time converted to document time < current document time - 5min can be discarded.

    That's fine, but what about crazy documents that put 1 million animations in a 5min span? Just leave that up to the browser. Also, what about mobile clients, is 5 min too long? Is this too prescriptive?

    Maybe, just make some suggestions (e.g. 1 min for mobile clients, 5 min for desktop?) and then define an exception to throw if there is a seek to some time outside that window.

    Also, note that defining this in terms of past intervals is direction-specific but that's probably ok since most long-running animations will run forwards.

    Acknowledgements