css-houdini-drafts icon indicating copy to clipboard operation
css-houdini-drafts copied to clipboard

[css-animationworklet] Custom easing

Open jakearchibald opened this issue 5 years ago • 2 comments

https://drafts.css-houdini.org/css-animation-worklet-1/#example-1 - the spec has an implementation of custom easing, but using it means you have to significantly change how you author animations, and the easing only applies across the whole animation, rather than keyframe-to-keyframe.

Is it worth providing a way to create custom easings?

Something like:

CSS.animationWorklet.addModule('custom-easings.js');

And in custom-easings.js:

registerEasing('bounce', class BounceEasing {
  constructor(options) {
    …
  }

  ease(position) {
    return position …
  }
});

Where the easing function takes a linear position, between 0-1, and returns its eased position.

Usage:

el.animate(keyframes, {
  easing: new WorkletEasing('bounce', options)
});

WorkletEasing could be using for easing the animation, but also for easing keyframes.

jakearchibald avatar Nov 11 '20 10:11 jakearchibald

Thinking about this more, I don't think WorkletEasing is the right idea. The defined easing should be callable through a CSS function, similar to paint(id), meaning custom easings could be used in CSS animations/transitions as well as web animations.

jakearchibald avatar Dec 04 '20 07:12 jakearchibald

Updated example:

CSS.animationWorklet.addModule('custom-easings.js');

And in custom-easings.js:

registerEasing('bounce', class BounceEasing {
  static get inputArguments() { return ['<number>']; }

  constructor([numBounces = 3]) {
    this.numBounces = numBounces;
  }

  ease(position) {
    // position is 0-1. This function should return a number.
    // Returning < 0 or > 1 is allowed.
    // Returning position as-is would be a linear easing.
    return position …
  }
});

Then in CSS:

@keyframes drop {
  from {
    transform: translateY(-400%);
    animation-timing-function: ease(bounce, 3);
  }
}

.el {
  animation: drop 1s;
}

Or the equivalent in the web animation API:

el.animate({
  offset: 0,
  transform: 'translateY(-400%)',
  easing: 'ease(bounce, 3)',
}, 1000);

We may also need an API like CSS.whenEasingDefined('bounce'), which returns a promise which resolves when an easing with name 'bounce' is registered. This is based on customElements.whenDefined, and it's something we may also want for other kinds of registrations like paint & animation.

jakearchibald avatar Dec 04 '20 09:12 jakearchibald