Web Animations minutes, 7 / 8 August 2012

Web Animations minutes, 7 / 8 Aug 2012

Etherpad: https://etherpad.mozilla.org/ep/pad/view/ro.eiMsLaB5x-p/latest
Present: Dmitry Baranovskiy, Alex Danilo, Shane Stephens, Brian Birtles

Agenda:
1. Renaming Anim/AnimInstance
2. What time do you pass to seek()?
3. Liveness
4. Template classes
5. Removing the Timing interface

0. STATUS UPDATE

Dmitry checked in Enum support to respec.js. Works great.
Brian working on start(), stop(), reverse(), changeSpeed(), pausing etc.

One month out from SVGOpen.

Current work items:
1. Specification (Brian / Dmitry to provide support)
    Shane to address TODOs in "Primitive animation operations" section
2!. Presentation (Alex)
(3). SVG Integration spec
4. Emulator (Shane and hopefully Dmitry)
    Shane to send Dmitry current state, so he can get familiar with the 
code.
(5). CSS Integration spec

1. RENAMING Anim/AnimInstance

Now that we have the global Animate function, script does not need to 
refer to the Anim interface directly as often.

Can we rename as follows?

s/Anim/AnimProto/
s/AnimInstance/Anim/

AnimTemplate may be better than AnimProto to avoid confusion with 
Anim.__proto__ and AnimPrototype

 > We will rename Anim -> AnimTemplate, AnimInstance -> Anim

2. WHAT TIME DO YOU PASS TO SEEK()?

Suppose I have this animation:

anim {
     delay: 3s;
     from: 100px;
     to: 200px;
     dur: 5s;
}

(Forget the syntax, this is some CSS-SVG neutral ground syntax I just 
made up)

3s after the document loads it begins animating from 100px to 200px. It 
finishes 8s after the document loads.

Later I call anim.seek(3).

What is the result?
a) 100px
b) 160px
c) something else?

Answers:
Alex and Brian: (b)
Shane: (a) or global time
Dmitry: (a) or (b)

Currently the answer as spec'ced is (a). If (b) is more intuitive then I 
need to revise how seek() works. The up-shot is we can probably get rid 
of the whole concept of item time which is probably confusing to most 
people.

What if you repeat the experiment, assuming that the animation was not 
triggered until after 30s (i.e. has a start time of 30s)?

 > Discussion about whether delay should be considered an intrinsic or 
extrinsic part of an item's timeline. General consensus that the model 
is currently angled towards it being intrinsic (e.g. the sandwich model 
sorts by start time and delay allows items to be shifted in their 
"effect" but still sorted by the sandwich model). Some disagreement wrt. 
"Active" being only when an item is filling or animating - i.e. an item 
can be in delay but not "Active" if there's no fill.

 > Resolved that it's intrinsic. i.e. seek(3) includes delay

 > Brian to look at rephrasing section talking about "Active" animations

3. LIVENESS

Some proposals to consider:

PROPOSAL A: Explicit delinking
(from François REMY)

Similar to existing but don't automatically break liveness. Rather, if a 
change is made to a linked instance (live instance) throw an exception 
and require an explicit call to makeIndependent (delink?) in order to 
make the change.

Shane: I like this for its brittleness - if you do something unexpected 
we make sure you know about it up-front.

PROPOSAL B: Everything is individually overridable except the 
AnimationFunction which requires explicit delinking

Originally when we tried to approach liveness we did what you'd expect,

i.e.
var template = new AnimTemplate;
template.timing.speed = 3;

var anim = template.animate(...);
? template.timing.speed // 3
? anim.timing.speed // 3

anim.timing.speed = 4;
? template.timing.speed // 3
? anim.timing.speed // 4

template.timing.speed = 5;
? template.timing.speed // 5
? anim.timing.speed // 4

But we ran into two problems:
i) How to reset each of these properties?
ii) Following this scheme through to all the different types of 
AnimFunction (including those to be added in the future, and 
script-defined ones) and supporting this property-by-property tracking 
on each of their sub-properties seemed like a real pain.

With regard to (i), I've defined TimedItem.animationDuration so that you 
can override the computed value. You can reset it by just assiging it to 
undefined or null (currently I've gone for undefined, but we can change 
it to null). I spoke to Cameron McCormack (WedIDL spec editor) and he 
says that's fine.

For (ii) we could say we do property-by-property overriding for the 
timing properties (i.e. everything on TimedItem and Timing), but treat 
the func property specially, i.e. if you try to change the copy attached 
to the instance it will throw an exception and you need to call clone 
(or something similar) before you can change it.
Unlike A, this lets you make small tweaks to the timing without losing 
liveness of the rest.

Shane: This works OK but do we have a strong use-case for tweaking the 
timing without losing liveness? If not, then maybe this is too complex.

PROPOSAL C: No liveness

Just drop liveness altogether. SVG and CSS do the bookkeeping of copying 
property changes across.

(Brian: This does raise some questions though. Will SVG and CSS just 
blindly overwrite the values on the instances? If not, you basically run 
into the same problems outlined at the start of proposal B.)

Shane: I don't like this mainly because liveness will be useful to 
advanced script users too, so we'd be replacing 1 painful mechanism with 
3 painful mechanisms that mostly do the same thing.

Note that if we go with C, we could introduce A (or even B) in a later 
version.

Alex and Dmitry: favour doing C for now, introducing A later
Dmitry: This is probably dependent on what we decide to do with the 
Timing interface.
Shane: Objections:
   - practically, this is already needed for SVG/CSS integration and 
authors will also sometimes want this feature (liveness), so we should 
support it
   - philosophically, if we're having such a hard time getting it right, 
why just shift the burden to SVG/CSS?

 > We'll come back to this in light of what we decide regard to Template 
classes at the Timing interface

4. TEMPLATE CLASSES

This is related to liveness but orthogonal to most proposals. The 
question is, do we need template classes?

One alternative we could have is to have Anim objects that have no 
target / startTime / parent, very lonely individuals, but nevertheless 
welcome. In a sense, these are the templates.

To create an "instance" you clone an Anim object and give it a target / 
startTime / parent along the way.

Anim objects might have 'defaultTarget' and 'defaultParent' properties 
to simplify cloning. i.e. anim.animate(4).
Liveness could still be achieved by having clones refer back to their 
source.

What this gives us is:

* A lot less interfaces to specify. It's simpler because you don't have 
to match up these parallel hierarchies.
* We could possibly also get rid of the Timing interface since the main 
reason it has been split out is to share the definitions between 
template and instance

Some downsides are:
* Confusing to have some Anim objects that work as templates and some 
that are actual animations
* In future it's probably useful to overload just the templates. e.g. 
for the SVG integration, define a special SVGAnimTemplate that does all 
the complicated work of managing syncbase timing etc. and then just 
spawns these very simple vanilla Anim objects at the appropriate times.

Shane: This has some intriguing possibilities. I would modify it 
slightly to exclude *just* the target, and allow the "template" versions 
to be inserted into timelines like "normal" ones. These would then act 
essentially as spacers. This removes the first downside, and means that 
every Anim object is both a template and potentially an animation.

In fact, untargetted Anim objects can even be parented by the global 
group, as this is a "par" group.

The second downside doesn't really seem like a downside to me :) 
Basically the mechanism is roughly the same, and we're only having a bit 
of trouble thinking about it because we started down the other path already.

Brian: Concerned about having all these dummy animations in the tree 
that are simply there to be cloned. It's confusing when you walk the 
tree and half of the "animations" are not actually doing any animation.

 > Need to flesh out the details to see if this is workable:

Kicking ground for the idea: https://etherpad.mozilla.org/07VpfyGtdw

5. REMOVING THE Timing INTERFACE

I (Brian) find the Timing interface a little confusing. For example, you 
have:
   anim.timing.startDelay

BUT
   anim.startTime

There's good reason for it--the delay is a property of the template, the 
start time is related to the specific instantiation--but I think authors 
will find it confusing. What do you think?

There are two reasons for the existence of the Timing interface:
* Share definitions between AnimTemplate and Anim
* To allow separation of specified and computed values
i.e. we have
   anim.timing.iterationDuration -- the specified duration, can be null 
meaning 'intrinsic duration' (e.g. for groups, videos etc.)

but we also have
   anim.iterationDuration -- the calculated duration

I (Brian) was thinking about collapsing Timing into TimedItem/TimedTemplate.

This would give you:
interface TimedItem {
     // Previous Timing interface
     attribute float               startDelay;
     attribute unrestricted float? iterationDuration;
     attribute unrestricted float  iterationCount;
     attribute float               iterationStart;
     attribute float               speed;
     attribute PlaybackDirection   direction;
     attribute TimingFunction      timingFunction;
     attribute FillMode            fill;

     // Existing TimedItem interface
     readonly attribute float?             animationTime;
              attribute unrestricted float animationDuration;
     readonly attribute float?             iterationTime;
     readonly attribute unrestricted float iterationDuration;
     readonly attribute unsigned long?     currentIteration;
              attribute float              startTime;
     readonly attribute unrestricted float endTime;
     readonly attribute AnimGroupInstance  parentGroup;
     readonly attribute float              timeDrift;

     void start (optional float timeFromNow = 0);
     void stop (optional float timeFromNow = 0);
     void pause ();
     void unpause ();
     bool getPauseState ();
     bool isPaused ();
     void seek (unsigned long itemTime);
     void changeSpeed (float speed);
     void reverse ();
     void cancel ();
};

and:

interface TimedTemplate {
     // Previous Timing interface
     attribute float               startDelay;
     attribute unrestricted float? iterationDuration;
     attribute unrestricted float  iterationCount;
     attribute float               iterationStart;
     attribute float               speed;
     attribute PlaybackDirection   direction;
     attribute TimingFunction      timingFunction;
     attribute FillMode            fill;

     // Existiing TimedTemplate interface
     TimedItem           animate (Element target, optional float startTime);
     ...
};

For the two versions of iterationDuration you could either have:
   specifiedIterationDuration
   computedIterationDuration

(or something a bit shorter)

Or just do like I've done with animationDuration. i.e. you can override 
it, otherwise it reflects the intrinsic iteration duration. That doesn't 
work so well, however, if we want the specified duration to take on 
values like "20%" etc.

Regarding the definitions, you'd define it once (probably in 
TimedTemplate since it appears first) and then just refer to those 
definitions from TimedItem.

Which do you prefer?

Shane: I must admit I actually like the separation of specification and 
computed values, which is what we have at the moment. If we roll these 
in together, maybe prefixing the computed versions with "computed" could 
be good? I don't think we'd also need a "specified" prefix.

Dmitry: Proposal to keep timing properties as properties, but convert 
all dynamic properties into methods.

TimedItem.animationTime → TimedItem.animationTime() [or 
TimedItem.getAnimationTime()]

This way it’s more clear that the value is not static and could be 
potentially expensive to get. If we decide to make them writable we 
could always allow the method to accept value or add setAnimationTime() 
(which is obviously uglier). This will remove confusion:
anim.timing.startDelay
anim.startTime
or
anim.startDelay
anim.startTime()

Next meeting: 9 Aug 18:00 PDT / 10 Aug 11:00 AEST / 10 Aug 10:00 JST @ 
https://etherpad.mozilla.org/CVoYIc2pWz

Received on Wednesday, 8 August 2012 05:39:18 UTC