# 機能設計書 115-PropertyBinding

## 概要

本ドキュメントは、Three.jsにおける`PropertyBinding`クラスの機能設計を記述する。PropertyBindingは、シーングラフ内の実際のプロパティへの参照を保持し、アニメーション値をオブジェクトプロパティに適用するための内部クラスである。

### 本機能の処理概要

PropertyBindingは、アニメーショントラック名（例: "mesh.position", "material.color"）を解析し、シーングラフ内の対応するオブジェクトとプロパティを特定して、アニメーション値の読み取り・書き込みを行う橋渡し役を担う。状態パターンを用いて、プロパティの種類に応じた最適なgetter/setterを動的に選択する。

**業務上の目的・背景**：アニメーションシステムがシーングラフ内の任意のプロパティを操作するためには、文字列ベースのパスから実際のプロパティへのバインディングが必要である。PropertyBindingは、このパス解析とプロパティアクセスを抽象化し、様々なプロパティ形式（直接値、配列、toArray/fromArrayメソッドを持つオブジェクト等）に対応する。

**機能の利用シーン**：
- Object3Dのposition, rotation, scaleアニメーション
- Materialのcolor, opacityアニメーション
- MorphTargetのinfluenceアニメーション
- SkeletonのBoneアニメーション
- カスタムオブジェクトプロパティのアニメーション

**主要な処理内容**：
1. トラック名のパース（nodeName, objectName, propertyName等の抽出）
2. シーングラフ内のノード検索
3. プロパティタイプに応じたgetter/setterの動的選択
4. needsUpdate/matrixWorldNeedsUpdateフラグの自動設定
5. AnimationObjectGroup用のCompositeバインディング

**関連システム・外部連携**：AnimationAction、PropertyMixer、AnimationObjectGroupと連携し、アニメーションの実際の適用を担当する。

**権限による制御**：特になし（ライブラリ内部機能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 該当なし | - | - | PropertyBindingはライブラリ内部で使用されるクラスであり、直接的なUI関連はない |

## 機能種別

プロパティアクセス / パス解析 / 状態パターン実装

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| rootNode | Object3D\|Skeleton | Yes | 検索の起点となるルートオブジェクト | - |
| path | string | Yes | プロパティパス | - |
| parsedPath | Object | No | 事前にパース済みのパス情報 | - |

### 入力データソース

- KeyframeTrackのname属性からのプロパティパス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| path | string | プロパティパス |
| parsedPath | Object | パース済みパス情報 |
| node | Object | バインド先ノード |
| rootNode | Object | ルートオブジェクト |

### 出力先

- PropertyMixerを介してオブジェクトプロパティに反映

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ
   └─ パスのパース（parsedPath生成）
   └─ ノードの検索（findNode）
   └─ 初期状態: getValue/setValue = unbound

2. bind() - プロパティバインディング
   └─ ノードの再検索（必要に応じて）
   └─ objectNameの解決（materials, bones, map等）
   └─ プロパティの解決
   └─ バインディングタイプの決定
   └─ バージョニングスキームの決定
   └─ getter/setterの選択

3. getValue() / setValue() - 値の読み書き
   └─ unbound状態なら自動bind()
   └─ バインディングタイプに応じた処理
```

### フローチャート

```mermaid
flowchart TD
    A[PropertyBinding生成] --> B[パースまたは既存parsedPath使用]
    B --> C[findNodeでノード検索]
    C --> D{getValue/setValue呼び出し}
    D --> E{bound状態?}
    E -->|No| F[bind呼び出し]
    E -->|Yes| G[getter/setter実行]
    F --> H{ノード存在?}
    H -->|No| I[unavailable設定]
    H -->|Yes| J{objectName解決}
    J --> K{プロパティ解決}
    K --> L{バインディングタイプ決定}
    L -->|Direct| M[直接アクセス]
    L -->|EntireArray| N[配列アクセス]
    L -->|ArrayElement| O[配列要素アクセス]
    L -->|HasFromToArray| P[fromArray/toArrayアクセス]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-115-01 | サポートオブジェクト名 | material, materials, bones, mapがサポート | objectName解決時 |
| BR-115-02 | 自動バインド | unbound状態でのアクセスは自動bind | getValue/setValue呼び出し時 |
| BR-115-03 | バージョニング | Material→needsUpdate、Object3D→matrixWorldNeedsUpdate | bind時にプロパティタイプから決定 |
| BR-115-04 | モーフターゲット名解決 | morphTargetInfluencesは名前からインデックスを解決 | propertyIndex解決時 |

### 計算ロジック

**トラック名パース**（parseTrackName）:
- 正規表現: `^(directory*)(nodeName)?(\.objectName[objectIndex])?(\.propertyName[propertyIndex])$`
- サポートフォーマット例:
  - `mesh.position`
  - `mesh.material.color`
  - `.bones[Armature.DEF_cog].position`

## データベース操作仕様

該当なし（メモリ内データ構造）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Error | パースエラー | 不正なトラック名 | 正しいパス形式を使用 |
| Error | パースエラー | propertyNameが空 | propertyNameを指定 |
| - | 警告 | ターゲットノードが見つからない | パスまたはシーン構造を確認 |
| - | エラーログ | プロパティが見つからない | プロパティ名を確認 |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- bind()は初回のみ実行、以降はキャッシュされたgetter/setterを使用
- 状態パターンによりif文を排除した高速なプロパティアクセス

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

特になし

## 備考

- PropertyBinding.Compositeは AnimationObjectGroup用の特殊バインディング
- unbind()でバインディングを解除し、再度bindできる状態に戻る

---

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

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

### 推奨読解順序

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

PropertyBindingの基本構造と正規表現パターンを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PropertyBinding.js | `src/animation/PropertyBinding.js` | 正規表現パターン（3-36行目） |
| 1-2 | PropertyBinding.js | `src/animation/PropertyBinding.js` | コンストラクタ（109-152行目） |

**読解のコツ**:
- `_trackRe`: トラック名全体のパース用正規表現
- `_supportedObjectNames`: サポートされるオブジェクト名（material, materials, bones, map）
- コンストラクタでpath, parsedPath, node, rootNodeを初期化
- 初期状態のgetValue/setValueはunboundメソッド

#### Step 2: 静的ユーティリティを理解する

静的メソッドの役割を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PropertyBinding.js | `src/animation/PropertyBinding.js` | create()（164-176行目） |
| 2-2 | PropertyBinding.js | `src/animation/PropertyBinding.js` | sanitizeNodeName()（185-189行目） |
| 2-3 | PropertyBinding.js | `src/animation/PropertyBinding.js` | parseTrackName()（209-255行目） |
| 2-4 | PropertyBinding.js | `src/animation/PropertyBinding.js` | findNode()（266-324行目） |

**主要処理フロー**:
- **164-176行目**: create() - AnimationObjectGroupならComposite、そうでなければPropertyBinding
- **185-189行目**: sanitizeNodeName() - スペースをアンダースコアに、予約文字を削除
- **209-255行目**: parseTrackName() - トラック名をパースして構造化データに
- **266-324行目**: findNode() - シーングラフ内のノードを検索（skeleton, children対応）

#### Step 3: プロパティアクセサを理解する

getter/setterの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PropertyBinding.js | `src/animation/PropertyBinding.js` | getter群（332-360行目） |
| 3-2 | PropertyBinding.js | `src/animation/PropertyBinding.js` | setter群（364-468行目） |
| 3-3 | PropertyBinding.js | `src/animation/PropertyBinding.js` | バインディングタイプ/バージョニング（737-790行目） |

**主要処理フロー**:
- `_getValue_direct`: 単純プロパティの直接読み取り
- `_getValue_array`: 配列全体の読み取り
- `_getValue_arrayElement`: 配列要素の読み取り
- `_getValue_toArray`: toArrayメソッドを持つオブジェクトの読み取り
- setter群も同様のバリエーション + needsUpdate/matrixWorldNeedsUpdate版

#### Step 4: bind処理を理解する

メインのバインディング処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PropertyBinding.js | `src/animation/PropertyBinding.js` | bind()（487-717行目） |
| 4-2 | PropertyBinding.js | `src/animation/PropertyBinding.js` | unbind()（722-731行目） |

**主要処理フロー**:
- **487-717行目**: bind() - ノード検索、objectName解決、プロパティ解決、バインディングタイプ決定、getter/setter選択
- **722-731行目**: unbind() - nodeをnull、getter/setterをunbound状態に戻す

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

```
PropertyBinding
    │
    ├─ create() [静的]
    │      ├─ root.isAnimationObjectGroup → Composite
    │      └─ else → PropertyBinding
    │
    ├─ constructor()
    │      ├─ parseTrackName() [parsedPathなしの場合]
    │      └─ findNode()
    │
    ├─ parseTrackName() [静的]
    │      └─ _trackRe.exec()
    │
    ├─ findNode() [静的]
    │      ├─ root.skeleton.getBoneByName()
    │      └─ searchNodeSubtree() [再帰]
    │
    ├─ _getValue_unbound() / _setValue_unbound()
    │      └─ bind() [自動呼び出し]
    │
    ├─ bind()
    │      ├─ findNode() [必要に応じて]
    │      ├─ objectName解決 (materials/bones/map)
    │      ├─ propertyIndex解決 (morphTargetDictionary)
    │      ├─ バインディングタイプ決定
    │      │      └─ BindingType (Direct/EntireArray/ArrayElement/HasFromToArray)
    │      ├─ バージョニング決定
    │      │      └─ Versioning (None/NeedsUpdate/MatrixWorldNeedsUpdate)
    │      └─ getter/setter選択
    │             └─ GetterByBindingType / SetterByBindingTypeAndVersioning
    │
    └─ unbind()
           └─ getValue/setValue = unbound
```

### データフロー図

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

トラック名 ─────────────▶ parseTrackName() ────────────▶ parsedPath
  "mesh.position"              │
                               ▼
                         {nodeName: "mesh",
                          propertyName: "position"}

rootNode + path ────────▶ PropertyBinding.create() ───▶ PropertyBinding
                                │
                                ▼
                         findNode()
                                │
                                ▼
                         対象ノード特定

setValue(buffer, offset) ▶ bind() [初回] ──────────────▶ ノードプロパティ更新
                                │
                                ▼
                         setter選択
                                │
                                ▼
                         プロパティ書き込み
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PropertyBinding.js | `src/animation/PropertyBinding.js` | ソース | メインクラス定義 |
| PropertyMixer.js | `src/animation/PropertyMixer.js` | ソース | バインディングを使用して値を蓄積・適用 |
| AnimationObjectGroup.js | `src/animation/AnimationObjectGroup.js` | ソース | Compositeバインディング用 |
| AnimationMixer.js | `src/animation/AnimationMixer.js` | ソース | バインディングの作成・管理 |
