diff --git a/box-tree-api/Overview.bs b/box-tree-api/Overview.bs
index 4097e3bd..2b71cd5b 100644
--- a/box-tree-api/Overview.bs
+++ b/box-tree-api/Overview.bs
@@ -72,6 +72,7 @@ Boxes are not explicitly exposed by this API.
API
+[Exposed=Window]
interface DeadFragmentInformation {
readonly attribute Node node;
readonly attribute double width;
diff --git a/css-animationworklet/Makefile b/css-animation-worklet-1/Makefile
similarity index 84%
rename from css-animationworklet/Makefile
rename to css-animation-worklet-1/Makefile
index 04d7e27d..63fe58ab 100644
--- a/css-animationworklet/Makefile
+++ b/css-animation-worklet-1/Makefile
@@ -4,9 +4,9 @@
#
# Use "make REMOTE=1" to use remote bikeshed
-SOURCEFILE=index.bs
-OUTPUTFILE=index.html
-PREPROCESSOR=bikeshed.py
+SOURCEFILE=Overview.bs
+OUTPUTFILE=Overview.html
+PREPROCESSOR=bikeshed
REMOTE_PREPROCESSOR_URL=https://api.csswg.org/bikeshed/
all: $(OUTPUTFILE)
diff --git a/css-animation-worklet-1/Overview.bs b/css-animation-worklet-1/Overview.bs
new file mode 100644
index 00000000..4f883932
--- /dev/null
+++ b/css-animation-worklet-1/Overview.bs
@@ -0,0 +1,1286 @@
+
+Title: CSS Animation Worklet API
+Status: ED
+Group: houdini
+ED: https://drafts.css-houdini.org/css-animation-worklet-1/
+TR: https://www.w3.org/TR/css-animation-worklet-1/
+Shortname: css-animation-worklet
+Level: 1
+Abstract:
+Editor: Majid Valipour, majidvp@google.com, w3cid 81464
+Editor: Robert Flack, flackr@chromium.org, w3cid 98451
+Editor: Stephen McGruer, smcgruer@chromium.org, w3cid 96463
+Ignored Terms: AnimationWorklet
+
+
+Introduction {#intro}
+=====================
+This section is not normative.
+
+This document introduces a new primitive that provides extensibility in web animations and enables
+high performance interactive procedural animations on the web. For details on the rationale and
+motivation see both [[explainer]] and [[principles]].
+
+The [=Animation Worklet=] API provides a method to create scripted animations that control a set
+of [=animation effects=]. The API is designed to make it possible for user agents to run such
+animations in their own dedicated thread to provide a degree of performance isolation from main
+thread.
+
+Relationship to the Web Animations API {#relationship-to-web-animations}
+------------------------------------------------------------------------
+This section is not normative.
+
+Animations running inside an [=Animation Worklet=] execution context expose the {{Animation}}
+interface from the Web Animations specification on the main javascript execution context. This means
+they can be controlled and inspected from main thread using the same Web Animation APIs.
+
+
+Animation Worklet {#animation-worklet-desc}
+===========================================
+Animation Worklet is a {{Worklet}} responsible for all classes related to custom
+animations. The worklet can be accessed via {{animationWorklet}} attribute.
+
+
+[Exposed=Window]
+partial namespace CSS {
+ [SameObject] readonly attribute Worklet animationWorklet;
+};
+
+
+The {{animationWorklet}}'s [=worklet global scope type=] is {{AnimationWorkletGlobalScope}}.
+
+{{AnimationWorkletGlobalScope}} represents the global execution context of {{animationWorklet}}.
+
+
+[ Global=(Worklet,AnimationWorklet), Exposed=AnimationWorklet ]
+interface AnimationWorkletGlobalScope : WorkletGlobalScope {
+ undefined registerAnimator(DOMString name, AnimatorInstanceConstructor animatorCtor);
+};
+
+callback AnimatorInstanceConstructor = any (any options, optional any state);
+
+
+
+Animator {#animator-desc}
+=========================
+
+An Animator represents a custom animation that is running inside
+{{AnimationWorkletGlobalScope}}. Each Animator is associated with an [=animation=] instance (of
+type {{WorkletAnimation}}) in the document and determines how that animation progresses its
+[=animation effect=]. The animate function contains the logic responsible for
+translating the animation current time into appropriate progress of the animation effect. An
+animator can only be instantiated by construction of a {{WorkletAnimation}} in the document.
+
+
+Two animators types are supported: [=Stateless Animator=] and [=Stateful Animator=] each
+providing a different state management strategy.
+
+
+Stateless Animator {#stateless-animator-desc}
+---------------------------------------------
+
+A Stateless Animator is a type of animator does not depend on any local state either
+stored on the instance or global scope. Effectively, the animate function of an
+[=Stateless Animator=] can be treated as a pure function with the expectation that given the same
+input, it produces the same output.
+
+
+
+ This is how an stateless animator class should look.
+
+ class FooAnimator {
+ constructor(options) {
+ // Called when a new animator is instantiated.
+ }
+ animate(currentTime, effect) {
+ // Animation frame logic goes here.
+ }
+ }
+
+
+
+Note: The statelessness allows animation worklet to perform optimization such as producing multiple
+animation frames in parallel, sharing a single animator instance for multiple animations, and
+performing very cheap teardown and setup. Using [=Stateless Animator=] is highly recommended to
+enable such optimizations.
+
+Stateful Animator {#stateful-animator-desc}
+-------------------------------------------
+
+A Stateful Animator is a type of animator that can have local state and animation worklet
+guarantees that it maintains this state as long as the stateful animator fulfills the contract
+required by its interface and as described following.
+
+
+[=Animation worklet=] maintains a set of {{WorkletGlobalScope}}s which may exist across different
+threads or processes. Animation worklet may temporarily terminate a global scope (e.g., to preserve
+resources) or move a running [=animator instance=] across different global scopes (e.g., if its
+effect is mutable only in a certain thread). Animation worklet guarantees that a stateful animator
+instance's state is maintained even if the instance is respawned in a different global scope.
+
+The basic mechanism for maintaining the state is that the animation worklet snapshots the local
+state that is exposed via the [=state function=] and then reifies it so that it can be passed into
+the constructor when the animator instance is respawned at a later time in a potentially different
+global scope. The [=migrate an animator instance=] algorithm specifies this process in details.
+
+A user-defined stateful animator is expected to fulfill the required contract which is that its
+state function returns an object representing its state that can be serialized using structured
+serialized algorithm and that it can also recreate its state given that same object passed to its
+constructor.
+
+
+ This is how a stateful animator class should look.
+
+ class BarAnimator {
+ constructor(options, state) {
+ // Called when a new animator is instantiated (either first time or after being respawned).
+ this.currentVelocity = state ? state.velocity : 0;
+ }
+ animate(currentTime, effect) {
+ // Animation frame logic goes here and can rely on this.currentVelocity.
+ this.currentVelocity += 0.1;
+ }
+ state() {
+ // The returned object should be serializable using structured clonable algorithm.
+ return {
+ velocity: this.currentVelocity;
+ }
+ }
+ }
+
+
+
+
+Animator Definition {#animator-definition-desc}
+-----------------------------------------------
+
+An animator definition is a [=struct=] which describes the author defined custom
+animation logic. It consists of:
+
+ - : animator name
+ :: A <>#.
+
+ - : class constructor
+ :: A {{AnimatorInstanceConstructor}} [=callback function=] type.
+
+ - : animate function
+ :: A [=Function=] [=callback function=] type.
+
+ - : state function
+ :: A [=Function=] [=callback function=] type.
+
+ - : stateful flag
+ :: A boolean flag
+
+
+A stateful animator definition is an [=animator definition=] whose
+[=animator definition/stateful flag=] is true.
+
+
+A document animator definition is a [=struct=] which describes the information needed by
+the [=document=] about the author defined custom animation. It consists of:
+
+ - : stateful flag
+ :: A boolean flag
+
+Registering an Animator Definition {#registering-animator-definition}
+---------------------------------------------------------------------
+The [=document=] has a [=map=] of document animator definitions. The map gets populated
+when {{registerAnimator(name, animatorCtor)}} is called.
+
+An {{AnimationWorkletGlobalScope}} has a [=map=] of animator definitions. The map gets
+populated when {{registerAnimator(name, animatorCtor)}} is called.
+
+Note that to register a [=stateful animator definition=] it is simply enough for the registered
+class to have a state function.
+
+
+
+When the registerAnimator(|name|, |animatorCtor|)
+method is called in a {{AnimationWorkletGlobalScope}}, the user agent must run the
+following steps:
+
+ 1. If |name| is not a valid <>, [=throw=] a [=TypeError=] and abort all these
+ steps.
+
+ 2. Let |animatorDefinitions| be the {{AnimationWorkletGlobalScope}}'s
+ [=animator definitions=] [=map=].
+
+ 3. If |animatorDefinitions|[|name|] [=map/exists=], [=throw=] a [=NotSupportedError=]
+ and abort all these steps.
+
+ 4. If the result of [=IsConstructor=](|animatorCtor|) is false, [=throw=] a
+ [=TypeError=] and abort all these steps.
+
+ 5. Let |prototype| be the result of [=Get=](|animatorCtor|, "prototype").
+
+ 6. Let |animateFuncValue| be the result of [=Get=](|prototype|, "animate").
+
+ 7. Let |animateFunc| be the result of [=converting=] |animateFuncValue| to the [=Function=]
+ [=callback function=] type. If an exception is thrown, rethrow the exception and abort
+ all these steps.
+
+ 8. Let |stateFuncValue| be the result of [=Get=](|prototype|, "state").
+
+ 9. Let |stateFunc| be the result of [=converting=] |stateFuncValue| to the [=Function=]
+ [=callback function=] type, If an exception is thrown, set |stateful| to be false,
+ otherwise set |stateful| to be true and |stateFunc| to be undefined.
+
+ 10. Let |definition| be a new [=animator definition=] with:
+
+ - [=animator name=] being |name|
+
+ - [=class constructor=] being |animatorCtor|
+
+ - [=animate function=] being |animateFunc|
+
+ - [=state function=] being |stateFunc|
+
+ - [=animator definition/stateful flag=] being |stateful|
+
+
+ 9. [=map/set=] the |animatorDefinitions|[|name|] to |definition|.
+
+ 10. [=Queue a task=] to run the following steps:
+
+ 1. Let |documentAnimatorDefinitions| be the associated [=document's=]
+ [=document animator definitions=] [=map=].
+
+ 2. Let |documentDefinition| be a new [=document animator definition=] with:
+
+ - [=animator definition/stateful flag=] being |stateful|
+
+ 3. If |documentAnimatorDefinitions|[|name|] [=map/exists=], run the following steps:
+
+ 1. Let |existingDocumentDefinition| be the result of [=map/get=]
+ |documentAnimatorDefinitions|[|name|].
+
+ 2. If |existingDocumentDefinition| is "invalid", abort all these steps.
+
+ 3. If |existingDocumentDefinition| and |documentDefinition| are not equivalent, (that is
+ their [=document animator definition/stateful flag=]s are
+ different), then:
+
+ [=map/set=] |documentAnimatorDefinitions|[|name|] to "invalid".
+
+ Log an error to the debugging console stating that the same class was registered
+ with different stateful flag.
+
+ 4. Otherwise, [=map/set=] |documentAnimatorDefinitions|[|name|] to
+ |documentDefinition|.
+
+
+
+
+Animator Effect {#animator-effect-desc}
+---------------------------------------
+
+A Animator Effect represents the underlying [=animation effect=] inside animation
+worklet.
+
+It has a corresponding effect property which is a reference to the underlying
+[=animation effect=]. It also has corresponding properties for the following
+[=animation effect=]'s properties:
+ * [=local time=],
+ * [=start delay=],
+ * [=end delay=],
+ * [=fill mode=],
+ * [=iteration start=],
+ * [=iteration count=],
+ * [=iteration duration=],
+ * [=playback direction=], and
+ * [=timing function=].
+
+[=Animator Effect=] is represented by the {{WorkletAnimationEffect}} interface
+inside {{AnimationWorkletGlobalScope}}.
+
+
+
+[ Exposed=AnimationWorklet ]
+interface WorkletAnimationEffect {
+ EffectTiming getTiming();
+ ComputedEffectTiming getComputedTiming();
+ attribute double? localTime;
+};
+
+
+
+Note: {{WorkletAnimationEffect}} is basically a restricted version of {{AnimationEffect}} interface
+ which does not have {{AnimationEffect/updateTiming}} but additionally allows local time to be set.
+
+
+
+: getTiming()
+:: Returns the specified timing properties using the corresponding properties.
+
+: getComputedTiming()
+:: Returns the calculated timing properties using the corresponding properties.
+
+: localTime
+:: Getting the attribute returns the corresponding [=local time=].
+ Setting the attribute updates the local time given this effect as |effect|
+ and the attribute value as |time|:
+
+ 1. If the |time| is the same as |effect|'s [=local time=] then skip following steps.
+
+ 2. Set the |effect|'s [=local time=] to |time|.
+
+ 3. Set the |effect|'s animator instance's [=sync requested flag=] to true.
+
+
+
+
+Animator Instance {#animator-instance-section}
+==============================================
+
+An animator instance is a [=struct=] which describes a fully realized custom
+[=animator=] in an {{AnimationWorkletGlobalScope}}. It has a reference to an
+[=animator definition=] and owns the instance specific state such as animation effect and
+timeline. It consists of:
+
+ - : [=animator name=]
+ :: A string used to identify the animator definition.
+
+ - : [=frame requested flag=]
+ :: A boolean flag that indicates if the animator needs to animate.
+
+ - : sync requested flag
+ :: A flag that indicates if the animator needs to sync its output.
+
+ - : effect
+ :: An [=Animator Effect=].
+
+ - : animator current time
+ :: A time value equivalent to the corresponding [=worklet animation=]'s current time.
+
+ - : animator timeline
+ :: The [=timeline=] of the corresponding [=worklet animation=].
+
+ - : animator serialized options
+ :: The serializable object representing the options to be used when constructing the animator
+ instance.
+
+A stateful animator instance is an [=animator instance=] whose corresponding
+definition is a [=stateful animator definition=].
+
+
+
+Creating an Animator Instance {#creating-animator-instance}
+-----------------------------------------------------------
+
+Each [=animator instance=] lives in an {{AnimationWorkletGlobalScope}}.
+
+Each {{AnimationWorkletGlobalScope}} has an animator instance set. The set is populated
+when the user agent constructs a new [=animator instance=] in the {{AnimationWorkletGlobalScope}}
+scope. Each [=animator instance=] corresponds to a worklet animation in the document scope.
+
+
+
+To create a new animator instance given a |name|, |timeline|, |effect|,
+|serializedOptions|, |serializedState|, 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 definitions=].
+
+ If |definition| does not exist abort the following steps.
+
+ 2. Let |animatorCtor| be the [=class constructor=] of |definition|.
+
+ 3. Let |options| be [=StructuredDeserialize=](|serializedOptions|).
+
+ 4. Let |state| be [=StructuredDeserialize=](|serializedState|).
+
+ 5. Let |animatorInstance| be the result of [=constructing=] |animatorCtor| with
+ «|options|, |state|» as arguments. If an exception is thrown, rethrow the exception and
+ abort all these steps.
+
+ 6. Let |animatorEffect| be the result of [=constructing=] a {{WorkletAnimationEffect}}
+ with its [=corresponding effect=] being |effect|.
+
+ 7. Set the following on |animatorInstance| with:
+ - [=animator name=] being |name|
+ - [=frame requested flag=] being false
+ - [=sync requested flag=] being false
+ - [=animator current time=] being unresolved
+ - [=effect=] being |animatorEffect|
+ - [=animator timeline=] being |timeline|
+ - [=animator serialized options=] being |options|
+
+ 8. Add |animatorInstance| to |workletGlobalScope|'s [=animator instance set=].
+
+
+
+
+Running Animators {#running-animators}
+--------------------------------------
+
+When the user agent wants to produce a new animation frame, if for any [=animator instance=] the
+associated [=frame requested flag=] is true then the the user agent must
+[=run animators=] for the current frame in all its associated global scopes.
+
+Note: The user agent is not required to run animations on every visual 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.
+
+
+
+When the user agent wants to run animators in a given |workletGlobalScope|, it
+must run the following steps:
+
+ 1. Iterate over all [=animator instance=]s in the |workletGlobalScope|'s animator instance
+ set. For each such |animator| the user agent must perform the following steps:
+
+ 1. Let |animatorName| be |animator|'s [=animator name=]
+
+ 2. Let the |definition| be the result of looking up |animatorName| on the
+ |workletGlobalScope|'s [=animator definitions=].
+
+ If |definition| does not exist then abort the following steps.
+
+ 3. If the [=frame requested flag=] for |animator| is false or the effect belonging
+ to the |animator| 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 individual animator
+ instances to throttle slow animators.
+
+ 4. Let |animateFunction| be |definition|'s [=animate function=].
+
+ 5. Let |currentTime| be [=animator current time=] of |animator|.
+
+ 6. Let |effect| be [=effect=] of |animator|.
+
+ 7. [=Invoke=] |animateFunction| with arguments «|currentTime|, |effect|»,
+ and with |animator| as the [=callback this value=].
+
+ 2. If any [=animator instance=]s in the |workletGlobalScope|'s [=animator instance set=]
+ has its [=sync requested flag=] set to true then [=sync local times to document=]
+ given |workletGlobalScope|.
+
+
+
+Note: Although inefficient, it is legal for the user agent to [=run animators=] multiple times
+in the same frame.
+
+
+Issue: should be explicit as to what happens if the animateFunction throws an exception. At least
+we should have wording that the localTime values of the effects are ignored to avoid incorrect
+partial updates.
+
+Removing an Animator Instance {#removing-animator}
+--------------------------------------------------
+
+
+
+To remove an animator instance given |animator| and |workletGlobalScope| the user agent
+must run the following steps:
+
+1. Remove |animator| from |workletGlobalScope|'s [=animator instance set=].
+
+
+
+
+Migrating an Animator Instance {#migrating-animator}
+----------------------------------------------------
+
+The migration process allows [=stateful animator instance=] to be migrated to a different
+{{AnimationWorkletGlobalScope}} without losing their local state.
+
+
+
+To migrate an animator instance from one {{AnimationWorkletGlobalScope}} to another,
+given |animator|, |sourceWorkletGlobalScope|, |destinationWorkletGlobalScope|, the user agent
+must run the following steps :
+
+ 1. Let |serializedState| be undefined.
+
+ 2. [=Queue a task=] on |sourceWorkletGlobalScope| to run the following steps:
+
+ 1. Let |animatorName| be |animator|'s [=animator name=]
+
+ 2. Let |definition| be the result of looking up |animatorName| on |sourceWorkletGlobalScope|'s
+ [=animator definitions=].
+
+ If |definition| does not exist then abort the following steps.
+
+ 3. Let |stateful| be the [=animator definition/stateful flag=] of |definition|.
+
+ 4. If |stateful| is false then abort the following steps.
+
+ 5. Let |stateFunction| be |definition|'s [=state function=].
+
+ 6. Let |state| be the result of [=Invoke=] |stateFunction| with |animator| as the
+ [=callback this value=]. If any exception is thrown, rethrow the exception and abort
+ the following steps.
+
+ 7. Set |serializedState| to be the result of [=StructuredSerialize=](|state|).
+ If any exception is thrown, then abort the following steps.
+
+ 8. Run the procedure to [=remove an animator instance=] given |animator|, and
+ |sourceWorkletGlobalScope|.
+
+ 2. Wait for the above task to complete. If the task is aborted, abort the following steps.
+
+ 3. [=Queue a task=] on |destinationWorkletGlobalScope| to run the following steps:
+
+ 1. Run the procedure to [=create a new animator instance=] given:
+ - The |animator|'s [=animator name=] as name.
+ - The |animator|'s [=animator timeline=] as timeline.
+ - The |animator|'s [=effect=] as effect.
+ - The |animator|'s [=animator serialized options=] as options.
+ - The |serializedState| as state.
+ - The |destinationWorkletGlobalScope| as workletGlobalScope.
+
+
+
+If an animator state getter throws the user agent will remove the animator but does not recreate it.
+This effectively removes the animator instance.
+
+
+Requesting Animation Frames {#requesting-animation-frames}
+----------------------------------------------------------
+
+Each [=animator instance=] has an associated frame requested flag. It is initially set
+to false. Different circumstances can cause the [=frame requested flag=] to be set to
+true. These include the following:
+ - Changes in the [=current time=] of the animator's [=timeline=]
+ - Changes in the [=current time=] of the animator's corresponding [=worklet animation=]
+
+Performing [=run animators=] resets the [=frame requested flag=] on animators to false.
+
+
+Web Animations Integration {#web-animation-integration}
+=======================================================
+
+
+Worklet Animation {#worklet-animation-desc}
+-------------------------------------------
+Worklet animation is a kind of [=animation=] that delegates animating its animation
+effect to an [=animator instance=]. It controls the lifetime and playback state of its
+[=corresponding animator instance=].
+
+Being an [=animation=], [=worklet animation=] has an [=animation effect=] and a
+[=timeline=]. However unlike other animations the worklet animation's [=current time=] does
+not directly determine the animation effect's [=local time=] (via its [=inherited time=]).
+Instead the associated [=animator instance=] controls the animation effect's [=local time=]
+directly. Note that this means that the [=timeline's=] current time does not fully determine the
+animation's output.
+
+[=Worklet animation=] has the following properties in addition to the {{Animation}} interface:
+ - : animation animator name
+ :: A string that identifies its [=animator definition=].
+ - : serialized options
+ :: A serializable options object that is used whe constructing a new animator instance.
+ - : corresponding animator instance
+ :: A [=Animator Instance=].
+
+
+The existence of [=corresponding animator instance=] for a [=worklet animation=] depends on
+the animation [=play state=]. See [[#web-animation-overrides]] for details on when and this
+correspondence changes.
+
+
+[Exposed=Window]
+interface WorkletAnimation : Animation {
+ constructor(DOMString animatorName,
+ optional (AnimationEffect or sequence)? effects = null,
+ optional AnimationTimeline? timeline,
+ optional any options);
+ readonly attribute DOMString animatorName;
+};
+
+
+
+
+
+
+ Overview of the worklet animation timing model.
+
+ The animation current time is input to the animator instance, which produces a local time value
+ for the animation effect. If the animator instance is running in a parallel global scope the
+ implementation may also choose to use the local time value to produce the animation output and
+ update the visuals in parallel.
+
+
+
+
+
+Creating a Worklet Animation {#creating-worklet-animation}
+----------------------------------------------------------
+
+
+WorkletAnimation(|animatorName|, |effects|, |timeline|, |options|)
+
+Creates a new {{WorkletAnimation}} object using the following procedure:
+
+ 1. Let |documentAnimatorDefinitions| be the associated [=document's=] document animator
+ definitions [=map=].
+
+ 2. If |documentAnimatorDefinitions|[|animatorName|] does not [=map/exists=], [=throw=] an
+ [=TypeError=] and abort the following steps.
+
+ 3. If |documentAnimatorDefinitions|[|animatorName|] is "invalid", [=throw=] an
+ [=TypeError=] and abort the following steps.
+
+ 4. Let |workletAnimation| be a new {{WorkletAnimation}} object.
+
+ 5. Run the procedure to [=set the timeline of an animation=] on |workletAnimation| passing
+ |timeline| as the new timeline or, if a |timeline| argument is not provided,
+ passing the [=default document timeline=] of the {{Document}} associated with the
+ {{Window}} that is the [=current global object=].
+
+ 6. Let |effect| be the result corresponding to the first matching condition from below.
+ : If |effects| is a {{AnimationEffect}} object,
+ :: Let effect be |effects|.
+ : If |effects| is a [=list=] of {{AnimationEffect}} objects,
+ :: Let |effect| be a new {{WorkletGroupEffect}} with its children set to |effects|.
+ : Otherwise,
+ :: Let |effect| be undefined.
+
+ 7. Let |serializedOptions| be the result of [=StructuredSerialize=](|options|).
+ Rethrow any exceptions.
+
+ 8. Set the [=serialized options=] of |workletAnimation| to |serializedOptions|.
+
+ 9. Set the [=animation animator name=] of |workletAnimation| to |animatorName|.
+
+ 10. Run the procedure to [=set the target effect of an animation=] on |workletAnimation|
+ passing |effect| as the new effect. Note that this may trigger action to
+ [=set animator instance of worklet animation=]. See [[#web-animation-overrides]] for more
+ details.
+
+
+
+
+Worklet Animation Timing and Sync Model {#timing-and-sync-model}
+----------------------------------------------------------------
+
+This section describes how [=worklet animation's=] timing model differs from other
+[=animations=].
+
+As described in [[#worklet-animation-desc]], the [=worklet animation's=] [=current time=] does
+not determine its [=animation effect's=] [=local time=]. Instead the associated
+[=animator instance=] controls the animation effect's [=local time=] directly. This means that the
+animation effect's local time is controlled from a {{WorkletGlobalScope}} which may be in a parallel
+execution context.
+
+Here are a few implications of the above semantics:
+
+ - Setting the [=current time=] or [=start time=] of a [=worklet animation=] does not
+ necessarily change its output, but may change the animation [=play state=].
+ - Similarly, invoking {{Animation/finish()}} or updating a [=worklet animation's=] playback
+ rate does not necessarily change its output, but may change the animation [=play state=]
+ - Querying the animation effect's local time using {{AnimationEffect/getComputedTiming()}}
+ may return stale information, in the case where the [=animator instance=] is running in a
+ parallel execution context.
+
+
+If a Worklet Animation animation is executing in a parallel worklet execution context, the last
+known state of its Animator Effects should be periodically synced back to the main javascript
+execution context. The synchronization of [=effect values=] from the parallel worklet execution
+context to the main javascript execution context must occur before
+[=running the animation frame callbacks=] as part of the document lifecycle.
+
+Note that due to the asynchronous nature of this animation model a script running in the main
+javascript execution context may see a stale value when reading a [=target property=] that is
+being animated by a Worklet Animation, compared to the value currently being used to produce the
+visual frame that is visible to the user. This is similar to the effect of asynchronous scrolling
+when reading scroll offsets in the main javascript execution context.
+
+
+
+
+To sync local times to document for a given |workletGlobalScope| the user agent
+must perform the action that corresponds to the first matching condition from the
+following:
+
+
+ : If the |workletGlobalScope| is not running in a parallel execution context
+ :: perform the following steps immediately:
+
+ : If the |workletGlobalScope| is running in a parallel execution context
+ :: [=queue a task=] to run the following steps before running the animation frame
+ callbacks as part of the document lifecycle:
+
+ 1. Iterate over all [=animator instance=]s in the animation worklet's global scope
+ [=animator instance set=]. For each such |animator| perform the following steps:
+
+ 1. If |animator|'s [=sync requested flag=] is false skip the rest of the steps.
+
+ 2. Let |animatorEffect| be |animator|'s [=effect=].
+
+ 3. Let |effect| be |animatorEffect|'s [=corresponding effect=].
+
+ 4. Set |effect|'s local time to |animatorEffect|'s local time.
+
+ 5. Set |animator|'s [=sync requested flag=] to false.
+
+
+
+
+
+To sync animation timings to worklet for a given |workletAnimation| the user agent
+must perform the following steps:
+
+ 1. If |workletAnimation| does not have a [=corresponding animator instance=], abort the
+ following steps.
+
+ 2. Let |animator| be |workletAnimation|'s [=corresponding animator instance=].
+
+ 2. Let |workletGlobalScope| be the {{AnimationWorkletGlobalScope}} associated with
+ |workletAnimation|.
+
+ 3. : If the |workletGlobalScope| is not running in a parallel execution context
+ :: perform the following steps immediately.
+
+ : If the |workletGlobalScope| is running in a parallel execution context
+ :: [=queue a task=] to run the following steps:
+
+ 1. Set |animator|'s [=animator current time=] to |workletAnimation|'s [=current time=]
+
+ 2. Let |animatorEffect| be |animator|'s [=effect=].
+
+ 3. Let |effect| be |animatorEffect|'s [=corresponding effect=].
+
+ 4. Set the following properties on |animatorEffect| to be the same as |effect|:
+ * [=start delay=],
+ * [=end delay=],
+ * [=fill mode=],
+ * [=iteration start=],
+ * [=iteration count=],
+ * [=iteration duration=],
+ * [=playback direction=], and
+ * [=timing function=].
+
+
+
+
+
+Note: Notice that the local time is not synced from the document to animation worklet.
+
+
+Issue(811): Come with appropriate mechanism's for [=animator instance=] to get notified when its
+ animation currentTime is changing e.g., via reverse(), finish() or playbackRate change. So that
+ it can react appropriately.
+
+
+Web Animations Overrides {#web-animation-overrides}
+---------------------------------------------------
+
+In addition to the existing conditions on when the [=animation=] is considered [=ready=], a
+[=worklet animation=] is only considered [=ready=] when the following condition is also true:
+
+ - the user agent has completed any setup required to create the [=worklet animation's=]
+ [=corresponding animator instance=].
+
+When a given worklet animation's [=play state=] changes from [=idle=] to [=finished=],
+[=running=], or [=paused=], run the procedure to
+[=associate animator instance of worklet animation=] given the worket animation as
+|workletAnimation|.
+
+When a given worklet animation's [=play state=] changes from [=finished=], [=running=] or
+[=paused=] to [=idle=], run the procedure to
+[=disassociate animator instance of worklet animation=]given the worklet animation as
+|workletAnimation|.
+
+When a given worklet animation's [=replace state=] changes from [=active=] to either
+[=persisted=] or [=removed=] run the procedure to
+[=disassociate animator instance of worklet animation]= given the worklet animation as
+|workletAnimation|.
+
+
+Issue: In web-animation play state is updated before the actual change in particular some operations
+such as play() are asynchronous. We should really invoke these Animator related operation after the
+appropriate animation operation is complete instead of when play state has changed. This will
+require either finding (or introducing) q new hook in web animation or having override for each such
+async operation.
+
+
+When the procedure to [=set the target effect of an animation=] for a given worklet animation
+is called, then [=set animator instance of worklet animation=] given the worklet animation as
+|workletAnimation|.
+
+When the procedure to [=set the timeline of an animation=] for a given |workletAnimation|
+is called, then [=set animator instance of worklet animation=] given the worklet animation as
+|workletAnimation|.
+
+When the procedure to [=set the current time=] or [=set the start time=] for a given worklet
+animation is called, then [=sync animation timings to worklet=] given the worklet animation as
+|workletAnimation|.
+
+When the procedure to [=update the timing properties of an animation effect=] for a given effect is
+called and that effect is owned be a worklet animation, then
+[=sync animation timings to worklet=] given that worklet animation as |workletAnimation|.
+
+
+
+
+To associate animator instance of worklet animation given |workletAnimation|,
+the user agent must run the following steps:
+
+ 1. If |workletAnimation| has a [=corresponding animator instance=], abort the following steps.
+ 2. Let |workletGlobalScope| be the {{AnimationWorkletGlobalScope}} associated with
+ |workletAnimation|.
+ 3. [=Queue a task=] on |workletGlobalScope| to run the procedure to create a new animator
+ instance, passing:
+ * The |workletAnimation|'s [=animation animator name=] as name.
+ * The |workletAnimation|'s [=timeline=] as timeline.
+ * The |workletAnimation|'s [=animation effect=] as effect.
+ * The |workletAnimation|'s [=serialized options=] as options.
+ * The |workletGlobalScope| as workletGlobalScope.
+ 4. If the procedure was successful, set the resulting [=animator instance=] to be the
+ [=corresponding animator instance=] of |workletAnimation|.
+
+
+
+
+
+To disassociate animator instance of worklet animation given
+|workletAnimation|, the user age must run the following steps:
+
+ 1. If |workletAnimation| does not have a [=corresponding animator instance=], abort the
+ following steps.
+ 2. Let |workletGlobalScope| be the {{AnimationWorkletGlobalScope}} associated with
+ |workletAnimation|.
+ 3. Let |animatorInstance| be |workletAnimation|'s [=corresponding animator instance=].
+ 4. [=Queue a task=] on the |workletGlobalScope| to run the procedure to remove an animator
+ instance, passing |animatorInstance| as instance and |workletGlobalScope| as
+ workletGlobalScope.
+ 5. Set |workletAnimation|'s [=corresponding animator instance=] as undefined.
+
+
+
+
+
+To set animator instance of worklet animation given
+|workletAnimation|, the user agent must run the following steps:
+
+ 1. [=disassociate animator instance of worklet animation=] given |workletAnimation|.
+ 2. [=associate animator instance of worklet animation=] given |workletAnimation|.
+
+
+
+Effect Stack and Composite Order {#effect-stack-composite-order}
+----------------------------------------------------------------
+
+As with other animations, [=worklet animations=] participate in the [=effect stack=]. A worklet
+animation does not have a specific [=animation class=] which means it has the same composite order
+as other Javascript created web animations.
+
+
+
+
+
+Additional Related Concepts {#related-concepts}
+===============================================
+
+
+Worklet Group Effect {#worklet-group-effect}
+--------------------------------------------
+This section is not normative.
+
+
+[=Group effect=] is a type of [=animation effect=] that enbales multiple child animation
+effects to be animated together as a group.
+
+{{WorkletGroupEffect}} is a type of [=group effect=] that allows its [=child effect's=]
+[=local times=] to be mutated individually.
+
+When a {{WorkletGroupEffect}} is set as the [=animation effect=] of a [=worklet animation=],
+its [=corresponding animator instance=] can directly control the [=child effects=]' local
+times. This allows a single worklet animation to coordinate multiple effects - see
+[[#example-2]] for an example of such a use-case.
+
+
+[Exposed=AnimationWorklet]
+interface WorkletGroupEffect {
+ sequence getChildren();
+};
+
+
+
+Issue(w3c/csswg-drafts#2071): The above interface exposes a conservative subset of GroupEffect
+proposed as part of web-animation-2. We should instead move this into a delta spec against the
+web-animation.
+
+
+Note: Group Effect is currently an experimental feature and not well specified in web animations. So
+the concept of {{WorkletGroupEffect}} may change dramatically as [=Group Effect=] get specified.
+See https://github.com/yi-gu/group_effect/blob/master/README.md for more details.
+
+
+ScrollTimeline {#scroll-timeline}
+---------------------------------
+This section is not normative.
+
+
+{{ScrollTimeline}} is a new concept being proposed for addition to web animation API. It defines
+an animation timeline whose time value depends on the scroll position of a scroll container.
+[=Worklet animations=] can have a scroll timeline and thus drive their scripted effects based
+on a scroll offset.
+
+Note: Access to input: We are interested on exposing additional user input beside
+scrolling (e.g., touch/pointer input) to these animations so that authors can create jank-free
+input driven animations which are not really possible today. We are still trying to figure out the
+right abstractions and mechanisms to do this.
+
+
+
+Security Considerations {#security-considerations}
+==================================================
+
+There are no known security issues introduced by these features.
+
+Privacy Considerations {#privacy-considerations}
+================================================
+
+There are no known privacy issues introduced by these features.
+
+Examples {#examples}
+====================
+
+
+Example 1: Spring timing. {#example-1}
+---------------------------------------
+Here we use Animation Worklet to create animation with a custom spring timing.
+
+
+
+
+
+
+
+
+
+
+
+
+registerAnimator('spring', class SpringAnimator {
+ constructor(options = {k: 1, ratio: 0.5}) {
+ this.timing = createSpring(options.k, options.ratio);
+ }
+
+ animate(currentTime, effect) {
+ let delta = this.timing(currentTime);
+ // scale this by target duration
+ delta = delta * (effect.getTimings().duration / 2);
+ effect.localTime = delta;
+ // TODO: Provide a method for animate to mark animation as finished once
+ // spring simulation is complete, e.g., this.finish()
+ // See issue https://github.com/w3c/css-houdini-drafts/issues/808
+ }
+});
+
+function createSpring(springConstant, ratio) {
+ // Normalize mass and distance to 1 and assume a reasonable init velocit
+ // but these can also become options to this animator.
+ const velocity = 0.2;
+ const mass = 1;
+ const distance = 1;
+
+ // Keep ratio < 1 to ensure it is under-damped.
+ ratio = Math.min(ratio, 1 - 1e-5);
+
+ const damping = ratio * 2.0 * Math.sqrt(springConstant);
+ const w = Math.sqrt(4.0 * springConstant - damping * damping) / (2.0 * mass);
+ const r = -(damping / 2.0);
+ const c1 = distance;
+ const c2 = (velocity - r * distance) / w;
+
+ // return a value in [0..distance]
+ return function springTiming(timeMs) {
+ const time = timeMs / 1000; // in seconds
+ const result = Math.pow(Math.E, r * time) *
+ (c1 * Math.cos(w * time) + c2 * Math.sin(w * time));
+ return distance - result;
+ }
+}
+
+
+
+Example 2: Twitter header. {#example-2}
+---------------------------------------
+An example of twitter profile header effect where two elements (avatar, and header) are updated in
+sync with scroll offset with an additional feature where avatar can have additional physic based
+movement based on the velocity and acceleration of the scrolling.
+
+
+
+
+
+
+
+
+// In document scope.
+
+
+
+
+
+// Inside AnimationWorkletGlobalScope.
+registerAnimator('twitter-header', class HeaderAnimator {
+ constructor(options, state = {velocity: 0, acceleration: 0}) {
+ // `state` is either undefined (first time) or it is the previous state (after an animator
+ // is migrated between global scopes).
+ this.velocity = state.velocity;
+ this.acceleration = state.acceleration;
+ }
+
+
+ animate(currentTime, effect) {
+ const scroll = currentTime; // scroll is in [0, 1000] range
+
+ if (this.prevScroll) {
+ this.velocity = scroll - this.prevScroll;
+ this.acceleration = this.velocity - this.prevVelocity;
+ }
+ this.prevScroll = scroll;
+ this.prevVelocity = velocity;
+
+
+ // Drive the output group effect by setting its children local times individually.
+ effect.children[0].localTime = scroll;
+
+ effect.children[1].localTime = curve(velocity, acceleration, scroll);
+ }
+
+ state() {
+ // Invoked before any migration attempts. The returned object must be structure clonable
+ // and will be passed to constructor to help animator restore its state after migration to the
+ // new scope.
+ return {
+ this.velocity,
+ this.acceleration
+ }
+ }
+
+});
+
+curve(scroll, velocity, acceleration) {
+
+ return /* compute an return a physical movement curve based on scroll position, and per frame
+ velocity and acceleration. */ ;
+}
+
+
+
+Example 3: Parallax backgrounds. {#example-3}
+---------------------------------------------
+A simple parallax background example.
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Inside AnimationWorkletGlobalScope.
+registerAnimator('parallax', class ParallaxAnimator {
+ constructor(options) {
+ this.rate_ = options.rate;
+ }
+
+ animate(currentTime, effect) {
+ effect.localTime = currentTime * this.rate_;
+ }
+});
+
diff --git a/css-animation-worklet-1/README.md b/css-animation-worklet-1/README.md
new file mode 100644
index 00000000..f88e06b9
--- /dev/null
+++ b/css-animation-worklet-1/README.md
@@ -0,0 +1,665 @@
+# Animation Worklet Explainer
+---
+
+# Overview
+
+Animation Worklet is a new primitive that provides extensibility in web animations and enables high
+performance procedural animations on the web. The feature is developed as part of the
+[CSS Houdini task force](https://github.com/w3c/css-houdini-drafts/wiki).
+
+The Animation Worklet API provides a method to create scripted animations that control a set of
+animation effects. These animations are executed inside an isolated execution environment, *worklet*
+which makes it possible for user agents to run such animations in their own dedicated thread to
+provide a degree of performance isolation from main thread. The API is compatible with Web
+Animations and uses existing constructs as much as possible.
+
+# Background
+
+Scripted interactive effects (written in response to `requestAnimationFrame`, `pointer events` 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 key user input (pointer events, gestures, scroll). This is why scripted effects are
+still very popular for implementing common effects such as hidey-bars, parallax, pull-to-refresh,
+drag-and-drop, swipe to dismiss and etc. Animation Worklet provides is key building block for
+enabling creation of smooth rich interactive visual effects on the web while also exposing an
+extensibility hook in web animations.
+
+
+See the [Animation Worklet design principles and goals](principles.md) for a more extended overview
+of the motivations behind Animation Worklet and how the design will be evolved to support a growing
+set of use cases. Also see [the status document](status.md) for high level implementation status and
+timeline. [Here][roc-thread] you may find an earlier high level discussion on general approaches to
+address this problem.
+
+
+# Motivating Use Cases
+
+* Scroll driven effects:
+ * Hidey-bar ([demo](https://googlechromelabs.github.io/houdini-samples/animation-worklet/twitter-header/)): animation depends on both scroll and time input.
+ * Parallax ([demo](https://googlechromelabs.github.io/houdini-samples/animation-worklet/parallax-scrolling/)): simplest scroll-driven effect.
+ * Custom paginated slider ([demo](http://aw-playground.glitch.me/amp-scroller.html)).
+ * Pull-to-refresh: animation depends on both touch and time inputs.
+ * Custom scrollbars.
+ * High-fidelity location tracking and positioning
+ * [More examples](https://github.com/w3c/css-houdini-drafts/blob/master/scroll-customization-api/UseCases.md) of scroll-driven effects.
+* Gesture driven effects:
+ * [Image manipulator](https://github.com/w3c/csswg-drafts/issues/2493#issuecomment-422153926) that scales, rotates etc.
+ * Swipe to Action.
+ * Drag-N-Drop.
+ * Tiled panning e.g., Google maps.
+* Stateful script driven effects:
+ * Spring-Sticky effect ([demo](http://googlechromelabs.github.io/houdini-samples/animation-worklet/spring-sticky/)).
+ * Touch-driven physical environments.
+ * Expando ([demo](http://googlechromelabs.github.io/houdini-samples/animation-worklet/expando/)): Procedural animations with multiple elements.
+* Animated scroll offsets:
+ * Having multiple scrollers scroll in sync e.g. diff viewer keeping old/new in sync when you
+ scroll either ([demo](https://googlechromelabs.github.io/houdini-samples/animation-worklet/sync-scroller/))
+ * Custom smooth scroll animations (e.g., physic based fling curves)
+* Animation Extensibility:
+ * Custom animation timings (particularly those that are not calculable a priori e.g., [spring demo](https://googlechromelabs.github.io/houdini-samples/animation-worklet/spring-timing/))
+ * Custom animation sequencing which involves complex coordination across multiple effects.
+
+
+Not all of these usecases are immediately enabled by the current proposed API. However Animation
+Worklet provides a powerfull primitive (off main-thread scripted animation) which when combined with
+other upcoming features (e.g.,
+[Event in Worklets](https://github.com/w3c/css-houdini-drafts/issues/834),
+[ScrollTimeline](https://wicg.github.io/scroll-animations/),
+[GroupEffect](https://github.com/w3c/csswg-drafts/issues/2071)) can address all these usecases and
+allows many of currently main-thread rAF-based animations to move off thread with significant
+improvement to their smoothness.
+See [Animation Worklet design principles and goals](principles.md) for a more extended discussion
+of this.
+
+
+***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.
+
+
+# Animation Worklet
+
+Animation Worklet attempts to address the above usecases by introducing a new primitive that enables
+extensibility in the web's core animation model [WebAnimations][WA]): custom frame-by-frame animate
+function!
+
+
+## How It Works
+
+Normally, an active animation takes its timeline time and according to its running state (e.g.,
+playing, finished) and playback rate, computes its own **current time** which it then uses to set
+its keyframe effect **local time**. Here is a simple example of a simple animation:
+
+```js
+const effect = new KeyframeEffect(targetEl,
+ {transform: ['translateX(0)', 'translateX(50vw)']},
+ {duration: 1000}
+);
+const animation = new Animation(effect, document.timeline);
+animation.play();
+```
+
+
+Animation Worklet allows this transformation from **current time** to **local time** to be
+customized via a special Javascript function `animate`. Similar to other Houdini worklets, these
+animate functions are called inside a restricted [worklet][worklet] context (`AnimationWorkletGlobalScope`)
+which means the don't have access to main document. Another implication is that implementor can run
+these off-thread to ensure smooth animations even when main thread is busy which is a key
+performance goal for animations.
+
+To leverage this machinery, web developer creates a special Animation subclass, `WorkletAnimation`.
+The only difference is that the WorkletAnimation constructor takes a `name` argument that identifies
+the custom animate function to be used. Animation Worklet then creates a corresponding *animater*
+instance that represent this particlar animation and then on each animation frame calls its
+`animate` function to determine the local time which ultimately drives the keyframe effect.
+
+
+
+
+Here the same simple example but using Animation Worklet instead.
+
+**index.html**
+```js
+// Load your custom animator in the worklet
+await CSS.animationWorklet.addModule('animator.js');
+
+const effect = new KeyframeEffect(targetEl,
+ {transform: ['translateX(0)', 'translateX(50vw)']},
+ {duration: 1000}
+);
+const animation = new WorkletAnimation('my-awesome-animator', effect);
+animation.play();
+```
+
+**animator.js**
+```
+registerAnimator('my-awesome-animator', class Passthrough extends StatelessAnimator {
+ animate(currentTime, effect) {
+ // The simplest custom animator that does exactly what regular animations do!
+ effect.localTime = currentTime;
+ }
+});
+```
+
+
+A few notable things:
+
+ - WorkletAnimation behaves the same as regular animations e.g., it can be played/paused/canceled
+ - WorkletAnimation can optionally accept an options bag to help the corresponding Animator
+ configure itself during construction.
+ - Animator controls the output of the animation by setting the AnimationEffect.localTime
+ - There is two types of Animators: Stateless and Statefull explicitly marked using superclasses.
+
+Below are a few more complex example each trying to show a different aspect of Animation Worklet.
+
+# Examples
+
+## Spring Timing
+
+Here we use Animation Worklet to create animation with a custom spring timing.
+
+
+```html
+
+
+
+
+```
+
+spring-animator.js:
+
+```js
+registerAnimator('spring', class SpringAnimator extends StatelessAnimator {
+ constructor(options = {k: 1, ratio: 0.5}) {
+ this.timing = createSpring(options.k, options.ratio);
+ }
+
+ animate(currentTime, effect) {
+ let delta = this.timing(currentTime);
+ // scale this by target duration
+ delta = delta * (effect.getTimings().duration / 2);
+ effect.localTime = delta;
+ // TODO: Provide a method for animate to mark animation as finished once
+ // spring simulation is complete, e.g., this.finish()
+ // See issue https://github.com/w3c/css-houdini-drafts/issues/808
+ }
+});
+
+function createSpring(springConstant, ratio) {
+ // Normalize mass and distance to 1 and assume a reasonable init velocit
+ // but these can also become options to this animator.
+ const velocity = 0.2;
+ const mass = 1;
+ const distance = 1;
+
+ // Keep ratio < 1 to ensure it is under-damped.
+ ratio = Math.min(ratio, 1 - 1e-5);
+
+ const damping = ratio * 2.0 * Math.sqrt(springConstant);
+ const w = Math.sqrt(4.0 * springConstant - damping * damping) / (2.0 * mass);
+ const r = -(damping / 2.0);
+ const c1 = distance;
+ const c2 = (velocity - r * distance) / w;
+
+ // return a value in [0..distance]
+ return function springTiming(timeMs) {
+ const time = timeMs / 1000; // in seconds
+ const result = Math.pow(Math.E, r * time) *
+ (c1 * Math.cos(w * time) + c2 * Math.sin(w * time));
+ return distance - result;
+ }
+}
+```
+
+Note that ideally once sping simulation is finished, the worklet animation would also dispatch
+the `finish` event. Adding the necessary mechanism to enable this is tracked
+[here](https://github.com/w3c/css-houdini-drafts/issues/808).
+
+## Twitter Header
+
+Note: This assumes experimental [ScrollTimeline][scroll-timeline] feature.
+
+An example of twitter profile header effect where two elements (avatar, and header) are updated in
+sync with scroll offset.
+
+```html
+
+
+
+
+
+
+
+```
+
+twitter-header-animator.js:
+```js
+registerAnimator('twitter-header', class TwitterHeader extends StatelessAnimator {
+ constructor(options) {
+ this.timing_ = new CubicBezier('ease-out');
+ }
+
+ clamp(value, min, max) {
+ return Math.min(Math.max(value, min), max);
+ }
+
+ animate(currentTime, effect) {
+ const scroll = currentTime; // [0, 1]
+
+ // Drive the output group effect by setting its children local times.
+ effect.children[0].localTime = scroll;
+ // Can control the child effects individually
+ effect.children[1].localTime = this.timing_(this.clamp(scroll, 0, 1));
+ }
+});
+```
+
+## Swipe-to-Action
+
+Another usecase for Animation Worklet is to enable interactive input-driven animation effects that
+are driven both by input events and time.
+
+To enable this we need a way to receive pointer events in worklet (e.g. via [CSS custom
+variables](https://github.com/w3c/css-houdini-drafts/issues/869) or [other
+mechanisms][input-for-worker]) and
+also allow [playback controls](https://github.com/w3c/css-houdini-drafts/issues/808) inside
+worklets. Both of these are natural planned additions to Animation Worklet.
+
+
+Consider a simple swipe-to-action effect which follows the user swipe gesture and when finger lifts
+then continues to completion (either dismissed or returned to origin) with a curve that matches the
+swipe gesture's velocity. (See this [example](https://twitter.com/kzzzf/status/917444054887124992))
+
+With Animation Worklet, this can be modeled as a stateful animator which consumes both time and
+pointer events and have the following state machines:
+
+
+
+
+Here are the three main states:
+
+1. Animation is idle, where it is `paused` so that it is not actively ticking
+2. As soon as the user touches down, the animation moves the target to follow the user touchpoint
+ while staying `paused` (optionally calculate the movement velocity, and overall delta).
+3. As soon as the user lift their finger the animation will the switch to 'playing' so that it is
+ ticked by time until it reaches its finished state. The final state may be decided on overall
+ delta and velocity and the animation curve adapts to the movement velocity.
+
+Note that while in (3), if the user touches down we go back to (2) which ensures responsiveness to
+user touch input.
+
+To make this more concrete, here is how this may be implemented (assuming strawman proposed APIs for
+playback controls and also receiving pointer events). Note that all the state machine transitions
+and various state data (velocity, phase) and internal to the animator. Main thread only needs to
+provide appropriate keyframes that can used to translate the element on the viewport as appropriate
+(e.g., `Keyframes(target, {transform: ['translateX(-100vw)', 'translateX(100vw)']})`).
+
+
+```javascript
+registerAnimator('swipe-to-dismiss', class SwipeAnimator extends StatefulAnimator {
+ constructor(options, state = {velocity: 0, phase: 'idle'}) {
+ this.velocity = state.velocity;
+ this.phase = state.phase;
+
+ if (phase == 'idle') {
+ // Pause until we receive pointer events.
+ this.pause();
+ }
+
+ // Assumes we have an API to receive pointer events for our target.
+ this.addEventListener("eventtargetadded", (event) => {
+ for (type of ["pointerdown", "pointermove", "pointerup"]) {
+ event.target.addEventListener(type,onPointerEvent );
+ }
+ });
+ }
+
+ onpointerevent(event) {
+ if (event.type == "pointerdown" || event.type == "pointermove") {
+ this.phase = "follow_pointer";
+ } else {
+ this.phase = "animate_to_completion";
+ // Also decide what is the completion phase (e.g., hide or show)
+ }
+
+ this.pointer_position = event.screenX;
+
+ // Allow the animation to play for *one* frame to react to the pointer event.
+ this.play();
+ }
+
+ animate(currentTime, effect) {
+ if (this.phase == "follow_pointer") {
+ effect.localTime = position_curve(this.pointer_position);
+ update_velocity(currentTime, this.pointer_position);
+ // Pause, no need to produce frames until next pointer event.
+ this.pause();
+ } else if (this.phase = "animate_to_completion") {
+ effect.localTime = time_curve(currentTime, velocity);
+
+ if (effect.localTime == 0 || effect.localTime == effect.duration) {
+ // The animation is complete. Pause and become idle until next user interaction.
+ this.phase = "idle";
+ this.pause();
+ } else {
+ // Continue producing frames based on time until we complete or the user interacts again.
+ this.play();
+ }
+ }
+
+ }
+
+ position_curve(x) {
+ // map finger position to local time so we follow user's touch.
+ }
+
+ time_curve(time, velocity) {
+ // Map current time delta and given movement velocity to appropriate local time so that over
+ // time we animate to a final position.
+ }
+
+ update_velocity(time, x) {
+ this.velocity = (x - last_x) / (time - last_time);
+ this.last_time = time;
+ this.last_x = x;
+ }
+
+ state() {
+ return {
+ phase: this.phase,
+ velocity: this.velocity
+ }
+ }
+});
+```
+
+```javascript
+
+await CSS.animationWorklet.addModule('swipe-to-dismiss-animator.js');
+const target = document.getElementById('target');
+const s2d = new WorkletAnimation(
+ 'swipe-to-dismiss',
+ new KeyframeEffect(target, {transform: ['translateX(-100vw)', 'translateX(100vw)']}));
+s2d.play();
+```
+
+
+# Why Extend Animation?
+
+In [WebAnimation][WA], [Animation][animation] is the main controller. It handles the playback commands
+(play/pause/cancel) and is responsible for processing the progressing time (sourced from Timeline) and
+driving keyframes effect which defines how a particular target css property is animated and
+ultimately pixels moving on the screen.
+
+By allowing extensibility in Animation we can have the most flexibility in terms of what is possible
+for example animation can directly control the following:
+ - Control animation playback e.g., implement open-ended animations with non-deterministic timings
+ (e.g., physical-based) or provide "trigger" facilities
+ - Flexibility in transforming other forms of input into "time" e.g., consume touch events and drive
+ animations
+ - Ability to handle multiple timelines e.g., animations that seamlessly transition btween being
+ touch/scroll driven to time-driven
+ - Control how time is translated e.g., new custom easing functions
+ - Drive multiple effects and control how they relate to each other e.g., new effect sequencing
+
+
+While there is benefit in extensibility in other parts of animation stack (custom timeline, custom
+effect, custom timing), custom animations provides the largest value in terms of flexibility and
+addressing key usecases so it is the one we are tackling first.
+
+Animation Worklet can be easily augmented in future to support other Houdini style extensibility
+features as well.
+
+
+TODO: Also discuss other models that we have considered (e.g., CompositorWorker) that bypassed
+web animation altogether.
+
+
+
+# Key Concepts
+
+## Animation Worklet Global Scope
+A [worklet global scope](https://drafts.css-houdini.org/worklets/#the-global-scope) that is created
+by Animation Worklet. Note that Animation Worklet creates multiple such scopes and uses them to
+execute user defined effects. In particular global scopes are regularly switched to enforce
+stateless and stateful animator contracts.
+
+
+## Animator
+
+Animator is a Javascript class that encapsulates the custom animation logic. Similar to other
+Houdinig worklets, animators are registered inside the worklet global scope with a unique name which
+can be used to uniquely identify them.
+
+
+## WorkletAnimation
+`WorkletAnimation` is a subclass of Animation that can be used to create an custom animation that
+runs inside a standalone animation worklet scope. A worklet animation has a corresponding animator
+instance in a animation worklet scope which is responsible to drive its keyframe effects. Here are
+the key differences compared to a regular web animation:
+ - Name: The name identifies the custom animator class registered in the animation worklet scope.
+ - Options: `WorkletAnimation` may have a custom properties bag that is cloned and provided to the
+ corresponding animator constructor when it is being instantiated.
+
+Note that worklet animations expose same API surface as other web animations and thus they may be
+created, played, paused, inspected, and generally controlled from the main document scope. Here is
+how various methods roughly translate:
+
+ - `cancel()`: cancels the animation and the corresponding animator instance is removed.
+ - `play()`: starts the animation and the corresponding animator instance gets constructed and
+ may get its `animate` function called periodically as a result of changes in its timelines.
+ - pause(): pauses the animation and the corresponding animator instance no longer receives
+ `animate` calls.
+ - finish(), reverse() or mutating playbackRate: these affect the currentTime which is seens by
+ the animator instance. (We are considering possiblity of having a `onPlaybackRateChanged`
+ callback)
+
+## Statefull and Statelss Animators
+
+Sometimes animation effects require maintaining internal state (e.g., when animation needs to depend
+on velocity). Such animators have to explicitly declare their statefulness but by inheritting from
+`StatefulAnimator` superclass.
+
+The animators are not guaranteed to run in the same global scope (or underlying thread) for their
+lifetime duration. For example user agents are free to initially run the animator on main thread
+but later decide to migrate it off main thread to get certain performance optimizations or to tear
+down scopes to save resources.
+
+Animation Worklet helps stateful animators to maintain their state across such migration events.
+This is done through a state() function which is called and animator exposes its state. Here is
+an example:
+
+```js
+// in document scope
+new WorkletAnimation('animation-with-local-state', keyframes);
+```
+
+```js
+registerAnimator('animation-with-local-state', class FoorAnimator extends StatefulAnimator {
+ constructor(options, state = {velocity: 0, acceleration: 0}) {
+ // state is either undefined (first time) or the state after an animator is migrated across
+ // global scope.
+ this.velocity = state.velocity;
+ this.acceleration = state.acceleration;
+ }
+
+ animate(time, effect) {
+ if (this.lastTime) {
+ this.velocity = time - this.prevTime;
+ this.acceleration = this.velocity - this.prevVelocity;
+ }
+ this.prevTime = time;
+ this.prevVelocity = velocity;
+
+ effect.localTime = curve(velocity, acceleration, currentTime);
+ }
+
+ state() {
+ // Invoked before any migration attempts. The returned object must be structure clonable
+ // and will be passed to constructor to help animator restore its state after migration to the
+ // new scope.
+ return {
+ this.velocity,
+ this.acceleration
+ }
+ }
+
+ curve(velocity, accerlation, t) {
+ return /* compute some physical movement curve */;
+ }
+});
+```
+
+
+## Threading Model
+
+Animation Worklet is designed to be thread-agnostic. Rendering engines may create one or more
+parallel worklet execution contexts separate from the main javascript execution context, e.g., on
+their own dedicated threads. Rendering engines may then choose to assign Animation Worklet
+animations to run in such contexts. Doing so allows Animation Worklet animations to avoid being
+impacted by main thread jank.
+
+Rendering engines may wish to make a best-effort attempt to execute animate callbacks synchronously
+with visual frame production to ensure smooth animation. However it is legal for rendering engines
+to produce visual frames without blocking to receive animation updates from a worklet (i.e., letting
+the effects slip behind). For example, this could occur when the animate function callback is
+unable to complete before the frame deadline.
+
+We believe that scripted animations which are run in a parallel execution environment and which
+limit themselves to animating properties which do not require the user agent to consult main thread
+will have a much better chance of meeting the strict frame budgets required for smooth playback.
+
+
+Note that due to the asynchronous nature of this animation model a script running in the main
+javascript execution context may see a stale value when reading a target property that is
+being animated in a Worklet Animation, compared to the value currently being used to produce the
+visual frame that is visible to the user. This is similar to the effect of asynchronous scrolling
+when reading scroll offsets in the main javascript execution context.
+
+
+
+
+
+ Overview of the animation worklet threading model.
+
+ A simplified visualization of how animators running in a parallel execution environment can sync
+ their update to main thread while remaining in sync with visual frame production.
+
+
+
+
+# Related Concepts
+
+The following concepts are not part of Animation Worklet specification but Animation Worklet is
+designed to take advantage of them to enable a richer set of usecases. These are still in early
+stages of the standardization process so their API may change over time.
+
+## ScrollTimeline
+[ScrollTimeline][scroll-timeline] is a concept introduced in
+scroll-linked animation proposal. It defines an animation timeline whose time value depends on
+scroll position of a scroll container. `ScrollTimeline` can be used an an input timeline for
+worklet animations and it is the intended mechanisms to give read access to scroll position.
+
+We can later add additional properties to this timeline (e.g., scroll phase (active, inertial,
+overscroll), velocity, direction) that can further be used by Animation Worklet.
+
+## GroupEffect
+
+[GroupEffect][group-effect] is a concept introduced in Web Animation Level 2 specification. It
+provides a way to group multiple effects in a tree structure. `GroupEffect` can be used as the
+output for Worklet Animations making it possible for it to drive complext effects spanning multiple
+elements. Also with some minor [proposed changes](group-effect-changes) to Group Effect timing
+model, Animation Worklet can enable creation of new custom sequencing models (e.g., with conditions
+and state).
+
+## Event Dispatching to Worker and Worklets
+[Event Dispatching to Worker/Worklets][input-for-worker] is a proposal in WICG which allows workers
+and worklets to passively receive DOM events and in particular Pointer Events. This can be
+benefitial to Animation Worklet as it provides an ergonomic and low latency way for Animation
+Worklet to receive pointer events thus enabling it to implement input driven animations more
+effectively.
+
+
+# WEBIDL
+
+`WorkletAnimation` extends `Animation` and adds a getter for its timelines.
+Its constructor takes:
+ - `animatiorId` which should match the id of an animator which is registered in
+the animation worklet scope.
+ - A sequence of effects which are passed into a `GroupEffect` constructor.
+ - A sequence of timelines, the first one of which is considered primary timeline and passed to
+ `Animation` constructor.
+
+
+```webidl
+
+[Constructor (DOMString animatorName,
+ optional (AnimationEffectReadOnly or array)? effects = null,
+ AnimationTimeline? timeline,
+ optional WorkletAnimationOptions)]
+interface WorkletAnimation : Animation {
+ readonly attribute DOMString animatorName;
+}
+```
+
+`AnimationEffectReadOnly` gets a writable `localTime` attribute which may be used to drive the
+effect from the worklet global scope.
+
+```webidl
+partial interface AnimationEffectReadOnly {
+ [Exposed=Worklet]
+ // Intended for use inside Animation Worklet scope to drive the effect.
+ attribute double localTime;
+};
+
+```
+
+# Specification
+The [draft specification](https://drafts.css-houdini.org/css-animationworklet) is
+the most recent version.
+
+
+[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
+[WA]: https://drafts.csswg.org/web-animations/
+[animation]: https://drafts.csswg.org/web-animations/#animations
+[worklet]: https://drafts.css-houdini.org/worklets/#worklet-section
+[input-for-worker]: https://discourse.wicg.io/t/proposal-exposing-input-events-to-worker-threads/3479
+[group-effect]: https://w3c.github.io/web-animations/level-2/#the-animationgroup-interfaces
+[group-effect-changes]: https://github.com/yi-gu/group_effects
+[scroll-timeline]: https://wicg.github.io/scroll-animations/#scrolltimeline
\ No newline at end of file
diff --git a/css-animationworklet/WIP.md b/css-animation-worklet-1/WIP.md
similarity index 100%
rename from css-animationworklet/WIP.md
rename to css-animation-worklet-1/WIP.md
diff --git a/css-animation-worklet-1/img/AnimationWorklet-threading-model.svg b/css-animation-worklet-1/img/AnimationWorklet-threading-model.svg
new file mode 100644
index 00000000..d463680b
--- /dev/null
+++ b/css-animation-worklet-1/img/AnimationWorklet-threading-model.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/css-animationworklet/img/WorkletAnimation-timing-model.svg b/css-animation-worklet-1/img/WorkletAnimation-timing-model.svg
similarity index 100%
rename from css-animationworklet/img/WorkletAnimation-timing-model.svg
rename to css-animation-worklet-1/img/WorkletAnimation-timing-model.svg
diff --git a/css-animation-worklet-1/img/swipe-to-dismiss-state.png b/css-animation-worklet-1/img/swipe-to-dismiss-state.png
new file mode 100644
index 00000000..1f01b8e7
Binary files /dev/null and b/css-animation-worklet-1/img/swipe-to-dismiss-state.png differ
diff --git a/css-animationworklet/principles.md b/css-animation-worklet-1/principles.md
similarity index 100%
rename from css-animationworklet/principles.md
rename to css-animation-worklet-1/principles.md
diff --git a/css-animationworklet/status.md b/css-animation-worklet-1/status.md
similarity index 100%
rename from css-animationworklet/status.md
rename to css-animation-worklet-1/status.md
diff --git a/css-animationworklet/Overview.bs b/css-animationworklet/Overview.bs
deleted file mode 100644
index e09c17c3..00000000
--- a/css-animationworklet/Overview.bs
+++ /dev/null
@@ -1,1041 +0,0 @@
-
-Title: CSS Animation Worklet API
-Status: ED
-Group: houdini
-ED: https://drafts.css-houdini.org/css-animationworklet-1/
-Shortname: css-workletanimation
-Level: 1
-Abstract:
-Editor: Majid Valipour, majidvp@google.com
-Editor: Robert Flack, flackr@chromium.org
-Editor: Stephen McGruer, smcgruer@chromium.org
-Ignored Terms: AnimationWorklet
-
-
-Introduction {#intro}
-=====================
-This section is not normative.
-
-This document introduces a new primitive for creating scroll-linked and other high performance
-procedural animations on the web. For details on the rationale and motivation see [[explainer]].
-
-The Animation Worklet API provides a method to create scripted animations that control a set
-of animation effects. The API is designed to make it possible for user agents to run such
-animations in their own dedicated thread to provide a degree of performance isolation from main
-thread.
-
-Relationship to the Web Animations API {#relationship-to-web-animations}
-------------------------------------------------------------------------
-
-Animations running inside an Animation Worklet execution context expose the {{Animation}}
-interface from the Web Animations specification on the main javascript execution context. This means
-they can be controlled and inspected from main thread using many of the Web Animation APIs. However
-Animation Worklet animations follow a different timing model that enables them to be script-driven,
-stateful, and runnable in a parallel worklet execution context. As such Web Animation APIs that seek
-or alter the input time (reverse, finish, etc.) have different semantics for Animation Worklet
-animations.
-
-
-Threading Model {#threading-model}
-==================================
-This section is not normative.
-
-Animation Worklet is designed to be thread-agnostic. Rendering engines may create one or more
-parallel worklet execution contexts separate from the main javascript execution context, e.g., on
-their own dedicated threads. Rendering engines may then choose to assign Animation Worklet
-animations to run in such contexts. Doing so allows Animation Worklet animations to avoid being
-impacted by main thread jank.
-
-Rendering engines may wish to make a best-effort attempt to execute animate callbacks synchronously
-with visual frame production to ensure smooth animation. However it is legal for rendering engines
-to produce visual frames without blocking to receive animation updates from a worklet (i.e., letting
-the effects slip behind). For example, this could occur when the animate function callback is
-unable to complete before the frame deadline.
-
-We believe that scripted animations which are run in a parallel execution environment and which
-limit themselves to animating properties which do not require the user agent to consult main thread
-will have a much better chance of meeting the strict frame budgets required for smooth playback.
-
-If a Worklet Animation animation is executing in a parallel worklet execution context, the last
-known state of its animation effects should be periodically synced back to the main javascript
-execution context. The synchronization of effect values from the parallel worklet execution
-context to the main javascript execution context must occur before running the animation
-frame callbacks as part of the document lifecycle. Note that due to the asynchronous nature of
-this animation model a script running in the main javascript execution context may see a stale value
-when reading a target property that is being animated in a Worklet Animation, compared to the
-value currently being used to produce the visual frame that is visible to the user. This is similar
-to the effect of asynchronous scrolling when reading scroll offsets in the main javascript execution
-context.
-
-
-
-
-
- Overview of the animation worklet threading model.
-
- A simplified visualization of how animators running in a parallel execution environment can sync
- their update to main thread while remaining in sync with visual frame production.
-
-
-
-Animation Worklet {#animation-worklet-desc}
-==============================
-Animation Worklet is a {{Worklet}} responsible for all classes related to custom
-animations. The worklet can be accessed via {{animationWorklet}} attribute.
-
-The {{animationWorklet}}'s worklet global scope type is {{AnimationWorkletGlobalScope}}.
-
-{{AnimationWorkletGlobalScope}} represents the global execution context of {{animationWorklet}}.
-
-
-[Exposed=Window]
-partial namespace CSS {
- [SameObject] readonly attribute Worklet animationWorklet;
-};
-
-
-
-
-Animator {#animator-desc}
-========
-
-An Animator represents an animation instance that is running on the animation thread.
-Animators are identified by a unique name and determine how the animation progresses its keyframe
-effects given current input time. Animator instances live in {{AnimationWorkletGlobalScope}}
-and each one is associated with a {{WorkletAnimation}} instance. An animator can only be
-instantiated by construction of a {{WorkletAnimation}}.
-
-
-Two animators types are supported: {{StatelessAnimator}} and {{StatefulAnimator}} each
-providing a different state management strategy.
-
-
-StatelessAnimator Interface {#stateless-animator-desc}
----------------------------
-
-This interface represents a stateless animator. This type of animator does not depend on any local
-state either stored on the instance or global scope. Effectively, the animate function of an
-{{StatelessAnimator}} can be treated as a pure function with the expectation that given the same
-input, it produces the same output.
-
-
-
-
-[Exposed=AnimationWorklet, Global=AnimationWorklet, Constructor (optional any options)]
-interface StatelessAnimator {
-};
-
-
-
-
-
- This is how the class should look.
-
- class FooAnimator extends StatelessAnimator{
- constructor(options) {
- // Called when a new animator is instantiated.
- }
- animate(currentTime, effect) {
- // Animation frame logic goes here.
- }
- }
-
-
-
-Note: The statelessness allows an animation worklet to perform optimization such as producing
-multiple animation frames in parallel and performing very cheap teardown and setup. Using
-StatelessAnimator is highly recommended to enable such optimizations.
-
-StatefulAnimator Interface {#stateful-animator-desc}
----------------------------
-
-This interface represents a stateful animator. This animator can have local state and animation
-worklet guarantees that it maintains this state as long as the stateful animator fulfills the
-contract required by this interface as described following.
-
-
-Animation worklet maintains a set of {{WorkletGlobalScope}}s which may exist across different
-threads or processes. Animation worklet may temporarily terminate a global scope (e.g., to preserve
-resources) or move a running animator instance across different global scopes (e.g., if its
-effect is mutable only in a certain thread). Animation worklet guarantees that a stateful animator
-instance's state is maintained even if the instance is respawned in a different global scope.
-
-The basic mechanism for maintaining the state is that the animation worklet snapshots the local
-state that is exposed via {{StatefulAnimator/state}} attribute and then reifies it at a later time
-to be passed into the constructor when the animator instance is respawned in a potentially different
-global scope. This processes is specified is details in migrate an animator instance
-algorithm.
-
-A user-defined stateful animator is expected to fulfill the required contract which is that its
-state attribute is an object representing its state that can be serialized using structured
-serialized algorithm and that it can also recreate its state given that same object passed to
-its constructor.
-
-
-[Exposed=AnimationWorklet, Global=AnimationWorklet,
-Constructor (optional any options, optional any state)]
-interface StatefulAnimator {
- attribute any state;
-};
-
-
-
-
- This is how the class should look.
-
- class BarAnimator extends StatefulAnimator {
- constructor(options, state) {
- // Called when a new animator is instantiated (either first time or after being respawned).
- this.currentVelocity = state ? state.velocity : 0;
- }
- animate(currentTime, effect) {
- // Animation frame logic goes here and can rely on this.currentVelocity.
- this.currentVelocity += 0.1;
- }
- get state {
- // The returned object should be serializable using structured clonable algorithm.
- return {
- velocity: this.currentVelocity;
- }
- }
- }
-
-
-
-
-Animator Definition {#animator-definition-desc}
--------------------
-
-An animator definition is a struct which describes the author defined custom
-animation as needed by {{AnimationWorkletGlobalScope}}. It consists of:
-
- - An animator name <>#.
-
- - A class constructor which is a VoidFunctioncallback function type.
-
- - An animate function which is a Functioncallback function type.
-
- - A stateful flag
-
-
-Registering an Animator Definition {#registering-animator-definition}
--------------------------------------
-An {{AnimationWorkletGlobalScope}} has a animator name to animator definition map.
-The map gets populated when {{registerAnimator(name, animatorCtorValue)}} is called.
-
-
-
-[ Exposed=AnimationWorklet, Global=AnimationWorklet ]
-interface AnimationWorkletGlobalScope : WorkletGlobalScope {
- void registerAnimator(DOMString name, VoidFunction animatorCtor);
-};
-
-
-
-
-When the registerAnimator(|name|, |animatorCtorValue|)
-method is called in a {{AnimationWorkletGlobalScope}}, the user agent must run the
-following steps:
-
- 1. If |name| is not a valid <>, throw a TypeError and abort all these
- steps.
-
- 2. If |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(|animatorCtorValue|) is false, throw a
- TypeError and abort all these steps.
-
- 4. Let |animatorCtor| be the result of converting animatorCtorValue to the
- VoidFunctioncallback function type. If an exception is thrown, rethrow the
- exception and abort all these steps.
-
- 4. Let |prototype| be the result of Get(|animatorCtorValue|, "prototype").
-
-
- 5. If SameValue(|prototype|, {{StatelessAnimator}}) is true set |stateful| to be
- false, otherwise if SameValue(|prototype|, {{StatefulAnimator}}) is
- true set |stateful| to be true, otherwise throw a TypeError and
- abort all these steps.
-
- 6. Let |animateValue| be the result of Get(|prototype|, "animate").
-
- 7. Let |animate| be the result of converting |animateValue| to the Function
- callback function type. If an exception is thrown, rethrow the exception and abort
- all these steps.
-
- 8. Let |definition| be a new animator definition with:
-
- - animator name being |name|
-
- - class constructor being |animatorCtor|
-
- - animate function being |animate|
-
- - stateful flag being |stateful|
-
-
- 9. Add the key-value pair (|name| - |definition|) to the animator name to animator
- definition map.
-
-
-
-Animator Instance {#animator-instance-section}
-======================================
-
-An animator instance is a struct which describes a fully realized custom animation
-instance in an {{AnimationWorkletGlobalScope}}. It has a reference to an animator definition
-and owns the instance specific state such as animation effect and timelines. It consists of:
-
- - An animator name.
-
- - An animation requested flag.
-
- - An animator effect which is an animation effect.
-
- - An animator current time which is the corresponding worklet animation's current
- time.
-
- - An animator timeline which is a timeline.
-
- - An animator attached timelines which is list of attached timelines
-
- - An animator serialized options which is a serializable object.
-
-A stateful animator instance is an animator instance whose corresponding
-animator definition's stateful flag is true.
-
-
-Creating an Animator Instance {#creating-animator-instance}
------------------------------------------------------------
-
-Each animator instance lives in an {{AnimationWorkletGlobalScope}}.
-
-Each {{AnimationWorkletGlobalScope}} has an animator instance set. The set is populated
-when the user agent constructs a new animator instance in the {{AnimationWorkletGlobalScope}}
-scope. Each animator instance corresponds to a worklet animation in the document scope.
-
-
-
-To create a new animator instance given a |name|, |timeline|, |effect|, |serializedOptions|,
-|serializedState|, 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.
-
- 2. Let |animatorCtor| be the class constructor of |definition|.
-
- 3. Let |timelineList| be a new list with |timeline| added to it.
-
- 4. Let |options| be StructuredDeserialize(|serializedOptions|).
-
- 5. Let |state| be StructuredDeserialize(|serializedState|).
-
- 6. Let |animatorInstance| be the result of constructing |animatorCtor| with
- [|options|, |state| as args. If an exception is thrown, rethrow the exception and abort all
- these steps.
-
- 7. Set the following on |animatorInstance| with:
- - animator name being |name|
- - animation requested flag being frame-current
- - animator current time being unresolved
- - animator effect being |effect|
- - animator timeline being |timeline|
- - animator attached timelines being |timelineList|
- - animator serialized options being |options|
-
- 8. Add |animatorInstance| to |workletGlobalScope|'s animator instance set.
-
-
-
-
-Running Animators {#running-animators}
---------------------------------------
-
-When the user agent wants to produce a new animation frame, if for any animator instance the
-associated animation requested flag is frame-requested then the the user agent
-mustrun animators for the current frame.
-
-Note: The user agent is not required to run animations on every visual 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.
-
-
-
-When the user agent wants to run animators in a given |workletGlobalScope|, it
-must iterate over all animator instances in the |workletGlobalScope|'s animator
-instance set. For each such |instance| the user agent must perform the following steps:
-
- 1. Let |animatorName| be |instance|'s animator name
-
- 2. Let the |definition| be the result of looking up |animatorName| on the |workletGlobalScope|'s
- animator name to animator definition map.
-
- If |definition| does not exist then abort the following steps.
-
- 3. If the animation requested flag for |instance| is frame-current or the effect
- 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.
-
- 4. Let |animateFunction| be |definition|'s animate function.
-
- 5. Let |currentTime| be animator current time of |instance|.
-
- 6. Let |effect| be animator effect of |instance|.
-
- 7. Invoke |animateFunction| with arguments «|currentTime|, |effect|»,
- and with |instance| as the callback this value.
-
-
-Note: Although inefficient, it is legal for the user agent to run animators multiple times
-in the same frame.
-
-
-Issue: should be explicit as to what happens if the animateFunction throws an exception. At least
-we should have wording that the localTime values of the keyframes are ignored to avoid incorrect
-partial updates.
-
-Removing an Animator Instance {#removing-animator}
------------------------------------------
-
-
-
-To remove an animator instance given |instance| and |workletGlobalScope| the user agent
-must run the following steps:
-
-1. Remove |instance| from |workletGlobalScope|'s animator instance set.
-
-
-
-
-Migrating an Animator Instance {#migrating-animator}
------------------------------------------
-
-The migration process allows stateful animator instance to be migrated to a different
-{{WorkletGlobalScope}} without losing their local state.
-
-
-
-To migrate an animator instance from one {{WorkletGlobalScope}} to another, given
-|instance|, |sourceWorkletGlobalScope|, |destinationWorkletGlobalScope|, the user agent
-must run the following steps :
-
- 1. Let |serializedState| be undefined.
-
- 2. Queue a task on |sourceWorkletGlobalScope| to run the following steps:
-
- 1. Let |animatorName| be |instance|'s animator name
-
- 2. Let |definition| be the result of looking up |animatorName| on |sourceWorkletGlobalScope|'s
- animator name to animator definition map.
-
- If |definition| does not exist then abort the following steps.
-
- 3. Let |stateful| be the stateful flag of |definition|.
-
- 4. If |stateful| is false then abort the following steps.
-
- 5. Let |state| be the result of Get(|instance|, "state"). If any exception is thrown,
- rethrow the exception and abort the following steps.
-
- 6. Set |serializedState| to be the result of StructuredSerialize(|state|).
- If any exception is thrown, then abort the following steps.
-
- 7. Run the procedure to remove an animator instance given |instance|, and
- |sourceWorkletGlobalScope|.
-
- 2. Wait for the above task to complete. If the task is aborted, abort the following steps.
-
- 3. Queue a task on |destinationWorkletGlobalScope| to run the following steps:
-
- 1. Run the procedure to create a new animator instance given:
- - The |instance|'s animator name as name.
- - The |instance|'s animator timeline as timeline.
- - The |instance|'s animator effect as effect.
- - The |instance|'s animator serialized options as options.
- - The |serializedState| as state.
- - The |destinationWorkletGlobalScope| as workletGlobalScope.
-
-
-
-If an animator state getter throws the user agent will remove the animator but does not recreate it.
-This effectively removes the animator instance.
-
-
-Requesting Animation Frames {#requesting-animation-frames}
-----------------------------------------------------------
-
-Each animator instance has an associated animation requested flag. It must be
-either frame-requested or frame-current. It is initially set to
-frame-current. Different circumstances can cause the animation requested flag to be
-set to frame-requested. These include the following:
- - Changes in the current time of any timeline in the animator's animator attached timelines
- - Changes in the current time of the animator's corresponding Worklet Animation
-
-[[#running-animators]] resets the animation requested flag on animators to
-frame-current.
-
-
-Web Animations Integration {#web-animation-integration}
-===============================
-
-
-Worklet Animation {#worklet-animation-desc}
--------------------------------------------
-Worklet animation is a kind of animation that delegates the animation playback to
-an animator instance. It controls the lifetime and playback state of its corresponding
-animator instance.
-
-Being an animation, worklet animation has an animation effect and a
-timeline. However unlike other animations the worklet animation's current time does
-not directly determine the animation effect's local time (via its inherited time).
-Instead the associated animator instance controls the animation effect's local time
-directly. Note that this means that the timeline's current time does not fully determine the
-animation's output.
-
-Worklet animation has the following properties in addition to the {{Animation}} interface:
- - an animation animator name which identifies its animator definition.
- - a serialized options which is serializable object that is used when
- constructing a new animator instance.
-
-
-
-
- Overview of the WorkletAnimation timing model.
-
- The animation current time is input to the animator instance, which produces a local time value
- for the animation effect. If the animator instance is running in a parallel global scope the
- implementation may also choose to use the local time value to produce the final effect value and
- update the visuals in parallel.
-
-
-
-
-
-Creating a Worklet Animation {#creating-worklet-animation}
------------------------------------------------------------
-
-
-[Exposed=Window,
- Constructor (DOMString animatorName,
- optional (AnimationEffect or sequence)? effects = null,
- optional AnimationTimeline? timeline,
- optional any options)]
-interface WorkletAnimation : Animation {
- readonly attribute DOMString animatorName;
-};
-
-
-
-
-
-WorkletAnimation(|animatorName|, |effects|, |timeline|, |options|)
-
-Creates a new {{WorkletAnimation}} object using the following procedure.
-
- 1. Let |workletAnimation| be a new {{WorkletAnimation}} object.
-
- 2. Run the procedure to set the timeline of an animation on |workletAnimation| passing
- |timeline| as the new timeline or, if a |timeline| argument is not provided,
- passing the default document timeline of the {{Document}} associated with the
- {{Window}} that is the current global object.
-
- 3. Let |effect| be the result corresponding to the first matching condition from below.
- : If |effects| is a {{AnimationEffect}} object,
- :: Let effect be |effects|.
- : If |effects| is a list of {{AnimationEffect}} objects,
- :: Let |effect| be a new {{WorkletGroupEffect}} with its children set to |effects|.
- : Otherwise,
- :: Let |effect| be undefined.
-
- 4. Run the procedure to set the target effect of an animation on |workletAnimation|
- passing |effect| as the new effect.
-
- 5. Let |serializedOptions| be the result of StructuredSerialize(|options|).
- Rethrow any exceptions.
-
- 6. Set the serialized options of |workletAnimation| to |serializedOptions|.
-
- 7. Set the animation animator name of |workletAnimation| to |animatorName|.
-
-
-
-Worklet Animation timing model {#timing-model}
-------------------------------------
-
-This section describes how worklet animation's timing model differs from other
-animations.
-
-In addition to the existing conditions on when the animation is considered ready, a
-worklet animation is only considered ready when the following condition is also true:
-
- - the user agent has completed any setup required to create the worklet animation's
- corresponding animator instance.
-
-As described in [[#worklet-animation-desc]], the worklet animation'scurrent time does
-not determine its animation effect'slocal time. Instead the associated animator
-instance controls the animation effect's local time directly. This means that the
-animation effect's local time is controlled from a {{WorkletGlobalScope}} which may be in a parallel
-execution context.
-
-Here are a few implications of the above semantics:
-
- - Setting the current time or start time of a worklet animation does not
- necessarily change its output, but may change the animation play state.
- - Similarly, invoking {{Animation/finish()}} or updating a worklet animation'splayback
- rate will only change the animation play state and may not change the output.
- - Querying the animation effect's local time using {{AnimationEffect/getComputedTiming()}}
- may return stale information, in the case where the animator instance is running in a
- parallel execution context.
-
-Issue(63): Come with appropriate mechanism's for animator instance to get notified when its
- animation currentTime is changing e.g., via reverse(), finish() or playbackRate change. So that
- it can react appropriately.
-
-
-Interaction with Animator Instances {#worklet-animation-animator-instances}
------------------------------------
-
-A worklet animation corresponds to at most one animator instance at any time, and may
-have no current corresponding animator instance. The correspondance of an animator
-instance for a worklet animation depends on the animation play state.
-
-
-
-To associate animator instance of worklet animation given |workletAnimation|,
-the user agent must run the following steps:
-
- 1. If |workletAnimation| has a corresponding animator instance, abort the following steps.
- 2. Let |workletGlobalScope| be the {{AnimationWorkletGlobalScope}} associated with
- |workletAnimation|.
- 3. Queue a task on |workletGlobalScope| to run the procedure to create a new animator
- instance, passing:
- * The |workletAnimation|'s animation animator name as name.
- * The |workletAnimation|'s timeline as timeline.
- * The |workletAnimation|'s animation effect as effect.
- * The |workletAnimation|'s serialized options as options.
- * The |workletGlobalScope| as workletGlobalScope.
- 4. If the procedure was successful, set the resulting animator instance as corresponding to
- |workletAnimation|.
-
-
-
-
-
-To disassociate animator instance of worklet animation given
-|workletAnimation|, the user age must run the following steps:
-
- 1. If |workletAnimation| does not have a corresponding animator instance, abort the
- following steps.
- 2. Let |workletGlobalScope| be the {{AnimationWorkletGlobalScope}} associated with
- |workletAnimation|.
- 3. Let |animatorInstance| be |workletAnimation|'s corresponding animator instance.
- 4. Queue a task on the |workletGlobalScope| to run the procedure to remove an animator
- instance, passing |animatorInstance| as instance and |workletGlobalScope| as
- workletGlobalScope.
- 5. Set |workletAnimation| as having no corresponding animator instance.
-
-
-
-When a given |workletAnimation|'s play state changes to pending, running, or
-paused, run the procedure to
-associate animator instance of worklet animation given |workletAnimation|.
-
-
-When a given |workletAnimation|'s play state changes to idle or finished,
-run the procedure to
-disassociate animator instance of worklet animation given |workletAnimation|.
-
-When the procedure to set the target effect of an animation for a given |workletAnimation|
-is called, then set animator instance of worklet animation given |workletAnimation|.
-
-When the procedure to set the timeline of an animation for a given |workletAnimation|
-is called, then set animator instance of worklet animation given |workletAnimation|.
-
-
-Timeline Attachment {#timeline-attachment}
--------------------
-
-Issue(61): Define semantics of attachment and detachment.
-
-ScrollTimeline {#scroll-timeline}
----------------------------------
-{{ScrollTimeline}} is a new concept being proposed for addition to web animation API. It defines
-an animation timeline whose time value depends on the scroll position of a scroll container.
-Worklet animations can have a scroll timeline and thus drive their scripted effects based
-on a scroll offset.
-
-Note: Access to input: We are interested on exposing additional user input beside
-scrolling (e.g., touch/pointer input) to these animations so that authors can create jank-free
-input driven animations which are not really possible today. We are still trying to figure out the
-right abstractions and mechanisms to do this.
-
-WorkletGroupEffect {#worklet-group-effect}
-------------------
-
-{{WorkletGroupEffect}} is a type of group effect that allows its child effect's
-local times to be mutated individually.
-
-When a {{WorkletGroupEffect}} is set as the animation effect of a {{WorkletAnimation}}, the
-corresponding animator instance can directly control the child effects' local
-times. This allows a single worklet animation to coordinate multiple effects - see
-[[#example-2]] for an example of such a use-case.
-
-
-[Exposed=AnimationWorklet]
-interface WorkletGroupEffect {
- sequence getChildren();
-};
-
-[Exposed=AnimationWorklet]
-partial interface AnimationEffect {
- // Intended for use inside Animation Worklet scope to drive the effect.
- attribute double localTime;
-};
-
-
-
-
-To set the {{localTime}} property on a |effect| to value |t|, the user agent should perform the
-action that corresponds to the first matching condition from the following:
-
- : If the |effect| does not have a parent group,
- :: Set the |effect| local time to |t|.
- : If the |effect| has a parent group and it is of {{WorkletGroupEffect}} type,
- :: Set the effect start time to (parent's transformed time - t). Note this effectively set's the
- |effect|'s local time to t.
- : Otherwise
- :: Throw an exception indicating that the child effect time can only be controlled by
- its parent group.
-
-
-
-Issue(w3c/csswg-drafts#2071): The above interface exposes a conservative subset
-of GroupEffect proposed as part of web-animation-2. Once that is available we
-should switch to it.
-
-
-Effect Stack and Composite Order {#effect-stack-composite-order}
---------------------------------
-
-As with other animations, worklet animations participate in the effect stack. A
-worklet animation does not have a specific animation class which means it has the same
-composite order as other Javascript created web animations.
-
-
-Examples {#examples}
-====================
-
-Example 1: Hidey Bar. {#example-1}
------------------------------------------
-An example of header effect where a header is moved with scroll and as soon as finger is lifted it
-animates fully to close or open position depending on its current position.
-
-
-
-
-
Some header
-
content
-
-
-
-
-
-
-
-// Inside AnimationWorkletGlobalScope
-
-registerAnimator('hidey-bar', class HidybarAnimator extends StatefulAnimator {
- constructor(options, state) {
- this.scrollTimeline_ = options.scrollTimeline;
- this.documentTimeline_ = options.documentTimeline;
-
- if (state) {
- this.startTime_ = state.startTime;
- this.direction_ = state.direction;
- }
- }
-
- animate(currentTime, effect) {
- const scroll = this.scrollTimeline_.currentTime; // [0, 100]
- const time = this.documentTimeline_.currentTime;
-
- const activelyScrolling = this.scrollTimeline_.phase == 'active';
-
- let localTime;
- if (activelyScrolling) {
- this.startTime_ = undefined;
- localTime = scroll;
- } else {
- this.startTime_ = this.startTime_ || time;
- // Decide on close/open direction depending on how far we have scrolled the header
- // This can even do more sophisticated animation curve by computing the scroll velocity and
- // using it.
- this.direction_ = scroll >= 50 ? +1 : -1;
- localTime = this.direction_ * (time - this.startTime_);
- }
-
- // Drive the output effect by setting its local time.
- effect.localTime = localTime;
- }
-
- getter state() {
- return {
- startTime: this.startTime_,
- direction: this.direction_
- }
- }
-});
-
-
-
-Issue: This example uses a hypothetical "phase" property on timeline as a way to detect when user
-is no longer actively scrolling. This is a reasonable thing to have on scroll timeline. A simple
-fallback can emulate this by detecting when timeline time (i.e. scroll offset) has not changed in
-the last few frames.
-
-
-Example 2: Twitter header. {#example-2}
---------------------------
-An example of twitter profile header effect where two elements (avatar, and header) are updated in
-sync with scroll offset.
-
-
-
-// In document scope.
-
-
-
-
-
-
-
-
-
-
-// Inside AnimationWorkletGlobalScope.
-registerAnimator('twitter-header', class HeaderAnimator extends StatelessAnimator {
- constructor(options) {
- this.timing_ = new CubicBezier('ease-out');
- }
-
- animate(currentTime, effect) {
- const scroll = currentTime; // scroll is in [0, 1000] range
-
- // Drive the output group effect by setting its children local times individually.
- effect.children[0].localTime = scroll;
- effect.children[1].localTime = this.timing_(clamp(scroll, 0, 500));
- }
-});
-
-function clamp(value, min, max) {
- return Math.min(Math.max(value, min), max);
-}
-
-
-
-Example 3: Parallax backgrounds. {#example-3}
------------------------------------------
-A simple parallax background example.
-
-
-
-
-
-
-
-
-
-
-
-
-
-// Inside AnimationWorkletGlobalScope.
-registerAnimator('parallax', class ParallaxAnimator extends StatelessAnimator {
- constructor(options) {
- this.rate_ = options.rate;
- }
-
- animate(currentTime, effect) {
- effect.localTime = currentTime * this.rate_;
- }
-});
-
diff --git a/css-animationworklet/README.md b/css-animationworklet/README.md
deleted file mode 100644
index abb08be1..00000000
--- a/css-animationworklet/README.md
+++ /dev/null
@@ -1,398 +0,0 @@
-# Animation Worklet Explainer
----
-
-# Overview
-
-Animation Worklet is a new primitive for creating scroll-linked and other high performance
-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
-
-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 such as scroll.
-
-This document proposes an API to create custom animations that execute inside an isolated execution
-environment, *worklet*. It aims to be compatible with Web Animations and uses existing constructs as
-much as possible. We believe this API hits a sweet spot in balancing among performance, richness,
-and rationality for addressing our key use cases.
-
-See the [Animation Worklet design principles and goals](principles.md) for an overview of the
-motivations behind Animation Worklet and how the design will be evolved to support a growing set of
-rich use cases. Also see [the status document](status.md) for high level implementation status and
-timeline.
-
-# Motivating Use Cases
-
-* Scroll-linked effects:
- - Parallax ([demo](https://googlechromelabs.github.io/houdini-samples/animation-worklet/parallax-scrolling/))
- - Animated scroll headers, eg. "hidey-bars" ([demo](https://googlechromelabs.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))
- - Springy sticky elements ([demo](http://googlechromelabs.github.io/houdini-samples/animation-worklet/spring-sticky/))
-
-* Animations with custom timing functions (particularly those that are not calculable a priori)
-
- - Spring timing function ([demo](https://googlechromelabs.github.io/houdini-samples/animation-worklet/spring-timing/))
-
-* Location tracking and positioning:
-
- - Position: sticky
-
-* Procedural animation of multiple elements in sync:
-
- - Efficient Expando ([demo](http://googlechromelabs.github.io/houdini-samples/animation-worklet/expando/), [more info](https://developers.google.com/web/updates/2017/03/performant-expand-and-collapse))
- - Compositing growing / shrinking box with border (using 9 patch)
-
-
-These usecases are enabled by the current proposed but [additional usecases](principles.md#animation-worklet-vision) are going to be addressed by extension of the API.
-
-***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.
-
-
-# Key Concepts
-
-## Animation Worklet Global Scope
-A [worklet global scope](https://drafts.css-houdini.org/worklets/#the-global-scope) that is created
-by Animation Worklet. Note that Animation Worklet creates multiple such scopes and uses them to
-execute user defined effects.
-
-## WorkletAnimation
-`WorkletAnimation` is a subclass of Animation that can be used to create an custom animation effect
-that runs inside a standalone animation worklet scope. A worklet animation has a corresponding
-animator instance in a animation worklet scope which is responsible to drive its keyframe effects.
-Here are the key differences compared to a regular web animation:
- - AnimationId should match a specific animator class registered in the animation worklet scope.
- - `WorkletAnimation` may have multiple timelines (including `ScrollTimeline`s).
- - `WorkletAnimation` may have a custom properties bag that can be cloned and provided to animator
- constructor when it is being instantiated.
-
-Note that worklet animations expose same API surface as other web animations and thus they may be
-created, played, paused, inspected, and generally controlled from main document scope. Here is how
-various methods roughly translate:
-
- - cancel(): cancels the animation and the corresponding animator instance is removed.
- - play(): starts the animation and the corresponding animator instance may get its `animate` function
- called periodically as a result of changes in its timelines.
- - pause(): pauses the animation and the corresponding animator instance no longer receives
- `animate` calls.
- - finish(): invokes `finish` on the corresponding animator instance.
- - reverse() or mutating playbackRate: invokes `playbackRateChanged` on the corresponding
- animator instance.
-
-## ScrollTimeline
-[ScrollTimeline](https://wicg.github.io/scroll-animations/#scrolltimeline) is a concept introduced in
-scroll-linked animation proposal. It defines an animation timeline whose time value depends on
-scroll position of a scroll container. `ScrollTimeline` can be used an an input timeline for
-worklet animations and it is the intended mechanisms to give read access to scroll position.
-
-## GroupEffect
-[GroupEffect](https://w3c.github.io/web-animations/level-2/#the-animationgroup-interfaces) is a
-concept introduced in Web Animation Level 2 specification. It provides a way to group multiple
-effects in a tree structure. `GroupEffect` can be used as the output for worklet animations. It
-makes it possible for worklet animation to drive effects spanning multiple elements.
-
-**TODO**: At the moment, `GroupEffect` only supports just two different scheduling models (i.e.,
-parallel, sequence). These models governs how the group effect time is translated to its children
-effect times by modifying the child effect start time. Animation Worklet allows a much more
-flexible scheduling model by making it possible to to set children effect's local time directly. In
-other words we allow arbitrary start time for child effects. This is something that needs to be
-added to level 2 spec.
-
-## Multiple Timelines
-Unlike typical animations, worklet animations can be attached to multiple timelines. This is
-necessary to implement key usecases where the effect needs to smoothly animate across different
-timelines (e.g., scroll and wall clock).
-
-### Primary Timeline
-The first timeline is considered the *primary timeline*. The only purpose of the primary timeline is
-to make integration with existing web animation machinery easier, in particular the primary timeline
-time will be used anywhere the web animation API needs to expose a time value, for example in
-[event timeline time](https://w3c.github.io/web-animations/level-2/#event-timeline-time), or
-[event current time](https://w3c.github.io/web-animations/level-2/#event-current-time).
-
-
-**TODO**: We are considering API designs that can make it possible for an animation to observe multiple
-timelines but only gets activated on a (dynamic) subset of them. This ensures we can be more
-efficient when updating the animation.
-
-## Animator Migration
-The animators are not guaranteed to run in the same global scope (or underlying thread) for their
-lifetime duration. For example, a user agents is free to initially run the animator on main thread
-but later decide to migrate it off main thread to get certain performance optimizations. To allow
-worklet animators to keep their state across migrations, the API provides the following lifetime
-hooks:
-
-```js
-// in document scope
-new WorkletAnimation('animation-with-local-state', [], [], {value: 1});
-```
-
-
-```js
-registerAnimator('animation-with-local-state', class {
- constructor(options, state) {
- // |options| may be either:
- // - The user provided options bag passed into the WorkletAnimation constructor on first initialization i.e, {value: 1}.
- // - The object returned by |destroy| after each migration i.e. {value: 42}.
- this.options_ = options;
- this.state_ = state || {value: Math.random()};
- }
-
- animate(timelines, effect) {
- this.state_.value += 0.1;
- effect.localTime = this.state_.value;
- }
-
- destroy() {
- // Invoked before each migration attempts.
- // The returned object must be structure clonable and will be passed to constructor to help
- // animator restore its state after migration to the new scope.
- return this.state_;
- }
-});
-```
-
-# Examples
-
-**TODO**: Add gifs that visualize these effects
-
-## Hidey Bar
-An example of header effect where a header is moved with scroll and as soon as finger is lifted
-it animates fully to close or open position depending on its current position.
-
-
-``` html
-
-
Some header
-
content
-
-
-
-```
-
-hidey-bar-animator.js:
-```js
-registerAnimator('hidey-bar', class {
-
- constructor(options) {
- this.scrollTimeline_ = options.scrollTimeline;
- this.documentTimeline_ = options.documentTimeline;
- }
-
- animate(currentTime, effect) {
- const scroll = this.scrollTimeline_.currentTime; // [0, 100]
- const time = this.documentTimeline_.currentTime;
-
- // **TODO**: use a hypothetical 'phase' property on timeline as a way to detect when user is no
- // longer actively scrolling. This is a reasonable thing to have on scroll timeline but we can
- // fallback to using a timeout based approach as well.
- const activelyScrolling = this.scrollTimeline_.phase == 'active';
-
- let localTime;
- if (activelyScrolling) {
- this.startTime_ = undefined;
- localTime = scroll;
- } else {
- this.startTime_ = this.startTime_ || time;
- // Decide on close/open direction depending on how far we have scrolled the header
- // This can even do more sophisticated animation curve by computing the scroll velocity and
- // using it.
- this.direction_ = scroll >= 50 ? +1 : -1;
- localTime = this.direction_ * (time - this.startTime_);
- }
-
- // Drive the output effects by setting its local time.
- effect.localTime = localTime;
-});
-
-```
-
-
-## Twitter Header
-An example of twitter profile header effect where two elements (avatar, and header) are updated in
-sync with scroll offset.
-
-```html
-
-
-
-
-
-
-
-```
-
-twitter-header-animator.js:
-```js
-registerAnimator('twitter-header', class {
- constructor(options) {
- this.timing_ = new CubicBezier('ease-out');
- }
-
- clamp(value, min, max) {
- return Math.min(Math.max(value, min), max);
- }
-
- animate(currentTime, effect) {
- const scroll = currentTime; // [0, 1]
-
- // Drive the output group effect by setting its children local times.
- effect.children[0].localTime = scroll;
- // Can control the child effects individually
- effect.children[1].localTime = this.timing_(this.clamp(scroll, 0, 1));
- }
-});
-
-```
-
-### Parallax
-```html
-
-
-
-
-
-
-
-
-```
-
-parallax-animator.js:
-
-```js
-// Inside AnimationWorkletGlobalScope.
-registerAnimator('parallax', class {
- constructor(options) {
- this.rate_ = options.rate;
- }
-
- animate(currentTime, effect) {
- effect.localTime = currentTime * this.rate_;
- }
-});
-```
-
-
-# WEBIDL
-
-`WorkletAnimation` extends `Animation` and adds a getter for its timelines.
-Its constructor takes:
- - `animatiorId` which should match the id of an animator which is registered in
-the animation worklet scope.
- - A sequence of effects which are passed into a `GroupEffect` constructor.
- - A sequence of timelines, the first one of which is considered primary timeline and passed to
- `Animation` constructor.
-
-```webidl
-
-[Constructor (DOMString animatorName,
- optional (AnimationEffectReadOnly or array)? effects = null,
- AnimationTimeline? timeline,
- optional WorkletAnimationOptions)]
-interface WorkletAnimation : Animation {
- readonly attribute DOMString animatorName;
-}
-```
-
-**TODO**: At the moment `GroupEffect` constructor requires a timing but this seems unnecessary for
-`WorkletAnimation` where it should be possible to directly control individual child effect local
-times. We need to bring this up with web-animation spec.
-
-`AnimationEffectReadOnly` gets a writable `localTime` attribute which may be used to drive the
-effect from the worklet global scope.
-
-```webidl
-partial interface AnimationEffectReadOnly {
- [Exposed=Worklet]
- // Intended for use inside Animation Worklet scope to drive the effect.
- attribute double localTime;
-};
-
-```
-
-
-
-
-# Specification
-The [draft specification](https://drafts.css-houdini.org/css-animationworklet) is
-the most recent version.
-
-
-[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
-
diff --git a/css-animationworklet/img/AnimationWorklet-threading-model.svg b/css-animationworklet/img/AnimationWorklet-threading-model.svg
deleted file mode 100644
index 26d7ba93..00000000
--- a/css-animationworklet/img/AnimationWorklet-threading-model.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/css-layout-api/Overview.bs b/css-layout-api/Overview.bs
index 899f1cee..6074248e 100644
--- a/css-layout-api/Overview.bs
+++ b/css-layout-api/Overview.bs
@@ -55,9 +55,6 @@ spec:css2; type:property; text:max-width
-urlPrefix: https://heycam.github.io/webidl/; type: dfn;
- urlPrefix: #dfn-;
- url: throw; text: thrown
urlPrefix: https://tc39.github.io/ecma262/#sec-; type: dfn;
text: constructor
text: Construct
@@ -66,10 +63,6 @@ urlPrefix: https://tc39.github.io/ecma262/#sec-; type: dfn;
url: terms-and-definitions-function; text: function
urlPrefix: native-error-types-used-in-this-standard-
text: TypeError
-urlPrefix: https://drafts.csswg.org/css-sizing/#; type: dfn
- text: intrinsic sizes
-urlPrefix: https://drafts.csswg.org/css-break/#; type: dfn
- text: fragmentation break
urlPrefix: https://www.w3.org/TR/CSS21/; type:dfn
urlPrefix: box.html#;
url: box-dimensions; text: box model edges
@@ -216,7 +209,7 @@ The {{LayoutWorkletGlobalScope}} is the global execution context of the {{layout
@@ -1594,8 +1587,9 @@ dictionary FragmentResultOptions {
BreakTokenOptions breakToken = null;
};
-[Constructor(FragmentResultOptions)]
+[Exposed=LayoutWorklet]
interface FragmentResult {
+ constructor(optional FragmentResultOptions options = {});
readonly attribute double inlineSize;
readonly attribute double blockSize;
};
diff --git a/css-paint-api/EXPLAINER.md b/css-paint-api/EXPLAINER.md
index f01f1e56..96a5402c 100644
--- a/css-paint-api/EXPLAINER.md
+++ b/css-paint-api/EXPLAINER.md
@@ -73,7 +73,7 @@ if ('paintWorklet' in CSS) {
}
```
-See the worklets explainer for a more involed explaination of worklets. In short worklets:
+See the worklets explainer for a more involved explaination of worklets. In short worklets:
- Are similar to workers in that the script runs in a separate global script context.
- A script inside a worklet has no DOM, Network, Database, etc access.
- The global script context lifetime is not defined (you should expect the script context to be killed at any point).
diff --git a/css-paint-api/Overview.bs b/css-paint-api/Overview.bs
index f356e559..f7570b54 100644
--- a/css-paint-api/Overview.bs
+++ b/css-paint-api/Overview.bs
@@ -36,6 +36,9 @@ Ignored Terms: PaintWorklet
spec:infra; type:dfn; text:list
spec:webidl; type:dfn; text:converting
+spec:html; type:dfn;
+ text:set bitmap dimensions;
+ text:reset the rendering context to its default state
@@ -71,6 +74,8 @@ which are related to painting.
The {{paintWorklet}}'s [=worklet global scope type=] is {{PaintWorkletGlobalScope}}.
+The {{paintWorklet}}'s worklet destination type is "paintworklet".
+
partial namespace CSS {
[SameObject] readonly attribute Worklet paintWorklet;
@@ -85,7 +90,7 @@ identical to the Window.{{Window/devicePixelRatio}} property.
@@ -142,7 +147,7 @@ by the paint function). It consists of:
DOMStrings.
- A input argument syntaxes which is a [=list=] of
- parsed [[css-properties-values-api-1#supported-syntax-strings]].
+ [=syntax definitions=].
- A PaintRenderingContext2DSettings object.
@@ -198,15 +203,15 @@ called, the user agent must run the following steps:
10. If |inputArgumentsIterable| is not undefined, then set |inputArguments| to the result of
[=converting=] |inputArgumentsIterable| to a sequence<DOMString>. If an
- execption is thrown, rethrow the execption and abort all these steps.
+ exception is thrown, rethrow the exception and abort all these steps.
11. Let |inputArgumentSyntaxes| be an [=list/empty=] [=list=].
12. [=list/For each=] |item| in |inputArguments| perform the following substeps:
- 1. Let |parsedSyntax| be the result of parsing |item| according to the rules in
- [[css-properties-values-api-1#supported-syntax-strings]]. If it fails to parse
- [=throw=] a [=TypeError=] and abort all these steps.
+ 1. Attempt to [=consume a syntax definition=] from |item|.
+ If failure was returned, [=throw=] a [=TypeError=] and abort all these steps.
+ Otherwise, let |parsedSyntax| be the returned [=syntax definition=].
2. [=list/Append=] |parsedSyntax| to |inputArgumentSyntaxes|.
@@ -402,6 +407,7 @@ For interfaces which use the {{CanvasDrawImage}} mixin:
{{CanvasDrawImage/drawImage}}.
Note: This should eventually be moved to the canvas section of the HTML specification.
+See Issue 819.
Drawing an image {#drawing-an-image}
====================================
@@ -596,8 +602,8 @@ When the user agent wants to invoke a paint callback given |name|, |i
[=computed value=]'s for properties listed in |inputProperties|.
8. Let |renderingContext| be the result of [=create a PaintRenderingContext2D object=] given:
- - "width" - The width given by |concreteObjectSize|.
- - "height" - The height given by |concreteObjectSize|.
+ - "width" - The width given by |snappedConcreteObjectSize|.
+ - "height" - The height given by |snappedConcreteObjectSize|.
- "paintRenderingContext2DSettings" - The
[=paint definition/PaintRenderingContext2DSettings object=] given by |definition|.
@@ -991,23 +997,26 @@ There are no known security issues introduced by these features.
Privacy Considerations {#privacy-considerations}
================================================
-There are no known privacy issues introduced by these features.
+* The timing of paint callbacks can be used as a high-bandwidth channel for detecting "visited" state for links.
+ (details)
+ This is not a fundamentally new privacy leak,
+ as visited state leaks from many interactions,
+ but absent any further mitigations,
+ this is a particularly high-bandwidth channel of the information.
+
+ No official mitigations are planned at this time,
+ as this privacy leak needs to be addressed more directly
+ to fix all such channels.
Changes {#changes}
==================
-Changes since the last publication:
-
-
- Adding converting the paint function to the WebIDL Function type, instead of just a raw
- javascript function.
- (Issue 743)
+Changes since the 9 August 2018 CR publication:
+
+* Filtered the list of input properties to a paint worklet to be only known or custom properties.
-
- Added a step to {{registerPaint()}} to filter out unsupported native CSS properties. These now
-do not appear in the {{StylePropertyMapReadOnly}} provided to the paint function.
- (Issue 523)
-
+* Added alpha flag to {{PaintRenderingContext2D}} to control whether the rendering surface is forced opaque or allows transparency.
-A Disposition of Comments is available.
+* Fix definition for the size of the output bitmap:
+ > The size of the output bitmap is the concrete object size of the object it is rendering to size of the fragment it is rendering.
diff --git a/css-paint-api/issues-cr-2018.bs b/css-paint-api/issues-cr-2018.bs
new file mode 100644
index 00000000..65ee503f
--- /dev/null
+++ b/css-paint-api/issues-cr-2018.bs
@@ -0,0 +1,57 @@
+Draft: https://www.w3.org/TR/2018/CR-css-paint-api-1-20180809/
+Title: CSS Painting API Level 1
+----
+Issue 1.
+Summary: Broken LInks
+From: Chris Lilley
+Comment: https://github.com/w3c/css-houdini-drafts/issues/787
+Response: https://github.com/w3c/css-houdini-drafts/issues/787#issuecomment-411123499
+Closed: Accepted
+Resolved: Editorial
+----
+Issue 2.
+Summary: CSS Paint API leaks browsing history
+From: Deian Stefan
+Comment: https://github.com/w3c/css-houdini-drafts/issues/791
+Response: https://github.com/w3c/css-houdini-drafts/issues/791#issuecomment-546460085
+Changes: https://github.com/w3c/css-houdini-drafts/commit/3c72275054d9d541e6526e2988567ad4d209f257
+Closed: Accepted
+Resolved: Editor discretion
+Verified: https://github.com/w3c/css-houdini-drafts/issues/791#issuecomment-546466424
+----
+Issue 3.
+Summary: Typo: use snappedConcreteObjectSize in paint callback
+From: Chris Harrelson
+Comment: https://github.com/w3c/css-houdini-drafts/issues/800
+Changes: https://github.com/w3c/css-houdini-drafts/commit/735ea42edf09f8d69de1eddbc7e7691528f56963
+Closed: Accepted
+Resolved: Editorial
+----
+Issue 4.
+Summary: Disconnect between css-paint-api-1 and HTML specs on CanvasImageSource
+From: Alan Jeffrey
+Comment: https://github.com/w3c/css-houdini-drafts/issues/819
+Response: https://github.com/w3c/css-houdini-drafts/issues/819#issuecomment-424360647
+Open: Waiting for HTML spec edits
+----
+Issue 5.
+Summary: Improve passing of large-scale data to PaintWorklet
+From: John Wiesz
+Comment: https://github.com/w3c/css-houdini-drafts/issues/872
+Response: https://github.com/w3c/css-houdini-drafts/issues/872#issuecomment-499903766
+Open: Waiting on edits to add new features to Properties an Values API
+----
+Issue 6.
+Summary: Cycle possibe using inputProperties()
+From: Stephen McGruer
+Comment: https://github.com/w3c/css-houdini-drafts/issues/877
+Response: https://github.com/w3c/css-houdini-drafts/issues/877#issuecomment-499922873
+Open: Needs Edits
+----
+Issue 7.
+Summary: Two-way communication between main thread and worklet
+From: Samad Aghaei
+Comment: https://github.com/w3c/css-houdini-drafts/issues/881
+Response: https://github.com/w3c/css-houdini-drafts/issues/881#issuecomment-546456591
+Closed: OutOfScope
+----
diff --git a/css-paint-api/issues-cr-2018.html b/css-paint-api/issues-cr-2018.html
new file mode 100644
index 00000000..9c7a0ccb
--- /dev/null
+++ b/css-paint-api/issues-cr-2018.html
@@ -0,0 +1,128 @@
+
+
+CSS Painting API Level 1 Disposition of Comments for 2018-08-09 CR
+
+
+
CSS Painting API Level 1 Disposition of Comments for 2018-08-09 CR
Introduction {#intro}
@@ -56,16 +61,540 @@ can only impact document layout or paint by being re-incorporated into the value
of other properties via a var() reference.
This specification extends [[css-variables]], allowing the registration of properties
-that have a value type, an initial value, and a defined inheritance behaviour.
+that have a value type, an initial value, and a defined inheritance behaviour,
+via two methods:
-This specification is complementary to [[css-paint-api]] and [[css-layout-api]], which
+* A JS API, the {{registerProperty()}} method
+* A CSS at-rule, the ''@property'' rule
+
+This specification is complementary to [[css-paint-api-1]] and [[css-layout-api-1]], which
allow custom properties to directly impact paint and layout behaviours respectively.
-Registering custom properties {#registering-custom-properties}
-==============================================================
+
+
+
+
+Registered Custom Properties {#behavior-of-custom-properties}
+=============================================================
+
+A [=custom property=] can become a registered custom property,
+making it act more like a UA-defined property:
+giving it a syntax that's checked by the UA,
+an initial value,
+and a specific inheritance behavior.
+This can be done by the ''@property'' rule,
+or the {{registerProperty()}} JS function.
+
+A [=custom property=] is considered to be registered for a {{Document}}
+if there is a valid ''@property'' rule
+defined for its name
+in one of the document's stylesheets,
+or its name is [=map/contains|contained=]
+in the document's {{[[registeredPropertySet]]}} slot
+(that is, {{registerProperty()}} was called to register it).
+
+A [=registered custom property=] acts similarly to an unregistered [=custom property=],
+except as defined below.
+
+Determining the Registration {#determining-registration}
+--------------------------------------------------------
+
+A [=registered custom property=] has a custom property registration
+that contains all the data necessary to treat it like a real property.
+It's a [=struct=] consisting of:
+
+* a property name (a [=custom property name string=])
+* a syntax (a [=syntax string=])
+* an inherit flag (a [=boolean=])
+* optionally, an initial value (a [=string=] which successfully [=CSS/parses=] according to the syntax)
+
+If the {{Document}}’s {{[[registeredPropertySet]]}} slot
+[=set/contains=] a record with the [=custom property’s=] name,
+the registration is that record.
+
+Otherwise,
+if the {{Document}}’s active stylesheets contain at least one valid ''@property'' rule
+representing a registration with the [=custom property’s=] name,
+the last such one in document order is the registration.
+
+Otherwise there is no registration,
+and the [=custom property=] is not a [=registered custom property=].
+
+Parse-Time Behavior {#parsing-custom-properties}
+------------------------------------------------
+
+[=Registered custom properties=] parse exactly like unregistered [=custom properties=];
+almost anything is allowed.
+The registered syntax of the property is not checked at parse time.
+
+Note: However,
+the syntax is checked at computed-value time,
+before substitution via ''var()''.
+See [[#calculation-of-computed-values]].
+
+
+ Why aren't custom properties syntax-checked?
+
+ When parsing a page's CSS,
+ UAs commonly make a number of optimizations
+ to help with both speed and memory.
+
+ One of those optimizations
+ is that they only store the properties that will actually have an effect;
+ they throw away invalid properties,
+ and if you write the same property multiple times in a single declaration block,
+ all but the last valid one will be thrown away.
+ (This is an important part of CSS's error-recovery
+ and forward-compatibility behavior.)
+
+ This works fine if the syntax of a property never changes over the lifetime of a page.
+ If a custom property is registered, however,
+ it can change its syntax,
+ so that a property that was previously invalid
+ suddenly becomes valid.
+
+ The only ways to handle this are to either store every declaration,
+ even those that were initially invalid
+ (increasing the memory cost of pages),
+ or to re-parse the entire page's CSS
+ with the new syntax rules
+ (increasing the processing cost of registering a custom property).
+ Neither of these are very desirable.
+
+ Further,
+ UA-defined properties have their syntax determined
+ by the version of the UA the user is viewing the page with;
+ this is out of the page author's control,
+ which is the entire reason for CSS's error-recovery behavior
+ and the practice of writing multiple declarations for varying levels of support.
+ A custom property, on the other hand,
+ has its syntax controlled by the page author,
+ according to whatever stylesheet or script they've included in the page;
+ there's no unpredictability to be managed.
+ Throwing away syntax-violating custom properties
+ would thus only be, at best, a convenience for the page author,
+ not a necessity like for UA-defined properties.
+
+
+[=Specified Value=]-Time Behavior {#specified-value}
+----------------------------------------------------
+
+Just like unregistered [=custom properties=],
+all [=registered custom properties=], regardless of registered syntax,
+accept the [=CSS-wide keywords=],
+such as ''inherit'' or ''revert''.
+Their behavior is defined in [[css-cascade-4#defaulting-keywords]].
+
+[=Computed Value=]-Time Behavior {#calculation-of-computed-values}
+------------------------------------------------------------------
+
+The [=computed value=] of a [=registered custom property=]
+is determined by the syntax of its [=registration=].
+
+If the [=registration’s=] syntax is the [=universal syntax definition=],
+the [=computed value=] is the same as for unregistered [=custom properties=]
+(either the specified value with variables substituted,
+or the [=guaranteed-invalid value=]).
+
+Otherwise, attempt to [=CSS/parse=] the property's value
+according to its registered syntax.
+If this fails,
+the [=computed value=] is the [=guaranteed-invalid value=].
+If it succeeds,
+the [=computed value=] depends on the specifics of the syntax:
+
+For "<length>",
+"<length-percentage>",
+"<angle>",
+"<time>",
+"<resolution>",
+"<integer>",
+"<number>",
+and "<percentage>" values:
+
+* If the specified value is a [=dimension=] literal
+ (such as ''50em'' or ''.2s''),
+ the computed value is the same value,
+ but with the unit converted to the corresponding [=canonical unit=]
+ for the type of value.
+* If the specified value is any other numeric literal
+ (such as ''5'' or ''20%''),
+ the computed value is as specified.
+ (In particular, percentages are never resolved against anything.)
+* If the specified value is a function that evaluates to one of those types
+ (such as a [=math function=]),
+ the computed value is defined by that function.
+
+For "<color>" values,
+the value is computed by [=resolving color values=].
+
+For "<custom-ident>", ident, or "*" values,
+the computed value is as specified.
+
+For "<url>" values,
+the computed value is one of the following:
+
+* if the URL is a relative URL,
+ the computed value is the resolved absolute URL as described in [[!css3-values]].
+* otherwise, the computed value is as specified.
+
+
+ URL behavior examples
+
+ Because URLs resolve against the base URL of the stylesheet they appear in, we can
+ end up with multiple relative URLs that resolve against different base URLs, even though
+ they appear in the same property.
+
+ For example, suppose '--url-foo' and '--url-bar' are registered
+ custom properties with ''<url>'' syntax, and that we have a stylesheet at
+ /style/foo/foo.css:
+
+
+ div {
+ --url-foo: url("foo.png");
+ }
+
+
+ and another stylesheet at /style/bar/bar.css
+
+
+ Here, the ''var(--url-foo)'' reference would produce a URL that resolves against
+ /style/foo, and the ''var(--url-bar)'' reference would produce a URL that resolves
+ against /style/bar.
+
+ On the other hand,
+ if both '--url-foo' and '--url-bar' were unregistered,
+ they would substitute their literal values
+ (relative URLs)
+ into the /index.html stylesheet,
+ which would then resolve the URLs against /index.html instead.
+
+
+
+For "<image>" values,
+the computed value is the [=computed <image>=].
+
+For "<transform-function>" and "<transform-list>" values,
+the computed value is as specified but with all lengths resolved to their computed values.
+
+For values with [[#multipliers|multipliers]],
+the computed value is a list of the computed values of the base type.
+
+For syntaxes specified with [[#combinator|the | combinator]],
+the computed value is given by applying the computed-value rules
+for the first clause that matches the value.
+
+
+Animation Behavior {#animation-behavior-of-custom-properties}
+-------------------------------------------------------------
+
+Note: As defined by [[css3-animations]] and [[css3-transitions]], it is possible to
+specify animations and transitions that reference custom properties.
+
+When referenced by animations and transitions,
+custom property values [=interpolate=] [=by computed value=],
+in accordance with the type that they parsed as.
+
+Note: This implies that a list of values,
+such as `+` or `#`,
+will interpolate as a simple list,
+matching up each component index-by-index,
+and failing if the number of components doesn't match.
+
+As an exception to the above rule,
+a value that parsed as a ``,
+a ``,
+or a `+`
+instead interpolates as per the 'transform' property.
+
+Note: If,
+for whatever reason,
+a custom property is defined with a syntax of `#`,
+this will thus first interpolate as a simple list,
+and then each list item will interpolate as a 'transform' value.
+
+Note: Registering (or changing the registration) of a custom property
+can change its computed value,
+which can start or interrupt a CSS transition.
+
+Conditional Rules {#conditional-rules}
+--------------------------------------
+
+As stated in [[#parsing-custom-properties]],
+both unregistered and [=registered=] [=custom properties=]
+accept (almost) all possible values at parse-time.
+[=Registered=] [=custom properties=] only apply their syntax at [=computed value=] time.
+
+So, all [=custom properties=],
+regardless of whether they're [=registered=] or unregistered,
+will test as "true" in an ''@supports'' rule,
+so long as you don't violate the (very liberal) generic syntax for [=custom properties=].
+
+
+ For example,
+ even if a custom property is registered
+ with syntax: "<color>";,
+ a rule like `@supports (--foo: 1em) {...}`
+ will still evaluate as true and apply those styles,
+ because the declaration does successfully parse as a valid property.
+
+
+
+Substitution via ''var()'' {#substitution}
+------------------------------------------
+
+Like unregistered custom properties,
+the value of a registered custom property can be substituted into another value with the ''var()'' function.
+However, registered custom properties substitute as their [[#calculation-of-computed-values|computed value]],
+rather than the original token sequence used to produce that value.
+
+Any ''var()'' function that references a registered custom property
+must be replaced with an equivalent token sequence,
+which is equal to the token sequence that would have been produced
+by [=serialize a CSS value|serializing=] the computed value,
+and [[css-syntax-3#tokenization|tokenizing]] the resulting string.
+
+
+ Suppose that '--x' is registered with ''<length>'' syntax,
+ and that '--y'is an unregistered custom property.
+
+
+
+ Because the computed value of '--x' (when serialized) is "80px",
+ the computed value of '--y' is
+ a <> with a value of "80" and unit "px".
+
+
+### Fallbacks In ''var()'' References ### {#fallbacks-in-var-references}
+
+References to registered custom properties using the ''var()'' function may
+provide a fallback. However, the fallback value must match the
+syntax definition of the custom property being referenced, otherwise the
+declaration is invalid at computed-value time.
+
+Note: This applies regardless of whether or not the fallback is being used.
+
+
+### Dependency Cycles via Relative Units ### {#dependency-cycles}
+
+[=Registered custom properties=] follow the same rules for dependency cycle resolution
+as unregistered [=custom properties=],
+with the following additional constraints:
+
+For any registered custom property
+with a <> or <> syntax component:
+
+* If the property contains any of the following units:
+ ''em'', ''ex'', ''cap'', ''ch'', ''ic'', ''lh'';
+ then add an edge between the property
+ and the ''font-size'' of the current element.
+* If the property contains the ''lh'' unit,
+ add an edge between the property
+ and the ''line-height'' of the current element.
+* If the property contains any of the following units: ''rem'', ''rlh'';
+ then add an edge between the property
+ and the 'font-size'' of the root element.
+* If the property contains the ''rlh'' unit,
+ add an edge between the property
+ and the 'line-height'' of the root element.
+
+
+
+ and ''font-size'' will behave as if the value ''unset'' was specified.
+
+
+
+
+
+
+The @property Rule {#at-property-rule}
+=================================================
+
+The ''@property'' rule represents a [=custom property registration=]
+directly in a stylesheet
+without having to run any JS.
+Valid ''@property'' rules result in a [=registered custom property=],
+as if {{registerProperty()}} had been called with equivalent parameters.
+
+The syntax of ''@property'' is:
+
+
+ @property <> {
+ <>
+ }
+
+
+A valid ''@property'' rule represents a [=custom property registration=],
+with the property name being the serialization of the <>
+in the rule's prelude.
+
+''@property'' rules require a 'syntax' and 'inherits' descriptor;
+if either are missing,
+the entire rule is invalid and must be ignored.
+The 'initial-value' descriptor is optional
+only if the syntax is the [=universal syntax definition=],
+otherwise the descriptor is required;
+if it's missing, the entire rule is invalid and must be ignored.
+
+Unknown descriptors are invalid and ignored,
+but do not invalidate the ''@property'' rule.
+
+Note: As specified in [[#determining-registration]],
+if multiple valid ''@property'' rules are defined for the same <>,
+the last one in stylesheet order "wins".
+A custom property registration from {{registerProperty()|CSS.registerProperty()}}
+further wins over any ''@property'' rules
+for the same <>.
+
+A ''@property'' is invalid if it occurs in a stylesheet inside of a [=shadow tree=],
+and must be ignored.
+
+Issue(939): This will likely change in the future,
+as the behavior of concept-defining at-rules in shadow trees
+becomes more consistently defined.
+
+The 'syntax' Descriptor {#the-syntax-descriptor}
+------------------------------------------------
+
+
+
+Specifies the syntax of the [=custom property registration=]
+represented by the ''@property'' rule,
+controlling how the property's value is parsed at [=computed value=] time.
+
+The 'syntax' descriptor is required for the ''@property'' rule to be valid;
+if it's missing, the ''@property'' rule is invalid.
+
+If the provided string is not a valid [=syntax string=]
+(if it returns failure when [=consume a syntax definition=] is called on it),
+the descriptor is invalid and must be ignored.
+
+
+The 'inherits' Descriptor {#inherits-descriptor}
+------------------------------------------------
+
+
+
+Specifies the inherit flag of the [=custom property registration=]
+represented by the ''@property'' rule,
+controlling whether or not the property inherits by default.
+
+The 'inherits' descriptor is required for the ''@property'' rule to be valid;
+if it's missing, the ''@property'' rule is invalid.
+
+
+The 'initial-value' Descriptor {#initial-value-descriptor}
+----------------------------------------------------------
+
+
+ Name: initial-value
+ Value: <>
+ For: @property
+ Initial: the [=guaranteed-invalid value=] (but see prose)
+
+
+Specifies the initial value of the [=custom property registration=]
+represented by the ''@property'' rule,
+controlling the property’s [=initial value=].
+
+If the value of the 'syntax' descriptor is the [=universal syntax definition=],
+then the 'initial-value' descriptor is optional.
+If omitted, the [=initial value=] of the property is the [=guaranteed-invalid value=].
+
+Otherwise,
+if the value of the 'syntax' descriptor is not the [=universal syntax definition=],
+the following conditions must be met for the the ''@property'' rule to be valid:
+
+ * The 'initial-value' descriptor must be present.
+ * The 'initial-value' descriptor's value must [=consume a syntax definition|parse successfully=]
+ according to the grammar specified by the [=syntax definition=].
+ * The 'initial-value' must be [=computationally independent=].
+
+If the above conditions are not met, the ''@property'' rule is invalid.
+
+
+
+
+Registering Custom Properties in JS {#registering-custom-properties}
+====================================================================
+
+To register a custom property via JS,
+the {{CSS}} object is extended with a {{registerProperty()}} method:
Additional, the {{Document}} object gains a new \[[registeredPropertySet]] private slot,
which is a set of records that describe registered custom properties.
-The {{PropertyDescriptor}} dictionary {#the-propertydescriptor-dictionary}
---------------------------------------------------------------------------
-
-A PropertyDescriptor dictionary represents author-specified configuration
-options for a custom property. {{PropertyDescriptor}} dictionaries contain the
-following members:
-
-: name
-:: The name of the custom property being defined.
-
-: syntax
-:: A string representing how this custom property is parsed.
-
-: inherits
-:: True if this custom property should inherit down the DOM tree; False otherwise.
-
-: initialValue
-:: The initial value of this custom property.
-
-The {{registerProperty()}} function {#the-registerproperty-function}
+The {{registerProperty()}} Function {#the-registerproperty-function}
--------------------------------------------------------------------
-The registerProperty(PropertyDescriptor descriptor) method
+The registerProperty(PropertyDefinition definition) method
registers a custom property according to the configuration options provided in
-descriptor.
+definition.
When it is called,
it executes the register a custom property algorithm,
-passing the options in its descriptor argument
+passing the options in its definition argument
as arguments of the same names.
@@ -125,40 +635,21 @@ as arguments of the same names.
associated Document's
{{[[registeredPropertySet]]}} slot.
- 2. Attempt to parse |name|
- as a <>.
- If this fails,
+ 2. If |name| is not a [=custom property name string=],
throw a {{SyntaxError}}
and exit this algorithm.
- Otherwise,
- let |parsed name| be the parsed value.
-
If |property set|
- already contains an entry with |parsed name| as its property name
+ already contains an entry with |name| as its property name
(compared codepoint-wise),
throw an {{InvalidModificationError}}
and exit this algorithm.
- 3. If |syntax| is not present,
- or is equal to "*" (U+002A ASTERISK),
- let |parsed syntax| be undefined,
- and skip to the next step of this algorithm.
-
- Otherwise, attempt to parse |syntax|
- according to the rules in [[#supported-syntax-strings]].
- If it does not parse successfully,
- throw a {{SyntaxError}}.
- Otherwise,
- let |parsed syntax| be the parsed syntax.
-
- Note: For example, a valid syntax string is something like "<length>",
- or "<number>+";
- the allowed syntax is a subset of [[css-values-3#value-defs]].
- Future levels of this specification are expected to expand the complexity of allowed syntax strings,
- allowing custom properties that more closely resemble the full breadth of what CSS properties allow.
+ 3. Attempt to [=consume a syntax definition=] from |syntax|.
+ If it returns failure, throw a {{SyntaxError}}.
+ Otherwise, let |syntax definition| be the returned syntax definition.
- 4. If |parsed syntax| is undefined,
+ 4. If |syntax definition| is the universal syntax definition,
and |initialValue| is not present,
let |parsed initial value| be empty.
This must be treated identically to the "default" initial value of custom properties,
@@ -166,8 +657,8 @@ as arguments of the same names.
Skip to the next step of this algorithm.
Otherwise,
- if |parsed syntax| is undefined,
- parse |initialValue| as a <>.
+ if |syntax definition| is the universal syntax definition,
+ [=CSS/parse=] |initialValue| as a <>.
If this fails,
throw a {{SyntaxError}}
and exit this algorithm.
@@ -180,8 +671,8 @@ as arguments of the same names.
and exit this algorithm.
Otherwise,
- parse {{PropertyDescriptor/initialValue}}
- according to |parsed syntax|.
+ [=CSS/parse=] {{PropertyDefinition/initialValue}}
+ according to |syntax definition|.
If this fails,
throw a {{SyntaxError}}
and exit this algorithm.
@@ -193,12 +684,12 @@ as arguments of the same names.
5. Set |inherit flag| to the value of |inherits|.
- 6. Let |registered property| be a record
- with a property name of |parsed name|,
- a syntax of |parsed syntax|,
+ 6. Let |registered property| be a [=struct=]
+ with a property name of |name|,
+ a syntax of |syntax definition|,
an initial value of |parsed initial value|,
and an inherit flag of |inherit flag|.
- Add |registered property|
+ [=set/Append=] |registered property|
to |property set|.
@@ -233,7 +724,7 @@ Registering a custom property must not affect the [=cascade=] i
Regardless of what syntax is specified for a registered property,
at parse time it is still parsed as normal for a [=custom property=],
accepting nearly anything.
-If the [=specified value=] for a registered [=custom property=]
+If the [=specified value=] for a [=registered custom property=]
violates the registered syntax,
however,
the property becomes [=invalid at computed-value time=]
@@ -281,91 +772,54 @@ the property becomes [=invalid at computed-value time=]
and becoming ''inherit''.
-Supported syntax strings {#supported-syntax-strings}
-----------------------------------------------------
+The {{PropertyDefinition}} Dictionary {#the-propertydefinition-dictionary}
+--------------------------------------------------------------------------
-The following syntax strings are supported:
-
-: Primitive Terms
-:: The following syntax strings are primitive terms that can be
- combined as described below:
-
- : "<length>"
- :: Any valid <> value
- : "<number>"
- :: <> values
- : "<percentage>"
- :: Any valid <> value
- : "<length-percentage>"
- :: Any valid <> or <> value, any valid <>
- expression combining <> and <> components.
- : "<color>"
- :: Any valid <> value
- : "<image>"
- :: Any valid <> value
- : "<url>"
- :: Any valid <> value
- : "<integer>"
- :: Any valid <> value
- : "<angle>"
- :: Any valid <> value
- : "<time>"
- :: Any valid <