JSFiddle - React, Tailwind, and code Playground

by dart_eugenius

HTML

<div id="elem">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="172.233 108.423 154.767 296.165"
	 enable-background="new 172.233 108.423 154.767 296.165">
<g transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)">
	<path d="M2222.002,3910c-105-15-223.003-47.998-301.001-85c-86.001-41.001-192.002-115-188.003-131.001
		c1.001-6.997,72.002-87.998,156.001-181.001l155-170l52.002,42.002c78.999,65,162.998,90,298.999,90
		c100,0,115.996-2.998,172.998-28.999c105-48.003,152.002-123.999,137.998-221.001C2690,3122.001,2602.002,3067.998,2300,2975
		c-235-72.002-341.001-125-430-215c-113.999-115-157.002-242.002-146.001-430c11.001-197.998,61.001-317.002,190-445
		c153.999-152.998,358.999-225,638.999-225c266.006,0,491.006,77.998,674.004,232.998l42.998,35l-167.002,185l-167.998,185
		l-52.002-52.002c-102.998-103.994-227.998-150-386.997-143.994c-91.001,2.998-108.999,7.002-170,37.002
		c-107.002,51.992-152.002,135-126.001,230c27.002,100,117.998,156.997,405,250.996c225,73.999,345,132.998,427.002,207.998
		c113.994,106.001,155.996,195,165,352.002c25,422.002-292.998,721.001-782.002,735C2343.999,3917.001,2257.002,3915,2222.002,3910z
		"/>
	<path d="M2390,1465c-25-7.998-65-30.996-88.999-52.002c-142.002-120.996-113.999-347.002,53.999-435.996
		c57.002-31.006,172.998-30,230.996,0c96.006,50.996,145,132.002,145,237.002c0,76.992-18.994,127.998-68.994,178.994
		C2589.004,1469.004,2486.001,1495.996,2390,1465z"/>
</g>
</svg>
</div>

CSS

#elem {
    width: 80px;
    margin: 100px auto 0;
}
#elem svg{
    width: 100%;
}

@-webkit-keyframes flipLeft {
  0% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 45deg);
    transform: perspective(400px) rotate3d(0, 1, 0, 45deg);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }

  40% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }

  60% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
  }

  80% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
  }

  100% {
    -webkit-transform: perspective(400px);
    transform: perspective(400px);
  }
}

@keyframes flipLeft {
  0% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 45deg);
    transform: perspective(400px) rotate3d(0, 1, 0, 45deg);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }

  40% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
    -webkit-animation-timing-function: ease-in;
    animation-timing-function: ease-in;
  }

  60% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
  }

  80% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
  }

  100% {
    -webkit-transform: perspective(400px);
    transform: perspective(400px);
  }
}

@-webkit-keyframes flipRight {
  0% {
    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -45deg);
    transform: perspective(400px) rotate3d(0, 1, 0, -45deg);
   ...

JavaScript

var $elem = $('#elem'),
    rect    = $elem[0].getBoundingClientRect()
    timerId = null;
    timeStamp = 0, x = 0,
    blocked = false,
    transform = 'rotateY({d}deg)';
    run = function(velocity){
        var abs = Math.abs(velocity)
        if(abs < .1) return;
        if(abs < 1) {
            if(velocity > 0) {
                $elem.addClass('flipLeft');
            } else {
                $elem.addClass('flipRight');
            }
            setTimeout(function(){
                clearTimeout(timerId);
                $elem.removeClass('flipLeft flipRight');
            }, 1200); // animations duration + 200
        } else {
            $elem.addClass('rotate');
            $elem.css({
                '-webkit-transform': transform.replace('{d}', parseInt(velocity,10) * 360),
                'transform': transform.replace('{d}', parseInt(velocity,10) * 360)
            });
            if(abs > 2) {
                $elem.css({
                    '-webkit-transition-duration': abs *.66 + 's',
                    'transition-duration': abs *.66 + 's',
                });
            }
            setTimeout(function(){
                clearTimeout(timerId);
                $elem.removeClass('rotate');
                $elem.removeAttr('style');
            }, abs > 2 ? abs *.66 * 1000 + 200 : 1200);
        }
    }

$elem.on('mouseenter',function (e) {
    x = e.clientX - rect.left;
    timeStamp = e.timeStamp || Date.now();
})
    
$elem.on('mousemove',function (e) {
    timeStamp = timeStamp || Date.now();
    time = e.timeStamp - timeStamp;
    distance = e.clientX - rect.left - x;
    clearTimeout(timerId);
    timerId = setTimeout(function(){
        run(distance/time);
        timeStamp = 0;
    }, 200);
});
$elem.on('mouseleave',function (e) {
    var distance = e.clientX - rect.left - x;
    var time = e.timeStamp? e.timeStamp - timeStamp : Date.now() - timeStamp;
    run(distance/time);
    clearTimeout(timerId);
    timeStamp = 0;
    x = 0;
});