Monthly Archives: March 2014

Feature detection

Because the technologies, primarily WebGL, WebRTC and CSS filters, that we are using in this project are so new, browser support is a substantial issue we have to deal with.

Feature detection is a way to detect whether the current browser supports particular features and to hide, display or load different features depending on the results.

Modernizr is an open source Javascript library which does just that. However, instead of having to use the whole library or going through the trouble of building my own Modernizr build with just the features I want, I instead opted to take just the three tests I needed and run them manually.

The Javascript I am using looks like so:

var Detector = {
webgl: ( function() { try { var canvas = document.createElement('canvas'); return !! window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')); } catch(e) { return false; } } )(),
webrtc: ( function() { try { return navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia } catch(e) { return false; } } )(),
cssfilter: ( function() { try { var el = document.createElement('div'); = '-webkit-filter:blur(2px);filter:blur(2px);'; return !! && ((document.documentMode === undefined || document.documentMode > 9)); } catch(e) { return false; } } )()

if(Detector.webgl) { document.documentElement.className = document.documentElement.className.replace('no-webgl', 'webgl'); };
if(Detector.webrtc) { document.documentElement.className = document.documentElement.className.replace('no-webrtc', 'webrtc'); };
if(Detector.cssfilter) { document.documentElement.className = document.documentElement.className.replace('no-cssfilter', 'cssfilter'); };

Classes on the HTML tag change from no-webgl to webgl for example if the feature is supported. This allows for the hiding and showing of elements in the CSS.

Features can also be checked within the Javascript by using a simple if-statement: if(Detector.webgl) { // do some WebGL stuff }


If WebGL isn’t supported, the user will not be able to complete the Clone A New Environment process, so we block them from the beginning:Unsupported

The user can also still visit the environment pages, however they will be greeted with a simple capture image of the environment, rather than the full 3D rendered version.

This is a good example of progressive enhancement.


If the user doesn’t support WebRTC, they will not be able to enjoy the webcam gesture feature. The user is warned when they click the webcam button that their browser is not supported.

We discussed whether we should hide the webcam button altogether if the browser isn’t supported, but decided to leave it visible to ensure that all users, regardless of their current browser, know that the feature is available, and may opt to change their browser in order to try out the feature.

CSS Filters

The CSS blur filter is used to add a highly blurred background to the environment page. If the feature wasn’t supported, the image would not be blurred and looked terrible.

If CSS filters aren’t supported, we hide the background completely.

Generating a preview of a newly cloned environment

Every time a user clones a new environment, a link to that environment will appear on their profile.

In order to make the links more visually appealing, we wanted to add an image along with the link. We could have used the Static Maps API satellite images however that wouldn’t be an accurate representation of what the user would expect to see once they had clicked through. A screenshot of the actual rendered 3D environment is what we needed to display, and luckily canvas makes it relatively easy to generate these captures.

I slotted the ‘capture’ process in between generating the height maps and redirecting to the environment page.

Hiding underneath the same fullscreen preloader as on the Clone A New Environment page, another ThreeJS environment is loaded into the page with a slightly different camera and controls setup to ensure the environment is in the correct position for the capture.

We can use ThreeJS’ WebGLRenderer’s build in capture function to encode the displayed content into a PNG base64 string:


This string is then passed into a PHP script to convert and save that string as an image to the server.

The PHP also converts the PNG to a JPEG and compresses it. The user’s profile page loads in 12 of these images on each page (see post on Pagination) so it is important to keep the file sizes low.

Environment Capture

Editable user profile

At the top of every user’s profile page, there is some information about the user: their username, avatar, location and Facebook and Twitter links.

Keeping with the idea that keeping initial signup forms short, the only information that is asked of the user when they sign up is their username, email and password, so this extra information has been made editable from their profile.

User Profile


I have added an edit button to the top-right of the profile page. This acts as a toggle between editing and saving profile information.

When the button is clicked, several input boxes appear allowing the user to enter their details.

User Profile Editing


The button changes from a pen to a tick, denoting that the same button can be used to save the entered details.

The user’s avatar is loaded automatically from an external service called Gravatar. The user will have to sign up through Gravatar in order to display their own avatar on our site.

The advantages being that we don’t have to provide support for uploading and storing avatar images. Which also avoids potential issues with unlawful images being uploaded.

Clone a new environment

The clone a new environment page has gone through many iterations.

To begin with, it all boils down to allowing the user to select a predefined area of the map and to kick off the cloning process. We use the Google Maps API to allow the user to interact with the map and handle the selection of a point.

We’ve added several enhancements in order to make the process easier:

  • An overlay grid appears once the user has zoomed to the required zoom level, showing the user the boundaries of the tile that they will be cloning
  • When clicking the map, the overlay grid will update to show the selected tile
  • The maximum zoom is also the required zoom level for selection
  • Satellite, hybrid and terrain map display options are visible to aid the user in finding an area of interest
  • A search box is available if the user already knows where they want to clone

The CLONE button also required quite a bit of validation:

  • Check whether a tile has been selected
  • Check whether that tile has already been cloned before by another user
  • Ensure the environment name the user enters is present and not longer than 30 characters

New Environment Map