- From: Rik Cabanier <cabanier@gmail.com>
- Date: Thu, 8 Aug 2013 11:45:13 -0700
- To: Shane Stephens <shans@google.com>
- Cc: "public-fx@w3.org" <public-fx@w3.org>
- Message-ID: <CAGN7qDD__2ZjvSn=rPrxMS61=8Q8zTzQkX-S94b4YzH4KpEzWQ@mail.gmail.com>
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