# シャボン玉 — Style Reference
> 骨色の壁に大きなイタリックの一語、その前に薄膜の球がひとつ浮かぶ

**Theme:** light  **Series:** PARTS 026  **World:** 架空の泡洗顔「awa」のトップ。泡は長く持たない、という事実を膜が薄くなって割れるシャボン玉で見せる。

## Concept
背景は骨色の壁と巨大なセリフのワードマーク。その手前にシャボン玉をひとつ置き、カーソルに遅れてついてくる。膜の色は薄膜干渉の計算から出していて、上が薄く下が厚いので、色の縞が重力の向きに並ぶ。時間とともに全体が薄くなり、上端から色が消え、26秒で割れて生まれ直す。クリックで割ることもできる。

## Signature Technique
全画面1枚のフラグメントシェーダー(WebGL1)。背景テキストは 2D canvas をテクスチャにして渡す。

- **球面**: `q = (px − center)/R`。`wob = 1 + 0.018·(sin 2a + 0.7 sin 3a + 0.5 sin 5a)`(時間で位相が動く)で q を割り、輪郭を揺らす。`z = sqrt(1 − r²)`、`N = (q, z)`。
- **膜厚 d (nm)**: `thick0 + drain·(1 − up)^1.7 + swirl·(fbm(q·2.6 − t·0.12) − .5)·2 + 40·noise(2.5a, 5r − 0.35t)`。`thick0` は寿命の中で 520 → 120 nm に線形で減る。`drain` = 480、`swirl` = 110。
- **薄膜干渉**: n = 1.33、`cosθt = sqrt(1 − (1 − cos²θi)/n²)`、波長 λ = 650 / 550 / 450 nm で `R(λ) = 0.5 − 0.5·cos(4π n d cosθt / λ)`。d → 0 で黒になる(割れる直前の黒い斑点)。彩度は 22% だけ落とす。
- **フレネル**: `fres = (1 − z)^2.4`、`amp = mix(0.06, 0.95, fres)`。中心はほぼ透明、縁で強く色が出る。
- **環境の反射**: `R = (2zq, 2z² − 1)`。窓 `smoothstep(.80, .985, R·(−.55, .62, .55))` と床の照り返し `smoothstep(.90, .995, R·(.5, −.55, .67))·0.45`。`env = 0.5 + 1.2·win + win2`。窓の中心には `smoothstep(.9935, .9985, …)` の小さな白い点を 85% で重ね、膜の張りを出す。
- **屈折**: 中空なので弱く、`uv − q·(1 − z)·0.07·R/res` だけ背景をずらす。
- 合成: `bg·(1 − amp·0.5) + F·amp·env + 白·win·fres·0.5`。外周 1.5% に `F·1.4 + 0.1` の縁取り。
- **生成と破裂**: 生成は 0.8 秒で `scale = 1 − (1−u)³`、不透明度は 0.3 秒で 0 → 1、揺れ振幅 4倍から減衰。破裂は 0.22 秒で半径 1.12 倍・不透明度 0・揺れ 7倍、破裂開始から 0.8 秒後に再生成。
- 膜厚の代表値(上端 + drain/2)を右下に `film <値> nm` と表示。寿命の中で 760 → 360 nm に下がる。

```glsl
vec3 film(float d,float cosT){ const float n=1.33; float cT=sqrt(1.-(1.-cosT*cosT)/(n*n));
  vec3 ph=4.*3.14159265*n*d*cT/vec3(650.,550.,450.); return .5-.5*cos(ph); }
float d=uThick0+uDrain*pow(1.-up,1.7)+uSwirl*(fbm(q*2.6+vec2(0.,-uT*.12))-.5)*2.;
float amp=mix(.06,.95,pow(1.-z,2.4));
col=bgR*(1.-amp*.5)+film(d,z)*amp*env;
```

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --bone | #ebebe8 | 壁。背景テクスチャの塗りも同じ |
| --ink | #221f1c | ワードマーク、見出し、クレジット |
| --stone | #797267 | 本文 |
| --pebble | #8c8a88 | ヘッダー補助、操作説明 |
| --teal | #2fa7a5 | 膜厚の数値だけに使う色 |
| --paper | #f5f5f3 | 予備の明るい面 |
| 膜の色 | 計算値 | 波長 650/550/450 nm の干渉から出るので固定色は無い |

## Typography
- ワードマーク: Instrument Serif italic 400、画面幅の62%(モバイル86%)、高さの72%上限。canvas に描く。
- 日本語見出し: Noto Sans JP 500、`clamp(18px, 1.6vw, 22px)`。本文 400、`clamp(13px, 1.05vw, 15px)`、最大幅 38em(デスクトップで本文が1行に収まり、句点だけが次行に落ちない)。`text-wrap: pretty`。
- ラベル: JetBrains Mono 400、11–12px、letter-spacing 0.06em。
- WebGL 不可時は `.fallback` に同じワードマークを HTML で表示。

## Spacing & Layout
- hero `min-height: 100svh`、3行グリッド。canvas は背面全面。
- ワードマーク中心は高さの46%(モバイル40%)。球は半径 `min(W, H)·0.30`(モバイル 0.40)、生成位置は横50%・下から56%。自走時はそこを中心に横 ±12%・縦 ±5% で漂う。
- 余白: 横 `clamp(20px, 5vw, 72px)`、上 `clamp(20px, 3vw, 40px)`、下 `clamp(18px, 2.6vw, 32px)`。見出しと本文の間 8px。モバイル左右 18px。
- breakpoint 760px: ヘッダー右を消し、フッターを縦積み。

## Motion
- 球はカーソルへ 5%/フレームで追従。カーソル無し・タッチ端末では周期約30秒 / 19秒で漂う。
- 膜の渦は 0.12/s で上向きに流れ、輪郭は 1.6–3.1 rad/s で揺れる。
- 寿命 26 秒で自動破裂、クリック/タップで即破裂。0.8 秒後に再生成。
- rAF 1本、IntersectionObserver と visibilitychange で画面外停止。リサイズで背景テクスチャを描き直す。
- `prefers-reduced-motion: reduce`: 上端膜厚 380 nm(表示 620 nm)・揺れ半分・時間 0 で1フレームだけ描く。自動破裂もしない。カーソル移動時だけ描き直す。

## Components
- hero: 背面 canvas(`aria-hidden`)+前面テキスト。
- header: 左に製品名、右に技法と波長。
- copy: 見出し1行+本文2文、左下。
- footer tag: `VALE / PARTS 026 / シャボン玉 · film <値> nm`(数値だけ --teal)と操作説明1行(タッチ端末では差し替え)。

## Do / Don't
- Do: 背景は明るい無地と1語だけ。球の屈折と透けが見える対象が要る。
- Do: 中心の反射率は 0.06 前後に抑える。上げると色付きの円盤に見える。
- Do: 膜厚は 100–900 nm の範囲で動かす。これを外れると色が出ない。
- Don't: 球を複数浮かべない。1つで十分で、増やすと装飾になる。
- Don't: 固定の虹色グラデーションに置き換えない。干渉式から出る色だけを使う。
- Don't: 影や床を描き足さない。

## References
- Micro: 明るい紙色の作業面と暖かい近黒の文字、強い色を小さな文字情報だけに使う考え方を借りた。水平線のグラデーションは使わず、色はすべて膜の干渉に任せた。
- BUTT STUDIO: 骨色の壁に巨大なセリフのワードマークを1つ置く構成を借りた。ワードマークを背景に下げ、その前に球を置いて屈折の対象にした。

## Usage
1. `<canvas id="gl">` を hero の背面に置き、`<link>` で Instrument Serif を読み込む。
2. `<script>` ブロック全体を移植する。フォント読込後に `buildBg()` が背景テクスチャを描く。
3. `P.word` と `buildBg()` 内の書体・塗り色を差し替える。背景に別の画像を使うときは `texImage2D` に渡すソースを変える。
4. 色は CSS 変数と `buildBg()` の `fillStyle`(壁・文字)を揃える。
5. 自動破裂が不要なら `P.life` を大きくする。膜厚の表示が不要なら `#film` の行を消す。

| パラメータ | 既定 | 意味 |
|---|---|---|
| radiusFrac | 0.30 / 0.40(モバイル) | 半径 / min(幅, 高さ) |
| life | 26 | 自動で割れるまでの秒数 |
| thick0 / thick1 | 520 / 120 | 上端の膜厚(nm)の初期値と終端値 |
| drain | 480 | 下に溜まる厚み(nm) |
| swirl | 110 | 渦による厚みの乱れ(nm) |
| wobble | 0.018 | 輪郭の歪み(半径比) |
| refract | 0.07 | 背景のずれ量 |
| follow | 0.05 | カーソル追従率 |
| dprMax | 1.5 | 表示解像度の上限 |
