シミュレーションチャンネル
概要
シミュレーションチャネルは、デバイスの状態のやり取りや、セッションコマンドおよび デバイスコマンドの送信を行うための、高頻度の双方向WebSocketチャネルです。
標準URL: ws://localhost:10001
ポートは設定で変更可能です。
基本的な行動(重要):
- クライアントが接続すると、サービスは初期インベントリを含むメッセージを送信し、そこには完全なデバイス一覧が含まれています。
- その後、サーバーはクライアントから受信した各メッセージに対して、正確に1つの 状態更新メッセージを送信します。
- 各ステート・アップデートには、すべてのデバイスの状態(およびステータス)が含まれています。
このページでは、シミュレーションチャネルのコアプロトコルとそのコマンドについて説明します。
追加のモジュールや機能により、システムに独自のコマンドや状態フィールドを追加・登録することができます。これらについては、「モジュール」のセクションで別途説明されています。
議事録作成のルール
クライアントメッセージごとに1つの応答
このサービスは、クライアントが受信した各メッセージに対して、すべてのデバイスの状態を含むステート更新メッセージを送信します。
つまり、
- デバイスの現在の状態のスナップショットが必要な場合は、何か(セッションコマンド、クエリコマンド、またはデバイスコマンド)を送信する必要があります。
- このチャネルは、クライアントからのメッセージによって制御される「ティック」ループのように動作します。
力を加えないポーリング(問い合わせコマンド)
力を加えたりシミュレーションパラメータを変更したりすることなく、状態の変化を観察したい場合は、クエリコマンドを使用してください:
probe_positionfürinverse3probe_orientationVerse Grips用
クエリコマンドにはコマンドデータが含まれておらず、単にデバイス情報の取得を促すだけであり、これにより、次のステート更新メッセージにおいて位置および姿勢データが最新のものとなるようにします。
すでに制御コマンドを送信しているシミュレーションセッション(set_cursor_force, set_cursor_position など)、 必要ありません 問い合わせコマンドの送信 – 応答フレームには常にデバイスの状態が含まれています。問い合わせコマンドは、 純粋な監視会議 gedacht(例:Haply Hub)など、デバイスへの制御を行わずにデバイスの状態を照会する必要があるもの。
構成と状態
- ダイ 初期在庫が記載されたメッセージ 含まれる
config,stateundstatus機器の。 - レギュラー ステート・アップデート- ニュースが含まれています
stateundstatus機器の。
設定情報を含むスナップショットを再度必要とする場合は、以下を使用してください。 session.force_render_full_state.
configure 対 commands
デバイス通知では、2つの別々の割り当てがサポートされています: configure und commands. これらはさまざまな目的を果たしています:
| 割り当て | Zweck | 頻度 |
|---|---|---|
configure | 一度設定すれば永続的に有効な設定:プリセット、基本設定、取り付け、フィルター、モジュール設定 | 一度送信するか、変更があった場合 |
commands | Pro Tick、非持続型:力、位置、トルク | 各ティックごとに送信する必要がある |
「」内の項目 commands (set_cursor_force, set_cursor_position, set_angular_torques, set_angular_position) となる 1ティックごとに適用され、保存されない – 送信を停止すると、その効果は直ちに終了し、デバイスはスリープ状態に戻ります。以下の操作を行ってください。 configure 複数のティックにわたって維持され、再送信されない必要があるすべてのものについて。
set_transform は特殊なケースであるset_transform 以下に記載されています commands、だが 持続的な – このサービスは、
新しい変換を送信するまで、最後に送信された変換を保持します。あなたは müssen 毎ティック送信する必要はありません。ただし、その目的はカメラやシーンのナビゲーションであるため、
ティックレートでのストリーミング(例えば、ユーザーがシーン内をパンする際に
1フレームにつき1回の変換を行うなど)が、連続的な移動ナビゲーションにおける想定される使用パターンとなります。
座標系
Haply デフォルトでは、Z軸が上向きの 右利き座標系を使用します。
座標の解釈および返り値の決定には、2つの設定項目が影響します:
session.configure.basis: `Haply` の座標と、アプリケーションの座標系との対応関係を変更します(参照: 基礎 (以下を参照)。inverse3[*].configure.preset: ワークスペースの起点となる、名前付きワーク構成を選択します(例:arm_front_centeredその点(0, 0, 0)(作業領域の中央)。各デバイス固有の「Configure」のセクションを参照してください。
ニュースの形式
このセクションでは、上位のエンベロープとメッセージタイプについて説明します。具体的な例については、このドキュメントの後半で紹介します。
機器グループ
メッセージは最上位レベルでデバイスタイプごとにグループ化されます(例: inverse3, verse_grip, wireless_verse_grip). 各デバイスタイプキーは、そのデバイス固有のオブジェクトを含む配列に関連付けられています。
Inventarの初期設定(サーバー → クライアント)
WebSocket接続の確立直後に1回送信されます。
各エントリには以下の内容が含まれます:
device_idconfigstatestatus
ステータス更新(サーバー → クライアント)
クライアントからのメッセージごとに1回送信されます。
各エントリには以下の内容が含まれます:
device_idstatestatus
参照:例:状態更新ペイロード
セッションコマンド用のエンベロープ(クライアント → サーバー)
セッションコマンドとは、現在の接続またはセッションに対して適用されるアクションであり、特定のデバイスに依存するものではありません。
{
"session": {
"<command_name>": {
"...": "..."
}
}
}
デバイスコマンド用のエンベロープ(クライアント → サーバー)
デバイスコマンドは、デバイスタイプキーの下で配列として送信されるため、1つのメッセージで1台または複数のデバイスにコマンドを送信することができます。各デバイスエントリは、 configure-割り当てだけでなく、 commands-割り当て。
{
"<device_type>": [
{
"device_id": "<id>",
"configure": {
"<config_key>": { "...": "..." }
},
"commands": {
"<command_name>": { "...": "..." }
}
}
]
}
1つのメッセージで同じ種類の複数のデバイスを制御するには、複数のエントリを指定することができます。
なお、以下の点にご注意ください。 commands 辞書は、特定のデバイスに対して複数のコマンドを含めることができますが、コマンドの種類ごとに1つしか含めることはできません。
その野原 execute
各コマンドまたはconfigureのエントリは、オプションのブール値を受け付けます "execute" (標準: true). 設定してください "execute": false、これにより、エントリは解析されますが、適用はされません。これは、リフレクションベースのシリアライザ(例:Unity)で役立ちます。 JsonUtility), これらは常にすべてのフィールドを出力します。
"set_cursor_force": { "execute": false, "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }
コマンドリファレンス
セッション
状態の完全なレンダリングを強制する
すべてのデバイスの状態と設定に関するスナップショットをリクエストしてください。
{
"session": {
"force_render_full_state": {}
}
}
セッションの設定
セッション単位の永続的な設定は、 session.configure 送信されました。これは、以下のパターンに合致します。 configure-デバイスレベルのマップ。
プロフィール
Haply Hubがシミュレーションを識別し、アプリごとにデバイス固有の設定を保存するために使用するセッションプロファイルの名前を指定します。
{
"session": {
"configure": {
"profile": {
"name": "my_profile"
}
}
}
}
基準(セッション全体)
セッション全体に対する基本マッピングを設定します。基本マッピングは、Haply の座標がアプリケーションの座標系にどのように変換されるかを定義するものです。 一度設定されると、すべてのデバイス状態はこの基本マッピングに基づいて返され、送信されたすべての 値もこの基本マッピングに基づいて解釈されます。
順列の文字列は、Z軸が上向きの右利き座標系を基準として、Haply によって指定されます。これは、以下の順列です。 X, Y, Z、必要に応じて、その前に + oder -. 例:
XYZ,ZYX,+Y-Z+X,X-ZYYZXつまり、あなたのYHaply の法的見解に合致する、貴殿のZHaply の進行方向と、あなたXHaply の上方方向。
Z軸が上向きの左利き用システムの例(Unreal、 X-YZ):
{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
session.set_basis軸の符号に関する規約は、時代遅れの session.set_basis und
session.configure.basis 変更されました。以前のコマンドでは正常に動作していた順列でも、新しいコマンドでは逆の変換結果が生成される場合があります。必要に応じて、軸の符号を反転させてください(例: X-ZY zu XZ-Y).
すべてのデバイス向けのコマンド
プロービング(すべての機器)
プロービングコマンドを使用して、力やその他のシミュレーションの変更を加えることなく、現在の位置および向きに関する情報を取得してください。
- inverse3:
probe_position - ヴァース・グリップ(
verse_grip,wireless_verse_grip):probe_orientation
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"probe_position": {}
}
}
],
"verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
],
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
]
}
変換を適用(すべてのデバイス)
デバイスに対するワークスペース変換(デバイス領域からアプリケーション領域へ)を設定します。
他のものとは違って commands-エントリは set_transform 永続的 – このサービスは、新しい値を送信するまで、最後に送信された値を保持します。ティックごとに値を送信する必要はありません。ただし、このサービスの目的はカメラやシーンのナビゲーションであるため、連続的に移動する場合は、ティックレートでのストリーミングが想定される使用パターンとなります(例:ユーザーがシーンを移動する際、1フレームごとに1回の変換を行うなど)。
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_transform": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}
]
}
「Verse grip」および「Wireless Verse grip」というデバイスでは、コンポーネントのみが影響を受けます。 rotation 変換の過程から――Gripは向きのみを報告するため、何も position oder scale 拡大・縮小や移動ができる。フィールドは position und scale これらは、Inverse3 とのスキーマの一貫性を保つという理由だけで受け入れられ(スナップショットで返されます)。通常は、これらを同一性値のままにしておくのが一般的です(position = {0,0,0}, scale = {1,1,1}).
Inverse3 対応デバイスの設定
設定エントリは、 configure-マップを送信しました。設定は永続化されます――一度送信するか、変更があった場合に送信してください。
プリセット
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front_centered" }
}
}
]
}
利用可能な値: device_defaults, arm_front, arm_front_centered, led_front, led_front_centered, custom.
基本(デバイスレベル)
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"basis": { "permutation": "ZXY" }
}
}
]
}
マウント
本装置の取り付け変換を指定します。以下の点に注意してください。 transform- 内のラッパー mount.
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"mount": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}
]
}
ダイ コマンドページ (クライアントからサーバーへ)には、以下の変換が含まれます: "mount": { "transform": { ... } }.
死ぬ スナップショットページ (サーバーからクライアントへ)の構成はフラットな構造となっています: "mount": { "position": {...}, "rotation": {...}, "scale": {...} }.
これは意図的な仕様です。コマンドは統一されたラッパーを使用しますが、スナップショットは変換結果を直接シリアル化します。スナップショットの構造をコマンドのペイロードにコピーしないようご注意ください。
減衰
均一な減衰および/または方向依存の減衰を制御します。少なくとも1つのフィールドを入力する必要があります。
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"damping": { "scalar": 0.5 }
}
}
]
}
方向に応じた減衰を設定したり、両方の設定を同時に適用したりすることもできます:
"damping": { "scalar": 0.5, "vector": { "x": 0.0, "y": 1.0, "z": 0.0 } }
フォース・ゲート
Force Gateの減衰ゲインを設定します(0.0~1.0)。
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"force_gate": { "gain": 0.3 }
}
}
]
}
Inverse3-コマンド
ある対象へのコマンドを inverse3- デバイスを送信するには、適切な device_id 鍵の下で inverse3 hinzu。コマンドは1ティックごとに有効であり、有効な状態を維持するには、各ティックごとに再度送信する必要があります。
単一のデバイスを制御する:
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
1つのメッセージで複数のデバイスを操作する:
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
},
{
"device_id": "049E",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
カーソル位置を設定する
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_position": {
"position": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
カーソル・クラフトを設定する
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
角度を設定する
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_position": {
"angles": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}
角トルクを設定する
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_torques": {
"torques": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}
Verse Grip 用設定
「Verse Grip」および「Wireless Verse Grip」は、同じ機能をサポートしています。 configure-「Inverse3 」のようなキーは、 preset, basis und mount.
Verse Grip用拡張プロトコル
コマンド set_extension_data これはVerse Grips用の拡張プロトコルの一部であり、ボード拡張プロトコルを実装したGripバージョンで使用されます。
グリップ拡張データを設定する
対応データ長:
- アップストリーム方向(クライアント→デバイス)で最大20バイト。
- ダウンストリーム方向(デバイス → クライアント)で最大 12 バイト。「State Update」メッセージ内で、次のように返されます。
state.extension_data.
データ仕様:
- 配列の長さ:20バイト
- 値の範囲:すべての値は0~255の範囲内です
{
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"set_extension_data": {
"extension_data": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
}
}
}
]
}
例
例:初期デバイスリスト(ペイロード)
WebSocketが接続されると、このサービスはデバイスの完全なリストを含むメッセージを送信します。最初のメッセージの内容は以下の通りです。 JSON-形式:
{
"inverse3": [
{
"device_id": "04BA",
"config": {
"type": "inverse3",
"port": "COM13",
"device_info": {
"major_version": 7,
"minor_version": 1,
"id": "04BA",
"device_type": 4,
"uuid": "2D35F80DD9005F599B68F49944CB04BA"
},
"extended_device_id": "2D35F80DD9005F599B68F49944CB04BA",
"extended_firmware_version": "8C20FDC8010AA1E15AA133CDA2534874",
"gravity_compensation": {
"enabled": true,
"scaling_factor": 1
},
"handedness": "right",
"streaming_mode": "USB",
"torque_scaling": {
"enabled": true
},
"home_return": {
"enabled": false
},
"filters": {
"force_gate": { "gain": 0.3 },
"damping": { "scalar": 0 }
},
"preset": "defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"angular_position": {
"x": -69.31704,
"y": 137.62952,
"z": 19.832787
},
"angular_velocity": {
"x": 0,
"y": 0,
"z": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"current_cursor_force": { "x": 0, "y": 0, "z": 0 },
"current_cursor_position": { "x": 0, "y": 0, "z": 0 },
"current_angular_torques": { "x": 0, "y": 0, "z": 0 },
"current_angular_position": { "x": 0, "y": 0, "z": 0 },
"control_domain": "cartesian",
"control_mode": "force",
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"config": {
"type": "verse_grip",
"port": "COM3",
"preset": "device_defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"config": {
"type": "wireless_verse_grip",
"port": "COM6",
"major_version": 1,
"minor_version": 4,
"hardware_version": 1,
"streaming_mode": "Radio",
"preset": "device_defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"connected": true,
"awake": true,
"ready": true
}
}
]
}
例:状態更新ペイロード
このサービスは、受信したメッセージごとに、すべてのデバイスの状態を含むステータス更新メッセージを送信します。
システムの状態を確認したい場合は、事前にシステムにメッセージ(例えば、プロービングコマンドや力値など。値がゼロであっても構いません)を送信する必要があります。これは、力を加えることなくデバイスを入力ソースとして使用する(例えば、位置追跡など)場合に特に重要です。
「ステータス更新」メッセージには、次のように記載されています。 JSON-形式:
{
"inverse3": [
{
"device_id": "04BA",
"state": {
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"angular_position": {
"x": -69.31704,
"y": 137.62952,
"z": 19.832787
},
"angular_velocity": {
"x": 0,
"y": 0,
"z": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"current_cursor_force": { "x": 0, "y": 0, "z": 0 },
"current_cursor_position": { "x": 0, "y": 0, "z": 0 },
"current_angular_torques": { "x": 0, "y": 0, "z": 0 },
"current_angular_position": { "x": 0, "y": 0, "z": 0 },
"control_domain": "cartesian",
"control_mode": "force",
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"connected": true,
"awake": true,
"ready": true
}
}
],
"custom_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"extension_data": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"ready": true
}
}
]
}