Re: [csswg-drafts] [web-animations-1] Generalized Time Values and Timelines

We discussed this [Generalized Time Values proposal](https://github.com/w3c/csswg-drafts/issues/2493#issue-310539963) in Houdini Berlin F2F. The feedback was that it is complex and perhaps requires too much change in web-animation model.

Since then we have spent more time thinking about this which has resulted to the alternative design below. The new design avoids mixing the input and time concepts and sidesteps the need to alter concept of 'time' as used by web-animation. This keeps the web-animation timing model simple while exposing multi-dimensional user input to animation worklet where it can be used for creating rich interactive effects. See motivation in [above comment](https://github.com/w3c/csswg-drafts/issues/2493#issue-310539963).

## AnimationInput Proposal

Introduce a new concept, **AnimationInput**, which represents an input source to an animation. A single animation can have many inputs and each input produces a 'current' value.

In addition to providing a value, AnimationInput can also be explicitly subscribed to (via listen/unlisten method pair). When a worklet animation is listening to an AnimationInput, changes to the input value invalidates the animation causing it to get executed and produce output in the next animation frame.

```webidl
interface AnimationInput {
   readonly any value;

   listen();
   unlisten();
}
```
A worklet animation constructor is updated to accepts a map of inputs. These inputs are then passed to the corresponding animator constructor when it is being initialized in the animation worklet global scope.

```webidl
typedef record<DOMString, AnimationInput> AnimationInputMap;

dictionary Options {
  AnimationInputMap inputs;
  any data;
};

[  Constructor(DOMString animatorName,
               (AnimationEffect or sequence<AnimationEffect>) effects,
                optional AnimationTimeline timeline,
                optional Options options)
] interface WorkletAnimation {}
```

## Explicit Input Subscription - Listen/Unlisten

By default an input source is passively observed <sup>[1](#perf_footnote)</sup> by the animation. The animation can switch to actively listening to the input source by calling `listen()` on it. Listening to an input source means that the animation gets to execute and produce output every time <sup>[2](#frame_footnote)</sup> that input value changes.

Some effects only need to observe an input but don’t need to be sampled when its value has changed. For example a touch driven effect that wants to calculate the velocity of a swipe gesture needs wall time as an input source, but should only be sampled when the touch input changes. Making the subscription step explicit allows the system to distinct between observing and listening. This ensures animations are sampled only when necessary.

Other effects may choose to observe multiple input sources but listen to only one at any given time. For example a hidey-bar effect is driven by scroll when that user is actively scrolling or time when scroll ends and the bar needs to complete its animation.



<a name="perf_footnote">[1]</a>: Default is passive observation to favor performance.
<a name="frame_footnote">[2]</a>: Every time is further limited to frame rate of the system. The animation is sampled every time there is a new frame *and* its inputs have changed.

## Non-Scalar Value
Unlike AnimationTimeline, the AnimationInput value does not need to be a scalar number. This is important for cases where the underlying source is inherently a multi-dimensional variable, where the dimensions can only be represented by e.g. an array or a dictionary.


## Open Quenstions

1. Should AnimationTimeline be an input type?
It is possible to make AnimationTimeline interface extend the AnimationInput interface. In this case the *currentTime*will be the same *value*. In this case the value is just time. The main motivation is to use pre-existing timeline when
we want to use input time which is nice.

2. Should WorkletAnimation continue to have a timeline?
One option is to alllow worklet animations to have both timeline and inputs. While these is overlap
between timeline and inputs, they play a different functions. Timeline allows the animation to
participate in coordinated playback with other web-animations while input is the mean to provide
rich input to animation. Note that that animations are allowed to have a null timeline. So it is
possible for a worklet animation to have a null timeline and only be driven by their input (e.g.,
for touch-driven effects). Alternatively, timeline can be explicitly unlistened in constructor.




## Example Inputs
Here are a few examples of non-scalar input sources with some speculation on how they can be modeled as AnimationInput. Note that these are **just ideas** to show the richness of the AnimationInput model. The the main proposal is AnimationInput itself and not these concrete implementations.

## ScrollAnimationInput
A scroll input; exposes both x,y, and scroll phase as a dictionary.

``` webidl
enum ScrollPhase {
  "active",
  "momentum"
};

dictionary ScrollValue {
  double x;
  double y;
  ScrollPhase phase;
}

ScrollAnimationInput : AnimationInput {
   readonly ScrollValue value;
}
```


## PointerAnimationInput
A pointer input that can be used to drive animations based on the position of pointers on an element. The pointer input value provides a snapshot of all active pointers during a possibly multi-touch user interaction. Its value is considered changed whenever a pointer is added, removed, or changes. A pointer input should be created with a source element and it is effectively equivalent to having a **passive** touch event listener on that element.


```webidl

dictionary PointersValue {
integer pointerCount;
DOMString identifier → dictionary PointerInfo {
    // client coordinate of the equivalent touch event
    dictionary  coordinate: {
        double x;
        double y;
    };
    dictionary radius {
        double x;
        double y;
    };
    double rotationAngle;
    double altitudeAngle;
    double azimuthAngle;
    PinterType type; // direct | stylus
}
}

PointerAnimationInput : AnimationInput {
   readonly PointersValue value;
}

```


## GestureAnimationInput

A GestureAnimation is a higher level input that allows worklet animation to be tied to gesture interaction such as  rotation, scale, translation. See for example MSGestureEvent and WebKit GestureEvent for some precedent work on exposing gestures on the web.

Here is a strawman API on how this input value can look like:


``` webidl

dictionary GestureValue {
  double rotation;
  double scale;
  dictionary translation {
      double x;
      double y;
  };

  dictionary velocity {
      double x;
      double y;
      double angular;
      double scale;
  };
};

GestureAnimationInput : AnimationInput {
   readonly GestureValue value;
}

```

-- 
GitHub Notification of comment by majido
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/2493#issuecomment-422109535 using your GitHub account

Received on Monday, 17 September 2018 17:51:37 UTC