Server Notice:


Public Pad Latest text of pad venn9K2sr2 Saved June 3, 2013

Web Animations F2F
Present: Doug, Mike, Shane, Steve, Brian
What is needed for FPWD:
1 PathAnimationEffect issues
  - going through proposal
  - how to expose: incl. rotation
  - writing spec text
  - 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
1. PathAnimationEffect ISSUES
  - going through proposal
  - how to expose: incl. rotation
  - writing spec text
> 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;
Discussed deferring definitions of path calculations to SVG but we will add further clarifications as necessary since SVG does not define much.
 - remove paced sections
 - write a timing function section for paced(...) [include non-normative description of reverse-lookup]
  - defer path definitions to SVG
> 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 forward".
'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.
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 'replace'
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 keyframe.
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 wanted
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 evenly.
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), linear
  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
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 functions:
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 (timingFunctionPoints)
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.
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) {; };
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 follows:
* 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, oniteration
* 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 properties:
  - 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).
FPWD Tomorrow? (╯°□°)╯︵ ┻━┻)
No. ┬─┬? ︵ /(.□. \)
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. ). 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 issue.
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 time?
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); };
* What about putting events on the player
elem.animate({ opacity: '0' }, 1).player.onstop =
  function(evt) {; };
 - 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 behaviour.
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.
Next meeting: Thurs June 6 18:00 PDT / Fri 7 June 11:00 AEST / Fri 7 June 10:00 JST @