Hue orbit
Soft colour blobs rotate around the centre and shift through the spectrum as you scroll.
The page background melts smoothly from one section’s colour into the next.
Each section declares a background and text colour in data attributes. On scroll, the script finds the pair of sections around the viewport centre and linearly interpolates their RGB values, then paints the body with the result.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Section colour blend</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 { transition: none; }
section { height: 100vh; display: grid; place-items: center; }
section h2 { font: 900 clamp(3rem, 13vw, 9rem)/1 system-ui, sans-serif; letter-spacing: -.04em; margin: 0; }
</style>
</head>
<body>
<section data-bg="#fff1e6" data-fg="#6d2e46"><h2>Morning</h2></section>
<section data-bg="#a2d2ff" data-fg="#03045e"><h2>Noon</h2></section>
<section data-bg="#ffafcc" data-fg="#590d22"><h2>Afternoon</h2></section>
<section data-bg="#ff7b00" data-fg="#2b0f00"><h2>Sunset</h2></section>
<section data-bg="#10002b" data-fg="#e0aaff"><h2>Night</h2></section>
<script>
const secs = [...document.querySelectorAll('section')];
const hex = h => [1, 3, 5].map(i => parseInt(h.slice(i, i + 2), 16));
const mix = (a, b, t) => 'rgb(' + a.map((v, i) => Math.round(v + (b[i] - v) * t)).join(',') + ')';
const cols = secs.map(s => ({ bg: hex(s.dataset.bg), fg: hex(s.dataset.fg) }));
function update() {
const pos = (scrollY + innerHeight / 2) / innerHeight - 0.5;
const i = Math.max(0, Math.min(secs.length - 1, Math.floor(pos)));
const j = Math.min(secs.length - 1, i + 1);
const t = Math.max(0, Math.min(1, pos - i));
document.body.style.background = mix(cols[i].bg, cols[j].bg, t);
document.body.style.color = mix(cols[i].fg, cols[j].fg, t);
}
addEventListener('scroll', update, { passive: true });
update();
</script>
</body>
</html>