Web Animations Level 2

Unofficial Proposal Draft,

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

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

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


Abstract

This specification defines a model for synchronization and timing of changes to the presentation of a Web page. This specification also defines an application programming interface for interacting with this model and it is expected that further specifications will define declarative means for exposing these features.

Status of this document

1. Delta specification

This is a delta specification, meaning that it currently contains only the differences from Web Animations Level 1 [WEB-ANIMATIONS-1]. Once the Level 1 specification is closer to complete, it will be merged with the additions here into a complete level 2 specification.

2. Changes since level 1

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

3. Timing model

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

3.1. Timing model overview

This section is non-normative

3.1.1. Hierarchical

This level of the specification includes an updated timing hierarchy diagram.

A hierarchy of timing nodes
A hierarchy of timing nodes. Each node in the tree derives its time from its parent node.

Along with the following updated description:

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

3.2. Animations

This section is non-normative

3.2.1. Setting the timeline of an animation

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

3.2.2. Setting the target effect of an animation

After the step to reschedule a pending play task add the following step:

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

After the step to assign new effect as animation’s target effect include the following step:

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

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

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

3.2.3. Waiting for the target effect

The definition of when an animation is ready needs to be extended to consider descendant effects and custom effects such that the first condition is:

3.2.4. Playing an animation

The procedure to play an animation needs to include scheduling a task for updating custom effects.

3.2.5. Pausing an animation

The procedure to pause an animation needs to refer to not on the target effect but also any descedants of the target effect.

Likewise, the procedure to pause an animation needs to include scheduling a task for updating custom effects.

3.2.6. Canceling an animation

The procedure to cancel an animation needs to include the final step:

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

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

3.2.7. Speed control

Add the following sentence:

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

3.3. Animation effects

Adds the following text:

The target effect of an animation is said to be directly associated with that animation.

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

An animation effect is associated with an animation if it is directly associated with an animation or if it has an ancestor group effect that is directly associated with an animation.

3.3.1. Types of animation effects

This specification defines two types of animation effects:

3.3.2. The active interval

In this level of the specification the lower bound of the acive interval is defined as:

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

The subsequent diagram should also refer to the animation effect start time as opposed to the animation start time.

Finally, the description of the end delay is updated to:

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

The normative description is updated as follows:

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

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

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

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

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

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

These definitions are incorporated in the calculation of the local time (see §3.3.3 Local time and inherited time) and active time.

And finally regarding the definition of the end time:

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

3.3.3. Local time and inherited time

This section is added.

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

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

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

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

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

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

If the animation effect has a parent group,

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

If the animation effect is directly associated with an animation,

the inherited time is the current time of the animation.

Otherwise,

the inherited time is unresolved.

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

3.3.4. Animation effect phases and states

This section is non-normative

The non-normative description of the in play state includes the following description;

This occurs when the animation effect and all its ancestors are in the active phase. Animation effects only “move” when they are in play.

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

Likewise for current

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

The normative definition of in play includes the following condition:

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

In place of:

  1. the animation effect is associated with an animation that is not finished.

The normative definition of current adds the following condition:

3.3.5. Fill modes

This section is non-normative

The description of the forwards fill mode is updated from:

When the animation effect is in the after phase, …

to:

When the animation effect is in the after phase, or when the animation effect is in the active phase but an ancestor is in its after phase, …

The description of the backwards fill mode is updated from:

When the animation effect is in the before phase, …

to:

When the animation effect is in the before phase, or when the animation effect is in the active phase but an ancestor is in its before phase, …

The description of the both fill mode is updated from:

When the animation effect …

to:

When the animation effect or an ancestor

(twice).

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

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

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

3.4. Repeating

3.4.1. Iteration intervals

After:

The length of a single iteration is called the iteration duration.

Add:

The initial iteration duration of an animation effect is simply its intrinsic iteration duration.

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

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

3.4.2. Iteration time space

This section is non-normative

The first few paragraphs of this section are replaced with:

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

3.4.3. Interval timing

This section is non-normative

The description is updated as follows:

In the examples below, for the repeated effect, at local time 1s, the iteration time is 0. For the sequenced effects, at inherited time 1s, only effect B will be in play; there is no overlap.

And likewise the figure is updated as follows:

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

3.5. Animation effect speed control

(This section is added.)

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

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

This section is non-normative

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

3.6. Core animation effect calculations

3.6.1. Overview

This section is non-normative

Update description from:

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

to:

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

Update diagram to show animation effect playback rate:

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

Update:

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

to:

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

Update the time calculations diagram as follows:

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

Update:

The first step, calculating the local time is described in Local time.

to:

The first step, calculating the local time is described in §3.3.3 Local time and inherited time.

3.6.2. Calculating the active duration

Updated to:

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

repeated duration = iteration duration × iteration count

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

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

The active duration is calculated according to the following steps:

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

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

3.6.3. Transforming the local time

3.6.3.1. Calculating the active time

Update the qualification on the definition of the active time to include reference to the parent group:

However, it is only defined when the animation effect should produce an output and hence depends on its fill mode and phase as well as the phase of its parent group, if any, as follows,

Update the definition to include the additional steps to for each phase:

If the animation effect is in the before phase,

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

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

Return an unresolved time value.

If the animation effect is in the active phase,

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

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

Return an unresolved time value.

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

Return an unresolved time value.

Otherwise,

Return the result of evaluating local time - start delay.

If the animation effect is in the after phase,

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

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

Return an unresolved time value.

Otherwise (the local time is unresolved),

Return an unresolved time value.

3.6.3.2. Calculating the overall progress

In the definition of the overall progress update the “Otherwise” branch of the definition of the initial progress as:

Otherwise,

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

If the animation effect playback rate is less than zero,

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

If the animation effect playback rate is zero,

Let overall progress be zero.

Otherwise,

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

3.7. Time transformations

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

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

See section 2 of the discussion from August 2013.

3.7.1. Calculating the transformed progress

Replace the second step as the calculation of the before flag (to accommodate the effect playback rate):

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

3.7.2. Calculating the transformed time

(This section is added.)

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

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

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

3.8. Grouping and synchronization

This section is non-normative

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

A simple example is illustrated below.

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

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

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

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

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

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

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

3.8.1. Relationship of group time to child time

This section is non-normative

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

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

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

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

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

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

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

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

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

3.8.2. The start time of children of a group effect

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

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

3.8.3. The intrinsic iteration duration of a group effect

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

If the group has no child effects,

the intrinsic iteration duration is zero.

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

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

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

3.8.4. Sequence effects

This section is non-normative

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

Compare the two arrangements illustrated below:

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

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

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

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

3.8.4.1. The start time of children of a sequence effect

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

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

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

This section is non-normative

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

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

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

3.8.4.2. The intrinsic iteration duration of a sequence effect

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

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

4. Animation model

4.1. Animation types

4.1.1. Not animatable

Update the description of an effect that targets a non-animated property as:

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

4.2. Combining effects

4.2.1. The effect stack

The procedure for sorting effects appends the following step:

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

4.3. Custom effects

(This section is added.)

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

This section is non-normative

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

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

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

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

A custom effect is an author-defined programming callback that is passed timing information as part of the update animations and send events procedure.

It needs to be called whenever timing properties are updated too, right?

4.3.1. Sampling custom effects

Custom effects are called for each referencing animation effect when the update animations and send events procedure is performed (henceforth referred to simple as an update) based on the following criteria.

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

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

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

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

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

    Otherwise, if the animation effect referencing the custom effect:

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

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

Some alternatives under consideration:

4.3.2. Execution order of custom effects

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

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

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

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

5. Programming interface

5.1. The AnimationTimeline interface

[Exposed=Window]
partial interface AnimationTimeline {
    Animation play (optional AnimationEffectReadOnly? effect = null);
};
Animation play(optional AnimationEffectReadOnly? effect = null)

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

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

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

Need to define the start behavior when effect is null.

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

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

effect

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

5.2. The AnimationEffectReadOnly interface

The following paragraph is added:

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

[Exposed=Window]
partial interface AnimationEffectReadOnly {
    // Timing hierarchy
    readonly attribute GroupEffectReadOnly?     parent;
    readonly attribute AnimationEffectReadOnly? previousSibling;
    readonly attribute AnimationEffectReadOnly? nextSibling;
};

[NoInterfaceObject]
interface AnimationEffectMutable {
    void before (AnimationEffectReadOnly... effects);
    void after (AnimationEffectReadOnly... effects);
    void replace (AnimationEffectReadOnly... effects);
    void remove ();
};
getComputedTiming()

The description of the duration attribute of the object needs to indicate that if timing.duration is the string auto, this attribute will return the current calculated value of the intrinsic iteration duration.

parent, of type GroupEffectReadOnly, readonly, nullable

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

Should this be parentGroup?

previousSibling, of type AnimationEffectReadOnly, readonly, nullable

The previous sibling of this animation effect.

nextSibling, of type AnimationEffectReadOnly, readonly, nullable

The next sibling of this animation effect.

void before (AnimationEffectReadOnly... effects)

Inserts effects before this animation effect.

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

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

  3. Insert effects before this animation effect.

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

Inserts effects after this animation effect.

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

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

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

  4. Insert effects before reference child.

void replace(AnimationEffectReadOnly... effects)

Replaces this AnimationEffectReadOnly with the passed in effects.

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

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

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

  4. Remove this animation effect from its parent group.

  5. Insert effects before reference child.

void remove()

Removes this animation effect from its parent group or animation.

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

5.3. The AnimationEffectTimingReadOnly interface

[Exposed=Window]
partial interface AnimationEffectTimingReadOnly {
    readonly attribute double                             playbackRate;
};
delay

Update the description as:

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

endDelay

Update the description as:

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

duration

Add:

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

playbackRate, of type double, readonly

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

5.4. The AnimationEffectTiming interface

Update the description to refer to the group/sequence effects:

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

[Exposed=Window]
partial interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
    inherit attribute double                             playbackRate;
};
playbackRate, of type double

See the playbackRate attribute of the AnimationEffectTimingReadOnly interface.

5.5. The AnimationEffectTimingProperties dictionary

partial dictionary AnimationEffectTimingProperties {
    double playbackRate = 1.0;
};
playbackRate, of type double, defaulting to 1.0

See the playbackRate attribute of the AnimationEffectTiming interface.

5.6. The ComputedTimingProperties dictionary

partial dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
    double startTime;
};
startTime, of type double

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

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

endTime

Update the description as:

The end time of the animation effect expressed in milliseconds in inherited time space.

This corresponds to the end of the animation effect’s active interval plus any end delay.

localTime

Update the second paragraph as:

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

5.6.1. The FillMode enumeration

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

Update the description as:

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

5.7. The GroupEffectReadOnly and GroupEffect interfaces

(This section is added.)

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

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

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

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

Creates a new GroupEffectReadOnly object using the following procedure:

  1. Create a new GroupEffectReadOnly object, group.

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

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

  4. Insert children before null.

children

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

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

timing

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

GroupEffect ()

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

children, of type AnimationNodeList, readonly

The list of child effects in the group.

firstChild, of type AnimationEffectReadOnly, readonly, nullable

The first child of this group effect.

lastChild, of type AnimationEffectReadOnly, readonly, nullable

The last child of this group effect.

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

  2. Insert effects before the first child.

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

  2. Insert effects before null.

GroupEffect clone ()

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

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

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

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

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

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

5.7.1. Processing a timing argument

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

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

If timing is an AnimationEffectTimingProperties object,

Return timing.

If timing is a double,

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

Otherwise (timing is undefined),

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

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

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

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

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

5.7.2. Definitions for manipulating hierarchies

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

  1. Let context effect be effect.

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

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

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

  3. Return null.

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

If effect has a parent group,

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

If effect is directly associated with an animation,

Disassociate effect from the animation.

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

  1. Remove effect from its parent.

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

5.8. The AnimationNodeList interface

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

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

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

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

The number of animation effects in the list.

getter AnimationEffectReadOnly? item(unsigned long index)

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

5.9. The SequenceEffectReadOnly and SequenceEffect interfaces

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

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

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

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

SequenceEffect clone ()

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

5.10. The KeyframeEffectReadOnly and KeyframeEffect interfaces

Add:

KeyframeEffect implements AnimationEffectMutable;

5.10.1. Creating a new KeyframeEffect object

This section is non-normative

Replace:

If the duration is not specified, a value of zero is used.

with:

If the duration is not specified, the intrinsic iteration duration is used which, for a keyframe effect, is zero.

Add:

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

new SequenceEffect(
  [
    new KeyframeEffect(elem, { opacity: 0 }, 1000),
    new KeyframeEffect(elem, { visibility: 'hidden' }, { fill: 'forwards' })
  ]
);

5.11. The EffectCallback callback function

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

callback EffectCallback = void (double? progress,
                                (Element or CSSPseudoElement) currentTarget,
                                Animation animation);

An EffectCallback is called each time an KeyframeEffectReadOnly object with which it is associated is updated.

double? progress

The iteration progress value for which to produce an effect. When this is null, the function SHOULD remove the effect.

(Element or CSSPseudoElement) currentTarget

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

Note that currentTarget may differ from animation.target.

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

Animation animation

The Animation object that is being updated.

5.12. The Animatable interface

sequence<Animation> getAnimations()

Add:

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

5.13. Model liveness

This section is non-normative

Regarding the section on, “ Changes made to the Web Animations model take effect immediately”, add:

The same concept applies to more complex modifications of the Web Animations model such as adding and removing children from an GroupEffect.

Add:

Changes made to the model using the programming interface do not cause any EffectCallback functions to be called

For example, in the following code, the callback function will not be called until after the script block has completed during regular updating.

var timesCalled = 0;
elem.animate(function() {
  timesCalled++;
}, 10000);
alert(timesCalled); // Displays ‘0’

Note: Need to spec this properly somewhere.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <strong class="advisement">, like this: UAs MUST provide an accessible alternative.

Conformance classes

Conformance to this specification is defined for three conformance classes:

style sheet
A CSS style sheet.
renderer
A UA that interprets the semantics of a style sheet and renders documents that use them.
authoring tool
A UA that writes a style sheet.

A style sheet is conformant to this specification if all of its statements that use syntax defined in this module are valid according to the generic CSS grammar and the individual grammars of each feature defined in this module.

A renderer is conformant to this specification if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by this specification by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.)

An authoring tool is conformant to this specification if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module.

Partial implementations

So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

Implementations of Unstable and Proprietary Features

To avoid clashes with future stable CSS features, the CSSWG recommends following best practices for the implementation of unstable features and proprietary extensions to CSS.

Non-experimental implementations

Once a specification reaches the Candidate Recommendation stage, non-experimental implementations are possible, and implementors should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec.

To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group.

Further information on submitting testcases and implementation reports can be found from on the CSS Working Group’s website at https://www.w3.org/Style/CSS/Test/. Questions should be directed to the public-css-testsuite@w3.org mailing list.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-EASING-1]
Brian Birtles; Dean Jackson; Matt Rakow. CSS Easing Functions Level 1. 9 October 2018. WD. URL: https://www.w3.org/TR/css-easing-1/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 7 June 2016. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS2/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[WEB-ANIMATIONS-1]
Brian Birtles; et al. Web Animations. 11 October 2018. WD. URL: https://www.w3.org/TR/web-animations-1/
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

IDL Index

[Exposed=Window]
partial interface AnimationTimeline {
    Animation play (optional AnimationEffectReadOnly? effect = null);
};

[Exposed=Window]
partial interface AnimationEffectReadOnly {
    // Timing hierarchy
    readonly attribute GroupEffectReadOnly?     parent;
    readonly attribute AnimationEffectReadOnly? previousSibling;
    readonly attribute AnimationEffectReadOnly? nextSibling;
};

[NoInterfaceObject]
interface AnimationEffectMutable {
    void before (AnimationEffectReadOnly... effects);
    void after (AnimationEffectReadOnly... effects);
    void replace (AnimationEffectReadOnly... effects);
    void remove ();
};

[Exposed=Window]
partial interface AnimationEffectTimingReadOnly {
    readonly attribute double                             playbackRate;
};

[Exposed=Window]
partial interface AnimationEffectTiming : AnimationEffectTimingReadOnly {
    inherit attribute double                             playbackRate;
};

partial dictionary AnimationEffectTimingProperties {
    double playbackRate = 1.0;
};

partial dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
    double startTime;
};

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

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

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

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

[Exposed=Window]
interface AnimationNodeList {
    readonly attribute unsigned long length;
    getter AnimationEffectReadOnly? item (unsigned long index);
};

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

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

KeyframeEffect implements AnimationEffectMutable;

callback EffectCallback = void (double? progress,
                                (Element or CSSPseudoElement) currentTarget,
                                Animation animation);

Issues Index

If new timeline is null, we should ensure that custom effects get called with an unresolved iteration progress (unless a subsequent change in the same script execution context makes this redundant).
This is not quite right. If old effect is attached to another animation in the same task then we should probably not do an extra callback with unresolved.

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

The procedures for calling custom effects need to be reworked. Currently they probably involve calling too often for changes that could be coalesced.
Currently timing functions that generate results outside the range [0, 1] will behave unexpectedly when applied to group effects, as children will increase iterations or enter into fill mode rather than continuing to extrapolate along their defined behavior (which is what they would do if the timing function applied to them directly).

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

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

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

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

See section 2 of the discussion from August 2013.

This whole feature needs to be revisited. The current thinking is that rather than having custom effects, we should simply have an onupdate callback on each animation effect. That would allow, for example, augmenting an existing effect with a function that performs logging or triggers additional actions at certain times. With the current arrangement, doing this would require adding a parent group just to achieve this.
It needs to be called whenever timing properties are updated too, right?
There may be use cases where an action needs to be triggered at a specific point in an animation tree. In many cases this can be achieved by inserting a custom effect with a step-start easing that spans the period during which the action should be triggered. However, this can impose additional layout requirements on the content which might be cumbersome to accomodate.

Some alternatives under consideration:

Need to define this more precisely. Are styles flushed? Presumably they are. Can we suspend reflow for the duration of executing the script-based animation effects and just do it once afterwards?
It has been suggested this method be renamed, or even removed (see TAG feedback).
Need to define the start behavior when effect is null.
Should this be parentGroup?
The remove() method can be used to remove an effect from either its parent group or animation. Should we keep it in level 1 and define it simply as removing the animation from its animation?