はじめに
こんにちは!わかと(@ts_st)です。
今回は、天気APIをただ表示するのではなく、Framer Motionを使って「やさしい体験」に変えた話を書きます。
作ったものは、『おてんきぐらし』という育成Webサービスです。
『おてんきぐらし』は、ユーザーのいる場所の現実世界の天気や時間と連動して、ゲーム内の世界やキャラクターの様子が変わるサービスです。
たとえば、大阪で雨が降っていればゲームの中も雨になり、夜になればキャラクターも眠ります。
天気予報を見るのは面倒です。
でも、急な雨や気圧の変化はつらいです。
そこで、ただ「今日の天気は雨です」と表示するのではなく、
雨だから、ゲームの中でも雨が降っている
雨の日だから、いつもと違う体験ができるかもしれない
という形に変えたいと思いました。
この記事では、その中でFramer Motionをどう使ったかを書きます。
作ったもの
作ったものは、現実の天気と連動する育成Webサービスです。
主な機能は以下です。
- 現実の天気や時間とゲーム内の世界が連動する
- 天気によってキャラクターの世界が変わる
- キャラクターをおさんぽに出せる
- おさんぽ先の景色や手に入るアイテムが天気によって変わる
- 集めたアイテムを図鑑で見られる
- 実績としてキャラクターとの思い出を残せる
この作品でやりたかったのは、天気APIの結果をそのまま情報として出すことではありません。
天気を、キャラクターとの体験に変換することです。
使った技術
主に使った技術は以下です。
Next.js
React
TypeScript
Tailwind CSS
Framer Motion
Vercel Postgres
Prisma
OpenWeatherMap API
Next.jsでUIとAPIまわりを作り、OpenWeatherMap APIで天気情報を取得しています。
アニメーションにはFramer Motionを使っています。
このプロジェクトでは、Framer Motionを派手な演出のためというより、天気やキャラクターの変化をやさしく見せるために使いました。
なぜmotionが必要だったのか
天気アプリなら、天気情報を表示するだけでも成立します。
天気: 雨
気温: 23℃
場所: 大阪
これだけでも情報としては十分です。
でも、『おてんきぐらし』でやりたかったのは、天気情報を確認させることだけではありません。
天気を見ること自体を、少しポジティブな体験にしたかったです。
雨の日は、普通に考えると少し面倒です。
傘がいる。
移動がしんどい。
気圧で体調が悪くなることもある。
でも、ゲームの中で雨が降っていたり、雨の日だけのアイテムが手に入ったりすると、少しだけ見え方が変わります。
「雨か、嫌だな」ではなく、
「雨だから、ゲーム内で何か起きるかも」
に変えられるかもしれません。
そのために、天気をただ文字として出すのではなく、motionで空気感として見せる必要がありました。
おてんきぐらしのmotionの方向性
今回のmotionで意識したのは、以下です。
- 派手にしすぎない
- 見ていて疲れない
- 天気の空気感を出す
- キャラクターが生きている感じを出す
- 操作したときに少しだけ気持ちよくする
reCAPTCHA風ゲームのような対戦ゲームでは、motionは相手を焦らせたり、場を荒らしたりするために使えます。
でも、おてんきぐらしでは逆です。
ユーザーを焦らせる必要はありません。
むしろ、ゆっくり見ていられることが大事です。
なので、motionの役割は「刺激」ではなく「安心感」に近いです。
天気ごとに空気を変える
天気の演出は、WeatherEffects というコンポーネントに分けています。
ここでは、天気の種類によって画面上のエフェクトを変えています。
雨や雷雨なら、しずくが上から下に落ちます。
雪なら、雪がふわふわ舞い落ちます。
晴れや快晴なら、光の玉や太陽の光のような演出を出します。
雨の日
雨の日は、画面全体に細いしずくを降らせています。
ただし、雨を強くしすぎると画面がうるさくなります。
なので、雨粒は細く、透明度も控えめにしています。
animate={{ y: '120vh', opacity: [0, 1, 0.8, 0] }}
transition={{
duration: drop.duration,
repeat: Infinity,
delay: drop.delay,
ease: 'linear'
}}
ここで大事なのは、雨がただの背景ではなく、現実の天気と連動していることです。
現実で雨が降っていると、ゲームの中にも雨が降る。
それだけで、現実とゲームの世界が少しつながったように感じられます。
雪の日はゆっくり見せる
雪の日は、雨よりもゆっくり動かしています。
雪は、雨のようにまっすぐ速く落ちるより、左右に少し揺れながら落ちた方がそれっぽく見えます。
animate={{
y: '110vh',
x: [0, Math.random() * 30 - 15, 0],
opacity: [0, 1, 0]
}}
雨と雪で同じ「落ちる」motionを使っても、速度や横揺れを変えるだけで印象がかなり変わります。
雨は少し現実的で、雪は少し幻想的です。
この違いをmotionで出せるのが面白かったです。
晴れの日は光を動かす
晴れの日は、画面に光の玉や太陽の光を出しています。
晴れを表現するとき、ただ背景を明るくするだけだと少し物足りません。
なので、画面全体にふわふわした光を置いて、ゆっくり動かすようにしました。
animate={{
y: [0, -50, 0],
x: [0, 30, 0],
opacity: [0.1, 0.5, 0.1],
scale: [orb.scale, orb.scale * 1.2, orb.scale]
}}
ここでは、ランダムな位置や速度を入れて、全部の光が同じ動きにならないようにしています。
もし光が全部同じタイミングで動くと、かなり作り物っぽく見えます。
少しずつズレている方が、空気が動いている感じが出ます。
キャラクターを生きているように見せる
おてんきぐらしでは、天気だけでなくキャラクターのmotionも大事です。
キャラクターは、ただ静止しているだけだとぬいぐるみやアイコンに見えます。
でも、少し上下に動いたり、ゆっくり傾いたりするだけで、生きている感じが出ます。
animate={{
y: ["-3%", "3%"],
rotate: [-2, 2, -2]
}}
transition={{
duration: 3,
repeat: Infinity,
repeatType: "mirror",
ease: "easeInOut"
}}
この動きはかなり小さいですが、作品の雰囲気には合っています。
激しく動かす必要はありません。
むしろ、ずっと画面にいるキャラクターだからこそ、見ていて疲れない動きにする必要があります。
moodで表情を変える
キャラクターには、いくつかのmoodがあります。
happy
neutral
sad
scared
sleepy
looking
moodによって口元や目の表現を変えています。
たとえば、眠っているときは眠そうな目になり、鼻提灯のような表現も入れています。
looking のときには蝶々が出てきて、目もその動きに合わせて少し動きます。
こういう小さなmotionは、機能として必須ではありません。
でも、キャラクターがただのUIではなく、そこにいる存在として感じられるようになります。
操作したときの小さな反応
キャラクターをタップしたときには、少し縮むようにしています。
whileTap={isStatic ? undefined : { scale: 0.9 }}
transition={{ type: "spring", stiffness: 400, damping: 15 }}
こういう小さな反応があると、画面を触ったときに気持ちよくなります。
おてんきぐらしのような作品では、派手な成功演出よりも、こうした小さな反応の積み重ねが大事だと思いました。
ユーザーに「操作できた」と伝える。
でも、主張しすぎない。
このくらいのmotionが、作品の空気感に合っていました。
天気表示も急に切り替えない
天気表示も、急にパッと切り替えるのではなく、AnimatePresenceで入れ替えています。
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 20 }}
transition={{ duration: 0.4 }}
天気が変わるときに、いきなり表示が変わると少し機械的に見えます。
でも、少しだけ上下に動かしながらフェードさせると、情報の変化がやわらかく見えます。
おてんきぐらしでは、こういう細かい部分でも、できるだけ急な変化を避けたいと思いました。
アイテム獲得を小さな成功体験にする
おさんぽでアイテムを手に入れたときには、モーダルを表示します。
ここでもFramer Motionを使って、背景をフェードインし、モーダル本体を少し拡大しながら表示しています。
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
transition={{ duration: 0.2 }}
この演出は派手ではありません。
でも、「アイテムをゲットした」という小さな成功体験を少しだけ気持ちよく見せるには十分です。
おてんきぐらしでは、レベルアップやランキングのような強い報酬ではなく、天気やおさんぽの中で小さな思い出が増えていくことを大事にしています。
だから、motionも強い達成感より、やわらかい嬉しさに寄せています。
安心感のために細かい動きを設計する
おてんきぐらしで入れている細かい動きや、動作の切り替え、てんちゃんの動きは、ただ画面をリッチに見せるためだけのものではありません。
全部、ユーザーに安心感を持ってもらうために実装しています。
天気が変わるときに急に切り替わらないこと。
雨や雪が画面の中で自然に動いていること。
晴れの日の光がゆっくり揺れていること。
てんちゃんが少しだけ上下に動いていること。
タップしたときに小さく反応すること。
アイテムを手に入れたときに、やわらかくモーダルが出てくること。
こういう一つ一つは、機能として見ると小さいです。
でも、作品全体で見ると「ここにいても大丈夫そう」と感じられる空気につながります。
おてんきぐらしでは、便利な天気アプリを作るというより、ユーザーが少し安心できる優しい世界を作りたいと思っていました。
だから、motionも強く目立たせるのではなく、世界の空気を壊さないように入れています。
motionを強くしすぎない
今回かなり意識したのは、motionを強くしすぎないことです。
Framer Motionを使うと、簡単に派手なアニメーションが作れます。
大きく跳ねる。
ぐるぐる回る。
一気に拡大する。
画面全体を動かす。
こういう演出も作れます。
でも、おてんきぐらしの目的は、ユーザーを驚かせることではありません。
天気を見ることを、少しやさしい体験に変えることです。
なので、motionも作品の目的に合わせて弱める必要がありました。
雨は静かに降る。
雪はゆっくり舞う。
光はふわふわ動く。
キャラクターは少しだけ揺れる。
モーダルは少しだけ出てくる。
このくらいの控えめなmotionの方が、この作品には合っていると感じました。
reCAPTCHA Gameとの違い
reCAPTCHA Gameでは、motionは相手を焦らせるために使いました。
画面を揺らしたり、回転させたり、ぼかしたり、玉ねぎを降らせたりしました。
一方で、おてんきぐらしでは、motionはユーザーを癒やすために使っています。
同じFramer Motionでも、目的が違うと使い方が全然変わります。
reCAPTCHA Game
-> 相手を焦らせるmotion
おてんきぐらし
-> ユーザーを癒やすmotion
この違いは、自分の中でもかなり面白かったです。
motionは「動かす技術」ではありますが、何のために動かすのかによって、設計が変わります。
おわりに
今回は、天気APIをただ表示せず、Framer Motionでやさしい体験に変えた話を書きました。
天気APIを使うだけなら、天気・気温・場所を表示すれば終わりです。
でも、それだけだとただの情報です。
おてんきぐらしでは、その情報をゲーム内の空気やキャラクターの反応に変えることで、天気を見る体験そのものを少し変えようとしました。
Framer Motionは、派手なアニメーションを作るためだけのものではありません。
雨を静かに降らせる。
雪をゆっくり舞わせる。
キャラクターを少しだけ揺らす。
アイテム獲得を少し嬉しく見せる。
そういう小さなmotionの積み重ねで、作品の空気感を作れると感じました。
同じmotionでも、使い方によって、相手を焦らせることもできるし、ユーザーを癒やすこともできます。
今回は、天気をただの情報ではなく、やさしい体験に変えるためのmotionを目指しました。