CSS
JavaScript

Animation WorkletのPolyfill試してみた

Animation Workletとは

Animation WorkletはCSS Houdini task forceで策定が進められているハイパフォーマンスなWebアニメーションや、スクロールの動きに連動するWebアニメーションを実現するための新しいAPIです。元々はCompositor Workletというものだったようですが、変遷を経てAnimation Workletに生まれ変わったようです。

Animation Workletはメインスレッドから切り離された専用のスレッドを持つことによってスレッドジャンキーなアニメーション処理でもメインスレッドへの影響を避けることができるようです。まだ仕様策定の段階なので、そのパフォーマンスを見ることはできませんが、polyfillが公開されているのでAPIを試すことができます。

Polyfillを使ってみる

scroll linked zoom

スクロールに連動してズームイン・アウトするオブジェクトを作
ってみます。

zoom.gif

const scroller = document.getElementById('scroller');
const circle = document.querySelector('.circle');
const options = null;

window.scrollLinkedZoom = new WorkletAnimation('scroll-linked-zoom-sample', [
    new KeyframeEffect(circle, [{'transform': 'translate(0, 0) scale(1)'}, {'transform': 'translate(-27px, 0) scale(0.4)'}], {duration: 144, fill: 'both'})],
    new ScrollTimeline({scrollSource: scroller, orientation: 'vertical', endScrollOffset: '144px', timeRange: 144}), {},
    options
);
window.scrollLinkedZoom.play();

new WorkletAnimation()でAnimation Workletオブジェクトを生成します。
第一引数に呼び出すアニメーションのモジュール名を指定します。
以降はモジュールに渡すパラメーターになります。
第二引数にはKeyFrameを設定します。ズームの大きさを指定します。
第三引数のScrollTimeLine()はスクロールの位置を検知するための設定です。
第四引数はオプションです。
play()を呼ぶことでアニメーションが動作します。

以下は呼び出されるアニメーションモジュールの定義です。

constructor(options) {
    this.options = options;
}

animate(currentTime, effect) {
    effect.children[0].localTime = currentTime;
}

constructor()は初期化関数です。引数にオプションが渡ってきます。
animate()はwhile(true)のような無限ループです。
ScrollTimeLine()によってスクロールの位置が随時currentTimeに送られます。
effectはKeyFrameです。localTimeで動きを調整します。ここではズームの大きさです。スクロールの位置をそのまま代入します。

ソース:https://github.com/taichitk/houdini-samples/tree/master/animation-worklet/scroll-linked-zoom-sample

モグラ叩き

ランダムに上下するオブジェクト群を作ってみます。

mogura.gif

const moguras = document.querySelectorAll('.mogura');
const effects = [];
const options = [];
const min = 1;
const max = 3;

moguras.forEach(function(mogura) {
    new KeyframeEffect(circle, [{'transform': 'translate(0, 0) scale(1)'}, {'transform': 'translate(-27px, 0) scale(0.4)'}], {duration: 144, fill: 'both'})],
    new ScrollTimeline({scrollSource: scroller, orientation: 'vertical', endScrollOffset: '144px', timeRange: 144}), {},
    options
});
window.springAnimation = new WorkletAnimation('spring', effects, new DocumentTimeline(), options);
window.springAnimation.play();

new WorkletAnimation()でオブジェクトを生成しますが、先ほどのScrollTimeLine()ではなくDocumentTimeLine()を使います。アニメーションがスタートしてからの経過時間を出力してくれます。

constructor(options) {
    this.options = options;
}

animate(currentTime, effects) {
    const time = currentTime * 0.001;
    const options = this.options;
    effects.children.forEach(function(effect, i) {
        const weight = options[i].weight;
        const repeatTime = Math.abs(Math.sin(time * Math.PI / weight) * 100);
        effect.localTime = repeatTime;
    });
}

currentTimeにDocumentTimeLine()から経過時間が送られてきます。
経過時間と共にモグラの位置が変わる処理を書きます。
モグラの位置をlocalTimeへ代入しています。

ソース:https://github.com/taichitk/houdini-samples/tree/master/animation-worklet/mogura

参考

CSS Animation Worklet API
WICG/animation-worklet