[web-anim] Web Animations Tokyo F2F, May 27, 28, 31

Web Animations Tokyo F2F, May 27, 28, 31

Present: Doug, Mike, Shane, Steve, Brian
Etherpad: https://etherpad.mozilla.org/ep/pad/view/ro.ym6OUGM4BAP/latest


1 PathAnimationEffect issues
   - going through proposal
   - how to expose: incl. rotation
   - pacing
2 Fill modes on descendants
3 Animatable properties - writing spec text
4 Keyframe offsets outside [0, 1]
5 Chained timing functions
6 Timing functions outside [0, 1]
7 Are chained timing functions enough?
8 Events
9 Accumulation
10 New DOM-style methods
11 Timing interface options -- needs an issue
12 Media integration - do we need for v1? for FPWD?
13 Animation priorities
14 Events revisited
15 Overflowing fill


 > Discussed how to approach pacing in the general case since we need to 
support pacing for more than just path animation effects (SVG allows 
calcMode="paced" on all animation types)

Add a new timing function, "paced(transform)"
  - 'transform' indicates the property to extract pacing information from
  - each animatable data type needs to define a notion of distance so 
pacing can be calculated
  - at an implementation level we effectively pass the animation effect 
to the (paced) timing function
  - if 'transform' is not one of the properties being animated by the 
animation effect linear interpolation is used

 > Discussed how to accommodate SVG's rotate parameters. One possibility

     attribute boolean autoRotate;
     attribute double rotateAngle;

 > Review Path animation effect section of: 

Discussed deferring definitions of path calculations to SVG but we will 
add further clarifications as necessary since SVG does not define much.


 > Discussed fill mode model alternatives.

Model A: Currently specified, a parent with a forwards fill causes 
cut-off children to fill forwards even if they are fill: none.

Model B: Child fill is always honoured - e.g. if a child is longer than 
the parent then the child fill will apply.

Noted that model A is problematic in the case of backwards fill since 
the children will be filled backwards regardless of their fill mode and 
yet this could actually be useful.

However, in order for model B to be useful, we probably need an 'auto' 
fill mode which means "use the fill mode of the parent unless there is 
no parent, in which case use auto".

'auto' fill mode uses the parent fill, unless you don't have a parent in 
which case the fill is 'forwards'.

 > Some discussion about whether this suggests we have an IDL member 
reflecting the 'computed' value of the fill mode.

We'll leave it out for now.

Drafted in 


 > Review animatable properties section of: 

Discussed categories of data types:

a) Not animatable (e.g. transition-name, transition-duration, SVG BiDi)
b) Animatable but not interpolable (e.g. display, position)
c) Animatable and interpolable (e.g. color, width, etc.)

Animations that specify (a) have no effect on the property, ever.

There is a 'composite procedure' which for (b) does something simple (ie 
always replaces), and for (c) applies the 'composite' operator 'add' or 

There is another 'find the intermediate value' procedure which for (b) 
chooses one of the end points and for (c) does linear interpolation

Discussed handling of keywords, shorthand value, relative values etc.

Relative values such as em units will be preserved using calc(). This is 
backwards compatible with CSS since the CSS bindings will simply feed 
the computed values to the model and not make use of this feature.

 > Shane to finish drafting animatable properties section.


Discussed options for keyframe offset outside (0,1) *again*.

Brian concedes that there can be some useful cases for defining values 
outside the range. For example, an animation that has a final value of 
green but defines 'orange' and 'red' keyframes as overshoot values.

What is the behaviour for a single value?

Basically, you construct a line from the underlying value at 0 to the 
specified value and interpolate along the line.  ie an 'add' keyframe at 
time fraction zero with the default value. If the single value is at 0, 
construct a horizontal line at the specified value. ie a keyframe at 
time fraction 1 with the same composite type and value as the first 

Drafted in 



A) Chains of whole timing functions:
   e.g. ease-in 0.3, cubic-bezier(0.3 0.4 0.7 0.8) 0.7, linear
-> Probably don't want timing functions on keyframes

B) Extend cubic-bezier
   e.g. cubic-bezier(0.3 0.4 0.7 0.8, 0.6 0.5 0.8 ... )
-> May or may not want timing functions on keyframes--easier if you *do*

C) Do nothing
   i.e. leave timing functions on keyframes and don't extend

Issues with A:
- Concern about the meaning of the trailing numbers after each function
- Difficulty of lining up timing functions with keyframes when this is 

Issues with B:
- Long string of numbers--not easy to read
- Requires having timing functions on keyframes

Issues with C:
- Can't do bounce effects
- Can't do complex timing functions that aren't bound to keyframes (e.g. 
on groups)

Proposal for A, if no offset values are specified, then align functions 
with  keyframes/points. This helps address the concern about lining up 
timing  functions with keyframes.

If  the list of functions differs in size to the list of 
keyframes/points:  match pairwise as far as you can then fill in the 
remaining segments with linear interpolation.
If no keyframes/points (groups, custom animation effect) then distribute 

So syntax looks like:

   ease-in, ease-out, linear

or (to space evenly):

   ease-in  0.33, ease-out 0.66, linear 1

Looking at the syntax, what are other options:

   ease-in to 0.3, cubic-bezier(0.3 0.4 0.7 0.8) to 0.7, linear to 1
   ease-in to (0.3, 0.5), cubic-bezier(0.3 0.4 0.7 0.8) to (0.7, 0.4), 
   ease-in 0.3 0.5, ...
   ease-in to 0.3 0.5, ...
   ease-in<0.3, 0.5>, ...
   0.3, 0.5: ease-in, ...
   scale(ease-in, 0.3, 0.5), ...

Another syntax proposal, split the x/y offsets into a separate property:

   timingFunction: ease-in, smooth cubic-bezier(...), ease-out
   timingFunctionPoints: (0.3, 1), (0.6, 0.2), (1, 1)

This makes the mode switch between aligning with keyframes or not explicit

If there are more functions than points, trim the functions list
If there are more points than functions, pad the end of the functions 
list with "linear"
So if you specify only points, you get a piecewise-linear curve

Drafted in 


Typically, timing functions are a transfer function from (0,0) to (1,1). 
However, if we allow keyframes offsets outside the range [0,1] and 
timing functions that line up with keyframes, the "effective timing 
function" (that is, the timing function you get when you piece all the 
per-keyframe timing functions together) no longer necessarily goes from 
(0,0) to (1,1).

Is this a problem? Does this break the model? Should we do something 
special in this case?

We *think* it is probably ok to break this invariant but we need to 
audit the timing calculations in the spec and make sure nothing depends 
on timing functions always going from (0,0) to (1,1).

Note that this can only occur on Animations - Timing Groups don't have 
keyframes with which timing functions can be automatically aligned - so 
the invariant is only weakly broken.

The other question is should we allow manually positioning timing 
functions outside the [0,1] range when using the chained syntax?

We think this is very rarely useful and can be added in a later version 
if necessary.

A further question: what happens with primitive timing functions when 
sampling outside the range [0,1]?

Stepping back, we observe that there are different kinds of timing 

1 Primitive timing functions: linear, cubic-bezier, ease-in etc.
   -- these *must* operate from (0,0)->(1,1) otherwise when you piece 
them together in a chain the corners won't match up and you'll have jumps
2 Chained timing functions
   -- there are two cases:
     (a) when the pieces of the chain correspond to keyframes
     (b) when the pieces of the chain have absolute positions 

For 2(b) we want to force that the composite (chained) timing function 
goes from (0,0)->(1,1)

For 2(a), however, it is ok if the composite timing function does not 
match this range--i.e. it isn't limited in x or y

Timing function and function points modes ...
* Primitive timing function mode: only one timing function specified, no 
timingFunctionPoints specified. You get the timing function applying 
over [0, 1]
* Matched timing function mode: more than one timingFunction specified, 
no timingFunctionPoints specified. Each timing function matches a pair 
of offsets (a segment), with synthetic keyframes counted. The 
timingFunction list is truncated or filled with 'linear' as appropriate.
* Custom timing function mode: timingFunctionPoints specified. Each 
timing function matches a pair of timingFunctionPoints. The 
timingFunction list is truncated or filled with 'linear' as appropriate. 
We match pairwise with timingFunctionPoints as far as possible then fill 
with linear.

In all cases, points outside the specified range are treated as linear 
with a gradient matching the boundary.

Drafted in 


Question: is this syntax suitable when you're trying to generate a 
timing function matching some existing curve? Is it complex to have to 
decompose the curve into pieces in a (0,0)->(1,1) box that is sometimes 
flipped? Should we *also* allow extended cubic-bezier syntax (i.e. 
multiple segments)?

Let's add the extended syntax to the spec and mark it at-risk.

 > Agreed that in the first version we want to provide just the lower 
level tools for expressing complex functions. In a subsequent version / 
spec we can add convenience shortcuts for expressing spring functions 
etc. easily (cf. the big list of pre-rolled functions in QML: 


Discussed the currently specced behaviour. The main problem with it is 
that it has two modes: seeked mode and normal mode. A good application 
will have to implement special handling depending on if an event was 
dispatched in seeked mode or not. Why not just always use seeked mode to 
simplify applications?

Another issue with the currently specced behaviour is that the use of 
uneased timing will sometimes cause events to fire at unexpected times 
(i.e. different to what is seen on the screen) and sometimes in a 
different order to what is observed.

So we have a situation where we want:
* To make sure seeking can be implemented in a manner that is constant 
in complexity when you have large seeks or when the device sleeps for a 
long period of time
* To produce something that can be used by CSS and SVG to implement 
their event dispatch (which dispatches all events)
* To be able to support simple useage from the API such as follows:

   elem.animate({ opacity: '0' }, 3).onend = function(evt) { 
evt.target.remove(); };

more generally

   elem.animate(...).onend = function(evt) { /* some cleanup */ };

We considered many models such as delta events, and setting time markers 
etc. but the model we currently think meets the requirements best is as 

* On a sample detect which items crossed an active interval boundary and 
which crossed an iteration boundary since the last sample. This 
calculation must be performed anyway in order to calculate the current time.
* At the API level, you can register to be called: onstart, onend, 
* For any item which crossed an active interval boundary and wasn't 
previously active, we call onstart; similarly, if we were active but no 
longer are, we call onend; and if the iteration has changed we call 
oniteration (and also if the parent iteration changed?). We haven't 
really worked out this definition but basically it has the following 
   - onstart, onend, oniteration are called at most once each per sample
   - if the item is active at the time of the sample, onstart will be 
called after onend (and vice versa). Not sure about oniteration. Is 
oniteration even that useful?
* Other users of the model, CSS and SVG, register instead for 
"timingchange" events which aren't exposed through the API.
   - there is at most one timingchange event per sample
* From a "timingchange" event you can get a list of changes that 
occurred since the previous sample. This procedure cannot be performed 
in constant time so we only call it from CSS/SVG and CSS/SVG may define 
limits where we don't perform this action. Furthermore, CSS/SVG would 
only call it when it had a registered event listener.
* At some point: either when producing the list of changes, or in the 
CSS/SVG part, we would also calculate the document time corresponding to 
each event. This will require inverting timing functions which sounds 
tricky but Mike is keen to work on it.
* SVG/CSS can then use the document time to sort events as necessary. 
I'm not yet sure how this work with regards to sorting times that occur 
at the same time but have a defined order.
    e.g. If a parent and child start at the same time, the child start 
event should come *after* the parent's, but if it's an end event it's 
the opposite order (since children operate *inside* their parent's time)

Do we need oniteration? Probably not.

The behavior of onstart/onend may be confusing since the number of times 
they get called is dependant on the sample rate. If that proves 
confusing, we may switch to simply generating change events with some 
parameters such as isActive. The event handler would then switch 
behavior based on that attribute (i.e. implement onstart/onend in the 
one function).


Looked at how to define accumulation when you have to-animation (or more 
generally, any keyframe animation effect with a mix of add/replace 
composition operations). We need to be compatible with SVG here (which 
disallows accumulation on to-animation).

We tried many solutions but none of them make sense whilst preserving 
SVG's behaviour here. Decided, for now at least, simply to ignore the 
accumulate operation if you have a keyframe animation effect where the 
composition operations are not uniform.

For those cases where the composition operation is uniform we simply 
follow what SVG does there (i.e. add the last value of the function * 
current iteration)


Went through proposed changes to API to match newer DOM-style methods 
(cf. http://dom.spec.whatwg.org/#childnode ). One issue raised is that 
DOM uses children to address the children of a node. Should we add a new 
interface TimedItemList and put length / item() on that.


Brian doesn't really like the separate object, but too bad, put it in an 

12. MEDIA INTEGRATION - do we need for v1? for FPWD?

 > Split it off into a separate spec.


First issue: We need a step before sorting by start time so that we can 
enforce CSS Animations beating CSS Transitions.

Second issue: We probably *don't* want to sort by effect start time but 
by player start time. We ran through various examples of animation 
hierarchies targetting the same property and it was clear that in all 
cases it is more intuitive if the animation in the player that started 
later wins, even if this animation actually started earlier than the 
animation in the other player.

-> What about within a hierarchy though? If you have two animations in 
the same tree targetting the same property? In this case tree order 
seems to make most sense. Tree order being depth first search 
(preorder/postorder doesn't matter since only the leaves animate).

Third issue: What to do when you have the same priority and player start 
Suggestion is to make player start order unique. So you record not only 
the player start time but the order in which each player was started. 
This provides control to CSS/SVG bindings etc. to say, for example, 
"start this player before that player" and thus control the priority.

Fourth issue: Why do we need priority on custom effects? This is because 
the order in which custom effects are executed is quite significant. 
Normally animation priority just controls the order in which stuff is 
combined but here it actually defines execution order so more control 
may be required. For now, let's leave it and add an issue mentioning 
that it may be at risk.


Some other ideas tossed around:
* Only generate change events with a lazily-generated list of changes 
each of which has a lazily-generated document time
* Do we provide onstart / onend shortcuts? They make things simpler but 
could be confusing since the number of times they get called is 
sample-rate dependent.
* What about only generating change events, e.g.
elem.animate({ opacity: '0' }, 1).onchange =
   function(evt) { if (!evt.isActive) evt.target.targetElement.remove(); };
* What about putting events on the player
elem.animate({ opacity: '0' }, 1).player.onstop =
   function(evt) { evt.target.source.targetElement.remove(); };
  - this is neat but doesn't help with a lot of interesting use cases

Justification doc


What happens if you specify a timing function on a group that overshoots 
the 1 value? (e.g. a spring function). During the overshoot phase the 
value passed to child timed items will be outside the children's active 
interval causing them to go into fill behaviour and effectively be 
clipped. This is probably not what you want since you effectively can't 
use such timing functions on groups and get extrapolated behavior.

 > Decided to pass extra state from parent to child saying basically, 
"I'm in my overflow/underflow range" and then the child performs 
extrapolation. It basically treats the time as if it's inside its active 
interval but doesn't increment the iteration index---it is extrapolation 

We only set this flag for children that touch the edge of the parent's 
iteration interval (or alternatively we pass down two times: iteration 
interval begin/end, and transformed time).

There are more details to work out but basically we think this is 
solveable and plan to address it after FPWD.

FPWD TODO: https://etherpad.mozilla.org/fUBir8RYin

Next meeting: Thurs June 6 18:00 PDT / Fri 7 June 11:00 AEST / Fri 7 
June 10:00 JST @ https://etherpad.mozilla.org/84QUWWDtwi

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

Received on Friday, 31 May 2013 06:21:18 UTC