[web-anim] Web Animations minutes, 1 / 2 May 2013

Web Animations minutes, 1 / 2 May 2013

Etherpad: https://etherpad.mozilla.org/ep/pad/view/ro.Ym0Dvh3bo6f/latest
Present: Doug, Dmitry, Shane, Brian

Agenda:
1. Status update
2. Keyframe shortcuts
3. Extending timing functions
4. Representing timing parameters
5. Starting animations now-ish


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

Brian:
- Finishing off timing events, esp. the non-normative dispatch algorithms
- Keyframe animation effect changes
   - allow targetting multiple properties
   - allow per-value composition mode
   - remove timing functions from key frames
   - redoing the IDL

Shane:
   - Some blink implementation work


2. KEYFRAME SHORTCUTS
=====================
(Brian)

I've reworked the keyframes part as described in the status update and 
also updated the IDL to match.

Using the dictionaries as-is, you end up with a syntax like this:

   [
     {
       values: [
         { property: 'left', value: '50px', composite: 'replace' },
         { property: 'top', value: '50px', composite: 'replace' }
       ],
       offset: 0
     },
     {
       values: [
         { property: 'left', value: '100px', composite: 'replace' },
         { property: 'top', value: '100px', composite: 'replace' }
       ],
       offset: 1
     }
   ]

Using default values for 'composite' and 'offset' you can get it down to:

   [
     {
       values: [
         { property: 'left', value: '50px' },
         { property: 'top', value: '50px' }
       ]
     },
     {
       values: [
         { property: 'left', value: '100px' },
         { property: 'top', value: '100px' }
       ]
     }
   ]

For animating a single property only it becomes:

   [
     { values: [ { property: 'left', value: '50px' } ] },
     { values: [ { property: 'left', value: '100px' } ] }
   ]

And for the simplest case, to-animation, it becomes:

   [
     { values: [ { property: 'left', value: '50px' } ] }
   ]

The last two are very common and there are a *lot* of braces and commas 
involved for a simple effect.

So I started investigating shortcuts and came up with two basic options:


Option 1, in the KeyframeAnimationEffect ctor / setFrames / 
Element.animate support the following shortcuts:

   { left: '50px' }
   { left: [ '50px', '100px' ] }

e.g. elem.animate({ left: '50px' }, 3);

Notes:
* Only one argument is supported (this avoids the precision issues that 
arise when trying to line up the offsets of parallel arrays)
* This only applies at the top-level. Basically we test if the argument 
is an array or an object and process differently.

i.e. you can do:

   keyframeEffect.setFrames({ left: '50px' })

or,

   keyframeEffect.setFrames([ { values: [ { property: 'left', value: 
'50px' } ] } ]);


Option 2 consists of two parts.

Firstly, (a) introduce the following as a short-cut for a Keyframe 
dictionary (i.e. a single frame) so it can be used anywhere a Keyframe 
dictionary can be used:

   { left: '50px' }

Doing that means setFrames becomes:

   keyframeEffect.setFrames([ { left: '50px' } ])

Two-valued animation becomes:

   keyframeEffect.setFrames([ { left: '50px' }, { left: '100px' } ]);

For the single-keyframe case the extra array [] braces seem unnecessary 
and would be particularly noticeable with Element.animate since it would 
become:

   Element.animate([ { left: '50px' } ], 3);

Which is frustrating for something you do a lot.

So, as a second step (b), introduce an additional shortcut to these 
methods that accepts a single object or an array.

This would let you do:

   keyframeEffect.setFrames({ left: '50px' })

Also, since there's no array shortcut (unlike Option 1), we can safely 
allow multiple properties. This makes the following possible:

   keyframeEffect.setFrames([{ left: '50px', top: '50px' }, { left: 
'100px', top: '100px' }]);


In essence what we're doing is introducing a type KeyframeShortcut 
which, as with Option 1, you can't represent in WebIDL due to 
limitations regarding iterating object properties. That's fine since we 
can add ECMAScript-specific prose to describe how to achieve this in a 
safe way.

Then we do as follows:

   typedef (Keyframe or KeyframeShortcut) KeyframeOrShortcut;
   typedef (KeyframeOrShortcut or sequence<KeyframeOrShortcut>) 
KeyframeParameters;

e.g.

   void setFrames(KeyframeParameters frames);

We can distinguish a Keyframe object from a KeyframeShortcut object by 
testing for the presence of a 'values' property.

Regarding the offset property, we could either:

(a) 'offset' maps to a CSS property called 'offset'--if you want to 
specify the offset you have to use the full syntax.
(b) 'offset' maps to the keyframe positional offset. If an 'offset' CSS 
property is ever introduced, either:
  - you won't be able to animate it using the shortcut
  - we'll introduce some other name especially for it, e.g. 'cssOffset'
(c) Rename the offset member of the KeyFrame dictionary now to avoid 
risk of a later clash, e.g. 'keyframeOffset'

I kind of gravitate towards (b) since it makes the following possible:

   elem.animate([{ left: '50px' }, { left: '100px', offset: 0.7 }]);

This seems like a fairly natural syntax and the likelihood of an 
'offset' property being introduced seems somewhat low? (we have lots of 
xxx-offset properties but no bare 'offset').

Note that to set a per-value composite operation you have to use the 
full syntax.

e.g.

   keyframeEffect.setFrames(
     [ { values: [ { property: 'left', value: '50px', composite: 'add' } 
] },
       { values: [ { property: 'left', value: '0' } ] } ]
   );

That's pretty verbose but this is probably an advanced use case. The 
main situation where you would want to mix composite modes is 
to-animation which can be handled using the shortcuts.


Overall I think Option 2 is preferable to Option 1 since it doesn't 
deviate as far from the canonical representation. The API remains 
frame-based; it doesn't provide a pseudo-property-based mode. That's a 
win from an understandability point of view: authors aren't switching 
between two modes of thinking.

Furthermore, Option 1 suffers from the inconsistency of supporting a 
short-hand syntax for single-property animations but not for 
multiple-property animations. That's likely to surprise authors and is 
also inconvenient.

The cost is verbosity for the case where you want to do this:

   left: 50, 150, 80, 300, 200, ....

Since it becomes:

   elem.animate([{ left: '50px' }, { left: '150px' },
                 { left: '80px' }, { left: '300px' },
                 { left: '200px' }, ...]);

I think for now it's trivial to write a utility function to generate 
that list. If *everyone* is doing this we can investigate other 
shortcuts later--perhaps even another type of AnimationEffect that is 
property-based (i.e. one property only and takes a list of values). For 
version 1 we ship the animation effect that matches CSS most closely.

➙ Assuming we can make/alter key frame animation effects from the API, 
Option 2 seems best.

➙ With regards to the offset property, we prefer option (b)

Shane: I'm happy to go with this frame-based approach because it matches 
the status quo. I would like to provide feedback that as a developer a 
property-based approach is easier for me to deal with. However it is 
worth noting that a polyfill converting property-based definitions to 
keyframe-based definitions is reasonably trivial.


Brian: And now for something completely different: another alternative 
is to not allow creating animation effects from the API at all in v1. 
Rather, you point to either a CSS animation name or an SVG animation 
element and it gets its animation function from there.

Shane: This would mean being stuck with CSS animation syntax for complex 
DOM animations that aren't SVG animations.

Doug: One disadvantage with this approach is that it makes doing 
dynamically generated animations really hard.

➙ Based on experience with Raphaël and a quick survey of whether people 
are actually generating animation effects dynamically, we think the 
ability to create animation effects from the API is necessary after all.


3. EXTENDING TIMING FUNCTIONS
=============================

Recap: Google Sydney team to look at tweaking approach/syntax to reduce 
cognitive load, make more readable etc.

ACTION: Sydney team to actually do this

Other related actions while we're at it:

ACTION: Steve to write design doc for media integration
ACTION: Shane to turn Steve's design doc into spec prose
ACTION: Doug to write spec prose for path effects
ACTION: Shane to write prose for sections 22 and 23
ACTION: Sydney team to review Events
ACTION: Sydney team to review sections 17 – 21


4. REPRESENTING TIMING PARAMETERS
==================================

Issue: Dictionary only? Timing interface? Duration member?
(see: http://lists.w3.org/Archives/Public/public-fx/2013AprJun/0063.html)

Shane: I talked to Elliot about this. He was pretty convincing that we 
should have a TimingDictionary and a Timing interface, and that doing 
iterationDuration.string / iterationDuration.seconds (or whatever) is 
not a great idea.

Reasons:
- Promoting duration etc. to interfaces may be costly from an 
implementation point of view
- Verbosity: iterationDuration.sec is longer than iterationDuration 
(Brian's counter-point: specified.iterationDuration is longer than 
iterationDuration.string; Shane: but iterationDuration is more likely to 
be used than specified.iterationDuration)
- Duplicating the Timing interface members as a dictionary is no 
problem. That's what dictionaries are for.

Shane's additional reason: hiding the layout computation away behind a 
'unit conversion' seems to be mixing things up.
Brian: SVG already does that.
Shane: but CSS doesn't, and CSS is much more widely used.

Brian has reservations that the TimingDictionary / Timing approach might 
be confusing because of the separation between specified and computed 
timing that this approach implies. Not sure it's necessary to introduce 
this concept. Shane feels that this will be familiar to users of CSS.

➙ Go with Timing / TimingDictionary for now, introduce an issue into the 
specification that details the .string/.sec approach to get wider feedback.


5. STARTING ANIMATIONS NOW-ISH
==============================

Summary: To support CSS properly, it's nice to be able to have a 
start-when-ready (this is so that the compositor can slip start-time 
until the next available vsync, after painting a new layer, etc. etc.). 
We'll need to implement something like this. Should we expose it?

Some discussion about whether play or playNow should be the default 
(e.g. play / playNow or play / playSoon)?

➙ Leave it out of the FPWD but consider introducing it shortly 
afterwards. Add an issue so we don't forget.


Next meeting: Thurs May 9 18:00 PDT / Fri 10 May 11:00 AEST / Fri 10 May 
10:00 JST @ https://etherpad.mozilla.org/NIDeLZFzCR

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

Received on Thursday, 2 May 2013 01:12:39 UTC