From ce3203a4cbca88d6fddcd0ca1bc5917f0d13673b Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 14 Sep 2016 11:46:50 -0400 Subject: [PATCH 001/114] Initial import of the proposal --- index.md | 414 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 index.md diff --git a/index.md b/index.md new file mode 100644 index 00000000..3f8f6c00 --- /dev/null +++ b/index.md @@ -0,0 +1,414 @@ +# Animation Worklet Explainer +--- + +# Overview + +AnimationWorklet is a new primitive for creating scroll-linked and other high performance +procedural animations on the web. + +{:toc} + +# Introduction + +Scripted effects (written in response to `requestAnimationFrame` or async `onscroll` events) are +rich but are subject to main thread jankiness. On the other hand, accelerated CSS transitions and +animations can be fast (for a subset of *accelerated* properties) but are not rich enough to enable +[many common use cases](#motivating-use-cases) and currently have no way to access scroll offset +and other user input. This is why scripted effects are still very popular for implementing common +effects such as hidey-bars, parallax, position:sticky, and etc. We believe (and others [agree][roc- +thread] that there is a need for a new primitive for creating fast and rich visual effects with the +ability to respond to user input (e.g., scroll). + +This document proposes an API to animate a small subset of accelerated properties inside an +isolated execution environment, *worklet*. We believe this API hits a sweet spot, one that is +currently missing in the platform, in balancing among performance, richness, and rationality for +addressing our key use cases. In particular by limiting ourselves to a subset of accelerated +properties we give up some richness to gain performance while maintaining rationality. Finally, it +is possible to fine tune this trade-off in future iteration of this API by exposing additional +options and without fundamentally reworking this design. + +# Motivating Use Cases + +* Scroll-linked effects: + - Parallax + - Hidey-bar + +* Animations with custom timing functions (particularly those that are not calculable a priori) + + - Spring timing function + +* Location tracking and positioning: + + - Position: sticky + +* Procedural animation of multiple elements in sync: + + - Compositing growing / shrinking box with border (using 9 patch) + +* Animating scroll offsets: + + - Having multiple scrollers scroll in sync (e.g. diff viewer keeping old/new in sync when you + scroll either) + - Implementing smooth scroll animations (e.g., custom physic based fling curves) + +* Custom effect libraries with reliable performance. + +# Examples + +Below is a set of simple examples to showcase the syntax and API usage. + +## Example 1. A fade-in animation with spring timing + + +Define animator in the worklet scope: + +```javascript +registerAnimator('spring-fadein', class SpringAnimator { + static inputProperties = ['--spring-k']; + static outputProperties = ['opacity']; + static inputTime = true; + + animate(root, children, timeline) { + children.forEach(elem => { + // read a custom css property. + const k = elem.styleMap.get('--spring-k') || 1; + // compute progress using a fancy spring timing function. + const effectiveValue = springTiming(timeline.currentTime, k); + // update opacity accordingly. + elem.styleMap.opacity = effectiveValue; + }); + } + + springTiming(timestamp, k) { + // calculate fancy spring timing curve and return a sample. + return 0.42; + } + +}); +``` + +Assign elements to the animator declaratively in CSS: + +```html +.myFadin { + animator:'spring-fadein'; +} + +
+
+ +``` + +## Example 2. Multiple Parallax animations + + +Register the animator in AnimationWorklet scope: + +```javascript +registerAnimator('parallax', class ParallaxAnimator { + static inputProperties = ['transform', '--parallax-rate']; + static outputProperties = ['transform']; + static rootInputScroll = true; + + animate(root, children) { + // read scroller's vertical scroll offset. + const scrollTop = root.scrollOffsets.top; + children.forEach(background => { + // read parallax rate. + const rate = background.styleMap.get('--parallax-rate'); + // update parallax transform. + let t = background.styleMap.transform; + t.m42 = rate * scrollTop; + background.styleMap.transform = t; + }); + }); + } +}); +``` + +Declare and assign elements to animations: + +```html + + +
+
+
+
+ +
+
+
+``` + +Define custom CSS properties in Document Scope: + + +```javascript +CSS.registerProperty({ +  name: '--parallax-rate', +  inherits: false, + initial: 0.2, +  syntax: '' +}); + +``` + +## Example 3. Position Sticky + + +Register the animator in AnimationWorklet scope: + + +```javascript +// worklet scope + +registerAnimator('top-sticky', class TopStickyAnimator { + static inputProperties = ['--trigger-point']; + static outputProperties = ['transform']; + static rootInputScroll = true; + + animate(root, children) { + // read scroller's vertical scroll offset. + const scrollTop = root.scrollOffsets.top; + + children.forEach(sticky => { + const triggerPoint = child.styleMap.get('--trigger-point'); + // if we have scrolled passed the trigger point the sticky element needs + // to behave as if fixed. We do this by using a transform to position + // the element relative to its container. + const stickyOffset = Math.max(0 , scrollTop - triggerPoint); + sticky.styleMap.transform = new CSSTransformMatrix({m42: stickyOffset}); + }); + }); + } +}); +``` + +In Document scope: + +```html + + + +
+ +
+
+
+
+ + +``` + +# Key Concepts + +## Animator Root & Child Elements + +Each animator instance is associated with a single root element and optionally many child elements. +Animator child elements will come from the root element’s DOM sub-tree. These two category of +elements have their own defined inputs and outputs. + +Two CSS properties (`animator` and `animator-root`) may be used to assign an HTML elements to an +animator instance either as a root or a child. + +The ability to operate (read/write attributes) on many elements in a single callback enables +powerful effects that are very hard to achieve if an animator was to operate on a single element. + +### Root Element + +The document’s root element is the default root element for each registered animator. Additional +HTML elements may be designated as root element for a given animator using `animator-root: +animator-identifier` CSS syntax. A new animator instance is constructed for each root element and +its lifetime is tied to the element’s lifetime. The root element and all the child elements in its +DOM sub-tree associated with this animator name get assigned to this animator instance. See below +for more details. + +### Child Elements + +Any HTML element may be assigned to an animator instance using `animator: animator-identifier` CSS +syntax. In this case, the element is assigned as a child element to the first ancestor animator of +the given name. + +***Note:*** The animator receives this in a flat list but we can also consider sending a sparse +tree instead. + +## Assigning an Element to an Animator Instance + +As discussed, an animator gets assigned a single root element and optionally many children +elements. Assigning an element to an animator instance involves the following: + + +1. The element would be treated as if it has an `will-change` attribute for each of its output + attributes. +2. An `AnimationProxy` is constructed for the element allowing read and write to declared input + and output properties. + 1. For any input property defined for this element, the animation proxy’s style map is + populated with its computed value. + 2. Similarly the animation proxy’s scroll offset is populated by the element’s scroll offset. +3. The constructed proxy is passed to the animator instance in the worklet scope and becomes + available to the animate callback in its next call. +4. Once `animate` is invoked, the new output values in style map (and similarly output scroll + offsets) are used to update the corresponding effective values and visuals. Eventually these + values will be synced backed to the main thread. + +## Explicit Input and Output Attributes + +All input and output of the animation are declared explicitly. This allows implementations to do +optimizations such as not calling the *animate *callback if no input has changed or if no outputs +have any visible effect. The following inputs and outputs may be declared on the animator class +using static attributes: + +**Input** + +* Regular and Custom CSS Properties - `inputProperties` and `rootInputProperties` (list of + identifiers) +* Scroll Offset - `inputScroll` and `rootInputScroll` (boolean) +* Time - `inputTime (boolean) + +**Output** + + +* [“Fast” CSS Properties](#limiting-mutations-to-fast-subset) - `outputProperties` and + `rootOutputProperties` (list of identifiers) +* Scroll Offset - `outputProperties` and `rootOutputProperties` (boolean) + +## Falling Out of Sync + +The API is designed to allow animation worklets to run on threads other than the main thread. In +particular, it is recommended to run them in a dedicated thread and provide a best-effort attempt +to run in sync with frame production in compositor. This ensures the animations will not be +impacted by jank on main thread. It is still possible for such animation to slip in relation with +frame production if *animate* callback takes a long time. We believe such slippage is going to be a +rare event because there is no other tasks beside authored animation tasks running on the thread +and also the exposed features are limited to the fast subset (see below). + +## Limiting Mutations to Fast Subset + +We initially plan to limit the mutable attributes to a "fast" subset which can be mutated on the +fast path of almost all modern browsers. + +Proposed Mutable Attributes: + +* Scroll Offsets +* Transform +* Opacity + +This is necessary to ensure animations can run on the the fast path. In future we may consider +supporting all animatable properties which means running the worklet on main thread. The animator +definition surfaces enough information that makes it possible to decide the target executing thread +in advance. + +## Relationship to Web-Animation/CSS Transition + +Effective values from animator gets synced back to the main thread. These values sit at the top of +the animation [effect stack][effect-stack] meaning that they overrides all values from other +animations (except CSS transitions). The value is to be treated as a forward-filling animation with +a single key-frame i.e., the effective value remains in effect until there is a new value from +animator. + +# CSS Syntax + + +``` +animator: [ ]# +animator-root: [ ]# + +where is a +``` + +# Web IDL + + +```webidl +partial interface Window { + [SameObject] readonly attribute Worklet animationWorklet; +}; +``` + +```webidl +callback VoidFunction = void (); // a JS class + +[Global=(Worklet,AnimationWorklet),Exposed=AnimationWorklet] +interface AnimationWorkletGlobalScope : WorkletGlobalScope { + void registerAnimator(DOMString name, VoidFunction animatorCtor); +}; +``` + + + +```webidl +// animationCtor should be a class with the following structure +callback interface AnimatorCtor { + static boolean inputTime = false; + static inputProperties = []; + static outputProperties = []; + static rootInputProperties = []; + static rootOutputProperties = []; + void animate(AnimationProxy root, sequence children, optional AnimationTimeline timeline); +}; +``` + + +```webidl +dictionary ScrollOffests { + unrestricted double left; + unrestricted double top; +}; + +[ + Exposed=(Window,AnimationWorklet), +] interface AnimationProxy { + attribute ScrollOffests scrollOffsets; + attribute StylePropertyMap styleMap; +}; +``` + +# Contributors + +This design supersedes our [CompositorWorker proposal][cw-proposal] and was possible by key contribution from: + +* Rob Flack (flackr@) +* Ian Vollick (vollick@) +* Ian Kilpatrick (ikilpatrick@) +* Sadrul Chowdhury (sadrul@) +* Shane Stephens (shanes@) + +And many other members of Chrome web platform team. + + +[roc-thread]: https://lists.w3.org/Archives/Public/public-houdini/2015Mar/0020.html +[cw-proposal]: https://github.com/w3c/css-houdini-drafts/blob/master/composited-scrolling-and-animation/Explainer.md +[effect-stack]: https://w3c.github.io/web-animations/#combining-effects \ No newline at end of file From 052fc01755a9d35466b1bf5456c6d1c59f5ce894 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 14 Sep 2016 11:51:05 -0400 Subject: [PATCH 002/114] Initial commit --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e69a669e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Majid Valipour + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 6249c25b86f21a26dcf5da30294b5c74968fef8c Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 14 Sep 2016 13:27:20 -0400 Subject: [PATCH 003/114] Add a simple jekyl config --- _config.yml | 2 ++ index.md | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..adfe85de --- /dev/null +++ b/_config.yml @@ -0,0 +1,2 @@ +url: http://majido.github.io/animation-worklet-proposal +title: Animation Worklet Proposal diff --git a/index.md b/index.md index 3f8f6c00..09274e28 100644 --- a/index.md +++ b/index.md @@ -1,9 +1,12 @@ -# Animation Worklet Explainer +--- +title: Animation Worklet Explainer --- +# Animation Worklet Explainer +--- # Overview -AnimationWorklet is a new primitive for creating scroll-linked and other high performance +git remotegit AnimationWorklet is a new primitive for creating scroll-linked and other high performance procedural animations on the web. {:toc} From 07ff22d2c02bae6bf6feea1569e30ba6d615c3b7 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 14 Sep 2016 13:30:40 -0400 Subject: [PATCH 004/114] Just use README --- index.md => README.md | 3 ++- _config.yml | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) rename index.md => README.md (99%) delete mode 100644 _config.yml diff --git a/index.md b/README.md similarity index 99% rename from index.md rename to README.md index 09274e28..fe299b25 100644 --- a/index.md +++ b/README.md @@ -4,9 +4,10 @@ title: Animation Worklet Explainer # Animation Worklet Explainer --- + # Overview -git remotegit AnimationWorklet is a new primitive for creating scroll-linked and other high performance +AnimationWorklet is a new primitive for creating scroll-linked and other high performance procedural animations on the web. {:toc} diff --git a/_config.yml b/_config.yml deleted file mode 100644 index adfe85de..00000000 --- a/_config.yml +++ /dev/null @@ -1,2 +0,0 @@ -url: http://majido.github.io/animation-worklet-proposal -title: Animation Worklet Proposal From 907b015aa2998525ece576367eae8100a337eb4e Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 14 Sep 2016 13:34:36 -0400 Subject: [PATCH 005/114] minor clean up --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index fe299b25..be57b848 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ ---- -title: Animation Worklet Explainer ---- - # Animation Worklet Explainer --- @@ -10,8 +6,6 @@ title: Animation Worklet Explainer AnimationWorklet is a new primitive for creating scroll-linked and other high performance procedural animations on the web. -{:toc} - # Introduction Scripted effects (written in response to `requestAnimationFrame` or async `onscroll` events) are @@ -19,8 +13,8 @@ rich but are subject to main thread jankiness. On the other hand, accelerated CS animations can be fast (for a subset of *accelerated* properties) but are not rich enough to enable [many common use cases](#motivating-use-cases) and currently have no way to access scroll offset and other user input. This is why scripted effects are still very popular for implementing common -effects such as hidey-bars, parallax, position:sticky, and etc. We believe (and others [agree][roc- -thread] that there is a need for a new primitive for creating fast and rich visual effects with the +effects such as hidey-bars, parallax, position:sticky, and etc. We believe (and others [agree][roc-thread] +that there is a need for a new primitive for creating fast and rich visual effects with the ability to respond to user input (e.g., scroll). This document proposes an API to animate a small subset of accelerated properties inside an From 6a604e683d1a2aea26a0885c3d0cc6aecaafc523 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 14 Sep 2016 14:02:30 -0400 Subject: [PATCH 006/114] Minor language clean up --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index be57b848..052c88d6 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ rich but are subject to main thread jankiness. On the other hand, accelerated CS animations can be fast (for a subset of *accelerated* properties) but are not rich enough to enable [many common use cases](#motivating-use-cases) and currently have no way to access scroll offset and other user input. This is why scripted effects are still very popular for implementing common -effects such as hidey-bars, parallax, position:sticky, and etc. We believe (and others [agree][roc-thread] -that there is a need for a new primitive for creating fast and rich visual effects with the -ability to respond to user input (e.g., scroll). +effects such as hidey-bars, parallax, position:sticky, and etc. We believe (and others +[agree][roc-thread]) that there is a need for a new primitive for creating fast and rich visual +effects with the ability to respond to user input such as scroll. This document proposes an API to animate a small subset of accelerated properties inside an isolated execution environment, *worklet*. We believe this API hits a sweet spot, one that is @@ -53,12 +53,12 @@ options and without fundamentally reworking this design. # Examples -Below is a set of simple examples to showcase the syntax and API usage. +Below is a set of simple examples to showcase the proposed syntax and API usage. ## Example 1. A fade-in animation with spring timing -Define animator in the worklet scope: +Register the animator in AnimationWorklet scope: ```javascript registerAnimator('spring-fadein', class SpringAnimator { @@ -124,7 +124,7 @@ registerAnimator('parallax', class ParallaxAnimator { }); ``` -Declare and assign elements to animations: +Assign elements to the animator declaratively in CSS: ```html + +
+
main content.
+
+
+
some other content that scroll in sync.
+
+``` + # Key Concepts ## Animator Root & Child Elements From 2819d6105edb7b28f7640767b9559e8b419fca8b Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Mon, 19 Sep 2016 14:00:09 -0400 Subject: [PATCH 014/114] Fix sync scroller example --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 7e0446bb..6f8490d6 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ Register the animator in AnimationWorklet scope: ```javascript // worklet scope -registerAnimator('synced-scroller', class TopStickyAnimator { +registerAnimator('sync-scroller', class SyncScrollerAnimator { static get inputProperties = ['--scroller-type']; static get inputScroll = true; static get outputScroll = true; @@ -262,8 +262,6 @@ registerAnimator('synced-scroller', class TopStickyAnimator { elem.scrollOffsets.left = master.scrollOffsets.left; }); } - - } }); ``` From e3d388b123e68494459a3b326ffe6cd5656972e2 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Tue, 20 Sep 2016 08:29:15 -0400 Subject: [PATCH 015/114] Add link to sync-scroller and spring-timing demos --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6f8490d6..c8b94378 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ options and without fundamentally reworking this design. * Animations with custom timing functions (particularly those that are not calculable a priori) - - Spring timing function + - Spring timing function ([demo](https://flackr.github.io/houdini-samples/animation-worklet/spring-timing/)) * Location tracking and positioning: @@ -45,10 +45,13 @@ options and without fundamentally reworking this design. * Animating scroll offsets: - - Having multiple scrollers scroll in sync (e.g. diff viewer keeping old/new in sync when you - scroll either) + - Having multiple scrollers scroll in sync e.g. diff viewer keeping old/new in sync when you + scroll either ([demo](https://flackr.github.io/houdini-samples/animation-worklet/sync-scroller/)) - Implementing smooth scroll animations (e.g., custom physic based fling curves) +***Note***: Demos work best in the latest Chrome Canary with the experimental +web platform features enabled (`--enable-experimental-web-platform-features` +flag) otherwise they fallback to using main thread rAF to emulate the behaviour. # Examples From 8d9999f9408a3f262497312650cd7963dce1d73f Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Thu, 22 Sep 2016 09:01:33 -0400 Subject: [PATCH 016/114] Update parallax sample to use fixed backgrounds I think It didn't make sense for the backgrounds to be position:absolute - they'd scroll with the scroller and then be transformed more. Even if wanted to show counter-transforms, in the slippage model this could look terrible (jitter). Instead rely on the root document scrolling and make the backgrounds position:fixed. Overflow scroller divs are also possible when the background isn't a descendent of the scroller, but that's more complex and less common. @majido @flackr @ianvollick, agree? --- README.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c8b94378..c490781d 100644 --- a/README.md +++ b/README.md @@ -138,26 +138,20 @@ Assign elements to the animator declaratively in CSS: ```html -
-
-
-
- -
-
-
+
+
``` Define Custom CSS properties in document Scope: From 0f48683769704cde3ef8ef061635f5c618dd520e Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Thu, 22 Sep 2016 16:04:55 +0100 Subject: [PATCH 017/114] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c490781d..16d4fdc1 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ registerAnimator('spring-fadein', class SpringAnimator { // read a custom css property. const k = elem.styleMap.get('--spring-k') || 1; // compute progress using a fancy spring timing function. - const effectiveValue = springTiming(timeline.currentTime, k); + const effectiveValue = this.springTiming(timeline.currentTime, k); // update opacity accordingly. elem.styleMap.opacity = effectiveValue; }); From 0fa1bd58acef033b24e8ad928f4abe5dfb44a90e Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Thu, 22 Sep 2016 16:18:51 +0100 Subject: [PATCH 018/114] Remove contributors Too hard to keep up to date with all the contributions we get --- README.md | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 16d4fdc1..1ce333ae 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ properties we give up some richness to gain performance while maintaining ration is possible to fine tune this trade-off in future iteration of this API by exposing additional options and without fundamentally reworking this design. +This design supersedes our [CompositorWorker proposal][cw-proposal]. + # Motivating Use Cases * Scroll-linked effects: @@ -452,19 +454,6 @@ dictionary ScrollOffests { }; ``` -# Contributors - -This design supersedes our [CompositorWorker proposal][cw-proposal] and was possible by key contribution from: - -* Rob Flack (flackr@) -* Ian Vollick (vollick@) -* Ian Kilpatrick (ikilpatrick@) -* Sadrul Chowdhury (sadrul@) -* Shane Stephens (shanes@) - -And many other members of Chrome web platform team. - - [roc-thread]: https://lists.w3.org/Archives/Public/public-houdini/2015Mar/0020.html [cw-proposal]: https://github.com/w3c/css-houdini-drafts/blob/master/composited-scrolling-and-animation/Explainer.md [effect-stack]: https://w3c.github.io/web-animations/#combining-effects From 3ece308e52b21c851db701468aafe193bfab3a3f Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Thu, 22 Sep 2016 16:23:08 +0100 Subject: [PATCH 019/114] Avoid "master" and "slave" terms "input" and "output" seem close enough --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1ce333ae..3ed94f2c 100644 --- a/README.md +++ b/README.md @@ -250,15 +250,15 @@ registerAnimator('sync-scroller', class SyncScrollerAnimator { static get outputScroll = true; animate(root, children) { - var master = children.filter(e => { return e.styleMap.get("--scroller-type") == "master"})[0]; - var slaves = children.filter(e => { return e.styleMap.get("--scroller-type") == "slave"}); + var input = children.filter(e => { return e.styleMap.get("--scroller-type") == "input"})[0]; + var outputs = children.filter(e => { return e.styleMap.get("--scroller-type") == "output"}); if (!master) return; - slaves.forEach(elem => { - elem.scrollOffsets.top = master.scrollOffsets.top; - elem.scrollOffsets.left = master.scrollOffsets.left; + outputs.forEach(elem => { + elem.scrollOffsets.top = input.scrollOffsets.top; + elem.scrollOffsets.left = input.scrollOffsets.left; }); } }); @@ -274,12 +274,12 @@ Assign elements to the animator in document scope: #main_scroller { --animator: sync-scroller; - --scroller-type: master; + --scroller-type: input; } #alt_scroller { --animator: sync-scroller; - --scroller-type: slave; + --scroller-type: output; } From 509e0f80409d771ba01737d79a24c2c4a7cf5337 Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Thu, 22 Sep 2016 16:56:00 +0100 Subject: [PATCH 020/114] Don't expose AnimationProxy on Window --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ed94f2c..e7d28e02 100644 --- a/README.md +++ b/README.md @@ -447,7 +447,7 @@ dictionary ScrollOffests { }; [ - Exposed=(Window,AnimationWorklet), + Exposed=(AnimationWorklet), ] interface AnimationProxy { attribute ScrollOffests scrollOffsets; attribute StylePropertyMap styleMap; From 07c86c464ab54131d7b117798630d65bf1ff9918 Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Thu, 22 Sep 2016 16:57:48 +0100 Subject: [PATCH 021/114] Add scroll settings to IDL --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e7d28e02..9fc0b8e0 100644 --- a/README.md +++ b/README.md @@ -435,6 +435,10 @@ callback interface AnimatorCtor { static outputProperties = []; static rootInputProperties = []; static rootOutputProperties = []; + static boolean inputScroll = false; + static boolean outputScroll = false; + static boolean rootInputScroll = false; + static boolean rootOutputScroll = false; void animate(AnimationProxy root, sequence children, optional AnimationTimeline timeline); }; ``` From e45b3f25d271a22388dd158f9c314c759576e7bb Mon Sep 17 00:00:00 2001 From: Rick Byers Date: Fri, 23 Sep 2016 23:07:31 +0100 Subject: [PATCH 022/114] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9fc0b8e0..8b62dbc5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # Overview AnimationWorklet is a new primitive for creating scroll-linked and other high performance -procedural animations on the web. +procedural animations on the web. It is being incubated here as part of the [CSS Houdini task force](https://github.com/w3c/css-houdini-drafts/wiki), and if successful will be transferred to that task force for full standardization. # Introduction @@ -253,7 +253,7 @@ registerAnimator('sync-scroller', class SyncScrollerAnimator { var input = children.filter(e => { return e.styleMap.get("--scroller-type") == "input"})[0]; var outputs = children.filter(e => { return e.styleMap.get("--scroller-type") == "output"}); - if (!master) + if (!input) return; outputs.forEach(elem => { From 36983421a4ebcddbdaab2fa8dfd238ba2b463b82 Mon Sep 17 00:00:00 2001 From: Yoav Weiss Date: Mon, 26 Sep 2016 20:57:47 +0200 Subject: [PATCH 023/114] Adding baseline LICENSE.md --- LICENSE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..98fad556 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,5 @@ +All Reports in this Repository are licensed by Contributors under the +[W3C Software and Document +License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). Contributions to +Specifications are made under the [W3C CLA](https://www.w3.org/community/about/agreements/cla/). + From 900aefa45cd79039855dd5b27f782c434acdcaac Mon Sep 17 00:00:00 2001 From: Yoav Weiss Date: Mon, 26 Sep 2016 20:57:48 +0200 Subject: [PATCH 024/114] Adding baseline CONTRIBUTING.md --- CONTRIBUTING.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..82877ce8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# Web Platform Incubator Community Group + +This repository is being used for work in the Web Platform Incubator Community Group, governed by the [W3C Community License +Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To contribute, you must join +the CG. + +If you are not the sole contributor to a contribution (pull request), please identify all +contributors in the pull request's body or in subsequent comments. + +To add a contributor (other than yourself, that's automatic), mark them one per line as follows: + +``` ++@github_username +``` + +If you added a contributor by mistake, you can remove them in a comment with: + +``` +-@github_username +``` + +If you are making a pull request on behalf of someone else but you had no part in designing the +feature, you can remove yourself with the above syntax. From 7b2af45c035fd182b55630442f5d219c24afbeea Mon Sep 17 00:00:00 2001 From: Yoav Weiss Date: Mon, 26 Sep 2016 20:57:48 +0200 Subject: [PATCH 025/114] Adding baseline index.html --- index.html | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 00000000..7566bc6e --- /dev/null +++ b/index.html @@ -0,0 +1,38 @@ + + + + + Spec proposal + + + + +
+

+ This specification does neat stuff. +

+
+
+

+ This is an unofficial proposal. +

+
+ +
+

Introduction

+

+ See ReSpec's user guide + for how toget started! +

+
+ + From 522791ec77477e89ac4aba45061362a89ddeee88 Mon Sep 17 00:00:00 2001 From: Yoav Weiss Date: Mon, 26 Sep 2016 20:57:48 +0200 Subject: [PATCH 026/114] Adding baseline w3c.json --- w3c.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 w3c.json diff --git a/w3c.json b/w3c.json new file mode 100644 index 00000000..8f70b426 --- /dev/null +++ b/w3c.json @@ -0,0 +1,5 @@ + { + "group": ["80485"] +, "contacts": ["yoavweiss"] +, "shortName": "animation-worklet" +} \ No newline at end of file From 78fa35076ea936b1f34dfdb94f235937e2681235 Mon Sep 17 00:00:00 2001 From: Brenton Simpson Date: Mon, 26 Sep 2016 16:58:08 -0700 Subject: [PATCH 027/114] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b62dbc5..0d32f7e7 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Assign elements to the animator in document scope:
- +
From 149b51c663d0525b1d3034c1ec6a9001248529e7 Mon Sep 17 00:00:00 2001 From: Brenton Simpson Date: Mon, 26 Sep 2016 17:18:23 -0700 Subject: [PATCH 028/114] Correcting grammar --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0d32f7e7..b7cbf630 100644 --- a/README.md +++ b/README.md @@ -369,9 +369,11 @@ The API is designed to allow animation worklets to run on threads other than the particular, it is recommended to run them in a dedicated thread and provide a best-effort attempt to run in sync with frame production in the compositor. This ensures the animations will not be impacted by jank on main thread. It is still possible for such animation to slip in relation with -frame production if *animate* callback cannot be completed in time. We believe such slippage is going to be a -rare event because there is no other tasks beside authored animation tasks running on the thread -and also the exposed features are limited to the fast subset (see below). +frame production if *animate* callback cannot be completed in time. We believe such slippage is going to be +rare because: + +- There are no other tasks running on the thread. +- The exposed features are limited to the fast subset (see below). ## Limiting Mutations to Fast Subset From ccdd6d480ac5806b0f67d755e02a029838e86e07 Mon Sep 17 00:00:00 2001 From: Brenton Simpson Date: Mon, 26 Sep 2016 16:50:12 -0700 Subject: [PATCH 029/114] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7cbf630..3bc4e513 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ This design supersedes our [CompositorWorker proposal][cw-proposal]. * Scroll-linked effects: - Parallax ([demo](https://flackr.github.io/houdini-samples/animation-worklet/parallax-scrolling/)) - - Animated scroll headers, eg. "hidey-bars" ([demo](https://flackr.github.io/houdini-samples/animation-worklet/twitter-header/), [twitter](https://twitter.com/LEGO_Group), [polyer paper-scroll-header-panel](https://elements.polymer-project.org/elements/paper-scroll-header-panel?view=demo:demo/index.html)) + - Animated scroll headers, eg. "hidey-bars" ([demo](https://flackr.github.io/houdini-samples/animation-worklet/twitter-header/), [twitter](https://twitter.com/LEGO_Group), [Polymer `paper-scroll-header-panel`](https://elements.polymer-project.org/elements/paper-scroll-header-panel?view=demo:demo/index.html)) * Animations with custom timing functions (particularly those that are not calculable a priori) From 7a7b4f32f2d2986f2187b430e59be39492bf8028 Mon Sep 17 00:00:00 2001 From: Brenton Simpson Date: Tue, 27 Sep 2016 14:22:57 -0700 Subject: [PATCH 030/114] Fixing typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3bc4e513..01f95895 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ registerAnimator('spring-fadein', class SpringAnimator { Assign elements to the animator declaratively in CSS: ```html -.myFadin { +.myFadein { animator:'spring-fadein'; } From f8d9e7ca3c902cefcffaf98772e2f114f3795ce4 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Mon, 23 Jan 2017 10:08:51 -0500 Subject: [PATCH 031/114] Remove reference to the compositor This is likely a leftover from the CompositorWorker proposal. The text reads fine just referencing frame production without naming the source. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 01f95895..1b56bcfa 100644 --- a/README.md +++ b/README.md @@ -367,10 +367,10 @@ using static attributes: The API is designed to allow animation worklets to run on threads other than the main thread. In particular, it is recommended to run them in a dedicated thread and provide a best-effort attempt -to run in sync with frame production in the compositor. This ensures the animations will not be -impacted by jank on main thread. It is still possible for such animation to slip in relation with -frame production if *animate* callback cannot be completed in time. We believe such slippage is going to be -rare because: +to run in sync with frame production. This ensures the animations will not be impacted by jank on +main thread. It is still possible for such animation to slip in relation with frame production if +*animate* callback cannot be completed in time. We believe such slippage is going to be rare +because: - There are no other tasks running on the thread. - The exposed features are limited to the fast subset (see below). From 14731335b07306d23e70bdd1b3b0fa210e7b0bb5 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 15 Feb 2017 15:08:02 -0500 Subject: [PATCH 032/114] Remove old license file and leave the default W3C S&D license --- LICENSE | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e69a669e..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Majid Valipour - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. From a539bb82c17defa6973c1ed01a05a2657eb7d926 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 8 Mar 2017 16:51:00 -0500 Subject: [PATCH 033/114] Initial spec commit --- Makefile | 20 ++ Overview.bs | 520 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 540 insertions(+) create mode 100755 Makefile create mode 100644 Overview.bs diff --git a/Makefile b/Makefile new file mode 100755 index 00000000..8658b1f2 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +# $Id: Makefile,v 1.5 2008/02/06 14:05:15 mike Exp $ +# +# FIXME: New documentation needed. +# +# Use "make REMOTE=1" to use remote bikeshed + +SOURCEFILE=Overview.bs +OUTPUTFILE=Overview.html +PREPROCESSOR=bikeshed.py +REMOTE_PREPROCESSOR_URL=https://api.csswg.org/bikeshed/ + +all: $(OUTPUTFILE) + +$(OUTPUTFILE): $(SOURCEFILE) +ifneq (,$(REMOTE)) + curl $(REMOTE_PREPROCESSOR_URL) -F file=@$(SOURCEFILE) > "$@" +else + $(PREPROCESSOR) -f spec "$<" "$@" +endif + diff --git a/Overview.bs b/Overview.bs new file mode 100644 index 00000000..7db66ef1 --- /dev/null +++ b/Overview.bs @@ -0,0 +1,520 @@ + + + + +
+urlPrefix: https://heycam.github.io/webidl/; type: dfn;
+    text: NotSupportedError
+    urlPrefix: #dfn-;
+        text: callback this value
+        text: exception
+        text: throw
+        url: throw; text: thrown
+    url: es-invoking-callback-functions; text: Invoke
+urlPrefix: https://www.w3.org/TR/css3-transitions/#; type: dfn;
+    text: animatable properties
+urlPrefix: https://www.w3.org/TR/web-animations/#; type: dfn;
+    url: the-documents-default-timeline; text: default document timeline
+urlPrefix: https://tc39.github.io/ecma262/#sec-; type: dfn;
+    text: constructor
+    text: Construct
+    text: IsCallable
+    text: IsConstructor
+    text: HasProperty
+    url: map-objects; text:map object
+    url: get-o-p; text: Get
+    url: set-o-p-v-throw; text: Set
+    url: terms-and-definitions-function; text: function
+    urlPrefix: native-error-types-used-in-this-standard-
+        text: TypeError
+
+ +
+{
+    "explainer": {
+        "href": "https://github.com/WICG/animation-worklet/blob/gh-pages/README.md",
+        "title": "Animation Worklet Explainer",
+        "status": "CR",
+        "publisher": "WICG",
+        "deliveredBy": [
+            "https://github.com/WICG/animation-worklet//"
+        ]
+    }
+}
+
+ +Introduction {#intro} +===================== +This document introduces a new primitive for creating scroll-linked and other high performance +procedural animations on the web. For details on the rational and motivation see [[explainer]]. + +The Animation Worklet provides a method to create scripted animations that can mutate a set +of user visible animatable attributes. The API is designed to make it possible such animations to +run in performance critical parts of rendering pipeline. Although the specification does not +require certain performance guarantees (e.g., running in sync with every frame produced or in +isolation from main thread) but the API is designed to facilitate and encourage this. + + +Relationship to Web Animation API: Animations running on Animation +Worklet do not necessarily run on main thread and thus are not synchronized with default +document timeline. At the moment we do not expose any API to start, stop, compose or otherwise +control these animations from outside the worklet however such functionality can be build on top +of the lower level messaging primitives that is provided. + +Note: Access to input: We are interested on exposing additional user input (e.g., +scrolling input) to these animations so that authors can create jank-free input driven animations +which are not really possible today. + + +Animation Worklet {#animation-worklet} +============================== +Animation Worklet is a {{Worklet}} responsible for all classes related to custom +animation. The worklet can be accessed via {{animationWorklet}} attribute. + +The {{animationWorklet}}'s worklet global scope type is {{AnimationWorkletGlobalScope}}. + +
+partial interface Window {
+    [SameObject] readonly attribute Worklet animationWorklet;
+};
+
+ +
+callback VoidFunction = void ();
+
+[Global=(Worklet,AnimationWorklet),Exposed=AnimationWorklet]
+interface AnimationWorkletGlobalScope : WorkletGlobalScope {
+    void registerAnimation(DOMString name, VoidFunction animationCtor);
+};
+
+ + +
+ Note: This is how the class should look. +
+        callback interface AnimationClass {
+            void animate(DOMHighResolutionTimeStamp timestamp);
+            attribute EventHandler onmessage;
+        };
+    
+
+ + + +Concepts {#concepts} +==================== +A animation definition describes an author defined animation which can be referenced by +a animator. It consists of: + + - A class constructor which is the class constructor + + - A animation function which is the animation function callback + + +A worklet animatable attribute is a CSS animatable properties that can be read +and mutated inside an Animation Worklet. + +Note: Initially Chrome only supports "accelerated" attributes (i.e., 'opacity', 'transform', +'scrollTop', and 'scrollLeft') but user agents may expose any attribute which may be animated +efficiently without being subject to slowness in main thread. + +Issue: The description for what may be an animatable attribute is hand wavy. This should be + defined as a subset of animatable properties as described in web animation spec. + + +An animation proxy defines a handle to an element which can be used to read or mutate +explicitly exposed worklet animatable attribute on it. It consists of: + + - A proxied element + + - A map of proxied attributes and their values + +A animator describes a fully realized animation linking an animation +definition with the instance specific state such as its specific animation proxies. It +consists of: + + - A animation name + + - A message port + + +A animator has an associated animator scope. It consists of: + + - A animation name + + - A state property which is a structured data. + + - An animation requested flag + + - A message port + + +Registering a Custom Animation {#registering-custom-animation} +============================================================ +The {{AnimationWorkletGlobalScope}} has a animation name to animation definition map. +The map gets populated when {{registerAnimation(name, animationCtor)}} is called. + +When the registerAnimation(|name|, +|animationCtor|) method is called, the user agent must run the following steps: + + 1. If the |name| is not a valid <>, throw a TypeError and abort all these + steps. + + 2. If the |name| exists as a key in the animation name to animation definition map, + throw a NotSupportedError and abort all these steps. + + 3. If the result of IsConstructor(|animationCtor|) is false, throw a + TypeError and abort all these steps. + + 4. Let |prototype| be the result of Get(|animationCtor|, "prototype"). + + 5. If the result of Type(|prototype|) is not Object, throw a TypeError + and abort all these steps. + + 6. Let |animate| be the result of Get(|prototype|, "animate"). + + 7. If the result of IsCallable(|animate|) is false, throw a TypeError and + abort all these steps. + + 8. Let |definition| be a new animation definition with: + + - animation name being |name| + + - class constructor being |animationCtor| + + - animation function being |animate| + + 9. Add the key-value pair (|name| - |definition|) to the animation name to animation + definition map of the associated document. + +Note: Taken from paint API spec with some simplifications. + +The {{AnimationWorkletGlobalScope}} has a animation name to instance map. The map is +populated when the user agent constructs a new animation instant to run animator. + + +Creating a Animator {#creating-animator} +==================================================== +The {{AnimationWorkletGlobalScope}} has a animator scope list. An custom +animator scope is constructed and added to the list whenever a new animator +instance is constructed. + +The animator scope contains animator specific state so unlike animation instances +they cannot be disposed arbitrarily. Additionally, each scope is able to communicate with +its associated animator instance in the browsing context through an implicit message +channel. + +
+[
+    Exposed=(Window),
+    RaisesException=Constructor,
+    Constructor(DOMString name)
+] interface Animator {
+    [RaisesException]  void postMessage(any message, optional sequence<Transferable> transfer);
+    attribute EventHandler onmessage;
+};
+
+ + +
+[
+    Exposed=(AnimationWorklet)
+] interface AnimatorScope {
+    [RaisesException] void postMessage(any message, optional sequence<Transferable> transfer);
+    attribute EventHandler onmessage;
+};
+
+ +When the {{Animator}} constructor is called the user agent must run the following +steps: + 1. Let |name| be the first argument of the constructor. + + 2. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of + worklet's WorkletGlobalScopes from the animation {{Worklet}}. + + 3. Let |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animation name to animation definition map. + + If |definition| does not exist, throw a NotSupportedError and abort + the following steps. + + 4. Create a new {{MessagePort}} object. Let this be the |outside port|. + + 5. Let |animator| be a new {{CutomAnimator}} Object with: + + - animation name being |name| + + - message port being |outside port| + + 6. Create a new animator scope with animation name |name|, and + {{MessagePort}} |outside port|. Let this be the |scope| + + 7. Associate |scope| with |animator|. + + 8. Return |animator|. + +To create a new animator scope with animation name |name|, and +{{MessagePort}} |outside port|: + 1. Create a new {{AnimatorScope}} object |scope| with: + + - animation name being |name| + + - state property being a new map object + + - animation request flag being animation-requested + + 2. Create a new {{MessagePort}} object owned by |scope|. Let |inside port| be this + new object. + + 3. Entangle |outside port| and |inside port|. + + 4. Set |scope|'s port to |inside port| + + 5. Add |scope| to animator scope list. + +Issue: Consider passing an state object in the constructor (which can include proxies) so the +animator can start ticking and being useful immediately. + + +Creating Animation Proxy {#creating-animation-proxy} +==================================================== +An animation proxy can be constructed in the document scope using the {{AnimationProxy}} +constructor. Animation proxy is a clonable object and thus can be serialized in a +message and posted to any animator scope via the animator port. + +The {{AnimationProxy}} constructor takes two parameters, first the element which is being proxied, +and second a list of {{DOMString}} identifying all of the worklet animatable attribute +which may be read or mutated using this proxy. + + +
+
+dictionary ScrollOffests {
+    unrestricted double left;
+    unrestricted double top;
+};
+
+[
+    Exposed=(Window,AnimationWorklet),
+    RaisesException=Constructor,
+    Constructor(Element element, sequence proxiedAttributes)
+] interface AnimationProxy {
+    attribute ScrollOffests scrollOffsets;
+    attribute StylePropertyMap styleMap;
+
+    void disconnect();
+};
+
+ +When the {{AnimationProxy}} constructor is called the user agent must run the following +steps: + + 1. Let |element| and |proxiedAttributes| be the first and second arguments of the constructor. + + 2. If |element| is null or not an instance of {{Element}} abort the following steps. + + 4. If any of the attribute in |proxiedAttributes| is not a worklet animatable attribute + i.e., cannot be read or cannot be mutated inside an animation worklet, throw + a NotSupportedError and abort the following steps. + + + 3. Let |proxy| be a new {{AnimationProxy}} Object with: + + - proxied element being |element| + + 4. Populate |proxy| with the computed value’s for properties listed in + |proxiedAttributes|. + + 5. Return proxy + + +Any mutation on the proxied attributes updates the effective value of that attribute on the +proxied element. + +Issue: Perhaps AnimationProxy should inherit {{StylePropertyMap}} + +Issue: Explain {{disconnect}} which also explains what happens when a proxied element is removed. + In other houdini APIs (e.g., paint and layout) the painter is only invocated if the the + element is alive. In Animation Worklet this is not the case so proxied element may get + removed while worklet has a handle on them. Such removals are equivalent to explicitly calling + |disconnect|. + + +Running a Animator {#running-animator} +====================================================== +Each animator is associated with an animation requested flag. It must be +either animation-requested, animation-not-requested. It is initially set to +animation-requested. + +When a user agent decides to produce a new animation frame, if for a animator the +associated animation request flag is animation-requested then the the user agent +may generate a custom animation frame for the current frame. + +Note: The user agent is not required to run animations on every frame. It is legal to defer + generating a custom animation frame until a later frame. This allow the user agent to + provide a different service level according to their policy. See Service Level for + more details. + + +To generate a custom animation frame, the user agent iterates over animator +scope list as |scope|: + + 1. If the animation requested flag for the scope is animation-not-requested + the user agent may abort all the following steps and remove the |scope| from the + list. + + 2. Let |name| be the animation name of |scope|. + + 3. Let |state| be the state of |scope|. + + 4. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of worklet's + WorkletGlobalScopes from the animation {{Worklet}}. + + 5. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animation name to animation definition map. + + If |definition| does not exist abort the following steps. + + 6. Let |animationInstance| be the result of looking up |name| on |workletGlobalScope|'s + animation name to instance map. If |animationInstance| is null run the following + substeps: + + TODO: Add steps to create new animation instance given the animation definition. + The algorithm should use CreateDataProperty(instance, "state", {{null}}) + to create the state property + + 7. If the result of Set(|animationInstance|, "state", |state|) is false abort the + following steps. + + 8. Let |animateFunction| be |definition|'s animation function. + + 9. Let |timestamp| be a {{DOMHighResTimeStamp}} indicating the current frame start time. + + 10. Invoke |animateFunction| with arguments «|timestamp|», + and with |animationInstance| as the callback this value. + + 11. Let |newState| be the result of Get(|animationInstance|, "state"). + + 12. Update |scope|'s state to be |newState|. + + 13. Call Set(|animationInstance|, "state", {{null}}). + + +Note: It is legal for the user agent to run a animator multiple times in the same +frame. + +Issue: Should we keep track of proxies passed to a worklet and not animate any + animators whose proxies are not within the visual viewport or whose attributes + are not mutated. + +Issue: We currently do not have an "initialized" notion. We allow mutations on the proxies while + uninitialized (or inactive). Such mutations will not have any effect until the proxy is + initialized. The initial value of properties will be the value at the proxy creation time. + Perhaps we should describe that proxy mutation may not take effect immediately. + +Issue: We need to throw an error when animation tries to store non-clonable data in state. + Should this be this eagerly at step 12? + +Closing a Animator {#closing-animator} +==================================================== +TODO: Define a close function that ends the animator. It can be called from document context or +animation context. + +Receiving and Sending Message {#receiving-and-sending-message} +============================================================= + +Each {{Animator}} instances have an implicit {{MessagePort}} associated with them. This port +is created when the animator instance is created and should have a lifetime that is as long as the +animator instance's lifetime. + +Similarly, each animator scope has a {{MessagePort}} which is entangled with the +associated animator port. Together, these ports create an implicit message +channel which can be used to communicate between the animator instance and its scope. + +All messages received by the animator port should immediately be re- +targeted at the {{Animator}} instance. Similarly any invocation of {{postMessage()}} on the +animator instance must immediately invoke the method of the same name on the port, with +the same arguments, and return the same return value. + +All messages received by the animator scope port should immediately be re- +targeted at an animation instance. This requires the worklet to first associate the scope +with an animation instance. Similarly any invocation of {{postMessage()}} on the animation +instance must immediately invoke the method of the same name on the port, with the same arguments, +and return the same return value. + + +Note: It is legal for a user agents to only deliver messages to a animator scope +immediately before running that animator. Similarly messages to a animator may be deferred +to any appropriate time in the document lifecycle. + +Issue: Refactor association steps to be used here and in running a animator. + +Service Level {#service-level} +============================== +TODO: Describe three difference service levels that user agent may provide. + +1. In sync with compositor frame production (isolated, sync) +2. Async from compositor but on own dedicated thread (isolated, async) +3. Async but on main frame with timing defined in relation to existing rAF (not isolated, async) + +Issue: Maybe this should become a v2 concept where we also introduce an API to allow authors to + request a certain service level. + + +Examples {#examples} +==================== + +Example 1: A parallax background. {#example-1} +----------------------------------------- + +
+<div id="scroller">
+    <div id="scroller">
+    </div>
+    Some content that overflows
+</div>
+
+
+ +
+// Inside AnimationWorkletGlobalScope.
+registerAnimation('parallax', class {
+    animate(timestamp) {
+        // read scroller vertical scroll offset.
+        const scrollTop = this.state.scroller.scrollTop
+        // update parallax transform
+        let t = this.state.parallax.transform;
+        t.m42 =  -0.2 * scrollTop;
+        this.state.parallax.transform = t;
+    }
+
+    onmessage(message) {
+        this.state.scroller = message.data[0]
+        this.state.parallax = message.data[1];
+    }
+});
+
+// Inside document scope
+
+document.animationWorklet.import('parallax.js').then(function() {
+    var scroller = new AnimationProxy(getElementById('scroller'), ['scrollTop']);
+    var parallax = new AnimationProxy(getElementById('parallax'), ['transform']);
+
+    var worklet = new AnimationWorklet('parallax');
+    worklet.postMessage([scroller, parallax]);
+});
+
+
From 6701aa5703694d84ae5f309b0d6dbab30436205f Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 22 Mar 2017 11:39:03 -0400 Subject: [PATCH 034/114] Update with new Animator concept and syntax and add CSS notation and update the example --- Overview.bs | 470 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 285 insertions(+), 185 deletions(-) diff --git a/Overview.bs b/Overview.bs index 7db66ef1..0ef820dd 100644 --- a/Overview.bs +++ b/Overview.bs @@ -7,7 +7,7 @@ Previous Version: Shortname: css-animation-api Level: 1 Abstract: -Editor: Majid Valipour, majidvp@chromium.org +Editor: Majid Valipour, majidvp@google.com @@ -71,18 +71,18 @@ isolation from main thread) but the API is designed to facilitate and encourage Relationship to Web Animation API: Animations running on Animation Worklet do not necessarily run on main thread and thus are not synchronized with default document timeline. At the moment we do not expose any API to start, stop, compose or otherwise -control these animations from outside the worklet however such functionality can be build on top -of the lower level messaging primitives that is provided. +control these animations from outside the worklet however our plan is to leverage existing web +animation APIs such as Element::getAnimations(). Note: Access to input: We are interested on exposing additional user input (e.g., scrolling input) to these animations so that authors can create jank-free input driven animations which are not really possible today. -Animation Worklet {#animation-worklet} +Animation Worklet {#animation-worklet-desc} ============================== Animation Worklet is a {{Worklet}} responsible for all classes related to custom -animation. The worklet can be accessed via {{animationWorklet}} attribute. +animations. The worklet can be accessed via {{animationWorklet}} attribute. The {{animationWorklet}}'s worklet global scope type is {{AnimationWorkletGlobalScope}}. @@ -97,18 +97,22 @@ callback VoidFunction = void (); [Global=(Worklet,AnimationWorklet),Exposed=AnimationWorklet] interface AnimationWorkletGlobalScope : WorkletGlobalScope { - void registerAnimation(DOMString name, VoidFunction animationCtor); + void registerAnimator(DOMString name, VoidFunction animatorCtor); };
Note: This is how the class should look. -
-        callback interface AnimationClass {
-            void animate(DOMHighResolutionTimeStamp timestamp);
-            attribute EventHandler onmessage;
-        };
+    
+        class FooAnimator {
+            static get inputProperties() { return ['--foo']; }
+            static get outputProperties() { return ['transform']; }
+
+            animate(root, children, timeline) {
+                // Animation frame logic goes here
+            }
+        }
     
@@ -116,70 +120,73 @@ interface AnimationWorkletGlobalScope : WorkletGlobalScope { Concepts {#concepts} ==================== -A animation definition describes an author defined animation which can be referenced by -a animator. It consists of: +A animator definition describes an author defined animation which can be referenced by +an animator. It consists of: - - A class constructor which is the class constructor + - A class constructor. - - A animation function which is the animation function callback + - A animate function. + + - A animator input property list. + - A animator output property list. -A worklet animatable attribute is a CSS animatable properties that can be read -and mutated inside an Animation Worklet. + - A animator root input property list. -Note: Initially Chrome only supports "accelerated" attributes (i.e., 'opacity', 'transform', -'scrollTop', and 'scrollLeft') but user agents may expose any attribute which may be animated -efficiently without being subject to slowness in main thread. + - A animator root output property list. -Issue: The description for what may be an animatable attribute is hand wavy. This should be - defined as a subset of animatable properties as described in web animation spec. - -An animation proxy defines a handle to an element which can be used to read or mutate -explicitly exposed worklet animatable attribute on it. It consists of: +An element proxy defines a handle to an element which can be used to read or +mutate explicitly exposed animatable attributes on it. It consists of: - A proxied element - - A map of proxied attributes and their values + - A map of proxied input attributes and their values + +An animator describes a fully realized custom animation linking an animator +definition with the instance specific: + + - A animator name. -A animator describes a fully realized animation linking an animation -definition with the instance specific state such as its specific animation proxies. It -consists of: + - An animator scope. - - A animation name - - A message port +A animator instance has an associated animator scope which is responsible for +specific animator state such as its element proxies. It consists of: + - A animator name. -A animator has an associated animator scope. It consists of: + - An animation requested flag. - - A animation name + - A rootelement proxy. - - A state property which is a structured data. + - A list of associated children element proxies. - - An animation requested flag - - A message port +Issue: Todo: Remove the concept of animator scope and merge what it owns in animator. +The concept of animator scope is no longer needed because we have decided not to kill animator +instances mid frame so state can be saved there. Also we are removing the message ports so we +no longer need to keep them alive independently. -Registering a Custom Animation {#registering-custom-animation} +Registering an Animator {#registering-animator} ============================================================ -The {{AnimationWorkletGlobalScope}} has a animation name to animation definition map. -The map gets populated when {{registerAnimation(name, animationCtor)}} is called. +The {{AnimationWorkletGlobalScope}} has a animator name to animator definition map. +The map gets populated when {{registerAnimator(name, animatorCtor)}} is called. -When the registerAnimation(|name|, -|animationCtor|) method is called, the user agent must run the following steps: +When the registerAnimator(|name|, +|animatorCtor|) method is called, the user agent must run the following steps: 1. If the |name| is not a valid <>, throw a TypeError and abort all these steps. - 2. If the |name| exists as a key in the animation name to animation definition map, + 2. If the |name| exists as a key in the animator name to animator definition map, throw a NotSupportedError and abort all these steps. - 3. If the result of IsConstructor(|animationCtor|) is false, throw a + 3. If the result of IsConstructor(|animatorCtor|) is false, throw a TypeError and abort all these steps. - 4. Let |prototype| be the result of Get(|animationCtor|, "prototype"). + 4. Let |prototype| be the result of Get(|animatorCtor|, "prototype"). 5. If the result of Type(|prototype|) is not Object, throw a TypeError and abort all these steps. @@ -189,34 +196,72 @@ When the registerAnimation(|name|, 7. If the result of IsCallable(|animate|) is false, throw a TypeError and abort all these steps. - 8. Let |definition| be a new animation definition with: + 8. Let |inputProperties| be the result of parsing a property list with name + "inputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception and + abort all these steps. + + 9. Let |outputProperties| be the result of parsing a property list with name + "outputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception and + abort all these steps. + + 10. Let |rootInputProperties| be the result of parsing a property list with name + "rootInputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception + and abort all these steps. + + 11. Let |rootOutputProperties| be the result of parsing a property list with name + "rootOutputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception + and abort all these steps. + - - animation name being |name| + 12. Let |definition| be a new animator definition with: - - class constructor being |animationCtor| + - animator name being |name| - - animation function being |animate| + - class constructor being |animatorCtor| - 9. Add the key-value pair (|name| - |definition|) to the animation name to animation + - animate function being |animate| + + - animator input property list being |inputProperties| + + - animator input property list being |outputProperties| + + - animator root input property list being |rootInputProperties| + + - animator root output property list being |rootOutputProperties| + + + 13. Add the key-value pair (|name| - |definition|) to the animator name to animation definition map of the associated document. -Note: Taken from paint API spec with some simplifications. -The {{AnimationWorkletGlobalScope}} has a animation name to instance map. The map is -populated when the user agent constructs a new animation instant to run animator. +The {{AnimationWorkletGlobalScope}} has a animator name to instance map. The map is +populated when the user agent constructs a new animator instance. + +When parsing a property list with name name for animatorCtor, +the user agent must run the following steps: + + 1. Let |properties| be an empty sequence<DOMString> + + 2. Let |propertiesIterable| be the result of Get(|animatorCtor|, |name|). + 3. If |propertiesIterable| is not undefined, then set |properties| to the result of + converting |propertiesIterable| to a sequence<DOMString>. If an + exception is thrown, rethrow the exception and abort all these steps. -Creating a Animator {#creating-animator} + + +Creating an Animator {#creating-animator} ==================================================== -The {{AnimationWorkletGlobalScope}} has a animator scope list. An custom -animator scope is constructed and added to the list whenever a new animator -instance is constructed. +The {{AnimationWorkletGlobalScope}} has a animator scope list. An animator scope +is constructed and added to the list whenever a new animator instance is constructed. -The animator scope contains animator specific state so unlike animation instances +The animator scope contains animator specific message port so unlike animator instances they cannot be disposed arbitrarily. Additionally, each scope is able to communicate with its associated animator instance in the browsing context through an implicit message channel. + +
 [
     Exposed=(Window),
@@ -246,35 +291,33 @@ steps:
         worklet's WorkletGlobalScopes from the animation {{Worklet}}.
 
     3. Let |definition| be the result of looking up |name| on the |workletGlobalScope|'s
-        animation name to animation definition map.
+        animator name to animator definition map.
 
         If |definition| does not exist, throw a NotSupportedError and abort
         the following steps.
 
     4. Create a new {{MessagePort}} object. Let this be the |outside port|.
 
-    5. Let |animator| be a new {{CutomAnimator}} Object with:
+    5. Let |animator| be a new {{Animator}} Object with:
 
-        - animation name being |name|
+        - animator name being |name|
 
         - message port being |outside port|
 
-    6. Create a new animator scope with animation name |name|, and
+    6. Create a new animator scope with animator name |name|, and
         {{MessagePort}} |outside port|. Let this be the |scope|
 
     7. Associate |scope| with |animator|.
 
     8. Return |animator|.
 
-To create a new animator scope with animation name |name|, and
-{{MessagePort}} |outside port|:
+To create a new animator scope given animator name as |name|, and
+{{MessagePort}} as |outside port|, the user agent must run the following steps:
     1. Create a new {{AnimatorScope}} object |scope| with:
 
-        - animation name being |name|
-
-        - state property being a new map object
+        - animator name being |name|
 
-        - animation request flag being animation-requested
+        - animation request flag being 
 
     2. Create a new {{MessagePort}} object owned by |scope|. Let |inside port| be this
         new object.
@@ -285,41 +328,33 @@ To create a new animator scope with animation name |name|, and
 
     5. Add |scope| to animator scope list.
 
-Issue: Consider passing an state object in the constructor (which can include proxies) so the
-animator can start ticking and being useful immediately.
 
-
-Creating Animation Proxy {#creating-animation-proxy}
+Creating an Element Proxy {#creating-element-proxy}
 ====================================================
-An animation proxy can be constructed in the document scope using the {{AnimationProxy}}
-constructor. Animation proxy is a clonable object and thus can be serialized in a
+An element proxy can be constructed in the document scope using the {{ElementProxy}}
+constructor. element proxy is a clonable object and thus can be serialized in a
 message and posted to any animator scope via the animator port.
 
-The {{AnimationProxy}} constructor takes two parameters, first the element which is being proxied,
+The {{ElementProxy}} constructor takes two parameters, first the element which is being proxied,
 and second a list of {{DOMString}} identifying all of the worklet animatable attribute
 which may be read or mutated using this proxy.
 
 
 
-
-dictionary ScrollOffests {
-    unrestricted double left;
-    unrestricted double top;
-};
-
 [
     Exposed=(Window,AnimationWorklet),
     RaisesException=Constructor,
     Constructor(Element element, sequence proxiedAttributes)
-] interface AnimationProxy {
-    attribute ScrollOffests scrollOffsets;
-    attribute StylePropertyMap styleMap;
-
-    void disconnect();
+] interface ElementProxy {
+    attribute StylePropertyMapReadOnly inputStyleMap;
+    attribute StylePropertyMapReadOnly outputStyleMap;
 };
 
-When the {{AnimationProxy}} constructor is called the user agent must run the following +Issue: Need to figure out how we are handlign scroll offsets. Previous approach was to have +mutable offset on each proxy but the new idea is to have readonly ScrollTimeline. + +When the {{ElementProxy}} constructor is called the user agent must run the following steps: 1. Let |element| and |proxiedAttributes| be the first and second arguments of the constructor. @@ -331,108 +366,183 @@ steps: a NotSupportedError and abort the following steps. - 3. Let |proxy| be a new {{AnimationProxy}} Object with: + 3. Let |proxy| be a new {{ElementProxy}} Object with: - proxied element being |element| - 4. Populate |proxy| with the computed value’s for properties listed in - |proxiedAttributes|. + 4. update proxy input style map with |proxy| and |proxiedAttributes|. + + 5. Return proxy. - 5. Return proxy +Any write on the outputStyle map, updates the effective value of the used style value of the on the +proxied element. This happens asynchronously. -Any mutation on the proxied attributes updates the effective value of that attribute on the -proxied element. -Issue: Perhaps AnimationProxy should inherit {{StylePropertyMap}} +Issue: We now longer allow direct construction of ElementProxy. Remove it. -Issue: Explain {{disconnect}} which also explains what happens when a proxied element is removed. - In other houdini APIs (e.g., paint and layout) the painter is only invocated if the the +Issue: Explain what happens when a proxied element is removed. + In other houdini APIs (e.g., paint and layout) the painter is only invocated if the element is alive. In Animation Worklet this is not the case so proxied element may get - removed while worklet has a handle on them. Such removals are equivalent to explicitly calling - |disconnect|. + removed while worklet has a handle on them. + + +When the user agent wants to update proxy input style map given |proxy|, and +|properties|, it must run the following steps: + + + 1. Let |styleMap| be a new {{StylePropertyMapReadOnly}} populated with only the + computed value of proxied element for properties listed in |properties|. + + 2. Set |proxy|'s inputStyleMap to |styleMap|. + -Running a Animator {#running-animator} +Running Animators {#running-animators} ====================================================== Each animator is associated with an animation requested flag. It must be -either animation-requested, animation-not-requested. It is initially set to -animation-requested. +either frame-requested, frame-not-requested. It is initially set to +frame-requested. -When a user agent decides to produce a new animation frame, if for a animator the -associated animation request flag is animation-requested then the the user agent -may generate a custom animation frame for the current frame. +When a user agent wants to produce a new animation frame, if for a animator the +associated animation request flag is frame-requested then the the user agent +must run animators for the current frame. Note: The user agent is not required to run animations on every frame. It is legal to defer - generating a custom animation frame until a later frame. This allow the user agent to - provide a different service level according to their policy. See Service Level for - more details. + generating an animation frame until a later frame. This allow the user agent to + provide a different service level according to their policy. -To generate a custom animation frame, the user agent iterates over animator +When the user agent wants to run animators, it must iterates over animator scope list as |scope|: - 1. If the animation requested flag for the scope is animation-not-requested - the user agent may abort all the following steps and remove the |scope| from the - list. + 1. If the animation requested flag for the scope is frame-not-requested + the user agent may abort all the following steps. - 2. Let |name| be the animation name of |scope|. + 2. Let |name| be the animator name of |scope|. - 3. Let |state| be the state of |scope|. - - 4. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of worklet's + 3. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of worklet's WorkletGlobalScopes from the animation {{Worklet}}. - 5. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s - animation name to animation definition map. + 4. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animator name to animator definition map. If |definition| does not exist abort the following steps. - 6. Let |animationInstance| be the result of looking up |name| on |workletGlobalScope|'s - animation name to instance map. If |animationInstance| is null run the following + 5. Let |animatorInstance| be the result of looking up |name| on |workletGlobalScope|'s + animator name to instance map. If |animatorInstance| is null run the following substeps: - TODO: Add steps to create new animation instance given the animation definition. - The algorithm should use CreateDataProperty(instance, "state", {{null}}) - to create the state property - - 7. If the result of Set(|animationInstance|, "state", |state|) is false abort the - following steps. + Issue: TODO: Add steps to create new animation instance given the animator definition. - 8. Let |animateFunction| be |definition|'s animation function. + 6. Let |animateFunction| be |definition|'s animate function. 9. Let |timestamp| be a {{DOMHighResTimeStamp}} indicating the current frame start time. - 10. Invoke |animateFunction| with arguments «|timestamp|», - and with |animationInstance| as the callback this value. + 10. Let |timeline| be a new {{AnimationTimline}} with its "currentTime" set to |timestamp|. - 11. Let |newState| be the result of Get(|animationInstance|, "state"). + 11. Let |root| be a root element proxy of |scope|. - 12. Update |scope|'s state to be |newState|. + 12. Let |children| be a children element proxies of |scope|. - 13. Call Set(|animationInstance|, "state", {{null}}). + 11. Invoke |animateFunction| with arguments «|root|, |children|, |timeline|», + and with |animatorInstance| as the callback this value. -Note: It is legal for the user agent to run a animator multiple times in the same +Note: It is legal for the user agent to run an animator multiple times in the same frame. -Issue: Should we keep track of proxies passed to a worklet and not animate any - animators whose proxies are not within the visual viewport or whose attributes +Issue: We should add provision that allows user agents to skip calling animate + on any animators whose proxies are not within the visual viewport or whose attributes are not mutated. -Issue: We currently do not have an "initialized" notion. We allow mutations on the proxies while - uninitialized (or inactive). Such mutations will not have any effect until the proxy is - initialized. The initial value of properties will be the value at the proxy creation time. - Perhaps we should describe that proxy mutation may not take effect immediately. - -Issue: We need to throw an error when animation tries to store non-clonable data in state. - Should this be this eagerly at step 12? - -Closing a Animator {#closing-animator} +Closing an Animator {#closing-animator} ==================================================== TODO: Define a close function that ends the animator. It can be called from document context or animation context. + +CSS Animator Notation {#css-animator-notation} +============================================== + +Two CSS properties 'animator' and 'animator-root' may be used to +assign an HTML elements to an animator instance either as a root element or a child element. + + +
+Name: animator
+Value:  [ none |  <> ]#
+Initial: auto
+Applies to: all elements
+Inherited: no
+Computed value: as specified
+Percentages: N/A
+Media: interactive
+Animatable: no
+
+ +
+
none +
+ There will be no animators. +
<> +
+ If there is a animator definition registered with that name, then a new + animator instance will be created with this element as its root element proxy. + The new animator lifetime is tied to this root element's lifetime. If no animator + definition exists with that name, then the instance will be created as soon as one is + registered. +
+ + + +
+Name: animator-root
+Value:  [ none |  <> ]#
+Initial: none
+Applies to: all elements
+Inherited: no
+Computed value: as specified
+Percentages: N/A
+Media: interactive
+Animatable: no
+
+ + +
+
none +
+ There will be no animators. +
<> +
+ If there is a animator definition registered with that name, then this element is + assigned to the first ancestor animator instance of the given name as a child element proxy. + If no animator definition exists with that name, then the element gets assigned as soon + as one is registered. + + Issue: TODO: If no ancestor animator instance exists with that name then we should create one + with document root element as its root. +
+ + +Note: All the elements in the root element's DOM sub-tree that get associated with the same animator + name will get assigned to the the animator instance linked with this root element. + + +Issue: Todo: Write the algorithm for element assignments. It will include construction of a new +{{ElementProxy}}, looking up or creating animator instance, and assiging the animator. We probably +need a diagram here too. + + +Effect Stack {#effect-stack} +============================ + +Issue: Todo: the animators output style values have the highest order in animation stack effect and +their composite operation is "replace" which is going to allow them to run independent on other +animations and in a different thread. Supporting other composite operation is not in scope at this +point. + + Receiving and Sending Message {#receiving-and-sending-message} ============================================================= @@ -456,65 +566,55 @@ instance must immediately invoke the method of the same name on the port, with t and return the same return value. -Note: It is legal for a user agents to only deliver messages to a animator scope -immediately before running that animator. Similarly messages to a animator may be deferred +Note: It is legal for a user agents to only deliver messages to an animator scope +immediately before running that animator. Similarly messages to an animator may be deferred to any appropriate time in the document lifecycle. -Issue: Refactor association steps to be used here and in running a animator. - -Service Level {#service-level} -============================== -TODO: Describe three difference service levels that user agent may provide. - -1. In sync with compositor frame production (isolated, sync) -2. Async from compositor but on own dedicated thread (isolated, async) -3. Async but on main frame with timing defined in relation to existing rAF (not isolated, async) - -Issue: Maybe this should become a v2 concept where we also introduce an API to allow authors to - request a certain service level. Examples {#examples} ==================== -Example 1: A parallax background. {#example-1} +Example 1: A fade-in animation with spring timing. {#example-1} -----------------------------------------
-<div id="scroller">
-    <div id="scroller">
-    </div>
-    Some content that overflows
-</div>
+.myFadein {
+  animator:'spring-fadein';
+}
+
+<section class='myFadein'></sectionlt;
+<section class='myFadein' style="--spring-k: 25;"></sectionlt;
+
+<scriptlt;
+document.animationWorklet.import('spring-timing.js');
+</scriptlt;
 
 
-// Inside AnimationWorkletGlobalScope.
-registerAnimation('parallax', class {
-    animate(timestamp) {
-        // read scroller vertical scroll offset.
-        const scrollTop = this.state.scroller.scrollTop
-        // update parallax transform
-        let t = this.state.parallax.transform;
-        t.m42 =  -0.2 * scrollTop;
-        this.state.parallax.transform = t;
+// Inside AnimationWorkletGlobalScope
+registerAnimator('spring-fadein', class {
+
+    static inputProperties =  ['--spring-k'];
+    static outputProperties =  ['opacity'];
+    static inputTime = true;
+
+    animate(root, children, timeline) {
+        this.startTime_ = this.startTime_ || timeline.currentTime;
+        const deltaT = timeline.currentTime - this.startTime_;
+        children.forEach(elem => {
+          // read a custom css property.
+          const k = elem.inputStyleMap.get('--spring-k') || 1;
+          // compute progress using a fancy spring timing function.
+          const effectiveValue = 1 * springTiming(deltaT, k);
+          // update opacity accordingly.
+          elem.ouputStyleMap.opacity = effectiveValue;
+        });
     }
 
-    onmessage(message) {
-        this.state.scroller = message.data[0]
-        this.state.parallax = message.data[1];
+    springTiming(deltaT, k) {
+        // simulate the spring effect and return a progress value between [-1, 1];
     }
 });
-
-// Inside document scope
-
-document.animationWorklet.import('parallax.js').then(function() {
-    var scroller = new AnimationProxy(getElementById('scroller'), ['scrollTop']);
-    var parallax = new AnimationProxy(getElementById('parallax'), ['transform']);
-
-    var worklet = new AnimationWorklet('parallax');
-    worklet.postMessage([scroller, parallax]);
-});
-
 
From 0e62f97416920ed0b514c9766211e6a460189e71 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 22 Mar 2017 15:50:31 -0400 Subject: [PATCH 035/114] minor updates --- Overview.bs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Overview.bs b/Overview.bs index 0ef820dd..4dacc6ef 100644 --- a/Overview.bs +++ b/Overview.bs @@ -379,12 +379,12 @@ Any write on the outputStyle map, updates the effective value of the used style proxied element. This happens asynchronously. -Issue: We now longer allow direct construction of ElementProxy. Remove it. +Issue: Todo: Remove this as we no longer allow direct construction of ElementProxy. -Issue: Explain what happens when a proxied element is removed. - In other houdini APIs (e.g., paint and layout) the painter is only invocated if the - element is alive. In Animation Worklet this is not the case so proxied element may get - removed while worklet has a handle on them. +Issue: Todo: Explain what happens when a proxied element is removed. In other houdini APIs (e.g., + paint and layout) the painter is only invocated if the element is alive. In Animation + Worklet this is not the case so proxied element may get removed while worklet has a handle + on them. When the user agent wants to update proxy input style map given |proxy|, and @@ -433,7 +433,7 @@ scope list as |scope|: animator name to instance map. If |animatorInstance| is null run the following substeps: - Issue: TODO: Add steps to create new animation instance given the animator definition. + Issue: Todo: Add steps to create new animation instance given the animator definition. 6. Let |animateFunction| be |definition|'s animate function. @@ -452,13 +452,13 @@ scope list as |scope|: Note: It is legal for the user agent to run an animator multiple times in the same frame. -Issue: We should add provision that allows user agents to skip calling animate +Issue: Todo: add provision that allows user agents to skip calling animate on any animators whose proxies are not within the visual viewport or whose attributes are not mutated. Closing an Animator {#closing-animator} ==================================================== -TODO: Define a close function that ends the animator. It can be called from document context or +Todo: Define a close function that ends the animator. It can be called from document context or animation context. @@ -520,7 +520,7 @@ Animatable: no If no animator definition exists with that name, then the element gets assigned as soon as one is registered. - Issue: TODO: If no ancestor animator instance exists with that name then we should create one + Issue: Todo: If no ancestor animator instance exists with that name then we should create one with document root element as its root. From 988dac75ea01dab5141ec45726ce18f250317c90 Mon Sep 17 00:00:00 2001 From: Majid Valipour Date: Wed, 22 Mar 2017 18:17:13 -0400 Subject: [PATCH 036/114] Add section around when to run animators, and clear confusion around scope vs animator - Merge animator and scope and make animator object a distinct term - Add section on when to dirty the flag - Remove unnecessary IDLs --- Overview.bs | 274 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 163 insertions(+), 111 deletions(-) diff --git a/Overview.bs b/Overview.bs index 4dacc6ef..2c328b78 100644 --- a/Overview.bs +++ b/Overview.bs @@ -121,7 +121,7 @@ interface AnimationWorkletGlobalScope : WorkletGlobalScope { Concepts {#concepts} ==================== A animator definition describes an author defined animation which can be referenced by -an animator. It consists of: +an animator instance. It consists of: - A class constructor. @@ -136,40 +136,34 @@ an animator. It consists of: - A animator root output property list. -An element proxy defines a handle to an element which can be used to read or -mutate explicitly exposed animatable attributes on it. It consists of: - - - A proxied element - - - A map of proxied input attributes and their values - -An animator describes a fully realized custom animation linking an animator -definition with the instance specific: +An animator instance describes a fully realized custom animation instance in the worklet +context and links an animator definition with the instance specific state such as its element +proxies. It consists of: - A animator name. - - An animator scope. + - An animation requested flag. + - A root element proxy. -A animator instance has an associated animator scope which is responsible for -specific animator state such as its element proxies. It consists of: + - A list of associated children element proxies. - - A animator name. - - An animation requested flag. +An element proxy defines a handle to an element which can be used to read or +write its explicitly exposed animatable attributes . It consists of: - - A rootelement proxy. + - An animator instance. - - A list of associated children element proxies. + - A proxied element. + - A read only map of proxied input properties their values. -Issue: Todo: Remove the concept of animator scope and merge what it owns in animator. -The concept of animator scope is no longer needed because we have decided not to kill animator -instances mid frame so state can be saved there. Also we are removing the message ports so we -no longer need to keep them alive independently. + - A map of proxies output properties to their values. +An animator object provides a handle in the browsing context for +a given animator instance. This may later be used to provide Javascript APIs for animators. -Registering an Animator {#registering-animator} +Registering an Animator Definition {#registering-animator-definition} ============================================================ The {{AnimationWorkletGlobalScope}} has a animator name to animator definition map. The map gets populated when {{registerAnimator(name, animatorCtor)}} is called. @@ -197,12 +191,12 @@ When the registerAnimator(|name|, abort all these steps. 8. Let |inputProperties| be the result of parsing a property list with name - "inputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception and - abort all these steps. + "inputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception and + abort all these steps. 9. Let |outputProperties| be the result of parsing a property list with name - "outputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception and - abort all these steps. + "outputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception and + abort all these steps. 10. Let |rootInputProperties| be the result of parsing a property list with name "rootInputProperties" for |animatorCtor|. If an exception is thrown, rethrow the exception @@ -235,7 +229,7 @@ When the registerAnimator(|name|, The {{AnimationWorkletGlobalScope}} has a animator name to instance map. The map is -populated when the user agent constructs a new animator instance. +populated when the user agent constructs a new animator instance. When parsing a property list with name name for animatorCtor, the user agent must run the following steps: @@ -252,14 +246,14 @@ the user agent must run the following steps: Creating an Animator {#creating-animator} ==================================================== -The {{AnimationWorkletGlobalScope}} has a animator scope list. An animator scope -is constructed and added to the list whenever a new animator instance is constructed. +Each animator instance lives in a {{AnimationWorkletGlobalScope}} and has a dual +animator object that lives in browsing context -The animator scope contains animator specific message port so unlike animator instances -they cannot be disposed arbitrarily. Additionally, each scope is able to communicate with -its associated animator instance in the browsing context through an implicit message -channel. +The animator instance cannot be disposed arbitrarily (e.g., in the middle of running animation +as it may contain the scripted animation state. +The {{AnimationWorkletGlobalScope}} has a animator instance list. Anytime a new +animator instance is constructed in that scope, it gets added to the list.
@@ -274,15 +268,6 @@ channel.
 
-
-[
-    Exposed=(AnimationWorklet)
-] interface AnimatorScope {
-    [RaisesException] void postMessage(any message, optional sequence<Transferable> transfer);
-    attribute EventHandler onmessage;
-};
-
- When the {{Animator}} constructor is called the user agent must run the following steps: 1. Let |name| be the first argument of the constructor. @@ -298,93 +283,124 @@ steps: 4. Create a new {{MessagePort}} object. Let this be the |outside port|. - 5. Let |animator| be a new {{Animator}} Object with: + 5. Let |animatorObj| be a new {{Animator}} with: - animator name being |name| - message port being |outside port| - 6. Create a new animator scope with animator name |name|, and - {{MessagePort}} |outside port|. Let this be the |scope| + 6. Queue a task to run the following substeps: - 7. Associate |scope| with |animator|. + 1. Use dark magic to pick the right animationWorklet scope. Let this be + |workletGlobalScope|. - 8. Return |animator|. + 2. Create a new animator instance with |name|, |outside port|, and + |workletGlobalScope|. Let this be the |animatorInstance|. -To create a new animator scope given animator name as |name|, and -{{MessagePort}} as |outside port|, the user agent must run the following steps: - 1. Create a new {{AnimatorScope}} object |scope| with: + 3. Associate |animatorInstance| with |animatorObj|. - - animator name being |name| + 7. Return |animatorObj|. + + + + +To create a new animator instance given |name|, |outside port|, and |workletGlobalScope|, +the user agent must run the following steps: + + 1. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animator name to animator definition map. + + If |definition| does not exist abort the following steps. + + Issue: We should check the animator instance list to make sure we don't create duplicate + instances for the same name and element. - - animation request flag being + 2. Let |animatorCtor| be the class constructor of |definition|. - 2. Create a new {{MessagePort}} object owned by |scope|. Let |inside port| be this + 3. Let |animatorInstance| be the result of Construct(|animatorCtor|). + + Issue: handle invalid construction. + + 4. Create a new {{MessagePort}} object owned by |instance|. Let |inside port| be this new object. - 3. Entangle |outside port| and |inside port|. + 5. Entangle |outside port| and |inside port|. + + 6. Set the following on |animatorInstance| with: + - animator name being |name| + + - animation request flag being frame-current - 4. Set |scope|'s port to |inside port| + - port being |inside port| - 5. Add |scope| to animator scope list. + 7. Add |animatorInstance| to animator instance list. Creating an Element Proxy {#creating-element-proxy} ==================================================== An element proxy can be constructed in the document scope using the {{ElementProxy}} constructor. element proxy is a clonable object and thus can be serialized in a -message and posted to any animator scope via the animator port. +message and posted to any animator instance via the animator object port. The {{ElementProxy}} constructor takes two parameters, first the element which is being proxied, -and second a list of {{DOMString}} identifying all of the worklet animatable attribute +and second a list of {{DOMString}} identifying all of the animatable attribute which may be read or mutated using this proxy. -
 [
     Exposed=(Window,AnimationWorklet),
     RaisesException=Constructor,
-    Constructor(Element element, sequence proxiedAttributes)
+    Constructor(Animator animator, Element element, sequence proxiedAttributes)
 ] interface ElementProxy {
     attribute StylePropertyMapReadOnly inputStyleMap;
     attribute StylePropertyMapReadOnly outputStyleMap;
 };
 
-Issue: Need to figure out how we are handlign scroll offsets. Previous approach was to have +Issue: Todo: Need to figure out how we are handling scroll offsets. Previous approach was to have mutable offset on each proxy but the new idea is to have readonly ScrollTimeline. When the {{ElementProxy}} constructor is called the user agent must run the following steps: - 1. Let |element| and |proxiedAttributes| be the first and second arguments of the constructor. + 1. Let |animatorObj|, and |element| be the first, and second arguments of the constructor. 2. If |element| is null or not an instance of {{Element}} abort the following steps. - 4. If any of the attribute in |proxiedAttributes| is not a worklet animatable attribute - i.e., cannot be read or cannot be mutated inside an animation worklet, throw - a NotSupportedError and abort the following steps. + 3. If |animatorObj| is null or not an instance of {{Animator}} abort the following steps. + 4. Create an element proxy with |animatorObj| and |element|. - 3. Let |proxy| be a new {{ElementProxy}} Object with: +Issue: Todo: Remove this as we no longer allow direct construction of ElementProxy. - - proxied element being |element| - 4. update proxy input style map with |proxy| and |proxiedAttributes|. +When user agent wants to create an element proxy given |animatorObj| and |element|, it +must run the following steps: - 5. Return proxy. + 1. Let |animatorInstance| be the animator instance associated with |animatorObj| + 2. Let |workletGlobalScope| be the scope associated with |animatorInstance|. -Any write on the outputStyle map, updates the effective value of the used style value of the on the -proxied element. This happens asynchronously. + 1. Let |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animator name to animator definition map. + 2. Let |inputProperties| be animator input property list of |definition|. -Issue: Todo: Remove this as we no longer allow direct construction of ElementProxy. + 3. Let |proxy| be a new {{ElementProxy}} Object with: -Issue: Todo: Explain what happens when a proxied element is removed. In other houdini APIs (e.g., - paint and layout) the painter is only invocated if the element is alive. In Animation - Worklet this is not the case so proxied element may get removed while worklet has a handle - on them. + - proxied element being |element|. + + - outputStyleMap being a new {{StylePropertyMap}}. + + 4. update proxy input style map with |proxy| and |inputProperties|. + + 5. Associate |proxy| with |animatorInstance|. + + 5. Return proxy. + + +Note: Writing to the outputStyle map will update the effective value of the used style value of the +proxied element. This may happen asynchronously. When the user agent wants to update proxy input style map given |proxy|, and @@ -397,14 +413,51 @@ When the user agent wants to update proxy input style map given |prox 2. Set |proxy|'s inputStyleMap to |styleMap|. +Issue: Todo: Explain what happens when a proxied element is removed. In other houdini APIs (e.g., + paint and layout) the painter is only invoked if the element is alive. In Animation + Worklet this is not the case so proxied element may get removed while worklet has a handle + for them. + + +Requesting Animation Frames {#requesting-animation-frames} +==================== +Each animator instance has an associated animation requested flag. It must be +either frame-requested, frame-current. It is initially set to +frame-current. + +When a new element proxy is assigned to or removed from an animator instance, that +animator instance'sanimation requested flag should be set to frame-requested. + +When the computed style for an element changes, the user agent must run the following steps: + +For each element proxy for that element, perform the following steps: + + 1. Let |proxy| be the current element proxy of the element. + + 2. Let |animator| be the |proxy|'s assigned animator. + + 3. Let |name| be the |animator|'s name. + + 4. Let |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animator name to animator definition map. + + 5. Let |inputProperties| be animator input property list of |definition|. + + 6. For each property in |inputProperties|, if the property’s computed value has changed, + set the animation requested flag on the |animator| to frame-requested. + + +Running animators sets animation requested flag on animators to +frame-current. + + +Issue: Todo: Animators that have Timeline as an explicit input will need to request frame +on every animation frame. Formulate this here. Running Animators {#running-animators} ====================================================== -Each animator is associated with an animation requested flag. It must be -either frame-requested, frame-not-requested. It is initially set to -frame-requested. -When a user agent wants to produce a new animation frame, if for a animator the +When a user agent wants to produce a new animation frame, if for any animator instance the associated animation request flag is frame-requested then the the user agent must run animators for the current frame. @@ -414,12 +467,12 @@ Note: The user agent is not required to run animations on every frame. It is leg When the user agent wants to run animators, it must iterates over animator -scope list as |scope|: +instance list as |instance|: - 1. If the animation requested flag for the scope is frame-not-requested + 1. If the animation requested flag for the instance is frame-current the user agent may abort all the following steps. - 2. Let |name| be the animator name of |scope|. + 2. Let |name| be the animator name of |instance|. 3. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of worklet's WorkletGlobalScopes from the animation {{Worklet}}. @@ -433,7 +486,7 @@ scope list as |scope|: animator name to instance map. If |animatorInstance| is null run the following substeps: - Issue: Todo: Add steps to create new animation instance given the animator definition. + Issue: Todo: Add steps to create new animatorInstance given the animator definition. 6. Let |animateFunction| be |definition|'s animate function. @@ -441,16 +494,16 @@ scope list as |scope|: 10. Let |timeline| be a new {{AnimationTimline}} with its "currentTime" set to |timestamp|. - 11. Let |root| be a root element proxy of |scope|. + 11. Let |root| be a root element proxy of |instance|. - 12. Let |children| be a children element proxies of |scope|. + 12. Let |children| be a children element proxies of |instance|. - 11. Invoke |animateFunction| with arguments «|root|, |children|, |timeline|», + 13. Invoke |animateFunction| with arguments «|root|, |children|, |timeline|», and with |animatorInstance| as the callback this value. -Note: It is legal for the user agent to run an animator multiple times in the same -frame. +Note: Although inefficient, it is legal for the user agent to run animators multiple times +in the same frame. Issue: Todo: add provision that allows user agents to skip calling animate on any animators whose proxies are not within the visual viewport or whose attributes @@ -458,8 +511,8 @@ Issue: Todo: add provision that allows user agents to skip calling animate<>
If there is a animator definition registered with that name, then a new - animator instance will be created with this element as its root element proxy. - The new animator lifetime is tied to this root element's lifetime. If no animator + animator instance will be created with this element as its root element proxy. + The new animator instance lifetime is tied to this root element's lifetime. If no animator definition exists with that name, then the instance will be created as soon as one is registered. @@ -530,7 +583,7 @@ Note: All the elements in the root element's DOM sub-tree that get associated wi Issue: Todo: Write the algorithm for element assignments. It will include construction of a new -{{ElementProxy}}, looking up or creating animator instance, and assiging the animator. We probably +{{ElementProxy}}, looking up or creating animator instance, and assigning the animator. We probably need a diagram here too. @@ -546,28 +599,27 @@ point. Receiving and Sending Message {#receiving-and-sending-message} ============================================================= -Each {{Animator}} instances have an implicit {{MessagePort}} associated with them. This port -is created when the animator instance is created and should have a lifetime that is as long as the +Each animator object has an implicit {{MessagePort}} associated with it. This port +is created when the animator object is created and should have a lifetime that is as long as the animator instance's lifetime. -Similarly, each animator scope has a {{MessagePort}} which is entangled with the -associated animator port. Together, these ports create an implicit message -channel which can be used to communicate between the animator instance and its scope. +Similarly, each animator instance has a {{MessagePort}} which is entangled with the +associated animator object port. Together, these ports create an implicit message +channel which can be used to communicate between the animator object and its instance. -All messages received by the animator port should immediately be re- -targeted at the {{Animator}} instance. Similarly any invocation of {{postMessage()}} on the -animator instance must immediately invoke the method of the same name on the port, with +All messages received by the animator object's port should immediately be re- +targeted at the animator object. Similarly any invocation of {{postMessage()}} on the +animator object must immediately invoke the method of the same name on the port, with the same arguments, and return the same return value. -All messages received by the animator scope port should immediately be re- -targeted at an animation instance. This requires the worklet to first associate the scope -with an animation instance. Similarly any invocation of {{postMessage()}} on the animation -instance must immediately invoke the method of the same name on the port, with the same arguments, -and return the same return value. +All messages received by the animator instance's port should immediately be re- +targeted at an animation instance. Similarly any invocation of {{postMessage()}} on the +animator instance must immediately invoke the method of the same name on the port, with +the same arguments, and return the same return value. -Note: It is legal for a user agents to only deliver messages to an animator scope -immediately before running that animator. Similarly messages to an animator may be deferred +Note: It is legal for a user agents to only deliver messages to an animator instance +immediately before running that animator. Similarly messages to an animator object may be deferred to any appropriate time in the document lifecycle. @@ -583,8 +635,8 @@ Example 1: A fade-in animation with spring timing. {#example-1} animator:'spring-fadein'; } -<section class='myFadein'></sectionlt; -<section class='myFadein' style="--spring-k: 25;"></sectionlt; +<section class='myFadein'></section> +<section class='myFadein' style="--spring-k: 25;"></section> <scriptlt; document.animationWorklet.import('spring-timing.js'); From 1ed2219bf9f70c6b84a355ed484c33b1b489a53c Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Thu, 23 Mar 2017 10:30:04 -0400 Subject: [PATCH 037/114] Add smcgruer@ to the editors list --- Overview.bs | 1 + 1 file changed, 1 insertion(+) diff --git a/Overview.bs b/Overview.bs index 2c328b78..861f8360 100644 --- a/Overview.bs +++ b/Overview.bs @@ -8,6 +8,7 @@ Shortname: css-animation-api Level: 1 Abstract: Editor: Majid Valipour, majidvp@google.com +Editor: Stephen McGruer, smcgruer@chromium.com
From 19988379bb1d352f9b415a35916318be2ddc382e Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Thu, 23 Mar 2017 10:55:55 -0400 Subject: [PATCH 038/114] Add example of not running animators for offscreen proxies. Adds an example to the note about service level that a browser may choose not to service offscreen proxies. --- Overview.bs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Overview.bs b/Overview.bs index 2c328b78..ea78ed05 100644 --- a/Overview.bs +++ b/Overview.bs @@ -463,7 +463,9 @@ associated animation request flag is frame-requested then the the Note: The user agent is not required to run animations on every frame. It is legal to defer generating an animation frame until a later frame. This allow the user agent to - provide a different service level according to their policy. + provide a different service level according to their policy. For example, a user agent + may choose not to service an animation whose proxies will not be visible within the visual + viewport on the current frame. When the user agent wants to run animators, it must iterates over animator @@ -505,10 +507,6 @@ instance list as |instance|: Note: Although inefficient, it is legal for the user agent to run animators multiple times in the same frame. -Issue: Todo: add provision that allows user agents to skip calling animate - on any animators whose proxies are not within the visual viewport or whose attributes - are not mutated. - Closing an Animator {#closing-animator} ==================================================== From 890c498dc3c3c1441268ce68a151c723dcec47c3 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Thu, 23 Mar 2017 10:30:36 -0400 Subject: [PATCH 039/114] Add .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b517b86d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore .bs generated file +Overview.html From 3066833d29303cad4eac5bca45c3bf00f827a753 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Thu, 23 Mar 2017 10:57:55 -0400 Subject: [PATCH 040/114] Remove references to Animator object and message ports The current spec does not have a browser-side Animator object, and it is no longer possible to directly communicate from the browser to the Animation worklet via message ports. In the future we will likely add a communication method based on Element::getAnimations(), but for now get rid of the inaccurate sections. --- Overview.bs | 110 +++++----------------------------------------------- 1 file changed, 10 insertions(+), 100 deletions(-) diff --git a/Overview.bs b/Overview.bs index 2c328b78..ede755ce 100644 --- a/Overview.bs +++ b/Overview.bs @@ -160,9 +160,6 @@ write its explicitly exposed animatable attributes . It consists of: - A map of proxies output properties to their values. -An animator object provides a handle in the browsing context for -a given animator instance. This may later be used to provide Javascript APIs for animators. - Registering an Animator Definition {#registering-animator-definition} ============================================================ The {{AnimationWorkletGlobalScope}} has a animator name to animator definition map. @@ -246,64 +243,13 @@ the user agent must run the following steps: Creating an Animator {#creating-animator} ==================================================== -Each animator instance lives in a {{AnimationWorkletGlobalScope}} and has a dual -animator object that lives in browsing context - -The animator instance cannot be disposed arbitrarily (e.g., in the middle of running animation +Each animator instance lives in an {{AnimationWorkletGlobalScope}}. The +animator instance cannot be disposed arbitrarily (e.g., in the middle of running animation as it may contain the scripted animation state. -The {{AnimationWorkletGlobalScope}} has a animator instance list. Anytime a new +The {{AnimationWorkletGlobalScope}} has an animator instance list. Anytime a new animator instance is constructed in that scope, it gets added to the list. - -
-[
-    Exposed=(Window),
-    RaisesException=Constructor,
-    Constructor(DOMString name)
-] interface Animator {
-    [RaisesException]  void postMessage(any message, optional sequence<Transferable> transfer);
-    attribute EventHandler onmessage;
-};
-
- - -When the {{Animator}} constructor is called the user agent must run the following -steps: - 1. Let |name| be the first argument of the constructor. - - 2. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of - worklet's WorkletGlobalScopes from the animation {{Worklet}}. - - 3. Let |definition| be the result of looking up |name| on the |workletGlobalScope|'s - animator name to animator definition map. - - If |definition| does not exist, throw a NotSupportedError and abort - the following steps. - - 4. Create a new {{MessagePort}} object. Let this be the |outside port|. - - 5. Let |animatorObj| be a new {{Animator}} with: - - - animator name being |name| - - - message port being |outside port| - - 6. Queue a task to run the following substeps: - - 1. Use dark magic to pick the right animationWorklet scope. Let this be - |workletGlobalScope|. - - 2. Create a new animator instance with |name|, |outside port|, and - |workletGlobalScope|. Let this be the |animatorInstance|. - - 3. Associate |animatorInstance| with |animatorObj|. - - 7. Return |animatorObj|. - - - - To create a new animator instance given |name|, |outside port|, and |workletGlobalScope|, the user agent must run the following steps: @@ -321,26 +267,19 @@ the user agent must run the following steps: Issue: handle invalid construction. - 4. Create a new {{MessagePort}} object owned by |instance|. Let |inside port| be this - new object. - - 5. Entangle |outside port| and |inside port|. - - 6. Set the following on |animatorInstance| with: + 4. Set the following on |animatorInstance| with: - animator name being |name| - animation request flag being frame-current - - port being |inside port| - - 7. Add |animatorInstance| to animator instance list. + 5. Add |animatorInstance| to animator instance list. Creating an Element Proxy {#creating-element-proxy} ==================================================== An element proxy can be constructed in the document scope using the {{ElementProxy}} constructor. element proxy is a clonable object and thus can be serialized in a -message and posted to any animator instance via the animator object port. +message and delivered to any animator instance. The {{ElementProxy}} constructor takes two parameters, first the element which is being proxied, and second a list of {{DOMString}} identifying all of the animatable attribute @@ -363,21 +302,19 @@ mutable offset on each proxy but the new idea is to have readonly ScrollTimeline When the {{ElementProxy}} constructor is called the user agent must run the following steps: - 1. Let |animatorObj|, and |element| be the first, and second arguments of the constructor. + 1. Let |element| be the first argument of the constructor. 2. If |element| is null or not an instance of {{Element}} abort the following steps. - 3. If |animatorObj| is null or not an instance of {{Animator}} abort the following steps. - - 4. Create an element proxy with |animatorObj| and |element|. + 4. Create an element proxy with |element|. Issue: Todo: Remove this as we no longer allow direct construction of ElementProxy. -When user agent wants to create an element proxy given |animatorObj| and |element|, it +When user agent wants to create an element proxy given |element|, it must run the following steps: - 1. Let |animatorInstance| be the animator instance associated with |animatorObj| + 1. Let |animatorInstance| be the animator instance associated with |element| 2. Let |workletGlobalScope| be the scope associated with |animatorInstance|. @@ -596,33 +533,6 @@ animations and in a different thread. Supporting other composite operation is no point. -Receiving and Sending Message {#receiving-and-sending-message} -============================================================= - -Each animator object has an implicit {{MessagePort}} associated with it. This port -is created when the animator object is created and should have a lifetime that is as long as the -animator instance's lifetime. - -Similarly, each animator instance has a {{MessagePort}} which is entangled with the -associated animator object port. Together, these ports create an implicit message -channel which can be used to communicate between the animator object and its instance. - -All messages received by the animator object's port should immediately be re- -targeted at the animator object. Similarly any invocation of {{postMessage()}} on the -animator object must immediately invoke the method of the same name on the port, with -the same arguments, and return the same return value. - -All messages received by the animator instance's port should immediately be re- -targeted at an animation instance. Similarly any invocation of {{postMessage()}} on the -animator instance must immediately invoke the method of the same name on the port, with -the same arguments, and return the same return value. - - -Note: It is legal for a user agents to only deliver messages to an animator instance -immediately before running that animator. Similarly messages to an animator object may be deferred -to any appropriate time in the document lifecycle. - - Examples {#examples} ==================== From d9dcb5e87974dc1e30b94b9c8bf78baf18653bca Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Thu, 23 Mar 2017 11:24:14 -0400 Subject: [PATCH 041/114] Add flackr to the editors list. --- Overview.bs | 1 + 1 file changed, 1 insertion(+) diff --git a/Overview.bs b/Overview.bs index 2c328b78..f851182a 100644 --- a/Overview.bs +++ b/Overview.bs @@ -8,6 +8,7 @@ Shortname: css-animation-api Level: 1 Abstract: Editor: Majid Valipour, majidvp@google.com +Editor: Robert Flack, flackr@chromium.org From 27f8d153df9488b79435254b466523558c976edb Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Thu, 23 Mar 2017 11:50:34 -0400 Subject: [PATCH 042/114] Describe what happens when a proxied element is removed. When a proxied element is removed we may continue to have running animations referring to proxies of that element. In progress animations continue to run with no visual effect on the now removed element. --- Overview.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Overview.bs b/Overview.bs index 2c328b78..a120a89c 100644 --- a/Overview.bs +++ b/Overview.bs @@ -413,10 +413,10 @@ When the user agent wants to update proxy input style map given |prox 2. Set |proxy|'s inputStyleMap to |styleMap|. -Issue: Todo: Explain what happens when a proxied element is removed. In other houdini APIs (e.g., - paint and layout) the painter is only invoked if the element is alive. In Animation - Worklet this is not the case so proxied element may get removed while worklet has a handle - for them. +When an element is removed, all proxies of that element are considered to be disconnected. +A disconnected proxy continues to have the last value from the computed value +of the proxied element properties, but setting values on its ouputStyleMap will have no +effect. Requesting Animation Frames {#requesting-animation-frames} From 004461d00d9c58f4c1458e286fba4ce6bb233efe Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Fri, 24 Mar 2017 15:54:02 -0400 Subject: [PATCH 043/114] Fix incorrect closing tag on 'must' --- Overview.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Overview.bs b/Overview.bs index 2c328b78..f7f3d5d7 100644 --- a/Overview.bs +++ b/Overview.bs @@ -428,7 +428,7 @@ either frame-requested, frame-current. It is initially set When a new element proxy is assigned to or removed from an animator instance, that animator instance'sanimation requested flag should be set to frame-requested. -When the computed style for an element changes, the user agent must run the following steps: +When the computed style for an element changes, the user agent must run the following steps: For each element proxy for that element, perform the following steps: From 775bc523bc5f89cb6d0e04bee49c15c8555b2c74 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Mon, 27 Mar 2017 15:35:05 -0400 Subject: [PATCH 044/114] Clarify that Element Proxy objects can only be created by user agents (#22) Clarify that Element Proxy objects can only be created by user agents It is no longer possible in the current version of the spec for user script to create element proxy objects (nor are they posted to the animator instance). Instead, the user agent handles creating them and passing them into the animate() call. --- Overview.bs | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/Overview.bs b/Overview.bs index d8b3a53b..77aff24e 100644 --- a/Overview.bs +++ b/Overview.bs @@ -279,40 +279,29 @@ the user agent must run the following steps: Creating an Element Proxy {#creating-element-proxy} ==================================================== -An element proxy can be constructed in the document scope using the {{ElementProxy}} -constructor. element proxy is a clonable object and thus can be serialized in a -message and delivered to any animator instance. +Element Proxy objects are created by the user agent for elements which have either 'animator' +or 'animator-root' CSS properties. They cannot be constructed from user script. A single element may +have multiple Element Proxy objects associated with it; one per animator instance. -The {{ElementProxy}} constructor takes two parameters, first the element which is being proxied, -and second a list of {{DOMString}} identifying all of the animatable attribute -which may be read or mutated using this proxy. +The {{ElementProxy}} interface exposes two maps: a read only map of proxied input properties to their +values, and a map of proxied output properties to their values. The input and output properties in +the maps are those specified in registerAnimator for the given animator instance.
 [
-    Exposed=(Window,AnimationWorklet),
-    RaisesException=Constructor,
-    Constructor(Animator animator, Element element, sequence proxiedAttributes)
+    Exposed=(AnimationWorklet),
 ] interface ElementProxy {
     attribute StylePropertyMapReadOnly inputStyleMap;
     attribute StylePropertyMapReadOnly outputStyleMap;
 };
 
+Issue: Todo: Should we have NoInterfaceObject/Exposed here? How do we properly represent that this +cannot be constructed via javascript? + Issue: Todo: Need to figure out how we are handling scroll offsets. Previous approach was to have mutable offset on each proxy but the new idea is to have readonly ScrollTimeline. -When the {{ElementProxy}} constructor is called the user agent must run the following -steps: - - 1. Let |element| be the first argument of the constructor. - - 2. If |element| is null or not an instance of {{Element}} abort the following steps. - - 4. Create an element proxy with |element|. - -Issue: Todo: Remove this as we no longer allow direct construction of ElementProxy. - - When user agent wants to create an element proxy given |element|, it must run the following steps: From fef8e5419db62e58f6da6cde0c9e98939ab7781c Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Mon, 27 Mar 2017 19:19:47 -0400 Subject: [PATCH 045/114] Fix ordering of CSS notation descriptions (#23) Fix ordering of CSS notation descriptions --- Overview.bs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Overview.bs b/Overview.bs index 77aff24e..af02de6e 100644 --- a/Overview.bs +++ b/Overview.bs @@ -444,14 +444,14 @@ Issue: Todo: Define when we may get rid of the animator. CSS Animator Notation {#css-animator-notation} ============================================== -Two CSS properties 'animator' and 'animator-root' may be used to +Two CSS properties 'animator-root' and 'animator' may be used to assign an HTML elements to an animator instance either as a root element or a child element.
-Name: animator
+Name: animator-root
 Value:  [ none |  <> ]#
-Initial: auto
+Initial: none
 Applies to: all elements
 Inherited: no
 Computed value: as specified
@@ -476,9 +476,9 @@ Animatable: no
 
 
 
-Name: animator-root
+Name: animator
 Value:  [ none |  <> ]#
-Initial: none
+Initial: auto
 Applies to: all elements
 Inherited: no
 Computed value: as specified

From 92bad2ec3f8c8c332c08896390d07eaf5d4b2e86 Mon Sep 17 00:00:00 2001
From: Stephen McGruer 
Date: Tue, 28 Mar 2017 09:07:04 -0400
Subject: [PATCH 046/114] Fix smcgruer editor email (#27)

---
 Overview.bs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Overview.bs b/Overview.bs
index af02de6e..d5b40f43 100644
--- a/Overview.bs
+++ b/Overview.bs
@@ -9,7 +9,7 @@ Level: 1
 Abstract:
 Editor: Majid Valipour, majidvp@google.com
 Editor: Robert Flack, flackr@chromium.org
-Editor: Stephen McGruer, smcgruer@chromium.com
+Editor: Stephen McGruer, smcgruer@chromium.org
 
 
From c0689862bf398d789896afb149e39b6db7305757 Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Tue, 28 Mar 2017 13:34:51 -0400 Subject: [PATCH 047/114] Abort creating a new animator instance if one already exists for that root. (#31) We should only have one instance of a named animator per animator-root element. --- Overview.bs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Overview.bs b/Overview.bs index d5b40f43..58c62dae 100644 --- a/Overview.bs +++ b/Overview.bs @@ -249,32 +249,32 @@ Each animator instance lives in an {{AnimationWorkletGlobalScope}}. The animator instance cannot be disposed arbitrarily (e.g., in the middle of running animation as it may contain the scripted animation state. -The {{AnimationWorkletGlobalScope}} has an animator instance list. Anytime a new +The {{AnimationWorkletGlobalScope}} has an animator instance list. Anytime a new animator instance is constructed in that scope, it gets added to the list. -To create a new animator instance given |name|, |outside port|, and |workletGlobalScope|, +To create a new animator instance given a |root element|, |name|, and |workletGlobalScope|, the user agent must run the following steps: - 1. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s - animator name to animator definition map. + 1. If an |animatorInstance| with the same |name| and |root element| exists within the animator + instance list then abort the following steps. - If |definition| does not exist abort the following steps. + 2. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animator name to animator definition map. - Issue: We should check the animator instance list to make sure we don't create duplicate - instances for the same name and element. + If |definition| does not exist abort the following steps. - 2. Let |animatorCtor| be the class constructor of |definition|. + 3. Let |animatorCtor| be the class constructor of |definition|. - 3. Let |animatorInstance| be the result of Construct(|animatorCtor|). + 4. Let |animatorInstance| be the result of Construct(|animatorCtor|). Issue: handle invalid construction. - - 4. Set the following on |animatorInstance| with: + + 5. Set the following on |animatorInstance| with: - animator name being |name| - animation request flag being frame-current - 5. Add |animatorInstance| to animator instance list. + 6. Add |animatorInstance| to animator instance list. Creating an Element Proxy {#creating-element-proxy} From 15a1122692bdd05973b62f9f29ef9673f689f980 Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Tue, 28 Mar 2017 13:35:11 -0400 Subject: [PATCH 048/114] Move the issue to handle scroll offset to animator registration. (#30) The issue concerning handling of scroll input makes sense to list in the section describing how to register animators as it will require changes to the class definition. --- Overview.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Overview.bs b/Overview.bs index 58c62dae..94e1f1d8 100644 --- a/Overview.bs +++ b/Overview.bs @@ -227,6 +227,9 @@ When the registerAnimator(|name|, definition map of the associated document. +Issue: Todo: Describe how we can read scroll offsets. The previous approach was to list +it as an input / output property of proxies but the new idea is to have a readonly ScrollTimeline. + The {{AnimationWorkletGlobalScope}} has a animator name to instance map. The map is populated when the user agent constructs a new animator instance. @@ -299,9 +302,6 @@ the maps are those specified in registerAnimator for the given animato Issue: Todo: Should we have NoInterfaceObject/Exposed here? How do we properly represent that this cannot be constructed via javascript? -Issue: Todo: Need to figure out how we are handling scroll offsets. Previous approach was to have -mutable offset on each proxy but the new idea is to have readonly ScrollTimeline. - When user agent wants to create an element proxy given |element|, it must run the following steps: From 4b472c769ab308852e6e4341420a296deff31372 Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Tue, 28 Mar 2017 14:04:31 -0400 Subject: [PATCH 049/114] Allow skipping offscreen animation instances. (#29) Allow skipping running the animate function for animation instances whose proxies will be offscreen as determined by the user agent. --- Overview.bs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Overview.bs b/Overview.bs index 94e1f1d8..e0f2efc4 100644 --- a/Overview.bs +++ b/Overview.bs @@ -391,16 +391,15 @@ associated animation request flag is frame-requested then the the Note: The user agent is not required to run animations on every frame. It is legal to defer generating an animation frame until a later frame. This allow the user agent to - provide a different service level according to their policy. For example, a user agent - may choose not to service an animation whose proxies will not be visible within the visual - viewport on the current frame. + provide a different service level according to their policy. When the user agent wants to run animators, it must iterates over animator instance list as |instance|: 1. If the animation requested flag for the instance is frame-current - the user agent may abort all the following steps. + or the proxies belonging to the |instance| will not be visible within the visual viewport + of the current frame the user agent may abort all the following steps. 2. Let |name| be the animator name of |instance|. From f7e118db0cdee9dace2b7303bec10ebc3ab61521 Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Tue, 28 Mar 2017 15:22:38 -0400 Subject: [PATCH 050/114] Add issue concerning permission to skip slow animators. (#32) --- Overview.bs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Overview.bs b/Overview.bs index e0f2efc4..78550964 100644 --- a/Overview.bs +++ b/Overview.bs @@ -401,6 +401,9 @@ instance list as |instance|: or the proxies belonging to the |instance| will not be visible within the visual viewport of the current frame the user agent may abort all the following steps. + Issue: Consider giving user agents permission to skip running animator instances to throttle + slow animators. + 2. Let |name| be the animator name of |instance|. 3. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of worklet's @@ -430,7 +433,6 @@ instance list as |instance|: 13. Invoke |animateFunction| with arguments «|root|, |children|, |timeline|», and with |animatorInstance| as the callback this value. - Note: Although inefficient, it is legal for the user agent to run animators multiple times in the same frame. From 1ec18be4aeb1004accf8750718abdbdb95a0ecf7 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Tue, 28 Mar 2017 16:11:04 -0400 Subject: [PATCH 051/114] Remove all linking errors (#33) The focus is on removing linking errors so that the output of bikeshed.py is actually useful. Where possible I have tried to correct the linking errors to what they should be, but if necessary I took the side of removing erroring code when I couldn't work out how to fix it. --- Overview.bs | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/Overview.bs b/Overview.bs index 78550964..c480e5c1 100644 --- a/Overview.bs +++ b/Overview.bs @@ -36,12 +36,15 @@ urlPrefix: https://tc39.github.io/ecma262/#sec-; type: dfn; text: IsCallable text: IsConstructor text: HasProperty + url: ecmascript-data-types-and-values; text: Type url: map-objects; text:map object url: get-o-p; text: Get url: set-o-p-v-throw; text: Set url: terms-and-definitions-function; text: function urlPrefix: native-error-types-used-in-this-standard- text: TypeError +urlPrefix: https://www.w3.org/TR/hr-time-2/#dom-; type: dfn + text: DOMHighResTimeStamp
@@ -89,15 +92,19 @@ animations. The worklet can be accessed via {{animationWorklet}} attribute.
 The {{animationWorklet}}'s worklet global scope type is {{AnimationWorkletGlobalScope}}.
 
 
+interface AnimationWorklet {
+  [NewObject] Promise<void> import(USVString moduleURL);
+};
+
 partial interface Window {
-    [SameObject] readonly attribute Worklet animationWorklet;
+    [SameObject] readonly attribute AnimationWorklet animationWorklet;
 };
 
 callback VoidFunction = void ();
 
-[Global=(Worklet,AnimationWorklet),Exposed=AnimationWorklet]
+[Exposed=AnimationWorklet]
 interface AnimationWorkletGlobalScope : WorkletGlobalScope {
     void registerAnimator(DOMString name, VoidFunction animatorCtor);
 };
@@ -142,7 +149,7 @@ An animator instance describes a fully realized custom animation inst
 context and links an animator definition with the instance specific state such as its element
 proxies. It consists of:
 
- - A animator name.
+ - A animator name.
 
  - An animation requested flag.
 
@@ -151,8 +158,8 @@ proxies. It consists of:
  - A list of associated children element proxies.
 
 
-An element proxy defines a handle to an element which can be used to read or
-write its explicitly exposed animatable attributes . It consists of:
+An element proxy defines a handle to an element which can be used to read or
+write its explicitly exposed animatable attributes. It consists of:
 
  - An animator instance.
 
@@ -223,7 +230,7 @@ When the registerAnimator(|name|,
         - animator root output property list being |rootOutputProperties|
 
 
-    13. Add the key-value pair (|name| - |definition|) to the animator name to animation
+    13. Add the key-value pair (|name| - |definition|) to the animator name to animator
         definition map of the associated document.
 
 
@@ -233,7 +240,7 @@ it as an input / output property of proxies but the new idea is to have a readon
 The {{AnimationWorkletGlobalScope}} has a animator name to instance map. The map is
 populated when the user agent constructs a new animator instance.
 
-When parsing a property list with name name for animatorCtor, 
+When parsing a property list with name name for {{animatorCtor}},
 the user agent must run the following steps:
 
     1. Let |properties| be an empty sequence<DOMString>
@@ -241,7 +248,7 @@ the user agent must run the following steps:
     2. Let |propertiesIterable| be the result of Get(|animatorCtor|, |name|).
 
     3. If |propertiesIterable| is not undefined, then set |properties| to the result of
-        converting |propertiesIterable| to a sequence<DOMString>. If an
+        converting |propertiesIterable| to a sequence<DOMString>. If an
         exception is thrown, rethrow the exception and abort all these steps.
 
 
@@ -275,7 +282,7 @@ the user agent must run the following steps:
     5. Set the following on |animatorInstance| with:
         - animator name being |name|
 
-        - animation request flag being frame-current
+        - animation requested flag being frame-current
 
     6. Add |animatorInstance| to animator instance list.
 
@@ -288,7 +295,7 @@ have multiple Element Proxy objects associated with it; one per animat
 
 The {{ElementProxy}} interface exposes two maps: a read only map of proxied input properties to their
 values, and a map of proxied output properties to their values. The input and output properties in
-the maps are those specified in registerAnimator for the given animator instance.
+the maps are those specified in registerAnimator for the given animator instance.
 
 
 [
@@ -318,7 +325,7 @@ When user agent wants to create an element proxy given |element|, it
 
         - proxied element being |element|.
 
-        - outputStyleMap being a new {{StylePropertyMap}}.
+        - {{outputStyleMap}} being a new {{StylePropertyMap}}.
 
     4. update proxy input style map with |proxy| and |inputProperties|.
 
@@ -375,8 +382,7 @@ For each element proxy for that element, perform the following steps:
         set the animation requested flag on the |animator| to frame-requested.
 
 
-Running animators sets animation requested flag on animators to 
-frame-current.
+[[#running-animators]] sets animation requested flag on animators to frame-current.
 
 
 Issue: Todo: Animators that have Timeline as an explicit input will need to request frame
@@ -386,11 +392,11 @@ Running Animators {#running-animators}
 ======================================================
 
 When a user agent wants to produce a new animation frame, if for any animator instance the
-associated animation request flag is frame-requested then the the user agent
+associated animation requested flag is frame-requested then the the user agent
 must run animators for the current frame.
 
 Note: The user agent is not required to run animations on every frame. It is legal to defer
-      generating an animation frame until a later frame. This allow the user agent to
+      generating an animation frame until a later frame. This allow the user agent to
       provide a different service level according to their policy.
 
 
@@ -422,9 +428,9 @@ instance list as |instance|:
 
   6. Let |animateFunction| be |definition|'s animate function.
 
-  9. Let |timestamp| be a {{DOMHighResTimeStamp}} indicating the current frame start time.
+  9. Let |timestamp| be a DOMHighResTimeStamp indicating the current frame start time.
 
-  10. Let |timeline| be a new {{AnimationTimline}} with its "currentTime" set to |timestamp|.
+  10. Let |timeline| be a new {{AnimationTimeline}} with its "currentTime" set to |timestamp|.
 
   11. Let |root| be a root element proxy of |instance|.
 
@@ -523,6 +529,15 @@ animations and in a different thread. Supporting other composite operation is no
 point.
 
 
+Security Considerations {#security-considerations}
+==================================================
+
+Issue: Need to decide what security considerations there are for this spec.
+
+Privacy Considerations {#privacy-considerations}
+================================================
+
+Issue: Need to decide what privacy considerations there are for this spec.
 
 Examples {#examples}
 ====================

From 2afbf497eda86d324abedd460370a4f1c9cc7803 Mon Sep 17 00:00:00 2001
From: Stephen McGruer 
Date: Thu, 6 Apr 2017 11:00:19 -0400
Subject: [PATCH 052/114] Update animator CSS section (#28)

* Make the CSS description more behavioral and less instructive
* Clarify behavior of animator-root:none
---
 Overview.bs | 62 ++++++++++++++++++++++++++---------------------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/Overview.bs b/Overview.bs
index c480e5c1..42e98fe6 100644
--- a/Overview.bs
+++ b/Overview.bs
@@ -451,13 +451,12 @@ Issue: Todo: Define when we may get rid of the animator.
 CSS Animator Notation {#css-animator-notation}
 ==============================================
 
-Two CSS properties 'animator-root' and 'animator' may be used to
-assign an HTML elements to an animator instance either as a root element or a child element.
-
+Two CSS properties 'animator-root' and 'animator' may be used to assign an HTML elements to an
+animator instance either as a root element or a child element.
 
 
 Name: animator-root
-Value:  [ none |  <> ]#
+Value:  none | <>#
 Initial: none
 Applies to: all elements
 Inherited: no
@@ -470,22 +469,27 @@ Animatable: no
 
none
- There will be no animators. -
<> + There will be no animator instance that has this element as its + root element proxy. +
<>#
- If there is a animator definition registered with that name, then a new - animator instance will be created with this element as its root element proxy. - The new animator instance lifetime is tied to this root element's lifetime. If no animator - definition exists with that name, then the instance will be created as soon as one is - registered. -
+ For each <> specified in the list, the following applies for each animation frame: + * If there is no animator definition registered with the given <>, the inclusion + of that <> as a value has no effect. + * Otherwise, an animator instance with this element as its root element proxy + will exist and will have its animation function called (with respect to the rules + laid out in [[#running-animators]]). + + If the same <> occurs multiple times in the list, only the first occurrence of that + <> is processed. +
 Name: animator
-Value:  [ none |  <> ]#
-Initial: auto
+Value:  none | <>#
+Initial: none
 Applies to: all elements
 Inherited: no
 Computed value: as specified
@@ -494,30 +498,26 @@ Media: interactive
 Animatable: no
 
-
none
- There will be no animators. -
<> + This element will not be passed into any animate function as one of the + children element proxies. +
<>#
- If there is a animator definition registered with that name, then this element is - assigned to the first ancestor animator instance of the given name as a child element proxy. - If no animator definition exists with that name, then the element gets assigned as soon - as one is registered. - - Issue: Todo: If no ancestor animator instance exists with that name then we should create one - with document root element as its root. -
+ For each <> specified in the list, the following applies for each animation frame: + * If there is no animator definition registered with the given <>, the inclusion + of that <> as a value has no effect. -Note: All the elements in the root element's DOM sub-tree that get associated with the same animator - name will get assigned to the the animator instance linked with this root element. + * Otherwise, an element proxy for this element will be passed into the + animate function of the closest ancestor animator instance with the given + <> as one of the children element proxies. If no such animator instance + exists, one is created with the document root element as it's root element proxy. - -Issue: Todo: Write the algorithm for element assignments. It will include construction of a new -{{ElementProxy}}, looking up or creating animator instance, and assigning the animator. We probably -need a diagram here too. + If the same <> occurs multiple times in the list, only the first occurrence of that + <> is processed. + Effect Stack {#effect-stack} From e1a6e0ae03e1a0a0ccfb2cd488e92271d495845f Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Fri, 7 Apr 2017 11:56:52 -0400 Subject: [PATCH 053/114] Change animator instance list to a map and handle Construct failure (#34) Also add wordage to create animator instances if they don't already exist when running animators. --- Overview.bs | 85 ++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/Overview.bs b/Overview.bs index 42e98fe6..f33a6446 100644 --- a/Overview.bs +++ b/Overview.bs @@ -237,9 +237,6 @@ When the registerAnimator(|name|, Issue: Todo: Describe how we can read scroll offsets. The previous approach was to list it as an input / output property of proxies but the new idea is to have a readonly ScrollTimeline. -The {{AnimationWorkletGlobalScope}} has a animator name to instance map. The map is -populated when the user agent constructs a new animator instance. - When parsing a property list with name name for {{animatorCtor}}, the user agent must run the following steps: @@ -259,32 +256,36 @@ Each animator instance lives in an {{AnimationWorkletGlobalScope}}. The animator instance cannot be disposed arbitrarily (e.g., in the middle of running animation as it may contain the scripted animation state. -The {{AnimationWorkletGlobalScope}} has an animator instance list. Anytime a new -animator instance is constructed in that scope, it gets added to the list. +The {{AnimationWorkletGlobalScope}} has an (animator name, root element) to instance map. +The map is populated when the user agent constructs a new animator instance in that scope. -To create a new animator instance given a |root element|, |name|, and |workletGlobalScope|, +To create a new animator instance given a |name|, |root element|, and |workletGlobalScope|, the user agent must run the following steps: - 1. If an |animatorInstance| with the same |name| and |root element| exists within the animator - instance list then abort the following steps. - - 2. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s - animator name to animator definition map. + 1. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s + animator name to animator definition map. If |definition| does not exist abort the following steps. - 3. Let |animatorCtor| be the class constructor of |definition|. + 2. Let |animatorInstanceMap| be |workletGlobalScope|'s (animator name, root element) to + instance map. - 4. Let |animatorInstance| be the result of Construct(|animatorCtor|). + 3. If an entry exists for |name| and |root element| within |animatorInstanceMap| then abort the + following steps. - Issue: handle invalid construction. + 4. Let |animatorCtor| be the class constructor of |definition|. - 5. Set the following on |animatorInstance| with: - - animator name being |name| + 5. Let |animatorInstance| be the result of Construct(|animatorCtor|). + If Construct throws an exception, set the result of looking up |name| and + |root element| in |animatorInstanceMap| to null, and abort the following steps. + + 6. Set the following on |animatorInstance| with: + - animator name being |name| - animation requested flag being frame-current - 6. Add |animatorInstance| to animator instance list. + 7. Set the result of looking up |name| and |root element| in |animatorInstanceMap| to + |animatorInstance|. Creating an Element Proxy {#creating-element-proxy} @@ -400,46 +401,44 @@ Note: The user agent is not required to run animations on every frame. It is leg provide a different service level according to their policy. -When the user agent wants to run animators, it must iterates over animator -instance list as |instance|: - - 1. If the animation requested flag for the instance is frame-current - or the proxies belonging to the |instance| will not be visible within the visual viewport - of the current frame the user agent may abort all the following steps. +When the user agent wants to run animators in a given |workletGlobalScope|, it +must iterate over all pairs of animator name and root element as (|animatorName|, +|rootElement|). For each such pair: - Issue: Consider giving user agents permission to skip running animator instances to throttle - slow animators. + 1. Let the |definition| be the result of looking up |animatorName| on the |workletGlobalScope|'s + animator name to animator definition map. - 2. Let |name| be the animator name of |instance|. + If |definition| does not exist then abort the following steps. - 3. Let |workletGlobalScope| be a {{AnimationWorkletGlobalScope}} from the list of worklet's - WorkletGlobalScopes from the animation {{Worklet}}. + 2. Let |instance| be the result of looking up (|animatorName|, |rootElement|) in the + |workletGlobalScope|'s (animator name, root element) to instance map. - 4. Let the |definition| be the result of looking up |name| on the |workletGlobalScope|'s - animator name to animator definition map. + If |instance| does not exist then create a new animator instance for |animatorName|, + |rootElement|, and |workletGlobalScope|, and let |instance| be the result of that. - If |definition| does not exist abort the following steps. + 3. If |instance| still does not exist or |instance| is null then abort the following steps. - 5. Let |animatorInstance| be the result of looking up |name| on |workletGlobalScope|'s - animator name to instance map. If |animatorInstance| is null run the following - substeps: + 4. If the animation requested flag for |instance| is frame-current or the proxies + belonging to |instance| will not be visible within the visual viewport of the current frame + the user agent may abort all the following steps. - Issue: Todo: Add steps to create new animatorInstance given the animator definition. + Issue: Consider giving user agents permission to skip running animator instances to throttle + slow animators. - 6. Let |animateFunction| be |definition|'s animate function. + 5. Let |animateFunction| be |definition|'s animate function. - 9. Let |timestamp| be a DOMHighResTimeStamp indicating the current frame start time. + 6. Let |timestamp| be a DOMHighResTimeStamp indicating the current frame start time. - 10. Let |timeline| be a new {{AnimationTimeline}} with its "currentTime" set to |timestamp|. + 7. Let |timeline| be a new {{AnimationTimeline}} with its "currentTime" set to |timestamp|. - 11. Let |root| be a root element proxy of |instance|. + 8. Let |root| be a root element proxy of |instance|. - 12. Let |children| be a children element proxies of |instance|. + 9. Let |children| be a children element proxies of |instance|. - 13. Invoke |animateFunction| with arguments «|root|, |children|, |timeline|», - and with |animatorInstance| as the callback this value. + 10. Invoke |animateFunction| with arguments «|root|, |children|, |timeline|», + and with |instance| as the callback this value. -Note: Although inefficient, it is legal for the user agent to run animators multiple times +Note: Although inefficient, it is legal for the user agent to run animators multiple times in the same frame. Closing an Animator {#closing-animator} From 8cdfb3282e5f079c1f829f11e80bf89487775bf9 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Fri, 7 Apr 2017 12:00:12 -0400 Subject: [PATCH 054/114] Fix link error (#35) --- Overview.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Overview.bs b/Overview.bs index f33a6446..cdd56eca 100644 --- a/Overview.bs +++ b/Overview.bs @@ -478,7 +478,7 @@ Animatable: no of that <> as a value has no effect. * Otherwise, an animator instance with this element as its root element proxy - will exist and will have its animation function called (with respect to the rules + will exist and will have its animate function called (with respect to the rules laid out in [[#running-animators]]). If the same <> occurs multiple times in the list, only the first occurrence of that From 9f69dd2d59b91f17e78daaae43ea95ecc527559e Mon Sep 17 00:00:00 2001 From: Robert Flack Date: Fri, 7 Apr 2017 22:33:58 -0400 Subject: [PATCH 055/114] Generate index.html and fix type and links. (#36) - Issues now points to github issues. - URL points to current version hosted by github. - Uses type CG-DRAFT in WICG group. --- .gitignore | 2 - Makefile | 4 +- Overview.bs => index.bs | 7 +- index.html | 2634 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 2601 insertions(+), 46 deletions(-) delete mode 100644 .gitignore rename Overview.bs => index.bs (99%) diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b517b86d..00000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore .bs generated file -Overview.html diff --git a/Makefile b/Makefile index 8658b1f2..04d7e27d 100755 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ # # Use "make REMOTE=1" to use remote bikeshed -SOURCEFILE=Overview.bs -OUTPUTFILE=Overview.html +SOURCEFILE=index.bs +OUTPUTFILE=index.html PREPROCESSOR=bikeshed.py REMOTE_PREPROCESSOR_URL=https://api.csswg.org/bikeshed/ diff --git a/Overview.bs b/index.bs similarity index 99% rename from Overview.bs rename to index.bs index cdd56eca..e642039e 100644 --- a/Overview.bs +++ b/index.bs @@ -1,9 +1,8 @@