# 通知設計書 2-connected

## 概要

本ドキュメントは、three.jsライブラリにおける`connected`イベント通知の設計について記載する。`connected`イベントは、WebXRコントローラーがXRセッションに接続された際に発火するイベントである。

### 本通知の処理概要

`connected`イベントは、WebXR APIを使用したVR/ARアプリケーションにおいて、コントローラーの接続を検知し、アプリケーションがコントローラーの入力に応答できるようにするための重要なイベントである。

**業務上の目的・背景**：WebXRアプリケーションでは、ユーザーがVRコントローラーやハンドトラッキングデバイスを使用する。これらのデバイスがXRセッションに接続された時点でアプリケーションに通知し、コントローラーの3Dモデル表示、UI要素の配置、入力ハンドリングの初期化等を行う必要がある。`connected`イベントにより、アプリケーションはコントローラーの存在を認識し、適切なインタラクションを提供できる。

**通知の送信タイミング**：WebXRセッション中に新しい入力ソース（XRInputSource）が追加された際、`inputsourceschange`イベントを受けてWebXRControllerの`connect()`メソッドが呼び出され、`connected`イベントが発火される。

**通知の受信者**：`connected`イベントの受信者は、XRコントローラーの各座標空間（targetRay、grip、hand）を表すGroupオブジェクトに登録されたリスナーである。アプリケーション開発者は`controller.addEventListener('connected', callback)`でリスナーを登録する。

**通知内容の概要**：イベントオブジェクトには`type: 'connected'`と`data`プロパティが含まれ、`data`にはXRInputSourceオブジェクトへの参照が設定される。これにより、接続されたデバイスのタイプ（コントローラー/ハンド）、ハンド情報（左/右）等を取得できる。

**期待されるアクション**：受信者は、接続されたコントローラーに対応する3Dモデルをシーンに追加し、コントローラーの位置・回転に追従するようセットアップする。また、ボタンやトリガーの入力イベントハンドラーを設定する。

## 通知種別

アプリ内イベント通知（EventDispatcherパターン）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無 |

### 送信先決定ロジック

WebXRControllerクラスの`dispatchEvent()`メソッドにより、targetRay、grip、handの3つのGroupオブジェクトに対して順次イベントが送信される。各Groupに登録された`connected`タイプのリスナー関数すべてに通知される。

## 通知テンプレート

### イベントオブジェクト形式

| 項目 | 内容 |
|-----|------|
| type | 'connected' |
| data | XRInputSourceオブジェクト |
| target | dispatchEvent実行元Groupオブジェクト（自動設定） |

### イベントオブジェクト例

```javascript
{
  type: 'connected',
  data: XRInputSource, // inputSource.handedness, inputSource.hand等を含む
  target: <Group>
}
```

### 添付ファイル

該当なし（イベント通知のため添付ファイルは存在しない）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | イベントタイプ | 固定値 'connected' | Yes |
| data | XR入力ソース | WebXR API XRInputSource | Yes |
| target | イベント発火元オブジェクト | EventDispatcher.dispatchEvent内で自動設定 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| WebXR API | inputsourceschange | event.addedに入力ソースが存在 | XRセッションで新しい入力ソースが追加された時 |
| 内部API | WebXRController.connect() | 常に送信 | connectメソッドが呼び出された時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| リスナー未登録 | 各座標空間（targetRay、grip、hand）に対応するGroupオブジェクトにリスナーが登録されていない場合は、そのGroupへの通知はスキップ |
| Groupが未初期化 | _targetRay、_grip、_handがnullの場合、そのGroupへの通知はスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[XRSession inputsourceschange発火] --> B[onInputSourcesChange処理]
    B --> C[event.addedをループ処理]
    C --> D[controller.connect inputSource 呼び出し]
    D --> E{inputSource.handが存在?}
    E -->|Yes| F[handのjointsを初期化]
    E -->|No| G[スキップ]
    F --> H[dispatchEvent type: connected, data: inputSource]
    G --> H
    H --> I{_targetRayがnullでない?}
    I -->|Yes| J[_targetRay.dispatchEvent event]
    I -->|No| K[スキップ]
    J --> L{_gripがnullでない?}
    K --> L
    L -->|Yes| M[_grip.dispatchEvent event]
    L -->|No| N[スキップ]
    M --> O{_handがnullでない?}
    N --> O
    O -->|Yes| P[_hand.dispatchEvent event]
    O -->|No| Q[終了]
    P --> Q
```

## データベース参照・更新仕様

該当なし（three.jsはクライアントサイドライブラリのためデータベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| リスナーエラー | リスナー関数内で例外が発生 | 例外はキャッチされず呼び出し元に伝播 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（XRセッション中のみ発火）

## セキュリティ考慮事項

- XRInputSourceオブジェクトには位置情報等のセンシティブなデータが含まれる可能性があるが、WebXR API自体がユーザー許可を必要とする
- イベントリスナー内でのデータ取り扱いはアプリケーション実装の責任範囲

## 備考

- `connected`イベントはXRセッション開始直後、または既存セッション中にコントローラーが追加された際に発火する
- 同一のXRInputSourceに対して複数のWebXRControllerが作成されることはない
- handモードの場合、connect時にhand.jointsが初期化される

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

WebXRControllerの内部構造と座標空間の概念を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WebXRController.js | `src/renderers/webxr/WebXRController.js` | _targetRay、_grip、_handの3つの座標空間の役割を理解 |

**読解のコツ**: WebXRControllerは12行目から425行目までのクラス。各座標空間はGroupオブジェクトで表現され、EventDispatcherを継承している。

#### Step 2: エントリーポイントを理解する

connectメソッドの実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WebXRController.js | `src/renderers/webxr/WebXRController.js` | 156-179行目のconnect()メソッド |

**主要処理フロー**:
1. **156行目**: connect(inputSource)メソッドの定義開始
2. **158-173行目**: handモードの場合、jointsを初期化
3. **175行目**: `this.dispatchEvent( { type: 'connected', data: inputSource } )`でイベント発火

#### Step 3: イベントディスパッチの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WebXRController.js | `src/renderers/webxr/WebXRController.js` | 126-148行目のdispatchEvent()メソッド |

**主要処理フロー**:
- **128-132行目**: _targetRayがnullでなければイベントを送信
- **134-138行目**: _gripがnullでなければイベントを送信
- **140-144行目**: _handがnullでなければイベントを送信

#### Step 4: 呼び出し元（WebXRManager）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | WebXRManager.js | `src/renderers/webxr/WebXRManager.js` | 550-614行目のonInputSourcesChange()関数 |

**主要処理フロー**:
- **570-573行目**: event.addedをループ処理
- **604-610行目**: controller.connect(inputSource)を呼び出し

### プログラム呼び出し階層図

```
XRSession
    │
    └─ inputsourceschange イベント
           │
           └─ WebXRManager.onInputSourcesChange()
                  │
                  └─ WebXRController.connect(inputSource)
                         │
                         ├─ hand.joints 初期化（handモード時）
                         │
                         └─ this.dispatchEvent({ type: 'connected', data: inputSource })
                                │
                                ├─ _targetRay.dispatchEvent(event)
                                │      └─ リスナー呼び出し
                                │
                                ├─ _grip.dispatchEvent(event)
                                │      └─ リスナー呼び出し
                                │
                                └─ _hand.dispatchEvent(event)
                                       └─ リスナー呼び出し
```

### データフロー図

```
[入力]                         [処理]                              [出力]

XRSession
inputsourceschange ───▶ onInputSourcesChange() ───▶ connect() ───▶ connectedイベント
    │                                                              │
    └─ event.added ─────────────────────────────────────────▶ data: XRInputSource
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WebXRController.js | `src/renderers/webxr/WebXRController.js` | ソース | XRコントローラーの管理、connectedイベント発火 |
| WebXRManager.js | `src/renderers/webxr/WebXRManager.js` | ソース | WebXR APIとの連携、inputsourceschangeイベントのハンドリング |
| EventDispatcher.js | `src/core/EventDispatcher.js` | ソース | イベント発火の基盤クラス |
| Group.js | `src/objects/Group.js` | ソース | 座標空間を表すオブジェクト（EventDispatcher継承） |
