JSFiddle - React, Tailwind, and code Playground

by Michael Prosser

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="debug"></div>
<div class="viewport">
  <div class="vrhand">
    <div class="palm"></div>
    <div class="finger finger-0">
      <div class="nuckle-1">
        <div class="nuckle-2"></div>
      </div>
    </div>
    <div class="finger finger-1">
      <div class="nuckle-1">
        <div class="nuckle-2"></div>
      </div>
    </div>
    <div class="finger finger-2">
      <div class="nuckle-1">
        <div class="nuckle-2"></div>
      </div>
    </div>
    <div class="finger finger-3">
      <div class="nuckle-1">
        <div class="nuckle-2"></div>
      </div>
    </div>
    <div class="finger finger-4">
      <div class="nuckle-1">
        <div class="nuckle-2"></div>
      </div>
    </div>
  </div>
</div>

CSS

html{
  height:100%;
}
body{
  height:100%;
  margin:0px;
  perspective:500px;
  position:relative;
  
  /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#7d7e7d+0,0e0e0e+100;Black+3D */
background: #7d7e7d; /* Old browsers */


}
.debug{
  position:fixed;
  left:0px;
  top:0px;
  color:#fff;
  font-family:helvetica;
  padding:8px;
  font-size:12px;
}

.viewport{
  position:fixed;
  top:0px;
  left:0px;
  right:0px;
  bottom:0px;
}
.vrhand{
  display:none;
  transform-style:preserve-3d;
  position:absolute;
  left:100px;
  top:120px;
  width:0px;
  height:0px;
  transform-origin:10% 10%;
  transition:all .1s;
}
.vrhand div{
  transform-style:preserve-3d;
  position:absolute;
  transition: all .5s;
}
.vrhand div:before{
  content:"";
  display:block;
  position:absolute;
  width:100%;
  height:100%;
  background-image:inherit;
  background-size:inherit;
  background-position:inherit;
  background-color:#000;
  transform:translateZ(-6px);
  border-radius:inherit;
}
.vrhand>.finger-0{
  left:-160px;
  top:80px;
  margin:0px !important;
  transform-origin:100% 100%;
  transform:rotateX(0deg) rotateY(-30deg) translateX(-20px) translateZ(-5px) rotateZ(-10deg);
  border-bottom-right-radius: 0% !important;
  border-bottom-left-radius: 90% !important;
}
.vrhand .finger-1{
  transform: rotateX(8deg) scaleX(1) scaleY(1) scaleZ(1);
}
.vrhand .finger-2{
  transform: rotateX(5deg) scaleX(1.1) scaleY(1.1) scaleZ(1.1);
}
.vrhand .finger-3{
  transform: rotateX(10deg) scaleX(1.05) scaleY(1.05) scaleZ(1.05);
}
.vrhand .finger-4{
  transform: rotateX(18deg) scaleX(.7) scaleY(.7) scaleZ(.7);
}
.vrhand .finger-0 .nuckle-1{
  transform: rotateX(10deg);
}
.vrhand .finger-1 .nuckle-1{
  transform: rotateX(13deg);
}
.vrhand .finger-2 .nuckle-1{
  transform: rotateX(15deg);
}
.vrhand .finger-3 .nuckle-1{
  transform: rotateX(14deg);
}
.vrhand .finger-4 .nuckle-1{
  transform: rotateX(10deg);
}

.vrhand>.finger-1{
 ...

JavaScript

var vrhand = {
	
  x: 0,
  y:0,
  
  status: 'off',
  side: 'right', // defaults to right hand
  hand_pose: 'open',
  hand_poses: Array('open', 'close', 'point'),
  
  // selector
  hand: $('.vrhand'),
  viewport: $('.viewport'),
  
  width: $('.viewport').width(),
  height: $('.viewport').height(),
  
  axis_x: 0,
  axis_y: 0,
  
  z_offset: 100,
  
  pose: function(handpose){
  
  	for(var i=0;i<vrhand.hand_poses;i++){
    
    	vrhand.hand.removeClass(vrhand.hand_poses[i]);
    
    }
    
    vrhand.hand.addClass(handpose);
  
  },
  toggle: function(){
  
  	if(vrhand.status == 'on'){
    
    	vrhand.status = 'off';
      vrhand.hand.hide();
      vrhand.viewport.css('cursor','auto');

    } else {
    
    	vrhand.status = 'on';
    	vrhand.hand.show();
      vrhand.viewport.css('cursor','none');
      
    }
  
  
  },
  update: function(){
  
  	vrhand.axis_x = vrhand.x - (vrhand.width/2);
    vrhand.axis_y = vrhand.y - (vrhand.width/2);
      
    $('.debug').text('x:' + vrhand.x + ' y:' + vrhand.y);
      
    var z = ((Math.abs(vrhand.axis_x)/10)-(Math.abs(vrhand.axis_y)/10))+vrhand.z_offset;
      
    if(vrhand.down){
      
    	 z-=20;
      
    }
    
    if(vrhand.side == 'left'){
    
    	var scale = ' scaleX(-1)';
    
    } else {
    
    	var scale = '';
    
    }
      
      vrhand.hand.css('transform','translateX(' + vrhand.x + 'px) translateY(' + (vrhand.y) + 'px) translateZ(' + z + 'px) rotateY(' + (vrhand.axis_x/20) + 'deg) rotateX(' + ((vrhand.axis_y/20)*-1) + 'deg)' + scale);
      
      requestAnimationFrame(vrhand.update);
  
  },
  
  init: function(){
  
  	vrhand.hand = $('.vrhand');
    vrhand.viewport = $('.viewport');
    
    vrhand.width = $('.viewport').width();
    vrhand.height = $('.viewport').height();
    
    $(document).mousemove(function(e){
    
    	vrhand.x = e.clientX;
    	vrhand.y = e.clientY;
    
    
    }).mousedown(function(e){
    
    	vrhand.down = true;
    	vrhand.hand.addClass('close');
    
 ...