HTML5 Experiment: A Rotating Solid Cube

Previously I shared an HTML5 experiment consisting of a rotating wireframe cube. Today, I will share a new experiment that makes a rotating solid cube. This experiment is largely based on the wireframe cube experiment.

To run this experiment you need a browser that supports the HTML5 canvas element. You should see a rotating solid cube below if your browser supports the canvas element. If not, you should consider upgrading your browser to the latest version.

The Code

Please leave a comment if you have any doubt, comment, or suggestion regarding this code.

<!DOCTYPE html>
<html>
<head>
    <title>HTML5 Experiment: A Rotating Solid Cube</title>
    <script type="text/javascript">
        window.onload = startDemo;

        function Point3D(x,y,z) {
            this.x = x;
            this.y = y;
            this.z = z;

            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                y = this.y * cosa - this.z * sina
                z = this.y * sina + this.z * cosa
                return new Point3D(this.x, y, z)
            }

            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                z = this.z * cosa - this.x * sina
                x = this.z * sina + this.x * cosa
                return new Point3D(x,this.y, z)
            }

            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                x = this.x * cosa - this.y * sina
                y = this.x * sina + this.y * cosa
                return new Point3D(x, y, this.z)
            }

            this.project = function(viewWidth, viewHeight, fov, viewDistance) {
                var factor, x, y
                factor = fov / (viewDistance + this.z)
                x = this.x * factor + viewWidth / 2
                y = this.y * factor + viewHeight / 2
                return new Point3D(x, y, this.z)
            }
        }

        var vertices = [
            new Point3D(-1,1,-1),
            new Point3D(1,1,-1),
            new Point3D(1,-1,-1),
            new Point3D(-1,-1,-1),
            new Point3D(-1,1,1),
            new Point3D(1,1,1),
            new Point3D(1,-1,1),
            new Point3D(-1,-1,1)
        ];

        // Define the vertices that compose each of the 6 faces. These numbers are
        // indices to the vertex list defined above.
        var faces  = [[0,1,2,3],[1,5,6,2],[5,4,7,6],[4,0,3,7],[0,4,5,1],[3,2,6,7]];

        // Define the colors for each face.
        var colors = [[255,0,0],[0,255,0],[0,0,255],[255,255,0],[0,255,255],[255,0,255]];

        var angle = 0;

        /* Constructs a CSS RGB value from an array of 3 elements. */
        function arrayToRGB(arr) {
            if( arr.length == 3 ) {
                return "rgb(" + arr[0] + "," + arr[1] + "," + arr[2] + ")";
            }
            return "rgb(0,0,0)";
        }

        function startDemo() {
            canvas = document.getElementById("thecanvas");
            if( canvas && canvas.getContext ) {
                ctx = canvas.getContext("2d");
                setInterval(loop,33);
            }
        }

        function loop() {
            var t = new Array();

            ctx.fillStyle = "rgb(0,0,0)";
            ctx.fillRect(0,0,400,250);

            for( var i = 0; i < vertices.length; i++ ) {
                var v = vertices[i];
                var r = v.rotateX(angle).rotateY(angle);
                var p = r.project(400,250,200,4);
                t.push(p)
            }

            var avg_z = new Array();

            for( var i = 0; i < faces.length; i++ ) {
                var f = faces[i];
                avg_z[i] = {"index":i, "z":(t[f[0]].z + t[f[1]].z + t[f[2]].z + t[f[3]].z) / 4.0};
            }

            avg_z.sort(function(a,b) {
                return b.z - a.z;
            });

            for( var i = 0; i < faces.length; i++ ) {
                var f = faces[avg_z[i].index]

                ctx.fillStyle = arrayToRGB(colors[avg_z[i].index]);
                ctx.beginPath()
                ctx.moveTo(t[f[0]].x,t[f[0]].y)
                ctx.lineTo(t[f[1]].x,t[f[1]].y)
                ctx.lineTo(t[f[2]].x,t[f[2]].y)
                ctx.lineTo(t[f[3]].x,t[f[3]].y)
                ctx.closePath()
                ctx.fill()
            }
            angle += 2
        }
    </script>
</head>
<body>
        <canvas id="thecanvas" width="400" height="250">
        Your browser does not support the HTML5 canvas element. <a href=#>Click here</a> to watch the video.
    </canvas>

    </body>
</html>

If you liked this experiment, please consider leaving a comment, sharing this post using one of the buttons below, or subscribing to the blog.

Leave a comment ?

55 Comments.

  1. Mira Longworth

    Excellent posting

  2. Hello & thanks for that !
    Is there a way to replace each faces by on HTML div or image?

    • Hello GeorgioA,

      I guess you want to make a texture mapped cube.
      First of all, let me tell you that there are 3 approaches for doing 3D with HTML:
      (1) CSS3 using 3D transforms (with or without javascript)
      (2) Canvas 2D (HTML5 + JavaScript) – this is the one used in this tutorial.
      (3) WebGL (HTML5 + JavaScript)

      It is possible to make a textured cube with the 3 approaches. However, the first approach is the only one that supports 3D animation of DIVs.

      The code in this tutorial is something like a mini 3d engine coded from scratch. To do texture mapping, we would need to implement a function to draw textured polygons, and additionally we would need to alter the Point3D class adding texture map coordinates (called UV coordinates).
      I will write a texture mapped version of this code, and post a tutorial about it in a few days.

      (Texture Mapping = applying an image to a 3D object)

  3. Great working example, but was wondering if it is possible to map images to the faces instead of the color values. Searched for replace color, your help will be greatly apriciated.

    • It is possible to map images to the cube. The process is called TEXTURE MAPPING. Today I will start a series of tutorials that aim to show how to draw a texture mapped cube. The series will be broken in 4 parts.
      Thank you very much :)

  4. I don’t want the background to be black.I want it to be transparent.What should I do?

    (http://codentronix.com/2011/05/10/html5-experiment-a-rotating-solid-cube/)

    • You can do that by replacing the the 2nd and 3rd statement in the loop() function:

      ctx.fillStyle = “rgb(0,0,0)”;
      ctx.fillRect(0,0,400,250);

      to

      ctx.clearRect(0,0,400,250); // this clears the canvas making it transparent

  5. it’s awesome, but i don’t know how to give a same color to all dimentions..?

  6. Shikhar Sahdev

    Thank you very much lefam.
    And Amir you can edit the colors from the 68th line:

    var colors = [[255,0,0],[0,255,0],[0,0,255],[255,255,0],[0,255,255],[255,0,255]];

    Change the colors as you want.

  7. Its awesome example. Can you please share textured cube code. And also just wanted to know whether you can add code to stop cube movement once user takes mouse over on any surface?

    • I will share code to do a textured cube as soon as I get some free time.
      Regarding the code to stop movement, you mean when the mouse is inside the whole canvas, or inside any of faces/surfaces of the cube?

  8. Hi, this example is cool, I like it.

    So I have one question, do you have a similar example with texture mapping drawing in each face in the cube?

    I don’t know if I can building, but I think is possible.

    Please let me know if you have any idea

    Thanks!

  9. i want background to have pictures..likewise pictures rotating..

  10. How to add images?

  11. Thank a lot for this code, I try to make a map for create a mini-game like Prelude of the Chambered (http://s3.amazonaws.com/ld48/index.html) or Wolfenstein 3D (http://en.wikipedia.org/wiki/Wolfenstein_3D) without use raycaster but I’ve no idea how to do that. I think create a map a 2D array (because I’ve only one layout) and a camera with coordinate x, y and z but I’m lost. It’s possible with this base code ? Can you help me, please ?

    (sorry for my english level, I’ve a bad school english level)

  12. This is great, but if one dimension is reduced (ie. y is in (-0.2,0.2) range), the algorithm for sorting faces by depth doesn’t work well. How could this be fixed?

  13. This is great! How could I add words on each wall of the cube?

  14. I want to rotate the 3d polygon(more than 3 cubes attached as single object) while on drag. please suggest
    how can i do that?

  15. Wonderful post, thanks for explaining it ;)

  16. Hi Lefam, Love the spinning cube and have tested it and it works and spins in all major browsers, which has been really hard to find. I need to do a texture mapped version of the cube and you said in 2011 that you would be posting a tutorial about the texture mapped cube in a few days, I haven’t been able to find it, did you post it? It is essential for me to have a texture mapped cube, preferably with text on each face as well as a picture and for each face to have a link to a website page, would this functionality be possible with this cube? Please help. Thank you so much.

    I guess you want to make a texture mapped cube.
    First of all, let me tell you that there are 3 approaches for doing 3D with HTML:
    (1) CSS3 using 3D transforms (with or without javascript)
    (2) Canvas 2D (HTML5 + JavaScript) – this is the one used in this tutorial.
    (3) WebGL (HTML5 + JavaScript)
    It is possible to make a textured cube with the 3 approaches. However, the first approach is the only one that supports 3D animation of DIVs.
    The code in this tutorial is something like a mini 3d engine coded from scratch. To do texture mapping, we would need to implement a function to draw textured polygons, and additionally we would need to alter the Point3D class adding texture map coordinates (called UV coordinates).
    I will write a texture mapped version of this code, and post a tutorial about it in a few days.
    (Texture Mapping = applying an image to a 3D object)

    • Hello @AnnW. Sorry for my late reply. I have been very busy.
      Sorry, I did not post the tutorial. But, I will post as soon as I have some free time.

  17. Amazing code. I tried making my own from scratch, matrix multiplication is too confusing. This page even works in mobile browsers like my 3Ds and iPod! By removing the code at line 120 and the last t[f[3]].z part on 105 you can create faces using 3 verts. I guess for texture mapped cubes in canvas you would have to get the image data from the UV image and skew it to the faces? Or some type of array that replaces the colors with the pixel data?

  18. I’mamazed, I have to admit. Rarely do I encounter a blog that’s both equally educative and engaging, and let me tell you,
    you have hit the nail on the head. The issue is something
    which too few men and women are speaking intelligently about.
    I am very happy that I stumbled across this during my search for something concerning this.

  19. hi lefam:

    I’m newbe of js cavas, I misunderstood below formula few days.
    y, z value is the offset distance ? Can you explain for me.
    Many thanks.
    //————————————-
    cosa = Math.cos(rad)
    sina = Math.sin(rad)
    y = this.y * cosa – this.z * sina
    z = this.y * sina + this.z * cosa
    //————————————-

  20. токарный станок по металлу – токарный станок с чпу, токарно винторезные станки.

  21. wondering if you can imbed video into each wall of this rotating cube while still keeping it all HTML5? Also, is there a way I can email you? I might be interested in hiring you to do some cube work for my personal website

    Andy

  22. оформить кредитную карту пенсионеру – получить займ без справок и поручителей, кредит наличными с доставкой на работу.

  23. very cool code. is it possible to create more cubes to have 2 or + cubes rotating on page?

    thanks a lot in advance!

  24. Awesome stuff, Cheers!

  25. This website certainly has all of the info I needed concerning this subject and
    didn’t know who to ask.

  26. I do consider alll of the idea you’ve offered in your
    post. They’re really convincing annd can certainly work.
    Nonetheless, the posts are verry short for newbies.
    May you please extend them a little from next time? Thank you for the post.

  27. Ремонт Айфон и Айпад – Замена микрофона iPhone 5S в Екатеринбурге, Замена защитного стекла iPhone 4S (тачскрина) в Екатеринбурге.

  28. However, in comparison to Tramadol, morphine does not have the ability to induce improved postoperative immuno-suppression. The
    nerve root and neurologic structures are protected and carefully retracted, so that the herniated
    disc can be removed. In addition, the Green Light Laser Prostate Treatment
    by less risk and complications than those previously used for treatment of BPH.

  29. Hi, of course this piece of writing is genuinely pleasant and I
    have learned lot of things from it about blogging.
    thanks.

  30. Very good article. I absolutely love this website. Thanks!

  31. thanks in advance

    Great work

    i want background to have pictures..
    image rotating

  32. If you are interested in topic: can you make money recycling old electronics
    - you should read about Bucksflooder first

  33. Your method of describing everything within this paragraph
    is genuinely nice, every one can without difficulty know it, Thanks
    a whole lot.

  34. Pretty greаt post. І simply stumbled uoon уour weblog and wаnted to mention that
    I’ve truⅼү enjoyed browsing yⲟur blog posts. Ⅰn аny case І’ll be subscribing
    іn your feed and I am hoping yyou ԝrite once mοre soon!

Leave a Comment

Notify me of followup comments via e-mail. You can also subscribe without commenting.