Trendy Image Trail Mouse Follow

In this video we will explore creating a mouse follow trail effect with images. We'll use p5.js for our code and I'll show you how to load it up in Webflow to use as a cool hero section too!

Watch the Tutorial on YouTubeGet the Project Cloneable

Inside <head> tag

<script defer src="https://cdn.jsdelivr.net/npm/p5@1.6.0/lib/p5.js"></script>

Inside </body> tag

<script>
// CONSTANTS
let imageUrls = [
  "https://assets-global.website-files.com/649cd036c3448ae14ea25a03/649cd26dc3448ae14ea35880_pexels-aliakbar-nosrati-15654407.jpg",
  "https://assets-global.website-files.com/649cd036c3448ae14ea25a03/649cd1c740f369d4f54540f4_pexels-godisable-jacob-993868.jpg",
  "https://assets-global.website-files.com/649cd036c3448ae14ea25a03/649cd1ca2cc144816adbe4b7_pexels-konstantin-mishchenko-2010812.jpg",
  "https://assets-global.website-files.com/649cd036c3448ae14ea25a03/649cd1ce12517504410409cf_pexels-andy-coffie-16864841.jpg",
  "https://assets-global.website-files.com/649cd036c3448ae14ea25a03/649cd1ec9f40c0296d9dafbb_pexels-harsh-kushwaha-1689731.jpg",
];
// distance mouse needs to move before next image is shown
let distThreshold = 100;
// scale factor to size images
let scaleFactor = 5;

// VARIABLES
// array to hold all of our images
let images = [];
// array to hold history of mouse positions and image index for that position
let queue = [];
// object containing our last (stored) mouse position
let lastMousePos = { x: 0, y: 0 };
// current image to show
let imgIndex = 0;

// load all of the images from their urls into the images array
function preload() {
  for (let i = 0; i < imageUrls.length; i++) {
    images[i] = loadImage(imageUrls[i]);
  }
}

// setup canvas and store initial mouse position
function setup() {
  let cnv = createCanvas(windowWidth, windowHeight);
  cnv.parent("canvas-parent");
  cnv.style("display", "block");
  cnv.style("position", "absolute");
  cnv.style("inset", "0");
  cnv.style("z-index", "-1");
  lastMousePos = { x: mouseX, y: mouseY };
}

function draw() {
  // clear the canvas
  clear();
  background(0);

  // calculate distance between current mouse position and last stored mouse position.
  let d = dist(mouseX, mouseY, lastMousePos.x, lastMousePos.y);

  // If distance is greater than threshold:
  // 1. Add current mouse position and current image index to the front of the queue
  // 2. Update lastMousePos to current mouse position
  // 3. Update imgIndex to next image index
  if (d > distThreshold) {
    queue.unshift({ x: mouseX, y: mouseY, index: imgIndex });
    lastMousePos = { x: mouseX, y: mouseY };
    imgIndex = (imgIndex + 1) % images.length;
  }

  // maintain queue length equal to number of images by removing the last item
  if (queue.length > images.length) {
    queue.pop();
  }

  // define scale of images based on width of canvas
  let scale = width / scaleFactor;

  // draw images in queue
  // draw order is reversed so that the first image in the queue is drawn on top
  for (let i = queue.length - 1; i >= 0; i--) {
    let img = images[queue[i].index];
    if (img) {
      // scale image based on scale factor
      let imgWidth = (img.width * scale) / img.width;
      let imgHeight = (img.height * scale) / img.width;
      // draw image at mouse position offset by half of image width and height
      image(
        img,
        queue[i].x - imgWidth / 2,
        queue[i].y - imgHeight / 2,
        imgWidth,
        imgHeight
      );
    }
  }
}

// resize canvas when window is resized
function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}
</script>