How can I make the side elements spin on the x-axis in this animation?


Tags: javascript,css3,animation,greensock,tweenlite

Problem :

I'm trying to build a rotating cube animation whose sides also rotate on their respective axis. Here's what I have so far:

http://codepen.io/Chevex/pen/pxtwj

The following CSS rules govern the position of the sides before each animation:

.front {
  transform: translateZ(100px);
  background-color: #0f0;
}
.back {
  transform: rotateY(180deg) translateZ(100px);
  background-color: #f00;
}
.right {
  transform: rotateY(90deg) translateZ(100px);
  background-color: #00f;
}
.left {
  transform: rotateY(-90deg) translateZ(100px);
  background-color: #ff0;
}
.top {
  transform: rotateX(90deg) translateZ(100px);
  background-color: #0ff;
}
.bottom {
  transform: rotateX(-90deg) translateZ(100px);
  background-color: #f0f;
}

This works great and positions the elements accordingly. Next I use the GSAP animation library to rotate the entire cube:

TweenMax.to($('.cube'), 7, { rotationY: 360, repeat: -1, ease: Linear.easeNone });

After that I animate the front and back sides so they spin in relation to the Z axis:

TweenMax.to($('.front, .back'), 2, { rotationZ: 360, repeat: -1, ease: Linear.easeNone });

Next the top and bottom on the Y axis:

TweenMax.to($('.top, .bottom'), 2, { rotationY: 360, repeat: -1, ease: Linear.easeNone });

So far so good. Now the left and right sides need to rotate on the X axis:

TweenMax.to($('.right, .left'), 2, { rotationX: 360, repeat: -1, ease: Linear.easeNone });

Now there is a problem. For some reason they appear to be rotating on the Z axis. I've tried rotating them on all 3 axis but they never appear to spin like a rolling coin the way the other sides did just fine. I thought it was a GSAP bug but I applied the following CSS animations to those sides manually and the same issue exists.

.right {
  transform: rotateY(90deg) translateZ(100px);
  background-color: #00f;
  -webkit-animation: spinRight 2s linear infinite;
}
.left {
  transform: rotateY(-90deg) translateZ(100px);
  background-color: #ff0;
  -webkit-animation: spinLeft 2s linear infinite;
}

@-webkit-keyframes spinRight {
  from {
    transform: rotateY(90deg) translateZ(100px) rotateX(0deg);
  }
  to {
    transform: rotateY(90deg) translateZ(100px) rotateX(360deg);
  }
}

@-webkit-keyframes spinLeft {
  from {
    transform: rotateY(-90deg) translateZ(100px) rotateX(0deg);
  }
  to {
    transform: rotateY(-90deg) translateZ(100px) rotateX(360deg);
  }
}

Any ideas why this is? How can I get the left and right sides of the cube to rotate the way all the others are rotating?



Solution :

Yes, you are gimbal locked, the rotateX value needs to be placed before the rotateY. Order is important for transforms.

What happens in your case is that the 90 degree (positive or negative) Y rotations rotate the X-axis into the Z (or -Z-axis). Usually when you have all 3, ordering X, Y, and Z will keep things straight for X, but Z will gimbal lock when Y is +/- 90 or 270. By putting X after the Y, you are rotating it into the Z axis (in that ordering it is 'inside' the Y-axis).

Try this:

@-webkit-keyframes spinRight {
  from {
    transform: rotateX(0deg) rotateY(90deg) translateZ(100px);
  }
  to {
    transform: rotateX(360deg) rotateY(90deg) translateZ(100px);
  }
}

@-webkit-keyframes spinLeft {
  from {
    transform: rotateX(0deg) rotateY(-90deg) translateZ(100px);
  }
  to {
    transform: rotateX(360deg) rotateY(-90deg) translateZ(100px);
  }
}

If this does not do the trick, try nesting a div and rotating that div's Z-axis. CSS has a limited 3d ability as gimbal lock is a huge problem. Also, the rotate3d is limited due to the 360 degree periods of sine and cosine waves (has to do with the maths determining the matrix). For matrix maths Sylvester works, or you can check out three.js which has its own features to deal with said limitations (I believe Google used three for its Rubik's cube doodle).


Edit from question author:

This answer was correct. The Greensock folks wanted me to nest my side elements in parent elements and modify the axis of the parent. That may have worked but my initial attempts were just causing other issues. After reading up a bit on Gimbal Lock I realized that it's the way the axis are being modified that causes the locking. I had an idea to get to the same position, but by manipulating the axis in a different way. It worked and this is the result:

http://codepen.io/Chevex/pen/pxtwj

Instead of:

TweenMax.set('.right', { rotationY: 90, x: '100px' });
TweenMax.set('.left', { rotationY: -90, x: '100px' });

I sat down and followed the axis in my head and came up with a new path to get the element to the same place.

TweenMax.set('.right', { rotationZ: 90, rotationY: 90, rotationX: 90, x: '100px' });
TweenMax.set('.left', { rotationZ: -90, rotationY: -90, rotationX: 90, x: '100px' });

After that I was able to animate the Y axis and get the intended result now that the Y axis is pointing the direction I had originally expected the X axis to point.

TweenMax.to('.right, .left', gearSpeed, { rotationY: 360, repeat: -1, ease: Linear.easeNone });

    CSS Howto..

    CSS - How to align divs horizontally?

    how do i remove the tab from this css megamenu

    CSS how to center ::after pseudo elem

    How to Identify which div in a sequence with the same class was clicked

    How do I change background color of li elements

    How to position an element just off the top of the browser viewport using only css?

    How can i see or how do i know where to put the control according to the screen when using css?

    Any Idea how this web site acheives a fluid/liquid layout [closed]

    How to highlight the menu item for the sort type of data on the page?

    How do I float 3 elements right above each other and one left?

    How to fast-blur in css/js?

    How to get two column float left div layout to word wrap?

    How to apply CSS styling to elements created by jquery's append()?

    How to override CSS Box Sizing for just one area on page?

    overlaping text with different styles over image, prevent text of one style to be shown on top of the text of another style

    How to transform xPath to CSS Selector

    How do I stop a CSS layout from distorting when zooming in/out?

    How to move menu to the right of the logo and to clean up unused space?

    How to override the default css class using c#

    How to implement CSS file style on selected div

    How to set an Ionic list item height with a background image

    How can I center a CSS background image as if the image had a different width (without cutting the bgimg off)?

    How to change the behavior of the following css button?

    How to parse xmlwebservice in phonegap

    How to dynamicaly change css style?

    How to change size of SVG circle

    How to make css style on Google custom search engine

    how i can change the CSS class on click of an element [closed]

    How to dynamically positioning html table by using css properties?

    How to use a JQuery Show/Hide script, to show hidden text