Web Animations/Meetings/Meeting 14

From Effects Task Force

Time, location: 23 Apr 16:30 PDT / 24 Apr 09:30 AEST / 24 Apr 08:30 JST, Skype + Etherpad

Outcomes

Liveness discussion:

  • Make timing and function properties initially a linked copy of the template's values. Changes to the template are reflected in the instances.
  • Any changes to either object result in the instance being disassociated from its template.
  • It is possible to generate an instance that is disassociated from its template when you call animate. This is the default behaviour for scripts.

Animation function collections:

  • We will have one function per animation.
  • We just need to find a way to share duration information. Need to look into duration="50%" and the like.

Synchronisation and container durations:

  • Initially the idea of "untilParentEnd" was considered reasonable, but after further discussion we might be able to achieve this is a more elegant way with duration="100%" or the ability to specify interval endpoints rather than start point + duration. Needs more thought.
  • The idea of negative delays making animations have an effect prior to their start time at first seemed promising, but it requires redefining start time since previously a delay always applied AFTER the start time and didn't change the start time. Not sure if we want to change this.

Addition of animation:

  • Decided the addition operation should be specified on the animation function.
  • There seems to be a need to group animations within the stack. Shane will write a mail to the group with examples.

Log

See the Etherpad, the following log is really confusing since you can't tell who is saying what.

Agenda:
1. liveness revisited
2. function collections revisited
3. liveness of 'functions'
4. synchronisation and container durations
5. addition of animation

1. Liveness revisited

I (Brian) want to reconsider this. Do we really want changes to a template to be reflected in all instances created from that template?
As discussed there are two issues here:

A) Making the instances (WebAnimationInstance) live
B) Making changes to the template (WebAnimation) get synced to the instance

We want (A), not sure about (B).

CSS wants (B).

If we have (A), CSS can implement (B) easily enough by just watching for changes to the style rules (and the equivalent CSSAnimation objects) and pushing those changes across to the corresponding WebAnimationInstance objects.

For script though, I think it's probably more useful and intuitive to do:

var a = new WebAnimation();
a.timing.duration = 3;
var instanceA = a.animate(elementA)[0];
a.timing.duration = 5;
var instanceB = a.animate(elementB)[0];

? instanceA.timing.duration; // 3
? instanceB.timing.duration; // 5

What do you think?

<Shane>I think SVG will also want to have template changes reflected in live animations, won't they? If not, I don't think it's that simple for CSS to support (B) but we can always take it to the WG and see how they feel.

Also, from the API point of view, supporting (B) is kind of messy.

<Shane>Yeah there's definitely some kind of problem with it, but I think we need to work on it further. Why did CSS decide to go down this particular route?

In CSS:

.foo {
    animation-duration: 4s;
}
.bar {
    animation-duration: 5s;
}

<div class="foo bar">..</div>

CSS mechanism discovers the .foo and .bar rules, manually merges the properties, and generates an Animation {duration: 5s;}, which in turn generates an AnimationInstance on the element.

To get to the Animation from script you have to go via the div:

var a = div.getActiveAnimations()[0].getAnimation();
a.duration = 6s; // what should this do?
var b = div.getActiveAnimations()[0];
b.duration = 6s; // what should this do?

If the .foo rule now changes, this has no effect on this div.
what if .bar changes?

Some possibilities:
* A subclass of Animation that reflects its changes to its instances and produces read-only instances
* Those read-only instances can be modified by disassociating them from the template--i.e. converting them to normal instances
  -- the disassociation could happen automatically by simply touching one of the timing parameters

LockedAnimation
- used by CSS, SVG and probably script can use it as well
- when you call animate, the functions and timing properties of the instances are tied to the template and reflect changes to the template
- but if you change any of their subproperties, the association is broken

Animation
- when you call animate, the instances are already independent of the template
- changes made to the template don't update the instances, you can forget about the instances

Maybe we need to integrate this into animate() and animateWithParent() somehow.

2. Function collections revisited

Currently we have a hierarchy where an Animation/AnimationInstance can contain multiple animation functions. This is to match CSS.

Under this arrangement the timing information is common to all functions (i.e. all properties being animated). If you want to change the timing for one property it's difficult. You can fudge it in different ways (e.g. set two keyframes to have the same value so the animations appears to start later, end sooner etc.) but that's all. For many changes you simply have to create a separate Animation. That's fine, but it's perhaps a little counter-intuitive / inconvenient to have to suddenly create a separate object.

I wonder if we'll get a request in future in override timing information on a function-by-function basis. If we do that, I think the API will start to get complex and heavy. It seems to me it would be better to encourage authors to use groups from the start.

i.e. one animation has only one function. When you query CSS style rules you get back a group.

If  we do this I think we need to rename WebTimeline as WebAnimationGroup  or something of the sort. The reason is that a timeline sounds complex  and heavy. Its relationship to an animation is also not obvious.

<Shane>I think it really does make sense for a set of animations to share the same timing - the point of keyframes is that you're specifying a set of complex and synchronized shape changes by describing the state of the object at various points.

Timing properties:
duration
start time
delay
iterationCount
timingFunction
speed
direction
fill

You can already share most of these by using groups except fill and duration. For fill, you probably something you want to set per animation. Duration, however, is hard. We might have "untilParentEnd" but is that enough?

.foo {
    animation-name: bob;
    animation-duration: 10s;
}
@keyframes bob {
    0% { width: 20px; height: 50px; }
    50% { width: 40px; }
    100% { width: 50px; height: 20px; }
}
-->
<par duration="10s">
    <seq duration="100%">
        <animate target="width" from="20px" to="40px" duration="50%"/>
        <animate target="width" from="40px" to="50px" duration="50%"/>
    </seq>
    <animate target="height" from="50px" to="20px" duration="100%"/>
</par>

There is also a strong use case in terms of being able to easily modify the timing of complex shape changes without having to keep track of a set of animations to do so.

Another reason to prefer a single animation function is that if we want to allow animation functions to control timing then there should be only one function per animation. For example, SVG 2 have a requirement to support pace="10px/s" or something of the sort. In this case, the values of the animation function should ultimately be reflected back to the animation's simple duration. However, if there are multiple animation functions this doesn't work.

<Shane>Pacing is complicated in lots of different ways, not just this. However, this one is relatively resolvable - just allow an <animation> container to specify which animation is paced.

3. Liveness of 'functions'

This might not even be worth discussing depending on what we decide about (1) and (2). If, for (1) we decide to do (B), then we need to work out how to sync/override functions. I've put a few thoughts in the spec on github and would appreciate your feedback.

4. Synchronisation and container durations

See mail, but basically, what do you think of:

- the "untilParentEnd" value for dur / iterationCount? 
- allowing negative delays on sequence container children to start the  children early? 

<Shane>My rough thoughts here are that we should probably avoid adding what are essentially timing-related constraint solvers to V1. The use cases are important ones, I agree, but they can all be solved with some pretty simple scripting; and while untilParentEnd does initially look attractive, I worry that it adds a lot of complexity and corner cases. Just as a simple corner case, what happens here?

<par>
  <animation duration="untilParentEnd"/>
</par>

Or here?

<par>
  <animation duration="untilParentEnd"/>
  <par>
    <animation duration="untilParentEnd"/>
  </par>
</par>

<par duration="4s">
  <par>
    <animation duration="untilParentEnd"/>
  </par>
</par>

AnimationInstance.timing.duration <-- specified duration
AnimationInstance.duration <-- effective duration

AnimationInstance.timing.duration = Animation.WEBA_DURATION_UNTIL_PARENT_END (=-1)
AnimationInstance.duration = 5

* Mark as feedback requested

I'm also not sure about allowing negative start times on delays, because it changes the calculation for start time in weird ways and allows animations to creep outside the bounds of their containers. Maybe we can make something work though - random idea: what about a timeshift container that moves everything a specified time backwards or forwards?

<par alignment="end">
  <video>
  <animation position="relative" delay="-5s" duration="5s"/>
</par>

<par alignment="end">
  <seq>
    <video>
    <animation id="empty" duration="2.5s"/>
  </seq>
  <animation duration="5s"/>
</par>

Proposals:

* animations and timed containers can have negative delays, and they can even begin playing before their start time, but they will be bounded by the times of their parents.
<seq>
  <video/>
  <par>
    <animate delay="-5s">
  </par>
</seq>

In this case the par will clip the animation off so you won't see the first 5s

<seq>
  <video/>
  <par delay="-5s"> // start time is video.duration;
    <animate> // start time of this is video.duration - 5s;
  </par>
</seq>

<seq>
  <video/>
  <animate delay="-5s"> // start time of this is video.duration;
</seq>

<seq>
  <video/>
  <animate duration="1s"> // start time of this is video.duration;
  <par delay="-5s">
    <animate> // start time of this is video.duration - 4s;
  </par>
</seq>

<seq>
  <video/>
  <animate duration="1s"> //start time of this is video.duration;
  <animate delay="-5s"> // start time of this is video.duration + 1s;
</seq>

How about this case? Probably you should see it

* Need to think this through---can delay actually go before the start time.

5. Addition of animation

I started specifying addition and came across a couple of things.  The first is pretty minor - we need a place to specify the addition operation (replace / accumulate / blend) - I think perhaps as part of each AnimationFunction, defaulting to replace?

Done.

The second issue is harder. Alex and I have been playing with some code I hacked up to explore the area, and have come across a couple of realizations:

1) The path rotation primitive really needs to be able to apply partially (i.e. to a subset of paths in a stack) - remember we talked about how path rotation could either apply to each path independently or to a stack of paths that are added together, and that both had strong use cases? For that model to resolve nicely with the animation stack approach we need to be able to apply path rotation to e.g. the top 3 paths but not the next 4.

2) Grouping of animations in the stack is really useful - for example, without grouping we can't do something like <complex set of positioning transforms> ADD (<path 1> MERGE <path 2>) ADD <more positioning, etc.>. The intention here is that an object is moving along path1 and moves over to path 2 over some number of seconds, but there's a bunch of setup that puts the paths in the right spot and the object in the right location relative to the paths.

But grouping is a real problem. How do we specify animation groups in the stack, when the stack is implicitly derived from start time and document order?