Sliding Ease Bars
Vertical bars interpolate between two noise-generated patterns using cubic easing, with mouse proximity and click bursts adding extra wave motion.
Generated using Grepped's AI UI component generator — created from scratch, not pulled from a library.
canvasbarseasinginterpolationinteractivebackgroundreactive
Live Preview — customize or regenerate this in the workspace
Loading preview…
Design Intent
Vertical bars that smoothly morph between two different noise patterns using cubic easing, with mouse interaction adding extra wave motion.
CSS
css
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #F0EEE6; }
canvas { display: block; width: 100%; height: 100%; }HTML
html
<canvas id="c"></canvas>Full Source
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #F0EEE6; }
canvas { display: block; width: 100%; height: 100%; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
var BG = '#F0EEE6';
var LC = '#444444';
var BC = '#5E5D59';
var LW = 1;
var SPEED = 0.005;
var REMOVE_WAVE = true;
function hexRgb(h) {
var c = h.charAt(0) === '#' ? h.slice(1) : h;
return { r: parseInt(c.slice(0,2),16), g: parseInt(c.slice(2,4),16), b: parseInt(c.slice(4,6),16) };
}
var canvas = document.getElementById('c');
var time = 0;
var mouse = { x: 0, y: 0, down: false };
var bursts = [];
function noise(x, y, t) {
var n = Math.sin(x*0.02+t)*Math.cos(y*0.02+t) + Math.sin(x*0.03-t)*Math.cos(y*0.01+t);
return (n+1)/2;
}
function resize() {
var dpr = window.devicePixelRatio || 1;
canvas.width = innerWidth * dpr;
canvas.height = innerHeight * dpr;
canvas.style.width = innerWidth + 'px';
canvas.style.height = innerHeight + 'px';
canvas.getContext('2d').scale(dpr, dpr);
}
function mouseFx(x, y) {
var d = Math.sqrt((x-mouse.x)*(x-mouse.x)+(y-mouse.y)*(y-mouse.y));
return Math.max(0, 1-d/180);
}
function burstFx(x, y, now) {
var tot = 0;
for (var k=0; k<bursts.length; k++) {
var b = bursts[k];
var age = now - b.t;
if (age < 2500) {
var dx = x-b.x, dy = y-b.y;
var dist = Math.sqrt(dx*dx+dy*dy);
var rad = age/2500*300, w = 60;
if (Math.abs(dist-rad) < w) tot += (1-age/2500)*b.i*(1-Math.abs(dist-rad)/w);
}
}
return Math.min(tot, 1.5);
}
function genPattern(seed, W, H, nLines) {
var sp = W/nLines;
var pat = [];
for (var i=0; i<nLines; i++) {
var bars = [], cy = 0;
while (cy < H) {
var nv = noise(i*sp, cy, seed);
if (nv > 0.5) {
var len = 10+nv*30, bw = 2+nv*3;
bars.push({ y: cy+len/2, h: len, w: bw });
cy += len+15;
} else { cy += 15; }
}
pat.push(bars);
}
return pat;
}
function draw() {
var ctx = canvas.getContext('2d');
time += SPEED;
var now = Date.now();
var W = canvas.clientWidth, H = canvas.clientHeight;
var nLines = Math.floor(W/15);
var sp = W/nLines;
var pat1 = genPattern(0, W, H, nLines);
var pat2 = genPattern(5, W, H, nLines);
var cyc = time % (Math.PI*2);
var mci = mouseFx(W/2, H/2)*0.5;
var adj = cyc+mci;
var ef;
if (adj < Math.PI*0.1) ef = 0;
else if (adj < Math.PI*0.9) ef = (adj-Math.PI*0.1)/(Math.PI*0.8);
else if (adj < Math.PI*1.1) ef = 1;
else if (adj < Math.PI*1.9) ef = 1-(adj-Math.PI*1.1)/(Math.PI*0.8);
else ef = 0;
var se = ef < 0.5 ? 4*ef*ef*ef : 1-Math.pow(-2*ef+2,3)/2;
var bc = hexRgb(BC);
ctx.fillStyle = BG;
ctx.fillRect(0, 0, W, H);
for (var i=0; i<nLines; i++) {
var lx = i*sp + sp/2;
var lmf = mouseFx(lx, H/2);
ctx.beginPath();
ctx.strokeStyle = LC;
ctx.lineWidth = LW+lmf*2;
ctx.moveTo(lx, 0); ctx.lineTo(lx, H); ctx.stroke();
var bars1 = pat1[i]||[], bars2 = pat2[i]||[];
var maxB = Math.max(bars1.length, bars2.length);
for (var j=0; j<maxB; j++) {
var bar1 = bars1[j] || { y: (bars2[j]||{y:0}).y-100, h:0, w:0 };
var bar2 = bars2[j] || { y: (bars1[j]||{y:0}).y+100, h:0, w:0 };
var bmf = mouseFx(lx, bar1.y);
var bf = burstFx(lx, bar1.y, now);
var baseW = Math.sin(i*0.3+j*0.5+time*2)*10*(se*(1-se)*4);
var mWave = bmf*Math.sin(time*3+i*0.2)*15;
var bWave = bf*Math.sin(time*4+j*0.3)*20;
var iy = bar1.y+(bar2.y-bar1.y)*se+baseW+mWave+bWave;
var ih = bar1.h+(bar2.h-bar1.h)*se+bmf*5+bf*8;
var iw = bar1.w+(bar2.w-bar1.w)*se+bmf*2+bf*3;
if (ih > 0.1 && iw > 0.1) {
var inten = Math.min(1, 0.8+bmf*0.2+bf*0.3);
ctx.fillStyle = 'rgba('+bc.r+','+bc.g+','+bc.b+','+inten+')';
ctx.fillRect(lx-iw/2, iy-ih/2, iw, ih);
}
}
}
if (!REMOVE_WAVE) {
for (var k=0; k<bursts.length; k++) {
var b2 = bursts[k];
var age2 = now-b2.t;
if (age2 < 2500) {
var p = age2/2500;
ctx.beginPath();
ctx.strokeStyle = 'rgba(100,100,100,'+(1-p)*0.2*b2.i+')';
ctx.lineWidth = 2;
ctx.arc(b2.x, b2.y, p*300, 0, Math.PI*2);
ctx.stroke();
}
}
}
requestAnimationFrame(draw);
}
resize();
window.addEventListener('resize', resize);
canvas.addEventListener('mousemove', function(e) {
var rect = canvas.getBoundingClientRect();
mouse.x = e.clientX-rect.left; mouse.y = e.clientY-rect.top;
});
canvas.addEventListener('mousedown', function(e) {
mouse.down = true;
var rect = canvas.getBoundingClientRect();
bursts.push({ x: e.clientX-rect.left, y: e.clientY-rect.top, t: Date.now(), i: 2 });
var now = Date.now();
bursts = bursts.filter(function(b){ return now-b.t < 2500; });
});
canvas.addEventListener('mouseup', function(){ mouse.down = false; });
draw();
</script>
</body>
</html>