Web Animations Level 2

W3C First Public Working Draft,

More details about this document
This version:
https://www.w3.org/TR/2023/WD-web-animations-2-20230221/
Latest published version:
https://www.w3.org/TR/web-animations-2/
Editor's Draft:
https://drafts.csswg.org/web-animations-2/
History:
https://www.w3.org/standards/history/web-animations-2
Feedback:
CSSWG Issues Repository
Inline In Spec
Editors:
(Invited Expert)
(Google)
Former Editors:
(Google)
(Google)
Suggest an Edit for this Spec:
GitHub Editor
Participate:
Fix the text through GitHub
Join the ‘waapi’ channel on the Animation at Work slack
IRC: #webanimations on W3C’s IRC
Issue Tracking:
GitHub
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 CSSWG at [email protected].


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.

CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, etc.

Status of this document

This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This document was published by the CSS Working Group as a First Public Working Draft using the Recommendation track. Publication as a First Public Working Draft does not imply endorsement by W3C and its Members.

This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

Please send feedback by filing issues in GitHub (preferred), including the spec code “web-animations” in the title, like this: “[web-animations] …summary of comment…”. All issues and comments are archived. Alternately, feedback can be sent to the (archived) public mailing list [email protected].

This document is governed by the 2 November 2021 W3C Process Document.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

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:

This module also includes some exploratory proposals for § 4.5 Custom effects, however there are some concerns about the design of this feature and it may be replaced in a future revision. See discussion.

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

Add:

The duration of a timeline gives the maximum value a timeline may generate for its current time. This value is used to calculate the intrinsic iteration duration for the target effect of an animation that is associated with the timeline when the effect’s iteration duration is "auto". The value is computed such that the effect fills the available time. For a monotonic timeline, there is no upper bound on current time, and timeline duration is unresolved. For a non-monotonic (e.g. scroll) timeline, the duration has a fixed upper bound. In this case, the timeline is a progress-based timeline, and its timeline duration is 100%.

3.3. Animations

Append:

Animation effects associated with a progress-based timeline require their timing properties to be converted to proportions. The procedure for converting a is as follows:

  1. If the iteration duration is auto, then perform the following steps.

    • Set start delay and end delay to 0, as it is not possible to mix time and proportions.

      Note: Future versions may allow these properties to be assigned percentages, at which point the delays are only to be ignored if their values are expressed as times and not as percentages.

    Otherwise:

    1. Let total time be equal to end time

    2. Set start delay to be the result of evaluating specified start delay / total time * timeline duration.

    3. Set iteration duration to be the result of evaluating specified iteration duration / total time * timeline duration.

    4. Set end delay to be the result of evaluating specified end delay / total time * timeline duration.

The procedure to normalize specified timing is as follows:

If timeline duration is resolved:

Otherwise:
  1. Set start delay = specified start delay

  2. Set end delay = specified end delay

  3. If iteration duration is auto:

    Otherwise:

3.3.1. Setting the timeline of an animation

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

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

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

  3. Let previous play state be animation’s play state.

  4. Let previous current time be the animation’s current time.

  5. Set previous progress based in the first condition that applies:

    If previous current time is unresolved:

    Set previous progress to unresolved.

    If end time is zero:

    Set previous progress to zero.

    Otherwise

    Set previous progress = previous current time / end time

  6. Let from finite timeline be true if old timeline is not null and not monotonically increasing.

  7. Let to finite timeline be true if timeline is not null and not monotonically increasing.

  8. Let the timeline of animation be new timeline.

  9. Set the flag reset current time on resume to false.

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

    If to finite timeline,
    1. Apply any pending playback rate on animation

    2. Let seek time be zero if playback rate ≥ 0, and animation’s associated effect end otherwise.

    3. Update the animation based on the first matching condition if any:

      If either of the following conditions are true:

      • previous play state is "running" or,

      • previous play state is "finished"

      Set animation’s start time to seek time.

      If previous play state is "paused":

      If previous progress is resolved:

      1. Set the flag reset current time on resume to true.

      2. Set start time to unresolved.

      3. Set hold time to previous progress * end time.

      This step ensures that previous progress is preserved even in the case of a pause-pending animation with a resolved start time.

      Otherwise

      1. Set start time to seek time.

    If from finite timeline and previous progress is resolved,

    Run the procedure to set the current time to previous progress * end time.

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

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

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

Issue: 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.3.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 associated 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.3.3. Waiting for the associated 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.3.4. Validating a CSSNumberish time

The procedure to validate a CSSNumberish time for an input value of time is based on the first condition that matches:

If all of the following conditions are true:

  • The animation is associated with a progress-based timeline, and

  • time is not a CSSNumeric value with percent units:

throw a TypeError.

return false;

If all of the following conditions are true:

throw a TypeError.

return false.

Oterwise

return true.

3.3.5. Setting the current time of an Animation

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

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

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

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

    2. Abort these steps.

  2. Let valid seek time be the result of running the validate a CSSNumberish time procedure with seek time as the input.

  3. If valid seek time is false, abort this procedure.

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

    If any of the following conditions are true:

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

    Otherwise,

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

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

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

  6. Make animation’s previous current time unresolved.

  7. Set the reset current time on resume flag to false.

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

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

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

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

    2. Apply any pending playback rate to animation.

    3. Make animation’s start time unresolved.

    4. Cancel the pending pause task.

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

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

3.3.6. Setting the start time of an Animation

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

  1. Let valid start time be the result of running the validate a CSSNumberish time procedure with new start time as the input.

  2. If valid start time is false, abort this procedure.

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

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

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

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

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

  6. Apply any pending playback rate on animation.

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

  8. Set the reset current time on resume flag to false.

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

    If new start time is resolved,

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

    Otherwise (new start time is unresolved),
    1. Set animation’s hold time to previous current time even if previous current time is unresolved.

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

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

3.3.7. Playing an animation

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

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

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

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

  3. Let seek time be a time value that is initially unresolved.

  4. Let has finite timeline be true if animation has an associated timeline that is not monotonically increasing.

  5. Let previous current time be the animation’s current time

  6. If reset current time on resume is set:

    • Set previous current time to unresolved.

    • Set the reset current time on resume flag to false.

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

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

    Set seek time to zero.

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

    If associated effect end is positive infinity,

    throw an "InvalidStateError" DOMException and abort these steps.

    Otherwise,

    Set seek time to animation’s associated effect end.

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

    Set seek time to zero.

  8. If seek time is resolved,

    If has finite timeline is true,
    1. Set animation’s start time to seek time.

    2. Let animation’s hold time be unresolved.

    3. Apply any pending playback rate on animation.

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

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

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

    1. Cancel that task.

    2. Set has pending ready promise to true.

  11. If the following four conditions are all satisfied:

    abort this procedure.

  12. If has pending ready promise is false, let animation’s current ready promise be a new promise in the relevant Realm of animation.

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

    1. Assert that at least one of animation’s start time or hold time is resolved.

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

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

      If animation’s hold time is resolved,
      1. Apply any pending playback rate on animation.

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

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

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

      If animation’s start time is resolved and animation has a pending playback rate,
      1. Let current time to match be the result of evaluating (ready time - start time) × playback rate for animation.

      2. Apply any pending playback rate on animation.

      3. If animation’s playback rate is zero, let animation’s hold time be current time to match.

      4. Let new start time be the result of evaluating ready time - current time to match / playback rate for animation. If the playback rate is zero, let new start time be simply ready time.

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

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

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

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

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

    If a user agent determines that animation is immediately ready, it may schedule the above task as a microtask such that it runs at the next microtask checkpoint, but it must not perform the task synchronously.

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

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

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

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

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

3.3.8. Pausing an animation

The procedure to pause an animation needs to refer not only to the associated effect but also any descendants of the associated effect.

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

3.3.9. Canceling an animation

Append the final step:
  1. Queue a task to call any custom effects associated with inclusive descendants of animation’s associated 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.3.10. 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.4. Animation effects

Adds the following text:

The associated 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.9 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 associated 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.4.1. Types of animation effects

This specification defines two types of animation effects:

3.4.2. The active interval

In this level of the specification the lower bound of the active 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.9.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.4.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.4.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.4.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:

Add the following definitions to the list used in determining the phase of an animation effect.

at progress timeline boundary

Determined using the following procedure:

  1. If any of the following conditions are true:

    return false

  1. Let effective start time be the animation’s start time if resolved, or zero otherwise.

    1. Set unlimited current time based on the first matching condition:

      start time is resolved:

      (timeline time - start time) × playback rate

      Otherwise

      animation’s current time

    2. Let effective timeline time be unlimited current time / animation’s playback rate + effective start time

    3. Let effective timeline progress be effective timeline time / timeline duration

    4. If effective timeline progress is 0 or 1, return true, otherwise false.

This procedure is not strictly correct for a paused animation if the animation’s current time is explicitly set, as this can introduce a lead or lag, between the timeline’s current time and animation’s current time.

This procedure can likely be simplified, and instead determine if at a scrolling boundary regardless of playback rate or start time. The surprising behavior that this is trying to prevent is an animation becoming inactive precisely at the scroll limit, alleviating the need for set a fill-mode with a ScrollTimeline. Checking if timeline current time is 0 or timeline duration may be sufficient.

Replace:

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

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

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

with:

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

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

  2. the animation direction is "backwards" and the local time is equal to the before-active boundary time and not at progress timeline boundary.

Replace:

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

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

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

with:

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

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

  2. the animation direction is "forwards" and the local time is equal to the active-after boundary time and not at progress timeline boundary.

3.4.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.5. Repeating

3.5.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 is calculated from the first matching condition from below:

If the animation effect is a group effect,

Follow the procedure in § 3.9.3 The intrinsic iteration duration of a group effect

If the animation effect is a sequence effect,

Follow the procedure in § 3.9.4.2 The intrinsic iteration duration of a sequence effect

If timeline duration is unresolved or iteration count is zero,

Return 0

Otherwise

Return (100% - start delay - end delay) / iteration count

Note: Presently start and end delays are zero until such time as percentage based delays are supported.

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

3.5.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.4.3 Local time and inherited time). Repetition introduces yet another time space: the iteration time space.

3.5.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.6. 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.7 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.7. Core animation effect calculations

3.7.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.4.3 Local time and inherited time.

3.7.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.7.3. Transforming the local time

3.7.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.7.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 playback rate is less than zero,

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

If the playback rate is zero,

Let overall progress be zero.

Otherwise,

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

3.8. 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.8.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 playback rate ≥ 0 (but not when both conditions are true), let going forwards be true, otherwise it is false.

3.8.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.9. 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.4.3 Local time and inherited time).

3.9.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 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.9.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.9.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. The end time may be expressed as a time or a percentage (in the case of a progress-based timeline). In the event of mixed time and percentage end times, the largest time based value equates to 100% for the purpose of time scaling.

  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.9.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.9.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.9.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.9.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 fulfillment of an animation’s current finished promise.

4.2. Keyframe Effects

4.2.1. The effect value of a keyframe effect

The procedure for computing the effect value of a single property referenced by a keyframe effect as one of its target properties, for a given iteration progress, current iteration and underlying value is amended by inserting the following step after the step to apply the keyframe effect composite mode.

  1. For each keyframe in interval endpoints:

    1. (As in web-animations-1).

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

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

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

4.3. Combining effects

4.3.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.4. Effect accumulation

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

This specification defines two iteration composite operations as follows:

replace

Each successive iteration is calculated independently of previous iterations.

accumulate

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

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

4.5. 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.5.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 accommodate.

Some alternatives under consideration:

  • Additional calling conditions could be defined to accommodate zero-width custom effects. For example, it could be required that the callback be called if (given infinite precision) there was a time between the previous and current update times that aligned with the custom effect.

  • Instead of adding special calling conditions to custom effects, a new type of animation effect, Trigger, could be introduced. The trigger would only ever act as a zero-width custom effect as described above, its constructor would take a callback function, but not require a target or timing. It could also specify other calling conventions, for example whether it should only trigger in a specific playback direction.

4.5.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.3.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 {
    readonly attribute CSSNumberish? currentTime;
    readonly attribute CSSNumberish? duration;
    Animation play (optional AnimationEffect? effect = null);
};

Update the attribute type for currentTime.

currentTime, of type CSSNumberish, readonly, nullable

Returns the current time for this timeline or null if this timeline is inactive. The value is expressed as a percentage for a progress-based timeline, or as a double in milliseconds otherwise.

duration, of type CSSNumberish, readonly, nullable

Returns the duration for this timeline.

Animation play(optional AnimationEffect? 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 associated 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 associated effect to assign to the newly-created Animation object.

5.2. The Animation interface

Update the startTime and currentTime of the Animation interface as follows:

[Exposed=Window]
partial interface Animation {
    attribute CSSNumberish?       startTime;
    attribute CSSNumberish?       currentTime;
};

Replace start time and current time attribute descriptions with:

startTime, of type CSSNumberish, nullable

Update the description as:

The start time of this animation. When associated with a progress-based timeline, start time must be returned as a CSSNumericValue with percent units. Otherwise start time must be returned as a double value, representing the time in units of milliseconds. Setting this attribute updates the start time using the procedure to set the start time of this object to the new value.

currentTime, of type CSSNumberish, nullable

update the description as:

The current time of this animation. When associated with a progress-based timeline, current time must be returned as a CSSNumericValue. with percent units. Otherwise current time must be returned as a double value, representing the time in units of milliseconds. Setting this attribute follows the procedure to set the current time of this object to the new value.

5.3. The AnimationEffect interface

[Exposed=Window]
partial interface AnimationEffect {
    // Timing hierarchy
    readonly attribute GroupEffect?     parent;
    readonly attribute AnimationEffect? previousSibling;
    readonly attribute AnimationEffect? nextSibling;

    undefined before (AnimationEffect... effects);
    undefined after (AnimationEffect... effects);
    undefined replace (AnimationEffect... effects);
    undefined 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, which may be a expressed as a double representing the duration in milliseconds or a percentage when the effect is associated with a progress-based timeline.

parent, of type GroupEffect, 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 AnimationEffect, readonly, nullable

The previous sibling of this animation effect.

nextSibling, of type AnimationEffect, readonly, nullable

The next sibling of this animation effect.

undefined before (AnimationEffect... 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
undefined after(AnimationEffect... 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.

undefined replace(AnimationEffect... effects)

Replaces this AnimationEffect 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.

undefined 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.4. The EffectTiming and OptionalEffectTiming dictionaries

partial dictionary EffectTiming {
    double delay;
    double endDelay;
    double playbackRate = 1.0;
    (unrestricted double or CSSNumericValue or DOMString) duration = "auto";
};

partial dictionary OptionalEffectTiming {
    double playbackRate;
};

Note: In this version of the spec, duration is not settable as a CSSNumericValue; however, duration may be returned as a CSSNumericValue when resolving the duration in getComputedTiming(). Future versions of the spec may enable setting the duration as a CSSNumeric value, where the unit is a valid time unit or percent.

delay, of type double

Update the description as:

The specified start delay which represents the number of milliseconds from an animation effect’s start time to the start of the active interval. The specified start delay is converted to a start delay following the normalize specified timing procedure.

endDelay, of type double

Update the description as:

The specified 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. The specified end delay is converted to an end delay following the normalize specified timing procedure.

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

Update the description as:

The specified iteration duration which is a real number greater than or equal to zero (including positive infinity) representing the time taken in milliseconds to complete a single iteration of the animation effect, or the string value auto to indicate that the iteration duration reflects the animation effect’s intrinsic iteration duration. The specified iteration duration is converted to an iteration duration following the normalize specified timing procedure.

playbackRate, of type double, defaulting to 1.0

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.5. Updating the timing of an AnimationEffect

Replace:

Assign each member that exists in input to the corresponding timing property of effect as follows:

with:

Assign each member that exists in input to the corresponding timing property of effect as follows:

Add:

Follow the procedure to normalize specified timing.

Timing properties may also be updated due to a style change. Any change to a CSS animation property that affects timing requres rerunning the procedure to normalize specified timing.

5.6. The ComputedEffectTiming dictionary

partial dictionary ComputedEffectTiming {
    CSSNumberish         startTime;
    CSSNumberish         endTime;
    CSSNumberish         activeDuration;
    CSSNumberish?        localTime;
};
startTime, of type CSSNumberish

The start time of this animation effect expressed as a percentage if associated with a progress-based timeline, or as a double in milliseconds otherwise.

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

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

endTime, of type CSSNumberish

Update the description as:

The end time of the animation effect in inherited timespace. The value is expressed as a percentage if associated with a progress-based timeline, or as a double in milliseconds otherwise. This corresponds to the end of the animation effect’s active interval plus any end delay.

activeDuration, of type CSSNumberish

Update the description as:

The active duration of this animation effect expressed as a percentage if associated with a progress-based timeline, or as a double in milliseconds otherwise.

localTime, of type CSSNumberish, nullable

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.

Append:

The value is expressed as a percentage if associated with a progress-based timeline, or as a double in milliseconds otherwise.

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 GroupEffect and no fill when applied to an KeyframeEffect.

5.7. The GroupEffect interface

(This section is added.)

Group effects are represented by the GroupEffect interface.

[Exposed=Window]
interface GroupEffect {
  constructor(sequence<AnimationEffect>? children,
              optional (unrestricted double or EffectTiming) timing = {});

  readonly attribute AnimationNodeList  children;
  readonly attribute AnimationEffect?   firstChild;
  readonly attribute AnimationEffect?   lastChild;
  GroupEffect clone ();

  undefined prepend (AnimationEffect... effects);
  undefined append (AnimationEffect... effects);
};
GroupEffect ()

Creates a new GroupEffect object using the following procedure:

  1. Create a new GroupEffect object, group.

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

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

    If options is an EffectTiming object,

    Let timing input be options.

    Otherwise (if options is a double),

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

  4. Call the procedure to update the timing properties of an animation effect of group from timing input.

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

  5. 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 GroupEffect interface.

timing

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

children, of type AnimationNodeList, readonly

The list of child effects in the group.

firstChild, of type AnimationEffect, readonly, nullable

The first child of this group effect.

lastChild, of type AnimationEffect, readonly, nullable

The last child of this group effect.

undefined prepend (AnimationEffect... 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.

undefined append (AnimationEffect... 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 GroupEffect object using the following procedure.

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

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

  3. Let cloned children be an empty sequence of AnimationEffect 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 GroupEffect() or SequenceEffect() constructor may be an EffectTiming 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 EffectTiming object.

If timing is an EffectTiming object,

Return timing.

If timing is a double,

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

Otherwise (timing is undefined),

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

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

  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 AnimationEffect? item (unsigned long index);
};
length, of type unsigned long, readonly

The number of animation effects in the list.

getter AnimationEffect? item(unsigned long index)

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

5.9. The SequenceEffect interfaces

Sequence effects are represented by the SequenceEffect interface.

[Exposed=Window]
interface SequenceEffect : GroupEffect {
  constructor(sequence<AnimationEffect>? children,
              optional (unrestricted double or EffectTiming) timing = {});

  SequenceEffect clone ();
};
constructor (sequence<AnimationEffect>? children, optional (unrestricted double or EffectTiming) 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 SequenceEffect object using the same procedure as defined for the clone() method of the GroupEffect interface except that a new SequenceEffect object is created.

5.10. The KeyframeEffect interfaces

The KeyframeEffect interface is modified to add the following:

partial interface KeyframeEffect {
    attribute IterationCompositeOperation    iterationComposite;
};
KeyframeEffect (target, keyframes, options)

Amend step 5 of the procedure to create a new KeyframeEffect object as follows:

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

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

KeyframeEffect (source)

Amend the procedure to create a new KeyframeEffect object with the same properties as source to include setting the iteration composite operation from source on effect.

iterationComposite, of type IterationCompositeOperation

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

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

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.

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.10.2. The KeyframeEffectOptions dictionary

The KeyframeEffectOptions dictionary interface is modified to add the following member:

partial dictionary KeyframeEffectOptions {
    IterationCompositeOperation iterationComposite = "replace";
};
iterationComposite, of type IterationCompositeOperation, defaulting to "replace"

The iteration composite operation used to define the way animation values build from iteration to iteration.

5.11. The IterationCompositeOperation enumeration

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

enum IterationCompositeOperation { "replace", "accumulate" };
replace

Corresponds to the replace iteration composite operation value such that the effect value produced is independent of the current iteration.

accumulate

Corresponds to the accumulate iteration composite operation value such that subsequent iterations of an animation effect build on the final value of the previous iteration.

5.12. The EffectCallback callback function

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

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

An EffectCallback is called each time an KeyframeEffect 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.13. 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.14. The AnimationPlaybackEvent interface

Replace double with CSSNumberish as the type for currentTime and timelineTime.

[Exposed=Window]
interface AnimationPlaybackEvent : Event {
    constructor(DOMString type, optional AnimationPlaybackEventInit
    eventInitDict = {});
    readonly attribute CSSNumberish? currentTime;
    readonly attribute CSSNumberish? timelineTime;
};
dictionary AnimationPlaybackEventInit : EventInit {
    CSSNumberish? currentTime = null;
    CSSNumberish? timelineTime = null;
};

Update the type for the AnimationPlaybackEvent attributes.

currentTime, of type CSSNumberish, readonly, nullable

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

timelineTime, of type CSSNumberish, readonly, nullable

The time value of the timeline with which the animation that generated the event is associated at the moment the event was queued. This will be null if the animation was not associated with an active timeline at the time the event was queued.

Update the type for the AnimationPlaybackEventInit members.

currentTime, of type CSSNumberish, nullable, defaulting to null

See the description of the currentTime attribute.

timelineTime, of type CSSNumberish, nullable, defaulting to null

See the description of the timelineTime attribute.

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

6. Privacy Considerations

No privacy considerations have been reported on this module.

7. Security Considerations

No security considerations have been reported on this module.

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 [email protected] mailing list.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS Display Module Level 3. 18 November 2022. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-EASING-1]
Brian Birtles; Dean Jackson; Matt Rakow. CSS Easing Functions Level 1. 13 February 2023. CR. URL: https://www.w3.org/TR/css-easing-1/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS Pseudo-Elements Module Level 4. 30 December 2022. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-TYPED-OM-1]
Shane Stephens; Tab Atkins Jr.; Naina Raisinghani. CSS Typed OM Level 1. 10 April 2018. WD. URL: https://www.w3.org/TR/css-typed-om-1/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 19 October 2022. WD. URL: https://www.w3.org/TR/css-values-4/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEB-ANIMATIONS-1]
Brian Birtles; et al. Web Animations. 8 September 2022. WD. URL: https://www.w3.org/TR/web-animations-1/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[CSS-ANIMATIONS-1]
Dean Jackson; et al. CSS Animations Level 1. 11 October 2018. WD. URL: https://www.w3.org/TR/css-animations-1/

IDL Index

[Exposed=Window]
partial interface AnimationTimeline {
    readonly attribute CSSNumberish? currentTime;
    readonly attribute CSSNumberish? duration;
    Animation play (optional AnimationEffect? effect = null);
};

[Exposed=Window]
partial interface Animation {
    attribute CSSNumberish?       startTime;
    attribute CSSNumberish?       currentTime;
};

[Exposed=Window]
partial interface AnimationEffect {
    // Timing hierarchy
    readonly attribute GroupEffect?     parent;
    readonly attribute AnimationEffect? previousSibling;
    readonly attribute AnimationEffect? nextSibling;

    undefined before (AnimationEffect... effects);
    undefined after (AnimationEffect... effects);
    undefined replace (AnimationEffect... effects);
    undefined remove ();
};

partial dictionary EffectTiming {
    double delay;
    double endDelay;
    double playbackRate = 1.0;
    (unrestricted double or CSSNumericValue or DOMString) duration = "auto";
};

partial dictionary OptionalEffectTiming {
    double playbackRate;
};

partial dictionary ComputedEffectTiming {
    CSSNumberish         startTime;
    CSSNumberish         endTime;
    CSSNumberish         activeDuration;
    CSSNumberish?        localTime;
};

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

[Exposed=Window]
interface GroupEffect {
  constructor(sequence<AnimationEffect>? children,
              optional (unrestricted double or EffectTiming) timing = {});

  readonly attribute AnimationNodeList  children;
  readonly attribute AnimationEffect?   firstChild;
  readonly attribute AnimationEffect?   lastChild;
  GroupEffect clone ();

  undefined prepend (AnimationEffect... effects);
  undefined append (AnimationEffect... effects);
};

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

[Exposed=Window]
interface SequenceEffect : GroupEffect {
  constructor(sequence<AnimationEffect>? children,
              optional (unrestricted double or EffectTiming) timing = {});

  SequenceEffect clone ();
};

partial interface KeyframeEffect {
    attribute IterationCompositeOperation    iterationComposite;
};

partial dictionary KeyframeEffectOptions {
    IterationCompositeOperation iterationComposite = "replace";
};

enum IterationCompositeOperation { "replace", "accumulate" };

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

[Exposed=Window]
interface AnimationPlaybackEvent : Event {
    constructor(DOMString type, optional AnimationPlaybackEventInit
    eventInitDict = {});
    readonly attribute CSSNumberish? currentTime;
    readonly attribute CSSNumberish? timelineTime;
};
dictionary AnimationPlaybackEventInit : EventInit {
    CSSNumberish? currentTime = null;
    CSSNumberish? timelineTime = null;
};

Issues Index

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 procedure to play an animation needs to include scheduling a task for updating custom effects.
The procedures for calling custom effects need to be reworked. Currently they probably involve calling too often for changes that could be coalesced.
This procedure is not strictly correct for a paused animation if the animation’s current time is explicitly set, as this can introduce a lead or lag, between the timeline’s current time and animation’s current time.
This procedure can likely be simplified, and instead determine if at a scrolling boundary regardless of playback rate or start time. The surprising behavior that this is trying to prevent is an animation becoming inactive precisely at the scroll limit, alleviating the need for set a fill-mode with a ScrollTimeline. Checking if timeline current time is 0 or timeline duration may be sufficient.
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 accommodate.

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?