Monday, December 17th, 2007

3D-style animation in JavaScript

Category: JavaScript

Joonas Lehtinen of IT Mill has shown us something that we should probably never do. As a proof of concept he decided to see if it was “possible to do a 3D-style animation in plain JavaScript without Flash, SVG, Canvas or any other fancy stuff.”

He ended up with a solution that:

  • Slice a image in 1px wide slices
  • Embed all the slides in the HTML using data-uris to avoid loading large number of images
  • Move and scale image slices for each animation frame to create some nice effect

So, first you litter your HTML with:

  1. <img id="slice-0" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABACAIAAABUc4oXAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAAewwAAHsMBvJeX2gAAACFJREFUCNdj+P//PxMDAwPd8INH75nw2Mnw/ftvBjq6CQDNIw8MeLLR3AAAAABJRU5ErkJggg=="/>
  2. <img id="slice-1" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABACAIAAABUc4oXAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlvRkZzAAAAAQAAAAAAEXZlawAAAAlwSFlzAAAewwAAHsMBvJeX2gAAAEpJREFUCNdj+P//PxMDAwNN8PsP35lOnn3MdOzUQ6brN18xvXrzlenJs49M+OwUE+Vh4uZiZbI2V2DSUBVluHPvDcO/f/8YaOROAMXBIDUsb8h5AAAAAElFTkSuQmCC"/>

and then you put them all together via JavaScript:

javascript

  1. // Draw a frame
  2.     function draw(x) {
  3.         var prevx=0;
  4.         for (i=0;i&lt;384;i++) {
  5.             var rad = i*3.14/384;
  6.             var nextx = Math.round((1-Math.cos(rad))*180);
  7.             var h=Math.round(40+50*Math.sin(rad));
  8.             var s = document.getElementById("slice-"+((i+x*2)%384));
  9.             s.height=h;
  10.             var w = Math.round(nextx-prevx);
  11.             if (w==0) {
  12.                 s.style.display="none";
  13.             } else {       
  14.                 s.style.display="block";
  15.                 s.width= w;
  16.                 s.style.top=""+(50-Math.round(h/1.5))+"px";
  17.                 s.style.left=""+(prevx)+"px";
  18.             }
  19.             prevx=nextx;
  20.         }
  21.     }
  22.    
  23.     // Animate the images
  24.     var frame=0;
  25.     function animate() {
  26.         draw(frame++);
  27.         setTimeout("animate()",1);
  28.     }
  29.  
  30.     // Initialize the image slices
  31.     for (i=0;i&lt;384;i++) {
  32.         var s = document.getElementById("slice-"+i);
  33.         s.style.position="absolute";
  34.         s.style.display="none";
  35.     }
  36.     animate();

Then sit and watch the animation.

jsanimate

Posted by Dion Almaer at 5:23 am
9 Comments

++---
2.8 rating from 69 votes

9 Comments »

Comments feed TrackBack URI

Listen to that CPU fan roar! 8-)

Comment by RichieHindle — December 17, 2007

It’s not different than the dozens of raycasting engines that have been around for years. And the markup … *yikes*

Also, I loath animations that are based on an arbitrary counter instead of a timestamp.

setTimeout("animate()",1);should readsetTimeout(animate,1);There is no reason to trigger the JavaScript parser/interpreter just to call a function.

Comment by Mathieu \'p01\' Henri — December 17, 2007

Richie, I do hear some roar from my MacBook Pro ;)

This is an example on how NOT to do the animation, but how to waste electricity in most obscure manner. It is amazing to see that a modern dualcore CPU is not enough for a smooth 400x200px animation. Anyhow – I decided to blog this as it might inspire someone else to use raycasting-type “rendering” for some meaningful purpose.

Comment by Joonas Lehtinen — December 17, 2007

while this is a nice hack, that has been also used for simulating 3D in flash, it is extremely resource consuming :(
I guess we will have to wait for some kind of OpenGL support in the rendering core…probably XHTML 8 ;)

Comment by OndraM — December 17, 2007

An interesting JS demo, but I’ll echo p01’s comments. I’m surprised the image data wasn’t compressed, encoded in JS and then written out dynamically – though I understand that would be time-consuming to do. ;)

Comment by Schill — December 17, 2007

“probably XHTML 8”

Eh. I’m holding out hope it’ll be in LMNOPHTML2.

Comment by Trevor — December 17, 2007

Schill, Image data is compressed as the individual slices are PNG, but of course including them as separate PNG:s instead of just one has a huge overhead.

Original PNG (384x64px) 6233 bytes, 384 slices totals 84350 bytes, All slices embedded to HTML as data-uris together with the javascript 145153 bytes, HTML compressed with gzip 19811 bytes

So in the end, if http compression is used, you end up with over 200% overhead for your image size (when comparing slice-animation html to original png). I would guess that the overhead would be a lot smaller if image was taller than 64px.

Comment by Joonas Lehtinen — December 18, 2007

Couldn’t this be done without using slices by having the image in an over:hidden and using position:relative to only expose the slices you want? It may end up being faster because you would have images at once.

Comment by LlamaGuy — January 5, 2008

Good work.
I never known 3d animation can do with Java script before. With 3d animation, I use several software such as Flash, Xara, Blender. I think using software to do 3d animation is much easier and faster.

Comment by LookingSoftware — April 19, 2008

Leave a comment

You must be logged in to post a comment.