English | 日本語
このガイドでは vrcpilot で VRChat を操作する際の実践的なループ — 起動、観測、行動、検証 — を解説します。フラグ単位の詳細は cli.ja.md、同等の Python API については python-api.ja.md を参照してください。
例は Linux + X11(または XWayland)を対象としています。Windows でも Section 1 の .env セットアップを省くだけで、同じ流れがそのまま動きます。
- VRChat が Steam 経由でインストールされており、Steam にログイン済みであること。
- デスクトップセッションが X11 または XWayland であること。
loginctl show-session "$XDG_SESSION_ID" -p Typeを実行しType=x11であることを確認してください。Wayland ネイティブセッションはサポート対象外です —focus()/unfocus()は警告を出してFalseを返し、合成入力はウィンドウに届きません。 - Steam が既に起動していること。 Steam が起動していない場合、
vrcpilot launchは 30 秒の待機時間を Steam の起動画面で使い切り、最終的にvrcpilot: VRChat did not start within 30.0sで失敗します。先に Steam を起動しておいてください。 - Linux 限定 —
vrcpilotよりも先にinputtino-pythonをインストールすること。 Linux の入力バックエンドはinputtinoを利用します。先にネイティブビルドの前提条件をインストールしたうえで、vrcpilotと同じ Python 環境にinputtino-pythonを導入してください。詳しくはREADME.ja.mdのインストール を参照。 - Linux 限定 —
/dev/uinputへの書き込み権限があること。 合成入力は/dev/uinputを経由します。sudo usermod -aG input "$USER"を実行し、一度ログアウトして再ログインしてください。groupsの出力にinputが含まれていれば OK です。 - 画面がロックされていないこと。 スクリーンロック中はウィンドウ操作が不安定になります。
SSH 経由のログインシェルでは通常 DISPLAY や XAUTHORITY が設定されていません。CLI セッションごとにプロジェクトルートの .env から読み込んでください:
set -a && . ./.env && set +a最小限の .env は次のとおりです:
DISPLAY=:0
XAUTHORITY=/home/<you>/.Xauthority
uv run が出す VIRTUAL_ENV=/usr does not match ... will be ignored という警告は無害です — uv run は引き続きプロジェクトの .venv を使います。
Windows では .env は不要です。デスクトップセッションと SSH / RDP / ローカルターミナルが既定で同じディスプレイを共有します。
vrcpilot launch --no-vr --screen-width 1280 --screen-height 720 --wait-timeout 60--no-vrはデスクトップモードを強制します。HMD のないマシンでは必ず指定してください。--wait-timeout 60は VRChat の PID が観測されるまでブロックし、観測できたら stdout に PID を出力します。終了コード0で起動成功を確認できます。- 起動直後、VRChat は
01〜04のアイコンが回転する Launch Pad 画面を表示します。これはメニューであってローディング表示ではなく、VRChat は裏でシェーダーコンパイル中であることがあります。 - 入力を送る前に 約 45 秒 待ってください。それより早い入力はシェーダーコンパイルやアバターロードと競合する可能性があります。
VRChat は外から見ると不透明なので、すべての操作の前後で観測を行ってください。
vrcpilot screenshot -o /tmp/vrc.png > /tmp/vrc.yamlstdout に出力される YAML には以下が記録されます:
path— PNG の絶対パス(ファイルモード)、もしくはimage— base64 PNG(インラインモード、-oを省略したとき)。x,y— VRChat ウィンドウの左上のデスクトップ絶対座標(情報用。下記の OCR / detect の結果はウィンドウローカル座標です)。width,height— 物理ピクセル単位のウィンドウサイズ。
vrcpilot ocr は自分では画面をキャプチャしません。Screenshot の YAML を pipe で渡すか、--screenshot <path> を指定してください:
# インラインパイプ(最短)
vrcpilot screenshot | vrcpilot ocr --viz /tmp/viz.png > /tmp/ocr.yaml
# 既存のスクリーンショット YAML を再利用
vrcpilot ocr --screenshot /tmp/vrc.yaml > /tmp/ocr.yaml各 words[i] は次を持ちます:
textとconfidence。pos.{polygon,bbox}— ウィンドウローカルピクセル(原点は VRChat ウィンドウの左上)。
vrcpilot mouse move も X Y 引数を同じウィンドウローカル座標系で解釈するため、pos.bbox をそのまま流し込めます — 座標ごとの変換は不要です。詳しくは cli.ja.md の座標系 を参照してください。
--viz [PATH] を指定すると、スクリーンショット上に polygon を重ね描きした PNG を生成します。OCR の出力を目視で確認するのに使えます。
vrcpilot detect は ocr と同じ入力契約に従います。探したい UI 要素の小さな参照 PNG を用意してください:
vrcpilot screenshot | vrcpilot detect -q assets/launch-pad.png --threshold 0.85 --top-k 3 > /tmp/det.yamldetections[i] は confidence、scale、rotation、そして pos.{polygon,bbox}(ウィンドウローカルピクセル)を持ちます。
TM_CCOEFF_NORMED は静的な UI 要素のピクセル単位で正確な切り抜きに対して最も良く機能します。テキストには OCR を使ってください。
# 600 / 360 を上で取得した OCR/detect の pos.bbox 中心に置き換えてください。
vrcpilot mouse move 600 360
vrcpilot mouse click left- 座標は VRChat ウィンドウローカルのピクセル です — OCR / detect が
posの下に出すのと同じフレームです。--relを付けると現在のカーソル位置からの差分に切り替わります。VRChat ウィンドウの外側の座標も拒否されず、そのまま OS に渡されます。 vrcpilot mouse clickの既定値はleftおよび--count 1です。ダブルクリックには--count 2を、ボタンを短時間押し続けるには--duration 0.05を指定してください。
ドラッグのような down/up の組み合わせ操作は、単一の Python プロセス内で行ってください。合成入力デバイスは CLI プロセスが終了するとカーネルによって解放されるため、mouse press の後に別の mouse release を呼び出してもコマンド間でボタンを押し続けることはできません。
vrcpilot keyboard press w --duration 1.0 # 約 1m 前進する
vrcpilot keyboard press shift w --duration 1.0 # 走って前進
vrcpilot keyboard press escape # 最前面のダイアログを閉じる--duration 0.1は VRChat が確実に受け取れる下限値です。これ以上小さくしないでください。- 複数キーを並べると同時押し(down all → sleep → up reversed)になります。上の
shift wは「shift を押したまま w をタップし、最後に両方離す」という意味です。 - 移動距離は
--durationに比例します。ワールドごとに調整してください。 - CLI の各呼び出しは個別のプロセスです。あるキーを押したまま別の操作をしたい場合は、同じプロセス内から Python API の
vrcpilot.keyboard.down(...)とvrcpilot.keyboard.up(...)を使ってください。
スキャンコードベースのキーボード入力では、日本語・絵文字・類似のテキストを直接タイプできません。paste を使うと OS のクリップボードに文字列をコピーしてから Ctrl+V を送信します:
vrcpilot paste "こんにちは、VRChat!"
# もしくは stdin から
cat msg.txt | vrcpilot pastepaste を実行する前に、まずテキストフィールドをクリックしてキーボードフォーカスを与えてください。xclip / xsel のない Linux 環境では pyperclip.PyperclipException が出ることがあります。いずれかをインストールしてください。
ワールド内(メニューが開いていない状態)では、デスクトップクライアントがマウスを取り込み、カーソルの動きでカメラを回せるようになります:
vrcpilot mouse move 200 0 --rel # 右に約 200 px 分回転
vrcpilot mouse move 0 -100 --rel # 上に約 100 px 分見上げるメニューが開いているときは、カーソルは UI クリックモードに戻ります。
vrcpilot record は映像、音声、またはその両方をキャプチャします。ファイル出力では、解決後のモードに応じてコンテナが選ばれます(映像を含む場合は MP4、音声のみは WAV)。stdout は常に自己記述形式の Matroska (MKV) バイトストリームになるため、ffmpeg などの下流ツールが追加のフォーマットフラグなしで取り込めます。
# 映像 + 音声 MP4、10 秒
vrcpilot record -o /tmp/vrc.mp4 --duration 10
# 映像のみ
vrcpilot record --video -o /tmp/vrc_video.mp4 --duration 10
# 音声のみ(VRChat のみ — Linux はネイティブ PipeWire、Windows は proc-tap、いずれもシステム音は含まない)
vrcpilot record --audio -o /tmp/vrc_audio.wav --duration 10
# 一時ファイルを使わずに ffmpeg に MKV をストリームして再エンコード
vrcpilot record --duration 5 | ffmpeg -i - -c copy /tmp/vrc.mkv-o PATHの拡張子はモードと一致させる必要があります(映像 / 両方は.mp4、音声のみは.wav)。不一致の場合は終了コード2で終わります。--fpsの既定値は 30 で、--audio単独と組み合わせると終了コード2で拒否されます。--durationを省略すると Ctrl+C まで録画し続けます。
フラグ全体のリファレンスと終了コードは cli.ja.md の record を参照してください。
vrcpilot mic は float32 PCM ストリームを仮想ケーブルの出力デバイスに再生します。VRChat 側でその仮想ケーブルをマイクとして設定しておけば、CLI が再生した音声は実際のマイクから話したかのように他のプレイヤーに届きます。主なユースケースは LLM エージェントの TTS を VRChat に繋ぐことです。
- VB-Audio Virtual Cable をインストールし、プロンプトが出たら再起動します。
- 設定 → システム → サウンド を開き、再生デバイス
CABLE Inputと録音デバイスCABLE Outputが両方表示されることを確認します。 - VRChat の Audio 設定で、マイク入力を
CABLE Output (VB-Audio Virtual Cable)に切り替えます。vrcpilot micはCABLE Inputに書き込み、VRChat はその音声をCABLE Output経由で読み取ります。
- PipeWire(
pipewire-pulse込み)とlibpulse0がインストールされていることを確認します。 Debian/Ubuntu の場合:sudo apt-get install pipewire pipewire-pulse libpulse0。 - 仮想マイクを一度だけ登録します:
vrcpilot linux-mic register。これにより~/.config/pipewire/pipewire.conf.d/vrcpilot-mic.confが書き出され、module-null-sinkがその場でロードされるので、現在のセッションでも すぐにデバイスが使えるようになります。 - VRChat の Audio 設定で、マイク入力を
Monitor of VRCPilot Virtual Micに切り替えます。vrcpilot micはVRCPilotMic(シンク)に書き込み、VRChat はその音声をVRCPilotMic.monitor(対応するモニターソース)から拾います。
ステータスは vrcpilot linux-mic status でいつでも確認でき、
vrcpilot linux-mic unregister で登録を解除できます。
--suffix <name> で名前付きの追加 sink を登録できます。本来の目的は、
複数の AI インスタンスを並列に走らせる際に、各インスタンスへ独立した
仮想マイク (VRCPilotMic_<name>) を割り当てて、それぞれの TTS 音声が
別インスタンスの入力に混線しないようにすることです。
vrcpilot linux-mic register --suffix bot # VRCPilotMic_bot を作る
vrcpilot linux-mic register --suffix obs # VRCPilotMic_obs を作る
vrcpilot linux-mic status --all # 登録済み全 suffix を列挙
vrcpilot linux-mic unregister --suffix bot # bot だけ削除
vrcpilot linux-mic unregister --all # 全部削除--suffix を省略すると既存の VRCPilotMic(空 suffix)が対象です。
suffix に使える文字は [A-Za-z0-9_-] のみです。
vrcpilot mic -i greeting.wavCLI は進捗(サンプルレート等)を stderr にログ出力し、WAV の再生が完了するまでブロックします。stdout は静かに保たれているので、生 PCM の生成元の下流に置いてもバイトストリームを汚しません:
# 任意の音声ソースを raw s16le にデコードして仮想マイクから再生する。
ffmpeg -i greeting.mp3 -f s16le -ar 48000 -ac 2 - \
| vrcpilot mic --format s16le --rate 48000 --channels 2Mic を一度だけ開き、エージェントが生成するチャンクを play() 呼び出しごとに 1 つずつ流し込んでください。with ブロックの間 soundcard プレイヤーが起動したままになるため、デバイス解決のコストはコンストラクタで一度だけ支払い、play(chunk) は反復ごとにバッファ書き込みだけを行います。
from collections.abc import Iterator
import numpy as np
from numpy.typing import NDArray
import vrcpilot
def agent_tts_chunks() -> Iterator[NDArray[np.float32]]:
# Replace with the agent's incremental TTS output.
for _ in range(10):
yield np.zeros(4800, dtype=np.float32) # 100 ms of silence per chunk
with vrcpilot.Mic(sample_rate=48000, channels=1) as mic: # picks up CABLE Input on Windows, VRCPilotMic on Linux
for chunk in agent_tts_chunks():
mic.play(chunk)チャンクの shape は、コンストラクタで選んだチャンネル数と一致させる必要があります(モノラルは (N,)、マルチチャンネルは (N, channels))。バックエンドの内部バッファが満杯のとき play() はブロックするため、ライブストリームに対して呼び出し側に自然なバックプレッシャーがかかります。
# 操作前のスナップショット
vrcpilot screenshot -o /tmp/vrc_before.png
# 操作
vrcpilot keyboard press escape
# 操作後のスナップショット — 画像ビューワで開いて確認
vrcpilot screenshot -o /tmp/vrc_after.pngスクリーンショットを ocr に流し、ある単語の最初の一致を選び、その中心をクリックします。例では mikefarah/yq v4 を使っています。jq を使う場合は、フィルタを '.words[] | select(.text == "Worlds") | .pos.bbox | @tsv' に置き換えてください。
read -r x y w h < <(
vrcpilot screenshot \
| vrcpilot ocr \
| yq -r '.words[] | select(.text == "Worlds") | .pos.bbox | join(" ")' \
| head -n 1
)
vrcpilot mouse move $((x + w / 2)) $((y + h / 2))
vrcpilot mouse click left(set -a && . ./.env && set +a && \
vrcpilot terminate && \
vrcpilot launch --no-vr --screen-width 1280 --screen-height 720 --wait-timeout 60 && \
sleep 45 && \
vrcpilot keyboard press escape && \
vrcpilot screenshot -o /tmp/vrc_menu.png \
| vrcpilot ocr --viz /tmp/vrc_menu_viz.png > /tmp/vrc_menu.yaml && \
vrcpilot keyboard press escape && \
vrcpilot terminate)VRChat を起動し、Launch Pad をキャプチャして OCR にかけ、その後終了します — 環境のスモークテストとして便利です。
| 症状 | 想定される原因 | 対処 |
|---|---|---|
vrcpilot: VRChat did not start within 30.0s |
Steam が起動していない、もしくは VRChat がインストール未済 | 先に Steam を起動し、Steam ライブラリでインストールを確認 |
vrcpilot focus がサイレントに 1 で終了 |
Wayland ネイティブセッション、または VRChat ウィンドウ未生成 | X11 / XWayland に切り替え、ウォームアップを待つ |
入力コマンドから VRChatNotFocusedError |
呼び出し直前にウィンドウのフォーカスが外れた | vrcpilot focus で再フォーカスしてから再試行 |
| Tab キーが効かない | 2026 系の UI では Tab がメニューに割り当てられなくなった | Escape(Launch Pad)と R(Radial Action Menu)を使う |
keyboard press が無視される |
--duration を 0.1 未満に下げている |
既定の 0.1 以上に戻す |
mouse move が OCR ターゲットから大きく外れる |
OCR/detect の pos をデスクトップ絶対座標として扱っている |
pos.bbox をそのまま渡す — mouse move はウィンドウローカル |
Linux で pyperclip.PyperclipException |
クリップボードバックエンドが未インストール | sudo apt-get install xclip(もしくは xsel) |
| キャプチャがハング、または即座に失敗 | Wayland ネイティブセッション、または画面ロック中 | X11 / XWayland に切り替え、画面のロックを解除 |
ここまでの内容はすべて python-api.ja.md に Python 版があります。エンドツーエンドの流れは次のとおりです:
from time import sleep
import vrcpilot
vrcpilot.launch(no_vr=True, screen_width=1280, screen_height=720)
sleep(45)
try:
shot = vrcpilot.take_screenshot()
if shot is None:
raise RuntimeError("could not capture VRChat")
result = vrcpilot.ocr(shot)
target = next((w for w in result.words if w.text == "Worlds"), None)
if target is not None:
x, y, w, h = target.bbox
vrcpilot.mouse.move(int(x + w / 2), int(y + h / 2))
vrcpilot.mouse.click(vrcpilot.MouseButton.LEFT)
vrcpilot.keyboard.press(vrcpilot.Key.W, duration=1.0)
finally:
vrcpilot.terminate()複数の操作にまたがってキーやボタンを押し続けたい場合は、ひとつの Python プロセス内で keyboard.down / up と mouse.press / release を使ってください。これらのハーフアクション API は意図的に CLI から省かれています。CLI の各呼び出しは個別のプロセスになるためです。