# レンズ — Style Reference
> 近白の紙の上を真鍮の虫めがねが動き、覗いた範囲だけ隠した一行が屈折して浮かぶ

**Theme:** light  **Series:** PLAY 007  **World:** 虫めがねと隠し文字。紙には見えている文と見えていない文がある。

## Concept
画面は薄い字の見出しと短い本文、その周りの余白全体に淡い灰の小さな本文(虫めがねの仕組みの文)が組まれた紙。真鍮の縁の虫めがねがカーソルに付いて動き、レンズの内側だけ「裏のレイヤー」が倍率 1.6 で拡大され、球面の法線で屈折し、縁で三色にずれて見える。裏のレイヤーには本文の行間と、紙全体の行間に黒(墨)の一行が敷いてあり、レンズを通した時だけ読める。初期位置は本文の一行目の行間に掛かる場所で、読み込み直後からゆっくり漂うので、静止画でも屈折と隠し文字が写る。色は紙と墨の階調に、青 1 色(印)と真鍮(縁)だけ。

## Signature Technique
2 レイヤーをテクスチャに描き、レンズ内だけ UV 屈折 + 倍率 + 色収差で合成する全画面フラグメントシェーダー(WebGL1)。

- レイヤー: 表(front)と裏(hidden)を同じ Canvas2D 描画関数で描き分け(`hidden` フラグ)、`texImage2D` で 2 枚のテクスチャにする。文字はすべて canvas に描く(DOM の文は WebGL 不可の時だけ表示)。字詰めは 1 文字ずつ `measureText` で折り返す
- レンズ座標: `d = (px − L) / R`、`r = |d|`。`r > 1.02` は表をそのまま
- 法線と屈折: `n = normalize((0.9d, √(1 − r²)))`、`rf = refract((0,0,−1), n, 1/1.5)`、`off = 0.35 × rf.xy / max(|rf.z|, .25)`
- 倍率: `base = d / 1.6 + 0.5 off`(レンズ中心を基準に uv を縮める)
- 色収差: チャンネル c ごとに `k = 1 + ca × (c − 1) × r⁸`(ca = 0.012)。縁の 2〜3px だけがずれ、中心は鮮明
- ガラス: `edge = smoothstep(.8, 1, r)` で青みと減光、楕円のハイライト 2 つ、縁 2.5px のアンチエイリアス
- 縁(真鍮): DOM の円に `conic-gradient` の金属色、`mask: radial-gradient` で幅 12px の環にし、`drop-shadow` で紙に落ちる影。柄は 16px 幅のグラデーションで −42° ± 5°(x 位置で傾く)
- 追従: `x += (target − x) × .14`。ホームは本文 1 行目の行間の中央。放置中は本文の幅の中を `sin(.3t)` で左右に往復し、縦は行間の ±¼ で揺れる
- 同じ仕組みを 3 か所で使う: hero(文字)、01 のパネル(表=灰の格子、裏=青の格子と点。レンズは Lissajous で周回)、03 のパネル(表=小さな淡い本文が組まれた紙面で、隠し行の位置だけ行が抜けている。裏=同じ紙面を薄くし、抜けた位置に墨の 4 行。レンズが行を左→右になぞり次の行へ跳ぶ、5.5 s / 行)
- 02 は CSS: 見出しを C/M/Y の 3 層 `mix-blend-mode: multiply` で重ね、スクロール進捗で ±26px(mobile ±10px)ずらす
- 解像度: dpr ≤ 2(mobile 1.5、パネルは 0.8 倍)。テクスチャはリサイズとフォント読込完了時だけ再描画。rAF 1 本、画面外は描かない

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --paper | #FAFAF7 | 地色 |
| --paper-2 | #F1F2EE | 予備の面 |
| --ink | #24262E | 見出し |
| --slate | #4A4D5A | 本文 |
| --mute | #8A8D98 | ラベル、ヒント |
| --hair | #E3E5E8 | 罫線と格子。パネル枠にも |
| --blue | #2F6BFF | 印。hover と focus にも。唯一の彩度 |
| sheet (canvas) | #CED1D7 | 紙全体に敷いた小さな本文(13.5px / mobile 12px、400) |
| --brass / --brass-l / --brass-d | #C9A24A / #F3DC92 / #7A5A1C | レンズの縁と柄の金具 |
| CMY | #1FC4E6 / #E8318F / #F2C400 | 02 の色収差見出しだけ |

## Typography
- Noto Sans JP。見出しは weight 200(h1 `clamp(38px, 5.4vw, 80px)`(wide は 1 行、mobile は読点で 2 行) / line-height 1.18 / tracking .03em、h2 `clamp(28px, 3.6vw, 52px)`、2 カラム内 `clamp(26px, 2.6vw, 38px)`)。本文 400 `clamp(16px, 1.25vw, 19px)` / line-height 1.9。隠し文字 500、本文の 0.72 倍、墨 #24262E
- ラベル: DM Mono 11.5px、tracking .22em、uppercase
- canvas 側も同じ指定(`200 {size}px "Noto Sans JP"`)で描き、`document.fonts.load` の完了後に描き直す
- 02 の見出し `clamp(40px, 9vw, 150px)`(mobile 7.4vw)、nowrap

## Spacing & Layout
- 基本単位 8px。区画の縦余白 `clamp(96px, 16vh, 180px)`、締め `clamp(120px, 22vh, 240px)`
- gutter `clamp(20px, 4vw, 56px)`、最大幅 1200px。hero は左寄せ 1 カラム(本文は 46em まで、mobile 22em)
- grid 5fr / 7fr、gap `clamp(32px, 6vw, 96px)`、860px 以下で 1 カラム
- パネル: 4:3(01)、16:9(03、mobile は 4:5)、radius 24px、hairline 枠、影はほぼ無し
- レンズ半径 `clamp(.21 × min(W,H), 100, 190)`
- breakpoints: 860px(grid)、640px(mobile 文字、柄の長さ)

## Motion
- 自走: レンズの漂い(hero)。01 の周回と 03 の走査。それ以外はカーソルかスクロールに従属
- カーソル: hero は常時追従、タッチは押している間だけ。離れると漂いに戻る
- 02: 進捗 `(0.85H − top) / (height + 0.3H)` で ±26px
- reduced-motion: レンズはホーム位置で静止、01 と 03 は固定位置、02 は 75% の位置で固定。レンズを手で動かすことはできる
- WebGL 不可: canvas と縁を消し、DOM の本文(隠し行は墨の 500 で常時表示)を出す

## Components
- hero: canvas(表/裏)+ DOM の縁と柄。左上に印付きラベル、見出し、本文、墨の隠し行(裏のみ)、mono のヒント。見出しと本文の右側と下は、紙全体に小さな本文を行送り 1.9 で流し込む(句読点は行頭に置かない)
- section 01: 見出し + 本文 + mono 表(layers / normal / refract / mag)、右に格子パネル
- section 02: 中央寄せの CMY 三層見出し、1 文、`ca` の現在値
- section 03: 見出しと 1 文を上に、16:9 の罫線パネル
- button: pill、ink 塗り、hover で青。focus-visible は青 2px outline
- footer: hairline の上に mono 11px `VALE / PLAY 007` と作品名

## Do / Don't
Do
- 隠し文字は墨、縁は真鍮だけ。他の彩度を置かない
- 表と裏の描画関数を 1 つにし、`hidden` フラグで差分だけ変える
- レンズのホームは本文に掛かる位置に置き、静止画で屈折が分かるようにする
- 色収差は `r²` に比例させ、中心は澄ませる
- テクスチャの再描画はリサイズとフォント読込時だけにする

Don't
- CSS の `backdrop-filter` や `scale` で代用しない(屈折と収差が出ない)
- ハイライトを大きくしない(文字が読めなくなる)
- 文章を 1 画面に 2 文より増やさない
- レンズを 2 つ以上同時に出さない
- 隠し文字を本文と同じ色で描かない

## References
- Aqua Voice(Whisper on paper): 「weight 200 の見出しが近白の紙に置かれ、青 1 滴だけが彩度を持つ」配分をそのまま骨格にした。紙は #FAFAF7、青は #2F6BFF に変え、PP Neue Montreal の代わりに Noto Sans JP 200。1 カラム中央の型は、レンズの通り道を空けるため左寄せ 1 カラムに変えた
- MindMarket(Warm storybook on cream paper): 「要素は少なく、型は大きく、角は大きく丸く、作品が主役」という密度を引き、クリーム紙は近白に、50〜64px の角丸は 24px に落とした。紙切り絵の挿絵の役を、真鍮の虫めがね 1 つに置き換えた
