← All gadgets

Wave Divider

A section break that rolls instead of sitting still

Running live from https://fun.whitneys.co, cross-origin and sandboxed.

Put it on your site

<iframe
  src="https://fun.whitneys.co/g/wave-divider"
  width="460"
  height="120"
  title="Wave Divider"
  sandbox="allow-scripts allow-popups-to-escape-sandbox"
  loading="lazy"
  style="border:0"></iframe>

An iframe, not a script tag -- so this gadget cannot touch the page you paste it into, and neither can we. Your settings above are baked into the URL.

The whole thing

Raw file

Every gadget is one file, and this is it -- all 2.3 kB. Take it, change it, ship it. Just keep the credit.

Show source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<script type="application/json" id="gadget-manifest">
{
  "name": "Wave Divider",
  "tagline": "A section break that rolls instead of sitting still",
  "category": "media",
  "tags": ["svg", "divider", "animation"],
  "author": "rwhitney",
  "background": "transparent",
  "size": { "w": 460, "h": 120, "resizable": false },
  "config": {
    "accent": { "type": "color", "label": "Colour", "default": "#66D9EF" },
    "speed":  { "type": "range", "label": "Speed", "min": 0, "max": 20, "step": 1, "default": 8 },
    "layers": { "type": "select", "label": "Layers", "options": ["one", "two", "three"], "default": "three" }
  },
  "permissions": []
}
</script>
<style>
  html, body { margin:0; height:100%; overflow:hidden; background:transparent; }
  svg { display:block; width:100%; height:100%; }
  .wave { animation: roll var(--dur, 8s) linear infinite; }
  .wave.b { animation-duration: calc(var(--dur, 8s) * 1.6); opacity: .55; }
  .wave.c { animation-duration: calc(var(--dur, 8s) * 2.4); opacity: .3; }
  @keyframes roll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
  @media (prefers-reduced-motion: reduce) { .wave { animation: none; } }
</style>
</head>
<body>
  <svg viewBox="0 0 200 40" preserveAspectRatio="none" aria-hidden="true">
    <g class="wave c"><path id="p3" d="M0 26 q 25 -10 50 0 t 50 0 t 50 0 t 50 0 V40 H0Z"/></g>
    <g class="wave b"><path d="M0 22 q 25 -12 50 0 t 50 0 t 50 0 t 50 0 V40 H0Z"/></g>
    <g class="wave a"><path d="M0 18 q 25 -14 50 0 t 50 0 t 50 0 t 50 0 V40 H0Z"/></g>
  </svg>
<script>
(function () {
  var cfg = window.gadget ? window.gadget.config : {};
  var accent = cfg.accent || '#66D9EF';
  var speed = typeof cfg.speed === 'number' ? cfg.speed : 8;

  document.documentElement.style.setProperty('--dur', (speed === 0 ? 0 : 24 / speed) + 's');
  [].forEach.call(document.querySelectorAll('path'), function (p) {
    p.setAttribute('fill', accent);
  });

  var keep = { one: 1, two: 2, three: 3 }[cfg.layers] || 3;
  var groups = document.querySelectorAll('.wave');
  // Hide from the back forward, so "one" leaves the crispest layer visible.
  for (var i = 0; i < groups.length - keep; i++) groups[i].style.display = 'none';
})();
</script>
</body>
</html>