こんにちは。普段フロントエンド(とか)エンジニアをしていますが、趣味でRTAをやっている繋がりでオンラインやオフラインのゲームイベントの運営もやってたりします。
この記事、別の話をしようと思っていましたが、悩んだ結果、運営をやっている繋がりでNodeCGというフレームワークを使ったりmaintainerをしたりしている話をしようと思います。
追記:NodeCGのDiscordサーバーに日本語チャットを作ってあるので気軽に参加してください https://discord.gg/jgQRuJK
NodeCG
https://nodecg.com
https://github.com/nodecg/nodecg
一言で言うと「ライブ配信のレイアウトをWeb技術で作るフレームワーク」です。
ちょっと何言っているのかわからないですね。
噛み砕くと
- Twitch、YouTube Live、ニコニコ生放送などのライブ配信で
- 動的でリッチな見た目の画面表示を作るための
- 大枠の仕組みを提供するフルスタックフレームワーク
です。
まだどんなものかよくわからないので、サンプルを動かしてみましょう。下のはGamesDoneQuick1というRTAイベントで使われた、NodeCGで作られたレイアウトです。(https://github.com/gamesdonequick/sgdq18-layouts)
ついでなので、実際のイベントで動いているところを見てみましょう
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を定義する、といったものです。
つくってみる
せっかくなので何か作ってみましょう。必要なものは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
{
"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に数字をカウントアップするボタンを付けてみます。
<!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
ディレクトリを作り、数字を表示するレイアウトを作ってみます。
<!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を出してみます。
右上のGRAPHICS
から、配信レイアウトを出せます
...他に何も書いていないので数字しかいません。実際にレイアウトを作る際は、HTML、CSS、SVGなどを駆使して上の動画みたいなレイアウトを作ります。
さておき、dashboardのボタンを押してみましょう。
いい感じでリアルタイムに動いています。
実際の配信での使い方
今までブラウザでレイアウトを表示してきましたが、実施の配信で使うときはブラウザに写しません。何を使うかというと配信ソフトについているブラウザソースの機能です。
例えば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人しか知らないので、もっと流行ってほしいですね!
-
同時視聴10万人以上、1週間で2億円以上寄付金を集めるマンモスチャリティイベント。RTAを披露して視聴者から寄付金を募る。 ↩