はじめまして!

「アメーバピグ」のデザイナー、2012年度入社の鈴木彩夏と申します。
今回は自分が携わったピグの麻雀ゲーム(以下、ピグ麻雀)のデザインについてお話します。

ピグ


はじめに

ピグ麻雀は、本格的な麻雀を自分のピグを通してプレイすることができ、
大富豪やしろくろなどに続く「アメーバピグ」内の新ゲームとして2013年5月末に登場しました。

ピグ と 麻雀

まずはじめに、デザインを進めていくにあたり1番のポイントとなったのは
「ピグ」の世界観に合う「麻雀」とはどんなものなのか、
というところでした。

「ピグ」と「麻雀」、この2つのそれぞれイメージを上げるとすると

ピグ
・かわいい
・ポップ
・女性的

麻雀
・歴史がある
・ギャンブル
・男性的

などがあるかと思いますが、

ここからは、このかけ離れている2つのイメージをどうひとつのデザインに落とし込んでいったかについて詳しくご説明します。

麻雀牌のデザイン

麻雀牌の文字を例にとると、
まずピグのデフォルトフォントと一般的な麻雀牌の文字、
2つの間をつくる
という検証を行います。


ここで重要なのはただただ間をつくっていくのではなく
2つのそれぞれの「らしさ」とは何かを考え、抽出したものを組み合わせていくことです。




それぞれのフォントを見てみると

ピグのフォント
こちらは、ピグでふだん使用しているフォントで、

・線幅が均一なゴシック体でクセが少ない
・丸みがあってかわいらしい

一般的な麻雀のフォント
対して、一般的な麻雀牌の文字は、

・筆文字っぽい
・メリハリがあって力強い

などの「らしさ」があげられます。

そして、それらを踏まえて2つの間のどのあたりが最適なのかを導きだし、
できた文字がこちらです。

結果その1

本来の麻雀の文字に使われている特徴的なエレメントを用いて、
文字の線幅は均一なゴシック体の印象は保ちつつも
部分的に線を膨らませることで、筆文字に見られるような手描きのニュアンスをだしました。

最終的に、これをベースに角に丸みをもたせることでかわいらしさをだし、
ひとつひとつの文字のバランスを調整したのちに、ピグ麻雀の牌は完成しました。


最後に

こうしたいくつかの検証を経てピグ麻雀のデザインは作られました。


いかがでしたでしょうか。
最後までお読み頂きありがとうございます!

これからも「アメーバピグ」をよろしくお願いします^^


次回は同じくピグ麻雀を担当したディベロッパーが別の視点から制作過程などをお話しします。
ぜひ、お楽しみに~( ´∀`)
みなさんこんにちは!
先週に引き続きまして、スマホ版Ameba担当の川口です。

前回予告した通り、後編ではPhantomJSを使ったさらに実践的なテスト手法を解説していきます。

※前編に関しては以下のリンクを参照ください。
PhantomJSを使ったスマホサイトテストの自動化(前編)

内容に関しては、前回お伝えしたとおり

・認証を前提としたページのテスト方法
・Sinon.JSを利用したAjaxのレスポンスの改変


という構成になっています。

認証を前提としたページのテスト方法

みなさんは認証が必要なサイトのテストをブラウザで行う場合、いつもどのようにテストされているでしょうか?

・アカウントとパスワードを手入力してログイン後のページをチェック
・男性ユーザーと女性ユーザーで表示が変わるため、それぞれでログインし直して表示を確認
・ユーザーのカスタマイズによって自由に表示が変えられるページを、色々なパターンで作ったアカウントを用いて1つずつ確認
・さらには上記のようなパターンを新しいリリースが行われるたびに一から(ry


上げればキリがないのですが、昨今の複雑化したWebサイト、特にユーザー認証を挟んで利用するようなサービスではとにかくテストが大変です。
ですが、そのようなサイトでもPhantomJSを使えば上記のようなパターンを全て自動でテストすることができます。

※前回と同じくMacOSX上での動作を前提として進めていきます。

■使用するツール・ライブラリ
・Node.js (0.10.11 最新安定バージョン)
  言わずと知れたサーバサイドJavaScriptです。
  今回のテスト対象である認証が実装されたサンプルをNode.jsで作成しましたので、まずこれをインストールします。
  Node.js公式サイト

・Express (2.5.11)
  Node.js用のフレームワークです。
  Express公式サイト

・jade (0.31.2)
  Node.js用のテンプレートエンジンです。
  jade公式サイト

Node.jsのインストール
公式サイトにあるインストールパッケージを使ってインストールしてもOKですが、brewが使える場合は
$ brew install node

でもインストール可能です。
※brewからのインストールの場合、最新安定版であるv0.10.11ではなくv0.10.0でインストールされますがこちらでも問題ないです。

認証が実装されたサンプル
下記URLにアップしていますので、ダウンロードして作業ディレクトリに配置して下さい。
なお、今回用意したサンプルはCookieのみを使ったあくまで簡易的な認証システムですので、実際には使用しないで下さい。
https://github.com/feb0223/1pixelTestSample201306_02

Express, jadeのインストール
ダウンロードしたサンプルのpackage.jsonにインストール設定を記述していますので、
$ cd ./server_sample
$ npm update

と実行すればインストールされます。
※npmはNode.js用のパッケージ管理ツールです。Node.jsのインストール時に同時にインストールされます。

さて、これで準備が整いましたので、ここから実際にテストを実行していきます。

まず認証が実装されたサンプルのサーバーを立ちあげます。
$ cd ./server_sample
$ node server.js

この状態でブラウザからhttp://localhost:8080にアクセスするとログイン画面が表示されます。

このサンプルを操作するPhantomJSのコードは以下の通りです。

test_auth.js
(function() {
var webpage = require('webpage');
var mocha = require('./lib/mocha-phantom.js').create({reporter:'spec', timeout:1000*60*5});
require('./lib/expect.js');

mocha.setup('bdd');

// テストの定義
describe('認証テスト', function() {
// pageオブジェクトを作成
var page = webpage.create();
// 画面のサイズを設定
page.viewportSize = {width: 320, height: 480};

/**
* 指定したアカウントの認証Cookieデータを取得
* @param {String} account
* @param {String} password
* @param {Function} callback
*/
function getAuthCookieData(account, password, callback) {
// Cookieクリア
phantom.clearCookies();

// 指定したページをオープン
page.open('http://localhost:8080', function(status) {
if (status !== 'success') {
console.log('error!');
phantom.exit();
return;
}

// ログインボタン押下時にも再度openイベントが走ってしまうため、
// ここで終わらせる。
if (page.url.match('\/top$')) {
return;
}

page.evaluate(function(account, password) {
$('#account').val(account);
$('#password').val(password);
}, account, password);

// ログインボタンの位置を取得
var btnClickPosition = page.evaluate(function() {
var btnShowModal = $('#login_btn').get(0);
var rect = btnShowModal.getBoundingClientRect();

var sx = (btnShowModal.screen) ? 0 : document.body.scrollLeft;
var sy = (btnShowModal.screen) ? 0 : document.body.scrollTop;
var position = {
left: Math.floor(rect.left + sx),
top: Math.floor(rect.top + sy),
width: Math.floor(rect.width),
height: Math.floor(rect.height)
};

return {
left: Math.round(position.left + position.width / 2),
top: Math.round(position.top + position.height / 2)
};
});

// ボタンをクリックしてログインする
page.sendEvent('click', btnClickPosition.left, btnClickPosition.top);

// submit処理のため1秒待つ
setTimeout(function() {
callback(phantom.cookies);
}, 1000);
});
}

var authCookieData = {};

// テストの前処理の記述
before(function(done) {
// user1,user2の認証Cookieデータを取得
getAuthCookieData('user1', 'user1password', function(user1Cookie) {
authCookieData['user1'] = user1Cookie;
getAuthCookieData('user2', 'user2password', function(user2Cookie) {
authCookieData['user2'] = user2Cookie;
done();
});
});
});

describe('user1でログイン', function() {
before(function(done) {
// Cookieクリア
phantom.clearCookies();
// user1の認証Cookieデータをセット
var cookies = authCookieData.user1;
for (var i=0; i < cookies.length; i++) {
phantom.addCookie(cookies[i]);
}
page.open('http://localhost:8080', function(status) {
if (status !== 'success') {
console.log('error!');
phantom.exit();
return;
}
// 画面のキャプチャ
page.render('./capture/user1_auth.png');
done();
});
});

describe('表示チェック', function() {
it('ユーザー名', function() {
var welcomeText = page.evaluate(function() {
return $('#main h4').text();
});
expect(welcomeText).to.be('ようこそuser1さん!');
});
});
});

describe('user2でログイン', function(done) {
before(function(done) {
// Cookieクリア
phantom.clearCookies();
// user2の認証Cookieデータをセット
var cookies = authCookieData.user2;
for (var i=0; i < cookies.length; i++) {
phantom.addCookie(cookies[i]);
}
page.open('http://localhost:8080', function(status) {
if (status !== 'success') {
console.log('error!');
phantom.exit();
return;
}
// 画面のキャプチャ
page.render('./capture/user2_auth.png');
done();
});
});

describe('表示チェック', function() {
it('ユーザー名', function() {
var welcomeText = page.evaluate(function() {
return $('#main h4').text();
});
expect(welcomeText).to.be('ようこそuser2さん!');
});
});
});

after(function() {
// PhantomJSの終了
phantom.exit();
});
});

// テストの実行
var runner = mocha.run();
})();

実行の際は、先ほどNode.jsのサーバーを立ち上げたものとは別のコンソールを立ちあげ、
$ cd ./phantomjs
$ phantomjs test_auth.js

という風に実行すればOKです。

一応PhantomJSでのテストの流れを解説すると、

1.PhantomJS上でログインページからアカウントとパスワードを指定してログイン。
2.ログイン後にCookie情報を抜き出して保持。
3.1~2の流れを別ユーザーでも実行してユーザーごとにCookie情報を保持。
4.ログインしたいユーザーのCookieをpage.open前にPhantomJSにセットしてログイン状態を再現。
5.ページを開くと、Cookieに認証情報が入っているため認証後のページにアクセスできる。


以上のような流れになっています。

テストの結果はどうでしたでしょうか?
正しく実行できていればコンソールに以下のように表示されると共に、/phantomjs/captureディレクトリにキャプチャ画像が保存されていると思います。
認証テスト
user1でログイン
表示チェック
ユーザー名
user2でログイン
表示チェック
ユーザー名
2 tests complete (3 seconds)


Sinon.JSを利用したAjaxのレスポンスの改変

Ajaxを使ってフロントでデータを取得してJavaScriptでDomを描画。
Webサイトの表示を速くする効果もあるため、昨今のサイトでは必ずといっていいほど使われている技術です。
ですがフロントで完結する作業だけあり、

・データ数が多い場合は「もっとみる」ボタンを表示
・逆にデータ数が少ない場合はページのレイアウトを調整
・Ajaxでエラーが返った場合は専用のエラーメッセージを表示する


などなど・・・
先ほどの認証を前提としたページに負けないぐらいの細かい表示分けがあることと思います。

こんなケースでもPhantomJS、そしてSinon.JSを使えばAjaxのリクエストを好きに改変して色々なパターンでテストすることができます。

使用するツール・ライブラリ
・Node.js (0.10.11 最新安定バージョン)

・Sinon.JS (2.5.11)
  Sinon.JS
  JasmineやMochaなどのテストフレームワークと組み合わせて使う、テストに関する様々なユーティリティを含んだライブラリです。
  残念ながら私はそこまで詳しくはないのですが、特に便利なものではフロントのJSにおけるxhr処理の置き換えやtimer系関数の置き換えなど、普段はテストが難しい箇所でもSinon.JSを使えば細かいテストが可能になります。
  更に詳しい解説については@hokacchaさんのスライドを見てもらえれば分かりやすいと思います。
  http://hokaccha.github.io/slides/sinonjs/

テスト対象のサンプル
先ほどの "認証を前提としたページのテスト" で使用したサンプルをそのまま使います。
先ほどと同じように
$ cd ./server_sample
$ node server.js

でサーバーを立ちあげておいてください。
テスト対象のページはhttp://localhost:8080/modalです。
(前回のモーダルウィンドウの使い回しですすいませんすいません)

このサンプルを操作するPhantomJSのコードは以下の通りです。
test_sinonjs.js
(function() {
var webpage = require('webpage');
var mocha = require('./lib/mocha-phantom.js').create({reporter:'spec', timeout:1000*60*5});
require('./lib/expect.js');

mocha.setup('bdd');

// テストの定義
describe('モーダルウィンドウテスト', function() {
// pageオブジェクトを作成
var page = webpage.create();
// 画面のサイズを設定
page.viewportSize = {width: 320, height: 480};

// テストの前処理の記述
before(function(done) {
// 指定したページをオープン
page.open('http://localhost:8080/modal', function(status) {
if (status !== 'success') {
console.log('error!');
phantom.exit();
return;
}

// モーダル表示ボタンの位置を取得
var btnClickPosition = page.evaluate(function() {
var btnShowModal = $('#btn_show_modal').get(0);
var rect = btnShowModal.getBoundingClientRect();

var sx = (btnShowModal.screen) ? 0 : document.body.scrollLeft;
var sy = (btnShowModal.screen) ? 0 : document.body.scrollTop;
var position = {
left: Math.floor(rect.left + sx),
top: Math.floor(rect.top + sy),
width: Math.floor(rect.width),
height: Math.floor(rect.height)
};

return {
left: Math.round(position.left + position.width / 2),
top: Math.round(position.top + position.height / 2)
};
});

// Sinon.jsの読み込み
page.injectJs('./include/sinon-1.7.1.js');

// xhrを置き換えてダミーサーバーを作成
page.evaluate(function() {
var server = sinon.fakeServer.create();
var response = [200, {}, '{"title":"モーダルウィンドウテストSinon.JS", "description":"PhantomJS上でSinon.JSを使ってAjaxのレスポンスを改変しています。"}'];
server.respondWith('GET', '/json/detail.json', response);
server.autoRespond = true;
// レスポンスを返すまでの時間をmsで指定
server.autoRespondAfter = 100;
window.sinonServer = server;
return;
});

// ボタンをクリックしてモーダルウィンドウを表示
page.sendEvent('click', btnClickPosition.left, btnClickPosition.top);

// Ajaxリクエストが発生するため1秒待つ
setTimeout(function() {
// ページのキャプチャ
page.render('./capture/modal_capture.png');

// 非同期処理の終了
done();
}, 1000);

});
});

describe('表示チェック', function() {
it('ウィンドウ', function() {
var modalLength = page.evaluate(function() {
return $('#main .modal').length;
});
expect(modalLength).to.be(1);
});

it('タイトル', function() {
var titleText = page.evaluate(function() {
return $('#main .modal .title').text();
});
expect(titleText).to.be('モーダルウィンドウテストSinon.JS');
});

it('説明', function() {
var descriptionText = page.evaluate(function() {
return $('#main .modal .description').text();
});
expect(descriptionText).to.be('PhantomJS上でSinon.JSを使ってAjaxのレスポンスを改変しています。');
});
});

after(function() {
// xhrをもとに戻す
page.evaluate(function() {
window.sinonServer.restore();
});
// PhantomJSの終了
phantom.exit();
});
});

// テストの実行
var runner = mocha.run();
})();

実行の際も先ほどと同じようにNode.jsのサーバーを立ち上げたものとは別のコンソールを立ちあげ、
$ cd ./phantomjs
$ phantomjs test_sinonjs.js

という風に実行すればOKです。

テストの結果はどうでしたでしょうか?
正しく実行できていればコンソールに以下のように表示されると共に、captureディレクトリに画像が保存されていると思います。
モーダルウィンドウテスト
表示チェック
ウィンドウ
タイトル
説明
3 tests complete (2 seconds)

キャプチャした画像
$1 pixel|サイバーエージェント公式クリエイターズブログ

このテストサンプルでは、ページ表示後のボタンがクリックされる前のタイミングでxhrの置き換えをしてAjaxを改変しましたが、ページの表示と同時にAjaxを実行しているようなケースではこれではうまくいきません。
ですがそんなケースでも、page.onInitializedを使ってフロントのJSが読み込まれる前のタイミングでSinonJSの処理を実行してしまえばOKです。
// page.onInitializedを使った例
page.onInitialized = function() {
// Sinon.jsの読み込み
page.injectJs('./include/sinon-1.7.1.js');

// xhrを置き換えてダミーサーバーを作成
page.evaluate(function() {
var server = sinon.fakeServer.create();
var response = [200, {}, '{"title":"モーダルウィンドウテストSinon.JS", "description":"PhantomJS上でSinon.JSを使ってAjaxのレスポンスを改変しています。"}'];
server.respondWith('GET', '/json/detail.json', response);
server.autoRespond = true;
// レスポンスを返すまでの時間をmsで指定
server.autoRespondAfter = 100;
window.sinonServer = server;
return;
});
};


今回のソースを下記にアップしていますので、よければそちらもご覧ください。
https://github.com/feb0223/1pixelTestSample201306_02

終わりに

前編・後編と分けて解説したPhantomJSでのテストはどうでしたでしょうか?
テストフレームワークやNodeをある程度理解している前提で解説した部分も多かったため、分かりにくいところもあったかと思いますが、これを機にPhantomJSについて興味を持っていただければ幸いです。

そして!
そんな技術を使ったスマートフォン版Amebaもどうかよろしくお願いしますm(_ _)m
https://s.amebame.com
みなさんこんにちは!
スマホ版Ameba担当の川口です。

ちょうど一年前、同じようにJavaScriptを使ったテスト手法について記事を書かせていただいたのですが、今回も懲りずにまた同じようなテーマで再登場いたしました。

※前回の記事に関しては以下のリンクを参照ください。
JavaScriptのテスト手法

$1 pixel|サイバーエージェント公式クリエイターズブログ-PhantomJSを用いた自動キャプチャシステム

さて、スマホ版Amebaの全面リニューアルから早くも1年経ったのですが、今回はそんなスマホ版Amebaで日々自動テストツールとして活躍してもらっているPhantomJSを紹介させていただきます。

長い記事になるため、今回は前編・後編に分けて以下のような構成でお送りいたします。

●前編
・PhantomJSの概要と特徴、利点と欠点
・実際のサイトを想定したPhantomJSでのテスト方法

●後編(※多少変更になる可能性もあります。)
・認証を前提としたページのテスト方法
・Sinon.JSを利用したAjaxのレスポンスの改変

PhantomJSの概要と特徴、利点と欠点

PhantomJS公式ページ

■PhantomJSの概要
みなさんはPhantomJSと聞いたときどのようなものを想像したでしょうか?
JavaScriptの新しいライブラリ? CoffeeScriptのようにJSに変換される言語?
いえ、違います。
PhantomJSはJSのライブラリでもJSに変換される言語でも無く、コンソール上からwebkitブラウザを操作する仕組みです。
このように言われてもピンと来ないかもしれませんが、簡単に説明するとChromeやSafariなどと同種のブラウザの一つです。(Chromeは近々Blinkに変わるので今後挙動が違ってくるかもしれませんが・・・)
ただし、ChromeやSafariと違いブラウザを操作するための画面(GUI)が無いため、操作は全てJavaScriptで記述したスクリプトで行なっていくことになります。

■PhantomJSの特徴
PantomJSの特徴としてはまず、先ほど説明したように画面(GUI)が存在しないという特徴があります。
画面が存在しないのに、ページの表示をどう確認するのか?
もうお気づきかもしれませんが、PhantomJSでは任意の指定したページを開き、そして好きなタイミングでキャプチャを撮ることができます。
これだけでも日々のテストとしては十分役に立つのですが、PhantomJSでは更に

・ページ内での任意のJavaScriptコードの実行
・指定したボタンのイベントを動作(発火)させる
・Cookieの書き換え
・UserAgentの書き換え
・JavaScriptエラーの取得
・Ajaxや画像など様々なリクエストの監視


などなど、現在のWEBページ制作では欠かせない要素のテストが全てコンソール上でできてしまいます。

■PhantomJSの利点
PhantomJSの利点としてはやはり、実行環境を選ばずにかつスクリプトで動作を制御できる、という点が大きいです。
これによってWindowsやMacのみならず、CentOSやUbuntuなどのLinux系のOSでも動作させることができます。(※Linux系OSの場合日本語フォントのインストールが別途必要になります)
実際、PhantomJSを使って構築したスマホ版Amebaのキャプチャシステムも現在CentOS上で稼働しています。(記事上部の画像がキャプチャシステムです)

■PhantomJSの欠点
これまでPhantomJSの様々な特徴や利点を解説して来ましたが、やはりPhantomJSにも欠点があります。
不満に思う点はたくさんあるのですが(笑)、基本的な部分でいうと当たり前ですがwebkit系以外のブラウザでの挙動をエミュレートできないというのが最も大きいです。
スマホサイトのテストであればPhantomJSでOKですが、PCを対象としたサイトとなるとあの憎っくきIE・・・ではなく天下のIE様にも対応しなければいけませんので、ブラウザを直接操作してテストするSeleniumなどのツールを使うことになると思います。

その他実際に使っていて気になった部分だと、

・JSでDomを追加してイベントを設定した要素に対し、イベントの発火ができない
  →スマホ版AmebaのようにJSでDom構築をやっているサイトでは絶望的ですorz
・イベント発火時、対象となる要素を絶対位置で指定しなければならない
・開いたページでリダイレクトが頻繁に発生すると高い確率でPhantomJSが落ちる
・一つのページオブジェクトでページ遷移を何度も行うと高い確率でPhantomJSが落ちる
・Ajaxでデータを取得して描画するページの場合、wait処理を挟んで描画が終わるのを
 待たなければならない

  →スマホ版Amebaの画面キャプチャの際にはAjaxのリクエストを監視して全ての
   リクエストが終わったタイミングでキャプチャしています。

などがありました。

実際のサイトを想定したPhantomJSでのテスト方法(準備編)

今回のテストはMacOSX上の環境で動かす事を前提に解説しています。
申し訳ないのですが、WindowsやLinux系OSでの動作に関しては適宜そのOSに沿った形に置き換えてお読み下さい。

まず準備段階として、PhantomJSやテストのためのライブラリを用意していきます。

■使用するツール、ライブラリ
・PhantomJS (1.9)
・Mocha (1.10.0)
  テスト用のライブラリです。
  前回のJasmineと同じくビヘイビア駆動開発の概念に基づいて設計されたライブラリで、さらに詳しい解説は前回の記事を参照してください。
・expect.js (0.2.0)
  アサーション関数(テスト結果をチェックするための関数)が多数用意されたライブラリです。
  今回のテストはMochaとexpect.jsの組み合わせで記述していきます。

■PhantomJSのインストール
公式ページからダウンロードして所定の場所に配置してもらうか、Homebrewがインストールされていれば、
$ brew update && brew install phantomjs

このコマンドでインストールできます。

■Mochaのインストール
残念ながら現在Mochaの最新版はPhantomJS上での動作に対応していないため、最低限の動作に対応するように私が自前で修正したものを使っていきます。
下記ページよりダウンロードして作業ディレクトリに配置して下さい。
https://github.com/feb0223/mocha-phantom

■expect.jsのインストール
こちらは特に修正の必要なくPhantomJS上で動作します。
下記ページよりダウンロードして作業ディレクトリに配置して下さい。
https://github.com/LearnBoost/expect.js

さて、これで実行環境が整いましたのでここから実際のテストを始めていきます。

実際のサイトを想定したPhantomJSでのテスト方法(実行編)

■基本的なPhantomJSの操作
テストを実行していく前にPhantomJSの基本的な操作を解説していきます。

●require('webpage').create()
URL指定でページを表示するためのpageオブジェクトを作成します。

●page.open()
WEBページのURLを指定してページを表示します。

●page.evaluate()
page.openでページを表示した後にそのページ内で任意のJavaScriptを実行します。
今回は表示したページ内でjQueryを読み込んでいるので、evaluate内でもjQueryを使ってdomアクセスを行なっています。

●page.sendEvent()
domの位置を直接指定してClickイベントなどを発火させることができます。
イベントの発火はこのsendEventでのみ可能となっており、page.evaluateメソッドを使ってページ内でdispatchEventなどを実行してもイベントを発火させることはできません。

●page.render()
パスを指定してページのキャプチャを撮ります。
pdf,jpeg,pngに対応しており、パスの拡張子指定によって出力形式が変わります。

■テストの実行
今回のテストでは、前回と同じく(決して使い回しではないです!)

1.ボタンをクリック
2.モーダルウィンドウが表示され、そこに商品などに関する詳細情報が表示される

という流れをPhantomJSで操作しながらテストしていきます。

test.js
// node.jsと違いphantomjsでは実行ファイルを即時関数で囲まないと
// 全てグローバルスコープで定義されてしまうため、即時関数で囲む。
(function() {
var webpage = require('webpage');
var mocha = require('./lib/mocha-phantom.js').create({reporter:'spec', timeout:1000*60*5});
require('./lib/expect.js');

mocha.setup('bdd');

// テストの定義
describe('モーダルウィンドウテスト', function() {
// pageオブジェクトを作成
var page = webpage.create();
// 画面のサイズを設定
page.viewportSize = {width: 320, height: 480};

// テストの前処理の記述
before(function(done) {
// 指定したページをオープン
page.open('../sample/index.html', function(status) {
if (status !== 'success') {
console.log('error!');
phantom.exit();
return;
}
// モーダル表示ボタンの位置を取得
// page.evaluateメソッドを使ってページ内部でのJavaScript実行結果を取得できる
var btnClickPosition = page.evaluate(function() {
var btnShowModal = $('#btn_show_modal').get(0);
var rect = btnShowModal.getBoundingClientRect();

var sx = (btnShowModal.screen) ? 0 : document.body.scrollLeft;
var sy = (btnShowModal.screen) ? 0 : document.body.scrollTop;
var position = {
left: Math.floor(rect.left + sx),
top: Math.floor(rect.top + sy),
width: Math.floor(rect.width),
height: Math.floor(rect.height)
};

return {
left: Math.round(position.left + position.width / 2),
top: Math.round(position.top + position.height / 2)
};
});

// ボタンをクリックしてモーダルウィンドウを表示
page.sendEvent('click', btnClickPosition.left, btnClickPosition.top);

// Ajaxリクエストが発生するため1秒待つ
setTimeout(function() {
// ページのキャプチャ
page.render('./capture/modal_capture.png');

// 非同期処理の終了
done();
}, 1000);
});
});

describe('表示チェック', function() {
it('ウィンドウ', function() {
var modalLength = page.evaluate(function() {
return $('#main .modal').length;
});
expect(modalLength).to.be(1);
});

it('タイトル', function() {
var titleText = page.evaluate(function() {
return $('#main .modal .title').text();
});
expect(titleText).to.be('モーダルウィンドウテスト');
});

it('説明', function() {
var descriptionText = page.evaluate(function() {
return $('#main .modal .description').text();
});
expect(descriptionText).to.be('1pixel用のテストです。');
});
});

after(function() {
// PhantomJSの終了
phantom.exit();
});
});

// テストの実行
var runner = mocha.run();
})();

実行の際は
$ phantomjs test.js

という風にphantomjsコマンドに実行するファイルを指定して実行します。
テストが成功していればコンソールに以下のよう表示されるはずです。
モーダルウィンドウテスト
表示チェック
ウィンドウ
タイトル
説明
3 tests complete (185 ms)

PhantomJSで実際にキャプチャした画像です。
$1 pixel|サイバーエージェント公式クリエイターズブログ

今回のテストソースを下記ページにアップしていますので、よければそちらもご覧ください。
https://github.com/feb0223/1pixelTestSample201306_01

終わりに

さて、PhantomJSを使ったテストはどうでしたでしょうか?
前回の記事ではあくまでフロント側でクリック動作などを再現するものでしたが、今回は実際のブラウザとほぼ同じ環境でのテストだったためより精度の高いテストができたと思います。
次回の後編ではさらに踏み込んだテストを行なっていきますので、期待してお待ちください。

はじめまして、ゴラクログのデザインを担当をしている鬼石広海と申します。

弊サービスは現在大幅リニューアル中ですので、UI周りはリニューアル後、又機会があればご紹介させて下さい。


今回は、駆け出しのデザイナーさん達の多くが課題にあげる、デザイン作業のスピードアップについてお話します。結論から言いますと、細部から作らずに土台作りを頑張ることが、結果的にスピードにつながるというお話です。


かなり基礎的なお話になります。

では実際にバナーデザインを例に紹介します。


1.構成要素を全部置く

まずはプランナーやプロデューサーと話し合って決めた構成要素を、とりあえず全部キャンバスに置いてみます。(今回は構成ありきですが、時間があればプランナーと相談しつつ、デザイナーが構成を作るのがベストです。)


必須要素を全部置かずにデザインし始めると、
後で追加するのはとても大変な作業なので、一旦全部置きます。ありがちなのは、プランナーが作ってくれた構成のレイアウトをそのまま利用して、構成に色をつけただけのいわゆるパワポデザインになってしまうこと。構成の完成度が高いほど、そのまま作らなければならないような気になってしまうので、構成はあくまで構成要素と割りきって、プランナーのセンスは無視してとりあえず要素を置きます。


2.ストーリーを考えて優先順位を決める

レイアウトする前に、ユーザーに期待するストーリーをなんとなく考えます。今回はバナー広告なので、店員(バナー)が通りすがりの人(ユーザー)を客引きするやり取りを想像してみます。


こんなやり取りを想像すると、優先順位が見えてきます。①インパクトの強い言葉で気を引かせ、②結論を先に言って興味を持ってもらい、③オトクな追加情報で落とす。と言う感じ。ここの優先度は、プランナーとも握っておくと良いと思います。


3.単色でレイアウトする

さて、優先順位が決まったら、実際に優先順に目立つようにレイアウトしていきます。ここを妥協して、色に頼って優先順位をつけ始めると、色とレイアウトの両方で優先順位を付けなければならず、色を変えてはレイアウトを変えたりと、行ったり来たりして時間がかかります。無駄に色数が増える原因にもなります。

あとは、いきなり細部から作り始めると、後で破綻します。例えばレイアウトを決める前に、鼻息荒くカッコイイボタンを作ってしまうと、

「超カッコイイボタンが出来た!!!
このボタンに合ったレイアウトにしなきゃ!!」


というよく分からない使命感に駆られ、「ボタンに合ったレイアウトをする」という方向に走ってしまいます。結果的にページ内の優先順位はあやふやになり俯瞰してみると何を伝えたいのかよくわからないデザインになります。結果先輩に駄目出しをくらい、イチからやり直しで時間がかかります。


これらは、バナーはもちろん、UIデザインなど、どんなデザインをする上でも同じ事が言えると思います。シンプルで美しいデザインは、レイアウトや、マージンのバランスで優先順位が付いているので、沢山の色を必要としません。

ですから極力単色、もしくは2色で根気強くベースデザインをすることをおすすめします。
要は下書きのようなものです。

この作業を、
作っては壊しを繰り返し行います。作ってみなければわからなかったりするので、とにかく手を動かして、最良のレイアウトを模索します。ここの作業が早くなれば一気に時間が短縮されると思います。


こんな感じになりました。
全体的に主張が強くなりましたが、「急げ!」や「今すぐ応募」が目立ち、何となく優先順位通りになりました。

4.色付けする

ベースが出来れば、あとは色をつけて、優先順位をより際立たせます。ここまでできていれば、あとはフォントを変えても、あしらいや色を変えても、優先順位は崩れません。


こんな感じにも。


こんな感じにもできます。

実際に上の2点は出稿済みのもので、
1点目は、あまりCVRが良くありませんでした。そこで、1点目のバナーは、掲載ページと色が馴染んでいて目立たなかったのでは?という仮説を立て、思いっきりトーンを変えて、2点目の黒ベースに変えたところ、CVRが約2倍上がりました。


このようなトーンを一気に変える作業も、ベースが固まっていれば瞬時に行うことができます。作業工数が短縮できて、汎用的にも作れます。

駆け出しデザイナーの皆様、是非お試し下さい。


はじめまして、人事本部 デザインコース採用担当の板敷です。
本日は、「Creative Summer Internship 2015」のご紹介をさせていただきたく
記事を書かせていただきました。

今年もサイバーエージェントでは、クリエイター向けインターンシップとして
「Creative Summer Internship 2015」を実施いたします。
サイバーエージェントのインターンシップでは、2週間という短期間にて
実際にスマホアプリの制作に挑戦いただく「実践型インターンシップ」です。

Creative JAM

今回はインターンシップも「Creative JAM」という新たなタイトルになり、
企画、デザイン、UI設計、マークアップ(HTML5、CSS3、JavaScript等)、
ディレクション、全て自分たちで考え、当社社員とともに挑戦していただきます。

現場で活躍している当社社員や内定者など、技術メンターとして
みなさんに惜しみないアドバイスをいたしますので、
実際にユーザーに使ってもらうサービスとしてリリースできる
クオリティまで目指していただきます。

詳細について、ご案内いたします。

日程
【第1日程】8月6日(火)~8月19日(月)
【第2日程】8月21日(水)~9月3日(火)
定員
各日程 30名

※ご応募は原則、1日程のみとなります
※個人での参加、チームでの参加も可能です。
参加者特典
・参加者全員、制作したアウトプットを自身のポートフォリオ(作品)に掲載可
・社員との懇親会、その他各種イベント参加権、本選考特別枠等
・MVP賞に選ばれた方には豪華商品の他、特典としてクリエイティブアカデミー参加権を授与します。
応募締め切り
7月5日(金)必着
応募に関する詳細はコチラから
http://www.cyberagent.co.jp/recruit/special/internship/

※昨年のインターンシップはどんな雰囲気だったか、
 ぜひこちらの記事を見ていただけますと嬉しいです。
http://ameblo.jp/ca-1pixel/entry-11357935427.html

最高の仲間とともに”創る”夏

この夏、インターンシップに参加したい。
何か新しいことにチャレンジしてみたい。
モノ創りを仲間と一緒に創ってみたい。
0→1から生み出す楽しさを知ってみたい。
企業を知ってみたい。などなど

サイバーエージェントのインターンシップが、
みなさんのきっかけになればと思っています。

最高の仲間とともに”創る”夏

みなさんもぜひ経験してみませんか?
今年の夏、みなさんとお会いできることを楽しみにしております!

http://www.cyberagent.co.jp/recruit/special/internship/

こんにちは、アメーバ事業本部コミュニティ部門の加藤(@ktknest)です。
フロントエンドディベロッパーとして、GIRL'S TALKの開発・運用を担当しています。



GIRL'S TALKは女性だけの完全匿名掲示板サービスで、テキストを主とした構成になっています。それ故、グラフィカルな要素が少ないこともあり、運営側からのお知らせの表示に賑やかしの効果も持たせて、電光掲示板風のティッカーを採用しています。

そこで今回は、陰ながら活躍してくれている、このティッカーを表現するにあたっての、注意点や実装方法をご紹介したいと思います。

実装方法の検討

まず、幾つかの方法から、オススメできない方法に触れておきます。

<marquee>タグを使う

その昔、Internet Explorerが独自実装したタグで、古いWebやガラケー等で使われていましたが、W3Cでも非推奨とされており使うべきではありません。ちなみに動作もカクカクです。。

JavaScript(jQuery)を使う

Webで検索してみると、jQueryのプラグインとしてシンプルなものから凝った演出のものまで数多く公開されています。
PCサイトで使う分には問題ないのですが、非力なスマホでは重く、実利用には厳しいことが多々です。(これはjQueryでのanimationの実装方法によるものなので、全てのケースがNGとは言えません)

ですので、残るはCSS3の活用です。

【方法1】CSS3 marquee を使う

CSS3ではCSS Marquee Level 3にて、<marquee>タグと似た要素が考えられています。
下記のようなコードで利用することができ、現在ChromeやSafariで先行実装されています。

■ CSS
.ticker {
  background-color: #333;
  color: #fcac1a;
  white-space: nowrap;
  overflow: hidden;

  overflow-x:-webkit-marquee;
  -webkit-marquee-direction: backwards;
  -webkit-marquee-style: scroll;
  -webkit-marquee-speed: 10;
  -webkit-marquee-increment: 1px;
  -webkit-marquee-repetition: infinite;

  overflow-x: marquee-line;
  marquee-direction: forward;
  marquee-style: scroll;
  marquee-speed: fast;
  marquee-play-count: infinite;
}

■ HTML
<div class="ticker">
    <p>Ticker test / use "overflow-x: marquee-line"</p>
</div>

サンプル:http://jsfiddle.net/ktknest/LrvsQ/

ただ、現時点では正式勧告されておらず、将来的にはなくなる可能性があります。
さらにこちらのドキュメントによれば、どうやら廃止の流れにあるようで、使用は避けておいた方がいいでしょう。

【方法2】CSS3アニメーション を使う

最後に挙げられるのが、CSS3アニメーションによる実装です。
先ほどの方法よりも、やや冗長にはなりますが、パフォーマンスや現状を考慮するとこれがベストだと思います。
こちらは下記のようなコードで実装できますので、ご覧ください。

■ CSS
.ticker {
  background-color: #333;
  color: #fcac1a;
  overflow: hidden;
}

.ticker p {
  display: inline-block;
  white-space: nowrap;
  padding-left: 100%;
  -webkit-animation-name: ticker-animation;
  -webkit-animation-timing-function: linear;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-duration: 10s;
}

@-webkit-keyframes ticker-animation {
  from { -webkit-transform: translate(0%);}
  99%,to { -webkit-transform: translate(-100%);}
}
/* webkitのみで省略 */

■ HTML
<div class="ticker">
    <p>Ticker test / use "keyframes + transform"</p>
</div>

サンプル:http://jsfiddle.net/ktknest/sa9K9/

詳しい説明は割愛しますが、display, white-space, padding-left の指定で領域の幅や開始位置などを調整し、translate(0%)→translate(-100%)をkeyframesでループさせてます。
流れる速度は文字数によって変わってしまうため、文字数に応じてanimation-durationを調節すればOKです。

さらにスムーズに動かすためには?

CSS3アニメーションは処理が重いため、古い端末ではスムーズには動かせないケースが出てしまいます。その場合、一部端末では3D処理用のGPUアクセラレーションを効かせることで改善する方法があります。

可能な場合は、
 -webkit-transform-style: preserve-3d;
または、
 -webkit-backface-visibility: hidden;

等を追加することで、3D処理をするよ という指定がされて、GPUアクセラレーションが有効になります。
しかし、他の要素に思わぬ影響を与えるなどバグの宝庫でもあるので、使用にはご注意を。



以上、いかがでしたでしょうか。
なかなか使う機会は少ないと思いますが、参考になれば何よりです。

最後まで読んでいただき、ありがとうございました。

はじめまして。「あそんで♪HuggPet」というソーシャルゲームのフロントエンドの開発を担当しています、2012年入社のホシナと申します。

「あそんで♪HuggPet」(以下HuggPet)では、開発にFreeMarkerというテンプレートエンジンを使用しています。今回は、FreeMarkerを使った開発を、フロントサイドの視点から少しばかりご紹介したいと思います。

FreeMarkerとは

FreeMarkerはJavaベースのテンプレートエンジンです。
FreeMarker Template Languageという言語で書かれたテンプレートファイルとJavaオブジェクトから、動的にHTMLのソースコードを生成することができます。


今回ご紹介するのは、テンプレートファイル(以下FTLファイル)側の基本的な書き方です。「そもそもFreeMarkerってなに?」「どう書けば良いの?」というフロントディベロッパーさんにお読みいただけると良いかもしれません。

FreeMarkerの全体的な機能についての詳細は、ここでは省略させていただきます。
ご興味のある方は、こちらをご参照ください。

FTLファイルの基本

先程も述べた通り、FTLファイルでは動的にHTMLのソースコードを生成できます。
まずはサーバサイドから受け取った変数をブラウザに出力してみましょう。下記のようなFTLファイルを用意します。

test.ftl
<!DOCTYPE html>
<html lang="ja">
<head>
	<title>テスト</title>
</head>
<body>
	<#-- テスト -->
	<p>テスト:${hoge}</p>
</body>
</html>

普通のhtmlファイルのソースコードと違うのは、
<#-- テスト -->
<p>テスト:${hoge}</p>
この辺りの記述ですね。

ここで、サーバサイドで、変数"hoge"に"fuga"という文字列を設定したとします。
すると、test.ftlのブラウザでの実行結果は
テスト:fuga
となります。"${hoge}"の部分に変数の値が出力されます。

FTLファイルでは、"${(変数名)}"という記述で変数にアクセスできます。変数には、文字列・数値・ブール値・配列・ハッシュ・Date型の値などを入れることができます。

変数の値をHTMLに直接出力する際は、エスケープ処理を忘れないようにしなければなりません。FTLにはエスケープ処理をしてくれるビルトインが用意されていて、
${hoge?html}
このように記述すればOKです。

また、コメント文は下のように書きます。
<#-- ここにコメントを書く -->

このように、サーバサイドから値を受け取ってソースコードを動的に生成していくのがFTLファイルの基本的な動きとなります。

それでは、HuggPetのソースコードを見ながら、現場での使用例をご紹介していきます。

"${(変数名)}"の使用例


画像の赤枠の部分は、ユーザーのピグ画像・ペット画像・体力ゲージを表示するモジュールです。この部分のFTLファイルのソースコードは、以下のようになっています。
<#-- ピグ画像・ペット画像 -->
<span id="pigg"><img src="${piggImageUrl!'default'?html}"></span>
<span id="piggPet"><img src="${synthesizeImage!'default'?html}"></span>

<#-- 体力ゲージ -->
<div id="piggStamina">
	<p class="time">あと${timeOfMaxStamina!?html}で全回復!</p>
	<dl class="gauge">
	    <dt style="width: ${(currentStamina / maxStamina * 100)?floor}%"></dt>
	    <dd>${currentStamina!?html}/${maxStamina!?html}</dd>
	</dl>
</div>

imgタグにおける使用

最初のピグ画像・ペット画像の部分を見てみます。
<span id="pigg"><img src="${piggImageUrl!'default'?html}"></span>
<span id="piggPet"><img src="${synthesizeImage!'default'?html}"></span>
画像のsrc属性の値を変数で受け取って、各ユーザーに対応する画像を表示しています。
src="${piggImageUrl!'default'?html}"
先程登場したビルトイン"?html"に加えて、"!'default'"という記述があります。この部分ではデフォルト値を設定しています。(省略可能です)
こう書いておくと、万一piggImageUrlの値を正常に受け取れなかった場合、src="default"となります。一部のAndroid端末ではsrc属性が空のimgタグが存在すると画面が正常に動作しないため、デフォルト値の設定が有効です。

数値計算

体力ゲージは、オレンジ色のゲージ部分のwidthを下記のように指定しています。
style="width: ${(currentStamina / maxStamina * 100)?floor}%"
体力ゲージのmax値(maxStamina)と現在の体力値(currentStamina)を受け取って割合を計算し、数値用のビルトイン"?floor"で数値を切り下げてから、オレンジ色の部分の幅を指定しています。


もう1ヶ所、使用例を見てみます。


こちらは「ひろば」(HuggPet内のサークル機能)のメンバー一覧を表示するモジュールです。
ひろばに所属しているユーザーの情報を、所属している人数分、表示しています。

この一覧部分のソースコードは、以下のようになっています。
※装飾のためのclassやidを省くなど、実際のソースコードより簡易化してあります。
<ul class="members">
<#list memberListPager.list as member>
  <li>
    <section>
      <#-- ユーザー画像・ピグ画像 -->
      <div>
        <img src="${member.userImg!'default'?html}">
        <img src="${member.petImg!'default'?html}">
      </div>

      <#-- ユーザー情報 -->
      <div>
      <p>${member.userName!?html}</p>
      <#if member.titleName??>
        <p>称号:${member.titleName!?html}</p>
      <#else>
          <p>称号はありません</p>
      </#if>
      <p>わざの数:
        ${member.normalSkillLearnedCount!?html}/
      ${member.normalSkillTotalCount!?html}</p>
      <#if member.eventSkillLearnedCount != 0>
        <p class="specialSkillCnt">${member.eventSkillLearnedCount!?html}</p>
      </#if>
      </div>
    </section>
  </li>
</#list>
</ul>

制御文の使用

FTLファイルでは、if文やswitch文などの制御文が使えます。例の中では、変数の存在を確かめるためにif文を使っています。
<#if member.titleName??>
	<p>称号:${member.titleName!?html}</p>
<#else>
	<p>称号はありません</p>
</#if>
この<#if hoge??>という書き方は、よく使用します。
変数の後に"??"をつけると、「変数が存在すればtrue」となります。変数が定義されていれば、空の場合でもtrueを返します。この例では、"member.titleName"が存在すれば値が表示され、"member.titleName"が存在しなければ「称号はありません」と表示されます。

因みにこのソースコードには登場しませんが、同じくよく使う記述に
<#if hoge?has_content>
というものがあります。こちらも変数が存在する場合にtrueを返しますが、"??"と異なるのは、変数が空のときはfalseを返すことです。

ループ処理

次に、ユーザー情報をリスト表示している大枠の部分です。
javascriptなどならfor文で実装するところですが、FTLでは
<ul class="members">
	<#list memberListPager.list as member>
		<li>~省略~</li>
	</#list>
</ul>
<#list>を使うことで、受け取ったlistの要素数だけ、ループ処理をします。所属しているユーザーの情報を埋め込んだli要素を、ユーザーの数="memberListPager.list"の要素数分出力してくれるわけです。
listの中の値には、<#list>内のas以降に指定した変数名を使ってアクセスできます。この例の中では、member.○○○という書き方をしています。

その他よく使用する記述

その他、HuggPetのFTLファイル内でよく登場する記述をご紹介しておきます。

<#assign>
変数を定義します。
<#assign hoge = "fuga">
<p>テスト:${hoge?html}</p>
(出力結果) テスト:fuga
といった具合です。

<#compress></#compress>
ホワイトスペースを削除します。ftlソースの一番外側をこれで囲む、というような使い方をしています。

<#include>
ファイルを読み込みます。例えば、共通ヘッダーをheader.ftlというファイル名で作成した場合、各ページでヘッダーを表示したい位置に
<#include "header.ftl">
と記述すればOKです。モジュールごとにファイルを分けて管理することができます。

まとめ

今回ご紹介したのは、ほんの一部分の基礎的な機能です。
突っ込んだ使い方については、こちらをご確認いただければと思います。
FreeMarker Manual

FreeMarkerは日本語のドキュメントが少ないので、本記事が少しでも参考になれば幸いです。

ここまでお読みいただきありがとうございました。
最後になりますが、「あそんで♪HuggPet」もぜひよろしくお願い致します。スマホで可愛いペットたちと触れ合ってみてください!


初めまして。社長室でUI/UXディレクターをしている渡辺(@mw19830720)と申します。現在は主にUI/UX視点でのAmebaスマホののクオリティ管理を担当しています。


direction


普段ディレクターが本ブログで執筆することはあまりないと思いますので、今回はいつもと少し雰囲気を変えて、「サービス立ち上げ時におけるUI設計やディレクションの質を高めるポイント」というテーマで、あえて盲点になっているかもしれないと感じている点をまとめてみました。




まずは画面設計のフェーズにおいて2点ほど。


仕様書全体を都度見返す


画面仕様書の作成には数日~長くて数週間程度かかると思いますが、その間できるだけ毎日、その日までに作成した仕様書全体を見返す癖をつけた方が良いと思います。


基本的に時間をかけるに従って思考がブラッシュアップされていくので、過去策定した分の仕様に関して、その時の考えと整合性が取れていない部分が見つかったり、より良いUI設計のイメージが湧くことも多いです。(疲れていた時に悩んで考えた仕様などは、別の日に冷静に見てみると「なぜこんな仕様にしたんだ。。」と思うことも。笑)


ただし、回り回って元の案の方がシンプルで良かったかも?と思い直すケースもあるので、途中で大きく仕様を方向転換する場合は、必ず資料のバックアップを取っておくようにしましょう。(ちなみに、SubversionやDropboxにはバージョン管理機能がついており、上書き更新していても過去の状態に戻れるので便利です)


行動フローとセットでユーザー心理をイメージする


上述の画面仕様書を見直す際のポイントなのですが、ある程度設計が進んだら各画面を繋ぎ合わせて、ユーザーはどういう気持ちでこの画面にやってくるかを想像することがとても重要だと思います。画面単体ではなく、そこに至る流れを意識することがポイントです。それに沿う形でコンテンツやアクションの優先順位を決め、UIに反映させていきます。


各画面への到達経路は複数あり、それぞれでユーザー心理が異なるケースもありますが、その場合は最もメジャーな経路を想定し、それに合わせたUIにするのがベストだと思います。




以下からは、デザイナーがジョインするディレクションフェーズにおけるポイントです。


ベースが固まるまでは妥協しない


普通はまずトップ画面などでベースとなるトンマナやUIを模索していく流れになると思いますが、経験上ここで妥協すると良いことがありません。初期段階の検討不足により後々ベースデザインを変更することになれば、プロジェクトが進んでしまっているほど修正範囲が大きくなってしまいます。


しかし、個人的にそれ以上に強く訴えたいのは、メンバーの「心を晴らす」ことの重要性です。プロデューサー(ディレクター)やデザイナーがモヤモヤした気持ちを残したままプロジェクトを進めてしまった場合、モノ作りのベクトルがズレたままの状態が続くため、間違いなくどこかでその歪みが出てきます。また、曇った気持ちを抱えたメンバーにはプロジェクトへの前のめりな関与は期待できなくなります。


このような状況を防ぐために、特にサービスの軸を決める初期段階においては、メンバーが納得できるまで粘り強く試行錯誤や議論を続けるべきだと思います。皆が納得し、すっきりした心理状態でベース部分のコンセンサスが取れれば、その後は良い雰囲気で一気にプロジェクトが進んでいきます。ちなみに、仮に致命的なまでに意見が割れてしまった場合、先々のことを考えれば初期段階でメンバーチェンジをするというのも各者にとってポジティブな決断だと思っています。


イメージしている例を提示する


デザイナーとトンマナを決めていくフローでは、イメージしている色味や質感を細かく言語化して伝えるのはかなり困難です。基本的には、他サービスの例をたくさん持ち出してイメージを伝えたり、それを材料に議論していくことをおすすめします。


自分の場合は、色味はこのサイトのこのバーの感じ、質感はこのサイトのこのボタンの感じなど、参考にできそうな要素を色々なサービスから細かく切り出して伝えています。バランスを取るのは難しくなりますが、切り出す単位が細かくなるほど、最終的なアウトプットはオリジナルなものに近付いていく傾向があると思います。


リアルなコンテンツを入れて確認する


デザインを作ったり実機テストをする際には、できるだけ本番リリース後に想定されるリアルなコンテンツを入れて確認した方が良いです。よく「あああああ」など適当な文字列や、まず投稿されないような画像を当て込んでいるケースを目にしますが、これだと雰囲気を掴めずに適切な評価ができなくなってしまうことがあります。


面倒臭いかもしれませんが、この辺りをきちんと対応しておくことでデザインを確認したりテストをしている時のテンションが上がったりする効果もあるので、意外に大事なことだと思っています。


全ての画面をデザイナーがデザインする


例えば、真っ白な背景に文字だけを配置する画面などはデザインパーツを全く作成する必要がないので、まれにデザイナーを介さず直接コーディング依頼をしてしまうケースが見受けられます。


しかし、こういった画面も文字サイズやマージンを調整してきちんとデザインしないと、目に見えてUIのクオリティにバラつきが出てしまいます。完全に同じレイアウトでコンテンツを入れ替えるだけのようなケースを除いては、基本的に全画面デザイナーを通すことが望ましいです。ただし、完全に管理者任せにするだけではダメで、こういったことはデザイナーが自身の責任範囲と捉え、積極的に介入していく姿勢も必要だと思います。


俯瞰して「伝わるUI」になっているかを確認する


各画面の最終チェック時には、ただキレイなUIだからと言って満足するのではなく、画面全体を俯瞰し、然るべきコンテンツに目線が向かうようにメリハリをつけられているか、これで本当にサービスのコンセプトが伝わるかという視点でレビューをすることが大切だと思います。


一旦コンセプトが決まればディティールを詰める作業に入るのですが、それをまた最後に俯瞰して見る。この詰める→俯瞰→詰める→俯瞰…の繰り返しがUIのクオリティを向上させるループだと思っています。




以上、頭に浮かんだことを思いつくままに羅列したので、うまく整理されておらず、また抜け漏れも多いかもしれませんが、読んでいただいた皆さんに少しでも新たなインプットがあれば嬉しく思います。


※個人ブログでもWeb戦略/サービス設計/UI・UXなどに関する記事を展開しておりますので、もしよろしければご覧ください。


個人ブログ:Innovation from Popular Sense
Twitter:@mw19830720


こんにちは!
ぼくらのブレイブガーディアン」の開発を担当しております本間と申します。

ぼくらのブレイブガーディアン」(以下ブレガー)は、
スマートフォン向けAmebaで提供中のソーシャルゲームです。

ぼくらのブレイブガーディアン


今回はブレガーの開発効率を高めるために使用した、
7つのJavaScriptライブラリおよびフレームワークをご紹介できればと思います。

それでは、早速どうぞ!

1.Zepto

zepto

http://zeptojs.com/

jQueryとほぼ同機能でファイルサイズ1/3の軽量ライブラリ。

DOM操作やAjax通信系のライブラリは、
習得コストを考えると、利用者が圧倒的に多い
jQueryを選ぶのがベストだと思います。

ただ、jQueryは30KBというファイルサイズが難点で、
一方でZeptoはモダンブラウザに特化しているため、
わずか10KB程度しかありません。(※ともに圧縮&gzip時)

jQueryと比べて、いくつかの機能が使えませんが、
主要機能のほとんどは使用可能であったため、
ブレガーでは、jQueryではなくZeptoを選びました。

ただ、jQueryはドンドン軽量化されていますし、
jqMobiのような新たな対抗馬もいるので、
今後はZepto以外のライブラリを選ぶかもしれません。

2.JsRender

jsrender

https://github.com/BorisMoore/jsrender

JavaScriptで扱えるテンプレートエンジン。

Ajaxで受け取ったデータを元にHTMLを書き換える際に、
直接DOM操作をすると非常に面倒ですが、ブレガーでは
JsRenderを用いて、テンプレートからHTMLを生成しています。

テンプレート化によって分業化しやすくなるので、
開発スピードが一気に速くなりました。

ドキュメントが少ないのが欠点ですが、
ヘルパー関数やカスタムタグが作れたりと高機能で
処理速度もほとんど気にならないほど速いです。

他のテンプレートエンジンと比べて、
記法が直感的で分かりやすいのもいいですね。

3.CreateJS

createjs

http://www.createjs.com/#!/CreateJS

Canvas描画・アニメーションライブラリ。

Canvasでの図形描画や画像読み込み、
アニメーションなどをより直感的に書けます。

特にActionScriptの経験がある人には
馴染みやすい記法だと思います。

ブレガーでは、Flashで作ったアニメーションを
JavaScriptに書き出すことができる、
「Toolkit for CreateJS」を利用しています。

4.Lo-Dash

lo-dash

http://lodash.com/

JavaScriptユーティリティライブラリ。

JavaScriptの配列やオブジェクトの複雑な操作を
すっきりシンプルに書けるライブラリ。

かゆいところに手が届く便利なメソッドが
数多く実装されていて、一度使ったら手放せません。

Underscore.jsと記法はほぼ同じですが、
こちらのほうが高機能かつ高速です。

5.Backbone.js

backbonejs

http://backbonejs.org/

JavaScriptMVCフレームワーク。

JavaScriptのMVCフレームワークは
いくつか存在しますが、Backbone.jsは
比較的ファイルサイズが軽く、
利用者が多いので情報も充実してます。

Observerパターンで書きやすくなり、
機能追加や修正のスピードが上がるので
個人的にはとても重宝しています。

「MVC」と書きましたが、Controllerがなく、
一般的なMVCとは概念的に異なるのでご注意を。

6.RequireJS

requirejs

http://requirejs.org/

モジュール管理および最適化ライブラリ。

各JavaScriptファイルの依存関係を

一元的に管理することができ、ビルド時には
複数ファイルの結合(単一ファイル化)や
コードの圧縮もしてくれるスグレモノです。

ブレガーのような、多数のJavaScriptファイルが
複雑に絡み合う大規模プロジェクトでは、
RequireJSの恩恵を大いに受けられます。

逆にファイル数の少ないプロジェクトの場合は、
わざわざ使う必要はないかもしれません。

7.Jasmine(with Sinon.js)

JavaScriptテストフレームワーク。

JSのロジックや通信のテストを
自動化したいときに非常に有用です。

Jasmine単体よりもSinon.JSと併用するほうが
いろいろと便利で書きやすいです。

仕様変更頻度の高いソーシャルゲームにおいて
全機能のテストコードを書くのは、
工数的に難しく、現実的ではありません。

いまのところブレガーでは、
共通基盤のみテストを自動化しています。

まとめ

今回はブレガーで使用しているライブラリを
いくつかご紹介しました。

スマホにしては多いのではないか?
と感じる方もいらっしゃるかもしれませんが、
私がライブラリを使うのには以下のような理由があります。

(1) 車輪の再発明をしなくて済むため工数短縮になる
(2) コードがちゃんとテストされているため安全
(3) コードの記法が統一されるため複数人で開発しやすい
(4) 既にdocumentがあるためコードの解説が不要

しかし、ライブラリを使うことが絶対に正しいとは限りません。

特にスマホの劣悪な通信環境では、
ファイルサイズを出来る限りミニマムに抑えなければ、
ユーザーが離脱する原因となってしまいます。

便利だからといって、大容量のライブラリを
バンバン使って操作性を悪化させては本末転倒です。

ブレガーでも、出来る限り軽量なライブラリを選び、
ライブラリを使わずに実装したほうが良いところは
自前で実装していきました。


大事なのは、ライブラリを使うことではなく、

ユーザーがストレスなく思いっきり楽しめるサービスを
いかに「速く」「安全に」創ることができるか。

これに尽きると思います。


最後までお読みいただき、ありがとうございました。

今回ご紹介した内容が、皆さんのサービス開発に
少しでもお役に立つことができれば嬉しいです。

ぼくらのブレイブガーディアン」も
是非是非プレイしてみてください!

bregar-avatar

はじめまして。
Ameba事業本部でイラストを担当している2012年入社の岡崎です。

今はブレイブナインというソーシャルゲームで、カードイラストの「塗り」の担当をしています。イラストの着彩をするうえで学んだ事、意識しているところを紹介します。
よろしくお願い致します。

内製カード制作の流れ

私たちのチームでは分業を行っています。設定資料をもとに
ラフ→線画作成→塗り
という流れで分業をしてイラストの制作をしています。

このように順番にまわってきたものを着彩していくのが僕の担当の部分です。

色を塗る

着彩は
1.色の選定
2.進化後の色のパターンの決定
3.塗り
4.仕上げ
の順番で考えています。

1.色の選定
まず色を選ぶ上で一番大切なのが、そのキャラクターらしさをわかりやすくすることです。
例として「暗黒騎士ヴァーリー」のカードをで考えてみます。
このカードは進化3段階目のカードになります。


まず、使う色を考えます。
「暗黒」というキーワードをもとに、
どのような色のを使えばそれらしさが出るか考えます。
暗黒だと暗い青や紫などが思いつくと思います。


そのパターンを基準に、線画にベースを塗って色のバランスをとります。

このヴァーリーの場合は一番メインに見せたい紫の他に、
色相の違う紫を使うことにしました。また面積の少ない部分にさし色として黄色をいれてバランスをとります。

2.色のパターンの決定

進化の色替えがある場合は、進化バリエーション色のパターンを決定します。
今説明しているヴァーリーは進化後のものなので、色のバリエーションは作りませんが、
進化前では2パターンの塗りをしています。

変わったということをはっきりわかってもらう必要がありますので、
キーワードとしていた暗黒騎士のイメージを損なわないようなパターンを作ります。

また、同じ色のパターンだとしても、
色の面積をかえることで印象を変えることができないかも考えたりします。

3.塗り
影をつけることで形をはっきりさせていきます。
まず光源を設定します。
どこから光を当てたら見やすくなるのかを考え決めます。

このようなイラストならば、手前と奥がはっきりしているので、
右を光源にしたほうが見えやすくなると考え、光源を設定しました。

その光源からずれないように意識しながら影をつけていきます。

光の方向をしっかりさせれば、要素の多いイラストでもすっきりします。
ブレイブナインのイラストの場合は、陰に焼き込みをいれています。
陰の中に明度の違いを入れることで、自然な反射光をいれられます。

<ショートカット紹介>
普段制作するときに使っているショートカットを少し紹介したいと思います。

ラバーハンド

・ペンツールを使うとき、このチェックボックスを入れると
軌跡が表示されて便利です。
command+enter
・パスを選択範囲に変更
alt+delete
・描画色で塗りつぶし
command+delete
・背景色で塗りつぶし
command+J
・選択範囲をコピーして新しいレイヤーの作成


4.仕上げ

最終的になると全体的な彩度等を調整していきます。手前にきている大きな部品があれば彩度を高めに設定してあげて、遠近感をだすようにします。
また一番見せたい色以外で抑えられるものは彩度を抑えて引っ込ませます。

最後に形の中で一番見せるべき流れを考えて、
それがはっきり見えるように黒い色で落とし見やすくするようにします。

そして最後にはカード枠にはまって完成になります。


最後に

絵は曖昧な部分が多くなってしまいがちですが、
その中でしっかり理由を持って、描いていくことが大切だと思います。

学生時代はなんとなくで描いてしまうことが多かったですが、社会人になってからは理由を持って描くように努力しています。それでもまだ曖昧に進めてしまうこともあるので、たくさん場数を踏んでスキルアップしていきたいと思っています。


ありがとうございました。
聖戦記ブレイブナインもよろしくお願いします。