- From: Brian Birtles <bbirtles@mozilla.com>
- Date: Fri, 31 May 2013 15:20:49 +0900
- To: "public-fx@w3.org" <public-fx@w3.org>
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
Agenda:
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
1. PATH ANIMATION EFFECT ISSUES
===============================
> 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:
https://docs.google.com/document/d/1D40pVzgWeYCivDxG6FFKgiZW7p4CuE_395iT8sTMklo/edit#heading=h.5s8u06mlsdmq
Discussed deferring definitions of path calculations to SVG but we will
add further clarifications as necessary since SVG does not define much.
2. FILL MODES ON DESCENDANTS
============================
> 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
https://docs.google.com/a/google.com/document/d/1D40pVzgWeYCivDxG6FFKgiZW7p4CuE_395iT8sTMklo/edit#
3. ANIMATABLE PROPERTIES
========================
> Review animatable properties section of:
https://docs.google.com/document/d/1D40pVzgWeYCivDxG6FFKgiZW7p4CuE_395iT8sTMklo/edit#heading=h.5s8u06mlsdmq
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.
4. KEYFRAME OFFSETS OUTSIDE [0, 1]
==================================
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.
Drafted in
https://docs.google.com/a/google.com/document/d/1D40pVzgWeYCivDxG6FFKgiZW7p4CuE_395iT8sTMklo/edit#
5. CHAINED TIMING FUNCTIONS
===========================
Options:
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
Drafted in
https://docs.google.com/a/google.com/document/d/1D40pVzgWeYCivDxG6FFKgiZW7p4CuE_395iT8sTMklo/edit#
6. TIMING FUNCTIONS OUTSIDE [0, 1]
==================================
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.
Drafted in
https://docs.google.com/a/google.com/document/d/1D40pVzgWeYCivDxG6FFKgiZW7p4CuE_395iT8sTMklo/edit#
7. ARE CHAINED TIMING FUNCTIONS ENOUGH?
=======================================
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:
http://qt-project.org/doc/qt-4.8/qml-propertyanimation.html#easing.type-prop)
8. EVENTS
=========
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
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).
9. ACCUMULATION
===============
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)
10. NEW DOM-STYLE METHODS
=========================
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.
11. TIMING INTERFACE OPTIONS
===========================
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.
13. ANIMATION PRIORITIES
========================
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.
14. EVENTS REVISITED
====================
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
https://docs.google.com/document/d/1Buv31J5wMnw-4DqRtv7LPXFhZUDqN-e47W5cGQonvpk/edit?usp=sharing
15. OVERFLOWING FILL
====================
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.
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