概要
マウスに吸い寄せられて追従し、離すと水しぶきを飛ばしながらプルンと元に戻る、目を引くマグネティック(磁石)CTAボタン。
使用技術
・GSAP(Tween + `gsap.ticker` によるカスタム物理演算ループ)
・SVGフィルター(`feGaussianBlur` + `feColorMatrix`)によるGooey(粘性)効果
・素のJavaScript(クラス設計 `HybridCTA`)
実装ポイント
・マウスとボタン中心の距離を計算し、`triggerRadius` 内なら移動量の50%を追従、3D回転(`rotationX/Y`)も付与
・液体層にSVGの `#goo-hybrid` フィルターを掛け、ぼかし+コントラスト増強でしぶきとボタンを溶け合わせて表示
・離した瞬間 `elastic.out(1, 0.3)` で弾むように原点復帰、引っ張り量が閾値超えなら水しぶきを生成
・水しぶきは `gsap.ticker` で毎フレーム速度・重力・寿命を更新する自作パーティクル物理演算で放物線落下を再現
・文字は別レイヤーでフィルターを掛けずに配置し、視差(Parallax)を付けつつ常にくっきり保つ
コアスニペット
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < triggerRadius) {
gsap.to([this.bg, this.content], {
x: dx * 0.5, y: dy * 0.5,
rotationX: -dy * 0.1, rotationY: dx * 0.1,
transformPerspective: 800,
duration: 0.5, ease: "power2.out", overwrite: "auto",
});
} else if (this.isHovering) {
// リリース: elastic でプルンと原点復帰
gsap.to([this.bg, this.content], {
x: 0, y: 0, rotationX: 0, rotationY: 0,
duration: 1.2, ease: "elastic.out(1, 0.3)", overwrite: true,
});
}
// 毎フレームの自作パーティクル物理演算(放物線落下)
updateParticles() {
for (let i = this.particles.length - 1; i >= 0; i--) {
const p = this.particles[i];
p.x += p.vx; p.y += p.vy;
p.vy += p.gravity; // 重力を加算して放物線を描く
p.life -= 0.02 + Math.random() * 0.02;
if (p.life <= 0) { p.el.remove(); this.particles.splice(i, 1); }
else gsap.set(p.el, { x: p.x, y: p.y, scale: p.life });
}
}