訪問者たちが炎を灯したり消したりして明るさをリアルタイムに変えられるサイトを作りました

category : レポート  tag : 
ogp_650

河本です。
弊社で、株式会社Razestのリブランディングプロジェクトとして、Webサイトのリニューアルを担当しました。

今回のWebサイトのテーマは
・ビジュアルで、ゲームを作るRazestという会社の世界観を見せる。
・サイト訪問者を楽しませる驚きのある仕掛けを入れる
ということで、
トップページは、Razestという会社の”脳内妄想工場”をイメージした3Dイラストの世界に、社名の由来である「情熱の炎」を配置。炎はサイト訪問者が付けたり消したりすることができ、炎が少なくなるとサイト全体が暗くなって見にくくなるという仕掛けを入れました。

以下について説明します。
■トップページは2Dだがクォータービューの絵が動く
■炎がリアルタイムに連動する
■タスクランナーのgulpを導入してみた
■その他言いたいこと
■さいごに

トップページは2Dだがクォータービューの絵が動く

トップページはCreateJSで作る事にした

アニメーション作成はAdobe Animate(Flash)から書き出し、MovieClipをJS側で配置することが出来るので、作業分担しやすい。
途中からFlashが得意な@_sakotsuにトップページのアニメーションをお願いした。

3Dを2Dのレイヤーとして配置する

3Dイラストレーターの豊田遼吾さんにイラストを依頼した。
PSDデータで動く部分についてパーツをレイヤーで分けた状態で納品してもらうことになった。
クォータービューなので個別のパーツレイヤーを3次元座標で配置し、毎フレーム2次元座標への変換、重なりのソートを行う事にした。

炎がリアルタイムに連動する

TOPでON/OFFした炎が下層ページの明るさにも影響する。

サーバーサイド

nodeアプリとしてつくったsocket.ioサーバをWebサーバのEC2インスタンスに同居させた。
下層ページの中にはメールフォームなど、https接続のページもあるため、socket.ioサーバを二つ立ち上げ、双方へブロードキャストしている。

//疑似コード
let ios=[ioHttp,ioHttps];
for(let io of ios){
  io.on('connection', function(socket) {
    for(let targetIo of ios){
      targetIo.emit("foo");
    }
  });
}

nodeアプリは常時稼働する。
落ちると怖いのでMochaとChaiを使って一通りユニットテストを書いておいた。
initd-foreverでサービス化している。
mod_proxy_wstunnelを使う事で同じ80ポートで待ち受け可能なようだが、無理矢理動かしているような印象を受けたので無理せずに別ポートで動作させた。

クライアントサイド

明るさは暗い状態の半透明レイヤーのopacity(またはalpha)を変えている。

トップページ

下層ページ

グラデーション部分はcanvasのNon-zero winding ruleを利用して、始めに全体を反時計回りで囲んだ後にくり抜く部分を時計回りで囲みくり抜く。

くり抜いた部分は中心が明るいグラデーションで埋める

タスクランナーのgulpを導入してみた

規模が大きいサイトになると、CSSがふくれあがり、手がつけられなくなる。
先方も困っていた。
SCSSを提案したところ、先方でも導入することが決まった。
今回のプロジェクトファイルを身近な動作例として活用して頂くことになった。

タスクランナーとしてMiddlemanを使って来たが、一般的とは言えないため、gulpを導入し、gulpプロジェクトごと納品することにした。

browserifyとbabelify

MiddlemanではCoffeeScriptを使っていたが、これを機にES2015とCommonJSを使ったスタイルに切り替える事にした。
babelを使ってES2015をES5へコンパイルする。
CommonJSのrequireはbrowserifyで実現する。
browserify用のbabelはbabelifyを使う。

IE9、IE10でも動くようにするには、
ES2015のクライアントコード側に
import “babel-polyfill”;
を書く必要があるのとgulpfile.jsのbabelifyオプションに
plugins: [[‘transform-es2015-classes’, {loose: true}]],
を指定する必要がある。
Parent constructor calls not working for IE <= 10

//gulpfile.jsから抜粋
gulp.task('babelify',function(){
  return gulp
  .src([paths.es6+'**/*.es6','!'+paths.es6+'**/_*.es6'])
  .pipe(plumber({
    errorHandler: notify.onError("Error: <%= error.message %>")
  }))
  .pipe(through2.obj(function(file,encode,callback){
    return browserify({
      entries:file.path,
      //debug:true,
      basedir:paths.es6,
    })
    .transform(babelify,{
      presets:["es2015"],
      plugins: [['transform-es2015-classes', {loose: true}]],
      //sourceMaps:"file",
    })
    .bundle(function(err, res) {
      if (err) { return callback(err); }
      file.contents = res;
      callback(null, file);
    })
    .on("error",function(err){
      console.log("Error : " + err.message);
    });
  }))
  .pipe(gulpif(!IS_DEBUG,uglify({preserveComments: 'license'})))
  .pipe(rename({
    extname:'.js',
  }))
  .pipe(gulp.dest(paths.js))
  .on('end',browserSync.reload);

});

ES2015を使ってCreateJSのDisplayObjectを継承する

EASELJSは以下のように継承する必要がある。
EASELJS INHERITANCE
ES2015を使う場合は、継承はES2015で行いpromoteだけ行う。
EaselJS: custom Display Objects in ES2015
↓例としてShapeを継承してみた。

See the Pen EaselJS Inheritance in ES2015 by Yusuke Kawamoto (@novogrammer) on CodePen.

SCSS(Sass)とCompass

SCSSはmixin、変数、式が便利。ネストも可能。
Compassは便利なmixinやスプライト機能が便利。

Jade

Middlemanで使っていたHamlとほぼ同じ構文を使える。
extendsとincludeが便利。
インデントでネストを表現するので、scssでネストしたスタイルシートと構造が一致する。
ページごとに大きくスタイルが変わるようなコーディングで迷子にならない。

Jadeは商標上の問題からPugへ名前が変更になる。

その他言いたいこと

慣性スクロール

簡易的な動摩擦で減衰を表現した。

電光掲示板っぽさのレイヤー

デバイスフォントを加工するのが難しいので、
Shapeに半透明の黒線を縦横に2px間隔で描いて、上に重ねた。
バナー部分も同様に重ねた。
よく使われる手法だと思う。

スマホファーストなレスポンシブWebデザイン

IE8がサポート外になったので、スマホ版のスタイルシートに必要に応じてPC版のスタイルシートを適用した。

EventEmitter2をメッセージキュー代わりに使う

EventEmitterはクライアントサイドでも使ってみたかった。使ってみると自前でコールバックしていた箇所がスッキリした。
socket.ioの送受信イベントやマウスホバーイベントの伝播に使った。

さいごに

Adobe Animate(Flash)はアニメーション作成ツールとしては優秀だと思うのでCreateJSで生き残っていきそうな気がする。
CreateJSはCommonJS形式でないのでimport(require)しなかったが、CreateJSに限らず、クライアントサイドのライブラリもCommonJS形式に対応してくれるとbrowserifyで使いやすくなると思った。

制作スタッフ

Razest Re-Branding Project

Producer:トミモトリエ(人間)
Destroyer:トミモトリエ(人間)

BROCHURE
Director:トミモトリエ(人間)
Planner:トミモトリエ(人間)
Designer:松尾聡(人間)
Copy Writier:久岡崇裕(parks)/ 田辺ひゃくいち(人間)
Game Director:朝戸一聖(TANSANFABRIK)
Photographer:島田勇子(ニコライス)

WEB
Director:トミモトリエ(人間)
Planner:トミモトリエ(人間)/ 山根シボル(人間)
Designer:山根シボル(人間)/ 松尾聡(人間)
Technical Director:河本裕介(人間)
Programmer:河本裕介(人間)
Front-end Engineer:河本裕介(人間)
Interactive Developer:水口卓哉(sakotsu)
Illustrator:豊田遼吾
Artist Manager:岸田吉哲(vision track)