Interactive Dots
A canvas-based dot grid background where dots scale and pulse in response to mouse movement and click ripples, creating an organic interactive feel.
Generated using Grepped's AI UI component generator — created from scratch, not pulled from a library.
canvasdotsgridinteractivebackgroundreactive
Live Preview — customize or regenerate this in the workspace
Loading preview…
Design Intent
A grid of dots that scale up and pulse when the mouse gets close, with ripple waves spreading from clicks.
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 DC = '#666666';
var GS = 30;
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 ripples = [];
var dots = [];
function initDots() {
dots = [];
var W = canvas.clientWidth, H = canvas.clientHeight;
for (var x = GS/2; x < W; x += GS) {
for (var y = GS/2; y < H; y += GS) {
dots.push({ ox: x, oy: y, phase: Math.random()*Math.PI*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);
initDots();
}
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/150);
}
function rippleFx(x, y, now) {
var tot = 0;
for (var k=0; k<ripples.length; k++) {
var r = ripples[k];
var age = now - r.t;
if (age < 3000) {
var dx = x-r.x, dy = y-r.y;
var dist = Math.sqrt(dx*dx+dy*dy);
var rad = age/3000*300, w = 60;
if (Math.abs(dist-rad) < w) tot += (1-age/3000)*r.i*(1-Math.abs(dist-rad)/w);
}
}
return Math.min(tot, 2);
}
function draw() {
var ctx = canvas.getContext('2d');
time += SPEED;
var now = Date.now();
var W = canvas.clientWidth, H = canvas.clientHeight;
var dc = hexRgb(DC);
ctx.fillStyle = BG;
ctx.fillRect(0, 0, W, H);
for (var i=0; i<dots.length; i++) {
var dot = dots[i];
var mf = mouseFx(dot.ox, dot.oy);
var rf = rippleFx(dot.ox, dot.oy, now);
var inf = mf+rf;
var size = 2+inf*6+Math.sin(time+dot.phase)*0.5;
var opacity = Math.max(0.3, 0.6+inf*0.4+Math.abs(Math.sin(time*0.5+dot.phase))*0.1);
ctx.beginPath();
ctx.arc(dot.ox, dot.oy, size, 0, Math.PI*2);
ctx.fillStyle = 'rgba('+dc.r+','+dc.g+','+dc.b+','+opacity+')';
ctx.fill();
}
if (!REMOVE_WAVE) {
for (var k=0; k<ripples.length; k++) {
var r2 = ripples[k];
var age2 = now-r2.t;
if (age2 < 3000) {
var p = age2/3000;
ctx.beginPath();
ctx.strokeStyle = 'rgba(100,100,100,'+(1-p)*0.3*r2.i+')';
ctx.lineWidth = 2;
ctx.arc(r2.x, r2.y, p*300, 0, Math.PI*2);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = 'rgba(120,120,120,'+(1-p)*0.2*r2.i+')';
ctx.lineWidth = 1;
ctx.arc(r2.x, r2.y, p*150, 0, Math.PI*2);
ctx.stroke();
}
}
}
requestAnimationFrame(draw);
}
resize();
window.addEventListener('resize', function() { 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();
ripples.push({ x: e.clientX-rect.left, y: e.clientY-rect.top, t: Date.now(), i: 2 });
var now = Date.now();
ripples = ripples.filter(function(r){ return now-r.t < 3000; });
});
canvas.addEventListener('mouseup', function(){ mouse.down = false; });
draw();
</script>
</body>
</html>