Platform/Layout/Extended Timelines

From MozillaWiki
Jump to: navigation, search

Summary: Following is a rough sketch of how the Web Animations API could be adapted to support scrubbing animations based on scroll position and (less critical) touch events.

Background reading: Web Animations spec, in particular the timeline and player concepts. Some additional background about players is on this blog. I (Brian) am not crazy about the idea but I think it's workable.

API

[Constructor ((Window or Element) scrollSource, Orientation orientation)
interface ScrollTimeline : AnimationTimeline {
  attribute Orientation orientation;
};

// Is there an existing enum somewhere we can use for this?
enum Orientation { "vertical", "horizontal" };

The currentTime of a ScrollTimeline would be basically scrollTop/scrollY or scrollLeft/scrollX (with the exception that it would track smooth scrolling even though this isn't reported to the DOM, see bug 1010538). We could probably add scaling parameters here too, possibly based on scrollHeight/scrollMaxY etc.

The playbackRate of an AnimationPlayer provides the mapping from scroll units to time units.

(We probably don't need this feature for now) We could extend this member to take an "auto" value like so:

interface AnimationPlayer : EventTarget {
   ...
   // Can be "auto" or a double
   (double or DOMString) playbackRate;
}

If AnimationPlayer is associated with a fixed length timeline like ScrollTimeline, the value "auto" sets the effective playbackRate so that the duration of the player's animation content stretches to fit the range of the scroll container (players are already aware of the length of their source content so this isn't breaking the model).

If AnimationPlayer is associated with an infinite timeline like the document timeline, then "auto" would simply be 1.0.

(We'd probably need a way of fetching the calculated value of playbackRate too. Not sure yet how best to represent this yet.)

Example usage

// Makes the character spin 180deg as you scroll the div
var timeline = new ScrollTimeline(div, "vertical");
timeline.play(new Animation(character, { transform: "rotate(180deg)" }, 100));

Note that this current approach doesn't require a subclass of AnimationPlayer like I thought it might.

Also note that by using a regular player you can have several animations tracking the same scroll container and then call pause(), reverse(), finish(), and update playbackRate etc. to take them out of the flow or change the way they track the scroll position. Setting startTime or adjusting the animation's delay can also allow offsetting them.

(Regarding the "auto" playbackRate behavior, the main problem is the '100' passed as the animation's duration would become completely arbitary. However, it's necessary since the default duration of an animation is zero so no matter what we set the playbackRate to we're not going to get meaningful times for running the animation.)

Implementation issues

If smooth scrolling is performed on the compositor, but the animation being scrubbed can only be run on the main thread we'll probably need to run the smooth scrolling interpolation code on the main thread as well.

Update: Apparently the main thread still gets scroll events (lagging behind a bit) and we can drive the animation from there.

Implementation strategy

We could probably start with a very limited subset that:

  • Is only enabled when OMTC and OMTA is enabled (no longer needed if we can drive main-thread animations via scroll events although it might be useful in terms of initially limiting the scope)
  • Throws an exception when trying to associate animation content that targets anything other than 'transform' with a ScrollTimeline (also, no longer needed?)
  • Simply fails to animate if preserve-3d etc. is set (anything that prevents us from doing OMTA but which could change from sample to sample) (As with the first point, no longer strictly needed)
  • Is only enabled for Gaia apps

Then we could gradually work at removing those restrictions in parallel with standardizing it.

Touch-based scrubbing

I'm not sure what the exact parameters would be here, but presumably we could use a similar approach.

Declarative syntax

If the API approach works, we could later map it to CSS using an animation-timeline property. Tab previously had some ideas around this.

Other timelines

I think there is potential for addressing some other use cases by providing further timelines:

  • FrameBasedTimeline - Some sorts of animations have fixed frames and they don't want to drop frames even if it leads to jank (e.g. [1]). This timeline would only increment the currentTime by a fixed amount on each sample (probably with some tolerance parameters).
  • WorkerTimeline - Only really useful for setting up animations consisting entirely of javascript callbacks (see "custom effects" in the spec) but that could still be useful e.g. for animating a CanvasProxy, WebGL (bug 709490) etc. using the same animation API