このプログラムは、マリオカート8デラックス(MK8DX)のレース結果を自動的に取得・分析し、チームスコアを管理するNext.jsアプリケーションです。 主にMK8DX 150cc Loungeでの使用を目的としています。
- OBS WebSocketとの連携: 配信画面からスクリーンショットを自動取得
- AI画像解析: Google Gemini APIを使用してレース結果画面を自動解析
- チームスコア管理: プレイヤーをチーム別に分類し、合計得点を自動計算
- リアルタイム表示: 配信オーバーレイとして使用可能なUI
- フロントエンド: Next.js 15、React 19、TypeScript
- スタイリング: Tailwind CSS、Framer Motion
- AI分析: Google Gemini Vision API
- 配信連携: OBS WebSocket
- 状態管理: React Hooks
- フォーム管理: React Hook Form
このアプリケーションを実行するには、以下のソフトウェアがインストールされている必要があります:
-
Node.js (v18.17.0以上推奨)
- 公式サイトからLTS版をダウンロード・インストール
- インストール確認:
node --version
-
pnpm (v8.0.0以上推奨)
- Node.js インストール後、以下のコマンドでインストール:
npm install -g pnpm
- インストール確認:
pnpm --version
-
OBS Studio (v29.0以上推奨)
- 公式サイトからダウンロード・インストール
- WebSocketプラグインが内蔵されているバージョンを使用
-
マリオカート8デラックス
- Nintendo Switch
- Google Gemini API
- Google AI StudioでAPIキーを取得
Windows の場合:
# Node.js公式サイトからインストーラーをダウンロードして実行
# https://nodejs.org/
# PowerShellまたはコマンドプロンプトで確認
node --version
npm --version
### 1. 環境構築
```bash
# リポジトリをクローン
git clone <your-repository-url>
cd mk8dx-bot
# 依存関係をインストール
pnpm install
# 環境変数を設定
cp .env.example .env.local- Google AI StudioでAPIキーを取得
.env.localに設定:
GEMINI_API_KEY=your_gemini_api_key- OBSで「ツール」→「WebSocketサーバー設定」を開く
- WebSocketサーバーを有効化
- 認証を設定し、
.env.localに追加:
# OBS WebSocket設定
OBS_IP=localhost
OBS_PASSWORD=your_obs_password
OBS_SOURCE_NAME=ウィンドウキャプチャ
# Google Gemini API
GEMINI_API_KEY=your_gemini_api_keyOBS設定の詳細:
OBS_IP: OBSが動作しているPCのIPアドレス(同一PCの場合はlocalhost)OBS_PASSWORD: OBS WebSocketサーバーで設定したパスワードOBS_SOURCE_NAME: スクリーンショットを取得するOBSソース名- 例:
ウィンドウキャプチャ,画面キャプチャ,Game Captureなど - OBSのソース一覧で確認できる名前を正確に入力してください
- キャプチャボードから認識する場合は
映像キャプチャデバイス
- 例:
# 開発サーバー起動
pnpm dev
# 本番ビルド
pnpm build
pnpm start-
OBS設定
- MK8DXのゲーム画面をOBSでキャプチャ
- キャプチャソース名を
.env.localのOBS_SOURCE_NAMEに設定 - レース結果画面が見える状態にする
-
アプリケーション操作
- ブラウザソースに
http://localhost:3000を入力 - 対話(操作)から「レース結果を取得」または「チーム合計点を取得」ボタンをクリック
- プレビューを操作しボタンが見えない大きさと位置に移動
- アプリが自動的にOBSからスクリーンショットを取得し、AI分析を実行
- ブラウザソースに
-
チームスコア管理
- レース結果が自動的にチーム別に分類される
- 各レースの得点が累積される
- 「チーム合計点を取得」で総合結果を更新可能
正確なレース結果を取得するために、以下のタイミングでボタンを押してください:
最適なタイミング: レース結果画面が完全に表示された瞬間
注意点:
- ✅ 良いタイミング: 順位とプレイヤー名が完全に表示されている
- ✅ 良いタイミング: 得点が全て表示されている
- ❌ 悪いタイミング: アニメーション中や読み込み中
- ❌ 悪いタイミング: 画面が切り替わっている最中
※事前に撮影したスクリーンショットを映しても大丈夫です。
最適なタイミング: 総合結果画面(累積得点画面)が表示された瞬間
注意点:
- ✅ 良いタイミング: 全プレイヤーの累積得点が表示されている
- ✅ 良いタイミング: 順位が確定している状態
- ❌ 悪いタイミング: レース途中の結果画面
- ❌ 悪いタイミング: 画面が不鮮明な状態
- URLを配信ソフトのブラウザソースとして追加
- リアルタイムでスコアが更新される透明なオーバーレイとして機能
src/app: Next.js App Routerのページとレイアウトsrc/components: 再利用可能なUIコンポーネントsrc/hooks: カスタムReactフック(useTeamScoreListなど)src/constants: 設定値とプロンプト定義src/infra: 外部API連携(gemini.ts、firebase.tsなど)src/types: TypeScript型定義
src/app/page.tsx: メインページsrc/app/api/fetch-race-results/route.ts: Gemini API連携(総合スコア取得)src/app/api/obs/route.ts: OBS WebSocket連携src/hooks/useTeamScoreList.ts: スコア管理ロジックsrc/constants/prompt.ts: AI分析用プロンプト
総合スコア画面から全プレイヤーの累積得点を取得するAPIエンドポイント。
POST /api/fetch-race-results?useTotalScore=true
Content-Type: application/json
{
"imageUrl": "data:image/png;base64,..."
}// 成功時
{
"success": true,
"response": {
"results": [
{
"id": "string",
"rank": number,
"name": "プレイヤー名",
"team": "チーム名",
"score": number,
"addedScore": 0,
"isCurrentPlayer": boolean
}
]
}
}
// エラー時
{
"success": false,
"error": "エラーメッセージ"
}- 共通接尾辞検出: 複数プレイヤー名の末尾に共通単語がある場合に抽出
- 共通接頭辞検出: 複数プレイヤー名の先頭に共通単語がある場合に抽出
- フォールバック: 共通パターンがない場合は名前の最初の1文字を使用
- プレイヤー行の背景色(黄色系)を分析
- 透明度や色の混合を考慮した判別ロジック
-
OBS接続エラー
- OBS WebSocketサーバーが有効になっているか確認
- IPアドレスとパスワードが正しいか確認
- ソース名が正確か確認: OBSのソース一覧で表示される名前と
OBS_SOURCE_NAMEが一致しているか確認
-
スクリーンショット取得エラー
- 指定したソース名がOBSに存在するか確認
- ソース名に全角文字や特殊文字が含まれている場合は、正確にコピーして設定
-
Gemini API エラー
- APIキーが正しく設定されているか確認
- API利用制限に達していないか確認
-
画像認識の精度
- レース結果画面が鮮明に表示されているか確認
- 他の画面要素が重なっていないか確認
| エラーコード | 原因 | 対処法 |
|---|---|---|
| 400 | imageUrlが未指定 | リクエストボディにimageUrlを含める |
| 429 | API利用制限 | 時間を置いて再試行 |
| 500 | 画像解析失敗 | 画面が正しく表示されているか確認 |
- 得点システム:
src/constants/mk8dx.tsで順位別得点を変更可能 - AI分析精度: プロンプトを調整してより高精度な認識を実現
- UI: Tailwind CSSクラスで見た目をカスタマイズ
主要な型はsrc/types/index.tsで定義されています:
interface TeamScore {
id: string;
rank: number;
name: string;
team: string;
score: number;
addedScore: number;
isCurrentPlayer: boolean;
}
interface RaceResult {
name: string;
team: string;
score: number;
isCurrentPlayer: boolean;
}AI分析の精度向上のため、以下の要素を含むプロンプトを使用:
- 具体的な指示: JSONフォーマットの明確な指定
- ルールベース: チーム名判別の優先順位を明記
- エラーハンドリング: 認識できない場合の代替動作
- 文脈理解: MK8DXの画面構成に特化した説明
MIT License
プルリクエストや Issue の報告を歓迎します。
質問や問題がある場合は、Issuesでお知らせください。
このプログラムはmk8dx-botから着想を得ました。 Thanks keisuke071411 !



