Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a disney dust style cursor trail

Tags:

javascript

css

I'm trying to make a cursor that leaves a trail of magic dust like in that intro to any Disney film: example. So the way I see it is it's split into two parts. 1. the trail and 2. similar trail that falls and fades out. So far I have made the basic trail work quite well, the code below is for the falling trail and essentially a copy of it with a css animation..

The problem I'm having is it's jittering a lot. I'm guessing the css animation is not great for performance and is causing this to really jitter on my page. I've just read up on requestAnimationFrame but am new to this so not sure how to implement it.. How could I use requestAnimationFrame instead of css here?

I also think creating the animation custom in js would allow there to also be a random offset in the animation of the falling particles.. much more like in the video.

window.addEventListener('mousemove', function (e) {
        //trail
         [1, .9, .8, .5, .25, .6, .4, .3, .2].forEach(function (i) {
      var j = (1 - i) * 50;
      var elem = document.createElement('div');
      var size = Math.ceil(Math.random() * 10 * i) + 'px';
      elem.style.position = 'fixed';
      elem.style.zIndex = 6;
      elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) + 'px';
      elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) + 'px';
      elem.style.width = size;
      elem.style.opacity = "0.5";
      elem.style.height = size;
      elem.style.background = 'hsla(' +
        Math.round(Math.random() * 160) + ', ' +
        '60%, ' +
        '90%, ' +
        i + ')';
      elem.style.borderRadius = size;
      elem.style.pointerEvents = 'none';
      document.body.appendChild(elem);
      
      window.setTimeout(function () {
        document.body.removeChild(elem);
      }, Math.round(Math.random() * i * 1000));

    });

        // falling trail
        [1, .9, .8, .5, .25, .6,  .3, .2].forEach(function (i) {
          var j = (1 - i) * 50;
          var elem = document.createElement('div');
          var size = Math.ceil(Math.random() * 10 * i) + 'px';
          elem.style.position = 'fixed';
          elem.style.zIndex = 6;
          elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) + 'px';
          elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) + 'px';
          elem.style.width = size;
          elem.style.opacity = "0.5";
          elem.style.height = size;
          elem.style.animation = "fallingsparkles 1s";
          elem.style.background = 'hsla(' +
            Math.round(Math.random() * 160) + ', ' +
            '60%, ' +
            '90%, ' +
            i + ')';
          elem.style.borderRadius = size;
          elem.style.pointerEvents = 'none';
          document.body.appendChild(elem);
          
          window.setTimeout(function () {
            document.body.removeChild(elem);
          }, Math.round(Math.random() * i * 1000));

        });
      }, false);
body {
  width:100%;
  height:100%;
  background-color: #000;
}

@keyframes fallingsparkles {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(50px);
  }
}
<body></body>
like image 381
AGrush Avatar asked Oct 01 '20 16:10

AGrush


2 Answers

I'm mostly posting this for others to use, where I refactored the code a bit. Nothing has changed, but it's easier to follow. I will follow up with a real answer.

let trailArr = [1, .9, .8, .5, .25, .6, .4, .3, .2];

function trailAnimation(e, i, callbackFn) {
  var elem = document.createElement('div');

  elem = styleSparkle(elem, e, i);

  if (typeof callbackFn == 'function') {
    elem = callbackFn(elem);    
  }
  
  elem.classList.add("sparkle");

  document.body.appendChild(elem);

  window.setTimeout(function () {
    document.body.removeChild(elem);
  }, Math.round(Math.random() * i * 1000));
}

function styleSparkle(elem, e, i) {
  let j = (1 - i) * 50;
  let size = Math.ceil(Math.random() * 10 * i) + 'px';
  
  elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) + 'px';
  elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) + 'px';
  
  elem.style.width = size;
  elem.style.height = size;
  elem.style.borderRadius = size;
  
  elem.style.background = 'hsla(' +
    Math.round(Math.random() * 160) + ', ' +
    '60%, ' +
    '90%, ' +
    i + ')';
  
  return elem;
}

window.addEventListener('mousemove', function (e) {
  trailArr.forEach((i) => {trailAnimation(e, i)});

  trailArr.forEach((i) => {trailAnimation(e, i, (elem) => {
    elem.style.animation = "fallingsparkles 1s";
    
    return elem;
  })});
}, false);
body {
  width:100%;
  height:100%;
  background-color: #000;
}

.sparkle {
  position: fixed;
  z-index: 6;
  opacity: 0.5;
  pointer-events: none;
}

@keyframes fallingsparkles {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(50px);
  }
}
<body></body>
like image 161
Rickard Elimää Avatar answered Nov 19 '22 05:11

Rickard Elimää


I made another version thats quite fun.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    body {
      width: 100%;
      height: 100%;
      background-color: #000;
    }
    .star-five {
      background: transparent;
      margin: 50px 0;
      position: relative;
      display: block;
      color: #ffffff;
      width: 0px;
      height: 0px;
      border-right: 100px solid transparent;
      border-bottom: 70px solid #ffffff;
      border-left: 100px solid transparent;
      /* transform: rotate(35deg) scale(0.1) translate(-1450px, -250px); */
    }
    .star-five:before {
      border-bottom: 80px solid #ffffff;
      border-left: 30px solid transparent;
      border-right: 30px solid transparent;
      background-color: transparent;
      position: absolute;
      height: 0;
      width: 0;
      top: -45px;
      left: -65px;
      display: block;
      content: '';
      transform: rotate(-35deg);
    }
    .star-five:after {
      background-color: transparent;
      position: absolute;
      display: block;
      color: #ffffff;
      top: 3px;
      left: -105px;
      width: 0px;
      height: 0px;
      border-right: 100px solid transparent;
      border-bottom: 70px solid #ffffff;
      border-left: 100px solid transparent;
      transform: rotate(-70deg);
      content: '';
    }
  </style>
</head>

<body>


<script>
  window.addEventListener('mousemove', function (e) {
    //trail
    [.7, .9, .8, .5, .25, .6, .4, .3, .2].forEach(function (i) {
      var j = (1 - i) * 50;
      var elem = document.createElement('div');
      var size = Math.ceil(Math.random() * 10 * i) + 'px';

      //ramdom number between 0 and 1
      var precision = 50; // 2 decimals
      var randomnum = Math.floor(Math.random() * (10 * precision - 1 * precision) + 1 * precision) / (1*precision);   
      var rOpacity = randomnum/10;
      var rSize = randomnum/120;

      elem.style.position = 'fixed';
      elem.classList.add('star-five')
      elem.style.zIndex = 6;
      elem.style.transform = `rotate(35deg) scale(${rSize})`
      //elem.style.transform = `rotate(35deg) scale(${rSize}) translate(-1450px, -250px)`
      elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) - 100 + 'px';
      elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) - 100 + 'px';
      //elem.style.width = size;
      //console.log(rSize);
      elem.style.opacity = rOpacity;
      //elem.style.height = size;
      // elem.style.background = 'hsla(' +
      //   Math.round(Math.random() * 160) + ', ' +
      //   '60%, ' +
      //   '100%, ' +
      //   i + ')';
      //elem.style.borderRadius = size;
      elem.style.pointerEvents = 'none';
      document.body.appendChild(elem);
      window.setTimeout(function () {
        document.body.removeChild(elem);
      }, Math.round(Math.random() * i * 1000));
    });
    ////
    
  }, false);
</script>

</body>

</html>
like image 3
AGrush Avatar answered Nov 19 '22 04:11

AGrush