<div class="mask"></div>
:root {
  --mouse-x: 50%;
  --mouse-y: 50%;
}

body {
  margin: 0;
  height: 100vh;
  background-image: url(https://since1979.dev/wp-content/uploads/2022/01/todd-quackenbush-x5SRhkFajrA-unsplash.jpg);
  background-position: center center;
  background-size: cover;
}

.mask {
  width: 100vw;
  height: 100vh;
  background-color: hsla(0,0%,0%, 0.9);
  mask: radial-gradient(
    circle at var(--mouse-x) var(--mouse-y),
    transparent 40px,
    black 150px
  );
  -webkit-mask: radial-gradient(
    circle at var(--mouse-x) var(--mouse-y),
    transparent 40px,
    black 150px
  );
}
// Get a reference to the .mask element.
const mask = document.querySelector('.mask');
const {mapRange} = gsap.utils;

// Add an event to catch mouse movements.
document.addEventListener('pointermove', (pos) => {
  
    // Calculate mouse position in %.
    let x = mapRange(
      0, window.innerWidth,
      0, 100, 
      pos.clientX
    );
    let y = mapRange(
      0, window.innerHeight,
      0, 100,
      pos.clientY
    );
  
    // Update the custom property values.
    gsap.set(mask,{
      '--mouse-x': x + '%'
    })
    gsap.set(mask,{
      '--mouse-y': y + '%'
    })
  
});

document.addEventListener('mousedown', () => {
  gsap.set(mask,{
    'display': 'none'
  })
});

document.addEventListener('mouseup', () => {
  gsap.set(mask,{
    'display': 'block'
  })
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.co/gsap@3/dist/gsap.min.js