(function() {
    let possibleColors = [
      "#D61C59",
      "#E7D84B",
      "#1B8798",
    ];
    let element = document.body;
  
    let width = window.innerWidth;
    let height = window.innerHeight;
    const cursor = { x: width / 2, y: width / 2 };
    const lastPos = { x: width / 2, y: width / 2 };
    const particles = [];
    const canvImages = [];
    let canvas, context, animationFrame;
  
    const char = "*";
  
    const prefersReducedMotion = window.matchMedia(
      "(prefers-reduced-motion: reduce)"
    );
  
    // Re-initialise or destroy the cursor when the prefers-reduced-motion setting changes
    prefersReducedMotion.onchange = () => {
      if (prefersReducedMotion.matches) {
        destroy();
      } else {
        init();
      }
    };
  
    function init() {
      // Don't show the cursor trail if the user has prefers-reduced-motion enabled
      if (prefersReducedMotion.matches) {
        console.log(
          "This browser has prefers reduced motion turned on, so the cursor did not init"
        );
        return false;
      }
  
      canvas = document.createElement("canvas");
      context = canvas.getContext("2d");
      canvas.style.top = "0px";
      canvas.style.left = "0px";
      canvas.style.pointerEvents = "none";
  
        canvas.style.position = "fixed";
        element.appendChild(canvas);
        canvas.width = width;
        canvas.height = height;
  
      context.font = "21px serif";
      context.textBaseline = "middle";
      context.textAlign = "center";
  
      possibleColors.forEach((color) => {
        let measurements = context.measureText(char);
        let bgCanvas = document.createElement("canvas");
        let bgContext = bgCanvas.getContext("2d");
  
        bgCanvas.width = measurements.width;
        bgCanvas.height =
          measurements.actualBoundingBoxAscent +
          measurements.actualBoundingBoxDescent;
  
        bgContext.fillStyle = color;
        bgContext.textAlign = "center";
        bgContext.font = "21px serif";
        bgContext.textBaseline = "middle";
        bgContext.fillText(
          char,
          bgCanvas.width / 2,
          measurements.actualBoundingBoxAscent
        );
  
        canvImages.push(bgCanvas);
      });
  
      bindEvents();
      loop();
    }
  
    // Bind events that are needed
    function bindEvents() {
      element.addEventListener("mousemove", onMouseMove);
      element.addEventListener("touchmove", onTouchMove, { passive: true });
      element.addEventListener("touchstart", onTouchMove, { passive: true });
      window.addEventListener("resize", onWindowResize);
    }
  
    function onWindowResize(e) {
      width = window.innerWidth;
      height = window.innerHeight;
  
        canvas.width = width;
        canvas.height = height;
    }
  
    function onTouchMove(e) {
      if (e.touches.length > 0) {
        for (let i = 0; i < e.touches.length; i++) {
          addParticle(
            e.touches[i].clientX,
            e.touches[i].clientY,
            canvImages[Math.floor(Math.random() * canvImages.length)]
          );
        }
      }
    }
  
    function onMouseMove(e) {
      window.requestAnimationFrame(() => {
          cursor.x = e.clientX;
          cursor.y = e.clientY;

        const distBetweenPoints = Math.hypot(
          cursor.x - lastPos.x,
          cursor.y - lastPos.y
        );
  
        if (distBetweenPoints > 1.5) {
          addParticle(
            cursor.x,
            cursor.y,
            canvImages[Math.floor(Math.random() * possibleColors.length)]
          );
  
          lastPos.x = cursor.x;
          lastPos.y = cursor.y;
        }
      });
    }
  
    function addParticle(x, y, color) {
      particles.push(new Particle(x, y, color));
    }
  
    function updateParticles() {
      if (particles.length == 0) {
        return;
      }
  
      context.clearRect(0, 0, width, height);
  
      // Update
      for (let i = 0; i < particles.length; i++) {
        particles[i].update(context);
      }
  
      // Remove dead particles
      for (let i = particles.length - 1; i >= 0; i--) {
        if (particles[i].lifeSpan < 0) {
          particles.splice(i, 1);
        }
      }
  
      if (particles.length == 0) {
        context.clearRect(0, 0, width, height);
      }
    }
  
    function loop() {
      updateParticles();
      animationFrame = requestAnimationFrame(loop);
    }
  
    function destroy() {
      canvas.remove();
      cancelAnimationFrame(animationFrame);
      element.removeEventListener("mousemove", onMouseMove);
      element.removeEventListener("touchmove", onTouchMove);
      element.removeEventListener("touchstart", onTouchMove);
      window.addEventListener("resize", onWindowResize);
    };
  
    function Particle(x, y, canvasItem) {
      const lifeSpan = Math.floor(Math.random() * 30 + 60);
      this.initialLifeSpan = lifeSpan; //
      this.lifeSpan = lifeSpan; //ms
      this.velocity = {
        x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
        y: Math.random() * 0.7 + 0.9,
      };
      this.position = { x: x, y: y };
      this.canv = canvasItem;
  
      this.update = function (context) {
        this.position.x += this.velocity.x;
        this.position.y += this.velocity.y;
        this.lifeSpan--;
  
        this.velocity.y += 0.02;
  
        const scale = Math.max(this.lifeSpan / this.initialLifeSpan, 0);
  
        context.drawImage(
          this.canv,
          this.position.x - (this.canv.width / 2) * scale,
          this.position.y - this.canv.height / 2,
          this.canv.width * scale,
          this.canv.height * scale
        );
      };
    }
  
    init();
  
    return {
      destroy: destroy
    }
  }
)();