<img src="//placehold.it/250x200" alt="" class="image">

<div class="circle-cursor circle-cursor--inner"></div>
<div class="circle-cursor circle-cursor--outer"></div>
body {
  margin: 0;
  --cursor-color: #000;
}
.circle-cursor {
  position: fixed;
  left: 0;
  top: 0;
  pointer-events: none;
  border-radius: 50%;
  transition: background-color 300ms;
}

.circle-cursor--inner {
  width: 5px;
  height: 5px;
  left: -2.5px;
  top: -2.5px;
  z-index: 11000;
  background-color: var(--cursor-color);
}

.circle-cursor--inner.circle-cursor--hover {
  background-color: rgba(0,0,0,0);
}

.circle-cursor--outer {
  width: 30px;
  height: 30px;
  left: -15px;
  top: -15px;
  border: 1px solid var(--cursor-color);
  z-index: 12000;
  opacity: 0.2;
}

.circle-cursor--outer.circle-cursor--hover {
  background-color: var(--cursor-color);
}
const image = document.querySelector('.image');

const cursorInner = document.querySelector('.circle-cursor--inner');
const cursorOuter = document.querySelector('.circle-cursor--outer');

let mx = window.innerWidth / 2;
let my = window.innerHeight / 2;
let cxi = mx, cyi = my, cxo = mx, cyo = my;

window.addEventListener('mousemove', (event) => {
  mx = event.clientX;
  my = event.clientY;
});

function update() {
  const dxi = (mx - cxi) * 0.2;
  const dyi = (my - cyi) * 0.2;
  cxi += dxi;
  cyi += dyi;
  
  const dxo = (mx - cxo) * 0.07;
  const dyo = (my - cyo) * 0.07;
  cxo += dxo;
  cyo += dyo;
  
  cursorOuter.style.transform = `translate(${cxo}px, ${cyo}px)`;
  cursorInner.style.transform = `translate(${cxi}px, ${cyi}px)`;
  
  requestAnimationFrame(update);
}

requestAnimationFrame(update);

image.addEventListener('mouseenter', () => {
  cursorInner.classList.add('circle-cursor--hover');
  cursorOuter.classList.add('circle-cursor--hover');
});

image.addEventListener('mouseleave', () => {
  cursorInner.classList.remove('circle-cursor--hover');
  cursorOuter.classList.remove('circle-cursor--hover');
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.