# ヘアライン金属 — Style Reference
> 温かい黒の面に、削り出しの金属ボタンが3つ。光の帯が削り目を横切ってカーソルに追う。

**Theme:** dark  **Series:** PARTS 023  **World:** アルミの塊から筐体を削るオーディオメーカー。

## Concept
ヘアライン仕上げの金属ボタン。主役は異方性反射で、削り目(横方向の細い筋)に直交する1本の光の帯が光源(カーソル)の位置に追う。
削り目は y 座標だけで決まる1次元ノイズ。縁は SDF の勾配で面取りし、押すと面取りが浅くなって全体が沈む。
背景は無地の黒。ボタンが3つ並ぶだけで、金属の違い(アルミ・真鍮・黒染め)がパラメータの差で見える。

## Signature Technique
WebGL1 フラグメントシェーダー。ボタン1つにつき canvas と program を1組。外部ライブラリなし。

- 形: `rbox(p, half, RADIUS)` の角丸矩形 SDF。`aa = 1 - smoothstep(-1, .5, d)` で縁をなめらかに切る。
- 面取り: `bw = BEVEL * 短辺 * (1 - press*.4)`、`t = clamp(-d/bw)`、`tilt = (1-t)²`。法線を SDF の勾配方向へ `tilt*.9` だけ倒す。
- 削り目(1px 行ごとのハッシュ × x 方向の 2D value noise。色のムラは 1次元 value noise を2オクターブ):
  ```glsl
  float hash(float n){ n=fract(n*.1031); n*=n+33.33; return fract(n*(n+n)); }
  float n1(float x){ float i=floor(x), f=fract(x); f=f*f*(3.-2.*f); return mix(hash(i),hash(i+1.),f); }
  float n2(vec2 p){ /* 2D value noise。行(y)は整数で渡し、x 方向だけ補間する */ }
  // 1px 行ごとの直線。行ごとに x 方向の濃淡が独立して変わり、筋が途中で薄れて消える
  float hair(vec2 q){ float r=floor(q.y); return hash(r*1.37+.5)*(.35+.65*n2(vec2(q.x*.012, r))); }
  float band(float y){ return n1(y*.035)*.6 + n1(y*.12+4.)*.4; }  // 太いムラ。色だけに使う
  vec2  hq = vec2(px.x, px.y+seed)*HAIR_FREQ;
  float h  = hair(hq)*.55 + band(hq.y)*.45;                    // 明るさのムラ
  float hy = (hair(hq+vec2(0,1)) - hair(hq-vec2(0,1)))*.5;     // 法線の傾き(1px 行の差だけ)
  vec3  n  = normalize(vec3(grad*tilt*.9, 1.) + vec3(0., hy*HAIR*6., 0.));
  ```
- 異方性ハイライト(Kajiya-Kay): 筋の方向 `T = normalize((1,0,0) - n*n.x)`、`H = normalize(L+V)`、`sinTH = sqrt(1 - dot(T,H)²)`、`aniso = pow(sinTH, SHINE*rough) * smoothstep(-.3,.6, n·L)`。筋に直交する縦の帯になる。
- 合成: `col = base*(.46+.54*n·L)*(.86+.28*h) + tint*(aniso*SPEC*(.75+.5*h) + pow(n·H,6)*.25 + pow(1-n·H,3)*.08)`。押下で 12% 暗く。面取り部は `n·L` が低いほど暗く、下辺はさらに暗い。
- 光源: 画面座標のカーソルをボタンの uv に変換し、縦横比を揃えて `uLight = (ux, (uy-.5)/asp+.5, LIGHT_Z/asp)`。待機時はボタンごとに、ボタンの少し上(uy 1.6)で光が左右に往復する。位相をボタンごとに 2.1 ずらすため、どの瞬間の静止画でも3つすべてに帯が写る。
- 仕上げ3種(`FINISH`): steel `base (.74,.75,.77) tint (1,1,1) rough 1.0 spec .75`、brass `base (.78,.62,.34) tint (1,.92,.7) rough .9 spec 1.0`、dark `base (.17,.17,.19) tint (.8,.82,.88) rough .8 spec .4`。`spec` は `P.SPEC`(.8)に掛ける倍率。
- `HAIR_FREQ` は DPR で割って渡すので、筋の間隔は CSS px で約1px に保たれる。seed はボタンごとに乱数で、3つの削り目が揃わない。

## Color Palette
| Token | HEX | 役割 |
|---|---|---|
| --ink | #161514 | 背景(温かい黒) |
| --soot | #1E1D1B | 背景中央の明るみ(radial-gradient #1C1B19) |
| --bone | #F3F1EC | 見出し・ロゴ・フォーカスリング |
| lead | #C9C5BC | 本文 |
| --sand | #A9A59C | eyebrow・フッター |
| --line | #2B2A27 | 予備(今は未使用) |
| steel | #BDBFC4 | アルミの地(シェーダー base) |
| brass | #C79E57 | 真鍮の地 |
| dark | #2B2B30 | 黒染めの地 |
| label-dark | #1A1A1C | 明るい金属の上の文字 |
| label-light | #EDEAE3 | 黒染めの上の文字 |

## Typography
- 単一ファミリー: Zen Kaku Gothic New。
- 見出し: 700、`clamp(38px, 6.4vw, 88px)`、line-height 1.12、letter-spacing -.02em、`text-wrap: balance`。mobile `clamp(34px, 9.6vw, 48px)`、`<br class="m">` で「削り出しの / アンプ。」の2行。
- 本文: 400、`clamp(14px, 1.15vw, 17px)`、line-height 1.9、最大 30em(mobile 24em)。
- eyebrow: 12px、letter-spacing .26em(mobile .18em)。ロゴ: weight 700 / 12px / .24em。
- ボタン文字: weight 500 / 14px / letter-spacing .14em。明るい金属は `text-shadow 0 1px 0 rgba(255,255,255,.35)`(刻印)、黒染めは `0 -1px 0 rgba(0,0,0,.6)` に 8px のぼかしを足す。

## Spacing & Layout
- 1画面 = `100svh`、`grid-template-rows: auto 1fr auto`。本文ブロックは中央、最大幅 960px。
- 左右余白 `clamp(20px, 5vw, 72px)`、上 26px、下 22px(+safe-area)。
- eyebrow → h1 26px、h1 → lead 24px、lead → ボタン列 48px(mobile 36px)。
- ボタン: 高さ 60px、最小幅 200px、左右 padding 30px、角丸 14px、間隔 18px。mobile は縦積み、幅 `min(100%, 300px)`、高さ 56px、間隔 14px。
- 影: `0 18px 40px -18px rgba(0,0,0,.9)` + 上辺 1px の白 12%。

## Motion
- カーソル lerp 0.1、押下の沈み lerp 0.25(シェーダー側)、CSS は `translateY(1px) scale(.985)` を .12s。
- 待機: ボタンごとに光源 x が `.5 + .36*sin(t*.56 + i*2.1)`(uv)で往復。
- requestAnimationFrame 1本で3つの canvas を順に描く。dt は 0〜0.05 秒。`visibilitychange` と IntersectionObserver(.row)で停止。
- `prefers-reduced-motion`: 光源を画面左上 42% / 30% に固定して1フレーム描く。押下は CSS のみ。
- WebGL 非対応: `body.nogl` で CSS の repeating-linear-gradient(削り目)+ 中央の白い帯に切り替える。

## Components
- hero: 全画面。上に社名と業種、中央に eyebrow / h1 / lead / ボタン列。
- button(.metal): `<button data-finish="steel|brass|dark">`、中に `<span>` のラベル。canvas は JS が prepend する。`:focus-visible` は骨色のリング。
- footer(.bot): 11px、左に操作説明、右に `VALE / PARTS 023 / ヘアライン金属`。

## Do / Don't
- Do: ボタンは2〜4個。並べることで仕上げの差が見える。
- Do: 削り目は横。帯は縦。向きを揃えないと金属に見えない。
- Do: 黒染めは `spec` を .4 以下にして文字を守る。
- Don't: 帯を2本以上出さない(光源は1つ)。
- Don't: 蛍光色の金属を作らない。base は実在の金属の反射率に寄せる。
- Don't: 背景にグリッド線や光の玉を置かない。黒の無地が金属を立たせる。

## References
- Cassette: 温かい黒(#19181a)に骨色の文字、色は1点だけという配分を抽象化。蛍光黄色は使わず、1点の色を真鍮ボタンに替えた。
- Shopify: 深い暗色の無地に、製品の質感だけで見せる構成を抽象化。緑黒は使わず、黒を温かい側に寄せてアルミの冷たさと対比させた。

## Usage
1. `.metal` の CSS(`.nogl` 系も)と `<script>` を切り出す。HTML は `<button class="metal" data-finish="steel"><span>文言</span></button>`。
2. JS は `.metal` を全て拾って canvas を prepend し、1つの rAF で描く。ボタンの数は自由(WebGL コンテキスト上限の都合で 8 個まで)。
3. 角丸は CSS の `border-radius` と `P.RADIUS` を同じ値にする。
4. パラメータは JS 冒頭の `P`:
   - `DPR` 描画解像度
   - `HAIR` 削り目の深さ(.05。.15を超えると筋がギラつく。太いムラを法線に入れると波板に見える)、`HAIR_FREQ` 密度(1.0)
   - `SHINE` 帯の鋭さ(90)、`SPEC` 帯の強さ(.8)
   - `BEVEL` 面取り幅(短辺比 .10)、`RADIUS` 角丸 px
   - `LIGHT_Z` 光源の高さ(1.1)、`FOLLOW` 追従(.1)、`IDLE` 待機の往復速度(.35)
   - `FINISH` 仕上げ: `base`(地色)、`tint`(帯の色)、`rough`(帯の幅。小さいほど広い)、`spec`(帯の強さ倍率)
5. 新しい仕上げは `FINISH` に追加し `data-finish` で指定する。銅なら `base [.72,.45,.33] tint [1,.8,.7]`。
6. 削り目を縦にするなら `hq` の x と y を入れ替え、`T` を `(0,1,0)` に替える。


