# 機能設計書: Color（RGBカラー管理）

## 1. 機能概要

### 1.1 機能の目的
Colorは、3Dグラフィックスで使用するRGB色を表現・操作するためのクラスである。16進数、CSS文字列、HSL、RGB値など多様な形式から色を設定でき、内部ではリニア色空間（LinearSRGBColorSpace）で値を保持する。色空間の自動変換機能を備え、正確な色管理を実現する。

### 1.2 主な機能
- 多様な形式からの色設定（16進数、CSS文字列、RGB、HSL）
- 色空間変換（sRGB ⇔ Linear）
- X11カラーネーム（140色）のサポート
- 色の演算（加算、減算、乗算、補間）
- HSL形式との相互変換
- CSS形式での出力

### 1.3 関連する画面/コンポーネント
- マテリアルの色設定
- ライトの色設定
- シーンの背景色
- フォグの色設定
- 頂点カラー

## 2. 機能仕様

### 2.1 データ構造

```javascript
class Color {
    r: number;      // 赤成分（0.0-1.0、リニア空間）
    g: number;      // 緑成分（0.0-1.0、リニア空間）
    b: number;      // 青成分（0.0-1.0、リニア空間）
    isColor: boolean; // 型判定フラグ
}
```

### 2.2 プロパティ詳細

| プロパティ名 | 型 | 説明 | デフォルト値 |
|-------------|-----|------|-------------|
| r | number | 赤成分（リニア空間） | 1 |
| g | number | 緑成分（リニア空間） | 1 |
| b | number | 青成分（リニア空間） | 1 |
| isColor | boolean | 型判定フラグ（読み取り専用） | true |

### 2.3 静的プロパティ

| プロパティ名 | 型 | 説明 |
|-------------|-----|------|
| Color.NAMES | Object | X11カラーネーム辞書（140色） |

### 2.4 メソッド詳細

#### 2.4.1 設定メソッド（Set）
| メソッド | 説明 |
|---------|------|
| set(r, g, b) | 柔軟な色設定（16進数/文字列/Color/RGB） |
| setScalar(scalar) | 全成分に同じ値を設定 |
| setHex(hex, colorSpace) | 16進数から設定 |
| setRGB(r, g, b, colorSpace) | RGB値から設定 |
| setHSL(h, s, l, colorSpace) | HSL値から設定 |
| setStyle(style, colorSpace) | CSS文字列から設定 |
| setColorName(name, colorSpace) | X11カラーネームから設定 |

#### 2.4.2 取得メソッド（Get）
| メソッド | 説明 |
|---------|------|
| getHex(colorSpace) | 16進数値を取得 |
| getHexString(colorSpace) | 16進数文字列を取得 |
| getHSL(target, colorSpace) | HSL形式で取得 |
| getRGB(target, colorSpace) | RGB形式で取得 |
| getStyle(colorSpace) | CSS文字列形式で取得 |

#### 2.4.3 色空間変換
| メソッド | 説明 |
|---------|------|
| copySRGBToLinear(color) | sRGB→Linearでコピー |
| copyLinearToSRGB(color) | Linear→sRGBでコピー |
| convertSRGBToLinear() | 自身をsRGB→Linearに変換 |
| convertLinearToSRGB() | 自身をLinear→sRGBに変換 |

#### 2.4.4 演算メソッド
| メソッド | 説明 |
|---------|------|
| add(color) | 色を加算 |
| addColors(c1, c2) | 2色を加算して設定 |
| addScalar(s) | スカラー値を加算 |
| sub(color) | 色を減算（0未満にならない） |
| multiply(color) | 色を乗算 |
| multiplyScalar(s) | スカラー値を乗算 |

#### 2.4.5 補間メソッド
| メソッド | 説明 |
|---------|------|
| lerp(color, alpha) | RGB空間で線形補間 |
| lerpColors(c1, c2, alpha) | 2色間のRGB補間 |
| lerpHSL(color, alpha) | HSL空間で線形補間 |

#### 2.4.6 その他
| メソッド | 説明 |
|---------|------|
| clone() | 複製を作成 |
| copy(color) | 他のColorをコピー |
| equals(color) | 等値比較 |
| fromArray(array, offset) | 配列から設定 |
| toArray(array, offset) | 配列に出力 |
| fromBufferAttribute(attr, index) | BufferAttributeから設定 |
| setFromVector3(v) | Vector3から設定 |
| applyMatrix3(m) | 3x3行列で変換 |
| offsetHSL(h, s, l) | HSL値をオフセット |
| toJSON() | シリアライズ用（16進数を返す） |

### 2.5 ビジネスルール
- 内部では常にリニア色空間（LinearSRGBColorSpace）で値を保持
- setHex/setStyleはデフォルトでsRGBからリニアに自動変換
- setRGBはデフォルトでリニア空間として扱う（変換なし）
- sub()は結果が0未満にならないようMath.maxで制限
- デフォルト色は白（r=g=b=1）
- アルファ成分は無視される（警告を出力）

### 2.6 色空間変換

#### sRGB → Linear変換公式
```javascript
function SRGBToLinear(c) {
    return (c < 0.04045) ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
}
```

#### Linear → sRGB変換公式
```javascript
function LinearToSRGB(c) {
    return (c < 0.0031308) ? c * 12.92 : 1.055 * Math.pow(c, 0.41666) - 0.055;
}
```

## 3. 処理フロー

### 3.1 set()メソッドのフロー
```
[set(r, g, b)]
      |
      v
[g, b が undefined?]
   Yes |           No
       v            |
[r の型判定]        v
       |       [setRGB(r, g, b)]
   +---+---+
   |   |   |
 Color 数値 文字列
   |   |   |
   v   v   v
copy() setHex() setStyle()
       |
       v
[自身を返却]
```

### 3.2 setStyle()のパース処理フロー
```
[setStyle(style, colorSpace)]
        |
        v
[正規表現マッチング]
        |
   +----+----+----+
   |         |    |
rgb/rgba  hsl/hsla #hex
   |         |    |
   v         v    v
[整数or%?]  [HSL解析] [3桁or6桁?]
   |         |    |
   v         v    v
setRGB()  setHSL() setHex()/setRGB()
        |
        v
[マッチなし: setColorName()]
        |
        v
[ColorManagement.colorSpaceToWorking()]
        |
        v
[自身を返却]
```

### 3.3 HSL変換フロー（getHSL）
```
[getHSL(target, colorSpace)]
        |
        v
[workingToColorSpace()]
        |
        v
[max, min 計算]
        |
        v
[lightness = (max + min) / 2]
        |
        v
[max === min?]
   Yes |         No
       v          |
[hue = 0]        v
[sat = 0]   [delta計算]
       |          |
       |          v
       |    [saturation計算]
       |          |
       |          v
       |    [hue計算（max成分による分岐）]
       |          |
       v          v
[target設定]<----'
```

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

### 4.1 推奨読解順序
1. **Color.js** - クラス定義とプロパティ（88-138行目）
2. 設定メソッド：set(), setHex(), setRGB()（149-237行目）
3. setStyle()のCSS解析処理（286-410行目）
4. 色空間変換：copySRGBToLinear(), convertSRGBToLinear()（480-531行目）
5. **ColorManagement.js** - 色空間管理（17-203行目）
6. HSL変換：setHSL(), getHSL()（248-610行目）

### 4.2 重要な処理の詳細

#### コンストラクタ（101-138行目）
```javascript
constructor( r, g, b ) {
    this.isColor = true;
    this.r = 1;  // デフォルト白
    this.g = 1;
    this.b = 1;

    return this.set( r, g, b );  // 引数があれば設定
}
```

#### setHex()の色空間変換（204-216行目）
```javascript
setHex( hex, colorSpace = SRGBColorSpace ) {
    hex = Math.floor( hex );

    this.r = ( hex >> 16 & 255 ) / 255;  // 上位8ビット
    this.g = ( hex >> 8 & 255 ) / 255;   // 中位8ビット
    this.b = ( hex & 255 ) / 255;        // 下位8ビット

    ColorManagement.colorSpaceToWorking( this, colorSpace );  // sRGB→Linear

    return this;
}
```
ビットシフトでRGB成分を抽出し、ColorManagementで色空間変換を実行

#### setHSL()のHSL→RGB変換（248-274行目）
```javascript
setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {
    h = euclideanModulo( h, 1 );  // 0-1に正規化
    s = clamp( s, 0, 1 );
    l = clamp( l, 0, 1 );

    if ( s === 0 ) {
        this.r = this.g = this.b = l;  // グレースケール
    } else {
        const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
        const q = ( 2 * l ) - p;

        this.r = hue2rgb( q, p, h + 1 / 3 );
        this.g = hue2rgb( q, p, h );
        this.b = hue2rgb( q, p, h - 1 / 3 );
    }

    ColorManagement.colorSpaceToWorking( this, colorSpace );
    return this;
}
```

#### hue2rgb()ヘルパー関数（34-43行目）
```javascript
function hue2rgb( p, q, t ) {
    if ( t < 0 ) t += 1;
    if ( t > 1 ) t -= 1;
    if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
    if ( t < 1 / 2 ) return q;
    if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
    return p;
}
```
色相から各RGB成分を計算するヘルパー

#### lerpHSL()のHSL空間補間（819-832行目）
```javascript
lerpHSL( color, alpha ) {
    this.getHSL( _hslA );
    color.getHSL( _hslB );

    const h = lerp( _hslA.h, _hslB.h, alpha );
    const s = lerp( _hslA.s, _hslB.s, alpha );
    const l = lerp( _hslA.l, _hslB.l, alpha );

    this.setHSL( h, s, l );
    return this;
}
```
RGB補間と異なり、色相を経由して自然な色遷移を実現

### 4.3 プログラム呼び出し階層図
```
Color
├── 設定メソッド
│   ├── set() → copy() / setHex() / setStyle() / setRGB()
│   ├── setHex() → ColorManagement.colorSpaceToWorking()
│   ├── setRGB() → ColorManagement.colorSpaceToWorking()
│   ├── setHSL() → hue2rgb() → ColorManagement.colorSpaceToWorking()
│   └── setStyle()
│       ├── [rgb/rgba解析] → setRGB()
│       ├── [hsl/hsla解析] → setHSL()
│       ├── [#hex解析] → setHex() / setRGB()
│       └── [色名] → setColorName() → setHex()
├── 取得メソッド
│   ├── getHex() → ColorManagement.workingToColorSpace()
│   ├── getHSL() → ColorManagement.workingToColorSpace()
│   └── getStyle() → ColorManagement.workingToColorSpace()
├── 色空間変換
│   ├── copySRGBToLinear() → SRGBToLinear()
│   ├── copyLinearToSRGB() → LinearToSRGB()
│   ├── convertSRGBToLinear() → copySRGBToLinear()
│   └── convertLinearToSRGB() → copyLinearToSRGB()
├── 演算メソッド
│   ├── add() / addScalar() / addColors()
│   ├── sub() → Math.max()
│   └── multiply() / multiplyScalar()
├── 補間メソッド
│   ├── lerp() / lerpColors()
│   └── lerpHSL() → getHSL() → setHSL()
└── その他
    ├── clone() / copy()
    ├── equals()
    ├── fromArray() / toArray()
    ├── fromBufferAttribute()
    ├── setFromVector3()
    ├── applyMatrix3()
    └── offsetHSL() → getHSL() → setHSL()
```

### 4.4 データフロー図
```
[入力形式]
    |
    +-- 0xFF0000 (16進数) --> setHex() --+
    |                                     |
    +-- "rgb(255,0,0)" --> setStyle() --+ |
    |   "hsl(0,100%,50%)"              | |
    |   "#ff0000"                      | |
    |   "red"                          | |
    |                                  | |
    +-- (1, 0, 0) RGB --> setRGB() ----+-+
    |                                    |
    v                                    v
[ColorManagement.colorSpaceToWorking()]
    |
    v
[内部表現: リニアRGB (r, g, b)]
    |
    v
[ColorManagement.workingToColorSpace()]
    |
    +---> getHex() --> 0xFF0000
    |
    +---> getHexString() --> "ff0000"
    |
    +---> getStyle() --> "rgb(255,0,0)"
    |
    +---> getHSL() --> {h: 0, s: 1, l: 0.5}
```

### 4.5 関連ファイル一覧
| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| src/math/Color.js | メイン | Colorクラスの実装 |
| src/math/ColorManagement.js | 関連 | 色空間管理と変換 |
| src/math/MathUtils.js | 関連 | clamp, euclideanModulo, lerp |
| src/math/Matrix3.js | 関連 | 色変換行列（XYZ変換用） |
| src/math/Vector3.js | 関連 | setFromVector3() |
| src/constants.js | 関連 | SRGBColorSpace定義 |
| src/materials/Material.js | 利用者 | マテリアルの色 |
| src/lights/Light.js | 利用者 | ライトの色 |

## 5. 使用例

### 5.1 基本的な色の設定
```javascript
// 16進数で設定（推奨）
const red = new THREE.Color( 0xff0000 );

// CSS文字列で設定
const green = new THREE.Color( "rgb(0, 255, 0)" );
const blue = new THREE.Color( "#0000ff" );
const yellow = new THREE.Color( "hsl(60, 100%, 50%)" );

// X11カラーネームで設定
const skyblue = new THREE.Color( 'skyblue' );

// RGB値で設定（リニア空間）
const gray = new THREE.Color( 0.5, 0.5, 0.5 );
```

### 5.2 マテリアルでの使用
```javascript
const material = new THREE.MeshStandardMaterial({
    color: 0xff0000  // 赤
});

// 後から変更
material.color.set( 'blue' );
material.color.setHex( 0x00ff00 );
material.color.setHSL( 0.5, 1, 0.5 );
```

### 5.3 色の演算
```javascript
const color1 = new THREE.Color( 0xff0000 );
const color2 = new THREE.Color( 0x0000ff );

// 加算
color1.add( color2 );  // マゼンタ的な色

// 乗算（フィルター効果）
const filter = new THREE.Color( 0.5, 1, 0.5 );
color1.multiply( filter );

// スカラー乗算（明るさ調整）
color1.multiplyScalar( 0.5 );  // 半分の明るさ
```

### 5.4 色の補間
```javascript
const start = new THREE.Color( 0xff0000 );  // 赤
const end = new THREE.Color( 0x0000ff );    // 青

// RGB空間での補間
const mid = start.clone().lerp( end, 0.5 );

// HSL空間での補間（虹色の遷移）
const hslMid = start.clone().lerpHSL( end, 0.5 );
```

### 5.5 HSL操作
```javascript
const color = new THREE.Color( 0xff0000 );

// HSL値を取得
const hsl = {};
color.getHSL( hsl );
console.log( hsl.h, hsl.s, hsl.l );

// HSL値をオフセット
color.offsetHSL( 0.1, 0, 0 );  // 色相を少しシフト
```

### 5.6 色空間変換
```javascript
const color = new THREE.Color();

// sRGB空間の値を明示的に設定
color.setRGB( 0.5, 0.5, 0.5, THREE.SRGBColorSpace );

// sRGB空間で値を取得
const srgbColor = new THREE.Color();
color.getRGB( srgbColor, THREE.SRGBColorSpace );
```

### 5.7 X11カラーネームの確認
```javascript
// 利用可能な色名を確認
console.log( THREE.Color.NAMES );
// { aliceblue: 0xF0F8FF, antiquewhite: 0xFAEBD7, ... }

// 色名から16進数を取得
const hexValue = THREE.Color.NAMES.coral;  // 0xFF7F50
```

## 6. 備考

### 6.1 色空間について
| 色空間 | 用途 | 特徴 |
|--------|------|------|
| sRGB | 入出力 | 人間の知覚に最適化、ディスプレイ標準 |
| Linear sRGB | 内部計算 | 物理的に正確な光の計算 |

### 6.2 lerp vs lerpHSL
| メソッド | 補間空間 | 特徴 |
|---------|----------|------|
| lerp() | RGB | 直線的、色がくすむことがある |
| lerpHSL() | HSL | 虹色の遷移、彩度が保持される |

### 6.3 注意事項
- three.jsはデフォルトでColorManagementが有効
- 16進数/CSS文字列はsRGBとして解釈される
- setRGB()のデフォルト色空間はリニア（変換なし）
- アルファ（透明度）はColorクラスではサポートしない
- sub()は負の値にならないよう制限される

### 6.4 X11カラーネーム
- 全140色をサポート
- 色名は小文字のみ（darkOrangeではなくdarkorange）
- Color.NAMESで色名→16進数のマッピングを参照可能

### 6.5 パフォーマンス
- setColorName()はsetStyle()より高速（正規表現なし）
- 色空間変換はColorManagement.enabled=falseでスキップ可能
- lerpHSL()はlerp()より遅い（HSL変換が必要）

### 6.6 互換性
- CSS Color Module Level 4形式（color()関数）をサポート
- rgba/hslaのアルファ値は無視（警告出力）
