Written by Super natural

Oh hi, and Happy Valentine’s Day. We lurve Valentine’s Day at Super natural and this year we’ve created a little something to show you all how much we love digital and to show you just how soppy we really are.

We’ve for a long time been tinkering with Mr Doob‘s Three.js and there’s all manner of experiments out there that will be sure to blow your mind but in looking through these we tend to see two veins of creative development:

The first is usually quite abstract, presumably because the developer that created them has limited design skills so just created boxes and shapes. Taking nothing away from this method of course, the output is still very exciting.

The second tends to be much more 3D driven. Our research leads us to believe the assets have been modelled using CAD or one of the many other 3D software applications out there and then exported to a JSON object. This could be achieved using something similar to the Blender exporter plugin.

These types of experiments are truly amazing but… they’re heavy, usually over 5mb which is too heavy for display advertising and questionably too heavy for 3/4G (mobile networks).

So we decided to meet in the middle and apply creative design to what are effectively just simple boxes. Or, to use the Three.js terminology, THREE.BoxGeometry(x,y,z).

Using this method we are able to code simple 3D graphics without needing to first model them in CAD, Cinema 4D, 3D StudioMax, Maya etc.

Here at Super natural, we love doing things that you wouldn’t normally do using methods that you wouldn’t normally use. Why? Well, we like to challenge ourselves.

So from here we made Daisy.


And here’s a code snippet of what the above looks like.

var daisyBodyGeom = new THREE.BoxGeometry(5, 5, 10);
var daisyBodyCol = new THREE.MeshPhongMaterial({ color: 0xffffff });
var daisy = new THREE.Mesh(daisyBodyGeom, daisyBodyCol);

All the elements in our Three.js scene have been created in this way. That’s right, everything is effectively THREE.BoxGeometry(x,y,z).

The next thing to discuss is the use of Canvas:

The HTML Canvas element is used to draw graphics, on the fly, via scripting (usually Javascript).

Source: W3 Schools

The downside is that if you were to create an entire website on Canvas you’d suffer from some quite major SEO issues; much like the old (ahem) Flash days where all the complex graphics and animation elements were ‘embedded’ inside the .swf which was then added to the HTML page. These ‘locked off’ elements meant search engines had difficulty crawling the content thus adversely affecting your web page’s overall ranking.

For that reason our experiment couldn’t be 100% Canvas, it had to be a hybrid. We’ll explain what we mean by that.

The page structure is largely as you’d expect from an HTML build but mid way down there’s our Canvas and into that we ‘inject’ our Three.js scene. This method means our web page will still be crawlable and could still be SEO friendly.

This hybrid method however is not without floors when combined with the Three.js Orbit Controls.

The Orbit Controls allow the user on ‘mouse click’ to navigate around the 3D scene by orbiting the scene’s main camera.

We’ve mentioned ‘mouse click’ above as this is the crux of the issue. Whilst on device ‘mouse’ is for the most part replaced with ‘touch’ but we do lose the combination of ‘scroll and press’.

On a desktop computer you’d usually use the mouse wheel to scroll a web page and this is possible without the need to click or press the mouse button down. So when on desktop you’re able to scroll up and down our page as you normally would, and if you click and drag over the Three.js Canvas you’re able to orbit around the 3D scene. On device however, there’s a problem. The method you’d use to scroll a webpage, ‘press and drag’, is also the same method required to orbit the Three.js scene.

Our solution: Orientation Control – the device’s orientation event.

As I’m sure you’ll be aware it is possible to read the device’s built-in compass to work out which way the device is heading and in which orientation it’s currently in. It’s also possible to determine if the device is tilted or not.

The W3C explanation makes for a fascinating read but in short we are able to convert the raw mathematical outputs from Alpha, Beta and Gamma to something more useful in a Three.js scene; X, Y, Z.

The formula is:

R = ZXY =
cos(α)cos(γ) - sin(α)sin(β)sin(γ) cos(γ)sin(α) + cos(α)sin(β)sin(γ) - cos(β)sin(γ)
- cos(β)sin(a) cos(α)cos(β) sin(β)
cos(γ)sin(α)sin(β) + cos(α)sin(γ) sin(α)sin(γ) - cos(α)cos(γ)cos(β) cos(β)cos(γ)

And we convert that to JavaScript like so:

function compassHeading(alpha, beta, gamma) {
var degtorad = Math.PI / 180;
var _x = beta ? beta * degtorad : 0;
var _y = gamma ? gamma * degtorad : 0;
var _z = alpha ? alpha * degtorad : 0;
var cX = Math.cos( _x );
var cY = Math.cos( _y );
var cZ = Math.cos( _z );
var sX = Math.sin( _x );
var sY = Math.sin( _y );
var sZ = Math.sin( _z );
var Vx = - cZ * sY - sZ * sX * cY;
var Vy = - sZ * sY + cZ * sX * cY;
var compassHeading = Math.atan( Vx / Vy );
return compassHeading * ( 180 / Math.PI );

Once we have the degrees we can now start to rotate elements from 0 to 360 degrees.

Easy really!



How do we decide if the Three.js scene is controlled via mouse or via orientation controls? A very helpful little JavaScript library known as Modernizr.

Modernizr is a small piece of JavaScript code that automatically detects the availability of next-generation web technologies in your user’s browsers. Rather than blacklisting entire ranges of browsers based on “UA sniffing,”

Source: Modernizr

There’s a few features we need to check for at this point, the first being whether the device / browser even has device orientation? As well as this (to be on the safe side), whether the device / browser supports touch events? This way we can be sure the user is definitely on a touch screen device with the ability to determine orientation.

Our check function looks a little like this:

if (touch && webgl && devicemotion && deviceorientation){
return "device";
else if (webgl){
return "desktop";
else {
return "backup";

It’s also worth noting that along with checking for device orientation and touch, we also double check against device motion and the final piece in the puzzle, WebGL. Without WebGL none of the above is possible.

(Web Graphics Library) is a JavaScript API for rendering interactive 3D computer graphics and 2D graphics within any compatible web browser without the use of plug-ins.

Source: Wikipedia

WebGL is quite well supported with the exception of course of our old chum Internet Explorer 9! Whilst UK usage for this browser is very low (0.4%*), we know from our own experience working with media agencies and even some of our clients that IE9 is still used. As such we need to ensure we have yet another fall-back in place so our site in some form appears even when used on such an archaic browser as IE9.

*Source: W3Schools

So there you have it. No shoot, no 3D software, just lovely delicious code and with our own custom fall-back solution:

Desktop: Mouse Control
Device: Orientation Control
No WebGL: A message to explain that the user really ought to use a more up to date browser.

Clearly the above is top level pillow chat so use it carefully and Happy Valentine’s Day!

Lots of love, Super natural