# ピントが合う文字 — Style Reference
> 真夜中の観測室。細い明朝の行が奥に並び、ピント面に来た1行だけが白く鋭くなる

**Theme:** dark  **Series:** PARTS 020  **World:** 架空の屈折望遠鏡メーカー「Toi」のトップ。ピントが合うまで星はにじんでいる、という見え方を文字で再現する。

## Concept
黒い画面に 6 行(ラベル2行+文4行)を縦に並べ、スクロール位置をピント面にする。各行はピント面からの距離で `blur` と `scale` と不透明度が変わり、合った1行だけが鋭く大きく、純白になる。外れた行は冷たい灰色でにじみ、レンズの色収差として青緑と紅の縁がわずかにずれる。無操作が 2.5 秒続くとピント面が行から行へ送られ、各行で止まるので、静止画には1行だけ合焦した状態が写る。

## Signature Technique
CSS `filter: blur()` + `transform: scale()` を行ごとに JS で更新。ライブラリなし。

- **ピント面**: `target = scrollY / (scrollHeight − innerHeight)`(0–1)。`.scroll` を 320svh にし、hero は `position: sticky; top: 0`。`focus` は target へ `1 − exp(−7.7·dt)`(60fps で 12%/フレーム、dt 上限 0.1 秒)で追従。
- **行の深さ**: `pos = i / (n − 1)`。距離 `d = |pos − focus| / 0.34`、合焦度 `f = max(0, 1 − d²)`。
- **blur**: `14px·(1 − f)`(モバイル 9px)。**scale**: `1 + 0.08·(pos − focus)`(手前は大きく、奥は小さく)。**opacity**: `0.38 + 0.62·f`。
- **色**: `.w::before` に灰色 #9aa1b2 の文字、`.g` に白 #ffffff の文字を重ね、`--f = f³` で白の不透明度を上げる。
- **色収差**: `--ca = 1 − f` を行に渡し、`text-shadow: calc(--ca·−0.14em) 0 rgba(36,218,217, .9·ca), calc(--ca·0.14em) 0 rgba(255,86,120, .75·ca)`。ぼけた行ほど左に青緑、右に紅の縁が出て、blur で溶けて色のにじみになる。合焦した行は縁が消える。
- **自動のピント送り**: 最後のスクロールから 2.5 秒で `raw = (0.5 + 0.5·sin(…))·(n−1)`、周期約 17 秒。`raw` の整数部 k の行で止まり、小数部が 0.36–0.64 の間だけ smoothstep で次の行へ送る。行ごとに止まる時間が長く、送りは速い。初期値は 0.42。位相は経過時間で固定し、`load` 完了から 3.5 秒後に `raw = 3.18`(4行目で停止中)になる値 `PHASE = asin(2·3.18/(n−1) − 1) − 3.5·autoSpeed·2π` を使う。ピントの追従は `1 − exp(−7.7·dt)`(60fps で 0.12 と同じ)。フレーム数に依存しないので、端末が違っても同じ時刻なら同じ行に合う。どの時刻でも行と行の間で止まる時間が短いので、静止画にはほぼ必ず1行だけ合焦した状態が写る(qa の撮影では2文目に合うことが多い)。
- 右端のレール `.rail` にピント面の位置を点で示す。

```js
const d = Math.abs(pos - focus) / 0.34, f = Math.max(0, 1 - d * d);
el.style.filter = `blur(${14 * (1 - f)}px)`;
el.style.transform = `scale(${1 + 0.08 * (pos - focus)})`;
el.style.opacity = 0.38 + 0.62 * f; el.style.setProperty('--f', f ** 3); el.style.setProperty('--ca', 1 - f);
```

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --void | #000000 | 地 |
| --paper | #ffffff | 合焦した行、クレジット |
| defocus | #9aa1b2 | ピントを外れた行 |
| --bone | #e5e7eb | ラベル行、ヘッダーの社名 |
| --graphite | #4d4d4d | ヘッダー補助とメタ情報と操作説明 |
| --dim | #2a2a2a | レール |
| aberration | #24dad9 / #ff5678 | 色収差の縁。ぼけた行にだけ薄く出る |

## Typography
- 行: Noto Serif JP 200、`clamp(22px, 3.4vw, 52px)`、line-height 1.4、letter-spacing 0.03em、`white-space: nowrap`(760px 以下は折り返し、`clamp(18px, 4.9vw, 30px)`)。
- ラベル行: JetBrains Mono 400、`clamp(11px, 1vw, 13px)`、letter-spacing 0.14em、大文字。
- ラベル: JetBrains Mono 400、11–12px。

## Spacing & Layout
- `.scroll` 320svh の中に sticky の hero(100svh)。3行グリッド。
- 行の間隔 `clamp(14px, 2.6vh, 30px)`、左寄せ、`transform-origin: left center`。
- レールは右端、高さ 28vh、1px。
- 余白: 横 `clamp(20px, 5vw, 72px)`、縦 `clamp(20px, 3vw, 40px)`。モバイル左右 18px。
- breakpoint 760px: ヘッダー右・メタ情報・レールを消し、フッターを縦積み。

## Motion
- スクロールでピント面が移動、追従は `1 − exp(−7.7·dt)`(60fps で 12%/フレーム)。
- 無操作 2.5 秒で自動往復(autoSpeed 0.06Hz、周期約 17 秒。各行で止まり、行間は速く送る)。スクロールすると即座に手動へ戻る。
- rAF 1本。IntersectionObserver と visibilitychange で画面外停止。reduced-motion のときだけ、追従が収束したら止まる。
- `prefers-reduced-motion: reduce`: 自動往復なし、ぼかしを 60% に弱め、スクロールにだけ追従。

## Components
- hero: ラベル行+文4行+ラベル行、右端のレール。
- header: 左に社名、右に技法名。
- meta: 左下にピント面の位置(%)、最大ぼかし、奥行きのスケール。
- footer tag: `VALE / PARTS 020 / ピントが合う文字` と操作説明1行。

## Do / Don't
- Do: 行は 4〜6 行。多いと全部ぼけて読む所が無くなる。
- Do: 合焦は1行だけ。focusWidth 0.34 で隣の行は 5px 前後ぼける。
- Do: 色は色収差の縁だけ。文字そのものに色のグラデーションを塗らない。
- Do: scale は ±8% まで。大きいと行がずれて見える。
- Don't: ぼかしを 20px 以上にしない。描画が重く、形も消える。
- Don't: 背景に星や光を描かない。文字がにじむだけで十分。
- Don't: 自動のピント送りを速くしない(周期 12 秒以上)。

## References
- Valo: 純黒に weight 300 の文字を浮かべ、青緑から紫への帯を1本だけ通す配色を借りた。帯は文字に塗らず、ぼけた行の色収差の縁(青緑と紅)にだけ残した。
- Haley Park: 森の羊皮紙に細い明朝を静かに組む写本の空気を借りた。緑の紙は使わず黒にし、明朝の細さだけ残した。

## Usage
1. `.scroll`(高さ 320svh)の中に sticky の `.hero` を置き、行を `.line` で並べる。ピントで白くしたい行は `<span class="w" data-t="…"><span class="g">…</span></span>` の構造にする。
2. `<script>` ブロック全体を移植する。
3. `P.maxBlur / depthScale / focusWidth` で見た目、`P.autoSpeed / idleAfter` で自動往復、`P.start` で初期のピント面を決める。
4. スクロール量と連動させたくないときは `onScroll` を外し、`target` を別の値で動かす。

| パラメータ | 既定 | 意味 |
|---|---|---|
| maxBlur | 14 / 9(モバイル) | 最大ぼかし(px) |
| depthScale | 0.08 | 手前と奥の拡大縮小 |
| focusWidth | 0.34 | ピントの深さ(行の深さ 0–1 に対する幅) |
| autoSpeed | 0.06 | 自動のピント送りの周波数(Hz) |
| idleAfter | 2.5 | 自動往復に入るまでの秒数 |
| start | 0.42 | 初期のピント面 |


