Article
The Art and Science of JavaScript
In this tutorial, we'll look at a technique for using CSS and JavaScript to build a first-person-perspective maze, in homage to old-school adventure games like Dungeon Master and Doom.
In truth, the scripting involved is fairly complex, and it won't be possible for me to spell out every nuance of the code in this single tutorial. In fact, I won't even list every method used in the script, as some of them are quite long. What I can do, though, is introduce you to the principles of creating shapes and perspective with CSS, and the task of using JavaScript to generate those shapes on demand to create a dynamic, three-dimensional perspective from a static, two-dimensional map.
The script, and all of its components, are included in the tutorial's downloadable code archive. All the code is robustly commented, so you should find it easy to follow. I recommend that you have it available to view as you read, so that you can refer to it as we go along.
Before we dive into a discussion of how it's built, let's take a look at the final result -- it's shown below.
![]()
That screenshot was taken with Opera, in which this script was originally developed, and it also works as intended in Firefox, Safari, and Internet Explorer 7. IE 6, however, is not fully supported: the game works, but it looks poor because IE 6 doesn't have all the CSS support we need (most notably, it lacks support for transparent borders). This tutorial was developed for SitePoint's book The Art & Science of JavaScript, and you can download it to keep and read offline. That downloadable PDF also includes the chapter on tables, in which I guarantee you'll find a few surprises!
I should also point out, in case it crosses your mind, that what we're doing here has no practical use. In fact, it could be argued that we're not really using the right technology for the job. I made this maze because I wanted to see if it was possible -- to push the envelope a little in terms of what can be done with JavaScript and CSS. But we're right at the edge of what's reasonable, and maybe Flash or SVG would be better suited to building a game like this.
But hey -- why climb a mountain? Because it's there!
Basic Principles
In 2001, Tantek Çelik published a technique for creating shapes using the interactions between CSS borders. We're going to use that technique to make a bunch of right-angle triangles.
Why triangles, I hear you ask? Well, because once you can render a triangle, you can render any polygon that you like. By combining triangles with the rectangles that we've always been able to render (using a good old div and the background-color property), we can create the walls of our maze and contribute to the sense of perspective. As you'll see, we'll draw these walls by slicing the player's view up into a number of columns.
We'll also need a floor plan for our maze, and a handful of methods for dynamically converting that floor plan into the polygons that represent the walls of our maze.
Making Triangles
If an element has a very thick border (say 50px), and adjacent borders have different colors, the intersection of those borders creates a diagonal line, as the figure below illustrates.

That example is simply a div element to which the following CSS rules are applied:
width: 200px;
height: 200px;
border: 50px solid #900;
border-color: #009 #900;
To render a triangle, we don't actually need the contents of that div -- we only need its borders. So let's remove the text, and reduce the width and height values to zero. What we're left with is the image shown below.

Here's the CSS that achieves that effect:
width: 0;
border: 50px solid #900;
border-color: #009 #900;
If we were to vary the relative border widths (applying, say, 50px on the left border and 25px on the top), we could create triangles with various angles. By setting the color of one of the borders to transparent, the diagonal line from the solid border stands alone, as the figure below reveals.

Now, if we wrap a second div element around the first, we'll be able to extract a single, discreet triangle. We can achieve this by:
- applying position: relative to the outer container
- applying position: absolute to the inner element
- clipping the inner element
Clipped elements are required to have absolute positioning, so the relative positioning on the container provides a positioning context for the inner element, as the figure below shows.
![]()
The code that produces that figure is still very simple. Here's the HTML:
<div id="triangle">
<div></div>
</div>
And here's the CSS:
#triangle
{
border: 2px solid #999;
position: relative;
width: 50px;
height: 25px;
}
#triangle > div
{
border-style: solid;
border-color: transparent #900;
border-width: 25px 50px;
position: absolute;
left: 0;
top: 0;
clip: rect(0, 50px, 25px 0);
}
Clipping and positioning is the crux of our ability to create discreet shapes using CSS. If we removed the clip, we'd get the result shown below.

You can see that by varying the clip and position properties on the inner element, we control which part of it is shown, and hence which of the triangles will be visible. If we wanted the bottom-right triangle, we would apply these values:
left: -50px;
top: -25px;
clip: rect(25px, 100px, 50px, 50px);
And we'd get the result depicted here.
![]()
James (aka