実質20行ほどでニコニコ動画風のコメント表示機能を作る 〜素の JavaScript とアニメーション用ライブラリ（GSAP）を利用〜

## はじめに
この記事は、以下のツイートの動画にあるようなニコニコ動画風のコメント表示を、HTML+JavaScript で実装した際の話です。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">テキストを動的に生成して、画面内をアニメーションで動かす処理を書いてた件、さらに一歩先へ。<br><br>OBSとの組み合わせ！<a href="https://twitter.com/hashtag/%E3%82%86%E3%82%8B%E3%83%A1%E3%82%AB%E3%83%88%E3%83%AD?src=hash&amp;ref_src=twsrc%5Etfw">#ゆるメカトロ</a> <a href="https://twitter.com/hashtag/Noodl%E3%82%82%E3%81%8F%E3%82%82%E3%81%8F%E4%BC%9A?src=hash&amp;ref_src=twsrc%5Etfw">#Noodlもくもく会</a> <a href="https://twitter.com/hashtag/%E3%83%93%E3%82%B8%E3%83%A5%E3%82%A2%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E4%BA%A4%E6%B5%81%E4%BC%9A?src=hash&amp;ref_src=twsrc%5Etfw">#ビジュアルプログラミング交流会</a> <a href="https://t.co/rngaNDFNWj">https://t.co/rngaNDFNWj</a> <a href="https://t.co/GuZqc1vMO8">pic.twitter.com/GuZqc1vMO8</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1299635436726312960?ref_src=twsrc%5Etfw">August 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こちらの動画の内容を実現しているものは、ボタンがクリックされたら動的にテキストを生成して画面上に流すという Webページと、その Webページとカメラ映像とをクロマキー合成する機能（[OBS](https://obsproject.com/ja) による）です。

記事のこの後の部分では、上記の Webページ の部分を作るまでの流れを書き、そして仕組みの話へと入っていきます。また、仕組みの話の後には、オンラインでコメント・リアクションをやりとりするサービス・プロトタイプの事例をいくつか書いています。

仕組みのところだけ知りたいという方は、「[作った仕組みについて」の項目](https://qiita.com/youtoy/private/051dc658025a3b21c7f0#%E4%BD%9C%E3%81%A3%E3%81%9F%E4%BB%95%E7%B5%84%E3%81%BF%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)からお読みください。

### 着手するまでの流れ1（OBS向けに過去に作った仕組み）
自身のプライベートの活動で、ここ最近はオンラインイベントの対応（自身でのイベント主催やLT登壇など）が増加しています。そんな中、配信・登壇者の側を便利にしてくれる仕組みや、イベントの参加者と登壇者をつなげる仕組みが自作できないか、と思っていました。

そして、以下の Qiita の記事やツイートの動画にあるような、配信などに使われるオープンソースのソフト「[OBS](https://obsproject.com/ja)」の「[obs-websocket というプラグイン](https://github.com/Palakis/obs-websocket)」を活用した遠隔操作の仕組みを作ったりしていました。
　●OBS をスマホや M5GO（M5Stack）から遠隔制御 〜 MQTT や obs-websocket を利用 〜 - Qiita
　　https://qiita.com/youtoy/items/23fb0e16f1a4428b5c9b
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">MQTTを利用し、PC上で動くOBSのシーンの切り替え操作を、他デバイスから制御してみた！<br><br>UIFlowでプログラムを書いたM5GOと、JavaScriptで処理を書いたWebサイトを表示したスマホの、2つのデバイスを操作し、3つのシーンを切り替えてみました。 <a href="https://t.co/fg3QAauCB6">pic.twitter.com/fg3QAauCB6</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1296488753641467907?ref_src=twsrc%5Etfw">August 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この配信者側で活用する仕組みを作ったところで、さらに配信者と視聴者をつなぐ部分の何かを作ることもできれば、と思いました。

### 着手するまでの流れ2（今回の内容の着手）
上記の仕組みを作った後に、自分も主催メンバーに入っている共同主催のイベント（もくもく会）を開催しました。

そのもくもく会でやる内容を考えていた時に、ふと「また OBS と組み合わせて使える何かを作ってみよう」と思いました。そして、おおまかな内容を考えた後に以下のツイートにあるような試作を始めました<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">今日の合同もくもく会は <a href="https://twitter.com/hashtag/%E3%83%93%E3%82%B8%E3%83%A5%E3%82%A2%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E4%BA%A4%E6%B5%81%E4%BC%9A?src=hash&amp;ref_src=twsrc%5Etfw">#ビジュアルプログラミング交流会</a> からの参加ですが、<br>なぜかJavaScriptで動的にテキスト生成をして、それをアニメーションで動かすようなことをしているｗ<a href="https://twitter.com/hashtag/%E3%82%86%E3%82%8B%E3%83%A1%E3%82%AB%E3%83%88%E3%83%AD?src=hash&amp;ref_src=twsrc%5Etfw">#ゆるメカトロ</a> <a href="https://twitter.com/hashtag/Noodl%E3%82%82%E3%81%8F%E3%82%82%E3%81%8F%E4%BC%9A?src=hash&amp;ref_src=twsrc%5Etfw">#Noodlもくもく会</a> <a href="https://t.co/qoeCwioeXn">pic.twitter.com/qoeCwioeXn</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1299598052492103681?ref_src=twsrc%5Etfw">August 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 作った仕組みについて
### プロトタイプを作るために考えたこと・やったこと
この記事の後半の[「既存のサービスやプロトタイプ」という項目](https://qiita.com/youtoy/private/051dc658025a3b21c7f0#%E6%97%A2%E5%AD%98%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%84%E3%83%97%E3%83%AD%E3%83%88%E3%82%BF%E3%82%A4%E3%83%97)に書いたような仕組みの中で、参加者の操作が行われた際に登壇者側に何か表示がされる方向のもの作りたい、と思いました。

そして、最初に手をつけようと思ったのが「ニコニコ動画風のコメント表示機能」でした。

#### コメント表示に必要な機能
まずは、「ニコニコ動画風のコメント表示機能」を最小限の実装で実現するために、必要な仕組みを頭の中で整理しました。その結果は以下のとおりです。

- 画面に流すテキストの要素の動的な生成と設定
    - 要素の動的な生成
    - 動的に生成した要素の画面上への配置
    - 動的に生成した要素へのテキストの設定
    - 処理に必要なスタイル・属性などの設定（id や style）
- 画面上での要素の移動
    - アニメーションの仕組みを用いた要素の移動
- クロマキー合成のための設定
    - 背景色をクロマキー用の色に設定

最終的には外部から受け取ったテキストやリアクションのトリガーに基づいて、画面上に流すテキスト等の表示を変えるつもりでしたが、表示部分のみを試す段階では外部との連携は省きました。とりあえず版の実装は「画面上にボタンを配置し、ボタンが押されるごとにテキストの動的な生成とアニメーションを行う」というものにしました。

#### アニメーションの処理の実装
テキストを動かすアニメーションの部分は、CSS か JavaScript の処理により自前での実装もできる部分ですが、後々、表示のさせ方を工夫したくなった際などの拡張性を考慮すると、ライブラリを使っておいたほうが良いと考えました。

以下の記事など、まとめ記事をいくつか見るなどして、最終的に速度・多機能製に優れると書かれていた「[GSAP](https://greensock.com/gsap/)」を用いることにしました。
　●現場で使えるアニメーション系JSライブラリまとめ（2020年版） - GSAP, CreateJS, WebAnimation, Velocityなど - ICS MEDIA
　　https://ics.media/entry/14973/

![GSAP_-_GreenSock.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/17f4bdd9-b9ea-2c05-282b-9df63580b707.jpeg)


そして、簡素な Webページを作り、動的に生成した要素を動かせることを確認しました。
（※[「着手するまでの流れ2（今回の内容の着手）」の項目](https://qiita.com/youtoy/private/051dc658025a3b21c7f0#%E7%9D%80%E6%89%8B%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%B5%81%E3%82%8C2%E4%BB%8A%E5%9B%9E%E3%81%AE%E5%86%85%E5%AE%B9%E3%81%AE%E7%9D%80%E6%89%8B)に掲載していた動画の内容）

### 実装したソースコードについて
ライブラリの調査・選定と機能テストを行い、その後に全体の実装を行いました。そこで書いた処理部分は「実質20行ほど」です（「実質」という部分に含まれていないのは HTMLの必須の構成要素で、今回用に手を加えてない部分）。

冒頭の動画で、OBS で合成していたテキストが流れる画面は、以下のようなものになります。
![ニコニコ動画風のコメント表示_と_03_ニコニコ動画風のインタフェースを作る_と_Slack___random___VS_Code_Meetup.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/e4b074bc-cc64-da98-a5ff-c8dd2c39b9b1.jpeg)

以下がソースコードですが、今回、「サクッと自分が試せれば良いや」という発想で作った段階のものであるため、ワンソースで適当な実装になっています（エラーハンドリング的なもの等は入ってないです）。もし、「こんな実装のほうが良いのでは？」等といったことがありましたら、記事のコメント欄にてコメントをいただけましたら幸いです。

```HTML
<!DOCTYPE html>
<html style="background:#00FF00;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ニコニコ動画風のコメント表示</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
</head>
<body>
  <button id="button01">テキストを流す</button>

<script>
const button01 = document.getElementById("button01");
button01.addEventListener("click", function(){createText()}, false);
let count = 0;

async function createText() {
  let div_text = document.createElement('div');
  div_text.id="text"+count; //アニメーション処理で対象の指定に必要なidを設定
  count++;
  div_text.style.position = 'fixed'; //テキストのは位置を絶対位置にするための設定
  div_text.style.whiteSpace = 'nowrap' //画面右端での折り返しがなく、画面外へはみ出すようにする
  div_text.style.left = (document.documentElement.clientWidth) + 'px'; //初期状態の横方向の位置は画面の右端に設定
  var random = Math.round( Math.random()*document.documentElement.clientHeight );
  div_text.style.top = random + 'px';  //初期状態の縦方向の位置は画面の上端から下端の間に設定（ランダムな配置に）
  div_text.appendChild(document.createTextNode('移動するテキスト'+count)); //画面上に表示されるテキストを設定
  document.body.appendChild(div_text); //body直下へ挿入

   //ライブラリを用いたテキスト移動のアニメーション： durationはアニメーションの時間、
   //        横方向の移動距離は「画面の横幅＋画面を流れるテキストの要素の横幅」、移動中に次の削除処理がされないようawait
  await gsap.to("#"+div_text.id, {duration: 5, x: -1*(document.documentElement.clientWidth+div_text.clientWidth)});

  div_text.parentNode.removeChild(div_text); //画面上の移動終了後に削除
}
</script>
</body>
</html>
```

動作確認は Mac版の Chrome（バージョン: 84.0.4147.135）で行っていました。

なお、今回、画面で流しているテキストは `div_text.appendChild(document.createTextNode('移動するテキスト'+count));` の部分で生成したものですが、仮のものなので今後は手を加えます。

具体的には、外部から MQTT などでリアルタイムに受け取ったテキストを表示させる形にするか、MQTT などでリアクションの ID的なものを受け取って ID に紐付いたテキストを表示させる、という実装を考えています。

### 配信用などに合成する（OBS が関わる部分）
上記を用いることで、グリーンバックの Webサイトにテキストが流れる画面が出せるようになりますが、配信用などに用いるにはクロマキー合成を行う必要があります。

詳細は割愛しますが、例えば一例として OBS を使って以下の対応をすれば OK です。

1. PC に外部モニタをつけるなど画面を 2つにし、一方に OBS、もう一方にブラウザ（今回作ったものを表示）を置く
2. OBS の「シーン」の「ソース」の中にコメント表示を重畳させたい対象を追加（記事の冒頭の動画は「映像キャプチャデバイス」で「PC内蔵のカメラ」を設定しています）
3. OBS の「シーン」の「ソース」の中に「画面キャプチャ」も追加し、上記1）のブラウザを指定
4. 上記2）で追加した 「画面キャプチャ」の「フィルタ」で「クロップ/パッド」と「クロマキー」の 2つを設定
5. 「クロップ/パッド」のフィルタ設定で「上」の数値を増やし、ブラウザのタブの部分などが見えないようにクリッピングする（「クロマキー」のフィルタ設定は、今回の記事内の背景色を指定していれば、特別な設定は不要）

## 既存のサービスやプロトタイプ
ここでは、今回作ったもの・今回の作ったものの先にある流れと同じ方向性のもの・同じ機能を備えたもので、使ったことがあるもの・気になっているものをいくつか記載します。

### オンラインイベント等で使えるコメントやリアクションを表示するためのサービス
#### Comment Screen
今回の内容は「ニコニコ動画風のコメント表示機能を作る」というものですが、オンラインイベントで活用できるコメント表示サービスで例えば「[Comment Screen](https://commentscreen.com/)」があります。
こちらは、コメント等を受ける側がアプリを起動すると、PCのデスクトップ上にコメントやアイコンなどを重畳表示するためのレイヤーができ、コメントを送る側が入力したテキスト等がPCのデスクトップに重畳表示されます。
![commentscreen_com.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1fbebc2d-1d66-af37-81e0-03ec4fcdb87f.jpeg)
このサービスは、自分が運営メンバーとなったイベントや、一般参加者になったイベントで何度も使われていてお世話になっています。

#### リモート擬音さん
また、ニコニコ動画風ではないですが、オンラインイベントで参加者がリアクションをしたら、登壇者側の画面にリアクションに応じた表示が行われるものに「[リモート擬音さん](https://remotegionsan.com/)」というものがあります。
![リモート擬音さん.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/9578bb7d-0ee2-a14b-8beb-7c9957f8a751.jpeg)
以下の使い方の記載にあるように、表示側の仕組みは Comment Screen とは異なります。こちらは、グリーンバックで構成された Webサイトが生成されるので、それを OBS などでキャプチャしてクロマキーを適用する、という使い方です。
![リモート擬音さん2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ce8f1fe3-2e09-5ee0-06a9-0a0868b6a9ce.jpeg)

### 上記以外のオンラインフィードバックシステムのプロトタイプ
#### 「いいね！」を受け取る仕組み＋可視化
その他、イベントでプロトタイプに関するLTが行われたもので、例えば以下のものがあります。
　●「作った登壇リアクションシステムをベースにNode-REDダッシュボード機能をゆるく紹介」 - ビジュアルプログラミングIoTLT vol3 - Speaker Deck
　　https://speakerdeck.com/1ftseabass/biziyuarupuroguraminguiotlt-vol3
オンラインイベント用ではなく、発端はオンライン授業で生徒さんの反応を受け取るため、という感じとのことです。オンラインで「いいね！」のリアクションを受け取り、その 5秒ごとの推移をグラフ化したりなどしています（可視化の部分は [Node-RED](https://nodered.org/) による実装）。
![「作った登壇リアクションシステムをベースにNode-REDダッシュボード機能をゆるく紹介」.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ea5a2eec-ec24-bdc0-4866-900802b6bc6b.jpeg)

#### リアクションを受け取り音にする
こちらも、イベントでプロトタイプに関するLTが行われたものです。
YouTube Live のアーカイブはこちら ⇒ https://youtu.be/lp3-ywQKKAc?t=966
![【19_30開始】IoT縛りの勉強会__IoTLT_vol_65_-_YouTube_🔊.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/cb7d50e2-abc0-4802-67ae-c071b25b7daa.jpeg)
仕組みとしては、登壇者側と視聴者側とを WebSocket でつなぎ、それを登壇者側はラズパイで受信する形のようでした。ラズパイは、リアルタイム通信で視聴者側のリアクションのトリガーを受け取り、そのタイミングで音声を再生してPCへはマイク入力で音を流し込む、というもののようでした。
![【19_30開始】IoT縛りの勉強会__IoTLT_vol_65_-_YouTube_🔊2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/4b7b98ae-04ec-299d-0dac-7281bf915c11.jpeg)

## 終わりに
今回、ニコニコ動画風のコメント表示機能を「素の JavaScript とアニメーション用ライブラリ（GSAP）」を使って実装する、ということをやりました。

現状は、表示するテキストは内部で生成しているので、この部分は本文でも書いたとおり MQTT などで外部から受け取る形に変えようとしているところです。

## 【追記】 デスクトップ上の表示に対応させてみた！
この表示機能、HTML+JavaScript で作っていましたが、**ふと「もしElectronで背景透過とかできたら、それを活用してデスクトップにもコメントを出せるのでは？」と思い**、試してうまくいきました！
（サクッと作ったとりあえず版なので、表示周りで少しおかしな感じのところはあるけれど・・・）

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">この前、以下のQiitaの記事に書いていたニコニコ動画風のコメント表示機能、文字はOBSでクロマキー合成する構成だったのですが、<br>ふと「もしElectronで背景透過とかできたら、デスクトップにも出せるのでは？」と思い、試してうまくいった！<br><br>↓こちらを拡張したバージョン<br>　<a href="https://t.co/nWImQlXbAN">https://t.co/nWImQlXbAN</a> <a href="https://t.co/KjjPQRqxmE">pic.twitter.com/KjjPQRqxmE</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1301162711602978825?ref_src=twsrc%5Etfw">September 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 【追記2】 外部からの操作・効果音の再生の機能を足してクロマキー合成を試した！
M5Stack（M5GO）でのボタン操作に応じて、コメントが表示される機能も作ってみました。
さらに、スマホ操作での制御・表示側での効果音再生の機能を追加し、OBSでクロマキー合成に使ってみるというのもやりました！
（実装に関し、端末間の通信はMQTTを使い、効果音再生のための処理周りではオーディオライブラリ「
howler.js」を使いました）
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">「ニコニコ動画風のコメント表示機能」に、外部の端末の操作で表示内容を変える機能や、表示側で効果音を出せる機能を追加した件の、その後。<br><br>このコメント表示機能と、カメラ映像・スライド表示とを、OBSを使ってクロマキー合成してみるのも試した！ <a href="https://t.co/23HnxQqlYg">https://t.co/23HnxQqlYg</a> <a href="https://t.co/JWmV5xK83B">pic.twitter.com/JWmV5xK83B</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1302546994326429696?ref_src=twsrc%5Etfw">September 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 【追記3】 オンラインイベントでのLT登壇とライブデモ
[コミュニティ放送部](https://community-bc.connpass.com/)というコミュニティのオンラインイベントでLT登壇して、[そこでライブデモもやりました](https://www.youtube.com/watch?v=w_ljw9S5zkE&t=5842)。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">昨日の <a href="https://twitter.com/hashtag/%E3%82%B3%E3%83%9F%E3%83%A5%E3%83%8B%E3%83%86%E3%82%A3%E6%94%BE%E9%80%81%E9%83%A8?src=hash&amp;ref_src=twsrc%5Etfw">#コミュニティ放送部</a> のイベントで、ライブデモをやったニコニコ動画風のコメント表示機能（ HTML+JavaScript で実装し、OBS でカメラ映像と合成 ）、YouTube Live のアーカイブで見え方を確認してみた。<br><br>きちんと伝わっていそうで、良かった！<a href="https://t.co/7i3fXRWLlE">https://t.co/7i3fXRWLlE</a> <a href="https://t.co/toZYaVWcGU">pic.twitter.com/toZYaVWcGU</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1310019953832075264?ref_src=twsrc%5Etfw">September 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 【追記4】 ニコニコ風コメントのライブラリ
Twitter上での CSSアニメーション関連の話題から、「[臆病な魔女](https://www.yui540.graphics/product)」というサイトを教えてもらい、過去作品のページを見ていたらニコニコ風コメントのライブラリという項目が。チェックしてみようと思います！

●yui540/nicoJS: ニコニコ風コメントを実装するライブラリ
　https://github.com/yui540/nicoJS

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">そのあたり確かにどういう考えで作られてるのか凄い気になりますよね。<br>ポートフォリオ？サイトの「臆病な魔女」も綺麗ですよ！過去作品とかも置いてあります<a href="https://t.co/DPprP5Ne9k">https://t.co/DPprP5Ne9k</a></p>&mdash; もっちー@iOS (@Motchy_1204) <a href="https://twitter.com/Motchy_1204/status/1339778974264614912?ref_src=twsrc%5Etfw">December 18, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 【追記5】 コメントを流す Chrome拡張
異なる PC間で画面上にコメントを流すことができる Chrome拡張がリリースされたようです。

●barrage-chat - Chrome ウェブストア
　https://chrome.google.com/webstore/detail/barrage-chat/odlofblmifehinhbohhmmidoamogehhi?hl=ja&authuser=0

## 【追記6】 コメントを流す仕組み： 未分類
あらためて調べた時に、いろいろな方の取り組み等を見かけたので追記。

●Milkcocoa ロスから卒業！｜野良ハック（ざっきー）｜note
　https://note.com/kitazaki/n/n3681cfcbc279
●GitHub - kitazaki/commetter
　https://github.com/kitazaki/commetter

●comets 発表スライド上にコメントが流せるサービス
　https://comets.nabettu.com/

●ニコニコ動画風のコメントをJavaScriptで作ってみよう – Blog
　https://spelunker2.wordpress.com/2016/05/02/%E3%83%8B%E3%82%B3%E3%83%8B%E3%82%B3%E5%8B%95%E7%94%BB%E9%A2%A8%E3%81%AE%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%82%92javascript%E3%81%A7%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86/

●YouTubeでニコニコ動画みたいに画面上にコメントを流す方法 | tomalog
　https://tmtmtlog.com/it/youtube-comment/