# 重力 — Style Reference
> 白い紙に黒い極太ゴシック、黄色のボタンが一つ。スクロールした瞬間に、ページの文字が全部落ちて床に積もる。

**Theme:** light  **Series:** PLAY 002  **World:** 真鍮の文鎮「重力」の商品サイト。文鎮が無い紙の上では文字が重力で落ちる。文鎮の下の文字だけが動かない。

## Concept
最初は普通の商品サイト。見出し・本文・チップ・ボタン・ロゴまで、画面にある要素はすべて矩形の剛体で、スクロールした瞬間に重力で落ち、ぶつかり、跳ね、画面の底に積もる。拾って投げられる。上にスクロールすると重力が上を向き、端末を傾ければその方向に落ちる。ページ先頭に戻すと元の場所に整列して、また普通のサイトに戻る。
02 では真鍮の文鎮(静止剛体)を見出しの上に置き、文鎮の下にある文字だけが落ちない。「置いた紙は、動かない」という商品説明を、物理で言う。

## Signature Technique
**DOM 要素を剛体にした 2D 物理シミュレーション(自前、ライブラリなし)。** 回転する矩形(OBB)を SAT と面クリッピングで 2 点接触させ、逐次インパルスとクーロン摩擦で解き、位置補正とスリープで積み上げを安定させる。

1. **文字の分解 `splitChars`**: `data-body="chars"` の要素は 1 文字ずつ `<span class="b">` に分け(元テキストは `aria-label` に残す)、`data-body="el"` はボタン・チップ・ロゴを 1 個の剛体にする。
2. **計測と固定 `buildWorld`**: 通常レイアウトのまま `getBoundingClientRect` で全要素の位置を取り、その座標で `position:absolute` に固定する(見た目は変わらない)。文字の当たり判定は幅 ×0.92、高さ font-size ×0.96 の矩形。質量 `m = w·h·0.002`、慣性 `I = m(w²+h²)/12`。
3. **壁**: ステージ四辺の外側に厚さ 400px の静止矩形。重力がどちらを向いても溜まる。
4. **衝突 `collide`**: 両多角形の各面法線で「最小貫入軸」(`leastPen`)を探し、参照面/入射面を決め、入射面を参照面の側面で 2 回クリップして接触点(最大 2)と貫入量を得る。法線は常に A→B。
5. **解決**: 8 反復の逐次インパルス。相対速度 `rv = vB + ωB×rb − vA − ωA×ra`、`j = −(1+e)·(rv·n) / (1/mA + 1/mB + (ra×n)²/IA + (rb×n)²/IB)`。反発 e=0.14、接触速度が `|g|·dt·1.5` 未満なら e=0(休止)。摩擦は接線インパルス `jt` を `|jt| ≤ j·μ`(μ=√(μA·μB)、文字 0.55、文鎮 0.8)で切る。クランプの符号は接線方向と同じ側(逆にすると発散する)。
6. **位置補正**: 貫入 − 0.6px の 30% を質量比で押し戻す。速度 ±6000px/s、角速度 ±30rad/s を上限に。
7. **スリープ**: 速度² + (角速度×半径)² < 900 が 0.6 秒続けば停止。起きている物体に触れると起きる。重力の向きが変わると全員起きる。
8. **固定時間刻み**: 1/60 秒、1 フレーム最大 3 ステップ。描画は起きている物体だけ `transform: translate(dx,dy) rotate(θ)`。
9. **解放 `release`**: スクロール進行 2.5% で全剛体を動的にし、0〜0.5 秒のランダムな遅延と初速(±160px/s、角速度 ±4rad/s)で落とす。進行 0.4% 以下に戻ると `reassemble`: 0.7 秒の ease-out で元の位置と角度 0 に戻し、再び固定。
10. **重力の向き**: 端末の傾き(`deviceorientation` の β/γ、iOS は「傾きを使う」ボタンで許可)があればそのベクトル。無ければスクロール方向(下スクロール = 下、上スクロール = 上)。右下の円盤の矢印が現在の向き。
11. **拾って投げる `bindDrag`**: pointerdown した剛体を `v = (pointer − pos)·18` で追従させ、離した瞬間の直近 120ms の指の速度(±3500px/s)を与える。落下中の文字だけ `touch-action:none`、落ちる前は `pan-y` で普段のスクロールを邪魔しない。

**01 真鍮 (WebGL レイマーチ)**: 角丸直方体 SDF `sdRoundBox(b=(1.0,.26,.40), r=.12)` を 140 ステップで行進(収束 0.0015)。外れた光線も最接近距離が 0.006 未満なら当たりとし、稜線の際に背景色の点線が出ないようにする。法線は中心差分。拡散はほぼ使わず、反射ベクトル R で手続きの撮影環境 `envc(R)` を引く金属シェーディング: 床側は紙の白 .80、地平線に暗い帯 .16、上は .30→.62 のグラデ、背面に縦の桟が 1 本入った窓(x −.33〜0、y .06〜.7 の柔らかい縁、強さ 1.75。横の桟は上面の奥の縁に細い線として出るので入れない)、右に縦長の帯ライト、真上に横長のソフトボックス。研磨目の接線 T 方向に R を ±0.1 振って 5 回平均し、窓の映り込みを研磨方向へ伸ばす。フレネルは Schlick、F0=(.95,.74,.38)。ヘアラインは研磨方向と直交する座標の value noise 3 オクターブ(800/260/38 周波)で、法線を 0.006 だけ揺らし明度を ±5.5% 変える。稜線(角丸の帯域)に環境の明るさに比例した白い縁ハイライト。異方性ハイライト `exp(−(T·H)²/0.004)·(N·H)^30`。床 y=−0.39 にソフトシャドウ(`min(10h/t)`)と接触 AO、影は画面端でフェード。カーソルで `rot` を ±0.8rad 回し、放置時はゆっくり自転。解像度は CSS の 0.8×DPR(スマホ 0.7)、縦長画面では焦点距離を 0.8 倍。

**02 重し**: 同じ World をもう 1 つ。文鎮 `.weight` を見出し 1 行目の 58% 位置に置き、中心がその矩形に入る文字は `held`(質量無限)。文鎮自体も静止剛体なので、落ちる文字がその上に乗る。IntersectionObserver で 55% 見えたら解放。

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --bg | #FBFBF8 | ページの白。hero/01/締め |
| --bg-2 | #F2F1EB | 02 の床。少しだけ沈んだ白 |
| --ink | #0D0D0D | 見出しと本文とボタン文字と矢印 |
| --ink-2 | #4A4A46 | 本文の補足 |
| --muted | #7A7973 | ラベルとヒントとフッターの文字 |
| --rule | #E2E1DA | 1px の罫、チップの枠、円盤の輪郭 |
| --yellow | #FFD600 | CTA ボタンだけ |
| --red | #FF3B2F | チップ 1 個だけ(真鍮) |
| --brass / --brass-2 | #C9A24A / #8C6A24 | 02 の文鎮のグラデーション。01 のシェーダーも同系 |

原色は黄と赤の 2 点のみ、面積は画面の 1% 以下。残りは白と黒。

## Typography
- **Zen Kaku Gothic New 900**: 見出し。hero h1 `clamp(46px, 8.4vw, 124px)`、行間 1.08、字間 −0.03em。01 h2 `clamp(34px, 4.6vw, 72px)`、02 h2 `clamp(38px, 6vw, 96px)`、締め `clamp(40px, 6vw, 96px)`。ロゴ 22px。
- **Zen Kaku Gothic New 400/500**: 本文 17px / 1.6(hero の lead は `clamp(16px, 1.4vw, 20px)`)、ボタン 15px 500 字間 .04em、チップ 13px 500、ラベル 12px 500 字間 .2em 大文字、ヒント 13px。
- `font-feature-settings:"palt"`。英字はラベル(`01 / 真鍮`, `VALE / PLAY 002`)のみ。
- 分解した文字は `white-space:pre` の inline-block。フォントは `document.fonts.load` 後に計測する。

## Spacing & Layout
- gutter `clamp(20px, 4vw, 56px)`、基本単位 8px。
- hero: 240vh のセクションに 100svh の sticky ステージ(min 580px)。内容は左寄せ・縦中央、h1 の最大幅 11em、lead 30em。
- 01: 2 カラム grid(1fr 1fr、min-height 92vh)。760px 以下で 1 カラム、3D ビューを上に(62vh)。
- 02: 100svh のステージ(min 560px)。
- 締め: 上下 `clamp(120px, 18vh, 220px)`、中央揃え。
- breakpoints: 760px(grid、h1 12.5vw、UI を右上へ)。

## Motion
- 重力 2200px/s²。空気抵抗は速度 ×0.999/step、角速度 ×0.995/step。
- 解放の遅延 0〜0.5 秒(reduced-motion では 0)。再整列 0.7 秒 ease-out cubic(reduced-motion では即時)。
- 01 の回転追従 `1 − e^(−5dt)`、自転 0.25rad/s(reduced-motion では静止)。
- rAF は 1 本(`tickers`)。起きている剛体が無く、01 が画面外なら止まる。
- reduced-motion でも物理は残す(ユーザー操作に応答するため)。自動の回転と遅延だけ消す。

## Components
- **hero**: 左上にロゴ(重力 + 真鍮の文鎮)、中央左にチップ 2 個 → h1 → lead → 黄色 CTA + ヒント。右下(スマホは右上)に「傾きを使う」(iOS のみ表示)と重力の向きを示す 40px の円盤。 「動かない。」の上半分に 01 の真鍮の静止画(後述)を載せる。幅は 5 文字分の約 1.04 倍(高さは行高の 1.5 倍まで、スマホ 1.0 倍)、下端を行の上から 40% の位置に置く。読み込み 1.5 秒後に見出しの残り「置いた紙は、」だけが重力で落ち、床に積み上がる。重しの下の 5 文字は固定。lead・ボタン・チップはスクロールまで落ちない(まだ落ちていない要素とは衝突させない)。スクロールで残りも落ち、上に戻すと組み直して 1.2 秒後にまた見出しだけが落ちる。
- **button**: 高さ 54px、横 28px、`border-radius:999px`、黄 `#FFD600` に 1px の内側罫。hover で `#ffe04d`。`focus-visible` は 2px 黒アウトライン。落下中は `click` を止める(キーボードは通す)。
- **chip**: 高さ 30px、13px、黒 1px の内側罫。赤チップは白文字で罫なし。
- **weight(文鎮)**: 01 のレイマーチ・シェーダーを `snap=1`(透明背景・床なし、カメラ (0, 1.25, 4.6)、焦点 6.6、rot (−0.04, 0.1))で 1800×600(スマホ 1200×400)に 1 回だけ描き、アルファの外接矩形で切り抜いて 1/2 に高品質縮小した PNG を hero と 02 の重しの背景に使う。影は `drop-shadow(0 18px 14px)` と `(0 4px 3px)` の二重。WebGL が無い時は全角丸の 3 段グラデーション。
- **footer**: 11px 字間 .2em 大文字、上に 1px の罫、`VALE / PLAY 002`。

## Do / Don't
**Do**
- 落ちる前は普通のサイトに見せる。仕掛けの気配を出さない。
- 原色はボタンと赤チップの 2 点で止める。落ちた後に色が目立つのはこの 2 点だけでいい。
- 文字は 1 文字ずつ剛体にする。単語単位では落ちた後が読めてしまい、面白くない。
- 物理は固定時間刻みで回し、描画は起きている物体だけ更新する。
- 文鎮の下の文字を残す。商品の意味がここで通る。

**Don't**
- 摩擦インパルスのクランプで符号を反転させない(エネルギーが増えて爆発する)。
- 落下中の要素に CSS transition を付けない。
- 背景にグリッドやグラデーションを敷かない。白い紙のまま。
- 見出しを 1 行 12 文字以上にしない。落ちた山が画面幅を超える。
- 傾きの許可を自動で求めない。ボタンで求める。

## References
- **Prisma Labs** (Refero): 白地に極太 700 の見出しと、黄色 1 色だけを機能的に使う考え方を抜き出した。書体は Cofo Sans から Zen Kaku Gothic New 900 に、黄は `#FFD600` をそのまま「唯一のボタン色」として採用し、分割レイアウトは 01 の 2 カラムにだけ残した。
- **Opennote** (Refero): 暖かい白の紙と、少量の濃い色を欄外のしるしのように置く考え方を参考にした。セリフと革色は捨て、紙の白 `#FBFBF8` と赤チップ 1 個、罫線 1 色のミニマルな構造だけを取り、「紙の上の文字」を物理で落とす主役に置き換えた。
