Googly Eyes mouse tracking

Googly Eyes That Follow Your Mouse | HTML CSS JavaScript Animation

Create fun and interactive Googly Eyes that follow your mouse using just HTML, CSS, and JavaScript! 🐭👀

In this tutorial, you’ll learn how to:

  • Design cute eyes with HTML & CSS
  • Track mouse movement with JavaScript
  • Animate pupil movement dynamically

Perfect for beginners who want to add a playful UI touch to their websites or learn more about DOM interaction.

💻 Source code included in the video!
🧠 Great for creative portfolios, Halloween effects, or quirky designs.

❤️‍🔥 Don’t forget to 👍 like, 🔁 share, and 🔔 subscribe for more fun frontend projects!
▶️ YouTube: 📺

HTML:

Create an HTML file and add the following code:

<svg id="eyes" width="128" height="128" viewBox="0 0 128 128">
  <defs>
    <linearGradient id="a" x1="0" x2="0" y1="46.676" y2="82.083" gradientUnits="userSpaceOnUse">
      <stop offset="0" style="stop-color:#424242"/>
      <stop offset="1" style="stop-color:#212121"/>
    </linearGradient>
    <g id="eye-shape">
      <path style="fill:#fafafa" d="M34.16 106.51C18.73 106.51 6.19 87.44 6.19 64s12.55-42.51 27.97-42.51S62.13 40.56 62.13 64s-12.55 42.51-27.97 42.51"/>
      <path style="fill:#b0bec5" d="M34.16 23.49c6.63 0 12.98 4 17.87 11.27 5.22 7.75 8.1 18.14 8.1 29.24s-2.88 21.49-8.1 29.24c-4.89 7.27-11.24 11.27-17.87 11.27s-12.98-4-17.87-11.27C11.06 85.49 8.19 75.1 8.19 64s2.88-21.49 8.1-29.24c4.89-7.27 11.23-11.27 17.87-11.27m0-4C17.61 19.49 4.19 39.42 4.19 64s13.42 44.51 29.97 44.51S64.13 88.58 64.13 64 50.71 19.49 34.16 19.49"/>
    </g>
    <path id="pupil-shape" style="fill:url(#a)" d="M25.63 59.84c-2.7-2.54-2.1-7.58 1.36-11.26.18-.19.36-.37.55-.54-1.54-.87-3.23-1.36-5.01-1.36-7.19 0-13.02 7.93-13.02 17.7s5.83 17.7 13.02 17.7 13.02-7.93 13.02-17.7c0-1.75-.19-3.45-.54-5.05-3.24 2.33-7.11 2.64-9.38.51"/>
  </defs>
  <use href="#eye-shape" id="eye-left"/>
  <use href="#pupil-shape" id="pupil-left"/>
  <g transform="translate(59.68 0)">
    <use href="#eye-shape" id="eye-right" />
    <use href="#pupil-shape" id="pupil-right"/>
  </g>
</svg>

CSS:

Create a CSS file and add the following code:

#eyes {
  --size: clamp(64px, 30vi, 256px); 
  block-size: var(--size); 
  inline-size: var(--size);
}

body {
  background: #f5deb3; 
  block-size: 100vb; 
  display: grid;
  grid-template-rows: 2fr 1fr; 
  place-items: center; 
  text-align: center;
}

a {
  font-family: sans-serif; 
  font-size: 2rem; 
  color: #333;
}

JavaScript:

Create a  JavaScript file and add the following code:

const eyesSVG = document.querySelector('#eyes');
const eyes = [
  {
    eye: eyesSVG.querySelector('#eye-left'), 
    offsetX: 0,
    pupil: eyesSVG.querySelector('#pupil-left')
  },
  {
    eye: eyesSVG.querySelector('#eye-right'), 
    offsetX: 0,
    pupil: eyesSVG.querySelector('#pupil-right')
  }
];

const updateEye = (ev, {eye, pupil, offsetX}) => {
  const eyeRect = eye.getBoundingClientRect();
  
  const centerX = eyeRect.left + eyeRect.width / 2;
  const centerY = eyeRect.top + eyeRect.height / 2;
  
  const distX = ev.clientX - centerX;
  const distY = ev.clientY - centerY;
  
  const pupilRect = pupil.getBoundingClientRect();
  
  const maxDistX = pupilRect.width / 2;
  const maxDistY = pupilRect.height / 2;
  
  const angle = Math.atan2(distY, distX);
  
  const newPupilX = offsetX + Math.min(maxDistX, Math.max(-maxDistX, Math.cos(angle) * maxDistX));
  const newPupilY = Math.min(maxDistY, Math.max(-maxDistY, Math.sin(angle) * maxDistY));
  
  const svgCTM = eyesSVG.getScreenCTM();
  
  const scaledPupilX = newPupilX / svgCTM.a;
  const scaledPupilY = newPupilY / svgCTM.d;
  
  pupil.setAttribute('transform', `translate(${scaledPupilX}, ${scaledPupilY})`);
}

// Pupil position starts off-centre on the X axis
const calcOffset = () => {
  for (const props of eyes) {
    props.pupil.removeAttribute('transform');
    
    const eyeRect = props.eye.getBoundingClientRect();
    const pupilRect = props.pupil.getBoundingClientRect();
    
    props.offsetX = ((eyeRect.right - pupilRect.right) - (pupilRect.left - eyeRect.left)) / 2;
  }
}

calcOffset();

globalThis.addEventListener('resize', () => { 
  calcOffset(); 
});

let frame = 0;

globalThis.addEventListener('mousemove', (ev) => {
  cancelAnimationFrame(frame);
  frame = requestAnimationFrame(() => { 
    for (const eye of eyes) { 
      updateEye(ev, eye); 
    } 
  });
});

Happy coding!

GooglyEyes #JavaScriptFun #MouseTracking #CSSAnimation #WebDevelopment #FrontendProject #LearnJavaScript #HTMLCSSJS #CreativeCoding #MiniProject