- From: Brian Birtles <bbirtles@mozilla.com>
- Date: Fri, 20 Dec 2013 08:38:48 +0900
- To: "public-fx@w3.org" <public-fx@w3.org>
Web Animations minutes, 19 / 20 Dec 2013 Present: Dirk, Doug, Shane, Brian Etherpad: https://etherpad.mozilla.org/ep/pad/view/ro.Ioh-B8wtvTy/latest Agenda: 1. Status updates 2. Moving timing function chains to keyframes (and fixing pacing at the same time) 3. Fill modes and groups 4. Is step-start a special case for backwards fill? 5. Should setting currentTime = 0 while "waiting" start immediately? 6. Replace CustomEffect with a callback function 1. STATUS UPDATES ================= Brian: - Lots of minor changes to spec including player algorithms Doug - Updating polyfill with latest renames KeyframeEffect, MotionPathEffect. Removed TimingInput.activeDuration - New demos repository: web-animations-demos - http://web-animations.github.io/web-animations-demos/ Shane - Updating polyfill with endDelay Steve - Draft of Media Integration spec 2. MOVING TIMING FUNCTION CHAINS TO KEYFRAMES (AND FIXING PACING) ================================================================= (Brian) I did some investigation about keyPoints based on last week's discussion about per-keyframe easing effects and removing timing function chains. You can see some test cases here: http://people.mozilla.org/~bbirtles/tests/keypoints.html There are significant implementation differences but you can see some of the combinations. (Firefox is probably not being as strict as it should and allows keyPoints to work with paced timing; Chrome doesn't seem to allow keyTimes without keyPoints etc.) If we allow keyPoints to be in any order (the spec allows this but only Firefox seems to support this) then even with timing function chains we can't support animateMotion since animations can go back on themselves. I would like to remove timing function chains since they introduce an odd dependency between the timing model and animation model where timing properties depend on the animation effect (so we can auto-align timing functions with keyframes). At the same time, we agreed to try and make pacing separate to easing. I think we can break it down into three parts: Part 1. Work out the "handles" for timing control For keyframe effects, the handles are the keyframes. For motion path effects, the handles are the points in the path UNLESS we have keyPoints in which case the handles are the key points (sort of, anyway, see below). Part 2. Position the handles Three modes: Evenly spaced in time (distribute mode) Paced spacing (if the handles correspond to key frames and there are keyframes without the target value, we evenly distribute them) (if the handles correspond to key points, we also sort the points on the path between the intermediate points to maintain velocity, i.e. we actually pace them too but the key points determine the sequence) Fixed spacing (if there are keyframes without offsets, we evenly space them) Part 3. Ease between the handles (The timed-item level easing is orthogonal and is a product of using the supplied time fraction.) How would this look from the model/API point of view? Some possibilities: A. Allow types of effect to be distinctive - AnimationEffect spacing: auto | paced(prop) | paced (type: DOMString) - KeyframeEffect offset/easing can be set on each keyframe - MotionPathEffect timingPoints: sequence<double> (aka keyPoints) pointTimes: sequence<double> (aka keyTimes) intervalEasing: <timing-function># (type: sequence<DOMString>?) (aka keySplines except more broad) (Note that for all these sequences we'll have to have getters and setters on the interface since WebIDL doesn't allow sequence as an attribute type) (Also, we'll probably end up making up separate KeyframeEffectOptions and MotionPathEffectOptions dictionaries for the arguments we pass in.) B. More unified approach - AnimationEffect spacing: auto | paced(prop) | paced | <number># type: (DOMString or sequence<double>) intervalEasing: <timing-function># (type: sequence<DOMString>?) - KeyframeEffect take offset/easing off keyframes - MotionPathEffect timingPoints: sequence<double> I don't think this actually works though with regards to keyframes that need to have timing functions on a per-property basis. So perhaps A? > Actually, the requirement is not to have timing functions on a per-property basis but on a per-keyframe basis and this is possible with B as well. > On the other hand, removing offsets from KeyframeEffect means we can't automatically distribute keyframes without offsets, which is a nice feature. > It also means dropping a keyframe or adding a keyframe requires modifying two lists > Hence, we think A is the best option. > We also think it's OK to just make these extra properties (timingPoints, pointTimes, intervalEasing, keyframe easing) part of the model for now, and expose them to the API later if there is demand for them. Note that with either approach we remove the need for timing function chains. By removing 'easingTimes' from Timing/TimingInput they have the same members and it becomes possible again to pass a Timing object where a TimingInput is expected. In effect, we've moved the sequences from Timing to the animation effects. > Brian to work this into the spec 3. FILL MODES AND GROUPS ======================== (Steve) Currently, when calculating the active time for a TimedItem with a parent, we may consider the parent's phase. However, we consider it only when the child is in the active phase. In this case, the child's active time is null unless the child's fill mode 'matches' the parent's phase. However, when the child is in the before or after phase, we don't consider the parent's phase. This can lead to some odd results. For example, consider a parent with forwards fill, which is sampled after the end of its active interval, and a child with backwards fill. The child's active time will be null if it ends before the end of the parent's active interval (phase after), or if it spans the end of the parent's active interval (phase active). However, it if starts after the end of the parent's active interval, it will be in the before phase and will have an active time of zero. This seem inconsistent: the child's active time should be null in this case. I think we should always consider the parent's phase, and the the child's active time should always be null unless its fill mode matches the parent's phase. I've uploaded a proposed spec change at https://github.com/web-animations/web-animations-spec/pull/20 which includes a diagram which demonstrates the situation. https://github.com/steveblock/web-animations-spec/raw/a2d0b980655d8ca63ce46fdba04d97a278919fbe/example.pdf > Discussed "the elf effect" where an animated character is defined to hammer a nail using a rotation animation. The artwork has the elf in the hammer-down position and the animation consists of an initial keyframe that raises the hammer up and a final keyframe that returns it to the down position. A backwards fill is used to make sure the hammer is up initially before the animation starts. If this animation is part of a group that gets clipped before the elf animation runs, and that group has a forwards fill, I think you expect the elf to continue holding the hammer above his head. This effect can be achieved using a fill mode of both (which also has the side-effect of making sure if the animation is cut-off part-way through, the partial effect is preserved, i.e. it avoids a discontinuity). As usual, Steve is right after all. > Brian to make this change 4. IS step-start A SPECIAL CASE FOR BACKWARDS FILL? =================================================== (Shane) In particular, what should this do before the start of the animation: Animation(target, [{left: '0px'}, {left: '100px'}], {duration: 2, delay: -1, easing: 'step-middle', fill: 'both'}); because: Animation(target, [{left: '0px'}, {left: '100px'}], {duration: 2, delay: 0, easing: 'step-start', fill: 'both'}); Will have a left of 0px > Brian to re-visit Steve's initial patch for this issue and see if we can use it to achieve this behaviour where the value used in the before phase reflects which side of the discontinuity you are on. (i.e. see if Steve is right, AGAIN) 5. SHOULD SETTING currentTime = 0 WHILE "WAITING" START IMMEDIATELY? ==================================================================== (Brian) You can put a player in a "waiting" state when it has a startTime in the future. In this case the currentTime is 0 (this is the new "bounded" behavior we decided on) but the "playing" state is false. If you call play() in such a state it begins playback immediately from zero. But what if you set currentTime = 0 ? There are arguments either way. a) It should start playing immediately since setting currentTime = 0.01 would do so and treating 0 as special creates a discontinuity. b) It should have no effect since setting an attribute to its current value shouldn't have side effects. I prefer (a) but I do wonder about this whole bounding behaviour. It somehow seems quite complicated. Shane: What if the currentTime was actually -n here, <because> we're in the waiting state. > Alternative proposal: Use a combination of the playback rate and current time to determine if the current time progresses. Basically if your playback rate is positive, the currentTime only progresses so long as it is < length-of-media. Likewise in reverse if currentTime > 0. > Brian to try and prototype and spec this. Alan to tear holes in it later. 6. REPLACE CustomEffect WITH A CALLBACK FUNCTION ================================================ (Brian) I've received feedback from a few developers that they feel like it would be more natural to just pass in a callback function instead of a CustomEffect. That is, instead of writing: var anim = new Animation(elem, { sample: function(time) { document.documentElement.currentScale = 1.0 + time * 2.0; } }, 3); You should be able just to write: var anim = new Animation(elem, function(time) { document.documentElement.currentScale = 1.0 + time * 2.0; }, 3); It may be possible to specify a union of either a callback function or a callback interface (not sure if WebIDL allows this, I have to check), but I'd prefer to keep things simple and just have the callback function. What would we lose? a) The ability to define a clone() method on the custom effect b) The priority field For (a) I think there are plenty of ways of working around that. For example, if you want to store state in your particular custom effect that is particular to an element (and so should be *copied* when cloning), just attach it to the element. I haven't seen this ability to define a clone() method in other APIs so I'm assuming it hasn't come up as an issue elsewhere. For (b) we already sort using the same order as for the animation stack (i.e. player start time, player sequence number, tree order). The difference is that since custom effects don't declare their target property this sorting takes place at a global level amongst all custom effects hence we added this further priority in case you need more control. I think it's acceptable not to provide this extra knob yet anyway. There are ways to tweak priority anyway. For example, suppose you defined custom effects that manipulate scale, rotate, and transform and combine them in a defined order. You could just make them annotate their target element with their output and when they run they combine their result in the defined order with any existing annotations. Then it wouldn't matter what order they ran in. Are there other uses cases that would be hard to realize without a custom effect priority? If not, I'd rather remove the CustomEffect interface and add in the callback function. We can add CustomEffect later if needed. > Some discussion about other work arounds for (a) and (b). For (a)--allowing per-instance state to be tracked with a callback function--we discussed whether the target parameter could be an arbitrary object but decided not to allow this yet. Closures provides one means of associating different targets with different functions. For other state, it could also be attached to the Animation object. We also discussed some ideas about interpolating arbitrary properties on objects but decided not to allow this yet. For (b)--associating priority--we note that Function objects can have properties attached to them and this might be an alternative to growing a CustomEffect interface. > Replace CustomEffect with a simple callback function Next meeting: Sometime in the week of 6 January 2014 @ https://etherpad.mozilla.org/yhmUQAEfpo Past meetings: http://www.w3.org/Graphics/fx/wiki/Web_Animations/Meetings
Received on Thursday, 19 December 2013 23:39:17 UTC