<!-- Uses perspective. Won't work in Safari (yet) -->
<div id="eye"></div>
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400);

html, body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  overflow: hidden;
}

body {
  background: #261A06;
  perspective: 1500px;
  perspective-origin: 60% 10%;
  font: 400 normal 100%/1.1 "Open Sans", sans-serif; 
}

article {
  position: absolute;
  transform-style:preserve-3d;
  transform: rotateX(-0deg) rotateY(0deg);

  width:10px;
  height:10px;
  border-radius: 5px;        
  background: red;
}

section {
  transform-style:preserve-3d;
  position: absolute;
  width:200px;
  height:1px;
  background: #fffcfc;
  box-shadow: 0 0 1.5px 0px #fffcfc;
  transform-origin: 0 50%;
}

figure {
  margin: 0;
  box-sizing: border-box;
  position: absolute;

  background: lightseagreen;
  box-shadow: 0 0 12px 2px lightseagreen;
  opacity: 0.4;
  filter: blur(2px);
  border-radius:6px;
}
#eye {
  width:40px;
  height:40px;
  position:absolute;
  border-radius: 40px;
  border:10px rgba(255,0,0,0.5) solid;
  margin-left: -20px;
  margin-top: -20px;
}
#eye:after{
  position: absolute;
  top:60px;
  width:140px;
  text-transform: uppercase;
  margin-left: -45px;
  color: white;
  content:'FEAR';
}
aside {
  position: absolute;
  width:200px;
  margin: 2em;
  color: snow;
}
// potatoDie heuristic programming

var w, h, pov;

window.onload = function () {

  w = window.innerWidth,
    h = window.innerHeight;

  var box = new Box(w/4, w/6, w/7, {x:w/2, y:h/2, z: 0});

  // Drag the child through the plane of its parent
  Draggable.create(document.getElementsByTagName('figure'), 
                   {
    type: 'x',
    onDragStart: function(event) {
      this.draggedSide = this.target.parentElement.className;
      this.lastX = this.x;
    },
    onDrag: function(event) {
      console.log ( this.x )
      var dx = this.x - this.lastX;
      box.update(this.draggedSide, dx);
      box.draw();

      this.lastX = this.x;
    }
  });

  // Put the eye at the perspective origin
  var po = window.getComputedStyle(document.body)['perspective-origin'].split(' ');
  var eye = document.querySelector('#eye');
  eye.style.left = po[0];
  eye.style.top = po[1];
  Draggable.create(eye, 
                   {
    onDragStart: function() {
      // document.body.style.background = "red";
    },
    onDrag: function(event) {
      document.body.style['perspective-origin'] = event.clientX + "px " + event.clientY + "px";
    }
  });
}

var Box = function(w, h, d, pos) {
  this.width = w;
  this.height = h;
  this.depth = d;
  this.position = pos;

  this.sides = this.designSides();

  this.addBoxToDom();
}

// All sides are first rotated 45deg around Y, to prevent having any normal ending up at right angles within its coordinate system's XY plane
Box.prototype.preRotate = 45;       

Box.prototype.designSides = function() {
  return {
    front:  {
      distance: this.depth/2,
      rotate: "rotateY(-90deg)",
      width: this.width,
      height: this.height
    },
    back:   {
      distance: this.depth/2,
      rotate: "rotateY(90deg)",
      width: this.width,
      height: this.height
    },
    right:  {
      distance: this.width/2,
      rotate: "rotateY(0deg)",
      width: this.depth,
      height: this.height
    },
    left:   {
      distance: this.width/2,
      rotate: "rotateY(180deg)",
      width: this.depth,
      height: this.height
    },
    top:    {
      distance: this.height/2,
      rotate: "rotateZ(-90deg)",
      width: this.depth,
      height: this.width
    },
    bottom: {
      distance: this.height/2,
      rotate: "rotateZ(90deg)",
      width: this.depth,
      height: this.width
    }
  };
};

/**
       * adds box to DOM and draws it based on model
       */
Box.prototype.addBoxToDom = function() {
  // The dombox is a container of 6 sides
  var dombox = document.createElement('article');
  dombox.className = "box";
  dombox.style.transform =
    "translate3d("+this.position.x + "px, " + this.position.y + "px, " + this.position.z + "px)";

  for ( var d in this.sides ) {
    // console.log ( d, this.sides[d], this.sides[d].transform )
    var sd = this.sides[d];

    var normalElem = document.createElement('section');
    normalElem.className = d;
    normalElem.style.transform = 
      "rotateY(" + this.preRotate + "deg) " +
      sd.rotate +
      "translateX(" + sd.distance + "px)";

    var face = document.createElement('figure');

    face.style.width = sd.width + "px";
    face.style.height = sd.height + "px";

    // Set all sides perpendicular to the normal (parent element).
    // Then translate along the normal, so it ends up at the box center and
    // the normal is sticking out in front
    face.style.transform = 
      "rotateY(90deg) " +
      "translateZ(" + (-sd.width/2) + "px) " +
      "translateY(" + (-sd.height/2) + "px)";

    normalElem.appendChild(face);
    dombox.appendChild(normalElem);

    // Store references for updating lateron
    this.sides[d].$normal = normalElem;
    this.sides[d].$face = face;
  }

  document.body.appendChild(dombox);
  this.dombox = dombox;
}

/**
       * Redraws the sides of the box, based on model data
       * Also repositions the box
       */
Box.prototype.draw = function(){
  var dombox = document.querySelector('.box');

  dombox.style.transform =
    "translate3d("+this.position.x + "px, " + this.position.y + "px, " + this.position.z + "px)";        
  var sides = this.sides;
  var preRotate = this.preRotate;

  drawFace('front', this.width, this.height, this.depth);
  drawFace('back', this.width, this.height, this.depth);
  drawFace('top', this.depth, this.width, this.height);
  drawFace('bottom', this.depth, this.width, this.height);
  drawFace('left', this.depth, this.height, this.width);
  drawFace('right', this.depth, this.height, this.width);


  function drawFace ( face, w, h, d) {
    var style = sides[face].$face.style;
    style.width = w + "px";
    style.height = h + "px";

    style.transform = 
      "rotateY(90deg) " +
      "translateZ(" + (-w/2) + "px) " + // repares displacement in local X after rotate 
      "translateY(" + (-h/2) + "px)";

    sides[face].$normal.style.transform = 
      "rotateY(" + preRotate + "deg) " +
      sides[face].rotate +
      "translateX(" + d/2 + "px)";                        
  }
}

/**
       * updates the model
       * @param  {[type]} side_label [description]
       * @param  {float} d          distance of drag
       */
var sin = Math.sin(Math.PI/4);
Box.prototype.update = function(side_label, d){
  // Why the factor 2???
  switch ( side_label ) {
    case 'front':
      this.depth += 2*d;
      this.position.x += sin * d;
      this.position.z += sin * d;
      break;
    case 'left':
      this.width += 2*d;
      this.position.x += (-sin * d);
      this.position.z += (sin * d);
      break;
    case 'top':
      this.height += 2*d;
      this.position.y -= d;
      break;            
    case 'bottom':
      this.height += 2*d;
      this.position.y += d;
      break;             
  }
}    

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/gsap/1.14.2/TweenMax.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.5/utils/Draggable.min.js