# 磁石 — Style Reference
> 白い紙に撒いた黒い砂鉄。カーソルの磁石が通ると、砂鉄が磁力線に並び、見出しの形に集まる。

**Theme:** light  **Series:** PLAY 003  **World:** 砂鉄と棒磁石の観察セットの商品サイト。紙の上の砂鉄が、見えない磁場を見える形にする。

## Concept
画面は砂鉄を薄く撒いた白い紙。カーソル(指)は N/S の小さな棒磁石で、近づくと砂鉄が磁力線に沿って針のように並び、両極に集まる。見出し「見えない力を、砂鉄で見る。」は紙に薄く刷ってあるだけで、磁石が文字の上を通ったときに砂鉄がその形に集まり、黒い文字として現れる。磁石が離れると砂鉄はゆっくり元の散らばりに戻る。
下のセクションは同じ物理を別の見え方で: 01 は磁力線の図(二つの磁石を動かし、押して極を反転)、02 は磁針の格子がカーソルの磁石に合わせて回る。

## Signature Technique
**WebGL2 の GPGPU 粒子(デスクトップ 102,400 粒、スマホ 36,864 粒)を二極の磁場で動かし、文字マスクの多段階勾配で見出しに集める。** ライブラリなし。

1. **状態テクスチャ**: `RGBA32F` を 2 枚(位置+速度 `(x, y, vx, vy)`、補助 `(角度, homeX, homeY, 整列度)`)、`EXT_color_buffer_float` + MRT(`drawBuffers`)でピンポン更新。320×320(スマホ 192×192)。
2. **初期化**: `hash(uv)` で紙全体に一様散布。home は初期位置。`prefers-reduced-motion` のときは 6 割の粒を文字マスク内に最大 8 回の棄却サンプリングで置き、静止画でも見出しが砂鉄で読める。
3. **磁場**: 磁石は中心 ±30px の 2 点(N: +、S: −)。`B = (p−N)/(|p−N|²+80) − (p−S)/(|p−S|²+80)`。影響度 `inf = smoothstep(R, 0.2R, min(dN, dS))`、R = 300px(スマホ 200)。
4. **力**: 両極への引力 `150000·(−dN/rN² − dS/rS²)·inf`、磁力線に沿う滑り `700·t·sign·inf`(t は B の単位ベクトル、近い極へ向かう符号)、揺らぎ `1800·(hash−.5)·inf`。摩擦は毎ステップ ×0.85、速度上限 700px/s。
5. **文字への集合**: 見出しを 2D canvas に白で描き、`generateMipmap` したマスクを `textureLod` で LOD 1/3/5 から中心差分で勾配を取り、`1.2·g1 + 1.6·g3 + 2.4·g5` を正規化した方向に `3200·fm` の力(fm は磁石中心から R2 = 270px の減衰)。マスク内(`lod0 > .5`)では速度 ×0.55、力 ×0.35 で沈着する。
6. **戻り**: 影響外では `(home − p)·2.6` の弱いばねで数秒かけて元の散らばりに戻る(「離すと崩れる」)。整列度は 0 へ減衰。
7. **針の向き**: 粒の角度ベクトルを B の向きへ `inf·0.35` で球面補間(符号は対称なので近い側へ)。整列度 `al` は `inf·0.3` で 1 へ。
8. **描画**: 頂点バッファなし、`gl_VertexID/6` から `texelFetch` で粒を読み、1 粒 = 細長い四角形 2 三角形(`TRIANGLES`, N²×6 頂点)。粒ごとの乱数 `big=rz³` で大きさをばらつかせる: 長さ `(0.9+3.2·al)·(0.5+0.9·rs)·(1+1.4·big)` px、幅 `0.7+2.6·big+0.5·rs·al` px。不透明度 `(0.17+1.02·al)·(0.8+0.35·rs)`、寄った粒ほど濃く、紙の上に休んでいる粒は薄い。色 `#08080A`、幅方向の端を 60% まで落として粒の輪郭を柔らかくする。文字の上では速度 ×0.25・加速 ×0.2 で止まりやすくし、整列度を 0.35 ずつ上げて黒く溜める。磁石は 140×34px(スマホ 108×28px)、棒の半長 66px(スマホ 50px)、磁場の及ぶ半径 350px(スマホ 175px)。
9. **磁石の動き**: ポインタの移動方向を 24px の窓で平滑化して棒の向きにする。3.5 秒操作が無いと、文字から離れた画面右下(中心 0.82W, 0.83H、スマホ 0.74W, 0.9H)の小さな楕円軌道(振幅 0.06W × 0.035H)を自動で周回する。磁場の毛羽立ちは右下に、見出しは砂鉄の黒い字形のまま読める。ステップは 1 フレーム 2 回。
10. **入出力**: hero は `cursor:none`、`touch-action: pan-y`(縦スクロールは生かす)。WebGL2 か float 描画先が無ければ DOM の見出しを表示する。

**01 磁力線 (Canvas2D 流線)**: 棒磁石 2 本(半長 54px)。各 N 極の周り 24 方向(スマホ 16)から RK2(刻み 3px、最大 1400 歩)で +B 方向へ積分、S 極 9px 以内か画面外で止める。S 極からは −B 方向に積分し、画面外に抜けた線だけ反転して採用。`Path2D` にキャッシュし、`lineDashOffset` を 28px/s で流して N→S の向きを示す。ドラッグで移動、4px 未満の押下で極を反転。

**02 磁針**: 9×4(スマホ 5×6)の針。見出しは読点の後を `inline-block` で包み、スマホで語の途中で折り返さない。各針の中心で二極の場 `B` を求め、`atan2(B) + π/2` を目標角に `1 − e^(−9dt)` で追従。ポインタが無いときは磁石が格子の上を自動で動き(下記 Motion)、針は常に場の向きを指す。

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --paper | #F7F7F3 | 紙。hero/01/締め |
| --paper-2 | #EEEEE8 | 02 の面、磁針の台 |
| --rule | #DCDCD5 | 1px の罫、磁針の輪 |
| --iron | #15161A | 砂鉄、見出し、本文、ボタン、磁針の S 側 |
| --ink-2 | #4B4C50 | 補足文 |
| --muted | #7E7F7B | ラベルとヒントとフッターの文字 |
| --n | #D7262C | 磁石の N 極。磁針の N 側 |
| --s | #2552C3 | 磁石の S 極 |

彩度のある色は磁石の 2 極だけ。面積は常に小さく、紙と砂鉄の白黒が画面を作る。

## Typography
- **Shippori Antique B1 400**: 見出し。hero(砂鉄で描く): `min(W×0.115, H×0.2)`px、2 行、行間 1.18(スマホは `min(W×0.2, H×0.09)` で 4 行)。01/02 h2 `clamp(34px, 4.8vw, 72px)`、締め `clamp(32px, 5vw, 80px)`、ロゴ 24px。
- **Noto Sans JP 400/500**: 本文 16px / 1.7、補足 15px、ボタン 15px 500 字間 .04em、ラベル 12px 500 字間 .2em 大文字、磁石の N/S 12〜14px 700。
- 見出しの砂鉄版は同じフォントを 2D canvas に描いてマスクにする(`document.fonts.load` 後)。紙には同じ文字を `rgba(21,22,26,.085)` で薄く刷る。アクセシビリティ用に `h1` は視覚的に隠して置く。

## Spacing & Layout
- gutter `clamp(20px, 4vw, 56px)`。
- hero 100svh(min 600px)。ロゴ左上、ヒントとボタンは下辺の両端。砂鉄の上に載る文字は紙色の下地(6px 12px)を敷く。
- 01: 見出しブロック + 高さ 68vh(min 420px)の図。02: 上下 `clamp(56px, 8vh, 96px)`、格子は最大幅 1200px、gap `clamp(14px, 2.6vw, 36px)`。
- breakpoints: 760px で磁針を 5 列。640px 未満の端末では粒数・影響半径・流線本数を落とす。

## Motion
- 砂鉄: 摩擦 0.85/step、速度上限 700px/s、2 サブステップ/フレーム。戻りのばね 2.6/s²。
- 自動の磁石: 無操作 3.5 秒で開始、周期 約 11 秒。reduced-motion では自動周回なし。
- 02 磁針: hero が画面外でカーソルが格子の上に無いとき、磁石が格子の中心を楕円 (0.3W × 0.28H、0.35/0.5 rad/s) で自動で動き、針は常に場の向きを指す。
- 初期状態: 粒の 62% を見出しの字形の中に置き、整列度 0.95(濃い黒)で始める。磁場の外では字形の上の粒は整列度 0.95 へ、紙の上の粒は 0 へ戻るので、磁石が通り過ぎても字は黒く読める状態に戻る。
- 01: 破線の流れ 28px/s(reduced-motion では静止)。02: 追従 `1 − e^(−9dt)`(reduced-motion では即時)。
- rAF は 1 本。hero/01/02 とも画面外では止まる。

## Components
- **magnet(カーソル)**: 64×16px。左半分が S の青で右半分が N の赤。極名は白文字で、影を付ける。`position:fixed` で hero と 02 の上だけ表示。
- **hero**: 砂鉄 canvas(透明)の下に薄い見出し canvas。ロゴ(磁石 / 砂鉄と棒磁石の観察セット)とヒントと黒ピルボタンを載せる。
- **button**: 高さ 52px、横 26px、`border-radius:999px`、砂鉄色。`focus-visible` は 2px アウトライン。
- **01 の磁石**: 108×22px、角丸 5px、紙色の縁と影、赤/青の半分ずつに N/S。
- **磁針**: 3×50% の針、上半分赤・下半分黒、紙色の円と 1px の輪の上。
- **footer**: 11px 字間 .2em 大文字、上に 1px の罫、`VALE / PLAY 003`。

## Do / Don't
**Do**
- 砂鉄は 1 粒 1 本の針で描く。点にすると砂に見えない。
- 静止時の砂鉄は薄く(不透明度 .34、長さ .9px)。紙が白く見える密度を守る。
- 文字は紙に薄く刷っておき、砂鉄が集まって初めて黒くなる順番にする。
- 磁石の色は N 赤・S 青の 2 点だけ。
- 影響外の粒は home に戻す。戻らないと画面が汚れていく。

**Don't**
- 粒を増やして紙を灰色にしない(デスクトップ 10 万粒が上限)。
- 引力だけにしない。磁力線に沿う滑りと針の整列が無いと、ただの吸い込みになる。
- マスクの LOD を 1 段だけにしない。遠い粒が文字の塊に寄れなくなる。
- 背景にグリッドやグラデーションを敷かない。白い紙。
- GLSL で `gl_` 始まりの変数名を使わない(予約語でコンパイルが落ちる)。

## References
- **Adaptive ML** (Refero): 色を一切使わず、見出しとただ一つの図版だけに目を集める構成を抜き出した。クリーム地とセリフは捨て、冷たい白 `#F7F7F3` とアンティーク系ゴシックに置き換え、「唯一の図版」を砂鉄のシミュレーションにした。
- **Slite** (Refero): 単色の紙の上に差し色を一か所だけ置く考え方を参考にした。テラコッタは使わず、差し色を磁石の N 赤・S 青という意味のある 2 色に限定し、ピル型ボタンと薄い罫の軽さだけを引き継いだ。
