View Demo (WebKit only) | Source @ GitHub

I haven’t done much 3D work except some OpenGL a number of years ago at university, so I had forgotten that:

**3D is hardwork!**

In terms of CSS3 3D transformations, its not so much that the actual CSS is any more difficult, its just that when you’re performing 3D rotations you very quickly lose track of important things such as orientation. Because of this, I decided to experiment with a 3D CSS cube that could be rotated via user input. For those that want to just dive in and look at the code, its available now on GitHub or take a look at the demo (WebKit only).

As a starting point, take a look at Paul Hayes very cool demo of a 3D cube. This is essentially what I wanted to create *but* it very elegantly highlights some of the difficulties with 3D work.

Try rotating the cube with the arrow keys, does the cube always rotate in the way you’d expect? If you’re anything like me it didn’t, I expect that when you press ‘left’ the cube would *always* visually spin left to right etc. But if you first press ‘up’ and then press ‘left’ the cube spins counter-clockwise and doesn’t show you a different cube face.

# Why does this happen?

In Paul’s example the up/down keys have been hardwired to rotate around the x-axis and left/right to the y-axis. This seems logical, given that directly after initialising the cube this will create the correct result. But what is actually happening when the cube is rotated?

The above image shows what happens to the X, Y & Z axis when the user presses ‘up’. As you can see, after the first rotation the z-axis is now where the y-axis was. So for future rotations, in order to rotate the cube horizontally we need to rotate around the z-axis, instead of the y-axis. This is why you get the perculiar behaviour in Paul’s demo.

# How do we work around this?

To work around this we need to delve a little deeper into the Javascript implementation of 3D transforms and forgo some of the neat helper functions like `rotateX(deg)`

and `rotateY(deg)`

.

The initial assumption that for vertical rotations we want to rotate around X and for horizontal around Y is fundementally correct, its just we need to keep track of where these axes are after rotations are applied to the DOM.

To do this we can make use of the transformation matrix. For more information of matrices there is quite a good explanation with a focus towards CSS3 here.

In a WebKit based browser we can get the the current matrix for an element like this *(using jQuery or Zepto frameworks for convenience)*:

```
var div = $('div#test');
var m = new WebKitCSSMatrix(div.css('webkitTransform'));
```

What we really need to understand about the matrix is that it defines the various transformations applied to our DOM elements, be they translates, rotations or scales. That is, the matrix tells us how to convert a point from its default position to where it currently is in 3D space given the current rotation.

With this knowledge what we need to do is use the matrix to work out where the original X and Y axis are currently situated. Each of the axes are actually just vectors describing a direction in 3D space, so can be described by:

```
x-axis => (1, 0, 0)
y-axis => (0, 1, 0)
```

In order to translate these vectors using the current transform matrix we need to perform some matrix maths. See here for a more detailed explaination of multiplying a matrix by a vector, or you can just trust that the following is true:

Thats great in theory but how do we do that in Javascript? Start by creating a helper `Vector`

object:

```
var Vector = function(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
```

We then need a way to enable matrix/vector multiplications, I decided to extend the `WebKitCSSMatrix`

object here and add a helper function to do this:

```
WebKitCSSMatrix.prototype.transformVector = function(v) {
var xOut = this.m11*v.x + this.m12*v.y + this.m13*v.z;
var yOut = this.m21*v.x + this.m22*v.y + this.m23*v.z;
var zOut = this.m31*v.x + this.m32*v.y + this.m33*v.z;
return new Vector(xOut, yOut, zOut);
};
```

With the `Vector`

helper object and the `transformVector()`

function we can now work out the correct vector to rotate around:

```
// Rotate 90 degrees around the original x-axis
var xAxis = new Vector(1, 0, 0);
var angle = 90;
// Get the current Matrix
var currentMatrix = new WebKitCSSMatrix(div.css('webkitTransform'));
// Work out what the vector looks like under the current Matrix
var xAxisTranslated = currentMatrix.transformVector(xAxis);
```

With the new x-axis vector we can now use the built in `rotateAxisAngle()`

function of the `WebKitCSSMatrix`

object to perform the rotation:

```
// Rotate the Matrix around the transformed vector
var newMatrix = m.rotateAxisAngle(xAxisTranslated.x, xAxisTranslated.y, xAxisTranslated.z, angle);
```

At this point we’ve worked out the new matrix of the DOM element so we just need to update the element with the new matrix:

```
// Setup CSS Transitions
div.css({
'-webkit-transition-duration': '400ms',
'-webkit-transition-timing-function': 'linear',
'transition-property': 'all',
});
setTimeout(function(){
div.get(0).style.webkitTransform = newMatrix;
}, 5);
```

If you want to have a play with this code for yourself then you can grab it from GitHub.

Pingback: Дайджест недели, 13 мая | Софт Буум

Pingback: 20 Stunning Examples CSS 3d Transforms | O2 Interactive

Pingback: CSS3 technology in action: Design examples | TechRepublic

Pingback: Amazing CSS 3D Animation Tutorials : Daily Syntax

Pingback: GNC Designstudio

Pingback: Continuing Da Cube | Erti Ori Sami

Pingback: 20 exemplos extraordinários de CSS 3D « wiliamluis

Pingback: 20 stunning examples of CSS 3D transforms » Web Design & Web Development: HTML, CSS, JQUERY, PHP

Pingback: 30 Amazing running 3D effect with CSS3 & HTML5 - Magazinein

Pingback: Building the WWW with CSS | Being Online