Hue orbit

Soft colour blobs rotate around the centre and shift through the spectrum as you scroll.

How it works

Three blurred blobs sit in a pinned layer. Scroll progress drives one angle that rotates the group and a hue value applied through hsl(), so motion and colour change together from a single number.

Full file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hue orbit</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-font-smoothing: antialiased; }

body { background: #0a0a12; color: #fff; }
.bg { position: fixed; inset: 0; overflow: hidden; display: grid; place-items: center; }
.orbit { position: relative; width: 70vmin; height: 70vmin; }
.orbit i { position: absolute; width: 45vmin; height: 45vmin; border-radius: 50%; filter: blur(60px); opacity: .8; }
.orbit i:nth-child(1) { left: 0; top: 0; }
.orbit i:nth-child(2) { right: 0; top: 10%; }
.orbit i:nth-child(3) { left: 20%; bottom: 0; }
.content { position: relative; padding: 30vh 8vw 40vh; max-width: 700px; }
.content h1 { font: 900 clamp(3rem, 10vw, 6rem)/1 system-ui, sans-serif; letter-spacing: -.04em; margin: 0 0 30vh; }
.content p { font: 600 clamp(1.4rem, 3vw, 2rem)/1.3 system-ui, sans-serif; margin: 0 0 40vh; }
</style>
</head>
<body>
<div class="bg"><div class="orbit" id="orbit"><i></i><i></i><i></i></div></div>
<main class="content">
  <h1>Hue orbit</h1>
  <p>One scroll value drives both the rotation and the colour.</p>
  <p>Keep going and the palette walks around the colour wheel.</p>
  <p>Blur turns hard circles into an ambient glow.</p>
  <p>Useful as a quiet background for a landing page.</p>
</main>
<script>
const orbit = document.getElementById('orbit');
const blobs = orbit.querySelectorAll('i');
function update() {
  const max = document.documentElement.scrollHeight - innerHeight;
  const p = max > 0 ? scrollY / max : 0;
  orbit.style.transform = 'rotate(' + (p * 360) + 'deg)';
  blobs.forEach((b, i) => { b.style.background = 'hsl(' + ((p * 300 + i * 70) % 360) + ', 85%, 60%)'; });
}
addEventListener('scroll', update, { passive: true });
update();
</script>
</body>
</html>

More color effects