Contents
導入
Figmin XR スクリプト API を用いた実務的な開発ガイドです。中級〜上級開発者を対象に、実機での検証と運用を念頭に置いた手順と注意点を示します。この記事は Figmin XR スクリプト API の型定義、正確な API シグネチャ、Quest 3 の Passthrough 権限、トークン運用やデバッグの実務例までを具体的に解説します。
開発環境の準備(必須ツール、Quest 3 設定、adb)
ローカル開発と実機デバッグの環境を整えます。Node.js、TypeScript、Git、VS Code、adb/Oculus Developer Hub を基本にします。Quest 3 は開発者モード有効化と USB デバッグか Wi‑Fi adb の準備が必要です。
必須ツールとローカルセットアップ
ここでは必要なツールと推奨設定を示します。バージョンや詳細は公式ドキュメントに合わせてください。
- Node.js(LTS 推奨。例: 18/20 LTS)
- npm または yarn(依存管理)
- TypeScript(型安全のため、実務では導入を推奨)
- エディタ:VS Code(ESLint / Prettier 拡張を導入)
- Git(バージョン管理)
- Figmin CLI / コンソール(スクリプト登録・シーン管理)
- adb(Android Platform Tools)と Oculus Developer Hub(ODH)
- ODH はビルド管理やログ収集が容易になります
Quest 3 のデバイス設定と接続
Quest 3 で実機デバッグを行うための基本手順を示します。Meta の開発者ガイドも参照してください。
- Meta/Meta for Developers(旧 Oculus)で開発者アカウントを登録します(developer portal)。
- Meta/Quest モバイルアプリでデバイスを開発者モードにします。
- Oculus Developer Hub をインストールし、デバイスを接続してログやパッケージ管理を行います。
- デバイスで USB デバッグ(および必要に応じて Wi‑Fi adb)を有効にします。詳しくは Meta の開発者ページを参照してください(例: https://developer.oculus.com/)。
adb とローカルサーバ接続の具体例
adb を使った再現可能なコマンド例と、トラブルシューティング手順を示します。各コマンドは PC 側の環境や adb バージョンに依存します。
- 接続確認(USB 接続時):
|
1 2 3 4 |
adb devices # 出力例: List of devices attached # 192.168.1.10:5555 device |
- Wi‑Fi 接続(デバイス側で adb を有効にしたあと):
|
1 2 3 |
adb tcpip 5555 adb connect 192.168.1.10:5555 |
- 開発サーバをデバイスから参照させる(device -> host の接続):
|
1 2 3 |
# PC で dev サーバが 8080 を listen している想定 adb reverse tcp:8080 tcp:8080 |
- Chrome DevTools(Oculus Browser)のリモートデバッグ用(ポート 9222 を転送する一例):
|
1 2 3 |
adb forward tcp:9222 localabstract:chrome_devtools_remote # その後 chrome://inspect で 9222 を指定して接続します |
トラブル対処のヒント:
- adb が unauthorized の場合、ヘッドセット内でデバッグ許可ダイアログを許可してください。
- Wi‑Fi 接続が不安定な場合は USB 接続でデバッグしてください。
- ファイアウォールがポートをブロックしていないか確認します。
Hello World と API シグネチャ(TypeScript 型定義、回転単位)
Figmin のスクリプト実行は標準的に register 関数をエクスポートする形です。ここでは実務で使える TypeScript の型定義例と、API の引数・戻り値・主要なエラーケースを明示します。回転はラジアン、座標は右手系(Y 上)を前提にします。
Script API の TypeScript 型定義とシグネチャ
以下は Figmin スクリプト API の代表的な型定義例です。実際の製品版 API はバージョンにより差異がありますので、必ず公式ドキュメント(下部参照)を合わせて確認してください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// 型定義の例(figmin-sdk の仮想型) export type Vec3 = [number, number, number]; export type Quat = [number, number, number, number]; export interface ScriptContext { scene: Scene; log: (message: string, level?: 'info'|'warn'|'error') => void; // その他 utilities... } export interface Scene { createEntity(opts?: { name?: string; prefab?: string }): Entity; findEntityByName(name: string): Entity | null; raycast(origin: Vec3, direction: Vec3, opts?: { maxDistance?: number }): RaycastHit[]; } export interface Entity { id: string; name?: string; addComponent<T = any>(type: string, props?: T): Component; getComponent<T = any>(type: string): Component | null; removeComponent(type: string): void; transform: Transform; destroy(): void; } export interface Transform { setPosition(pos: Vec3): void; // 単位: メートル getPosition(out?: Vec3): Vec3; setScale(s: Vec3): void; setRotationEuler(rad: Vec3, order?: 'XYZ'|'YXZ'|'ZXY'): void; // ラジアン setRotationQuaternion(q: Quat): void; } |
注意点(エラーケース):
- scene.createEntity はシーンがロード中または容量超過の場合に例外を投げる場合があります(実装により null を返すこともありうる)。
- addComponent は型不一致や未知のコンポーネント名で例外を投げることがあるため、呼び出し側で try/catch を検討してください。
- onUpdate の dt は秒単位の浮動小数点です。
Hello World 実装(回転単位と座標系の明示)
回転はラジアン、座標は右手系で Y が上方向です。以下は修正版のサンプル(TypeScript 形式)です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// hello-world.ts import type { ScriptContext, Entity } from 'figmin-sdk'; const DEG2RAD = Math.PI / 180; export default function register(ctx: ScriptContext) { const { scene, log } = ctx; let box: Entity | null = null; let angleRad = 0; // ラジアンで管理 return { async onAttach(parent) { // createEntity は Entity を返す。例外が出る場合は捕捉する。 box = scene.createEntity({ name: 'hello-box' }); box.addComponent('mesh', { primitive: 'box' }); box.addComponent('material', { color: '#FF6600' }); // 座標単位はメートル。ここではユーザの目線より下に配置。 box.transform.setPosition([0, 1.2, -1.5]); box.transform.setScale([0.3, 0.3, 0.3]); // 初期回転はオイラー(ラジアン) box.transform.setRotationEuler([0, 0, 0]); log('Hello World: box created'); }, onUpdate(dt) { // dt は秒。回転速度は 30 deg/s とする。 angleRad += (30 * DEG2RAD) * dt; if (box) { // Y 軸周りに回転(右手系、+Y は上) box.transform.setRotationEuler([0, angleRad, 0]); } }, onDetach() { if (box) { box.destroy(); box = null; log('Hello World: box destroyed'); } } }; } |
このサンプルの前提:
- 座標はメートル、回転はラジアン。
- 回転配列は Euler [x, y, z](回転順序は API のオプションで指定可能)。
- 物理的な速度や配置は VR の実測で調整してください。
API の戻り値とエラーケース(主要メソッド)
以下は主要 API の想定シグネチャと考えられるエラー例です。
- Scene.createEntity(opts?): Entity
- 戻り値: Entity(成功)
- エラー: SceneNotLoadedError、CapacityExceededError、InvalidPrefabError
- Entity.addComponent(type: string, props?): Component
- 戻り値: Component
- エラー: UnknownComponentError、InvalidPropsError
- Transform.setPosition(pos: Vec3): void
- エラー: InvalidArgumentError(NaN を与えた場合等)
- Scene.raycast(origin, dir, opts?): RaycastHit[]
- 戻り値: 空配列またはヒット配列(distance, point, normal, entityId)
- エラー: InvalidArgumentError、PhysicsUnavailableError
実務ではこれらのエラーを try/catch してフォールバックを用意してください。
入力・アニメーション・物理(実践パターンと評価手順)
入力、アニメーション、物理は体験品質に直結します。ここでは実践的なコードパターンとパフォーマンス評価手順を示します。GC を増やさない実装や評価指標を必ず取り入れてください。
Transform/Material/Animation の実践例
Transform 操作では一時配列を再利用して GC を減らします。補間は四元数 slerp を用いると回転の破綻が少ないです。
|
1 2 3 4 5 6 7 8 9 10 |
// ベクトル再利用と線形補間の例 const tmpPos: [number, number, number] = [0, 0, 0]; function lerpVec(out: [number, number, number], a: [number, number, number], b: [number, number, number], t: number) { out[0] = a[0] + (b[0] - a[0]) * t; out[1] = a[1] + (b[1] - a[1]) * t; out[2] = a[2] + (b[2] - a[2]) * t; return out; } |
アニメーションの注意:
- マテリアルはプロパティだけ更新し、オブジェクトを再生成しない。
- 大きなタイムライン管理は System 側で行う。
ユーザー入力(ハンドトラッキング/コントローラ/Raycast)
入力は複数のソースを抽象化します。Raycast 経由での選択とグラブは一般的な実装です。
- 想定 API(例):
- Input.on(event: 'selectstart'|'selectend'|'squeeze', handler: (ev)=>void)
- Scene.raycast(origin: Vec3, dir: Vec3): RaycastHit[]
グラブの流れ:
- selectstart で raycast を実行して対象を特定する。
- 対象を kinematic に切り替え、手(ハンド)に親子付けする。
- selectend で物理に戻し、速度を与えて投げる。
ハプティクス:
- 短い振動は操作感を高めますが過度は避けます。
物理シミュレーションの実務的注意点と評価方法
物理の品質はステップ周波数とソルバ設定に依存します。負荷低減でステップ周波数を下げると安定性や精度が低下します。評価手順とメトリクス例を示します。
- 評価手順例:
- ベースライン(例: 60Hz、CCD 無効)のテストシーンを用意する。
- 同一シーンで 30Hz、45Hz 等に切り替え、定量的な差を計測する。
- 計測項目: フレームレート、CPU 使用率、衝突ミス率、オブジェクト位置の RMS 誤差。
-
高速オブジェクトでのトンネリング(衝突抜け)や振動を確認する。
-
一般的な影響:
- 30Hz に下げると、移動の滑らかさが低下し衝突の精度が落ちる可能性が高いです。
- 対応策: CCD(連続衝突検出)、サブステップ、物理予測の導入。
実務では自動化テストで RMS 誤差や衝突ミス数の閾値を定め、変更時に回帰テストを回してください。
Quest 3 向け MR(Passthrough)とプラットフォーム要件
Passthrough を使った MR 統合は権限・同意・プライバシー要件が中心的です。Meta(Oculus)のプラットフォームポリシーに従った同意 UI、データ処理の開示、ストレージや送信の制限が必要です。
Passthrough の権限フローと Meta の要件(参照リンク付き)
Passthrough 利用時はユーザーに明示的な同意を得ることが必須です。カメラ映像を端末外へ送信する場合は追加の規約遵守が求められます。公式情報の参照先(一例):
- Figmin スクリプト API(Script/Authentication/Entities などの該当章):
- https://www.figmin.com/api/documentation.html#script-api
-
https://www.figmin.com/api/documentation.html#authentication
-
Meta / Oculus(Passthrough・権限・ポリシー):
- Oculus Developer Hub / Docs: https://developer.oculus.com/
- Platform Policy(権限・プライバシー要件): https://developer.oculus.com/policy/
- データ取扱いとプライバシーに関する一般的指針: https://developers.facebook.com/policy/
必ず最新ドキュメントの「Passthrough」「Permissions」「Privacy」章を参照してください。権限フローや UI 表示要件は頻繁に更新されます。
実装例: Passthrough レイヤとオクルージョン
実装上の基本方針:
- ランタイムの許可 API を呼び出してからレイヤを有効化する。
- 深度情報が提供される場合は深度ベースでオクルージョンを行う。
- 深度が無い場合はステンシルや手動マスクで代替する。
概念的なコード例(擬似):
|
1 2 3 4 5 |
// パーミッション取得と Passthrough レイヤ生成の流れ(擬似) await platform.requestCameraPermission(); // プラットフォーム API const layer = scene.createPassthroughLayer({ opacity: 1.0 }); layer.setDepthMask(true); // デバイスが深度を提供する場合 |
実装時の注意:
- Passthrough レイヤはレンダリングコストを増やします。必要時のみ有効化してください。
- ユーザーが明確に許可/無効化できる UI を提供してください。
プライバシーとデータ処理の注意点
カメラ映像や深度データの収集・保存・送信には厳しい制約があります。遵守すべき一般的原則:
- 必要最小限のデータのみを扱う。
- ユーザーに対して利用目的を明示し、明示同意を得る。
- カメラ映像を外部サーバに送る場合は追加の法的合意とセキュリティ対策が必要。
- GDPR、CCPA 等の地域法規に従うこと(該当する場合)。
運用と運用設計(マルチプレイヤー同期、デバッグ、デプロイ、セキュリティ)
運用フェーズでの設計と検証手順を提示します。ここではマルチプレイヤー同期、プロファイリング、CI/デプロイ、認証・トークンの安全運用に重点を置きます。これらはそれぞれ別ページに詳細化することを推奨します。
マルチプレイヤー同期設計(戦略、帯域対策、メッセージ設計)
同期戦略の選択は体験要件によります。低遅延を優先するならクライアント予測+サーバ補正、整合性を重視するなら権威サーバを採用します。
- 典型的メッセージ設計(位置更新、イベント):
|
1 2 3 4 5 6 7 8 9 10 |
// 位置更新メッセージ(バイナリ推奨) struct PosUpdate { uint32 entityId; int16 x; // スケールして int16 化(例: meters * 1000) int16 y; int16 z; int16 rotY; // 角度を量子化 uint16 timestamp; // ms low16 } |
- 帯域削減手法:
- 差分(delta)同期
- 興味管理(Interest Management)
- 量子化と圧縮(座標を int16 にスケール)
-
更新頻度を役割ごとに変える(プレイヤー 10-20Hz、重要イベントは即時)
-
権威の検証:
- サーバ側で速度や位置の不正を検証し、必要に応じて補正を返す。
デバッグとプロファイリング(手順とツール)
実機での定量的プロファイリングが重要です。優先順位はフレームレート、CPU/GPU、メモリ、ネットワークです。
- 主要ツール:
- Chrome DevTools(chrome://inspect)
- Oculus Developer Hub のログ/プロファイリング
- adb logcat(デバイスログ)
- 測定例(フレームタイム):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 簡易 FPS 計測 let last = performance.now(); let frames = 0; function frame() { const now = performance.now(); frames++; if (now - last >= 1000) { console.log('FPS', frames); frames = 0; last = now; } requestAnimationFrame(frame); } |
- ネットワークの診断:
- RTT 測定用に ping/pong を実装して ms 単位でログを取る。
デプロイと CI(TypeScript、ESLint、ビルド、GitHub Actions 例)
実運用では静的ホスティング(CDN)+HTTPS を基本にします。ネイティブ配布は各ストアの要件に従ってください。
- 代表的な tsconfig.json(抜粋):
|
1 2 3 4 5 6 7 8 9 10 11 |
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "lib": ["DOM", "ES2020"], "strict": true, "outDir": "dist", "sourceMap": true } } |
- ESLint / Prettier と組み合わせ例(設定はプロジェクトに合わせて調整):
|
1 2 3 4 5 6 7 |
// .eslintrc.js(抜粋) module.exports = { parser: '@typescript-eslint/parser', extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], rules: { /* チーム規約 */ } }; |
- GitHub Actions(CI)のサンプル(抜粋):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '18' } - run: npm ci - run: npm run lint - run: npm run build - run: npm test |
デプロイはビルド成果物を CDN/S3/CloudFront 等へアップロードし、HTTPS で配信してください。Figmin へのアップロードは Figmin CLI を用います(公式手順に従う)。
セキュリティと認証(短命トークン、リフレッシュトークン、CORS、サーバ側検証)
クライアントに永久トークンを埋め込まないことが最重要です。安全なフローの例を示します。
- 推奨フロー(概念):
- 認証サーバでユーザ認証を行い、短命 Access Token(例: 有効期間 5〜15 分)を発行する。
- Refresh Token は HttpOnly, Secure, SameSite=strict の Cookie に保存し、リフレッシュ時に回転(rotating refresh token)を行う。
- クライアントは Access Token を Authorization: Bearer ヘッダで API に送る。
-
サーバはトークン署名とスコープを検証し、重要な判定はサーバ側で行う。
-
Express による CORS 設定例:
|
1 2 3 4 5 6 7 8 |
const cors = require('cors'); app.use(cors({ origin: 'https://your.app.domain', methods: ['GET','POST','PUT','DELETE'], allowedHeaders: ['Content-Type','Authorization'], credentials: true })); |
- トークン発行の擬似コード(概念):
|
1 2 3 4 5 6 |
// access token: 5m, refresh token stored hashed in DB const accessToken = jwt.sign({ sub: userId, scope: 'script:run' }, ACCESS_SECRET, { expiresIn: '5m' }); const refreshToken = generateSecureRandom(); storeHashedRefreshToken(userId, hash(refreshToken)); setHttpOnlyCookie(res, 'refresh', refreshToken); |
注意:
- リフレッシュトークンの盗難対策として「リフレッシュトークンの回転」を実装し、使われたトークンを失効させること。
- API の重要操作(アセット編集、課金処理等)はサーバ側で常に再検証すること。
ログと個人情報の取り扱い(マスキング、保持期間、アクセス制御)
ログに個人情報やトークンを出力しないでください。ログは最小化し、必要時にマスキング処理を行います。
- マスキングの例(擬似コード):
|
1 2 3 4 |
function maskPII(msg) { return msg.replace(/\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})\b/g, '[EMAIL]'); } |
- 運用ルール(例):
- デバッグログの保持期間: 7〜30 日
- セキュリティログの保持期間: 90〜365 日(法令と社内ポリシーに合わせる)
- ログへのアクセスは RBAC で制御し、監査ログを残す
運用時のよくあるトラブルと対処
代表的な問題と初期対応例を列挙します。
- 接続できない(adb/ネットワーク):
- adb devices で認識を確認。unauthorized はヘッドセットの許可ダイアログを確認。
- adb reverse が効かない場合はファイアウォール設定や adb バージョンを確認。
- Passthrough が動作しない:
- ランタイムのパーミッションが付与されているか、プラットフォームポリシーを確認。
- CORS/認証エラー:
- サーバの CORS 設定とトークン検証ロジック(iss/aud/exp)を確認。
- 物理オブジェクトがジャンプする:
- 物理ステップ周波数とサブステップ、質量設定を見直す。
参考リンクと公式ドキュメント
以下は必ず公式を最初に確認するためのリンク例です。外部ブログ等を参照する場合は信頼性を検証してください。
- Figmin 公式 API ドキュメント(スクリプト API / 認証 / Entity)
- https://www.figmin.com/api/documentation.html#script-api
- https://www.figmin.com/api/documentation.html#authentication
-
https://www.figmin.com/api/documentation.html#entities
-
Meta / Oculus(Passthrough、権限、ポリシー)
- Oculus Developer: https://developer.oculus.com/
- Platform Policy: https://developer.oculus.com/policy/
-
データ・プライバシー参考: https://developers.facebook.com/policy/
-
法令・プライバシー(参考)
- GDPR 概要: https://gdpr.eu/
- CCPA 概要: https://oag.ca.gov/privacy/ccpa
注意: app-tatsujin.com 等の第三者サイトは一次情報ではありません。第三者資料を使う場合は著者・更新日・一次出典を確認し、公式情報を優先してください。
まとめ
Figmin XR スクリプト API を使った実務開発の要点を押さえました。まずはローカルと Quest 3 の接続を確立し、TypeScript 型定義に沿った実装で回転単位(ラジアン)や座標系(右手系・Y 上)を明確にします。Passthrough は Meta の権限とプライバシー要件に厳密に従い、カメラデータの取り扱いを最小化してください。運用面では短命トークン、リフレッシュトークンの回転、ログのマスキング、CI による静的チェックを導入し、パフォーマンスは実機で定量評価してから妥協案(物理ステップ削減など)を適用してください。