概要
画面を上下に分割し、下半分を反転させて上半分を映す鏡面反射。水面のゆらぎとグリッチノイズがマウスの動きに反応する、キービジュアル・ヒーロー向けのインタラクティブ演出。
使用技術
・GSAP + ScrollTrigger + Observer(マウス/タッチ速度検知)
・SVGフィルター(feTurbulence + feDisplacementMap による歪み)
・CSS Scroll Snap / `transform: scaleY(-1)` + mask-image(反射表現)
実装ポイント
・反射面はCSSで作る。同じ背景を持つ下半分を `transform: scaleY(-1)` で反転し、`mask-image` の下方向グラデーションで徐々にフェードさせて水面らしく見せる
・歪みはSVGの `feTurbulence` の `baseFrequency` と `feDisplacementMap` の `scale` をJSから動的に書き換えて表現。GSAPでダミー値オブジェクト(`this.val`)を補間し、`onUpdate` で `setAttribute` して反映
・`WaterEffect` はゆらぎ用に `repeat: -1, yoyo: true` のループタイムライン、`GlitchEffect` は `ease: “steps(5)”` の断続変化に加え `triggerRandomGlitch` を `gsap.delayedCall` でランダム再帰させ不定期にノイズを走らせる
・スクロールはScrollTriggerに `scroller: “.gallery-container”` を指定してScroll Snapコンテナと連携。`onToggle` で表示中セクションのエフェクトのみ `play`/`pause` して負荷を制御
・`Observer`(`type: “pointer”`)でマウス/タッチ速度(`velocityX/Y`)を取得し、勢いに応じて歪みを一時的に強めてから戻す反応を実装
コアスニペット
this.tl = gsap.timeline({
repeat: -1, yoyo: true, paused: true,
onUpdate: () => this.update(),
});
// ...
update() {
const fx = this.val.baseFreqX + this.val.mouseFreqX;
const fy = this.val.baseFreqY + this.val.mouseFreqY;
const s = this.val.baseScale + this.val.mouseScale;
this.turb.setAttribute("baseFrequency", `${fx} ${fy}`);
this.disp.setAttribute("scale", s);
}