# 流れ場 — Style Reference
> 黒い紙の上に、風の筋が白い線で描かれていく

**Theme:** dark  **Series:** PARTS 032  **World:** 架空の風況データサービス「Nagare」のトップ。風の向きを数値で見せる代わりに、粒子が流れた跡をそのまま画面にする。

## Concept
画面全体が1枚の流れ場。粒子はカールノイズの速度場に乗って流れ、通った跡が少しずつ消える。渦の中心には線が集まり、流れの速い所には長い筋ができる。色は黒と白だけ。カーソルの周りだけ渦ができ、その中の粒子が藍色になる。無操作時は仮のカーソルが画面右寄りを漂う。テキストは左下に見出し1行と本文2文、右上に粒子数の読み出し。

## Signature Technique
GPGPU 粒子 + 軌跡の蓄積バッファ。

1. **位置テクスチャ**: 一辺 `side`(50、モバイル 32)の RGBA float。`xy`=位置(画面高さ=1、幅=aspect)、`z`=年齢、`w`=seed。WebGL2 は `RGBA32F`(不可なら `RGBA16F`)、WebGL1 は `OES_texture_float`。
2. **速度場**(`SIM_FS`): 3D simplex ノイズ `n(x·scale, y·scale, t·evo)` の勾配を 90 度回して 2D カールにする。発散がゼロなので粒子が一か所に溜まらない。
   ```glsl
   vec2 curl2(vec3 p){ float dy = n(p+e_y) - n(p-e_y), dx = n(p+e_x) - n(p-e_x); return vec2(dy, -dx)/(2e); }
   vec2 v = curl2(q) + .3 * curl2(q*2.1 + offset);   // 2 オクターブ
   v *= 1. / (1. + .12 * length(v));                  // 速すぎる所を抑える
   v += (perp(d)/r * vortex - d/r * pull) * smoothstep(R, 0, r) * 6.;   // カーソルの渦と引き込み
   p = mod(p + v*speed*dt, vec2(aspect, 1.));          // 端は反対側へ
   // dt は 0〜0.033 に丸める。rAF の時刻は start() 直前の performance.now() より前になることがあり、負の dt は粒子を逆走させる
   if (age > life) { p = hash(seed, t); age = 0.; }    // 寿命(2.5–6 秒)で位置を散らし直す
   ```
3. **軌跡**: 画面解像度の RGBA8 FBO を2枚ピンポン。毎フレーム `max(prev − decay, 0) · fade` で前フレームを暗くして書き写し、その上に粒子を `ONE / ONE` の加算で描く。引き算を混ぜるので 8bit でも完全に黒へ戻る。
4. **粒子**: `gl_PointSize = 1.3·dpr`、丸い点、明るさ `alpha=0.85`。年齢で 0.4 秒かけて現れ、寿命の 0.6 秒前から消える。カーソル半径 ×1.4 の中では `vT = smoothstep(R·1.4, 0, d)^.6` で白→藍 #4632FF に混ぜ(vT .45 で藍に達する)、明るさを最大 3.6 倍にする。
5. **表示**: 軌跡テクスチャに背景色 `#050505` を足して画面へ。
6. 起動時に 90 ステップ(reduce 時は 240 ステップ)を内部で回してから見せる。IntersectionObserver と visibilitychange で画面外停止。リサイズで軌跡 FBO だけ作り直す。

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --obsidian | #050505 | 地。表示シェーダーの背景色も同じ |
| --paper | #fdfdfd | 粒子、見出し、ブランド名、クレジット |
| --pearl | #d4d4d4 | 本文 |
| --ash | #8a8a8a | ヘッダーのラベル、操作説明 |
| --stone | #5a5a5a | 予備(未使用) |
| --indigo | #3b2bff | ヘッダーの区切り点。面には使わない |
| acc(JS) | #4632ff | カーソル周りの粒子。加算で重なるので CSS の藍より少し明るくしてある |

## Typography
- 日本語見出し: Noto Sans JP 500、`clamp(20px, 1.8vw, 26px)`、letter-spacing −0.01em、line-height 1.45。
- 本文: Noto Sans JP 400、`clamp(13px, 1.05vw, 15px)`、最大幅 30em。
- ラベル: JetBrains Mono 400、11–12px、letter-spacing 0.06–0.08em。粒子数は JS で実測を書き込む。
- WebGL 不可時は `.fallback` にブランド名を Inter 400 の大きな字で出す。

## Spacing & Layout
- hero `min-height: 100svh`、3行グリッド。canvas は背面全面。
- 余白: 横 `clamp(20px, 5vw, 72px)`、縦 `clamp(20px, 3vw, 40px)`。モバイル左右 18px。
- 見出しは左下、クレジットは右下。流れ場の上に置き、上下端だけ黒のグラデーションで流線を沈める(Components 参照)。
- breakpoint 760px: ブランド横の説明を消し、フッターを縦積み。

## Motion
- 流速 0.075(画面高さ/秒)× ノイズの勾配。場は `evo=0.07` でゆっくり変わる。
- 軌跡は `decay 0.004 / fade 0.985` で、約 100 フレーム(1.7 秒)で消える。
- カーソル: 半径 0.22(画面高さ比)の渦(0.9)と引き込み(0.25)。タッチはなぞっている間だけ。
- 無操作時は仮のカーソルが `x = aspect·(0.62 + 0.1·sin(0.3t))`、`y = 0.5 + 0.12·sin(0.21t + 1)` をゆっくり漂い、渦と引き込みを 0.6 倍で掛ける。静止画でも渦と藍が写る。
- `prefers-reduced-motion: reduce`: rAF を回さず、240 ステップ進めた軌跡を1枚描いて止める。風の筋の静止画になる。

## Components
- hero: 背面 canvas(`aria-hidden`)+前面テキスト。テキスト層は `pointer-events: none`。
- header: 左にブランド名、右に `curl noise · 2,500 particles` の読み出し。区切り点だけ藍。
- copy: 見出し1行+本文2文。
- 文字の下の沈め: 上端 120px に `rgba(5,5,5,.78)→0`(`::before` は DOM 上 canvas より前なので `z-index:1` を付けないと canvas の下に隠れる)、下端 `min(34vh,300px)` に `0→.55→.82` のグラデーションを canvas と文字の間に敷く。文字には `text-shadow: 0 0 14px #050505, 0 0 4px #050505`。画面中央の流線の明るさは変えない。
- footer tag: `VALE / PARTS 032 / 流れ場` と操作説明1行(タッチ端末では文言差し替え)。

## Do / Don't
- Do: 粒子数 × 軌跡の長さ = 画面の被覆率として調整する。被覆率 25–35% で風の筋に見える。
- Do: 軌跡の減衰には引き算を混ぜる。乗算だけだと 8bit バッファに灰色の膜が残る。
- Do: 端は反対側へ回す。消して撒き直すと端に空白の帯ができる。
- Don't: 粒子を 1 万以上にしない。筋が面になり、流れが読めなくなる。
- Don't: 速度場を 1 オクターブにしない。渦が同じ大きさで並び、模様に見える。
- Don't: 色をグラデーションで付けない。藍はカーソルの周りだけ。

## References
- Savee: ほぼ黒の地に白い文字、色は電気的な藍を1点だけという構造を借りた。藍を装飾からカーソル周りの粒子に移した。
- HashiCorp: 黒い技術的な面の上で、光る物体1つが唯一の色になる考え方を借りた。物体をカーソルの渦に置き換え、残りは白線だけにした。

## Usage
1. `<canvas id="gl">` を hero の背面に置く。フォントは任意。
2. `<script>` ブロック全体を移植する。`boot()` が canvas の寸法を測り、粒子テクスチャと軌跡 FBO を作る。
3. 色は `ink` / `acc` / `bg` を CSS 変数と揃える。明るい地にする場合は加算を `ONE_MINUS_DST_COLOR, ONE` に変えるか、軌跡を反転して表示する。
4. 速度場を差し替える: `SIM_FS` の `v = ...` 行を任意のベクトル場(画像から読んだ風データ等)にする。
5. 粒子数の読み出しが不要なら `#n` の行を消す。

| パラメータ | 既定 | 意味 |
|---|---|---|
| side | 50 / 32(モバイル) | 粒子テクスチャの一辺。粒子数は side² |
| scale / evo | 1.7 / 0.07 | ノイズの空間周波数と時間変化 |
| speed | 0.075 | 流速(画面高さ/秒) |
| life | [2.5, 6] | 寿命(秒)の範囲 |
| vortex / pull / curR | 0.9 / 0.25 / 0.22 | カーソルの渦の強さと引き込みと半径 |
| coreR | 1.4 | 藍に染まる範囲(curR に対する比) |
| decay / fade | 0.004 / 0.985 | 軌跡の減衰(引き算、乗算) |
| size / alpha | 1.3 / 0.85 | 粒子径(px)と1粒の明るさ |
| dprMax | 1.75 / 1.5(モバイル) | 表示解像度の上限 |

被覆率を変えずに線を細かくしたい場合は `side` を上げ、`fade` を下げる。
