This experiment shows how simple CSS transformations and transparent images can be leveraged to show and rotate a contour terrain generated from a height map in the browser with good performance.

The following code pen contains a demo:

See the pen on CodePen.

Given a grayscale heightmap, I was originally going to turn each pixel into a cube, with each cube consisting of 5 <div> elements (a top, and four sides). These cubes would then be stretched along the Z-axis to show a terrain:

CSS 3D Landscape Result

However, in Firefox this approach did not work when the number of cubes surpassed 16 (see this post for an explanation and in Chrome performance became unacceptable at around 256 cubes, or a 16×16 height map. Even showing only the tops of the cubes would quickly become too much. Clearly this technique could not be used for heightmaps of any usable size, i.e. at least 100×100.

I therefore took a different approach. If each layer of the height map were dynamically rendered into a transparent PNG, then I would need only as many divs as I have different height levels in my height map. For 64 levels (reasonable to obtain the effect I was looking for), this would thus yield only 64 div elements, each div containing a slice of the terrain.

Taking this sample 256×256 heightmap with grayscale values 0-63 as input for a small PHP script:

Height map

The first image is colored only where the heightmap has grayscale value 0, the second image is colored only where the heightmap has grayscale value 1, and so on. A second image is then used to determine which colors to use to color the final PNGs:

Color map

The resulting 64 slices set as base-64 encoded backgrounds of <div> elements placed in a single container element, and each slice is translated along the Z-axis by a small amount. Slice 0 is not translated at all, while slice 63 is translated to the height of the final terrain:

#terrain div:nth-child(1) {
  background-image: url('data:image/png;base64,iVBORw0KG...AAElFTkSuQmCC');
  transform: translateZ(0em);

Color map

It turns out that the performance of this approach is quite good. The PNGs add up to a total of about 400 kB, and can be generated beforehand for speed (i.e. the PHP code is not part of the final project). With animations added that zoom and rotate the terrain, this has the potential to become part of something bigger.