YouTube 等のライブ配信で野球の試合を中継する際に、OBS のような配信ソフトウェアにスコアボード画面をクロマキー合成で表示するためのアプリケーションです。
- 主な機能
- クイックスタート
- システム構成
- 主要ファイル構成
- 技術スタック
- セットアップと実行方法
- 基本的な使い方
- マルチPC構成での使用方法
- マスター/スレーブ操作制御
- 初期設定ファイルの生成
- 試合のリセットと再開
- トラブルシューティング
- さらに詳しく
- リアルタイム更新: 操作パネルから入力した内容が、WebSocket を通じて即座に表示ボードへ反映されます。
- 状態の永続化: 試合状況がサーバー側に自動保存され、ブラウザのリフレッシュやサーバー再起動後も試合を継続できます。
- シンプルな操作画面: Web ブラウザから誰でも簡単に試合状況(スコア、イニング、SBO カウント、ランナー情報)を更新できます。
- OBS 連携: 表示ボードは背景が緑色になっており、OBS などの配信ソフトウェアで簡単にクロマキー合成できます。
- マルチPC対応: サーバーのIPアドレスを指定することで、別のPCから操作パネルと表示ボードにアクセス可能です。
- 設定自動生成: コマンドラインツールで
init_data.jsonを簡単に生成できます(インタラクティブモード、YAML、コマンドライン引数の3つの方法に対応)。
5分で始める最短手順
npm installこのコマンドにより、以下が自動的に実行されます:
- 必要なnpmパッケージ(Bootstrap、Vue.js、ws、js-yamlなど)のインストール
postinstallフックによる依存ファイルの自動コピー(Bootstrap CSS/JS、Vue.jsをpublic/へ)
node server.jsコンソールに Server is listening on port 8080 と表示されれば成功です。
- トップページ: http://localhost:8080/
- 操作パネル: http://localhost:8080/operation.html
- 表示ボード: http://localhost:8080/board.html
- OBSで「ソース」→「ブラウザ」を追加
- URL:
http://localhost:8080/board.html - 「エフェクトフィルタ」→「クロマキー」で緑色を抜く
詳細は セットアップと実行方法 をご覧ください。
トップページ(index.html)から、操作パネル(operation.html)と表示ボード(board.html)へアクセスします。操作パネルと表示ボードは、WebSocket サーバー(server.js)を介してリアルタイムに通信します。
graph LR;
subgraph "サーバー"
D("WebSocketサーバー</br>server.js</br><i>Master/Slave制御</i>");
end
subgraph "クライアント (ブラウザ)"
A("トップページ</br>index.html");
B1("操作パネル 1</br>operation.html</br><b>Master</b>");
B2("操作パネル 2</br>operation.html</br><i>Slave (read-only)</i>");
C("表示ボード</br>board.html</br><i>Viewer</i>");
end
D <-->|WebSocket</br>game_state_update| B1;
D -->|WebSocket</br>game_state| B2;
D -->|WebSocket</br>game_state| C;
A --> B1;
A --> B2;
A --> C;
.
├── public/ # 静的ファイル(Webサーバーが配信)
│ ├── index.html # トップページ(メニュー)
│ ├── operation.html # 操作パネルのUI
│ ├── board.html # OBS等で表示するスコアボード画面
│ ├── css/
│ │ ├── main.css # カスタムスタイル
│ │ └── bootstrap.min.css # Bootstrap CSS (npm経由で自動生成)
│ ├── js/
│ │ ├── Scoreboard.js # Vue.jsのスコアボードコンポーネント
│ │ ├── main.js # 操作パネルのVue.jsアプリケーション
│ │ ├── board.js # 表示ボードのVue.jsアプリケーション
│ │ ├── vue.global.js # Vue.js (npm経由で自動生成)
│ │ └── bootstrap.bundle.min.js # Bootstrap JS (npm経由で自動生成)
│ └── img/ # 画像ファイル
├── scripts/ # ビルド・ユーティリティスクリプト
│ ├── copy-deps.js # npm依存関係をpublic/にコピーするスクリプト
│ └── generate-init-data.js # init_data.json生成ツール
├── config/ # 設定ファイル
│ ├── init_data.json # 大会名・チーム名の初期設定ファイル
│ └── config.yaml.example # YAML設定ファイルのサンプル
├── data/ # 実行時データ
│ └── current_game.json # 試合状況の保存ファイル(自動生成)
├── doc/ # ドキュメントと画像
│ ├── ARCHITECTURE.md # システムアーキテクチャ詳細
│ ├── MASTER_SLAVE_ARCHITECTURE.md # Master/Slave制御の詳細
│ ├── PRODUCTION_DEPLOYMENT.md # 本番環境デプロイガイド
│ ├── WEBSOCKET_RECONNECTION.md # WebSocket再接続機能
│ ├── board.png # 表示ボードのスクリーンショット
│ ├── index.png # トップページのスクリーンショット
│ ├── operation.png # 操作パネルのスクリーンショット
│ └── operation_slave.png # スレーブ状態のスクリーンショット
├── logs/ # ログファイル
│ ├── pm2-error.log # PM2エラーログ(自動生成)
│ └── pm2-out.log # PM2標準出力ログ(自動生成)
├── ecosystem.config.js # PM2設定ファイル
├── server.js # WebサーバーとWebSocketサーバー
└── package.json # プロジェクト情報と依存ライブラリ
- フロントエンド:
- HTML5 / CSS3
- Bootstrap 5
- Vue.js 3
- バックエンド:
- Node.js
- ws (WebSocket ライブラリ)
- js-yaml (YAML パーサー)
前提条件: Node.jsと npm がインストールされていること。
プロジェクトのルートディレクトリで以下のコマンドを実行します。
npm installこのコマンドにより、以下が自動的に実行されます:
- 必要なnpmパッケージ(Bootstrap、Vue.js、ws、js-yamlなど)のインストール
postinstallフックによる依存ファイルの自動コピー(Bootstrap CSS/JS、Vue.jsをcss/とjs/ディレクトリへ)
サーバーは「開発モード」と「本番モード」の 2 つのモードで実行できます。
ターミナルにデバッグ用のログが出力されます。
node server.jsコンソールにServer is listening on port 8080などのメッセージが表示されれば成功です。
本番の配信などでログを非表示にする場合は、NODE_ENV環境変数をproductionに設定して起動します。
NODE_ENV=production node server.js-
トップページ:
http://localhost:8080/またはhttp://localhost:8080/index.htmlにアクセスします。 -
操作パネル:
http://localhost:8080/operation.htmlにアクセスします。 -
表示ボード:
http://localhost:8080/board.htmlにアクセスします。この URL を OBS 等のブラウザソースに設定してください。
サーバーを起動したターミナルで Ctrl + C を押すと停止します。
- 操作パネル (
http://localhost:8080/operation.html) を開く - 大会名とチーム名が正しく表示されているか確認
- 「表/裏」と「イニング」を選択して試合開始
- 得点: 「+」ボタンで加点、「-」ボタンで減点
- BSO: 各ボタンで増減、「クリア」でリセット
- ランナー: チェックボックスで出塁状態を切り替え
- 攻守交代: 表裏を切り替えて次のイニングへ
- OBSで「ソース」→「ブラウザ」を追加
- URL:
http://localhost:8080/board.html - 幅: 1920px、高さ: 1080px(または配信解像度に合わせて調整)
- 「エフェクトフィルタ」→「クロマキー」を追加
- キーカラータイプ: 緑色を選択
- スコアボードが緑色の背景なしで表示されます
別のPCから操作パネルや表示ボードにアクセスする場合(例: 操作用PCと配信用PCを分ける):
サーバーを起動しているPCで以下のコマンドを実行します:
# Linux/Mac
hostname -I
# Windows
ipconfig例: 192.168.1.100 と表示された場合
localhost をサーバーのIPアドレスに置き換えてアクセスします:
http://192.168.1.100:8080/ # トップページ
http://192.168.1.100:8080/operation.html # 操作パネル
http://192.168.1.100:8080/board.html # 表示ボード
- OBSで「ソース」→「追加」→「ブラウザ」を選択
- URLに表示ボードのアドレスを入力:
http://192.168.1.100:8080/board.html - クロマキー合成で緑色を抜く
WebSocket接続は、アクセスしたURLのホスト名を自動的に使用するため、追加の設定は不要です。
複数の端末からoperation.htmlに同時にアクセスした場合、最初に接続した端末のみが操作可能(Master)となり、後から接続した端末は閲覧専用(Slave)となります。詳細はマスター/スレーブ操作制御セクションをご覧ください。
複数のユーザーが操作パネルに同時にアクセスする場合、競合を防ぐためマスター/スレーブ制御が働きます。
- マスター (👑): 最初に接続したユーザーのみが操作可能
- スレーブ (👁️): 後から接続したユーザーは閲覧専用
- リロード時の権限維持: マスターがブラウザをリロードしても、マスター権限が維持されます(5秒以内の再接続)
- 自動昇格: マスターがタブを閉じて5秒経過すると、最も古いスレーブが自動的にマスターに昇格
- 手動解放: マスターは「🔓 マスター権限を解放」ボタンで権限を他のユーザーに明示的に譲渡可能
操作パネルのナビゲーションバーに現在の役割が表示されます:
- 👑 緑色バッジ: マスター(操作可能)
- 👁️ 黄色バッジ: スレーブ(閲覧専用)
複数のタブを開いた場合:
- 最初のタブのみがマスターになります
- 2つ目以降のタブはスレーブになります
- 各タブは独立したセッションとして扱われます
マスターがリロード(F5)した場合:
- 5秒以内に再接続すれば、マスター権限が維持されます
- セッションストレージに保存されたトークンで自動認証されます
- スレーブユーザーには影響ありません
マスターがタブを閉じた場合:
- 5秒間の猶予期間が設けられます
- 猶予期間内に再接続しない場合、次に古いスレーブユーザーが自動的にマスターに昇格します
- UIが即座に更新されます
2人での交代運用:
- マスターが「🔓 マスター権限を解放」ボタンをクリック
- 最も古いスレーブが即座にマスターに昇格
- 元マスターはスレーブに降格(意図しない切り替えを防止)
技術的詳細は doc/MASTER_SLAVE_ARCHITECTURE.md をご覧ください。
操作パネルを開いた際の初期値は config/init_data.json ファイルで設定します。このファイルは 自動生成ツール を使って簡単に作成できます。
3つの方法で init_data.json を生成できます:
対話形式で入力します:
npm run init実行例:
大会名を入力してください [現在: 大会名]: 夏季大会
試合の最終イニングを入力してください [現在: 9]: 7
参加チーム名を入力してください [入力終了: enterのみ]:
チーム 1: A
チーム 2: B
チーム 3: C
チーム 4: D
チーム 5: E
✓ 先攻チーム: A
✓ 後攻チーム: B
✓ init_data.json を生成しました
YAMLファイルを用意して生成します:
# サンプルファイルをコピー
cp config/config.yaml.example config/my-config.yaml
# 編集
nano config/my-config.yaml
# 生成
npm run init config/my-config.yamlYAMLファイルの例(config/my-config.yaml):
game_title: 夏季大会
last_inning: 7
team_names:
- A
- B
- C
- D
- E一行のコマンドで直接指定します:
npm run init -- -t "夏季大会" -i 7 --teams "A,B,C,D,E"オプション:
-t, --title <string>: 大会名(必須)-i, --innings <number>: 最終イニング(1-9、デフォルト: 9)--teams <string>: 参加チーム(カンマ区切り、必須、最低2チーム)-h, --help: ヘルプ表示
- 先攻チーム (
team_top): 参加チームの1番目 - 後攻チーム (
team_bottom): 参加チームの2番目 - イニング配列 (
game_array):["試合前", 1, 2, ..., イニング数, "試合終了"] - チーム選択肢 (
team_items):[" ", チーム1, チーム2, ...]※先頭は全角スペース
既存の config/init_data.json がある場合、自動的に config/init_data.json.bak にバックアップされます。
{
"game_title": "夏季大会",
"team_top": "A",
"team_bottom": "B",
"game_array": ["試合前", 1, 2, 3, 4, 5, 6, 7, "試合終了"],
"team_items": [" ", "A", "B", "C", "D", "E"],
"last_inning": 7
}もちろん、config/init_data.json を直接編集することも可能です。
game_title: 大会名team_top: 先攻チームteam_bottom: 後攻チームgame_array: イニング選択プルダウンの選択肢team_items: チーム名選択プルダウンの選択肢(先頭は全角スペース)last_inning: 最終イニング
操作パネルの「🔄 試合初期化」ボタンで試合状況をリセットできます。
リセットされる内容:
- イニング → 試合前(0回)
- 得点 → 両チーム0点
- BSO・ランナー → すべてクリア
維持される内容:
- チーム名と大会名(そのまま引き継がれます)
新しい大会を開始する場合:
npm run initで新しいconfig/init_data.jsonを生成- 操作パネルの「📋 新規大会で初期化」ボタンをクリック
- 新しい大会設定が読み込まれます
サーバーにアクセスできる場合:
# 保存された試合状況を削除
rm data/current_game.json
# サーバーを再起動
node server.js操作パネルを開くと config/init_data.json の初期値から開始されます。
原因と対処法:
- WebSocket接続が切断されている可能性があります
- ナビゲーションバーの接続状態インジケーターを確認してください
- ブラウザをリフレッシュ(F5キー)してください
- サーバーが起動しているか確認:
ps aux | grep node
原因:
- サーバーが停止している
- ネットワーク接続に問題がある
対処法:
- サーバーが起動しているか確認:
node server.jsまたはnpm run pm2:status - ネットワーク接続を確認
- ブラウザの開発者コンソール(F12)でエラーメッセージを確認
- 自動再接続を待つ(通常は数秒以内)
- 再接続に失敗した場合はブラウザをリロード(F5キー)
詳細は doc/WEBSOCKET_RECONNECTION.md をご覧ください。
原因:
- 最初に接続したユーザーがマスターを保持している
対処法:
- マスターユーザーに「🔓 マスター権限を解放」ボタンを押してもらう
- または、マスターユーザーがブラウザを閉じると自動的に次のユーザーがマスターに昇格
原因と対処法:
- URLが間違っている:
http://[サーバーIP]:8080/board.htmlを確認 - OBSのキャッシュ問題: ブラウザソースを削除して再作成
- ファイアウォール: サーバーのポート8080が開いているか確認
対処法:
# ポート8080を使用しているプロセスを確認
lsof -i :8080
# プロセスを終了
kill -9 <PID>
# または、PM2で管理している場合
npm run pm2:stop- システムアーキテクチャ - 技術スタック、状態管理、WebSocketプロトコル、セキュリティ
- Master/Slave アーキテクチャ - 詳細な実装、メッセージプロトコル、エッジケース、テスト手順
- WebSocket自動再接続 - 再接続アルゴリズム、実装詳細、トラブルシューティング
- 本番環境デプロイ - PM2を使った運用、モニタリング、自動起動設定、ログ管理
このプロジェクトでは、Bootstrap と Vue.js を npm 経由で管理しています。
依存ファイルを手動で再コピーする場合:
npm run build:deps依存パッケージを更新する場合:
npm update bootstrap vue詳細は doc/ARCHITECTURE.md - 依存関係の管理 をご覧ください。
このプロジェクトは以下のオープンソースソフトウェアを使用しています(すべてMITライセンス):
- Vue.js (v3.4.0+) - MIT License
- Bootstrap (v5.3.3+) - MIT License
- ws (v8.13.0+) - MIT License
- js-yaml (v4.1.0+) - MIT License
実際にインストールされるバージョンは package-lock.json をご確認ください。



