LottieとNuxtでWebページをリッチにする


会社のAdventCalendarだから気合を入れて書かなければと思った結果気合が遅延しました…  

最初はFlutterに関して書く予定でしたがちょっと別の機会に取っておこうと思います。  
今回はLottieとNuxtを使ったwebページ構築を試してみたのでそちらをご紹介したいと思います。  

## Lottieとは
https://airbnb.design/lottie/

airbnbがAndroid,iOS,React Native向けに作ったライブラリでAdobe After Effectで作成した動画をjsonに書き出しページ上にSVGやキャンバスなどで組み込むことができます。  
AfterEffectsはモーショングラフィックスを作ることに長けたソフトウェアですのでうまく使えばリッチなウェブページを作れるわけです。  
流れとしては

AfterEffect ←lottie-web(旧Bodymovin)→  JSONデータ  ← Lottie-vue → HTML(SVG|canvas|HTML)  
という流れです。

※BodymovinはLottieの旧名称のようです。そのためところどころlottieとBodymovinがドキュメント状などでも混ざってたりします、気をつけて読みんでいきましょう。

## AfterEffectとLottieの制約
AfterEffectは月額数千円で使える比較的安価な動画制作ツールです。素材を用意しそれにEffectをつけたり、各フレーム(時間)に対してキーフレームと呼ばれるポイントを打って動きを制御していきます。  
ただし今回はWebページです。LottieはJSONからWebページに展開する性質上AfterEffectsのEffectは使用できません。  
使用できるAfterEffectsは次の機能です。

- プリコンプ
- 図形
- 平面
- 画像
- ヌルオブジェクト
- テキスト
- マスクとマスク反転
- タイムリマッピング
- シェイプレイヤー
- エクスプレッション

逆に次の機能は使えないようです

- 音声素材
- 動画素材
- 画像シーケンス素材
- No negative layer stretching! No idea why, but stretching a layer messes with all the data.
    - negative layerの意が汲み取れず… 詳細不明

## AfterEffectにプラグインを追加する
まずはAfterEffectsがJSONデータを書き出せれるように拡張機能を追加します。Readmeではて手順を2通り用意されていますが今回はAdobeのCreativeCloudClientのアプリ経由で追加します。  
次のWebページから紐付いているAdobeIDでログインしてFreeをクリックすると自動でインストールされます。

https://www.adobeexchange.com/creativecloud.details.12557.html

またAfterEffect設定を開いてスクリプトから~にチェックを入れておきます。
![](https://i.imgur.com/O1Eq0oz.png)


## AfterEffectsで素材を作る

今回は次のようなコンポを用意しました。正味5分ほどで作った文字と平面レイヤーのアニメーションです。  
やっぱりEffectなしの制約は厳しくいつもより時間がかかりました。  
![](https://i.imgur.com/ocjQ4yU.gif)

これをBodymovinを使ってJSONを書き出します。

まずは拡張機能からBodymovinを呼び出します。
![](https://i.imgur.com/cdascSB.png)


表示されたら次のて手順で書き出しを行います。
![](https://i.imgur.com/NEPORCr.png)

これでAftterEffectでの作業はおしまいです。

## Nuxtのアプリケーションを作る
ここからはいつものおなじみの作業です。  
次のコマンドを打ってNuxtプロジェクトを作ります。

```
$ npx create-nuxt-app lotty-vue-sample                                                                                                                                                                                                 [~]
npx: 402個のパッケージを11.736秒でインストールしました。
> Generating Nuxt.js project in /Users/matsushitashousatoru/lotty-vue-sample
? Project name lotty-vue-sample
? Project description My rad Nuxt.js project
? Use a custom server framework none
? Use a custom UI framework element-ui
? Choose rendering mode Universal
? Use axios module yes
? Use eslint yes
? Use prettier no
? Author name godan
? Choose a package manager yarn
Initialized empty Git repository in /Users/matsushitashousatoru/lotty-vue-sample/.git/
yarn install v1.7.0
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning eslint > file-entry-cache > flat-cache > circular-json@0.3.3: CircularJSON is in maintenance only, flatted is its successor.
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > element-ui@2.4.11" has unmet peer dependency "vue@^2.5.2".
warning " > eslint-loader@2.1.1" has unmet peer dependency "webpack@>=2.0.0 <5.0.0".
warning " > eslint-plugin-vue@4.7.1" has incorrect peer dependency "eslint@^3.18.0 || ^4.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
warning Your current version of Yarn is out of date. The latest version is "1.12.3", while you're on "1.7.0".
info To upgrade, run the following command:
$ brew upgrade yarn
✨  Done in 22.46s.

  To get started:

    cd lotty-vue-sample
    yarn run dev

  To build & start for production:

    cd lotty-vue-sample
    yarn run build
    yarn start
```

次にyarnでlottie-vueを突っ込みます。

```
$ yarn add  vue-lottie                                                                                                                                                                     

[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > element-ui@2.4.11" has unmet peer dependency "vue@^2.5.2".
warning " > eslint-plugin-vue@4.7.1" has unmet peer dependency "eslint@^3.18.0 || ^4.0.0".
warning "eslint-plugin-vue > vue-eslint-parser@2.0.3" has unmet peer dependency "eslint@>=3.9.0".
warning " > vue-lottie@0.2.1" has unmet peer dependency "vue@^2.5.16".
[4/4] 📃  Building fresh packages...
```
公式のサンプルに従ってlottie用のミックスイン コンポーネントを作成します。  
引数がなければデフォルト値で動けるよう設定していきます。

lotty_sample/components/lottie.vue

```vuejs

<template>

    <div :style="style" ref="lavContainer"></div>
</template>

<script>
  import lottie from 'lottie-web';
  export default {
    props: {
      options: {
        type: Object,
        required: true
      },
      height: Number,
      width: Number,
    },

    data () {
      return {
        style: {
          width: this.width ? `${this.width}px` : '100%',
          height: this.height ? `${this.height}px` : '100%',
          overflow: 'hidden',
          margin: '0 auto'
        }
      }
    },
    mounted () {
      console.log(this.options.animationData.default)
      this.anim = lottie.loadAnimation({
          container: this.$refs.lavContainer,
          renderer: 'svg',
          loop: this.options.loop !== false,
          autoplay: this.options.autoplay !== false,
          animationData: this.options.animationData.default,  // ここだけ変更何故かデフォルトを入れないと動かなかった… (要検証)
          rendererSettings: this.options.rendererSettings
        }
      );
      this.$emit('animCreated', this.anim)
    }
  }
</script>
```

次にページ側からlottieを呼び出して、先程書き出したJSONを与えます。

lotty_sample/pages/index.vue

```vuejs

<template>
  <section class="container">
    <div>
      <h1 class="title">lotty-vue-sample</h1>
      <!--  先程作ったlottieコンポーネントを呼び出し、 そのときにjsonのデータを受け渡す。  -->
      <lottie :options="defaultOptions" :height="400" :width="400" v-on:animCreated="handleAnimation"/>

    </div>
  </section>
</template>

<script>
import Logo from "~/components/Logo.vue";
import Lottie from "~/components/Lottie.vue";

// JSONデータを読み込み
import * as animationData from "~/assets/podcaster.json";

export default {
  components: {
    Logo,
    Lottie
  },
  data() {
    return {
      // データを定義
      defaultOptions: { animationData: animationData },
      animationSpeed: 1
    };
  },
  methods: {
    handleAnimation: function(anim) {
      this.anim = anim;
    },

  
  }
};
</script>

<style>
body{
  background-color: black;
}
</style>

```

これで`yarn run dev`で実行してみると。

![](https://i.imgur.com/J1z41VU.gif)

ブラウザで作成したアニメーションが動きました!  

ワンポイントでも気軽に使うこともできそうですね。コレによってWebでもリッチなアニメーションが可能になりそうです。  
いろいろ試行錯誤して進展あれば新しく記事書きますー。