Login Form Avatar を React で実装してみた


Login Form Avatar

少し前、 Dribbble で Animated login form avatar なるものが人気を得ていました。

ログインフォームの入力欄に文字を入力すると、フォームの上部にいるアバターが文字の入力を目で追い、パスワードを入力し始めると目を覆い隠すというものです。
(実際に見ていただいたほうが早いと思います)

Login Animal

Login Form Avatar の Swift 実装である Login Critter に感化され、練習も兼ねて React で実装してみました。

デモ

マウスカーソルを追うクマ
キャレットを追うクマ

オンラインデモ

コード

コードは GitHub で公開しています。が、あとで綺麗に書き直す!と言ったっきり整理していないのでそこは勘弁してください

どうやって動いてるの?

実は平面的に動いてるだけ

結構立体的に動いているように見えますが、実はこれはマウスカーソルやキャレットの位置に応じて目や鼻や口などのパーツを平面的に動かしているだけです。

今回題材とした動物が単純な丸で構成されていることも助けにはなっていると思いますが、たったこれだけで結構立体的に動いているように見えます。

顔のパーツの可動範囲をあらかじめ定義しておき、マウスカーソルやキャレットの位置に応じてその可動範囲内で動かしています。

たとえばマウスカーソルが画面の一番左(マウスカーソルを動かすことができると勝手に決めた仮想の領域の最も左)にあるときは、パーツの可動範囲のうち最も左になるように、反対に画面の一番右にあるときは可動範囲のうち最も右になるように配置しています。上下も同じです。

それぞれの可動範囲は実際に動かしてみて、それっぽく見えた位置にしています。

腕のアニメーション

腕のアニメーションだけ、マウスカーソルやキャレットの位置には関係なく動きます。

あらかじめ両腕が目を覆い隠すように配置しておき、CSS の transform: translate() で描画範囲の外に出るようにしておきます。

その後パスワードフォームにフォーカスが当たったタイミングで transform: unset を適用することで、パスワードを入力中に両腕で目を覆い隠すようにしています。

雑感

当初の想定通り、目で追う対象の移動量に比例してパーツを平面的に動かすだけでも案外立体的に動いているように見えました。
人間の目が補正して、立体的に動いているように見えているんだと思います。人間すごい。

両腕で目を覆い隠すアニメーションのところはなんとなく両腕が描画範囲から外に出る位置に translate しているだけなので、腕の画像のサイズや目の位置などを変更した場合にそこも変更しなければいけないというのはなんだか面倒な気がします。改善したいです。

コードの説明

最後に、軽くコードの説明をしておきます。

まず、アバター全体を表すコンポーネントとして Animal コンポーネントがあります。
Animal コンポーネントは directionX, directionY という属性を持ち、これは Animal の目線の方向を指定します。

directionXdirectionY はそれぞれ 0 から 1 の値を取り、 0 が最も左(上)で、 1 が最も右 (下) となります。

次に、顔のパーツとして FacePart コンポーネントを Animal コンポーネントの子要素として追加します。

FacePart コンポーネントを Animal コンポーネントの子要素に追加することで、 Animal に指定した directionX, directionY 属性が FacePart コンポーネントに同期されます。

パーツの可動範囲は position 属性に {minX: number, minY: number, maxX: number, maxY: number} という構造で指定し、値は全て、親となる Animal コンポーネント内での相対的な位置(左上が原点)を 0 から 1 の数で指定します。例えば 0.5 は X 軸方向または Y 軸方向の中央を意味します。

それぞれの FacePart コンポーネントは props に指定された directionX, directionY 属性の値と position 属性の値から、親要素 (Animal) から見た自身の相対的な位置を決定します。
この時 FacePart コンポーネントは position で指定された位置が自身のコンポーネントの中心となるように配置されるため、[0.5, 0.5] という位置が指定された場合は完全に中央に配置されることになります。

このデモで使用したクマの耳、頭、目、マズル、鼻、口の可動範囲を指定した Ear, Head, Eye, Muzzle, Nose, MouthFacePart を継承したコンポーネントとして既に定義してあるので、これらのコンポーネントの src 属性だけを変更して画像を差し替えてみるだけでも面白いかもしれません。

良い感じにできたら共有してもらえるとてもうれしいです!