Re: [web-animations] Simplifying timing groups

On Thu, Aug 8, 2013 at 5:32 AM, Shane Stephens <shans@google.com> wrote:

> Apologies in advance for the long email. This is a complex topic and I'm
> not sure that discussion on a mailing list does it justice. In particular,
> I think some wires have been crossed along the way:
>
> (1) Nobody is seriously considering "arbitrary timing functions" on Timed
> Items, certainly not for the first version of the specification. There is a
> restricted set that comprises essentially the same timing functions
> currently available in CSS.
>
> (2) Timing groups are functionally very similar to iterations. To argue
> against timing functions on Timing Groups logically implies that Timing
> Groups should not be allowed to iterate either.
>
> Here are the similarities:
> * Both timing functions and iterations manipulate the local time of the
> child animations
>

This seems like a flaw in the model.
Why would pausing a group, freeze all its child animations?

Maybe I should study the spec more...


> * Neither (the current set of) timing functions nor iterations can
> introduce more than two time inversions per segment.
> * Both timing functions and iterations can cause the start/end point and
> child iteration points to repeat.
> * Neither timing functions nor iterations are visible from the perspective
> of the child when looking at local time.
>
> (3) Limited time inversions are not difficult to understand or deal with,
> and they produce some really nice effects (like smooth changes of
> direction). As mentioned above, iterations already produce inversions, and
> we deal with this in the model just fine. What is tricky is unbounded
> inversions - such as might be produced by a spring timing function. We do
> not intend to introduce timing functions with unbounded inversions to this
> version of the specification.
>
> (4) Contrary to Brian's statements, there are several animations APIs that
> currently provide group timing primitives of some sort. They tend to be
> very similar in scope and behavior to the set of timing functions we
> currently allow on Timing Groups. What is key about the restrictions in
> these APIs is not that they prevent inversions - they don't. Instead (with
> the exception of GSAP, see below for more detail), they prevent *unbounded*
> inversions.
>
> (5) Removing timing functions from Timing Groups is not a simplification.
> On the contrary, it significantly complicates the model, because it takes
> what was a unified concept that applied to both Timing Groups and
> Animations (the Timed Item abstraction) and forces it to be split into
> different abstractions for groups and animations.
>
> Three important concepts for specification simplicity are:
> (A) API/concept surface area. Removing this feature actually increases
> surface area, as an additional interface or concept needs to be introduced
> to deal with the difference between Timing Groups and Animations.
> (B) Consistency. Removing this feature introduces an inconsistency to the
> set of things that can be animated by Players.
> (C) Ease of use. Removing this feature makes some things that seem like
> they should be easy very hard to do. For a concrete example, without this
> feature it's impossible in the general case to take a complex animation
> (that might e.g. be generated programatically, or from a library of
> effects) and apply a simple easing to it.
>
> To the extent that this thread has discussed complexity, it is mostly
> talking about implementation complexity. Is it not explicitly against the
> principles of the W3C to choose a slightly simpler implementation at the
> expense of users?
>
> -----
>
> The real issue is that unbounded inversions in a timing function can lead
> to an unbounded number of events, and make it difficult to place those
> events in document time. This issue is entirely theoretical as we don't
> have timing functions with unbounded inversions, and because we already
> need to deal with inversions due to the presence of iterations.
> Nevertheless, I think there might be some things we could potentially look
> at to simplify the location of these inversions, without breaking the
> model. If people are interested, I'll make some suggestions in a follow up
> to this email.
>
> I've included some more specific responses below.
>
> On Thu, Aug 8, 2013 at 4:30 PM, Brian Birtles <bbirtles@mozilla.com>wrote:
>
>> Hi Shane,
>>
>> Thanks for your response. I'll follow up below.
>>
>>
>> (2013/08/08 13:32), Shane Stephens wrote:
>>
>>> On Thu, Aug 8, 2013 at 1:25 PM, Brian Birtles <bbirtles@mozilla.com
>>> <mailto:bbirtles@mozilla.com>> wrote:
>>>     i. It means you can't convert from an animation's local time to the
>>>     corresponding document time since timing functions are not always
>>>     invertible. This introduces all sorts of complexity. For example,
>>>     for event handling to report both a local time and document time for
>>>     an event we have introduced uneased timing[1] which is not
>>>     well-liked and as an alternative we have considered some fairly
>>>     arbitrary approximations.
>>>
>>>
>>> I think this is a misrepresentation. Every observable animation start,
>>> end and iteration change has an exact corresponding document time. These
>>> times are in general derivable from the timing functions.
>>>
>>
>> I think it's reasonably complex.
>>
>
> I'm glad you no longer believe that it can't be done :)
>
>
>> For example, in Gecko when we evaluate cubic bezier timing functions we
>> approximate the curve with straight-line segments to find the t for a given
>> x. If we go in reverse where a given y may have multiple t's, we can't rely
>> on a table of fixed chord lengths since they may obscure some crossings of
>> a given y. I think it could be challenging to define this in a way that is
>> consistently implemented and performant if we allow arbitrary timing
>> functions. We could probably do something reasonable for a restricted set
>> of timing functions though.
>>
>
> You're talking about the impact of a specification decision on a specific
> implementation, rather than focusing on keeping the model simple. For an
> alternate data point, Blink uses recursive bezier splitting to find points
> on and lengths of beziers. This approach does not suffer from the
> shortcomings that a table of fixed chord lengths does.
>
> Also: we already have a very restricted set of timing functions. Nobody is
> suggesting we allow 'arbitrary timing functions', whatever they are
> supposed to be. The inversions in the very simple set we have are easy to
> characterize and will not impact performance (even with a table of fixed
> chord lengths).
>
> Another example of complexity is stepped timing functions where we have to
>> be careful how we define which x to return for a given y since a single
>> input may map to a whole range of outputs. I think the 'correct' answer
>> will depend on a number of factors, possibly the type of event to be
>> dispatched or the playback direction.
>>
>
> Yes, this is something we'd need to think through.
>
>
>> So I think, while probably solveable, it's complex enough to defer to a
>> later stage.
>
>
> We shouldn't defer features because one implementation is forced to modify
> the way it approximates beziers. This is not the appropriate definition of
> complexity to use when making these decisions.
>
>
>
>>      It also introduces some as-yet unresolved questions such, "If a
>>>     timing function on a group causes a child to oscillate between being
>>>     in and out of the active phase repeatedly, perhaps even a dozen
>>>     times in 100ms for a spring function, do we dispatch events for
>>>     every one of those transitions?" (And if we have real spring
>>>     functions the number of crossings would depend on how you evaluate
>>>     the function and could be huge.)
>>>
>>>
>>> If we have short iteration durations and lots of iterations we have the
>>> same problem.
>>>
>>
>> The issue is really the question about whether we should report all those
>> starts and ends at all. Sometimes its useful to have them, sometimes its
>> not.
>>
>> I can give a concrete example of this if needed but I think it's simpler
>> if we design the model so the question never arises in the first place.
>
>
> Are you suggesting that neither iterations not timing functions produce
> intermediate start and end events? Whatever one does, the other should do.
>
>
>>
>>      iii. It complicates implementation since this feature makes it
>>>     difficult to decompose timing hierarchies into simple animations
>>>     that could be passed off to another process or even another API.
>>>     Without this feature, any timing hierarchy could potentially be
>>>     flattened down to a series of very simple sub-animations. (For
>>>     example, an iteration count of a group would be represented by
>>>     producing several sub-animations, one for each iteration. A
>>>     direction setting on a group could be represented by flipping the
>>>     playback rate on some of those sub-animations etc. On the other
>>>     hand, splitting a timing function on a parent into pieces, then
>>>     combining the appropriate piece with any timing functions already
>>>     applied to the child's sub-animations, is far more complex.)
>>>
>>>
>>> This is false. It is entirely possible to decompose timing hierarchies
>>> with timing functions on groups. Given that timing functions need to be
>>> represented in the simple sub-animations anyway, it is not much of a
>>> stretch at all to allow a stacked timing function to be used here.
>>>
>>
>> The claim was it is complex, not impossible.
>>
>
> Stating that "without this feature, any timing hierarchy could potentially
> be flattened.." strongly implies that with the feature it could not.
>
>
>> I still think it's a reasonable bit of work. Even if you don't split the
>> timing functions but just inherit the whole list of functions along with
>> appropriate offsets you still have to effectively apply playback rate,
>> direction changes etc. in *in between* the functions in order to produce
>> the same result. You could probably achieve that by modifying the offsets
>> into the curves but it's starting to get complicated. (Then if you're
>> interfacing onto any system that doesn't support a stack of timing
>> functions you have to composite the functions together which is probably
>> only possible by approximation.)
>
>
> I am very uncomfortable reducing the viability of the API simply because
> of a theoretical system which you need to interface with but that you
> aren't allowed to modify. In practice there are a number of approaches one
> could take to support animations off-main-thread, including splitting
> animations on animation boundaries, splitting animations on inversion
> boundaries (which is your proposal for iterations anyway), and simply
> supporting a subset of the animations model on the secondary thread.
>
>      * GSAP, which has an impressive feature set, has no 'ease' property
>>     on TimelineLite / TimelineMax.
>>
>>
>> GSAP allows you to tween both the currentTime and the timeScale on
>> TimelineLite and TimelineMax, which is the same thing as a timing
>> function.
>
>
> > timeScale() is just the playback rate. progress(), time() and
> totalTime() likewise correspond to setting the
> > playback position.
>
> > You can repeatedly call these methods to emulate a timing function but
> that's the not same as having timing
> > function on a group. You can do that in Web Animations too without
> having timing functions on groups.
>
> Actually, GSAP allows you to *tween* these values, which means you can
> define an automatically running animation with a timing function applied to
> it that modifies these values, which is functionally at least as powerful
> as directly applying a timing function to the Timeline.
>
> It's not even like this is an obscure feature: (a) it's part of
> TimelineLite, and (b) the fact that you can do it is explicitly called out
> in the documentation preamble for this class.
>
>
>>
>>      * WPF which has, by far, the most complicated animation API I have
>>>     ever seen, only has easing functions on animations.
>>>
>>>
>>> WPF provides at least the ability to accelerate and decelerate
>>> Timelines, from which both Animations and TimelineGroups inherit.
>>>
>>
>> That's not arbitrary timing functions. That's the same as SMIL3.
>
>
> ...and Web Animations!
>
> A combination of acceleration, deceleration, and auto-reversing provides
> almost as much power as the cubic-bezier timing function we provide. There
> are differences, but they are minor. Every other timing function we provide
> has no inversions.
>
>
>>
>>      * SMIL3, as discussed later, which is infamous for its complexity,
>>>     does not allow arbitrary timing functions on groups.
>>>
>>>
>>> And yet SMIL3 does supply auto-reversing, which is not invertible.
>>>
>>
>> If you model it as additional iterations with direction set, then it's
>> invertible in the same way that iterations are invertible--that is, you
>> have to know the current iteration but that's generally an easy requirement
>> to satisfy.
>>
>
> It is my strong contention that this is equally true of every timing
> function we currently support in Web Animations.
>
>
>> And SMIL3 still doesn't support arbitrary timing functions on groups.
>
>
> What exactly are the arbitrary timing functions we support? Do you mean
> parameterized timing functions like cubic-bezier? If so, then SMIL3 and WPF
> support something that is functionally very similar.
>
>
>>      This begs the question, do we really need this?
>>>
>>>
>>> If you choose your features based on what everybody else does, then
>>> given that 3/4 of the animations engines you supplied provide it, the
>>> answer is clearly yes. However, I'd prefer to analyse whether this
>>> feature is *useful* and proceed from there.
>>>
>>
>> None of those APIs allow arbitrary timing functions on groups.
>
>
> ... just like us.
>
> Much more importantly, all 3 APIs provide a time-varying measure of
> control over the flow of time in groups. If we adopt your suggestion then
> we won't.
>
>
>>
>>      * In general, provided the 'current iteration' of each parent is
>>>     known, it is possible to convert from an animation's local time to
>>>     document time which may be useful in a number of contexts (it may,
>>>     for example, be something we expose via the API in future).
>>>
>>>
>>> This is always possible. Note that sometimes multiple document times can
>>> produce the same local time. Note further that this is already true in
>>> the presence of iterations, without taking timing functions into account.
>>>
>>
>> That's why I included the condition, "provided the 'current iteration' of
>> each parent is known."
>
>
> Again, I strongly contend that a similar condition is all that is required
> to fix the apparent problems with timing problems.
>
>
>>      * There is no need for special overflow fill handling.
>>>
>>>
>>> We already perform special overflow fill handling on Animations. Why are
>>> TimingGroups different?
>>>
>>
>> It's a different mechanism. The handling for animations doesn't require
>> any extra state to be passed around. In fact, if we were to remove
>> arbitrary timing functions from groups this behaviour could become a
>> property of the animations model.
>
>
> There is extra state required - you now need to be able to specify what
> happens out-of-bounds on an Animation. We had considerable discussion about
> this in Tokyo. Adding a similar feature to Timed Items is a natural
> extension.
>
>
>>      * Media references are not required to support timing functions
>>>     initially. If timing functions are useful there, we can determine
>>>     the sort of timing functions that are readily implementable and
>>>     restrict the set of timing functions permitted accordingly. For
>>>     example, overshoot doesn't make much sense for media. Likewise, some
>>>     features of chained timing functions probably don't make much sense
>>>     for anything other than animations (like the keyframe alignment
>>>     feature).
>>>
>>>
>>> This is an orthogonal issue to your proposal.
>>>
>>
>> It's not orthogonal because if we have timing functions on groups we
>> *must* be able to support easing media since we'll get inherited time that
>> is eased, possibly multiple times. It's not clear that that's a reasonable
>> requirement for all implementations. I'd be surprised if all platforms
>> provide that sort of feature.
>>
>
> All of our old drafts and meeting minutes specify that media doesn't (have
> to) ease, and merely respects the overall boundaries of the time slice
> allocated to it. This is even implemented in the polyfill. It works just
> fine.
>
> Additionally, media integration isn't even part of L1 any more.
>
> By removing timing functions from groups we can restrict the easing
>> available on media to that which seems useful and implementable (which may
>> be none initially).
>
>
> That sentence is equally true if you remove the part about timing
> functions :)
>
>
>>  It's probably clear by now that I don't agree with your reasoning. Can
>>> we come at this question from a use-case based analysis instead?
>>>
>>> For a start, timing functions on groups make it easy to:
>>> (1) keep the timing of a number of animations in sync (by applying the
>>> function to a ParGroup)
>>> (2) smear a timing function across a composite effect (for example,
>>> applying an ease-in across a SeqGroup containing multiple child
>>> animations)
>>> (3) keeping consistent timing across a complex hierarchy of ParGroups
>>> and SeqGroups
>>>
>>> Without timing functions on groups, how would you provide this
>>> functionality?
>>>
>>
>> There are definitely things that you can't do as easily without arbitrary
>> timing functions on groups but I can't find a single animation engine
>> anywhere that supports this functionality which suggests that for all
>> current concrete use cases authors have managed fine without it.
>>
>
> We are not talking about arbitrary timing functions, we are talking about
> a carefully controlled set. And in fact three of the four animations APIs
> discussed support controlled easing on groups.
>
>
>> Rik points out that Flash doesn't support this and yet somehow Flash
>> authors have managed pretty well.
>>
>
> Rik's suggestion that Timing Groups are like Scenes leads me to believe
> that Flash doesn't have a concept matching Timing Groups at all, so this is
> hardly relevant.
>
> Note that in Flash you can group a set of elements together then animate
> them as a single object. When you do so, you can control the timing of the
> group as a single entity. With your proposed change, this might be
> achievable in limited circumstances (e.g. when all elements are part of a
> well-defined DOM subtree and you are only animating the transform), but it
> certainly isn't generally achievable.
>
>  Last year in October when we demoed Web Animations we actually used this
>> feature to ease both a door and its creaking sound. There are two things to
>> note about this use case:
>>
>> a) It could easily be done by applying the timing function to the two
>> child animations independently.
>> b) It could *also* be done by allowing a restricted set of timing
>> functions on groups.
>>
>
> I have implemented smooth animation along a path that responds to
> keystrokes by changing the destination along that path. It is essentially
> impossible without timing functions on groups. Timing functions with at
> least one inversion are required in order to handle the case of a change of
> direction.
>
> I have also implemented and demoed some of the layout transitions ideas
> that the CSSWG has talked about. Getting smooth layout transitions with
> keyframes is again not impossible without timing functions on groups, but
> it's much harder as timing fragments would need to be computed manually,
> and effects split, by the user, at arbitrary points.
>
> If you want to talk about complexity, supporting these kinds of behaviors
> without timing functions on groups is *very* complex.
>
>
>> I'm open to the possibility of adding restricted easing behaviour on
>> groups like SMIL3 offers. I'd prefer to add that later but would be ok with
>> adding it sooner if there is sufficient demand. I think that would address
>> a number of the uses you outlined above without introducing many of the
>> undesirable qualities of allowing arbitrary timing functions.
>>
>
> OK, let's add the restricted set of timing functions that we already have.
> Nobody is asking for arbitrary timing functions.
>
>
>> I just feel that introducing features that (a) introduce considerable
>> complexity, (b) are provided by no other animation platform we've found
>> yet, and (c) for which we have yet to find concrete use cases that can't be
>> solved by other means, seems like over-engineering for a first version of a
>> spec. I think we can add this later if needed.
>>
>
> (a) no, the feature provides limited additional implementation complexity
> but actually simplifies the model
> (b) no, analogues to the feature are provided by at least 3 other
> animation platforms. Even Flash provides a limited version
> (c) no, I have presented two concrete use cases above and I suspect if you
> look at existing animation content you'll notice a lot more
>
> Sincerely,
>     -Shane Stephens
>
>
>> Best regards,
>>
>> Brian
>>
>
>
>

Received on Thursday, 8 August 2013 18:45:42 UTC