00:00 / 00:00

Persona

プラグインAPI

Personaは他のアプリから操作できるローカルWebSocketサーバーを動かします。シーンの切り替え、レイヤーの追加と配置、表情の切り替え、モーションの再生、リップシンク付き音声の再生、トラッキング状態の取得、そしてモデルパラメータへの直接書き込みができます

既定ではオフです。設定 → プラグインAPIでオンにし、キーを作成して、そのトークンをプラグインに貼り付けてください

有効にする

コントロール効果
APIを有効にするサーバーを起動する。キーがなければ何も接続できない
ポート既定は25034
ローカルネットワークからのアクセスを許可ループバックを越えてバインドし、スマートフォンや別のマシンから接続できるようにする

ローカルネットワークからのアクセスをオンにすると、このマシンが応答するアドレスが表示されるので、ブラウザをどこへ向ければよいか分かります

ポートがすでに使われている場合、このセクションは黙って失敗するのではなくエラーを表示します

APIキー

キーは必須です——認証のない接続は拒否されます。キーを作成でキーに名前を付けると、そのトークンが一度だけ全文表示されます。行にあるコピーボタンを押せば、いつでも全文を取り出せます

操作効果
トークンをコピー完全なトークンをクリップボードにコピーする
キーの名前を変更その場で名前を変更する
キーを失効させる削除する。そのキーを使っているセッションは閉じられ、再接続しないよう伝えられる

各キーの行には接続中未使用、または最終使用とその相対時刻が表示されます。クライアントが名乗ると、直近の名前とバージョンがその行に記録されるため、接続中のクライアントがいなくてもキーを見分けられます

トークンはOSの安全なストレージに保管されます。それが利用できないマシンでは、トークンを平文のファイルに書き込むのではなく、説明を添えてキーの作成が失敗します

プラグインフォルダ

プラグインはモデルやアセットのファイルを登録するようPersonaに依頼し、そのうえで読み込ませることができます。これが通るのはプラグインフォルダに追加したフォルダ内のファイルだけです——それ以外のパスはすべてforbidden-pathで拒否されます

接続中のクライアント

サーバーの動作中は、開いているセッションがすべて一覧表示されます。クライアントが申告した名前、バージョン、開発元、使用しているキー、そして接続元が表示されます。ブラウザのクライアントはページのオリジンを表示します

一度も名乗らないクライアントは不明なクライアントとして並びますが、機能はまったく同じです。行にある切断ボタンを押すとそのセッションが閉じられ、再接続しないよう伝えられます

Webコンソール

persona.laplace.liveはこのAPIのブラウザ用フロントエンドです。サーバーが動いていることを確認する最速の手段であり、配信の途中でスマートフォンやタブレットから使えるリモコンでもあります

ホスト、ポート、キーを入力すれば、動作中のアプリを操作できます。シーン、レイヤー、表情、モーション、エフェクト、カメラとライティング、ショートカット、トラッキング、設定、そしてパラメータインジェクターです。レイアウトはデスクトップのコントロールパネルと同じで、左にレイヤーとその下に固定されたステージトラッキングショートカットパラメータ設定の5行、右に選択中のものの詳細が入り、ウィンドウが十分に広ければ左右に並びます——違うのは、ここでは各セクションがブックマークできる本物のURLだということです。表情とモーションは専用のページではなく、選んだモデルに属します。エフェクトもアプリと同じくレイヤー一覧の行で、開けばそれぞれのパラメータを調整できます。各セクションは選択中のインスタンスに実際にできることを基準に判定するので、その形式では応えられない機能はエラーを出さずに自ら無効化されます

レイヤー一覧の下にあるシーンに追加ボタンからは、アプリと同じインベントリが開き、中身はAPI経由でレジストリから読み込まれます。ブラウザはネイティブのファイルダイアログを開けないので、ここでの登録はパス指定です——プラグインフォルダに追加したフォルダ内のパスに限られます

シーンのアセットのうち、環境マップLUTはアプリと同じようにそれぞれタブを持ち、行をクリックすると現在のシーンに適用され、トーストが確認を伝えます。アニメーションには専用のタブがありません。クリップを再生するメソッドがないからです——すべてタブの種類のピッカーから登録し、コンソール自身の選択…ボタンでレイヤーの待機アニメーションとして選びます

キーはブラウザに——暗号化なしで——記憶させることも、そのセッション中だけ保持することもできます。インターネットに出るデータはありません。このページは手元のマシンやローカルネットワーク上のPersonaと直接通信します

APIのないものはデスクトップアプリ側に残ります。アップデーター、APIキー、トレイアイコン、ウィンドウの位置とサイズ、ネイティブのファイル選択、ステージ上のハンドル、ショートカットの記録、そして3Dオブジェクトや環境に組み込まれたライトです。アプリとシーンのショートカットの作成もデスクトップ側だけで、コンソールからは実行しかできません

Stream Deck

Stream DeckプラグインはこのAPIのもう1つの公式クライアントで、モデルとシーンの切り替え、ホットキー、表情、モーション、そしてアバターの移動とスケールを物理キーの上に載せます

SDK

@laplace.live/persona-sdkは型付きのクライアントで、Node、Bun、ブラウザ、OBSブラウザソースのどこでも同じコードが動きます

import { PersonaClient } from "@laplace.live/persona-sdk";

const persona = new PersonaClient({ token: "sk-lp-v1-…" });
await persona.connect();

await persona.call("expression.toggle", { name: "Smile" });
persona.on("motion.started", (m) => console.log("playing", m.group));

すべてのメソッドは1つの共有テーブルで型付けされているので、呼び出しのリクエストとレスポンスの形はメソッド名から決まります。SDKリファレンスでは、インストール、クライアントのオプション、認証、パラメータリース、そしてエクスポートされているすべての型を扱っています

イベント

セッションが受け取るのは、自分が購読したものだけです。SDKは再接続後に購読を張り直すので、ソケットが切れてもイベントの流れが黙って止まることはありません

イベント発火のタイミング
scene.changedシーンへのあらゆる変更:作成、削除、名前の変更、適用、編集
scene.loadingシーンの適用やパイプラインのウォームアップの開始と終了
settings.changedアプリの設定が変わったとき
instance.loadedモデルインスタンスのステージ上での読み込みが完了したとき
selection.changed編集の選択対象が移ったとき。どこからの操作でも
expression.changed適用中の表情の組み合わせが変わったとき
expression.persistenceモデルの「表情を記憶する」フラグが切り替わったとき
motion.startedモーションの再生が始まったとき
motion.endedモーションの再生が終わったとき
speech.startedspeech.playの発話が始まったとき
speech.ended発話が終わったとき——再生完了、停止、上書きのいずれでも
hotkey.stateホットキーの設定が変わったとき
shortcut.stateグローバルショートカットの一覧・名前・OS登録状態が変わったとき
tracking.statusフェイストラッキングまたはボディトラッキングの状態が変わったとき
registry.changedモデルやアセットが登録されたとき——該当する一覧を読み直すこと

メソッド一覧

モデルを対象とするメソッドは省略可能なinstanceIdを取り、既定ではシーンのメインモデルに作用します

グループメソッド
scene.*list get activate create duplicate rename delete setShortcut patch
instance.*list get add setModel remove setVisible setTrackingSources reorder setPrimary setPlacement setMToon setIdle info
selection.*get set
object.*add rename setContent setSpace setPlacement attach setLightOverrides anchors
expression.*list active toggle getPersistence setPersistence
motion.*list play playing
speech.*play stop
hotkey.*list set trigger
shortcut.*list trigger
model.* / asset.*それぞれのlistregister
settings.*get patch
tracking.* / pose.*tracking.addSource tracking.updateSource tracking.removeSourcesetEnabledsetSource、加えてpose.setPorttracking.status
stage.*resetTransform resetCamera shockwave
app.* / session.*app.info app.localAddresses app.stats、およびsession.identify
storage.*get set delete list
param.*inject release

ケイパビリティ

接続先のビルドに何ができるかは、2段階のケイパビリティ一覧が示します。判定にはこれらを使い、バージョン番号は決して使わないでください

アプリ自身のものはhelloapp.infoが報告します——現在はstoragespeechshortcutsです。各インスタンス固有のものはinstance.listcapabilitiesにあり、どのケイパビリティにも含まれないメソッドはunsupported-for-formatで拒否されます

トラッキングソース

Personaでは設定済みのトラッキングソースを複数同時に動かせます。settings.tracking.sourcesが一覧を返し、tracking.addSourcetracking.updateSourcetracking.removeSourceで管理します。instance.setTrackingSourcesはソースIDを使い、インスタンスのフェイスとボディのチャンネル(faceSourceIdposeSourceId)を対応するソースへ割り当てます。nullを指定するとそのチャンネルのトラッキングが止まり、存在しないIDもnullと同じ扱いです。新しいインスタンスは各チャンネルの既定ソースに割り当てられ、1つのソースを複数のインスタンスで共有できます

フェイスソースはvts-iosifacialmocapのいずれかで、省略可能なphoneIpで1台の送信元に固定できます。ボディソースはvmcを使い、それぞれが1つのportを持ちます。別のソースが使っているポートは拒否されます。廃止されたvts-ios-nativeはプロトコル上で拒否されます

tracking.statusはフェイスとボディの集約状態に加え、設定済みソースそれぞれの状態をsourcesマップで返します。tracking.statusイベントも同じ形です

従来の単一ソース用メソッドは、引き続き各チャンネルの先頭のソースを扱います。tracking.setSourceはその種類を変更し、pose.setSourceは必要ならVMCソースを作成してポートを返し、pose.setPortはそのポートを変更します。tracking.setEnabledpose.setEnabledは今もチャンネル全体のマスタースイッチです

音声

speech.playは音声を再生し、その音量で口を動かします。動作するのはspeechケイパビリティを持つインスタンスだけです——これは形式ではなく描画エンジンによって決まるので、インスタンスのランタイムを見てください。現在は既定エンジンのLive2Dがこのケイパビリティを持ち、レガシーWebGLモードにはありません

パラメータ説明
urlhttps:http:(ローカルのTTSブリッジ)、またはインラインのdata:audio/*ペイロード
volume省略可能。0..1
instanceId省略可能。既定はシーンのメインモデル

1つのモデルにつき発話は1つで、新しい再生が現在のものを上書きします。呼び出しが返ってきたら再生が始まったということで、始まらなかった場合はinvalid-stateになります。speech.startedspeech.endedが発話を挟み、speech.stopで途中終了できます

グローバルショートカット

shortcutsケイパビリティを持つビルドでは、アプリ自身のアプリのショートカット——一連のステージ変更をまとめて実行するマクロ——を一覧・実行できます

メソッド効果
shortcut.listすべてのショートカットを列挙
shortcut.triggeridを指定して1つ実行

アクションの中身はアプリ側に留まります。一覧が返すのはidtitleacceleratorregistered、そしてactionKindsの配列です——各アクションが何をするかを知らなくても、ボタンを一列描くには十分です。titlenullのときはactionKindsからラベルを組み立ててください。SDKのshortcutLabelがやっているのがまさにこれです

acceleratornullになり得ます。エラーではなく、単にキーの組み合わせが割り当てられていないだけで、shortcut.triggerからは変わらず実行できます。一覧・名前・OS登録状態のいずれかが変わるたび、shortcut.stateが一覧をまるごと送り直します

プラグインストレージ

storage.*はプラグインに永続的なキーバリューストレージを提供し、名前空間はAPIキーごとに分かれます——キーがプラグインの身元であり、同じキー上のすべてのセッションが同じデータを共有し、キーを失効させるとデータも削除されます。値は任意のJSONです

メソッド効果
storage.getキーを読む。一度も書いていないキーはvalue: nullを返す
storage.setキーに書き込む
storage.deleteキーを削除する。存在しないキーでも成功する
storage.listすべてのキーをソートして列挙する

上限はキー名が128文字、シリアライズ後の値が1つあたり64 KB、APIキーあたり256個のキーです。キー数の上限を超えるstorage.setinvalid-stateを返します

エラー

persona.callは文字列のcodeを持つPersonaApiErrorを投げます:

コード意味
parse-errorフレームが妥当なJSONではない
invalid-requestエンベロープの形式が不正
unknown-methodこのビルドにそのメソッドがない
invalid-paramsパラメータが検証を通らなかった
not-found参照されたIDが何にも解決されない
unsupported-for-formatそのインスタンスの形式では実行できない——たとえばLive2DモデルへのMToonの設定
conflictパラメータリースを別のセッションが保持している
renderer-unavailableステージが応答できない——ウィンドウがない、または描画プロセスが再読み込み中
forbidden-pathパスが設定済みのどのプラグインフォルダにも含まれていない
invalid-state現在は許可されていない:最後のシーンの削除、ストレージの上限超過、開始できなかった音声など
internalそれ以外のすべて

このコードの集合はプロトコルの一部です。クライアントは未知のコードを持つエラーフレームを破棄するので、新しいコードはプロトコルのバージョン更新とともにしか現れず、新たな失敗は既存のコードを再利用します

切断

クライアントは予期しない切断のあと自力で再接続します。サーバー側のクローズコードのうち2つは終端的で、このループを止めます。再接続しても決して成功しないからです:

コード定数原因
4001CLOSE_KEY_REVOKEDキーが失効した
4002CLOSE_FORCE_DISCONNECTEDユーザーがそのセッションを切断した

どちらの場合もクライアントは最終的にclosed状態に落ち着きます。onCloseが指定されていれば終端的な切断はそちらへ通知され、onWarningは呼ばれません。onCloseがなければonWarningへフォールバックします。1001はこれに含まれません——サーバーが停止中であることを意味するので、復帰したら再接続してください

失効は即座に効きます。送信待ちのフレームは破棄され、ステージの応答を待っていたリクエストが書き込みに至ることはなく、失効と競合した接続は4001で閉じられます。すでにステージへ渡されたアクションは完了することがあります——失効の直前に届いた場合と同じです——が、そのレスポンスが届くことはありません

バージョンの不一致

プロトコルはバージョンを持っており、接続先のビルドと一致しない場合、SDKは警告を出します。古いPersonaが知らないイベントを購読しても致命的ではありません——SDKは1つずつ購読する方式にフォールバックし、通ったものを保持して、残りについては名前を挙げて警告します

最終更新日:2026年9月3日

Tech otakus destroy the world