Creating a 3D Effect in 2D HTML5 Canvas Games

HTML5 Canvas doesn’t include a built-in 3D context. Without using an add-on product such as WebGL (, 3D has to be simulated using the 2D context.

Some games require the sophistication of a true 3D engine like WebGL. However, many games built using the Canvas 2D context can be significantly enhanced by simulating aspects of 3D motion.

In the Ballpark sample game from HTML5 Canvas for Dummies, the thrown baseball is simulated moving away from the ball thrower toward the ball player along a simulated z axis third dimension. The z axis 3D effect is accomplished by decreasing the size of the baseball in proportion to it's movement upward along the 2D y axis.

You can play the game yourself by clicking here.  To see the full code, right click on the game web page and select View Page Source.

To simulate 3D movement using this technique, the following steps were used:

1.    Assign a z axis variable to each new object.

Along with the xPos and yPos variables, assign a zPos variable as in code section S2 assignments for baseballs:

     ball[b].zPos = zStart;

2.    As the object moves, update the z position.

In the sample game, in code section R8, the z position is calculated based  on the y axis position (yPos) and a z sizing factor (zSizeFact):

     var newZPos  = (ball[b].yPos/canvasBL.height) * zSizeFact;

     ball[b].zPos = newZPos;  

3.    Fix the z position under specified conditions.

In the sample game, the baseball is simulated to move along the z axis only away from the ball thrower. Also, to simplify the simulation, only movement up the y axis is used to increase z axis movement. So, when the ball starts to move down on the y axis, the z position is fixed. This code is in sections R9-R12:

     // FIX Z position of zFix is greater than zero.      

     if(ball[b].zFix > 0)  {ball[b].zPos = ball[b].zFix};

     // Z FIX check for not already set.

     if(ball[b].zFix == 0)

     {   // Z FIX conditions check. 

        var newYPos  = ball[b].yPos;

        if(((newYPos > curYPos) || (ball[b].bounce)) && (curYPos < zFixMaxY))

        {  // FIX Z POSITION at current level and no smaller than minSize.

           ball[b].zFix = Math.max((curYPos/canvasBL.height)*zSizeFact, minSize);   }   }