最近Framerというデザインプロトタイピングツールにハマっています。
プロトタイピングというのは、アプリやwebの開発をする前に、その試作品(プロトタイプ)を作って、ユーザーへのインタビューに使ったり、開発メンバーの間でどのようなものを作るのかの共通認識を合わせたりするためのものです。
世の中にはたくさんのプロトタイピングツールが出回っています。
Framerは、その中でもコード(JavaScript)をベースにプロトタイプを作るツールで、他のツールと比べて群を抜いて完成度の高いアプリやwebのモックを作ることができます。
GoogleやFacebook, Uberといった名だたる企業がこのツールをプロダクト開発に取り入れています。
残念なことに、私の周りのデザイナーの多くがFramerに興味を持ってはくれたものの、Framerの闇に飲み込まれていってしまいました。「プログラミング言語に慣れていないのでハードルが高すぎる」「値段が高い(月額$15ドル)」というセリフを残して、彼らは去っていってしまいました。
おっしゃる通りです。
Framerの良いところを挙げればキリがないのですが、そんなことは今回はバサッと割愛して、Framerの公式チュートリアルよりも、もっとずっとわかりやすく始めの導入を書いていきたいと思います。
※ このチュートリアルは、David Leeの許可を得てこちらの記事を参考にさせていただいて作成しています
始める前に
本題に入る前に、おそらく多くのデザイナーが触ったことのないであろう、CoffeeScriptの話をしたいと思います。すでに何かしらのプログラミング経験(JavascriptでもPHPでも、jqueryでも!)がある人は、この章は飛ばして大丈夫です。
FramerのCoffeeScriptはプログラム言語ではない
Framerでは、CoffeeScriptでプロトタイプを作っていくことになります。CoffeeScriptとは、JavaScriptの記法の一つで、従来のJavaScript言語と比べてシンプルな記述をすることができる言語です。私もFramerを触るまでCoffeeScriptに触れたことは一切ありませんでした(そして今もFramer以外の場面でCoffeeScriptを書くことはありません w)
我々デザイナーは開発者ではないので、Framerを使う上で覚える必要のあることはごくわずかです。ここで一気に覚えてしまいましょう。
Valiable -変数-
通常、プログラミングで数字や文字の値を代入するためには、変数名の宣言と、型の指定が必要です。しかしCoffeeScriptでは、型を指定する必要がありません。整数でも、小数でも、文字でも、配列*でも、オブジェクトでも、どのようなものも代入することが可能です。
positionX = 10 #整数型
scaleValue = 1.2 #小数型
backgroundColor = "#999999" #文字型
Dot -点-
Framerを使っていると、しばしばこの点(.)が登場します。この点と点でつなぎ合わされた要素は、すべて、一つの要素を指し示しています。ピカソの本名は「パブロ・ディエーゴ・ホセ・・・ルイス・イ・ピカソ」と、とても長かったりしますよね。これと一緒です。一つ注意する点があるとすれば、ここで指定する要素は、レイヤーだけでなく、レイヤーのプロパティ(色や透明度、x座標など)も含まれるということです。レイヤーの子レイヤー、そのレイヤーのx座標…というようにどんどん階層を下げて一つの要素を指定していきます。
sketch.circles.scale = 1.2 #circlesという名前のレイヤーの大きさ(scale)を指定している
sketch.circle3.opacity = 0.5 #circle3という名前のレイヤーの透明度(opacity)を指定している*Framerではレイヤーの構造はいちいち丁寧に親要素から書く必要はありません。(書くとエラーになります)Framerではレイヤー名は被らないようになっています。東京に住んでる人が自分の住所を書くときに、他とかぶる地名がないので、"東京都"を省略して"港区"から書き始めるのと一緒です。
Indentation -インデント-
インデントはプログラムの構造を指定するために使われます。通常のJavaScriptでは{}で囲うところをCoffeeScriptではtabキーでスペースを空けてプログラミング構造を視覚化します。
layer = new Layer
opacity: 1
rotation: 90*layerのプロパティ(opacity透明度とrotation角度)を一段空けて書くことでlayerのプロパティであることを定義している。
CoffeeScriptのお勉強で必要なのはこれだけです!
Framerを構成する3要素:Layer, Event, State
Framerを使ってインタラクションを作るのに必ず意識すべき要素が3つあります。それはLayer, Event, Stateの3つです。
Layer
FramerでLayerを作る方法は2つあります。
一つはFramerで直接つくる方法、もう一つはsketchから読み込む方法です。どちらの方法も一長一短ですが、最初のうちはsketchから読み込むようにして、徐々にFramer上でレイヤーを作るのに慣れていくと良いです。
まずはFramerの体験版をダウンロードして、アプリを起動させましょう!起動したら、Sketchファイルをインポートします。この時、インポートするsketchファイルをsketch上で開いておくのを忘れないでください。
すると左半分の黒い部分に下のようなコードが現れると思います。が、最初は深く考えなくて良いです。おまじないだと思ってください。
さあ!これで全てのsketchレイヤーにアクセスすることができるようになりました。もしあなたがこのsketchファイルをダウンロードしていたら、下のコードを黒画面に打ち込めば、”X(cancel)”ボタンが消えるはずです。
sketch.cancel.opacity = 0 #"cancel"はsketch上のxボタンのレイヤー名
今回は”opacity”というプロパティを使いましたが、他にもたくさんのプロパティを指定することができます。いろいろ試してみましょう。
sketch.cancel.scale = 2.0 #大きさが2倍になる
sketch.cancel.x = 100 #x座標が100の位置に移動する
これであなたはsketchのレイヤーをFramer上で操作できるようになったことになります。
Events
次に考えるべきなのは、ユーザーがどのようなアクションをしたらレイヤーの色や形を変えるか、です。これをEventと言います。
FramerではたくさんのEventを検出することができます。Click, Drag, Scroll, Swipe…などなどです。どのようなEventがあるかはこちらにまとまっています。
どのようにEventとLayerを紐付けるのか、まずは分かりやすく日本語で書いてみましょう
もしcancelレイヤーがclickイベントを取得したら
(clickした時に)cancelレイヤーを削除せよ
これをFramerにもわかるようにCoffeeScriptで書くと
sketch.cancel.onClick ->
sketch.cancel.opacity = 0
一行目ではcancelレイヤーをclickした時に(.onClick)何かしらのアクションを起こすよう指定しています。最後の”->”はEventを指定する時のおまじないだと思ってください。onClickも一まとまりのおまじないで、clickアクションを取得したい時に使います。
そしてインデントした二行目で、どういったアクションを起こすのかを記述しています。(この場合はopacity = 0)
さて、これでx(cancel)ボタンを消すことができましたが、消しっぱなしになってしまいましたね。ボタンを押してる間だけ消えて、ボタンを離すと再び現れるようにしてみましょう。
sketch.cancel.onTouchStart ->
sketch.cancel.opacity = 0sketch.cancel.onTouchEnd ->
sketch.cancel.opacity = 1
いかがでしょうか?
onTouchstartとonTouchEnd、2つのEventを複数設定することで、アクションが一方通行になることを防げたと思います。Framerには本当にたくさんのEventが揃っています。僕らが思いつく限り全てのEventをカバーしてくれてるのも、Framerの魅力の一つです。
もう一つ、便利TIPSをご紹介します。
自力でイベントを設定した時、そのイベントが本当に呼び出されているのか、不安になることがあると思います。そんな時にはprint文が便利です。
sketch.cancel.onClick ->
print "clickされたよ"
もし正しくEvent設定がされていれば、x(cancel)ボタンをクリックした時に画面の右下に””で囲んだ文が出力されるはずです。Framerでコードを書いてうまくいかない時は、このようにして動作の確認をします。
State
ここまでで、clickしたらlayerの性質を変化させる、ということができるようになりました。でも、突然消えたり色が変わったりするのはなんだか不自然です。じわっと消えるようにしてあげたいですね。Stateは最後の仕上げをしてくれます。
Stateは状態A(stateA)から状態B(stateB)への変化の仕方を詳細に設定できるもの、と考えてもらえれば分かりやすいと思います。cssアニメーションを触ったことのある人なら、「cssのstateアニメーション」と言えばピンとくると思います。
stateを設定するにはstateAとstateBの2つ(beforeとafter)を設定する必要があります。
仮に
- stateA = x(cancel)ボタンが出ている
- stateB = x(cancel)ボタンが消えている
だとして、stateAとstateBの設定をしていきましょう。
まずはstateAから…と、言いたいところですが、実はstateAはもう定義されています。sketchからレイヤーの設定を引っ張ってきた状態がstateAですから。stateBの設定は以下のようにします。
sketch.cancel.states.add
fadeout: # ←stateの名前を定義している
opacity: 0
scale: 0
“レイヤー名.states.add”でstateの設定を開始し、改行してstate名を定義(この場合は”fadeout”)再び改行・インデントしてstateBの性質を書いていくことになります。
これに対して、stateAはopacity=1 /scale = 1ということになります。
では、「x(cancel)ボタンをクリックした時にxボタンをstateBに変化させる」というプログラムを書いてみましょう
sketch.cancel.onClick ->
sketch.cancel.states.switch("fadeout")*switch("fadeout")の代わりに.next()と書くこともできます
直接opacityを変化させた時と比べて、しゅ〜ん…とボタンが消えていったのではないでしょうか?
でも、自分でも消え方を調整したいですよね?そんな時はstateB(=fadeout)の定義を下のように書き換えましょう!
sketch.cancel.states.add
fadeout:
opacity: 0
scale: 0
animationOptions: # animationの変化の仕方を定義している
curve:"spring"
調整前のものと比べると、消え方が若干変わったのではないでしょうか?
以上がFramerの3大要素です!Layer, Event, Stateこの3つを覚えれば、Framerで大体のことはできるようになります!
ではこの3つを踏まえて、実際のプロトタイプを作っていきましょう!
Example: Pokémon GO
いよいよpokemon GOのプロトタイプを作っていきます!
こちらが今回作るモックの最終系です。つまづいたらダウンロードしてみてください。
① Sketchファイルをインポート
sketchを最初にインポートするときは出現するレイヤーも含めて全てインポートするのが基本です。
なので最初にこのsketchファイルをインストールしたときはこのような画面になってるはずです。レイヤーの名前と位置をよく確認しましょう。
最初にどのような構成にしたら望みのアニメーションになるかを考えます。
① PokemonBallをクリックしたらbg, cancel, pokemon, shop, library, toolsが現れる(その際、pokemon, shop, library, toolsはcancelボタンの位置からそれぞれのポジションに移動する)
② cancelをクリックしたらbg, cancel, pokemon, shop, library, toolsが消える(その際、pokemon, shop, library, toolsはそれぞれのポジションからcancelボタンに向かって集まりながら消える)
とすれば、実際の画面と同じものが作れそうです。
② 邪魔なレイヤーを消す
最初はナビゲーションが表示されない状態にしたいので、邪魔なレイヤーは消します。下の6行を書き加えます。
sketch = Framer.Importer.load("imported/mockup@2x")# sketchファイルをインポートするコードの後ろに書かないとエラーが起きるsketch.tools.opacity = 0
sketch.library.opacity = 0
sketch.shop.opacity = 0
sketch.pokemon.opacity = 0
sketch.cancel.opacity = 0
sketch.bg.opacity = 0
MAP画面が表示されるはずです。
③ 各レイヤーにStateを設定する
消えたり移動したりするレイヤーについてはstateを設定していきます。ここでは、全レイヤー共通で、PokemonBallレイヤーを押した時に現れるstateをfadein、cancelボタンを押した時に消えるstateをfadeoutと定義することとします。
まずbgについては、opacityが1から0, 0から1になるので、
sketch.bg.states.add
fadein:
opacity: 1
fadeout:
opacity:0
animationOptions:
curve: "spring"
のように定義します。animationOptionはあってもなくても大丈夫です。
続いて、cancelについてはopacityだけでなくscaleも変化するので
sketch.cancel.states.add
fadein:
opacity: 1
scale:1
fadeout:
opacity:0
scale:0
animationOptions:
curve: "spring"
のように定義してやります。
最後にpokemon, shop, library, toolsですが、これはちょっと複雑です。x,yの座標を変化させなくてはいけないからです。
sketch.pokemon.states.add
fadein:
opacity: 1
x:sketch.pokemon.x
y:sketch.pokemon.y
fadeout:
opacity:0
x:Align.center
y:1166
animationOptions:
curve: "spring"
このように定義してあげるとスッキリいきます。
Framerのxy座標は親のレイヤーの影響を受けるので、注意が必要です。まず、fadeout時の座標から説明します。
fadeout:
opacity:0
x:Align.center
y:1166
xの座標を`Align.center`としていますがこれは親レイヤーの座標にかかわらず画面の中央にx座標を合わせる時に使うプロパティです。
続いて`y:1166`ですが、これはcancelのy座標と同じ値を取ってきています。
これで、pokemonはfadeout時にcancelに向かって移動することになります。
続いて、fadein時のコードです
fadein:
opacity: 1
x:sketch.pokemon.x
y:sketch.pokemon.y
fadein時は、初期のxy座標(sketchファイルのxy座標)に戻れば良いので、直接sketch上の座標を入れてあげてもいいのですが、
x:sketch.pokemon.x
y:sketch.pokemon.y
と指定してやれば、sketchファイルのxy座標を取ってきてくれるので、自動的に元の位置に戻ります。
pokemon以外のshop, library, toolsについても、同じコードで書くことができるので、レイヤー名の部分だけ書き換えてコピペしましょう。
④ Eventを指定する
最後に、
① PokemonBallをクリックしたらbg, cancel, pokemon, shop, library, toolsが現れる(その際、pokemon, shop, library, toolsはcancelボタンの位置からそれぞれのポジションに移動する)
② cancelをクリックしたらbg, cancel, pokemon, shop, library, toolsが消える(その際、pokemon, shop, library, toolsはそれぞれのポジションからcancelボタンに向かって集まりながら消える)
の条件文を組み込みます。これはもう説明不要ですね。
sketch.PokemonBall.onClick ->
sketch.bg.states.switch("fadein")
sketch.cancel.states.switch("fadein")
sketch.pokemon.states.switch("fadein")
sketch.shop.states.switch("fadein")
sketch.library.states.switch("fadein")
sketch.tools.states.switch("fadein")
sketch.cancel.onClick ->
sketch.bg.states.switch("fadeout")
sketch.cancel.states.switch("fadeout")
sketch.pokemon.states.switch("fadeout")
sketch.shop.states.switch("fadeout")
sketch.library.states.switch("fadeout")
sketch.tools.states.switch("fadeout")
最後に、完成したコードを貼り付けておきます。
# Import file "mockup" (sizes and positions are scaled 1:2)
sketch = Framer.Importer.load("imported/mockup@2x")sketch.tools.opacity = 0
sketch.library.opacity = 0
sketch.shop.opacity = 0
sketch.pokemon.opacity = 0
sketch.cancel.opacity = 0
sketch.bg.opacity = 0sketch.bg.states.add
fadein:
opacity: 1
fadeout:
opacity:0
animationOptions:
curve: "spring"
sketch.cancel.states.add
fadein:
opacity: 1
scale:1
fadeout:
opacity:0
scale:0
animationOptions:
curve: "spring"sketch.pokemon.states.add
fadein:
opacity: 1
x:sketch.pokemon.x
y:sketch.pokemon.y
fadeout:
opacity:0
x:Align.center
y:1166
animationOptions:
curve: "spring"
sketch.shop.states.add
fadein:
opacity: 1
x:sketch.shop.x
y:sketch.shop.y
fadeout:
opacity:0
x:Align.center
y:1166
animationOptions:
curve: "spring"sketch.library.states.add
fadein:
opacity: 1
x:sketch.library.x
y:sketch.library.y
fadeout:
opacity:0
x:Align.center
y:1166
animationOptions:
curve: "spring"sketch.tools.states.add
fadein:
opacity: 1
x:sketch.tools.x
y:sketch.tools.y
fadeout:
opacity:0
x:Align.center
y:1166
animationOptions:
curve: "spring"sketch.PokemonBall.onClick ->
sketch.bg.states.switch("fadein")
sketch.cancel.states.switch("fadein")
sketch.pokemon.states.switch("fadein")
sketch.shop.states.switch("fadein")
sketch.library.states.switch("fadein")
sketch.tools.states.switch("fadein")
sketch.cancel.onClick ->
sketch.bg.states.switch("fadeout")
sketch.cancel.states.switch("fadeout")
sketch.pokemon.states.switch("fadeout")
sketch.shop.states.switch("fadeout")
sketch.library.states.switch("fadeout")
sketch.tools.states.switch("fadeout")
もし物足りないと思ったら、アニメーションの微妙な調整をしてみたりしてください。結構奥が深いです。
最後に
ここまできたら、Framerでインタラクションを作るパターンが読めてきたと思います。
- Layerのプロパティをセットする
- Statesを定義する
- Eventsを定義する
この3セットが頭に入ってれば、どんなインタラクションも作ることができます!
これであなたもFramer使いです。
もしFramerに関する疑問・質問があったら
https://www.facebook.com/groups/framerjs/
こちらのFabcebookグループで質問してみることをお勧めします。
NEXT STEP
個人的に、中級編くらいまでいくと、Framer使った方が圧倒的に早い、という場面が多くなってきます。
初級編
細かいインタラクションが作れるのは嬉しいけど、Prottみたいな画面遷移ってどうやって作るの?って人に
スクロール要素を作りたい!という人に
Framerでスワイプでめくれるページ要素を作りたい!という人に
Moduleを使ってみたい!という人に
input入力欄を作りたい!という人に
中級編
今回のチュートリアルで、似たようなコードの繰り返しが多くてめんどくさいなーと思った人に
もっともっと無駄を省きたい!という人に
上級編
毎度毎度同じ画面を実装するの面倒だな〜と思った人に
Firebaseと連携させてよりリアルなデータ連携をしたいという人に
APIを引っ張ってきてよりリアルなプロトタイプを作りたい人に