いいね、そのレイヤーに来たか。
じゃあ「Plugin → Webサーバ → Roblox」の通信を、OSレベルの正式仕様として一度きっちり言語化しよう。
全体像:レイヤーと責務
- Plugin Layer(作者のIDE層)
- ユーザー操作・UI・パラメータ編集
- 「こういう曲を生成して」と AI サーバにリクエストを送る
- Webサーバ / AI Layer(意味生成層)
- Structure / Melody / Rhythm を生成
- 最終的に Playback JSON v1 を返す
- Roblox Game Layer(物理層)
- 受け取った JSON をそのまま PlaybackEngine に渡して「鳴らすだけ」
1. 通信方向とトランスポート
- Plugin → Webサーバ
- HTTP(S)
POST /generateSong - Content-Type:
application/json
- HTTP(S)
- Webサーバ → Plugin
- 同じく HTTP レスポンスで JSON を返す
- Plugin → Roblox Game
- RemoteEvent / RemoteFunction(Roblox 標準)←直接は不可
ReplicatedStorage:WaitForChild("PlaybackRequest")など
2. Plugin → Webサーバ リクエスト仕様
エンドポイント
POST /generateSong
Request JSON(例:v1.0)
{
"version": "1.0",
"projectId": "love_dance_demo_001",
"seed": 12345,
"bpm": 128,
"lengthBeats": 128,
"style": "LoveDance",
"structure": {
"sections": [
{ "name": "Intro", "startBeat": 0, "lengthBeats": 16 },
{ "name": "A", "startBeat": 16, "lengthBeats": 32 },
{ "name": "B", "startBeat": 48, "lengthBeats": 32 }
]
},
"tracks": [
{ "role": "Lead", "instrument": "SynthLead", "enabled": true },
{ "role": "Pad", "instrument": "Pad", "enabled": true },
{ "role": "Bass", "instrument": "Bass", "enabled": true },
{ "role": "Drums", "instrument": "Drums", "enabled": true }
]
}
ポイント
- Plugin は「意味の要求」だけ送る
- BPM / 長さ / スタイル / セクション構造 / トラック構成
- 音符は 一切送らない(それは AI の責務)
3. Webサーバ → Plugin レスポンス仕様(Playback JSON v1)
Response JSON
{
"version": "1.0",
"projectId": "love_dance_demo_001",
"bpm": 128,
"tracks": [
{
"instrument": "SynthLead",
"notes": [
{ "note": 72, "velocity": 110, "startBeat": 16.0, "durationBeats": 0.5 },
{ "note": 76, "velocity": 105, "startBeat": 16.5, "durationBeats": 0.5 }
]
},
{
"instrument": "Bass",
"notes": [
{ "note": 36, "velocity": 120, "startBeat": 16.0, "durationBeats": 1.0 }
]
}
]
}
ここが OS 的に重要
- Roblox 側は この JSON だけ知っていればよい
note / velocity / startBeat / durationBeats / instrument / bpm- それ以外の意味・理論はすべて AI 側に閉じ込める
4. Plugin → Roblox Game 通信仕様
RemoteEvent 名
PlaybackRequest(例)
送るデータ構造(Lua テーブル)
local playbackData = {
version = "1.0",
bpm = songJson.bpm,
tracks = songJson.tracks
}
PlaybackRequest:FireServer(playbackData)
サーバ側受信
PlaybackRequest.OnServerEvent:Connect(function(player, playbackData)
-- ここで PlaybackEngine.playSong(playbackData, baseNote) を呼ぶだけ
end)
ポイント
- Plugin は「ただ JSON を Lua テーブルにして渡すだけ」
- Game サーバは「ただ PlaybackEngine に渡すだけ」
- 双方とも 音楽理論を一切知らない
5. バージョニングと互換性
トップレベルに version を必須
"version": "1.0"- 将来:
1.1でswing,humanize,automationなどを追加しても1.0のフィールドは壊さない
Plugin 側の方針
- 未知のフィールドは 無視
versionが想定外なら:- ログに警告
- それでも基本フィールドがあれば鳴らす
6. セキュリティ / 儀式的制約
- Plugin → Webサーバ
- APIキー or トークン(ヘッダ)
- 例:
X-Client-Id,X-Auth-Token
- Plugin → Roblox Game
- RemoteEvent は Plugin からのみ呼ぶ前提(開発用)
- 公開ゲームで使う場合は:
- サーバ側で
playerを検証 - 必要なら
projectIdとplayer.UserIdを紐づける
- サーバ側で
7. OS 的まとめ
- Structure / Melody / Rhythm / Playback の責務分離
- Structure〜Rhythm:AIサーバ
- Playback:Roblox(物理層)
- Plugin の役割
- 人間の意図 → AIリクエスト
- AIレスポンス → Roblox に橋渡し
- Roblox の役割
- 「Playback JSON v1」を受け取り、
PlaybackEngine に渡して ただ鳴らすだけ
- 「Playback JSON v1」を受け取り、
ここまでが「通信プロトコル仕様 v1.0」の骨格。
次の一手としては:
- Playback JSON v1 の正式スキーマ(擬似 JSON Schema)を書く
- Plugin UI の「プリセット → リクエスト JSON 変換表」を OS 化する
- Mixing Layer(音量・パン・FX)をどのレイヤーに置くか決める
どこから OS 図に落としていきたい?