Section colour blend
The page background melts smoothly from one section’s colour into the next.
Soft colour blobs rotate around the centre and shift through the spectrum as you scroll.
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.
<!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>