# 煙の軌跡 — Style Reference
> ほぼ黒の面に、線香から白い煙が一筋立ち上る。カーソルが通った道にも煙が残り、渦を巻いて消える。

**Theme:** dark  **Series:** PARTS 041  **World:** 手で巻いた白檀のお香。一本が燃え尽きるまで十五分。

## Concept
全画面の背景。主役はGPUの流体ソルバで、カーソルの通った道に速度と密度(煙)を注入し、浮力と空気の揺らぎで立ち上らせる。
煙は白一色。待機中は画面下の線香の火から細い煙が一筋出るので、触らなくても動いている。線香の軸と橙の火だけをシェーダーで描き、煙の出所を見せる。
文字はセリフの見出し1本と短文。装飾は煙だけ。

## Signature Technique
WebGL2(なければ WebGL1 + half float)の2Dオイラー流体。demos/flow のソルバを転用し、文字マスク・refill・bloom を外した。

- 場: 速度 RG16F(短辺 256、mobile 128)、煙 R16F(短辺 768、mobile 384)。
- 1ステップ: curl → vorticity confinement(CURL 12) → forces(浮力 + ノイズのカール) → divergence → pressure(前フレームの圧力を 0.8 倍して初期値にし、Jacobi 24回、mobile 14) → gradient subtract → advection(速度、煙)。
- forces:
  ```glsl
  float psi(vec2 p){ return vn(p*2.0 + t*(.08,-.05)) + .5*vn(p*4.6 + t*(-.15,.11)) + .25*vn(p*9.5 + t*(.25,.2)); }
  vec2 c = (dψ/dy, -dψ/dx);            // 発散のない揺らぎ
  v += c * NOISE * (.15 + d*1.4) * dt; // 煙のある所ほど揺れる
  v.y += d * BUOYANCY * dt;            // 浮力(BUOYANCY 55)
  ```
- 注入(splat): `exp(-|p|²/r)` のガウス。カーソルは前フレームとの間を最大6点で補間し、速度 `Δ*SPLAT_FORCE(1600)`、煙 `DYE(.16)*min(1, 移動量*40+.25)/n*1.4`(n は補間点数)を分けて入れる。半径は `SPLAT_RADIUS/100`(横長画面では aspect 倍)。
- 線香(idle): `(IDLE_X, IDLE_Y) = (.5, .14)` に半径 .035、煙 .09、上向き速度 320(±25 の揺れ)、横に `sin` の小さな揺れ。毎フレーム注入し続ける。
- 初期化: 読み込み直後に 150 ステップ先に計算し、最初の1枚から煙が立っている状態にする。
- 減衰: 煙 .55、速度 .9(`r/(1+k*dt)`)。上端の 30% では `k·(1 + TOP_FADE·smoothstep(.7, 1, y))` に上げる(煙 TOP_FADE 5、速度はその半分)。浮力で上がった煙が天井に溜まってキノコ形になるのを防ぐ。
- 表示: 煙の勾配(texel×6)から法線を作り `light = .8 + .3*dot(n, (-.35,.75,.75))`。厚み `1-exp(-d*1.4)` で芯を明るく、`alpha = 1-exp(-d*3)` で背景と混ぜる。周辺減光 45%、1.6/255 のディザ。
- 線香と火(display 内、`STICK:true`): 火は `(IDLE_X, IDLE_Y-.008)`。芯 `smoothstep(.006,.002,d)·1.2`、滲み `exp(-60d)·.35`(5.3Hz と 2.1Hz の積で揺れる)、広い暈 `exp(-12d)·.06`。軸は火の下 .006〜.2(.12 から消え始める)に約2pxの線で、`#291C16` から下へ暗くなる。火の近くの煙は `exp(-14d)·.8` で EMBER を掛けて橙を拾う。
- 解像度: canvas は `min(dpr, 2)`(mobile 1.5)。

## Color Palette
| Token | HEX | 役割 |
|---|---|---|
| --void | #07070B | 背景(シェーダー BG も同値) |
| SMOKE | #F0F0F5 | 煙の色 |
| EMBER | #FF6B29 | 線香の火と、煙の根元の照り |
| stick | #291C16 | 線香の軸 |
| --bone | #EDEDED | 見出し・ロゴ・ボタン地 |
| lead | #B9B9C0 | 本文 |
| --ash | #8E8E96 | eyebrow・フッター |
| cta-text | #0A0A0E | ボタン文字 |

## Typography
- 見出し: Shippori Mincho 500、`clamp(38px, 6.2vw, 86px)`、line-height 1.25、letter-spacing .03em、中央揃え。mobile `clamp(34px, 9.4vw, 48px)` で2行。
- 本文・ラベル: Zen Kaku Gothic New。本文 400、`clamp(14px, 1.15vw, 17px)`、line-height 1.9、最大 30em(mobile 24em、2行)。
- eyebrow: 12px、letter-spacing .26em(mobile .18em)。ロゴ: weight 500 / 12px / .24em。
- ボタン: weight 500 / 13px / letter-spacing .1em。

## Spacing & Layout
- 1画面 = `100svh`、`grid-template-rows: auto 1fr auto`。本文ブロックは中央、最大幅 980px。
- 左右余白 `clamp(20px, 5vw, 72px)`、上 26px、下 22px(+safe-area)。
- eyebrow → h1 28px、h1 → lead 26px、lead → CTA 36px。
- 線香の位置は画面下 14%。CTA の下に煙の出所が来るよう、本文ブロックは `padding-bottom: 4vh`。

## Motion
- 1フレーム1ステップ(dt は最大 1/60)。requestAnimationFrame 1本。`visibilitychange` と IntersectionObserver で停止。
- カーソルの注入は pointermove ごとに補間して途切れさせない。
- `prefers-reduced-motion`: 線香の煙を 240 ステップ計算して1枚だけ描く。フッター文言を差し替える。
- WebGL(half float)非対応: `.still` の radial-gradient 3つで煙の筋を置く。

## Components
- hero: 全画面。上にブランド名と業種、中央に eyebrow / h1 / lead / CTA。
- button(.cta): 高さ44px、pill、bone 地に黒文字。hover で白くなり1px浮く。focus-visible は bone のリング。
- footer(.bot): 11px、左に操作説明、右に `VALE / PARTS 041 / 煙の軌跡`。

## Do / Don't
- Do: 煙は白1色。色を付けると流体デモに見える。暖色は線香の火とその直上だけ。
- Do: 待機中の煙は一筋だけ。出所は1か所。
- Do: 文字は煙より明るく(bone)。煙の最大輝度は文字より下に保つ。
- Don't: 煙の量(DYE)を .3 以上にしない。画面が白く埋まる。
- Don't: 背景に色やグリッドを置かない。黒が煙を立たせる。
- Don't: 浮力を 120 以上にしない。煙が上に抜けて軌跡が残らない。

## References
- North Kingdom: void ink(#050311)に白1色という配分を抽象化。紫の寄った黒は使わず、#07070B の素直な黒にした。
- Dimension: 黒の面に bone の文字と白い pill ボタンという階層を抽象化。ガラスのパネルは使わず、要素を文字と煙だけに絞った。

## Usage
1. `<canvas id="gl">`、`.still`、`#hint` と `<script>` を切り出す。外部ライブラリは不要。
2. canvas は `position:fixed; inset:0; touch-action:none`。上に載せる要素は `z-index:1`、触る要素だけ `pointer-events:auto`。
3. パラメータは JS 冒頭の `P`:
   - `SIM_RES` / `DYE_RES` 解像度(短辺)
   - `DENSITY_DISSIPATION` 煙の消える速さ(.55)、`VELOCITY_DISSIPATION` 流れの弱まり(.9)
   - `PRESSURE_ITER` 圧力の反復(24 / mobile 14)、`CURL` 渦(12)
   - `SPLAT_RADIUS` 注入半径(.16)、`SPLAT_FORCE` 速さ係数(1600)、`DYE` 煙の量(.16)
   - `BUOYANCY` 浮力(55)、`NOISE` 空気の揺らぎ(2.2)
   - `IDLE` 線香の有無、`IDLE_X / IDLE_Y` 位置、`IDLE_RADIUS / IDLE_DYE / IDLE_RISE` 細さ・量・上昇
   - `TOP_FADE` 上端で煙を消す強さ(5、0 で天井に溜まる)
   - `STICK` 線香の軸と火の描画、`EMBER` 火の色
   - `SMOKE` 煙の色、`BG` 背景色
4. 線香を消すなら `IDLE:false` と `STICK:false`。複数の出所が要るなら `idle()` の中で `splat` を増やす。
5. 明るい背景で使うなら `BG` を紙色、`SMOKE` を灰色にし、display の `alpha` を `1-exp(-d*2)` に下げる。
