# 呼吸する文字 — Style Reference
> 骨白の紙の上で、一語だけが呼吸している

**Theme:** light  **Series:** PARTS 011  **World:** 架空の可変フォント「Aria Flex」の見本ページ。文字そのものが主役で、UIは消える。

## Concept
見出し一語「Breathe」が、4秒吸って6秒吐く周期で太さ(wght)と幅(wdth)を変える。カーソルを近づけた文字だけ、さらに太く広がる。見る人に「文字が生きている」と一瞬で伝えるための画面で、色は使わず、太さの変化だけで視線を動かす。下の読み出し(wght / wdth / 吸う・吐く)は見本帳の計測値として置き、演出が何をしているかを言葉で説明しない。

## Signature Technique
可変フォント Roboto Flex の `wght` `wdth` 軸を、文字ごとに `font-variation-settings` で毎フレーム更新する。

- 1文字ずつ `<span>` に分割し、CSS変数 `--w` `--d` を書き換える。
- 呼吸カーブ: 周期 T = inhale 4s + exhale 6s。`s = u < inhale ? u/inhale : 1 - (u-inhale)/exhale` を smoothstep `s*s*(3-2s)` で丸める。
- 文字ごとの位相ずれ: `sec - i * lag * T * 0.25`(lag 0.24、1文字あたり 0.6秒遅れ)。左から右へ波が渡り、どの瞬間を切り取っても語の中に細い字と太い字が並ぶ。静止画でも可変フォントだと分かる。
- 呼吸の範囲: wght 220→860、wdth 86→118。
- カーソル近接: 文字中心までの距離を文字高さ×1.6 で正規化し、`k = exp(-dist^2 * 2.2)`。wght に +220k、wdth に +26k を加算。上限 wght 1000 / wdth 151。
- 目標値への追従は `cur += (target - cur) * 0.12` の一次遅れ。
- 読み出し `#rw` `#rd` は7文字の現在値の平均、`#phase` は周期内の位置で「吸う / 吐く」(停止中は「停止」)。
- 幅が変わるので文字の中心座標は16フレームごとに再計測(`resize` と `document.fonts.ready` でも計測)。rAF は1本、IntersectionObserver と visibilitychange で画面外は停止。

```js
const b = breath(sec - i * lag * T * 0.25);        // 0..1
let w = 220 + 640 * b, d = 86 + 32 * b;
const k = Math.exp(-((dist / (fontH * 1.6)) ** 2) * 2.2);
w += 220 * k; d += 26 * k;
span.style.setProperty('--w', w); span.style.setProperty('--d', d);
```

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --bone | #fafaf8 | 画面全体の地。わずかに暖かい白 |
| --paper | #ffffff | ボタン反転時の文字色 |
| --ink | #18161a | 見出し文字と本文とボタン枠に使う紫がかった近黒 |
| --graphite | #4a4850 | 説明文 |
| --helper | #898b91 | 計測ラベル、ヘッダー、フッター注記 |
| --mist | #e4e2e8 | 予備の罫線色(未使用でも保持) |
| --violet | #4823ff | 吸う/吐くの状態表示と focus ring のみ。面には使わない |

## Typography
- Display: Roboto Flex(opsz 144 固定、wght 100–1000、wdth 25–151)。サイズ `clamp(64px, 14.4vw, 214px)`、line-height 0.92、letter-spacing -0.02em。
- 日本語: Noto Sans JP 400/500。見出し `clamp(17px, 1.5vw, 21px)` 500、本文 `clamp(13px, 1.05vw, 15px)` 400、line-height 1.6–1.7。
- 計測値・ヘッダー・フッター: JetBrains Mono 400、11–12px、letter-spacing 0.04–0.06em、tabular-nums。
- 見出しの英単語はフォント軸を見せるために1語のみ。日本語は軸を持たないので動かさない。

## Spacing & Layout
- hero は `min-height: 100svh` の3行グリッド(header / stage / footer)。
- 横余白 `clamp(20px, 5vw, 72px)`、縦余白 `clamp(20px, 3vw, 40px)`。モバイルは左右18px。
- stage は中央寄せの縦積み、要素間 `clamp(20px, 3.2vw, 40px)`。本文最大幅 34em。
- breakpoint 640px: ヘッダー右の軸レンジを非表示、フッターを縦積みに。見出し語は `22vw`(390px幅で約86px。最も広い軸値でも画面内に収まる上限)。
- 横スクロール防止のため hero は `overflow: hidden`、body は `overflow-x: hidden`。

## Motion
- 呼吸周期 10秒(吸う4 / 吐く6)。smoothstep で端が止まる。
- 文字ごとに 0.6秒ずつ遅れ(lag .24 × 周期10秒 × .25)、左から右へ波が渡る。
- カーソル追従は一次遅れ 0.12/フレーム。離れると自然に戻る。
- ボタンで呼吸の停止/再開。停止中は中間値(b=0.5)で固定、カーソル反応は続く。
- `prefers-reduced-motion: reduce`: アニメーションとボタンを消し、中央が太く端へ細くなる静止状態(wght 780→400、wdth 116→92)にする。

## Components
- hero: 上に小さなモノスペースのヘッダー(見本名 / 軸レンジ)、中央に1語+計測値+見出し+本文、下にボタンとクレジット。
- 計測値: `wght 637  wdth 108  吸う` の3項目。数字は ink、状態語のみ violet。
- 本文: 文節ごとに `<span class="ph">`(white-space:nowrap)で包み、カタカナ語の途中で折り返さない。
- button: 高さ約36px、角丸999px、1px ink 枠、hover で ink 反転。focus-visible は violet 2px アウトライン。
- footer: 右下に `VALE / PARTS 011 / 呼吸する文字` と操作説明1行(タッチ端末では文言を差し替え)。

## Do / Don't
- Do: 1語だけ動かす。語数が増えると呼吸が見えなくなる。
- Do: 地は無彩色に近い暖かい白にし、色は状態表示だけに絞る。
- Do: wdth を動かすときは中央寄せにして、語が中心から広がるようにする。
- Don't: 文字ごとに色を変えない。太さの差だけで十分。
- Don't: 周期を3秒以下にしない。点滅に見える。
- Don't: 装飾の罫線やグラデーションを足さない。

## References
- Fonts In Use: 「白い壁に文字だけを並べる」姿勢を借りた。黒1色のインクと最小のUIという構造は同じにし、書体はベントン系の見本帳から可変サンセリフの1語に置き換え、字形そのものを動かした。
- Cake Equity: 暖かい骨白の地(#fafaf8)と紫がかった近黒(#18161a)、強い紫を1点だけ使う配色の考え方を借りた。紫をCTAに使う代わりに、状態表示と focus ring だけに縮小した。

## Usage
1. `<link>` で Roboto Flex(`opsz,wdth,wght` 軸付き)を読み込む。別の可変フォントでも `wght` と `wdth`(または任意の軸)があれば差し替え可。
2. HTML: `<div class="word" id="word">Breathe</div>` と、表示したければ計測値の `#rw` `#rd` `#phase`、停止ボタン `#toggle`。不要なら JS 内の該当行を消す。
3. CSS: `.word` と `.word span` の2ルール(`font-variation-settings` に `var(--w)` `var(--d)` を渡す部分)を移植する。
4. JS: `<script>` ブロック全体を移植し、`P` オブジェクトで調整する。

| パラメータ | 既定 | 意味 |
|---|---|---|
| inhale / exhale | 4.0 / 6.0 | 吸う・吐く秒数 |
| wMin / wMax | 220 / 860 | 呼吸での wght 範囲 |
| dMin / dMax | 86 / 118 | 呼吸での wdth 範囲 |
| lag | 0.24 | 文字ごとの位相ずれ(周期×0.25 に対する比) |
| cursorW / cursorD | 220 / 26 | カーソル近接で加算する wght / wdth |
| radius | 1.6 | 影響半径(文字高さの倍数) |
| ease | 0.12 | 追従の滑らかさ(0.05–0.3) |

注意: wdth を動かすと行幅が変わる。親を `display:flex; justify-content:center` にし、`white-space:nowrap` と十分な左右余白を確保する。
