Eye follow cursor in javascript

Learn how to create eye follow cursor in javascript.

It is a simple project in which we will create an eye which will keep blinking at an interval and the eye will move along the cursor giving us a feel that it is following the cursor.

Eye follow cursor in javascript

By building this project you will learn.

  • HTML:- How to layout to HTML elements to create an eye.
  • CSS:- Use css to create the blink animation.
  • Javascript:- How to get the position of the cursor and move the eye along with it.

I have completed the development in three different stages. In each stage I complete first part and then move to the next.

  1. Create the layout of the eye.
  2. Design the eye and create the blink animation.
  3. Move the eye along with the cursor by listening on the mousemove event.

I assume you now have a good idea about what and how we are going to build it, so let’s start doing it.

HTML layout of eye.

If we think in general terms an eye is composed of three different parts.

  1. A wrapper which contains the eye and eye lashes.
  2. An eye.
  3. Top and bottom eye lashes.

We will also create the layout by placing the elements in such a way.

Wrapper will be created using div and eye and lashes will be created using span.

All these will be placed inside a main tag to contain them and align it on the screen.

<main>
    <div class="eyes">
        <span class="eye-lash up"></span>
        <span class="eye-retina"></span>
        <span class="eye-lash down"></span>
    </div>
    <div class="eyes">
        <span class="eye-lash up"></span>
        <span class="eye-retina"></span>
        <span class="eye-lash down"></span>
    </div>
</main>

Designing the eye and blink animation.

An eye should be able to move freely inside the wrapper and the eye lashes are above the eye. So we have to keep our wrapper relative positioned and the eye and lashes absolute to it.

main {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

/* Wrapper */
.eyes {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  margin: 5px;
  background: #ffeb3b;
  box-shadow: 0 0 3px;
  position: relative;
  overflow: hidden;
}

/* Eye */
.eye-retina {
  display: inline-block;
  width: 50%;
  height: 50%;
  background: red;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

/* lashes */
.eye-lash {
  position: absolute;
  height: 50%;
  background: orange;
  width: 100%;
  z-index: 1;
}

As we want to align both the eyes to the center of the screen we have flexed the main and aligned all its children to center vertically and horizontally.

Now to create the blink effect on the eye-lash. One lash should come from the top and second from the bottom, that is why if you can see we have added to extra classes to the eye-lashes while creating the layout up and down.

The up eye lash we will come from top to center and the bottom one will come from bottom to center and the animation will keep on repeating at given interval.

To give the effect of lashes as closing and opening we have to use a trick while creating the animation. As an animation keyframes work in percentage of time.

In the first 10% of time we close and open the lash by moving from top to center and back to top and then the remaining 90% of time it will remain idle. This will give effect of eye is blinking at intervals.

.up {
  top: -50%;
  animation: blinkbottom 10s linear infinite;
}

.down {
  bottom: -50%;
  animation: blinktop 10s linear infinite;
}

@keyframes blinkbottom {
  0% {
    top: -50%;
  }
  5% {
    top: 0;
  }
  10% {
    top: -50%;
  }
}

@keyframes blinktop {
  0% {
    bottom: -50%;
  }
  5% {
    bottom: 0;
  }
  10% {
    bottom: -50%;
  }
}

Eye following cursor with javascript.

To move the eyes along with the cursor, we have to get the position of the cursor relative to the window in percentage.

Getting the value in percentage will help to move the eye properly inside the wrapper.

To get the cursor position we will have to listen to the mousemove event on the window. so lets do that.

But before doing this, lets pull the eye element using the selector and store it in the variable so that we can use it later.

//Eyes
const retina = document.querySelectorAll(".eye-retina");

window.addEventListener("mousemove", (e) => {
  e = e || window.event;

  //Position of cursor in pixel
  const { pageX, pageY } = e;

  //Available area of window
  const { innerWidth, innerHeight } = window;

  //Cursor left position in percentage
  let left = (pageX / innerWidth) * 100;

  //Cursor top  position in percentage
  let top = (pageY / innerHeight) * 100;

  //Prevent the eye from getting hidden at the left and right end.
  left = left < 25 ? 25 : left;
  left = left > 75 ? 75 : left;

  //Prevent the eye from getting hidden at the top and bottom end.
  top = top < 25 ? 25 : top;
  top = top > 75 ? 75 : top;

  //Move the eye
  retina.forEach((f) => {
    //If the cursor is in center of both the eyes the keep the eye in center
    f.style.left = `${left > 45 && left < 55 ? 50 : left}%`;
    f.style.top = `${top > 45 && top < 55 ? 50 : top}%`;
  });
});

Here if you see we get the cursor position with pageX and pageY in pixel which represents top and left and then calculate the percentage based on the size of the window.

For example suppose cursor is at 837px left and window is 1366px wide then the cursor is 837 / 1366 * 100 = 61.27379209370425% left.

And also we don't our eyes to get hidden when the cursor goes to the extreme left or bottom, that is why if the cursor is beyond certain threshold then we prevent it from moving further.

  //Prevent the eye from getting hidden at the left and right end.
  left = left < 25 ? 25 : left;
  left = left > 75 ? 75 : left;

  //Prevent the eye from getting hidden at the top and bottom end.
  top = top < 25 ? 25 : top;
  top = top > 75 ? 75 : top;

And if the cursor is in the center of both the eyes then keep them in center.

//If the cursor is in center of both the eyes the keep the eye in center
f.style.left = `${left > 45 && left < 55 ? 50 : left}%`;
f.style.top = `${top > 45 && top < 55 ? 50 : top}%`;

I hope 🙏🏻 you have learned something today. If you like the article then do share it with others.