Rive Appでダークモード対応のアニメーションを実装
背景
最近Rive Appでアニメーションを作ったのですが、サイトのテーマによって全く見えなくなるという悲しい現象が発覚しました。
React環境でのRiveはcanvasまたはwebglなのでCSSでテーマをどうにかすることは不可能です。
解決策はRiveのInputを使い現在のテーマをRiveに送り、その変数でアニメーションを切り替えるロジックを組み込むことです。
基本設定
デザインの作成
まず初めに、Rive Appでベースとなるデザインを作成します。ベクターツールを使って必要な図形や要素を描きましょう。この記事では省略します。
アニメーションの作成
次に、作成したデザイン要素にアニメーションを適用します。タイムラインを使って、動きやエフェクトを設定していきます。アニメーションをステートマシンに組み込むためには、タイムライン上でキーフレームを設定し、各要素の動きや変化を制御していきます。
今回の例ではテキストパスのオフセットを0%から100%にしてます。ループにすることでアニメーションが別のものに移行するまで、永遠に続きます。
ステートマシンの設定
ここからが今回の本題であるダークモード対応のキモです。ステートマシンを使って、ライトモードとダークモードの切り替えを実装します。
まず、ベースとなるアニメーションをステートマシンに組み込みます。その後、同じアニメーションのダークモードバージョンを作成する必要があります。
ダークモードバージョンの作成方法
ライトモードのタイムラインを右クリック>duplicateで名前をつけてください。ダークモードバージョンでは、最初の1フレーム目にエレメントの色を白にするキーフレームを設定します。同様に、ベースのアニメーション(ライトモード)も最初のフレームで全てのエレメントを黒に色を設定するキーフレームを作成します。Art Boardを左クリックすると右側のselected colorsに使われてる色がすべて表示されるのでそこからキーフレームを打つと楽です。色を変更して青いダイヤモンドのボタンを押すとタイムラインにキーフレームが打ち込まれます。
この設定により、テーマが切り替わったときに自動的に正しい色に再設定される仕組みが完成します。
新しく作ったダークモードのアニメーションをドラッグでタイムラインに追加し、entryから左クリックで繋げてください。
モード切替のためのインプット設定
ステートマシン上でライトモードとダークモードを切り替えるためには、外部からのインプットを作成する必要があります。
インプット作成(+をクリックしbooleanを選択。名前はisDarkMode
)
ステートマシンでの切替設定
作成した変数を使って、ステートマシン上でライトモードからダークモード、ダークモードからライトモードへの遷移を設定します。矢印をクリックし右のconditionからisDarkMode
を選び移行するアニメーションに対してtrue
かfalse
にしてください。
スピンアニメーション中にテーマが変わった場合
次にアニメーション中にアプリのテーマが変わったときにアニメーションを変更する必要があります。先ほどと同じようにインプットを使います。ただし今回はアニメーション同士に矢印が出ます。
これでステートマシンが完成です。ページがロードした際、アプリケーションのテーマによって isDarkMode
の変数が決まり、それによりまずどちらの方向に進むかが決まります。そして、そこからスピンアニメーションがループしますが、外部でテーマが変わった場合、再び反対側のテーマにステートツリーが移動するという仕組みです。
ステートツリーが正しく実装されているかチェック。
Export>for runtime(.riv)を選択し作成したRiveアニメーションをダウンロードします。
Reactでの実装
次に、作成したRiveアニメーションをReactアプリケーションにて実装する方法を説明します。
基本的なRiveアニメーションの読み込み
まずuseRive
hookを使用してRiveのアニメーションを読み込みます。<RiveComponent>
はコンポーネントで、アニメーションを表示したい場所に起きます。rive
はref
なようなものでアニメーションライフサイクルを管理することが出来ます。
import {
useRive,
Layout,
Fit,
Alignment,
useStateMachineInput,
} from '@rive-app/react-canvas'
const Component = () => {
const { RiveComponent, rive } = useRive({
src: '/rive/dark_mode_tutorial.riv', // ファイル名
stateMachines: ['spin'], // ステートマシン名
layout: new Layout({
fit: Fit.Contain,
alignment: Alignment.Center,
}),
autoplay: false,
});
// Rive instanceが読み込まれた後、アニメーションを再生する
useEffect(() => {
if (rive) {
rive.play();
}
}, [rive]);
return (
<div>
<RiveComponent />
</div>
);
};
isDarkModeをアプリ側から制御
Riveアニメーションに設定したisDarkMode
インプットを設定するため、以下のuseStateMachineInput
hookを使います。
const isDarkMode = useStateMachineInput(rive, 'spin', 'isDarkMode')
アプリのテーマを取得してisDarkMode.value
を更新することでRive内のステートマシンが動作します。
const { theme } = useTheme() // フレームワークによる
const isDarkMode = useStateMachineInput(rive, 'spin', 'isDarkMode')
useEffect(() => {
if (isDarkMode) {
isDarkMode.value = theme === 'dark' // テーマが更新するとインプットも更新
}
}, [isDarkMode, theme])
これでテーマに合わせて自動的にRiveのアニメーションがテーマを変更します!
まとめ
Rive Appでダークモード対応のアニメーション作成、以上になります。今の所このような使い方はあまり主流では無いのか、DocsやSDKには何も記載されていないです。アニメーション内でキーフレームを使い色を変える作業が若干面倒です。
ただし、複数のアニメーションで設定する必要はない(他のアニメーションで色をキーフレームしてない場合に限る)ので、複数のアニメーションを同時に実行する場合すべてにこのようなロジックを組み込む必要はありません。
Rive Appはかなり機能が多いので今後も情報を共有していこうと思います!
Discussion