SVG turbulence displacement

SVG 난기류 변위

Feeding feTurbulence noise into feDisplacementMap as a push-map — the SVG filter combo that fakes water ripples or a wobble effect with no image assets.

Also known as: feTurbulencefeDisplacementMapWater ripple filter
···
html
<svg width="0" height="0"><filter id="ripple" x="-30%" y="-30%" width="160%" height="160%">
  <feTurbulence id="turb" type="fractalNoise" baseFrequency="0.02 0.04" numOctaves="2" seed="3" result="n"/>
  <feDisplacementMap id="disp" in="SourceGraphic" in2="n" scale="18" xChannelSelector="R" yChannelSelector="G"/>
</filter></svg>
<div class="pool"><h1 class="wave" id="txt">WAVE</h1></div>
<div class="label" id="l">scale: 18</div>
css
.pool{position:absolute;inset:0;display:grid;place-items:center;background:linear-gradient(180deg,#0ea5e9,#075985)}
.wave{position:relative;color:#fff;font:800 15vmin/1 sans-serif;letter-spacing:.02em;filter:url(#ripple);margin:0}
.label{position:absolute;left:10px;bottom:10px;padding:4px 10px;border-radius:999px;background:rgba(0,0,0,.55);color:#fff;font:600 12px/1.4 monospace}
js
const disp = document.getElementById('disp');
const turb = document.getElementById('turb');
const l = document.getElementById('l');
let t = 0;
function loop(){
  t += 0.02;
  const scale = 14 + Math.sin(t) * 10;
  disp.setAttribute('scale', scale.toFixed(1));
  const bf = 0.018 + Math.sin(t * 0.6) * 0.006;
  turb.setAttribute('baseFrequency', bf.toFixed(4) + ' ' + (bf * 1.8).toFixed(4));
  l.textContent = 'scale: ' + scale.toFixed(0);
  requestAnimationFrame(loop);
}
loop();

feTurbulence draws a Perlin-noise-like random pattern. On its own it just looks like colourful static, but feed it into feDisplacementMap as in2 and it becomes a push-map: "shift each source pixel in x/y by however much this noise's R/G channels say." The result is the original content wobbling along the noise's contours.

baseFrequency controls how fine the noise is (smaller = big, smooth swells; larger = tight, jittery ripples), and feDisplacementMap's scale controls how hard it pushes. This demo oscillates both on a sine wave every frame for a continuous underwater-style wobble.

The catch is cost — noise generation and displacement are recomputed across the whole filter region every frame, so it gets noticeably heavy over a large area or the full page. Keep it scoped to small elements like text or a logo.

When to use

Scope it to one small element — a headline, a logo — for an underwater or heat-haze feel. Keep numOctaves around 2 to hold down the cost.