JavaScript
Node.js
Node.jsDay 7

ライブ配信レイアウトを作るNode.jsのフレームワーク

こんにちは。普段フロントエンド(とか)エンジニアをしていますが、趣味でRTAをやっている繋がりでオンラインやオフラインのゲームイベントの運営もやってたりします。

この記事、別の話をしようと思っていましたが、悩んだ結果、運営をやっている繋がりでNodeCGというフレームワークを使ったりmaintainerをしたりしている話をしようと思います。


NodeCG

https://nodecg.com

https://github.com/nodecg/nodecg

NodeCG

一言で言うと「ライブ配信のレイアウトをWeb技術で作るフレームワーク」です。

ちょっと何言っているのかわからないですね。

噛み砕くと


  • Twitch、YouTube Live、ニコニコ生放送などのライブ配信で

  • 動的でリッチな見た目の画面表示を作るための

  • 大枠の仕組みを提供するフルスタックフレームワーク

です。

まだどんなものかよくわからないので、サンプルを動かしてみましょう。下のはGamesDoneQuick1というRTAイベントで使われた、NodeCGで作られたレイアウトです。(https://github.com/gamesdonequick/sgdq18-layouts)

Kapture 2018-12-08 at 3.31.39.gif

ついでなので、実際のイベントで動いているところを見てみましょう

https://youtu.be/tsUvZ9yiN_U?t=1433


おおざっぱな説明

バックエンドにexpressが使われ、HTML+CSS+JSでブラウザにレイアウトを表示します。

NodeCGでレイアウトを構築するときにつくる、フロントエンドとバックエンドがセットになったものをbundleと呼んでいます。1つまたは複数のbundleを組み合わせて1つのNodeCGアプリを作るイメージです。

1つのbundleは



  • dashboard: レイアウトを操作するページ


  • graphics: 表示するレイアウトのページ


  • extension: サーバーサイド (今回は省略)

の3つに分かれています。

dashboardで操作すると、NodeCGのサーバーサイドを通してgraphicsに反映され、追加でサーバーサイドのロジックを書きたい場合extensionを定義する、といったものです。

nodecg bundle architecture (1).png


つくってみる

せっかくなので何か作ってみましょう。必要なものはNode 8以上です。


NodeCGをcloneして準備する

なかなかセットアップが原始的ですが、許してください。2018年ですが本当にbowerという文字が見えています。許してください。(ここでしか使う必要はないです。)

$ npm i -g nodecg-cli bower

$ nodecg setup
$ mkdir bundles/hoge-layout
$ cd $_
$ npm init -y


bundleの設定を書く

bundles/hoge-layoutのほうのpackage.jsonに設定を書いていきます。https://nodecg.com/tutorial-5_manifest.html


package.json

{

"nodecg": {
"compatibleRange": "^1.0.0",
"dashboardPanels": [
{
"name": "sample-panel",
"title": "Sample Panel",
"file": "sample-panel.html"
}
],
"graphics": [
{
"file": "index.html",
"width": 1280,
"height": 720
}
]
}
}


dashboardを書く

dashboardディレクトリを作り、dashboardに数字をカウントアップするボタンを付けてみます。


dashboard/sample-panel.html

<!DOCTYPE html>

<html>
<body>
<button id="increment">+1</button>
<script>
const incrementEl = document.getElementById('increment')
const countReplicant = nodecg.Replicant('count')

incrementEl.addEventListener('click', () => {
countReplicant.value += 1
})
</script>
</body>
</html>



graphicsを書く

graphicsディレクトリを作り、数字を表示するレイアウトを作ってみます。


graphics/index.html

<!DOCTYPE html>

<html>
<body>
<div id="count"></div>
<script>
const countEl = document.getElementById('count')
const countReplicant = nodecg.Replicant('count', {defaultValue: 0})

countReplicant.on('change', newValue => {
countEl.innerText = newValue
})
</script>
</body>
</html>



動かす

$ cd ../..

$ node .

これでNodeCGが起動するので、localhost:9090でdashboardを出してみます。

Screen Shot 2018-12-08 at 01.42.41.png

右上のGRAPHICSから、配信レイアウトを出せます

Screen Shot 2018-12-08 at 01.43.56.png

...他に何も書いていないので数字しかいません。実際にレイアウトを作る際は、HTML、CSS、SVGなどを駆使して上の動画みたいなレイアウトを作ります。

さておき、dashboardのボタンを押してみましょう。

Kapture 2018-12-08 at 1.52.14.gif

いい感じでリアルタイムに動いています。


実際の配信での使い方

今までブラウザでレイアウトを表示してきましたが、実施の配信で使うときはブラウザに写しません。何を使うかというと配信ソフトについているブラウザソースの機能です。

Screen Shot 2018-12-08 at 03.39.53.png

Screen Shot 2018-12-08 at 03.40.24.png

例えばOBS Studioは、内蔵のChromiumを使って配信に直接表示することができ、ブラウザに写してそれをキャプチャ、といった煩わしい手順がいらないです。こういった理由で、このような動的なレイアウトはNodeCGでなくてもHTML+CSS+JSが使われることが多いです。


すこし詳しく説明

全機能紹介するとキリがないので、抜粋しつつ


機能

dashboardとgraphicsの中のJSでは、window.nodecgが定義されていて、いろいろなプロパティがいますが、例で使ったのはnodecg.Replicantです。

これはNodeCGの中にある簡易的なデータベースのためのAPIで、代入された値を保存して同時に変更をlistenerに伝える仕組みです。dashboardで数を増やしたら、その瞬間サーバーを通してgraphicsに'changed'イベントが伝えられ、新しい値が伝わります。

Replicantは実際にファイルに保存されるため、何かの不具合でサーバーが落ちたとしても値が保存されます。(やり直しがないライブ配信ではかなり大事な機能です)

他にもいろいろ機能があります



  • message: データのやり取りでなく、イベントを直接やり取りできる機能


  • sound: 音声ファイルをアップロードしておき、キューを送ることでレイアウトで音を再生できる機能


  • asset: 画像や動画ファイルをアップロードして、レイアウトやダッシュボードから参照できる機能

など。

基本的に薄く、unopinionatedに作られているため、例のようにplainなHTMLで作ったり、Reactで書いたりVueで書いたりなんでもできます。 (フレームワークの部分はPolymer 2でできていますが、中身を作る際は関係ありません)


中身の技術

Replicantの代入、変更、mutateに対してJSのProxyを挟むことで、変更を検知して各場所にWebSocketを通じて通知することで、すべての場所で同じデータを見ているような仕組みになっています。。

Proxyは興味深く、IE11で使用できずPolyfillも不可能なためまだ流行っていませんが、IE11を最初からサポートしていないNodeCGではこのような使い方ができています。(将来VueがリアクティビティをProxyで作り直すことも発表されています。)

(dashboardで値の変更)→(proxyがサーバーに通知)→(サーバーがgraphicsに通知)→(graphicsの表示が変更)

フロントエンドのリアクティブなフレームワークがHTMLとJSの間でリアクティビティを実現しているのと同じような関係を、クライアントとサーバーの壁を超えて実現しているあたり面白い仕組みだと思っています。


Maintainerとして

個人的な話をすると、1年半くらい前、このフレームワークを使って関わっているイベントのレイアウトを作るのが、本格的にプログラミングを始めるきっかけでした。

その後、TypeScriptの型定義をつけたり、テストのリファクタリングしたりしていたら、maintainerにならないかと誘われました。それまでは作者のLangeが1人でメンテナンスしてきたこともあり、まだまだ発展途上なフレームワークなので、できるだけ貢献していきたいです。

あと、海外では幅広いイベントで使われているのですが、日本で使っているのが自分ともう1人しか知らないので、もっと流行ってほしいですね!





  1. 同時視聴10万人以上、1週間で2億円以上寄付金を集めるマンモスチャリティイベント。RTAを披露して視聴者から寄付金を募る。