00:00 / 00:00

Persona

SDK

@laplace.live/persona-sdkはプラグインAPIの型付きクライアントであり、通信スキーマの正式な定義でもあります。このページは型のリファレンスです。サーバーの有効化、キー、メソッド一覧についてはプラグインAPIを参照してください

アイソモーフィックです——Node 22+、Bun、ブラウザ、OBSブラウザソースで動きます——実行時の依存はワイヤースキーマを支えるzodだけです

npm install @laplace.live/persona-sdk

何が作れるか

Persona Consoleは、このSDKで何ができるかを示す公式のリファレンス実装です。アプリ全体のリモコンで——シーン、レイヤーとそれを埋めるインベントリ、表情、モーション、パラメータのバインド、ホットキー、トラッキング、設定——それらがブラウザのタブ1枚に収まり、配信中にスマートフォンから操作する前提でレイアウトされています

注目すべきは、デスクトップ側のコードをまったく取り込んでいないことです。プラグインAPIがその契約のすべてであり、つまりコンソールにできることは、同じSDKで書いたものなら何にでもできます

真似する価値のあるパターンがいくつかあります:

  • 形式ではなくケイパビリティで判定する。インスタンス単位の各セクションは、まず呼び出してunsupported-for-formatを処理するのではなく、InstanceRuntime.capabilitiesを読んで自ら無効化します
  • 再接続はキャッシュの破棄として扱う。ソケットが切れている間に見逃したイベントは再送されないので、遅延取得したデータは「少し古い」のではなく無効です——再接続時に捨てて、必要なものを読み直してください
  • 終端的なクローズコードを正しく扱う40014002は再接続するなという意味です。それ以外は再試行する価値があります
  • 購読はSDKに任せるpersona.on(…)は再接続後に購読を張り直すので、呼び出し側で管理する必要はありません

LLMプロンプト

下のプロンプトをAIアシスタントに貼り付けるか、プロジェクトのCLAUDE.mdAGENTS.mdのようなルールファイルに保存してください。プラグインを書いてもらうのに必要な背景はこれでひととおり揃います。どのモデルにも読みやすいよう英語で書かれており、引用しているドキュメントURLはそのまま取得できます

You are helping me build a plugin for LAPLACE Persona, a desktop VTuber app
(https://laplace.live/persona). Persona exposes a local WebSocket server called the
Plugin API, and `@laplace.live/persona-sdk` is its typed client.

Before writing any code, fetch the reference documents listed at the end — they are
the single source of truth for method names, events, error codes and types. Do not
rely on memory and do not invent names.

## Setup

- Install `@laplace.live/persona-sdk`. Isomorphic: Node 22+, Bun, browsers and OBS
  browser sources. Its only runtime dependency is zod.
- The user enables the server in Persona under Settings → Plugin API and creates an
  API key there. Tokens look like `sk-lp-v1-…`. Default endpoint: `ws://127.0.0.1:25034`.
- Everything — values and types — is exported from the package root; there is no
  other entry point.

## Client

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

const persona = new PersonaClient({
  token: "sk-lp-v1-…", // required; everything else is optional
  clientInfo: { name: "My Plugin", version: "1.0.0" }, // display-only identity
});
await persona.connect();

const { scenes, activeSceneId } = await persona.call("scene.list");
await persona.call("scene.patch", {
  background: { mode: "color", color: "#00ff00", imageAssetId: null },
});
persona.on("motion.started", (m) => console.log("playing", m.group));

const mouth = persona.driveParameter("MouthOpen", 0.8); // parameter lease
mouth.set(0.3);
mouth.release();
```

`call(method, params?)` is fully typed — the method name determines the request and
response shapes. Methods cover scenes, model instances, stage objects, expressions,
motions, speech, hotkeys, automations, model and asset registration, settings,
tracking and pose input, per-key storage and parameter injection; events notify you
of scene, selection, expression, motion, speech, tracking and registry changes. The
exact method and event names, parameter shapes, error codes and limits live in the
reference below — look them up instead of guessing. Gate features on the
capabilities reported by `app.info` and `instance.list`, never on version strings.

## Reference

Fetch these before writing code. The documentation is served as raw Markdown —
append `.mdx` to any page URL (`.en.mdx` for English):

- https://laplace.live/persona/plugin-api.en.mdx — server setup, API keys, and every
  method, event, error code and limit
- https://laplace.live/persona/sdk.en.mdx — the SDK client: options, auth modes and
  every exported type

クライアント

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

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

const { scenes, activeSceneId } = await persona.call("scene.list");
await persona.call("scene.patch", {
  background: { mode: "color", color: "#00ff00", imageAssetId: null },
});
persona.on("motion.started", (m) => console.log("playing", m.group));

PersonaClientは次のオプションで構築します。必須なのはtokenだけです

Prop

Type

ClientInfo

clientInfoは、自分のアプリがPersonaの設定の接続中のクライアントにどの名前で並ぶかを決めます。省略可能で、自己申告であり、表示専用です——認可には決して使われません——SDKが再接続のたびに申告し直します

const persona = new PersonaClient({
  token,
  clientInfo: { name: "My Overlay", version: "1.2.0", developer: "You" },
});

Prop

Type

認証

既定ではトークンは?token=クエリパラメータで渡されます。ブラウザではこれしかできません。Nodeではリクエストヘッダーを設定するソケットを渡すことで、トークンをAuthorization: Bearerヘッダーとして送れます——別途インストールしたwsパッケージを使います:

import WebSocket from "ws";

const persona = new PersonaClient({
  token,
  auth: "header",
  createWebSocket: (url, headers) => new WebSocket(url, { headers }),
});

WebSocketLikecreateWebSocketが返すべきソケットの形です。グローバルのWebSocketwsのクライアントも構造的にこれを満たすので、型アサーションは不要です

Prop

Type

パラメータリース

driveParameterはモデルのパラメータに値を継続的に設定し、InjectionHandleを返します。ハートビートはSDKが担当し、リースは最後の書き込みからおよそ1秒で期限切れになります——つまりプロセスが落ちればパラメータは固まったままにならず、自動的に元へ戻ります

const mouth = persona.driveParameter("MouthOpen", 0.8);
mouth.set(0.3);
mouth.release();

1つのパラメータを同時に保持できるセッションは1つだけです。2つ目はconflictエラーを受け取ります

3つ目の引数にはweightに加えてonErrorも渡せます。バックグラウンドのハートビートが失敗したときに通知されるので、呼び出し側が更新のたびにawaitする必要はありません

Prop

Type

クローズ

onCloseは、サーバーまたはネットワーク由来のクローズをすべて報告します。元のソケットのクローズコードと理由に加えて、クライアントが再接続しないものを示すterminalが付きます。クライアント自身の処理(状態、保留中の呼び出し)が終わったあとで発火するので、その中でclose()を呼んでも安全です。自分から呼んだclose()は報告されません。これを指定した場合、終端的なクローズはonWarningを通らなくなります

Prop

Type

PersonaClientState

type PersonaClientState = "closed" | "connecting" | "open" | "reconnecting";

定数

エクスポート意味
PROTOCOL_VERSION4ワイヤー形式に破壊的変更があると増える。サーバーはhelloで自身のバージョンを報告する
DEFAULT_API_HOST127.0.0.1ユーザーがローカルネットワークからのアクセスを有効にしない限り、サーバーはここにのみバインドする
DEFAULT_API_PORT25034変更しない限り、アプリはこのポートで待ち受ける
SCENE_ACTIVATION_TIMEOUT_MS120000requestTimeoutMsを指定しない場合に、SDKがscene.activateを待つ時間
CLOSE_KEY_REVOKED4001終端的なクローズコード——キーが失効した
CLOSE_FORCE_DISCONNECTED4002終端的なクローズコード——ユーザーがこのセッションを切断した
CLOSE_SERVER_STOPPING1001サーバーが停止中。終端的ではない——復帰したら再接続する
INJECT_LEASE_TTL_MS1000注入したパラメータが最後の書き込みからどれだけで元に戻るか
INJECT_HEARTBEAT_MS100SDKが保持中のリースを再送する間隔
STORAGE_KEY_MAX_LENGTH128ストレージのキー名の最大長
STORAGE_VALUE_MAX_LENGTH65536シリアライズ後の値1つあたりの長さの上限
STORAGE_KEYS_MAX256APIキー1つが保持できるキーの数
SPEECH_URL_MAX_LENGTH8000000speech.playurlの上限。base64のWAVで約40秒分に相当

API_ERROR_CODESEVENT_NAMESINPUT_NAMESAPP_CAPABILITIESFPS_LIMIT_PRESETSEFFECTS_QUALITY_LEVELSas constの配列として提供されるので、ピッカーがアプリの受け付ける値を正確に列挙できます。isApiErrorCodeisEventNameisAppCapabilityはそれらの型ガードで、injectTargetKeyは注入対象の正規化されたキーを構築します

personaWsUrlはホスト、ポート、secureフラグ——またはユーザーが入力した1行のアドレス——からソケットのURLを組み立てます。hosthost:port、角括弧の有無を問わないIPv6、そしてそのまま通す完全なws(s):// URLに対応します。トークンはここには含まれず、PersonaClientが自分で付け足します。parsePortisValidPortは対になる入力検証です

モデルとアセット

モデルとアセットは同じ形のエントリを共有します。kindは常にそのエントリが何かを、originは常にどこから来たかを表します——bundledはアプリに同梱されたもの、userはユーザーが登録したものです。その隣に、アプリのコンテンツマニフェストが宣言した作者クレジットが並びます

Prop

Type

type ModelFormat = "live2d" | "vrm";
type ContentOrigin = "bundled" | "user";
type AssetKind =
  | "image"
  | "video"
  | "audio"
  | "prop"
  | "ibl"
  | "lut"
  | "animation"
  | "cameraMotion";
type InventoryKind = ModelFormat | "pngtuber" | AssetKind | "effect";

effectはファイルを指さない唯一の種類です。インベントリはこれを使って内蔵エフェクトを並べます

model.listModelRef——kindModelFormatに絞ったContentRef——を返します。asset.listAssetRefを返し、こちらはkindAssetKindに絞ったうえでexistsが加わります。ファイルがディスクから消えるとfalseになります

Prop

Type

Prop

Type

CatalogItem

CatalogItemはコンテンツ選択に使う、転送方式に依存しないメタデータ型です。ローカルの登録項目とリモートのカタログ項目を共通の形式で扱えます。ContentRefからインストール前には未確定のoriginを除き、カタログ情報を追加したものです。downloadは未インストール項目の取得方法を示し、省略されていればローカルに存在します

Prop

Type

配置

スクリーン空間はピクセル単位で、原点はステージの中心です。ワールド空間はメートル単位です。パネルには角度で表示されますが、ワイヤー形式での回転はすべてラジアンです

Prop

Type

Prop

Type

Place2DPlace3Dはオブジェクト版です——フィールドは同じで、opacityが加わります

シーンアイテム

シーンのitems配列は、モデルとオブジェクトをz順で一緒に保持します

type SceneItem = SceneModelItem | SceneObjectItem;

Prop

Type

Prop

Type

Prop

Type

ObjectContent

オブジェクトが描画する内容で、kindで区別されます。captureを除き、現時点でいずれもUIから作成できます——レイヤーを参照してください

type ObjectContent =
  | { kind: "image"; assetId: string }
  | {
      kind: "video";
      assetId: string;
      loop: boolean;
      muted: boolean;
      volume: number;
    }
  | { kind: "prop"; assetId: string }
  | {
      kind: "web";
      url: string;
      width: number;
      height: number;
      fps: number;
      transparent: boolean;
      css: string;
      layer: WebLayer;
      shutdownWhenHidden: boolean;
    }
  | { kind: "capture"; source: CaptureKind; sourceId: string; label: string };

type ObjectSpace = "2d" | "3d";
type WebLayer = "behind" | "front";
type CaptureKind = "display" | "window";

Prop

Type

ピン留め

Prop

Type

AttachAnchor

type AttachAnchor =
  | { kind: "root" }
  | { kind: "bone"; bone: string }
  | {
      kind: "artMesh";
      id: string;
      verts: [number, number, number];
      weights: [number, number, number];
    };

object.anchorsは親が提供するアンカーをAnchorOptionとして返します——アンカーと、その表示名の組です。VRMはモデルルートとヒューマノイドのボーンを、Live2Dはモデルルートとすべてのアートメッシュを返します。アートメッシュの各行には、リストを取得した時点の描画順であるorderも付きます

AttachDepth

type AttachDepth =
  { kind: "front" } | { kind: "behind" } | { kind: "artMesh"; id: string };

depthは、Live2Dアイテムが追従先のモデルの内側のどこに描かれるかです——後ろ、前面、またはそのアートメッシュの1つのすぐ上。使われるのは、Live2Dモデルに追従するLive2Dインスタンスだけで、instance.attachで設定します

Prop

Type

depthStops(meshes)は深さのコントロールの段を後ろから前へ並べます——後ろ、描画順に各アートメッシュの上、前面。depthStopIndex(meshes, depth)はある深さがどの段にあるかを返し、親にもうないアートメッシュは最前面の段として扱います。pinRiders(items, instanceId)instanceIdに直接、または連なるピン留めを介して追従しているすべてのインスタンスを返します。これらにはピン留めできません。pinnableParents(models, items, instanceId)はそこからピン留め先の選択肢を作り、無効にすべきものにridesThisを付けます。defaultAttach(parentInstanceId)は新しいピン留めで、アンカーはルート、位置は前面、分割もチューニングもありません

Prop

Type

Prop

Type

シーン

Prop

Type

Prop

Type

Prop

Type

背景

Prop

Type

type BackgroundMode = "transparent" | "color" | "image";

カメラ

Prop

Type

Prop

Type

cameraDistanceLimits(environment, radius)は、マウスでの操作が守る距離の範囲を返します。DISTANCE_MINDISTANCE_MAX、つまり0.35と20で、シーンの3Dセットが幅10メートルほどの部屋より大きく、または小さく配置されていると、比率に応じて広がります。radiusはセット自身のバウンディング半径で、scene.inspectenvironment.radiusから取ります——セットの読み込みが終わるまではnullで、古いビルドは返しません——nullを渡すと通常の範囲になります

ライティング

Prop

Type

type SceneLightType = "directional" | "point" | "ambient" | "area" | "spot";
type ShadowQuality = "off" | "low" | "medium" | "high" | "ultra";
type ShadowFilter = "pcf" | "pcss";

SCENE_LIGHT_TYPESSHADOW_QUALITY_LEVELSSHADOW_FILTERSは、ライトの種類、シャドウの段階、フィルターをas constの配列として提供します。順序はパネルと同じです

followCameraはライトの位置と角度をカメラ基準にし、followCameraOptionsはカメラのどの動きに追従するかを選び——DEFAULT_LIGHT_FOLLOW_CAMERA_OPTIONSは3つともオンです——followCameraReferenceはオフにした選択肢が固定した値を持ちます。ライトを動かさずに追従を切り替えるには、フィールドを直接書き換えずにscene.setLightFollowCameraを呼んでください。ライティングを参照してください

Prop

Type

Prop

Type

iblAssetIdmodelAssetIdはそれぞれ環境マップと3Dセットを指定し、environment-map-modelを持つビルドは両方を同時に受け付けます。書き込みにはenvironmentWithAsset()を使ってください。この関数は選んだほうを設定してもう一方は残し、出ていくセットに紐づいていたライトの上書きを落とします。マップを選ぶとbakeFromModelはオフになり、マップもセットもなかった所にセットが入ったときだけオンになり、セットが別のセットに替わるときはそのまま残ります。nullなら両方を消します。environmentClearPatch(environment, slot)'model''map'、またはnullで両方を削除する編集を組み立てます。モデルを消すとbakeFromModelとそのライトの上書きも一緒に消え、マップだけを消すと照明は残ったセットに引き継がれます。ほかの2つのヘルパーはパネルのボタンに対応します。applyEnvironmentLighting()は2つのライトルートを有効にしてシーン自身のライトを理想の強さまで下げ、applyEnvironmentLook()EnvironmentLookをシーンに適用します

Prop

Type

Prop

Type

Prop

Type

Prop

Type

SCENE_VOLUMETRIC_LIGHTING_SPECSは霧の各スライダーの範囲を持ち、defaultSceneVolumetricLighting()はシーンが最初に持つ霧の設定を返し、healSceneVolumetricLighting()は任意の値を範囲内に補正します。霧はライトごとにSceneLight.volumetricでオンにします。sceneLightCanHaze(type)はその種類が霧を照らせるかを、sceneLightHazes(light)はそのライトがいま霧を照らしているかを返します

エフェクト

SceneEffectsは意図的にフラットです。「スイッチと数値」を持つエフェクトはすべてトップレベルに置かれているので、ツールから一律に走査できます。あるエフェクトがパネルのどこに現れるかは表示上の選択であって、構造ではありません

Prop

Type

レイヤーリストにどのエフェクトが行を持つかは、environment.effectLayers——このレジストリの「スイッチと数値」を持つキー、つまりToggleEffectKeyのリスト——が別に持っています。enabledとは別物で、enabledはオンかどうか、effectLayersは行があるかどうかです。エフェクトをオンにパッチすると行も自動で追加されるので、enabledだけ書けば足ります

type SceneToneMapping = "none" | "neutral" | "aces" | "agx";

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

グラデーションとリムライトは24種類のブレンドモードEffectBlendModeを共有します。EFFECT_BLEND_MODESはそれをパネルと同じ順序で並べたものです

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

rainsnowは形こそ他のエフェクトと同じですが、振る舞いは異なります。ポストチェーンの一段ではなく、シーンの中のジオメトリです。を参照してください

モデルとオブジェクトも、それぞれ独自のエフェクトを持ちます——SceneModelItemSceneObjectItemeffectseffectLayersで、シーンのエフェクトより先に適用され、instance.setEffectsで編集します。含まれるのはLayerEffectKeyの部分集合、つまりcolorlevelscolorWheelscolorShiftselectColorsgradientblurbloomdiffusionrimoutlinedropShadowだけです。ブルームの色選択のフィールドが効くのはこちらだけです。レイヤーエフェクトを参照してください

切り替え効果

transitionは、シーンに入るときに再生される効果です——シーン切り替えを参照してください。scene-transitionsケイパビリティを持たないビルドには含まれません。SCENE_TRANSITION_TYPESが種類を列挙し、defaultSceneTransition()はどのシーンも最初に持つカットを返し、healSceneTransition()は任意の値を範囲内に補正します

Prop

Type

environment.itemTransitionは、シーンのモデル、オブジェクト、生成された物体がどのように現れ、消えるかです——表示・非表示を参照してください。古いビルドには含まれません。ITEM_TRANSITION_STYLESがスタイルを列挙し、defaultItemTransition()はどのシーンも最初に持つ300ミリ秒のglitchを返し、ITEM_TRANSITION_MAX_MSは上限の5000ミリ秒です

Prop

Type

ランタイム状態

instance.listはステージ上の各アイテムに実際に何ができるかを報告するので、クライアントはエラーで気付くのではなく、コントロールをあらかじめ無効化できます

Prop

Type

type InstanceCapability =
  | "motions"
  | "expressions"
  | "placement-2d"
  | "placement-3d"
  | "mtoon"
  | "idle-clips"
  | "idle-motions"
  | "pose"
  | "live2d-params"
  | "speech";

speechは読み込み済みのLive2Dモデルだけが報告するので、ランタイム側のケイパビリティ一覧にしか現れず、formatからは判断できません。アプリ自身のケイパビリティは別の一覧で、helloapp.infoが報告します——機能の有効・無効はこれで判定し、versionの比較に頼らないでください

type AppCapability =
  | "storage"
  | "speech"
  | "automations"
  | "controllers"
  | "model-editing"
  | "asset-inspection"
  | "layer-effects"
  | "scene-transitions"
  | "area-lights"
  | "spot-lights"
  | "camera-follow-lights"
  | "shadow-filters"
  | "environment-map-model"
  | "spawn"
  | "tracking-lost"
  | "motion-stop"
  | "stage-capture";

stage.capturestage-captureケイパビリティ)は{ dataUrl, width, height }を返します——ステージウィンドウのアルファ付きPNGで、最長辺はmaxEdge以下、64 – 2048の範囲で既定値は1024です。画面を見られないクライアントが結果を確かめる手段で、残りの契約はプラグインAPIにあります

Prop

Type

filesでは各モーションがモデルファイルでの元の番号を保ちます。ファイルが欠けているモーションは空文字列として残るので、後ろのモーションの番号はずれません。motionSlots(files)は再生できるエントリをその番号とともに返します。空のスロットをmotion.playで再生しようとするとnot-foundになり、ファイルが1つもないグループは一覧に含まれません。Live2Dモデルでは、model3.jsonが宣言していない.motion3.jsonもモデルフォルダーからすべて列挙され、それぞれがファイル名を名前とするグループになります

motion.stop(アプリのケイパビリティmotion-stop)は再生中のモーションをフェードアウトさせ、アイドルに戻します。アイドルしか再生していないときは{ stopped: false }を返します。motion.playingoneShotmotion.startedにもあります)は、そのモーションがstopで終わる種類かどうかを示します

Prop

Type

Prop

Type

Prop

Type

ホットキー

Prop

Type

Prop

Type

HotkeyConfigregisteredを除いた同じ形——つまりhotkey.setが受け付けるものです

オートメーション

アプリ自身のオートメーションは別ものです。モデルではなくアプリに属し、1つのオートメーションがアクションの並びを持ち、ショートカット、イベント、呼び出しのいずれかで始まります。automation.listが一覧を返し、automation.runが1つを実行し、automation.stateは一覧が変わるたびに全体を送り直します。automationsケイパビリティが必要で、使い方はプラグインAPIにあります

Prop

Type

type AutomationActionKind =
  | "effect-toggle"
  | "effect-params"
  | "effect-clip"
  | "camera-pose"
  | "reset-camera"
  | "play-camera-motion"
  | "stop-camera-motion"
  | "layer-visibility"
  | "stream-mode"
  | "switch-scene"
  | "toggle-expression"
  | "play-motion"
  | "play-audio"
  | "audio-control"
  | "remove-all-expressions"
  | "load-model"
  | "model-position";

actionKindstriggerKindsの型がユニオンではなくstring[]なのは意図的です。サーバーはSDKより新しい種類を送ってくることがあります。automationActionLabelは1つのアクションの種類に英語のラベルを与え、未知のものは汎用の名前にまとめます。automationLabelはオートメーション全体のラベルを返します——titleがあればそれを、なければ各アクションのラベルを一覧の順に·でつないだものです。この順序は再生の順番ではありません。AUTOMATION_BOUNDARY_KINDSisAutomationBoundaryが指すのは、タイムラインの開始前に終わる準備の種類、switch-sceneload-modelです

設定

Prop

Type

SettingsPatchは書き込み可能な部分集合で、lipSynccontrollerenabledスイッチのみ)、windowuiperformanceがいずれも省略可能です。トラッキングとポーズはtracking.*pose.*から変更します。どちらの型も、SDKが一緒にエクスポートしている実行時のZodスキーマSettingsSchemaSettingsPatchSchemaから推論されています。パッチをパースすると未知のキーと読み取り専用のキーは取り除かれ、レスポンスのパースでは未知のフィールドもそのまま通ります。PersonaClientが設定を自動で検証することはありません

type TrackingSourceId = "persona-ios" | "ifacialmocap" | "vts-ios";
type PoseSourceId = "vmc" | "mocopi";
type TrackingSourceKind = TrackingSourceId | PoseSourceId | "mediapipe";
type TrackingStatus = "off" | "waiting" | "tracking" | "no-face";
type PoseStatus = "off" | "waiting" | "tracking";
type EffectsQuality = "low" | "medium" | "high";

トラッキングソース

tracking.sourcesは設定済みのソースの一覧で、ネットワークの顔と身体のソース、そしてウェブカメラを含みます。複数を同時に走らせられ、モデルインスタンスはSceneModelItemfaceSourceIdposeSourceIdhandSourceIdを通じてidでソースに紐づきます

Prop

Type

tracking.sourcepose.sourcepose.portは複数ソース以前のフィールドで、いまは各チャンネルの最初のネットワークソースを映しているだけです。古いクライアントのために残されています。新しいコードはsourcesを読んでください

mediapipeウェブカメラソースは独自のオプションを持ち、その既定値はDEFAULT_MEDIAPIPE_CONFIGにあります

Prop

Type

type HandTrackingMode = "arms" | "fingers";

ソースの種類は、もはや1つのチャンネルに対応しません——ウェブカメラは3つすべてを担えます。sourceSupportsChannel(source, channel)は、ソースが現在のタスクのスイッチでfacehandsposeを供給できるかを判定し、sourceChannelEnabled(source, channel, masters)はさらにソース自身のスイッチと、ネットワークソースならフェイスとポーズのマスタースイッチも考慮します

リップシンク

settings.lipSynclipSync.configureは、デスクトップのマイクを表す同じLipSyncConfigを共有します。マイクによるリップシンクに対応していないビルドでは、Settingsにこの項目がありません

Prop

Type

lipSync.statelipSync.calibrateLipSyncStateを返します。キャリブレーションの手順はマイクによるリップシンクにあります

Prop

Type

SceneModelItemlipSyncModeで、マイクがそのモデルを動かすかどうかをモデルごとに決めます:

type LipSyncMode = "off" | "always" | "when-untracked";

ストレージ

storage.*の値は任意のJSONです。上限は定数を、使い方はプラグインストレージを参照してください

type JsonValue =
  string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };

注入

Prop

Type

type InjectTargetType = "input" | "live2d-param" | "vrm-expression";

InjectTargetvalueweightを除いた同じ形です。inputを対象とする場合、idINPUT_NAMESから取ります——VTube Studio自身の語彙に、52個の生のARKitチャンネルを加えたもので、モデルの.vtube.jsonが参照している名前でもあります

VTSの語彙の21個:

FaceAngleX FaceAngleY FaceAngleZ FacePositionX FacePositionY FacePositionZ EyeOpenLeft EyeOpenRight EyeLeftX EyeLeftY EyeRightX EyeRightY Brows BrowLeftY BrowRightY MouthSmile MouthOpen MouthX CheekPuff JawOpen TongueOut

さらにARKitを前置した52個のチャンネルが続きます。名前はARKitのブレンドシェイプ名の頭を大文字にしたもので、ARKitJawOpenARKitMouthSmileLeftARKitEyeBlinkRightなどです。前置するのは、VTSの語彙にすでにJawOpenCheekPuffTongueOutがあり、.vtube.jsonの入力名の照合が大文字小文字を区別しないためです

この3つの名前がARKIT_TWINSです。それぞれ対応するARKitチャンネルと同じ浮動小数点値で、どちらの綴りも受け付け、どちらもARKit側のidとして読まれます。各入力のレンジはINPUT_RANGESにあります——頭と手の角度は、ARKitチャンネルは0..1、それ以外は無次元です

inputターゲットはコントローラーの入力も受け付けます。プロファイル#1はVTSの19個の名前(ControllerStickLeftX/YControllerStickRightX/Y、スティック押し込み、十字キー、フェイスボタン、ショルダー、トリガー、optionsとhome)をそのまま使い、#2以降はControllerのあとに番号が入ります(Controller2StickLeftXController12Crossなど)。プロファイル数の上限はありません。BASE_CONTROLLER_INPUT_NAMESが#1の既定のコントロールを列挙し、controllerInputNameが番号付きの名前を組み立て、getInputRangeがレンジを返します——スティックと十字キーのYは上が正です

ウェブカメラの手とマイクが、さらに2つの系統を加えます。HAND_INPUT_NAMESはVTSの26個の手の入力に、HandLeftAngleYHandRightAngleYを加えたものです:左右それぞれの検出、位置、角度、開き具合、指1本ごとの値(HandLeftFinger_1_Thumbなど)、そしてBothHandsFoundHandDistanceです。VOICE_INPUT_NAMESはVTSのVoiceVolumeVoiceFrequencyVoiceVolumePlusMouthOpenVoiceFrequencyPlusMouthSmileVoiceAからVoiceOまで、VoiceSilenceに、VoiceMouthOpenと符号付きのVoiceMouthSpreadを加えたものです。ほかのinputターゲットと同じく、注入はLive2Dでのみ有効です

3つ目の系統はOSのカーソルです。MOUSE_INPUT_NAMESにはMousePositionXMousePositionYがあり、カーソルのあるディスプレイ上の−1..1で、FacePositionYと同じく右へ、そして上へ向かうほど大きくなります。どちらもフェイストラッキングとも、トラッキングのスイッチとも独立しています

これらの入力がLive2Dモデルのパラメータへどう届くかはパラメータの割り当てを参照してください

メッセージ形式

SDKを使うなら不要です——プロトコルに直接つなぐ人のためのものです

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

Prop

Type

ApiErrorCodeErrorMessageが運ぶcodeの値の閉じた集合です——それぞれの意味はエラーを参照してください。PersonaApiErrorcallが投げるクラスで、このコードを保持します

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

Tech otakus destroy the world