mcpField
X
xrift-world

xrift-world

github.com/webxr-jp開発173 回インストール5 日前に更新
リポジトリ

xrift-world について

xrift-worldは、XRift向けWebXRワールドを作成・変更するための開発ガイドです。React Three Fiber開発者向けに、プラットフォーム固有の実装ルール、デバイス対応要件、設定、コード参照をまとめています。

主な機能

  1. 01XRift APIと型のリファレンス
  2. 02アセット読み込みと配置ルール
  3. 03PC・モバイル対応の指針
  4. 043D操作とUIのパターン
  5. 05物理・カメラ設定

活用シーン

  1. 01XRift WebXRワールドの作成
  2. 02モバイルやVR向け操作の調整
  3. 03ワールドの物理とカメラの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/webxr-jp/xrift-skills --skill xrift-world

インストール後、Claude Code で/xrift-worldを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api-reference.md
code-templates.md
type-definitions.md

詳細

XRift ワールド開発ガイド

XRift プラットフォーム向けの WebXR ワールドを作成・変更するためのガイドです。

参考資料

  • API リファレンス - @xrift/world-components のすべてのフック、コンポーネント、定数の完全な仕様
  • コードテンプレート - GLB モデル、テクスチャ、Skybox、インタラクションなどの実装パターン
  • 型定義 - User、PlayerMovement、VRTrackingData、TeleportDestination、WorldInfo、InstanceInfo、ConfirmOptions、Tag、VideoState、LogEntry、PhysicsConfig、CameraConfig、VoiceVolumeOverrideContextValue の型定義

重要なルール(必ず守ってください)

  1. アセットを読み込むときは、必ず useXRift() の baseUrl を使用してください
  2. アセットファイルは public/ ディレクトリに配置してください
  3. baseUrl には末尾の / が含まれるため、${baseUrl}path の形式で結合してください(${baseUrl}/path は誤りです)
// Correct
const { baseUrl } = useXRift()
const model = useGLTF(`${baseUrl}robot.glb`)

// Wrong
const model = useGLTF('/robot.glb')           // Absolute path - NG
const model = useGLTF(`${baseUrl}/robot.glb`) // Extra / - NG

デバイス対応(必ず守ってください)

訪問者は PC、モバイル(スマートフォンとタブレット)、VR ヘッドセットから同じインスタンスに参加します。**ワールドは、少なくとも PC とモバイルの両方で動作する必要があります。**可能な限り VR にも対応してください。

デバイス対応操作方法
PC必須マウス+キーボード、中央の照準+クリック
モバイル必須タッチ、仮想ジョイスティック
VRできる限り対応コントローラー、レイ+トリガー

開発サーバー(npm run dev)では PC 操作しか試せないため、次のような問題を見落としがちです。

  1. **独自のキーボードショートカット(window.addEventListener('keydown'))に機能を依存させないでください。**モバイルと VR にはキーボードがないため、それらの機能は使えなくなります。W/A/S/D、Space、Q/E、G、H、Esc などのキーもプラットフォームによって使用されています。
    • ボタンとスイッチ:Interactable でラップします(PC ではクリック、モバイルではタッチ、VR ではコントローラーで操作)
    • 乗り物:Seat / Vehicle の onControlInput を使用します(キーボード、仮想ジョイスティック、サムスティックの入力はすべて同じ形式で届きます)
    • テキスト入力:TextInput。確認:useConfirm
    • ショートカットは、Interactable からも実行できるアクションについて、PC での利便性を高める目的でのみ使用できます
  2. **DOM 要素で HUD や UI を作成しないでください。**DOM オーバーレイは、画面の小さいモバイル端末や画面の向きを変えたモバイル端末で表示が崩れ、プラットフォームの仮想ジョイスティックやボタンに重なります。VR では 3D シーンのみがレンダリングされるため、DOM UI は一切表示されません。
    • UI は 3D 空間のオブジェクトとして配置します。@react-three/drei の Text、パネルやメニューには @react-three/uikit を使用します
    • 日本語テキストには useDefaultFont を読み込み、プレイヤーの方を向くように BillboardY でラップし、クリック可能にするには Interactable でラップします
  3. **進行を Grabbable だけに依存させないでください。**現在、つかむ操作が機能するのは PC のみです(ポインターロック+照準)。

プロジェクトの概要

  • 目的:XRift プラットフォーム向けの WebXR ワールド
  • 技術スタック:React Three Fiber + Rapier 物理エンジン + Module Federation
  • 動作の仕組み:CDN にアップロードされ、フロントエンドによって動的に読み込まれます

プロジェクト構成

xrift-world-template/
├── public/              # Asset files (place directly, no subdirectories needed)
│   ├── model.glb
│   ├── texture.jpg
│   └── skybox.jpg
├── src/
│   ├── components/      # 3D components
│   ├── World.tsx        # Main world component
│   ├── dev.tsx          # Development entry point
│   ├── index.tsx        # Production export
│   └── constants.ts     # Constants
├── .triplex/            # Triplex (3D editor) config
├── xrift.json           # XRift CLI config
├── vite.config.ts       # Build config (Module Federation)
└── package.json

xrift.json の設定

physics(物理設定)
フィールド型デフォルト説明
gravitynumber9.81重力の強さ(正の値。地球=9.81、月=1.62、木星=24.79)
allowInfiniteJumpbooleantrue無限ジャンプを許可するかどうか
{
  "physics": {
    "gravity": 9.81,
    "allowInfiniteJump": true
  }
}

例:

  • 障害物コースのワールド:落下のリスクを加えるには "allowInfiniteJump": false を設定します
  • 低重力のワールド:浮遊感のある動きにするには "gravity": 1.62(月の重力)を設定します
  • 高重力のワールド:重みのある動きにするには "gravity": 24.79(木星の重力)を設定します
camera(カメラ設定)
フィールド型説明
nearnumberニアクリップ距離(この距離より近いオブジェクトを非表示にします)
farnumberファークリップ距離(この距離より遠いオブジェクトを非表示にします)
{
  "camera": {
    "near": 0.1,
    "far": 1000
  }
}

例:

  • 広大なワールド:遠くのオブジェクトをレンダリングするには "far": 5000 を設定します
  • 精密なワールド:近距離のレンダリング精度を高めるには "near": 0.01 を設定します
outputBufferType(出力バッファーの種類)

WebGLRenderer の出力バッファーの種類を指定します。ポストプロセス処理と HDR レンダリングの精度に影響します。

値説明
UnsignedByteType8 ビット整数(デフォルト、標準的なレンダリング)
HalfFloatType16 ビット浮動小数点数(HDR とポストプロセス処理)
FloatType32 ビット浮動小数点数(最高精度、GPU 負荷は高め)
{
  "outputBufferType": "HalfFloatType"
}
items(最初から配置するアイテム)

<Item itemId> を使用してワールドに配置する、ユーザーが作成したアイテムの ID です。本番環境では、ここに記載された ID のアイテムのみが読み込まれます(入室時に事前読み込みされ、訪問者はこのリストからバンドルの URL を解決します)。自分で作成したアイテム、またはライブラリに追加したアイテム(マーケットプレイスで入手したもの)のみ宣言できます。最大 50 個です。

{
  "items": [
    "2a69ded4-d913-4359-8c1f-eac83a982b0c"
  ]
}

ローカル開発の場合は、@xrift/sdk/vite の xriftDev() を vite.config.ts に追加し、xrift login を実行します。これにより、DevEnvironment は開発サーバーのプロキシ(/__xrift)を介して、本番環境と同じバンドルを読み込みます。アイテムとワールドを同時に開発するには、<DevEnvironment items={{ [itemId]: Component }}> にローカルコンポーネントを渡します。

permissions(権限設定)

ワールドが必要とする権限を宣言します。宣言した権限は、インスタンスへの入室時に承認画面としてユーザーに表示されます。

フィールド型説明
allowedDomainsstring[]ワールドが通信する外部ドメイン
allowedCodeRulesstring[]緩和するコードセキュリティルール
{
  "permissions": {
    "allowedDomains": ["api.example.com", "cdn.example.com"],
    "allowedCodeRules": ["no-storage-access", "no-network-without-permission"]
  }
}
allowedCodeRules

@xrift/code-security アナライザーで定義されるルールです。デフォルトでは安全でない操作はブロックされますが、必要に応じて制限を緩和できます。

カテゴリルール説明
動的コードno-evaleval() を許可します
動的コードno-new-functionFunction コンストラクターを許可します
動的コードno-string-timeout文字列引数を指定した setTimeout/setInterval を許可します
動的コードno-javascript-blobJavaScript Blob の作成を許可します
難読化no-obfuscation難読化されたコードパターンを許可します
ネットワークno-network-without-permissionfetch、WebSocket などを許可します
ネットワークno-unauthorized-domainallowedDomains に含まれないドメインへの接続を許可します
ネットワークno-rtc-connectionWebRTC ピア接続を許可します
ネットワークno-external-import外部 JavaScript モジュールのインポートを許可します
ストレージno-storage-accesslocalStorage/sessionStorage の使用を許可します
ストレージno-cookie-accessCookie の読み書きを許可します
ストレージno-indexeddb-accessIndexedDB へのアクセスを許可します
ストレージno-storage-eventストレージイベントのリスニングを許可します
DOMno-dangerous-dominnerHTML とスクリプトの挿入を許可します
ブラウザー APIno-navigator-access位置情報、カメラ、マイク、クリップボードの使用を許可します
グローバルno-sensitive-api-overridefetch などの上書きを許可します
グローバルno-global-overridewindow、document の上書きを許可します
グローバルno-prototype-pollutionプロトタイプの変更を許可します

コマンドリファレンス

# Development
npm run dev        # Start dev server (http://localhost:5173)
npm run build      # Production build
npm run typecheck  # Type checking

# XRift CLI
xrift login        # Authenticate
xrift create world # Create new world project
xrift upload       # Upload (auto-detect from xrift.json)
xrift whoami       # Check logged-in user
xrift logout       # Log out

開発環境

npm run dev を実行して開発サーバーを起動します。一人称視点でワールド内を移動してテストできます。

操作キー
周囲を見るクリックしてマウスをロックし、マウスを動かします
移動W / A / S / D
上昇/下降E または Space / Q
インタラクト照準を合わせてクリックします
マウスロックを解除ESC

Interactable コンポーネントのクリック動作も開発環境でテストできます(中央の Raycaster が LAYERS.INTERACTABLE レイヤーを検出します)。Grabbable も動作します。G でつかんで配置し、マウスホイールで距離を調整して、クリックで確定します。

Seat と Vehicle は開発環境で登録されるだけです。着席にはアバター、カメラ、物理演算が必要なため、ワールドを XRift 上で実行するまでは何も起こりません。

dev.tsx の構成

src/dev.tsx は開発専用のエントリーポイントです。本番ビルドには含まれません。

注:本番環境では XRiftProvider は必要ありません(フロントエンドが自動的にラップします)。

依存関係

Required (peerDependencies)
  • react / react-dom ^19.0.0
  • three ^0.182.0
  • @react-three/fiber ^9.3.0
  • @react-three/drei ^10.7.3
  • @react-three/rapier ^2.1.0
XRift-specific
  • @xrift/world-components - XRift hooks and components
Module Federation Shared パッケージ

ホスト(xrift.net)と shared で共有されるパッケージ。ワールドの vite.config.ts で shared に宣言すれば、ワールドチャンクにバンドルされずホストから提供される。

パッケージバージョン要件
react^19.0.0
react-dom^19.0.0
react-dom/client-
react/jsx-runtime^19.0.0
three^0.176.0
three/addons/loaders/GLTFLoader.js-
three/addons/loaders/DRACOLoader.js-
three/addons/loaders/KTX2Loader.js-
@react-three/fiber^9.0.0
@react-three/rapier^2.0.0
@react-three/drei^10.0.0
@react-three/uikit^1.0.0
@pmndrs/uikit^1.0.0
@xrift/world-components^0.1.0
three/addons の注意
  • three/addons バレルを shared にすると Lottie 由来の eval がバンドルに含まれるため、サブパス単位で shared にしている
  • ワールド側でも three/addons/loaders/DRACOLoader.js のようにサブパスで import & shared 宣言する
// vite.config.ts — shared の設定例(xrift-world-template 準拠)
federation({
  name: 'xrift_world_template',
  filename: 'remoteEntry.js',
  exposes: {
    './World': './src/index.tsx',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^19.0.0' },
    'react-dom': { singleton: true, requiredVersion: '^19.0.0' },
    'react-dom/client': { singleton: true },
    'react/jsx-runtime': { singleton: true },
    three: { singleton: true, requiredVersion: '^0.176.0' },
    // three/addons はバレルではなくサブパス単位で宣言する
    'three/addons/loaders/DRACOLoader.js': { singleton: true },
    '@react-three/fiber': { singleton: true, requiredVersion: '^9.3.0' },
    '@react-three/rapier': { singleton: true, requiredVersion: '^2.1.0' },
    '@react-three/drei': { singleton: true, requiredVersion: '^10.7.3' },
    '@xrift/world-components': { singleton: true, requiredVersion: '^0.1.0' },
  },
}),

Troubleshooting

"useXRift must be used within XRiftProvider"

Cause: Not wrapped with XRiftProvider

Solution:

  • Check that src/dev.tsx uses XRiftProvider
  • When using Triplex: check .triplex/provider.tsx
Assets fail to load

Cause: Not using baseUrl, or incorrect path concatenation

Solution:

// Correct
const { baseUrl } = useXRift()
const model = useGLTF(`${baseUrl}robot.glb`)

// Wrong
const model = useGLTF('/robot.glb')
const model = useGLTF(`${baseUrl}/robot.glb`)
Physics not working

Cause: Not wrapped with Physics component, or missing RigidBody

Solution:

<Physics>
  <RigidBody type="fixed">  {/* or "dynamic" */}
    <mesh>...</mesh>
  </RigidBody>
</Physics>

Links

Example Implementations

  • GLB model: src/components/Duck/index.tsx
  • Skybox: src/components/Skybox/index.tsx
  • Animation: src/components/RotatingObject/index.tsx
  • Interaction: src/components/InteractableButton/index.tsx
  • User tracking: src/components/RemoteUserHUDs/index.tsx
  • Teleport: src/components/TeleportPortal/index.tsx
  • Main world: src/World.tsx

コメント