From the feed
Aurora mesh hero background
A dependency-free animated gradient hero built on one canvas element.
Yours to take. No sign-up, no email, no attribution needed.
The code
const c = document.getElementById('aurora');
const x = c.getContext('2d');
let W, H;
// Each blob drifts on its own two sine waves, so the loop never
// repeats visibly. ax/ay = how far it wanders, sx/sy = how fast.
const blobs = [
{ col: [168, 65, 44], ax: 0.22, ay: 0.16, sx: 0.31, sy: 0.23, r: 0.55 },
{ col: [34, 64, 94], ax: 0.28, ay: 0.20, sx: 0.19, sy: 0.29, r: 0.62 },
{ col: [234, 159, 144], ax: 0.18, ay: 0.24, sx: 0.27, sy: 0.17, r: 0.48 },
];
const rgba = (c, a) => `rgba(${c[0]},${c[1]},${c[2]},${a})`;
function size() {
W = c.width = c.clientWidth;
H = c.height = c.clientHeight;
}
function frame(now) {
const t = now / 1000;
x.clearRect(0, 0, W, H);
// This one line is what makes them blend instead of stack.
x.globalCompositeOperation = 'lighter';
for (const b of blobs) {
const cx = W * (0.5 + b.ax * Math.sin(t * b.sx));
const cy = H * (0.5 + b.ay * Math.cos(t * b.sy));
const R = Math.max(W, H) * b.r;
const g = x.createRadialGradient(cx, cy, 0, cx, cy, R);
g.addColorStop(0, rgba(b.col, 0.62));
g.addColorStop(0.45, rgba(b.col, 0.22));
g.addColorStop(1, rgba(b.col, 0));
x.fillStyle = g;
x.beginPath();
x.arc(cx, cy, R, 0, Math.PI * 2);
x.fill();
}
x.globalCompositeOperation = 'source-over';
requestAnimationFrame(frame);
}
addEventListener('resize', size);
size();
requestAnimationFrame(frame);We do this for a living, on bigger things.
Tomoe builds operations software for businesses running real money through spreadsheets and WhatsApp threads. The same care that went into this effect goes into an order portal that a warehouse depends on.