goo フィルターでカーソルをとろとろにする
2026-06-05
SVG の feGaussianBlur と feColorMatrix を組み合わせると、複数の丸がくっついて溶け合うような表現ができます。カーソルに追従する水滴っぽいエフェクトはこれで作りました。タッチデバイスではカーソルという概念自体がないので、pointer: fine のときだけ出すようにしています。
goo フィルターの正体
feGaussianBlur で丸同士の境界をぼかしてから、feColorMatrix でアルファのコントラストを一気に上げると、ぼけて重なった部分が「つながった」ように見えます。これがいわゆる goo(メタボール)表現で、SVG フィルターを CSS の filter: url(#goo) として参照するだけで使えます。
フィルターの行列でいじっているのはアルファチャンネルだけです。alpha を 20倍して -10 する、のような極端な係数にすると、半透明のグレーゾーンが「くっきり不透明」か「完全透明」の二択に割れます。ブラーで滲んだ中間領域が不透明側に倒れることで、離れた丸同士の間に「橋」が架かる仕組みです。
追従のばね感
カーソルを追う丸は5つあって、それぞれ前の丸の位置を少し遅れて追いかけます。実装は requestAnimationFrame のループで「現在位置 += (目標位置 - 現在位置) × 係数」を繰り返すだけの、いわゆる線形補間です。追従係数を丸ごとに少しずつ小さくすると、先頭がキビキビ・末尾がとろとろになって、水滴が伸びてちぎれるような動きになります。
サイズも先頭から末尾へ小さくしています。大きい水滴が先導して小さい粒が付いていく形は、実際の水滴が壁を伝うときの見た目に近く、goo フィルターで融合したときのシルエットもきれいです。
タッチデバイスでの出し分け
hover: hover と pointer: fine のメディアクエリで、マウス環境のときだけ goo レイヤーを生成しています。タッチでは丸がその場に取り残されて不気味なので、タップの波紋だけ残して思い切って消しました。CSS 側でもレイヤーごと display: none にする二重ガードにしてあり、JS の判定がすり抜けても表示されない構えです。
パフォーマンスの注意点
SVG フィルターは適用範囲が広いと重くなります。このサイトでは追従する丸を乗せた固定レイヤー1枚にだけフィルターを当て、それ以外の要素には触らせていません。また、丸の移動は left/top の書き換えではありますが、対象が5個の小さな div だけなので実測で問題は出ていません。もし数を増やすなら transform への切り替えを検討すると思います。