1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ヘッドレスの Ubuntu 26.04 で、AI(Claude Code)に Roblox のゲームを作らせる

1
Posted at

はじめに

※この記事はClaude Codeに書いてもらいました。人間には読みにくいかも知れませんが、同じことをAIにやって欲しい時に、この記事を渡すと上手く使ってくれて手戻り少なく作業してくれるのではと思います。

モニターもデスクトップ環境もない Linux サーバーで Roblox Studio を動かします。そのサーバーに Claude Code を常駐させ、スマホやブラウザから Remote Control で指示を出して、AI に Roblox のゲームを作らせます。AI はコードを書くだけでなく、Studio でのテストプレイ、画面の確認、Publish まで自分で回します。

使うのは次のとおりです。

  • Roblox Studio を動かす側: Vinegar(Flatpak)、その標準の Wine「kombucha」、ヘッドレスの sway、wayvnc
  • AI 側: Claude Code CLI の Remote Control(systemd で常駐)

この記事は、実際にこの環境で人間の指示のもとAIが Roblox のゲーム(空戦シューティング)を 1 本作り、PS5 で遊べるところまで運用した記録をもとにしています。途中で踏んだ不具合と回避策もまとめました。

この記事でできること

  • 画面のないサーバー上で Roblox Studio(Windows 版)を GPU 描画で動かす。テストプレイは毎秒 60 フレーム
  • Claude Code をサーバーに常駐させ、スマホの Claude アプリや claude.ai から指示を出す
  • AI が Luau のコードを書き、Studio のプレイスへ自動で同期し、テストプレイして結果をログと画面で確かめる
  • AI が Studio を操作して Publish する。人がやるのはログインと、実機(PC・PS5 など)での遊び心地の確認だけ
  • 必要なときは、手元の PC から SSH トンネル経由の VNC で Studio の画面を見る

全体の構成

名前が roblox- や claude-rc@ で始まるものは、systemd のユーザーサービスです。

ポイントは次の 4 つです。

  1. Wine は Vinegar 標準の kombucha を使う。 Studio 向けの修正が入っています。ただしヘッドレス環境では、環境変数を 1 つ足さないと起動しません(「ハマりどころ 1」)。
  2. 画面はヘッドレスの sway(Wayland)にし、Studio は Xwayland 上で X11 として動かす。 Xvfb でも動きますが、GPU を使えないため遅く、不安定でした。
  3. Claude Code は claude remote-control を systemd で常駐させる。 外向きの HTTPS だけで動くので、サーバーのポートを開ける必要はありません。
  4. AI が Studio を「見て・触れる」道具をそろえる。 キー入力(xdotool)、画面の取得、ログの読み方、コードの同期、ゲームに組み込んだ自動テストです。

検証した環境

項目 バージョンなど
OS Ubuntu 26.04.1 LTS(カーネル 7.0)、デスクトップなし
CPU / GPU AMD Ryzen 7 PRO 3700U(Radeon Vega、amdgpu)、メモリ 13 GB
Mesa 26.0.8
sway / wayvnc / Xwayland 1.11 / 0.9.1 / 24.1.10
Flatpak 1.16.6
Vinegar 1.9.4(Flathub、ランタイム org.gnome.Platform 50)
Wine kombucha stable+20261009201837(Wine 11.19 ベース)
Roblox Studio 0.743
Claude Code 2.1.282(ネイティブインストーラー)
補助ツール Luau 0.743(構文チェック)、Playwright 1.62(Chromium)、python-xlib、Pillow

作業用には専用の Linux ユーザー(この記事では claude)を用意しています。AI はこのユーザーの権限で動きます。sudo の権限は与えていません。

第 1 部 Roblox Studio を動かす

1. パッケージを入れる

管理者権限が必要なのはここだけです。

sudo apt install flatpak sway wayvnc xwayland wl-clipboard xdotool python3-venv

作業ユーザーが GPU のデバイスを使えるようにします。/dev/dri/renderD128 は render グループのものです。

sudo usermod -aG render,video "$USER"

ログインしていない間も systemd のユーザーサービスを動かしたいので、lingering を有効にします。

sudo loginctl enable-linger "$USER"

2. Vinegar を入れる

Flathub をユーザー単位で追加し、Vinegar を入れます。

flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install --user -y flathub org.vinegarhq.Vinegar

Vinegar は、初回起動時に Studio 本体と kombucha(Wine)をダウンロードし、Wine 環境(prefix)を作ります。起動はこのあと sway を用意してから行います。

3. ヘッドレス sway を用意する

sway の設定 ~/.config/sway-roblox/config を作ります。Studio の本体は画面いっぱいに並べ、ダイアログは sway に自動で浮かせます。

output HEADLESS-1 resolution 1920x1080 position 0 0 bg #202830 solid_color
default_border none
default_floating_border normal 2
focus_follows_mouse no
xwayland enable

最初は「Studio のウィンドウを全部浮動表示にする」ルールを入れていました。すると描画位置がずれたので、外しています。

systemd のユーザーサービス ~/.config/systemd/user/roblox-sway.service を作ります。

[Unit]
Description=Headless sway (Wayland) for Roblox Studio via Vinegar/kombucha

[Service]
Type=simple
Environment=WLR_BACKENDS=headless
Environment=WLR_HEADLESS_OUTPUTS=1
Environment=WLR_LIBINPUT_NO_DEVICES=1
Environment=WLR_RENDERER=gles2
Environment=WLR_RENDER_DRM_DEVICE=/dev/dri/renderD128
ExecStart=/usr/bin/sway -c %h/.config/sway-roblox/config
Restart=on-failure
RestartSec=3

[Install]
WantedBy=default.target
  • WLR_BACKENDS=headless を指定すると、モニターがなくても仮想の出力(HEADLESS-1)を 1 つ作ります。
  • WLR_LIBINPUT_NO_DEVICES=1 を指定すると、入力デバイスがなくても起動します。キーボードとマウスの入力は VNC と xdotool から入れます。
  • WLR_RENDER_DRM_DEVICE には GPU の render ノードを指定します。

起動すると、Wayland のソケット wayland-1 と、Xwayland の :0 ができます。

4. wayvnc で画面を共有する

~/.config/wayvnc/config を作ります。

address=127.0.0.1
port=5999
enable_auth=false

認証をなしにしている代わりに、このマシン内(127.0.0.1)からの接続しか受け付けません。外からは SSH トンネルを通して使います。

~/.config/systemd/user/roblox-wayvnc.service を作ります。

[Unit]
Description=wayvnc for the headless sway (127.0.0.1:5999, no auth)
Requires=roblox-sway.service
After=roblox-sway.service

[Service]
Type=simple
Environment=WAYLAND_DISPLAY=wayland-1
ExecStartPre=/bin/sh -c 'for i in $(seq 50); do [ -S "$XDG_RUNTIME_DIR/wayland-1" ] && exit 0; sleep 0.2; done; exit 1'
ExecStart=/usr/bin/wayvnc --config %h/.config/wayvnc/config
Restart=on-failure
RestartSec=3

[Install]
WantedBy=default.target

起動します。

systemctl --user daemon-reload
systemctl --user start roblox-sway roblox-wayvnc

手元から接続するときは SSH でポートを転送し、VNC クライアントで 127.0.0.1:5999 に接続します。

ssh -L 5999:127.0.0.1:5999 user@server

MobaXterm なら、VNC セッションの Remote hostname を 127.0.0.1、Port を 5999 にします。そのうえで「SSH gateway (jump host)」にサーバーを指定すると、トンネルを自動で張ってくれます。

5. Vinegar(kombucha)の設定

~/.var/app/org.vinegarhq.Vinegar/config/vinegar/config.toml を作ります。

[studio.env]
XDG_SESSION_TYPE = "wayland"

これがないと、kombucha は「no driver could be loaded」で起動しません。理由は「ハマりどころ 1」で説明します。

続けて、Wine のグラフィックドライバーを X11(winex11)に固定します。kombucha には Wayland ドライバーもありますが、kombucha 自身が「experimental, please use winex11」と警告しているとおり、Studio はこのドライバーでは落ちました。

DISPLAY=:0 flatpak run --command=sh org.vinegarhq.Vinegar -c '
export WINEPREFIX=$HOME/.var/app/org.vinegarhq.Vinegar/data/vinegar/prefixes/studio
K=$HOME/.var/app/org.vinegarhq.Vinegar/data/vinegar/kombucha
$K/bin/wine reg add "HKCU\\Software\\Wine\\Drivers" /v Graphics /d x11 /f
$K/bin/wineserver -w'

prefix と kombucha は Vinegar の初回起動で作られます。まだ無い場合は、先に一度 Studio を起動して閉じてから実行してください。

6. Studio を起動する

起動スクリプト ~/roblox/start-studio-wl.sh を作ります。

#!/bin/sh
exec env DISPLAY=:0 WAYLAND_DISPLAY=wayland-1 XDG_SESSION_TYPE=wayland \
  flatpak run org.vinegarhq.Vinegar "$@" >> "$HOME/roblox/studio-wl.log" 2>&1
chmod +x ~/roblox/start-studio-wl.sh
~/roblox/start-studio-wl.sh &

VNC で見ると Studio が立ち上がっているはずです。ログは次の場所に出ます。

  • Vinegar のログ: ~/.var/app/org.vinegarhq.Vinegar/cache/vinegar/logs/
  • Studio のログ: ~/.var/app/org.vinegarhq.Vinegar/data/vinegar/appdata/Roblox/logs/*Studio*.log

7. ログインする

ここが一番の難所です。Studio 内蔵のログイン画面(WebView2)は、Wine 上だと表示はされてもキーボード入力を受け付けません。Quick Sign-in も失敗しました。そこで「Login via Browser」を使い、外部ブラウザでログインします。

流れは次のとおりです。

7-1. Wine が開く URL をホスト側へ渡す

Flatpak の中から直接ホストのブラウザは起動できないので、ファイルを介して渡します。まず ~/.var/app/org.vinegarhq.Vinegar/data/open-url.sh を作ります。Flatpak の中からも見える場所に置く必要があります。

#!/bin/sh
printf '%s\n' "$1" >> "$HOME/.var/app/org.vinegarhq.Vinegar/cache/open-url.txt"

Wine の winebrowser がこのスクリプトを使うよう、レジストリに登録します。

flatpak run --command=sh org.vinegarhq.Vinegar -c '
export WINEPREFIX=$HOME/.var/app/org.vinegarhq.Vinegar/data/vinegar/prefixes/studio
$HOME/.var/app/org.vinegarhq.Vinegar/data/vinegar/kombucha/bin/wine reg add \
  "HKCU\\Software\\Wine\\WineBrowser" /v Browsers \
  /d "$HOME/.var/app/org.vinegarhq.Vinegar/data/open-url.sh" /f'

7-2. ホスト側で Chromium を開く

~/roblox/url-bridge.sh を作ります。

#!/bin/sh
F="$HOME/.var/app/org.vinegarhq.Vinegar/cache/open-url.txt"
[ -s "$F" ] || exit 0
URL=$(tail -n 1 "$F"); : > "$F"
export DISPLAY=:0
export XDG_DATA_DIRS="$HOME/.local/share/flatpak/exports/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
setsid -f /path/to/chrome \
  --no-sandbox --disable-gpu --user-data-dir="$HOME/roblox/browser-profile" --no-first-run \
  --window-size=1100,900 "$URL" >/dev/null 2>&1
  • Chromium には、Playwright が入れたもの(~/.cache/ms-playwright/chromium-*/chrome-linux64/chrome)を使いました。Ubuntu の chromium パッケージは snap 版です。
  • --no-sandbox を付けているのは、Ubuntu の AppArmor が非特権ユーザー名前空間を制限していて、サンドボックスを作れないためです。ログイン専用の使い捨てプロファイルに限って使い、ログインが終わったら browser-profile を削除します。
  • XDG_DATA_DIRS に Flatpak の exports を足しているのは、Chromium が次の手順の関連付けを見つけられるようにするためです。

このスクリプトを、ファイルが書き換わったときに走らせます。roblox-url-bridge.path を作ります。

[Unit]
Description=Open URLs requested by Roblox Studio in Chromium

[Path]
PathModified=%h/.var/app/org.vinegarhq.Vinegar/cache/open-url.txt

[Install]
WantedBy=default.target

roblox-url-bridge.service も作ります。

[Unit]
Description=Open the last URL requested by Roblox Studio in Chromium

[Service]
Type=oneshot
ExecStart=%h/roblox/url-bridge.sh
# 起動した Chromium はサービス終了後も残す
KillMode=process

最初は Type=simple にしていました。するとサービスが動作中のまま残り、2 回目以降の URL が開かれませんでした。oneshot と setsid に変えて直しています。

7-3. roblox-studio-auth:// を Vinegar に関連付ける

xdg-mime default org.vinegarhq.Vinegar.desktop x-scheme-handler/roblox-studio-auth
xdg-mime default org.vinegarhq.Vinegar.desktop x-scheme-handler/roblox-studio

7-4. デスクトップポータルに DISPLAY を渡す

デスクトップセッションがないと、xdg-desktop-portal-gtk が起動に失敗し、Vinegar が応答を約 1 分待ちます。その間に、ブラウザから渡した認証コードの期限が切れてしまいます。ポータルに画面を渡しておきます。

~/.config/systemd/user/xdg-desktop-portal-gtk.service.d/display.conf を作ります。

[Service]
Environment=DISPLAY=:0
systemctl --user daemon-reload
systemctl --user enable --now roblox-url-bridge.path
systemctl --user restart xdg-desktop-portal-gtk

7-5. ログインする

  1. Studio のログイン画面で「Login via Browser」を押す
  2. VNC 上に Chromium が開くので、Roblox にログインする(パスワードは本人が入力する)
  3. 「Studio を開く」の確認が出たら許可する
  4. Studio にログイン状態が反映される

ログイン後の最初の Studio が固まったことがありました。そのときは Studio を再起動すると、以後は自動でログインされました。終わったら rm -rf ~/roblox/browser-profile でブラウザのプロファイルを消します。

第 2 部 Claude Code を常駐させ、スマホから指示する

8. Claude Code を入れてログインする

作業ユーザーで、Claude Code のネイティブインストーラーを実行します。~/.local/bin/claude に入ります。

curl -fsSL https://claude.ai/install.sh | bash

一度対話モードで起動し、/login で claude.ai のアカウントでログインします。Remote Control は claude.ai のサブスクリプションでのログインが必要です。ANTHROPIC_API_KEY や、claude setup-token で作る長期トークンでは使えません。

cd /srv/work/mygame        # ゲームのリポジトリ
claude                     # /login でログインし、このディレクトリを信頼する(Trust)

claude remote-control は、まだ信頼していないディレクトリでは Trust <directory>? [y/N] と確認します。systemd から起動すると確認に答えられずに止まるので、最初に一度、端末から対話的に起動して信頼しておきます。初回は Remote Control を有効にするかの確認(Enable Remote Control? (y/n))も出ます。

9. AI に許す操作を決める

~/.claude/settings.json で、AI が確認なしに使ってよい道具を決めます。この環境では次のようにしました。

{
  "permissions": {
    "allow": ["Bash", "Edit", "Read", "WebFetch", "WebSearch"],
    "defaultMode": "default"
  }
}

Studio の操作も、ビルドも、ログの確認もすべてシェル経由なので、Bash を許可しないと、スマホから一つずつ承認することになり実用になりません。その代わり、次の歯止めをかけています。

  • AI は専用ユーザーで動かし、sudo は与えない。パッケージの追加など管理者の作業は、人が行う
  • VNC など、AI が立ち上げるサービスは 127.0.0.1 でだけ待ち受ける
  • Roblox のパスワードは AI に扱わせない。ログインは人が VNC 上のブラウザで行う
  • 「Publish してよい条件」などのルールを、最初に言葉で決めて伝える(第 4 部)

10. Remote Control を systemd で常駐させる

プロジェクトごとに 1 つ動かせるよう、テンプレートユニット ~/.config/systemd/user/claude-rc@.service を作ります。%i がプロジェクト名(/srv/work/ の下のディレクトリ名)になります。

[Unit]
Description=Claude Code Remote Control (%i)

[Service]
WorkingDirectory=/srv/work/%i
ExecStart=%h/.local/bin/claude remote-control --name "%i"
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

起動直後はネットワークがまだ使えず失敗することがあったので、名前解決できるまで待つ drop-in を足しています(~/.config/systemd/user/claude-rc@.service.d/wait-net.conf)。

[Service]
ExecStartPre=/bin/sh -c 'until getent hosts api.anthropic.com >/dev/null; do sleep 2; done'
TimeoutStartSec=300

有効にします。第 1 部の手順 1 で lingering を有効にしてあるので、ログインしていなくても動き続けます。

systemctl --user daemon-reload
systemctl --user enable --now claude-rc@mygame

claude remote-control は、Anthropic の API へ外向きの HTTPS で接続し、指示を待ちます。サーバー側で受け付けるポートは開けません。SSH 接続が切れても止まらないよう、端末ではなく systemd で動かしているのが要点です。

11. スマホやブラウザから接続する

claude.ai/code か、Claude アプリ(iOS / Android)のセッション一覧に、--name で付けた名前(mygame など)のセッションが出ます。それを開けば、サーバー上の Claude Code に指示を出せます。

  • 会話はサーバー上の Claude Code で処理され、ファイルの編集やコマンドの実行もサーバー上で行われます
  • スマホから画像やファイルも送れます。Studio のエラー画面のスクリーンショットや、PS5 で撮った写真を送って直してもらう、といった使い方ができます
  • AI が作った画像(サムネイルなど)は、サーバー上のファイルとして残ります。手元に持ってくるときは SSH(SFTP)で取り出します

第 3 部 AI が Studio を扱えるようにする

AI は画面を直接見られず、マウスも持っていません。そこで「入力する」「見る」「結果を読む」をすべてコマンドでできるようにします。

12. 入力・画面取得・ログ

やりたいこと 方法
キーボード・マウス DISPLAY=:0 xdotool ...(Xwayland に直接入れる)
画面の取得 python-xlib で Xwayland のウィンドウを直接取得する(下記)
ウィンドウの配置 swaymsg(ソケットは /run/user/$UID/sway-ipc.*.sock)。複数のウィンドウは layout tabbed
日本語の入力 X の CLIPBOARD に文字列を置いてから Ctrl+V で貼る
Luau の実行 Studio のコマンドバーに入力して Ctrl+Enter(Enter は改行)
結果を読む Studio のログの [FLog::CreatorOutput] の行に print の出力が出る

Studio のログは ~/.var/app/org.vinegarhq.Vinegar/data/vinegar/appdata/Roblox/logs/*Studio*.log です。Studio のウィンドウごとに別のファイルになるので、ls -t の先頭が作業中のウィンドウのものとは限りません。

画面の取得は、VNC 経由(vncdo capture)だと古いフレームが返ることがよくありました。Xwayland から直接取るほうが確実です。

# xshot.py: Xwayland(:0) の、いま前面のウィンドウを PNG で保存する
import sys, subprocess
from Xlib import display, X
from PIL import Image
d = display.Display(':0')
wid = int(sys.argv[2]) if len(sys.argv) > 2 else int(subprocess.check_output(
    ['xdotool', 'getactivewindow'], env={'DISPLAY': ':0'}).strip())
w = d.create_resource_object('window', wid)
g = w.get_geometry()
img = w.get_image(0, 0, g.width, g.height, X.ZPixmap, 0xffffffff)
Image.frombytes('RGB', (g.width, g.height), img.data, 'raw', 'BGRX').save(sys.argv[1])

メニューやダイアログは別のウィンドウになるので、xdotool search --name ... で ID を調べて 2 つ目の引数に渡します。AI は撮った PNG を読んで(画像を理解できます)、ボタンの位置を判断したり、HUD の見え方を確かめたりします。

Python の道具は venv にまとめておきます。

python3 -m venv ~/tools/venv
~/tools/venv/bin/pip install python-xlib pillow playwright vncdotool
~/tools/venv/bin/playwright install chromium

13. Luau の構文チェック

Studio に送る前に、Luau のコマンドラインツールで構文を確かめます。AI は書き換えるたびにこれを回します。

~/roblox/bin/luau-compile --binary src/client/Main.client.luau > /dev/null && echo ok

14. スクリプトを Studio へ同期する

最初は Rojo(rojo serve と Studio プラグイン)を使いました。しかし Wine 上の Studio では、プラグインの WebSocket 接続が切れ、再接続のためにパネルを操作すると Studio が落ちました。そこで次の構成に置き換えています。

  • ホスト側: Python の小さな HTTP サーバー(127.0.0.1:34873、roblox-acsync.service)。ソースのフォルダをまとめて JSON で返す /bundle と、変更検知用のハッシュを返す /hash を持つ
  • Studio 側: ローカルプラグイン。編集モードのときだけ 1.5 秒ごとに /hash を確かめ、変わっていたら /bundle を取ってスクリプトを作成・更新・削除する。結果を [ACSync] ... created= updated= removed= とログに出す

これで AI は「ファイルを書き換える → ログに [ACSync] の行が出るのを待つ」だけで、Studio にコードを反映できます。ファイル名の規則(.server.luau / .client.luau)は Rojo と同じにしてあります。

注意点が 2 つあります。

  • プラグインの置き場所: Studio が実際に読むローカルプラグインのフォルダは、Wine 環境の中の drive_c/users/<user>/AppData/Local/Roblox/Plugins です。Vinegar の appdata/Roblox/Plugins ではありません。
  • HTTP 通信はプラグインで行う: コマンドバーから HttpService を使うと、プレイスの HttpEnabled 設定に縛られます。プラグインならその制限を受けません。

15. ゲームに自動テストを組み込む

AI がテストプレイの結果を判断できるよう、ゲーム側に「自動操縦」と「状態のログ」を組み込みます。切り替えは workspace の属性で行い、Studio のコマンドバーから設定します。

workspace:SetAttribute("ACAutoTest", true)   -- 自動操縦で遊ぶ

自動操縦中は、2 秒ごとに状態を 1 行で print します。

[AC] stat t=27 fps=60.0 play wave=3 kills=14 score=14000 shots=41 hits=9 msl=14/58 ... nearMsl=12.8 nearBullet=8.6 safety=0

AI は Play ボタンを押して、ログをこの行が出るまで監視し、数字で判断します。この例では「毎秒 60 フレームか」「敵弾が必ず外れているか(nearMsl / nearBullet)」を見ています。クリアしたら [AC] clear rank=S time=36 ... を出し、5 秒後に自動で再開します。

ほかにも、用途ごとに属性を足しました。

  • 撃たずに飛び回る(敵に撃たせ続け、接待の仕組みを確かめる)
  • 機動を順に試し、機動ごとの角度の変化をログに出す
  • HUD を隠して後方視点にする(サムネイル撮影用)
  • ゲームパッドの操作案内を強制表示する(ゲームパッドのない Studio で確認するため)

Publish の前には、AI が属性をすべて nil に戻します。

テスト用の入力には注意点があります。自動操縦が「決定」を押しっぱなしにすると「押した瞬間」にならず、タイトル画面から進みませんでした。押す・離すを交互に入れるようにしています。

16. Publish する

AI は File メニューから Publish します。メニューは別ウィンドウなので、画面を取得して項目の位置を確かめてからクリックします。結果は Studio のログの Published new changes in "..." to Roblox. で判断します。

Rojo で組み立てた .rbxl から既存のプレイスへ上書き Publish すると、publishAs が始まったあと何も起きずに止まります。 通常版の Wine でも kombucha でも同じでした。Studio 自身のテンプレートから作ったプレイス(File → New → Baseplate)に、スクリプトだけを同期して Publish すると成功しました。以後は Studio で作ったプレイスを「器」として使っています。

17. Creator Hub の設定も AI に任せる

アイコンやサムネイルの登録、サーバーの最大人数などは Creator Hub(Web)で設定します。人が VNC 上の Chromium でログインしたあと、AI がそのブラウザを Playwright で操作しました。

  1. AI が Chromium を --remote-debugging-port=9333 --remote-debugging-address=127.0.0.1 付きで開く
  2. 人が VNC で入り、ログインする(パスワードは人だけが扱う)
  3. AI が Playwright の connect_over_cdp("http://127.0.0.1:9333") でつなぎ、ページを開いて設定する。画像のアップロードも set_input_files でできる
  4. 終わったら AI がブラウザを閉じ、プロファイルを削除する

第 4 部 AI との作業の進め方

道具がそろっても、進め方を決めないと AI は暴走しがちです。うまくいったやり方をまとめます。

18. 最初に決めて、言葉で伝えたこと

  • 作るものの範囲: 「元にした HTML 版と同じ内容」「1 人用」
  • 段階に分ける: 段階 0(開発基盤)→ 1(最小版)→ 2(ゲームの中身)→ 3(HUD)→ 4(操作感)→ 5(演出)→ 6(効果音)→ 7(仕上げ)。段階ごとに「完了の条件」を決める
  • Publish のルール: 「各段階の終わりの Publish はしてよい。ただし必ず Studio で動作確認してから」
  • 人の役割: ログインと、実機(Windows・PS5)で遊んで確かめること。ゲームバランスや見た目の好みの判断

19. 記録を AI と共有する

AI は会話が長くなると前のことを要約して忘れていくので、リポジトリに記録を残させます。

  • 計画書(PLAN.md): 段階の表と状態(「Studio で確認済み・Publish 済み・ユーザー確認待ち」など)。段階ごとに「分かったこと」「確認の結果(数字)」を追記させる
  • 手順書(README.md): 環境の構成、Studio の操作のしかた、回避策、テスト用の属性の一覧。次に作業するときの AI が最初に読む
  • Claude Code のメモリ: 「Publish は Studio で確認してから」のような、守ってほしい方針は Claude Code のメモリにも書かせておく

段階が終わるたびに git にコミットさせると、どこで何が変わったかを追えます。

20. AI にできないこと

  • 音を聞くこと: 効果音は名前で選ぶしかありません。合うかどうかは人が聞いて判断します
  • 実機での確認: PS5 のコントローラーや、テレビでの見え方、重さは、人が遊んで伝えます
  • ログイン: 2 要素認証の設定を変えると Studio のログインも切れます。そのときは人がもう一度ログインします

ハマりどころ

1. kombucha が「no driver could be loaded」で起動しない

kombucha には「X11 セッションではカーソルを隠さない」という独自パッチ(0017)があります。このパッチが X11 ドライバーの初期化中に strcmp(getenv("XDG_SESSION_TYPE"), "wayland") を NULL チェックなしで呼んでいます。デスクトップセッションのないサーバーではこの変数がないため、初期化が失敗し、ドライバーを読み込めずに終わります。

LD_DEBUG で kombucha と通常版 Wine の読み込みの様子を比べて、原因を突き止めました。XDG_SESSION_TYPE を設定すれば直ります(手順 5、6)。

当初はこれを「kombucha と Xvfb の相性」と誤解し、通常版 Wine(wineroot 設定)に逃げていました。通常版 Wine では、Team Create のプレイスを開いたとき、Publish の直後、Rojo のパネル操作のときに、Studio が Qt5Core.dll 内で落ちていました。kombucha に戻してからは一度も起きていません。

2. Xvfb では DXVK の画面が出ない、遅い

最初の構成は Xvfb + openbox + x11vnc でした。Xvfb には GPU がないので、MESA_VK_WSI_DEBUG=sw で表示を回避する必要があり、編集画面もテストプレイも毎秒 40 フレーム前後でした。ヘッドレス sway なら GPU で描画でき、毎秒 60 フレーム出ます。

3. 自動復元ダイアログが空のまま、画面の操作をふさぐ

Studio が異常終了したあとに出る「自動復元」のダイアログは、中身が描画されません。それでいてメイン画面への入力を受け付けなくなります。起動前に appdata/Roblox/RobloxStudio/AutoSaves/ の復元ファイルを別の場所へ移しておきます。

4. 同じアカウントの Team Create には 1 台しか入れない

手元の Windows の Studio と、サーバーの Studio の両方から、同じアカウントで同じ Team Create のプレイスに入ることはできません。後から入った方が入ると、先にいた方が切断されます(RCC-276)。Roblox 側の仕様です。

5. 入力まわりの癖

  • xdotool の日本語入力は文字化けする → クリップボード経由で貼る
  • vncdo のキー入力は、Shift が必要な記号(括弧など)が落ちる → xdotool を使う
  • この環境では I キーが KeyCode.None として届き、O キーは届かなかった → テストでは別のキーで代用した(実機の Windows では問題なし)
  • ゲーム側でキーの押下状態を毎フレーム調べる方式だと、短く押したキーを取りこぼす → ContextActionService のイベントで「押した瞬間」を記録する

6. pkill -f で自分のシェルを殺す

pkill -f Roblox のようなパターンは、それを実行している自分のシェルのコマンドラインにも一致します。pkill -x を使うか、flatpak kill org.vinegarhq.Vinegar を使います。

7. AI 向けの環境の癖

  • VNC の画面は古いことがある: vncdo capture は古いフレームを返すことが多く、AI が状況を見誤りました。Xwayland から直接取ります(手順 12)
  • 短いキー入力の取りこぼし: ゲーム側で、キーの押下状態を毎フレーム調べる方式だと、xdotool の短い押しを取りこぼしました。ContextActionService のイベントで「押した瞬間」を記録する方式にしています。人が速く押したときの取りこぼしもなくなります
  • ウィンドウの位置は変わる: sway のタブ表示のときと、ウィンドウが 1 つのときでは、Studio の座標が 25 ピクセルずれます。メニューも開くたびに位置を確かめます
  • ゲームパッドがない: Studio にはゲームパッドがつながっていないので、コントローラー用の表示は属性で強制して確かめます。実際のボタンの効き具合は実機で確認します

性能

AMD Ryzen 7 PRO 3700U 内蔵の Radeon Vega での結果です。

構成 編集画面 テストプレイ
Xvfb + 通常版 Wine(ソフトウェア表示) 約 40 fps 約 39 fps
ヘッドレス sway + kombucha(GPU) 60 fps 60 fps

テストプレイの中身は、約 12,000 個の WedgePart でできた地形、粒子の雲や煙、HUD を持つゲームです。

止める・再開する

止めるとき:

flatpak kill org.vinegarhq.Vinegar
systemctl --user stop roblox-url-bridge.path roblox-acsync roblox-wayvnc roblox-sway
systemctl --user disable roblox-url-bridge.path roblox-acsync
# AI も止めるなら
systemctl --user stop claude-rc@mygame

再開するとき:

systemctl --user start roblox-sway roblox-wayvnc roblox-acsync roblox-url-bridge.path
~/roblox/start-studio-wl.sh &

ログイン状態は Wine 環境に残るので、再開後にログインし直す必要はありませんでした。

まとめ

  • ヘッドレス Linux でも、Vinegar + kombucha + ヘッドレス sway(Xwayland)+ wayvnc の組み合わせなら、Roblox Studio を GPU 描画で実用的に動かせます。
  • kombucha は XDG_SESSION_TYPE を設定しないと起動しません。デスクトップのないマシンで一番はまりやすい点です。
  • ログインは、内蔵画面をあきらめて 外部ブラウザ + URL の中継 + プロトコルの関連付け で通します。
  • Claude Code の Remote Control を systemd で常駐させれば、スマホから AI に指示を出し続けられます。ポートを開ける必要もありません。
  • AI に Studio を任せるには、入力(xdotool)・画面(Xwayland から直接取得)・結果(ログ)・コード(同期プラグイン)・判定(ゲームに組み込んだ自動テスト) の道具をそろえることが要です。
  • 人の仕事は、範囲とルールを決めること、ログインすること、実機で遊んで確かめることに絞れます。

参考:

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?