Reverse-engineering Of Google Home Animations

Discover what is the technology behing animations on Google homepage.

I am sure you've noticed that sometimes you can see animations for special events instead of the logo of Google on its homepage such as this one:

This animation is not a movie and it not made with flash. It is pure javascript. And one thing great with javascript is that it is a client-side code, so you can read it. When you browse the web and you see something cool, you can just open the cover and see how it is made. Let's do it for this animation.

Code compression

But, for speed reasons, the javascript is compressed to make the code shorter and faster to download :

  • all the variables and functions are renamed with letters to make it shorter,

  • all the white spaces and end of lines are trimmed,

  • and some tricks such as a == 1 && doThing() instead of

    if (a == 1) {
        doThing()
    }
    

And the result of that process is that it looks like a Christmas Tree :

This code is not made to be human-readable, but fast to be downloaded.

Images sprites

So how can you make that kind of animation in Javascript? The trick used by Google is a loop that add a new image every 86ms (I don't know why 86). But this is not the whole image that is repainted at each iteration, it is only the part that has changed. So Google made 155 different images that the script displays one by one. But it would be too slow to make 155 requests to load all the images. So Google used only one big image with all the small images:

And for each iteration of the loop, it says:

Put this part of the big image here on the screen

I unpacked the code and cleaned it to keep only what is essential the make the animation run. I renamed the variables and functions with meaningful names so you can read and understand the code pretty easily.

var data = [[307, 48, 88, 89], ...]; // 155 elements in the array data

var logo = document.getElementById("logoGoogle");
var tileNumber = 0;
var offSetX = 0;
var offSetY = 0;
var maxHeigth = 0;

var displayNext = function() {
    var left = data[tileNumber][0];
    var top = data[tileNumber][1];
    var width = data[tileNumber][2];
    var height = data[tileNumber][3];
    var newLine = data[tileNumber][4];

    // Creates and position the new tile
    var tile = document.createElement("div");
    tile.id = "logo" + tileNumber;
    tile.style.left = left + "px";
    tile.style.top = top + "px";
    tile.style.width = width + "px";
    tile.style.height = height + "px";
    tile.style.background = "url(/img/post-reverse-engineering-of-google-homepage-animation/sprite.png) no-repeat " + -offSetX + "px " + -offSetY + "px";
    //tile.style.border = "1px solid #DDD";
    logo.appendChild(tile);

    // Computes the offsets for the next tile
    maxHeigth < height && (maxHeigth = height);
    newLine ? (offSetX = 0, offSetY += maxHeigth, maxHeigth = 0) : offSetX += width;

    // Call this function again if it is not the last tile
    tileNumber++;
    tileNumber < data.length && window.setTimeout(displayNext, 83);
};

var image = document.createElement("img");
image.addEventListener("load", window.setTimeout(displayNext, 3000));
image.src = "/img/post-reverse-engineering-of-google-homepage-animation/sprite.png"

Comments on the code

First, you have an array with all the coordinates of the small images (which part of the big image goes where). All the elements of the array is an 4-element array [x, y, width, height] except for the ends of line of the big image that have a 1 as 5th element ([x, y, width, height, 1]) To wait the big image to be loaded before starting the animation, there is this trick:

  • the area of the animation has as background the first image of the animation (separate from the big image).

  • the script creates an img tag with source the big image whithout adding it to the document. So the browser will download the big image but not dispay it.

  • the scripts add the event

    When this img is ready, launch the loop

Quentin Pleplé
June 2011