[web-anim] Web animations minutes, 17 / 18 December 2012

Web animations minutes, 17 / 18 December 2012
(Bumper Christmas edition)

Etherpad: https://etherpad.mozilla.org/ep/pad/view/ro.McqSq5rhwYm/latest
Present: Dmitry Baranovskiy, Steve Block, Shane Stephens, Douglas 
Stockwell, Brian Birtles

Agenda:

1. Status update
2. Keyframe revision
3. Comparing with QML
4. Comparing with Core Animation
5. Feedback from Rob Arnold
6. Null animation function
7. Interaction with script
8. Time sources
9. Fixing Anim.duration vs Anim.timing.duration
10. The chopping block
11. GroupedAnimationEffect
12. Override stylesheets
13. Animation stack & Keyframe animations
14. Default fill mode


1. STATUS UPDATE
================

Brian:
* Writing up events stuff

Shane:
* Travelling, polyfill hacking, talking to interested Googlers about Web 
Animations


2. KEYFRAMES REVISION
=====================
(Brian)

I've revised the keyframes interfaces with the following changes:
* Add ctors
* Redone the way we interpret values to the ctor since 
sequence<DOMString> and sequence<KeyframesDictionary> are not 
distinguishable
* Add a distribute method to space all the keyframes out evenly

This distribute method in particular hopefully makes it easier to 
add/remove keyframes whilst keeping them equally spaced.

(I had another proposal here where we allowed null offsets that meant 
'space me out evenly' but it was complex so I dropped it.)

Shane: LGTM.

3. COMPARING WITH QML
=====================
(Brian)

ben 
(http://brian.sol1.net/svg/2012/10/31/web-animations/comment-page-1/#comment-38011) 
suggested we consider QML
http://doc.qt.nokia.com/4.8-snapshot/qdeclarativeelements.html

Some observations:
* Many features are similar, even the parallel and sequence animations 
are similar. That's good news.

* SpringAnimation element
    -- could be realised with the proposed SmoothTimingFunc and then add 
some syntactic sugar to make bouncing animations easier
    -- I've asked Pomax (author of 
http://processingjs.nihongoresources.com/bezierinfo/) for some help with 
SmoothTimingFunc.

* Includes a PauseAnimation -- temporal equivalent of a spacer gif
    -- worth adding?
    -- Shane: I have an alternative approach that is simpler than a new 
primitive (and also useful for the trigger stuff :))

* Terminology
    -- They don't have groups. Should we just call ParAnimGroup, ParAnim?
    -- Shane: I think distinguishing between groups and root animations 
is useful.

* Uses ms (integer) for duration. window.setTimeout etc. use ms as well. 
Perhaps ms are more common on the web platform? Should we use ms 
instead? And if so, is an integer too imprecise?

Shane: No! Seconds are really easy to use and make code look good.

Brian: some data gathering...
window.setTimeout - long - milliseconds
window.setInterval - long - milliseconds
XMLHttpRequest.timeout - unsigned long - milliseconds
HTMLMediaElement.duration - unrestricted double - seconds
Date.getTime - milliseconds
PerformanceTiming.* - milliseconds
PerformanceNavigationTiming.* - DOMHighResTimeStamp (double) - milliseconds
CSS Animation/TransitionEvent.elapsedTime - float - seconds

➙ Agreed to stick with seconds (double) in particular to line up with 
HTMLMediaElement and CSS animation/transition events and also because 
longs representing milliseconds do not offer enough precision.


4. COMPARING WITH CORE ANIMATION
================================
(Brian)

I've had a bit of a look over Core Animation to see how similar we are:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html

At a glance it looks like we're pretty close since it's based on SMIL 
and CSS Transitions/Animations is based on Core Animation.

Some naming suggestions:

  * Core Animation uses beginTime and timeOffset -- it has the same 
double-offset!!!! We are not crazy!
    * Some renaming possibilities here:
      * s/startTime/beginTime/
        * startTime: 'start' just seems friendlier, matches HTML5 text 
tracks
        * beginTime: matches CoreAnimation, close to SVG (begin attr)
        * NOTE: HTMLMediaElement has startDate (was 
startTimeOffset/startTime/initialTime) which is the initial offset into 
the resource
      * s/startDelay/beginOffset/
        * startDelay: close to CSS (animation-delay)
        * beginDelay: relationship to beginTime is obvious (assuming we 
go with that), close to CSS (animation-delay)
        * beginOffset: relationship to beginTime is obvious (assuming we 
go with that), close to Core Animation (timeOffset)
        * NOTE: HTMLMediaElement has startDate (was 
startTimeOffset/startTime/initialTime) which is the offset into the resource

➙ Agreed to stick with startDelay and startTime

Rationale: delay is a lot clearer than offset. "beginDelay" sounds 
silly. Therefore "startDelay". Therefore "startTime".

  * Core Animation uses fillMode where we have fill
    * fillMode: matches enum name (FillMode), Core Animation (fillMode), 
CSS (animation-fill-mode)
    * fill: matches SVG, shorter
    * 2012-11-30[Brian]: Renamed fill to fillMode

  * Core Animation uses timingFunction where we have timingFunc (see 
above where I suggest we go with timingFunction)
    * 2012-11-29[Brian]: Renamed
    * This was discussed informally at the time and included in the 
minutes from 2012-12-11.

  * Core Animation uses speed where we have playbackRate
    * the reason we went with playbackRate was to match 
HTMLMediaElement. I think that wins.

  * Our Timing object is represented in CoreAnimation by a MediaTiming 
interface

➙ Some general sense that an interface may be preferable here. Will 
consider when we discuss how to refactor defaults and so on.

  * Core Animation uses parent time, active local time (=our item time), 
basic local time (=our iteration time)
    * There's no animation time but even in our model, animation time is 
really an implementation detail. In terms of the API it's irrelevant. 
Maybe we should try to hide it a bit more. The time spaces diagram 
appears quite complicated.
    * Should we rename?
      * iteration time -> basic time (SMIL calls this simple time)
      * item time -> active time (SMIL calls this active time)

➙ Iteration time is more descriptive than basic time

Item time is not great. It's also quite similar to iteration time. How 
about local time?

➙ We'll give local time a try

Shane, Steve: If we have a time window then we could have 
timeWindow.activeTime instead of animation time

➙ Rename animation interval to active interval.


5. FEEDBACK FROM ROB ARNOLD
===========================
(Brian)

“I think it would be helpful to have examples to use examples for 
individual features (ex: seeking; I haven’t seen a need for that yet) 
and indicate what areas the API is intended to be used for (games, rich 
content, ui?)”

➙ Yes. We should put this in a different document (a primer). We will 
also increase the number of examples in the specification, but these 
will be for the purpose of illuminating how the specification works 
rather than justifying the decisions made in the specification.

“I am sadly quite well aware that CSSOM for Transitions/Animations is 
painful so having a good API there which addresses mutation (O(n²) to 
remove all keyframes of an animation in WebKit) and triggering (no 
awkward forced synchronous style calc) would be helpful.”

This ties into Shane's desire to expose web animations objects as 
CSS/SVG manipulators.

"One thing that I do think is important but not addressed in the spec is 
concurrency (I assume that this is what you meant by hardware 
accelerated animations). In particular, asynchronous animations are 
highly useful in covering up main thread lag due to events or 
implementations beyond the author's control. This is key on mobile where 
performance expectations are high due to a direct manipulation UI but 
processing power is weak. As a motivating example, consider trying to 
implement a feed of mixed content (say, Facebook's newsfeed) with native 
quality scrolling. Things like garbage collection, image decoding, 
style/layout from new content being inserted and time mysteriously 
unaccounted for (thanks Chrome!) disrupt the framerate 
during/transitioning into fling scrolling (which can use CSS animations 
for better physics / dependable scroll position events). The current and 
proposed APIs seem to assume some sort of synchronous execution between 
the JS and on screen animation; for this reason I like asynchronous 
events so that the animation thread isn't stalled by content."
  * I (Brian) followed this up and Rob provided the following 
clarification: "I think there are some implicit assumptions in the API 
such as the relation between the start of an animation and when you tell 
it to start; with asynchronous animations, you'll need to account for a 
delay (due to vsync, IPC overhead, etc...) and the page may want to take 
that into account when computing its UI."

Some discussion on synchronicity of events and the possible use of 
observers.

 > Brian to continue speccing events without observers.
 > Shane to show events model (once specced) to observers guys and see 
what they think.

This could also be about the delay between calling start() and when the 
animation first updates. This would cause a jump.

We might add a feature in a future version for“start this animation asap 
but whatever you do, start from the beginning”
  → startASAP()?
  → base it off a trigger?

“I do like that you can compute the animation in JS with your own 
internal structure and then have the browser query that instead of 
shoving it into the CSSOM (creating a lot of garbage via string 
allocation).”
  * I asked, “I just want to check I've understood this part. Are you 
referring to CustomAnimFunc? If that's the case, then the user-supplied 
function just applies the effect itself. It doesn't return anything to 
the browser.”
  * To which Rob responded: “Oh, I thought that it was to allow JS to 
specify the animation curve so that the browser can asynchronously 
render it. This is an example of where I mean that the spec does not 
seem to permit an asynchronous (multithreaded) implementation.”

Perhaps Rob simply was referring to the fact that you can build up an 
animation entirely from script without going through the CSSOM.

“Oh, and if we could get instrumentation on how well the animation was 
played back (frame level timing would be sufficient) then that would 
really help our testing I suspect.”
  * Rob later helped with some ideas about how to get this data when 
animations are offloaded to the GPU, “I suspect that it's not too tricky 
to get the data; exposing it to script may be hard. There is a GL 
extension (even available on some mobile devices) called GL_timer_query 
which lets you time the GPU pipeline. DirectX has had a similar API for 
a while.”

➙ Maybe a future version but some concern about all vendors being 
willing to expose this information


6. NULL ANIMATION FUNCTION
==========================
(Brian)

Does it make sense to allow Animation.animationFunction to be null-able?

The reason this comes up is that if you call
    new Animation(elem, { '-moz-transform': 'translate(-60)' });
This calls
    AnimationFunction.createFromProperties({'moz-transform': 
'translate(-60)'});

On a UA that doesn't support '-moz-transform' the algorithm there will 
mean createFromProperties returns null. I think this is correct 
behaviour and there's an example in the spec of where the null behaviour 
can be useful.

But then, what is 'new Animation' supposed to do?

a) Just set animationFunction to null?
b) Throw an exception saying its bad input?
c) Make some sort of generic function to fill in its place?

I don't think (c) is really great since I can't think of a suitable 
function for that unless you make a KeyframesAnimationFunction with a 
blank property and no frames?

(b) warns you about the error but it will commonly mean that for a given 
browser that the author hasn't tested the content with that doesn't 
support said property, everything grinds to a halt. Whereas with (a) it 
continues, it just does nothing.

The downside of (a) is that there's no visible warning and every time 
you access Animation.animationFunction you need to check if it's null or 
not. That said, Animation.animationFunction is already of type 
(AnimationFunction or CustomAnimationFunction) so you probably should be 
checking the type there anyway.

So my vote is (a) unless someone can suggest a good function for (c).

Note that making an animation function with '-moz-transform' as the 
property EVEN on UAs that don't support it isn't an option due to the 
way we process that property bag in order to avoid indeterminancy (it's 
complicated).

Shane: I'm totally down with (a). It's the minimum specification effort 
approach :-D


7. INTERACTION WITH SCRIPT
==========================
(Brian)

I think we need to clearly specify three things regarding liveness and 
scripting:

  * If I change any of the values (e.g. the duration), do all the other 
timing values immediately update? (e.g. end time)

Brian: suggest yes
Shane: polyfill does

  * Does the target property(ies) update? e.g. does the computed style 
of the height I'm animating instantly update? (i.e. do we do a 
synchronous sample in effect) or does it lazily update? (i.e. if I query 
it I'll get the updated value but I won't see any change in rendering 
otherwise)

Brian: suggest no update until current script block completes
Shane: "until the script block finishes". This is good enough.

  * In a given script block is it possible for a clock tick to occur? 
(i.e. can the value I get back for the currentTime of the global clock 
at the start of a script execution block differ from the one I get back 
at the end of the script execution block)

Brian: suggest no
Shane: there's a specific hack in the polyfill to implement no here :-)

Shane: ... so I think this is all LGTM.


8. TIME SOURCES
===============

Awaiting Shane's description of Timeline → Time source transformations

Shane: Sorry, still no progress here :(


9. FIXING Anim.duration VS Anim.timing.duration
===============================================
(Brian)

Long discussion based largely on the fact that we have the following 
arrangement:

  * Anim.duration -- read-only, calculated iteration duration
  * Anim.timing.duration -- read/write, nullable, specified iteration 
duration

This is not great. Full notes of proposals are available on the 
etherpad: https://etherpad.mozilla.org/ep/pad/view/ro.McqSq5rhwYm/latest

In summary they include:

* Renaming Anim.timing to Anim.defaults
* Pushing the timing members into Anim, e.g. Anim.defaultDuration (cf 
HTMLMediaElement's defaultPlaybackRate)
* Dropping defaults and putting everything on TimedItem. Values 
initially reflect computed values unless they are overridden.
* Make attributes represent live/calculated values. Add accessor methods 
for fetching or resetting to default/specified values.

This discussion has led to the notion of having a "default" set of 
values and a "live" set similar to CSS' specified and computed style.

This allows an animation to be reversed without affecting the 
animation's serialized state. The approach used here can likely be 
re-used for templating and has led to a "time window" proposal where the 
default values establish the "box" into which the animation is played 
and changes to the live values do not effect it.

Related only vaguely, the idea was also floated about separating out 
interfaces. For example, TimedItem simply represents an item in the time 
graph with a start and end time, whilst subsequent interfaces add time 
transformations and so on. This approach attempts to reduce the 
complexity of TimedItem using inheritance instead of composition.

 > Brian to come up with a different proposal


10. THE CHOPPING BLOCK
======================
(Brian)

What can we drop from v1 to make things simpler and faster to ship?

My (Brian's) suggestions:
  * Templates
    * Lots of complexity here. I think if we make animations easily 
cloneable and add convenience methods that take a DOMNodeList/sequence 
and generate the necessary animations we'd get 80% of the convenience. 
For controlling multiple running animations we have groups that cover 
some of the cases.
    * The main argument for keeping templates that I can see is because 
implementations are going to have to implement something like templates 
anyway in order to manage changes to animations generated by markup so 
why not formalise this behaviour from the start?
    * Shane: I have some feedback from web developers too - the 
"immediate" effect of Animation objects is strange to them but the 
ability to create Templated animations ameliorates this significantly.
      * Brian: Is this about animations playing as soon as you create them?

Doug, Steve and Shane had a bit of a discussion on what to do with 
templates:
https://docs.google.com/document/d/1JYHXUJy-vaaw6C_zAh1vDpuQUVczegu6UZNeZ6U0z5s/edit
Brian: Looks good. I think we need to work out how defaults should work 
first, then consider how template-like behaviour would fit in.

  * Merging
    * It's great but I'm not sure if it's necessary for currently 
pressing use cases. We should still work on it to make sure when we do 
go to add it the architecture doesn't explode.
    * Shane: We've agreed it's necessary to make "to" animations clean. 
I'm still in favor of including it because it doesn't add very much 
complexity at all, and the merge behavior still needs to be specified 
regardless.

➙ Shane to add diagrams.
➙ Need to talk about grouping and parameterized merge in more detail in 
a future meeting.

  * Sharing of Timing objects
    * Really, how often will this be done?
    * Shane: if we don't allow timing objects to be shared, then *that* 
is when we have to start specifying stuff. They share naturally.
    * Brian: In section 9 I'm proposing removing them for other reasons.
    * Shane: There *will be* an object or objects with default values 
that are accessible from script. It is more natural to allow these to be 
shared than not. Having said that, the templating stuff that we were 
looking at before might in fact imply these should not be sharable anyway.
  * TimingFuncCallback
    * This adds a lot of complexity (just see the massive TODO there) 
and if we have SmoothTimingFunc then I think we can cover most cases.
    * 2012-11-29[Brian]: I already removed this feature
    * Shane: I support this
  * TimedItem.animDuration
    * Easy to calculate, but necessary?
    * Shane: probably not. Also tiny. Defer removal unless we have to?
  * TimedItem.locallyPaused
    * Again, simple, but necessary? Would pause(), play() and unpause() 
be enough? (We currently don't have unpause but MediaControllers do. The 
difference is basically that it wouldn't auto-rewind.)
    * Shane: this falls out *SO CLEANLY* in code! I'd be reluctant to 
remove.
      * Brian: It doesn't mean you remove the code, just that you hide 
it from view.
      * Maybe mark at risk?


11. GroupedAnimationEffect
==========================
(Brian)

Genuine question, is it needed or should it be merged with 
KeyframeAnimationEffect?

What is it used for that couldn't be achieved by making 
KeyframeAnimationEffect support targetting multiple properties like you 
can do in CSS?

Of course, you could re-use timing to apply to a PathAnimationEffect and 
KeyframeAnimationEffect, but do you do that often enough that you 
couldn't just set up a group for that?

I guess doing so would be contingent on being able to represent that 
arrangement in SVG? Or maybe not since changes to Animations don't 
reflect back to SVG.

Shane: I'm not fussed either way. We do have a request to support a 
group constructor that has keyframe offset as the primary key (rather 
than property) - it would be natural to put this on a group; but less so 
on a keyframes object directly I think.

Shane: Also it's important to keep in mind that groups were initially 
included for the purpose of grouping operations inside the compositor. 
I've got some proposals that would stop this from happening - we should 
at least review those before committing to removing groups.

Also, I'd like to make KeyframeAnimationEffect a bit more friendly to 
use by allowing operations such as:

    effect.frames.add(0.3, 'left', '100px');
    // Overwrites the frame at 0.3 if there is one

Currently, you need to do:

   effect.frames.add({ property: 'left', offset: 0.3, value: '100px' });

It might even be worth supporting:

   var frame = effect.frames['0.3'];

Returns the last frame with offset 0.3 if there is one. If there is 
none, does the interpolation and returns a new frame?

Shane: Is this sort of thing something we should defer until v2? It 
would sit cleanly on top of a more primitive API (and could be 
polyfilled very nicely in the short term).

 > Leave this for now (but make an annotation that these may be possible 
future improvements)


12. OVERRIDE STYLESHEETS
========================

How are we going here? What was the issue even?

Shane: The issue is that Animations and Transitions in CSS inject into 
different places in the stylesheet stack. It doesn't actually matter too 
much though - time sources basically make this problem go away because 
we can have a time source per injection point.

 > We're looking good at the moment


13. ANIMATION STACK & KEYFRAME ANIMATIONS
=========================================

(Continuing actions from a previous meeting regarding merging and 
behaviour where no keyframe is defined)

what should [{offset: 0.5, left: 100px}] do?
( polyfill currently does this: [{offset: 0, left: 0px}, {offset: 0.5, 
left: 100px}, {offset: 1, left: 0px}] )
( CSS animations snapshot document state and fill in missing values with 
that )

 > We will revisit this later


14. DEFAULT FILL MODE
=====================

Feedback suggests "both" instead of "forward"

 > Mark as an issue in the spec


Next meeting: Mon Dec 7, 17:30 PST / Tues 8 Jan 12:30 AEDST / Tues 8 Jan 
10:30 JST @ https://etherpad.mozilla.org/6dtzemgWAe

Past meetings: http://www.w3.org/Graphics/fx/wiki/Web_Animations/Meetings

Received on Tuesday, 18 December 2012 07:10:04 UTC