Web Platform Team Blog

Making the web awesome

Building a Screensaver in HTML

Screen SaverTo get some experience working with and optimizing CSS 3D transformations, we decided to build an HTML screensaver demo (GitHub repo). Here’s how it works:

  1. Open the demo in any modern browser with proper 3D CSS transformation support (Chrome, Safari, or Firefox).
  2. Choose your favorite image sharing services (Flickr, 500px, Instagram, or Dribbble).
  3. Watch the photos animate vertically, then fully rotate horizontally at regular intervals.
  4. Use your arrow keys to rotate the images manually.

The demo wasn’t all that technically challenging, but there were some interesting issues along the way.


Compensating for Perspective

Perspective CompensationTo create the illusion of perspective and depth, objects that are supposed to be further away are scaled down. As a result, when you create a bunch of images with random X, Y, and Z coordinates, they tend to form a tunnel-like shape on the screen, congregating around the centre which isn’t very pleasing to the eye (a). To compensate, we explicitly shift the images to the sides to make them appear more evenly distributed (b).


Screen Saver LoadingFor all UI graphics, we used SVG. SVG has several advantages over images:

  1. For our simple case, SVG icons were much smaller than PNGs.
  2. SVG is much easier to script: change color, rotate, add glow, etc.
  3. Since SVG graphics are vectors, they look better on displays with high resolutions.

Math.random() is Not Very Random

We found that randomizing the horizontal position makes images sometimes crowd around one particular side of the screen. To compensate, we divide screen into columns and ensure that images appear in all columns. We then “randomize” the X, Y, and Z coordinates within each column. The result is that the images are much more evenly distributed.

Keeping Images Out of Your Face

When the images rotate around the Y axis, they get too close to the camera which makes them look a bit ugly and disturbing. To make it look more appealing, we add an animation that pulls the camera back at the beginning of the rotation, then returns it to where it was at the end. The effect is subtle, but much less jarring and generally more pleasing.

Technical Issues


To work around XHR crossdomain security restrictions, we decided to use JSONP, but there was a nasty surprise: the 500px API doesn’t actually support JSONP. To workaround this issue, we use YQL to pull JSON from 500px and to convert it into JSONP.


Screen Saver Rotation
The main issue was, of course, the performance of the animation. The animation itself is relatively simple code that uses requestAnimationFrame(). The animation works by combining all the animations’ CSS transformations (vertical and horizontal movement as well as rotation) into a matrix representation that later gets applied using matrix3d(). Operating via matrix3d() instead of separate properties resulted in a surprisingly big performance boost in Chrome. This is actually a known bug and hopefully will be fixed in an upcoming release. Additionally, in CSS transformations, there is no way to transform the camera’s position or angle, therefore to achieve the desired effect, we faked it by calculating (in JavaScript) the position of each element as the camera rotates around.


  1. February 19, 2013 at 1:45 pm, Franklin said:

    “Math.random() is Not Very Random”

    But randomness implies clustering:

  2. February 22, 2013 at 3:08 pm, thinsoldier said:

    Would it be possible to modify this to pull local images via file:// ?