This is the abstract for your specification.

Scaling the time

The TimingFunctionCallback callback

In addition to the timing functions provided by Web Animations, authors may also provide their own time scaling function. The behavior of this function is defined by the TimingFunctionCallback type below.

A TimingFunctionCallback function has the same behavior as defined for the scaleTime method on the TimingFunction interface. That is, it takes an input time fraction, applies some scaling operation to it, and returns an output time fraction.

For the same input time and item, this function MUST return the same output.

As a result, a user agent MAY cache the results returned by a TimingFunctionCallback as an optimization. Note, however, that if the item object is changed, this consitutes different input to the function and hence the user agent MUST NOT cache the results of the callback if the item object changes. Given the requirement that callback functions do not change item, a user agent can expect that it is safe to cache the output of a TimingFunctionCallback for at least the duration of a sample.

Is it important to be able to differentiate between when the scaling is being applied to an iteration as a whole or simply to a segment of a keyframe animation?

I suspect it probably is and that that would consitute different input to the function.

double time
The input time fraction in the range [0.0, 1.0].
TimedItem? item
The TimedItem for which the scaling is being performed. This object MUST NOT be modified.

Applying time manipulations

Needs to be adjusted as follows:

  1. Scale the time as follows:
    If timing.timingFunction is a TimingFunction object,

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

    If timing.timingFunction is a TimingFunctionCallback function,

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

    If calling timing.timingFunction results in an exception being thrown, let scaled iteration time be unscaled iteration time.

    Need to consider:

    • Is there any way to lock down the model during this step? i.e. make everything read-only? (Of course it's not fully possible, but can we do enough that it's meaningful?) Maybe implementations can just display something in the console: "If you're changing stuff in a timing function you're going to have a bad time"
    • Can we cache some values before calling to ensure that at least this procedure will complete as expected?
    • Need to define exactly when this procedure is performed since both the timing and the number of times it is called could produce different results if the script has side effects. For example, does querying TimedItem.iterationTime result in the script being executed every time?

      Possibly could define things such that iteration time is evaluated on each sample (need to define sampling) and then only if iterationTime is explicitly requested (i.e. no caching there)... what about other operations that rely on iteration time being up to date? what are they?

    • At points where this is called we need to check the state of the model after calling.
    • Do we need some disclaimer saying, "if the script has side effects all bets are off"
    • Also need to be careful that the callback doesn't call anything that triggers calculating the iteration time (e.g. TimedItem.iterationTime should use a cached value in that case)
    • I think script-defined timing functions might get punted to v2
    Otherwise,
    Let scaled iteration time be unscaled iteration time.

Animation templates

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

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

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

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

Unlinked animations can be linked to a template by:

Provide some javascript sample here demonstrating?

Animation interface members

attribute AnimationTemplate? template

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

Setting this property has the following effect:

  1. Let new template be the value to assign to the template property.
  2. If new template is null,
    1. Call unlink().
  3. Otherwise,
    1. Set timing to new template.timing.clone().
    2. Set effect to new template.effect.clone().
    3. Set template to new template.
AnimationTemplate templatize()

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

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

The effect is equivalent to the following steps:

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

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

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

The effect is equivalent to the following steps:

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

The AnimationTemplate interface

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

The TimedTemplate interface

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

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

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

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

This allows the following sort of usage:

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

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

AnimationTarget target
The element or pseudo-element to be targetted.
optional double startTime

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

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

sequence<TimedItem> animate ()

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

This allows the following sort of usage:

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

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

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

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

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

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

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

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

Instantiating an AnimationTemplate

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

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

Group templates

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

Lots of questions here about how this should work.

The AnimationGroupTemplate interface

TBD

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

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

Returns newItem.

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

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

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

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

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

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

Returns the removed items.

sequence<TimedTemplate> splice ()

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

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

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

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

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

The ParGroupTemplate interface

ParGroup objects can be created from ParGroupTemplate objects.

The SeqGroupTemplate interface

SeqGroup objects can be created from SeqGroupTemplate objects.

Instantiating an AnimationGroupTemplate

TBD. This is probably all wrong.

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

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

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