# フィルムの粒子 — Style Reference
> 近黒の画面に 24fps の粒子。暗部ほど粗く、隅はビネットで沈み、たまに縦の傷が走る

**Theme:** dark  **Series:** PARTS 099  **World:** 架空の映像レーベル「Nightreel」。16mm の夜の場面。

## Concept
画像とメディア効果。ページの最前面に透明な WebGL キャンバスを置き、毎フレーム違うハッシュノイズを「粒」として乗せる。粒は暗い場所で強く、明るい中心で弱い。隅はビネットで暗く、全体が 1〜2px 揺れ(ゲートウィーブ)、明るさがわずかに明滅し、5 フレームに 1 回の確率で縦の傷が走る。更新は 24fps に間引き、フィルムに見せる。
下の画面は近黒に氷白の文字、電気的な青 1 語と、青い水平線 1 本。カーソルを右へ動かすほど粒が増え、ISO と grain の読み出しが変わる。

## Signature Technique
- 透明 canvas(`premultipliedAlpha: true`)、`blendFuncSeparate(ONE, ONE_MINUS_SRC_ALPHA)`。フラグメントの出力は「加える光(rgb)」と「取り除く量(alpha)」の 2 役。
- 粒: `g = mix(hash(floor(px) + frame·7.1), hash(floor(px·.5) + frame·3.3), .35) - .5`。`px` は `gl_FragCoord / SIZE`(SIZE 1.1、モバイル 1.4)。正の g は `add`、負の g は `sub` へ。
- 暗部ほど強く: 画面中心からの距離 `r` で明るさを近似(`bright = 1 - smoothstep(0, .9, r)`)、`amount = GRAIN·mix(1, .45, bright)`。
- ビネット: `smoothstep(.35, 1.15, r)·.55` を alpha に加える。
- ゲートウィーブ: フレームごとに `hash1(frame)` から ±.6px のずれを粒の座標に足す。
- 明滅: `(hash1(frame·.13) - .5)·.035` を alpha から引く / 光に足す。
- 傷: `step(.93, hash1(floor(frame/5)))` のとき、x = `hash1(...)·W` に幅 1.5px の線を、縦方向のハッシュで途切れさせて描く。
- 24fps: `now - last ≥ 1000/24` のときだけ `frame++` して描く。rAF は 60 でも粒は 24 回/秒しか変わらない。
- 入力: pointer の x で `GRAIN` を .08〜.68 に、.15/frame で追従。
- `prefers-reduced-motion`: 1 フレームだけ描いて止める(揺れ・明滅・傷は 0)。

```glsl
float g=mix(hash(floor(px)+uFrame*7.1),hash(floor(px*.5)+uFrame*3.3+11.),.35)-.5;
float amount=uGrain*mix(1.,.45,bright);
vec3 add=vec3(max(g,0.))*amount*1.6*uTint+scr;
float a=clamp(max(-g,0.)*amount*1.2+vig-fl,0.,1.);
o=vec4(add+max(fl,0.)*.5,a); // premultiplied
```

## Color Palette
| Token | HEX | Role |
|---|---|---|
| --void | #050608 | 地 |
| scene | #121620 | 中心の弱い光(放射グラデ) |
| --ice | #e9eef5 | 見出し、ラベルの強調 |
| --mist | #9aa3b0 | ラベル、脚注(粒が乗っても読める明るさ) |
| body | #d2d8e1 | 本文 |
| --blue | #1f58f2 | 見出しの 1 語、水平線、focus |
| grain tint | (1, .98, .94) | 粒の光のわずかな暖色 |

## Typography
- 見出し: Inter 500、`clamp(40px, 7.2vw, 112px)`、line-height .98、letter-spacing -.04em。1 語だけ青。
- 本文: Zen Kaku Gothic New 400(300 だと粒に負ける)、`clamp(14px, 1.1vw, 16px)`、line-height 1.9、最大幅 30em、`word-break: auto-phrase`。
- ラベル・読み出し: Space Mono 11px、大文字、letter-spacing .14〜.16em、tabular-nums。

## Spacing & Layout
- 画面は fixed、3 行グリッド(上ラベル / 本文 / 下ラベル)。余白 `clamp(20px, 5vw, 72px)`、下 64px(タグと重ねない)。
- 水平線は下から 112px、青、opacity .7。
- 読み出し(ISO / grain / fps)は本文の下、間隔 28px。

## Motion
- 粒 24fps。揺れ ±.6px、明滅 ±1.75%、傷は平均 5 フレームに 1 回未満。
- GRAIN の追従 .15/フレーム。
- `prefers-reduced-motion: reduce`: 静止 1 枚。

## Components
- page: 上ラベル行(レーベル / リール)、見出し + 本文 + 読み出し、下ラベル行(タイムコード)。
- canvas#grain: 最前面、`pointer-events: none`。
- tag: `VALE / PARTS 099 / フィルムの粒子` と操作説明 1 行(タッチ端末で文言差し替え)。

## Do / Don't
- Do: 粒を 24fps に間引く。60fps の粒はテレビの砂嵐に見える。
- Do: 暗部に強く、明部に弱く。均一な粒は「上に乗せた」と分かる。
- Do: 粒の光にわずかな暖色を入れる。純白の粒は冷たくデジタルに見える。
- Don't: GRAIN を .7 以上にしない。文字が読めない。
- Don't: 傷を毎フレーム出さない。たまに走るから傷になる。
- Don't: `mix-blend-mode: overlay` で貼らない。premultiplied の加算 / 減算のほうが暗部の制御が効く。

## References
- Atlantic.vc: 「近黒に氷白の文字、見出しの 1 語だけ電気的な青」という配色と字組みの考え方を借りた。粒子の画像は使わず、粒をシェーダーで作った。
- Phantom Studios: 「黒い面に文字と 1 本の信号線だけ」という構成を借りた。緑の線を青にし、粒子の層を足した。

## Usage
1. HTML: ページの最後に `<canvas id="grain">` と、必要なら読み出し(`#gv` `#iso`)を置く。
2. CSS: `canvas#grain{position:fixed;inset:0;pointer-events:none;z-index:最上}` の 1 ルール。下のページは何でもよい(写真・動画の上でも効く)。
3. JS: `<script>` 全体を移植。パラメータは `P`:
   - `GRAIN` 粒の量(初期 .32、操作で .08〜.68)、`SIZE` 粒の大きさ(px)、`VIGNETTE` 隅の暗さ、`FLICKER` 明滅、`WEAVE` 揺れ(px)、`SCRATCH` 傷の濃さ(.25)、`FPS` 粒の更新回数、`TINT` 粒の光の色
   - 粒を暗部に集める基準は画面中心からの距離。写真の上で使うなら、写真の輝度をテクスチャとして渡し `bright` に使うとよい(`uniform sampler2D` を 1 つ足す)。
4. 読み出しと pointer の制御が不要なら、`addEventListener('pointermove', ...)` と `gv/iso` の行を消す。
5. WebGL2 が無い環境では `.nogl` が付き canvas が消える。下のページはそのまま見える。
