<div class="ball">
  <div class="halo"></div>
  <div class="halo"></div>
  <div class="halo"></div>
</div>



:root {
  --mouse-x;
  --mouse-y;
  --scale;
  --radius: 40px;
  --factor: 1;
}

.ball {
  width: var(--radius);
  height: var(--radius);
  background: #D92659;
  border-radius: 50%;
  position:absolute;
/* use calc() and the CSS variables created above to center the ball around the mouse position.  */
  transform: translate(calc(var(--mouse-x) * 1px - var(--radius)/2),calc(var(--mouse-y) * 1px - var(--radius)/2));
}

.halo {
  width: var(--radius);
  height: var(--radius);
  background: rgb(114, 61, 83);
  border-radius: 50%;
  position:absolute;
  opacity: .15;
/*   filter: blur(var(--factor)); */
  transform: scale(calc(var(--scale) * var(--factor)));
 
}

.halo:nth-of-type(1) {
  --factor: .3;
}

.halo:nth-of-type(2) {
  --factor: 0.5;
}

.halo:nth-of-type(3) {
  --factor: .9;
}

body {
  background: #070611;
  font-family: Verdana, sans-serif;
}

p {
  color: whitesmoke;
  width: 400px;
  top: 10px;
  left: 10px;
  position:absolute;
}
var [xpos,targetX,ypos,targetY, velX, velY] = [0,0,0,0,0,0];

const docStyle = document.documentElement.style;
const drag = 0.8;
const strength = 0.12;

function springItOn() {

  var diffX = targetX - xpos; 
  diffX *= strength;
  velX *=drag;
  velX += diffX;
	xpos += velX;
  
  var diffY = targetY - ypos; 
  diffY *= strength;
  velY *=drag;
  velY += diffY;
	ypos += velY;
  
  //apply the newly calculated positions via CSS custom properties each frame. SO FANCY
  docStyle.setProperty('--mouse-x', xpos);
  docStyle.setProperty('--mouse-y', ypos);
  
  //set the halo scale property baesd on some arbitrary math for kicks
  docStyle.setProperty('--scale', (velY + velX)*strength);

  requestAnimationFrame(springItOn);
}

springItOn();

//update the target position based on where the mouse is
 document.addEventListener('mousemove', (e) => {
  targetX = e.clientX;
  targetY = e.clientY;
});
View Compiled
Rerun