Simon’s Google Doodle – HTML5 + JS jQuery Game

Dude, you’ve heard a lot about Google doodles haven’t you? What about that Pacman one? It is just addictive. Company owners know how a funny game and unlimited search powers could be dangerous for productivity. And how it can be a marketing boost. The most amazing thing is that we can create our own addictive HTML game. Actually, this is why we are here today. With this tutorial you’ll see how to use some of JavaScript and HTML capabilities to build simple yet funny games.

So, let’s rock!

Demo first, please

You can download or try our online demo. Please, don’t forget to come back here if you want to just go playing first :)

“Well, actually I don’t know what a Doodle is..”

Google Doodles started when Larry and Sergey played with the corporate logo to indicate their attendance at the Burning Man festival in the Nevada desert. Since that day we’ve seen a lot of funny Doodles, and Google’s homepage is used to remind us of all kind of important facts.

But they are more than just paintings, games or experiments. They are made with the best current practices (some of them, created specifically for a Doodle). And Google being as supportive as they are of open source technology, usually release the commented source code, so you can just take a look and try to understand what those amazing guys are doing.

Oh, and I don’t know if you knew about it, but today is Simon’s day according to 1stWebdesigner’s official fake holiday calendar. Seems important, right? This is why we’ll build a game for it.

So, what will we be doing?

Simon is one of my favorite games (just after Sudoku and Gammon). Can you think of an easier game to code? You know, four buttons, easy actions. I just can’t think of a better starting point to learn HTML5 gaming.

Well, first of all you need to know what this Simon thing looks like. I just found a picture of it at Mercado Livre (kind of a Brazilian e-bay) and made my own version in Photoshop.

Since we are doing it via HTML5, the colors shouldn’t be directly on image (otherwise you won’t be able to change colors, make your own console…). So I’ve used Chris Coyier‘s technique for color animation. Basically we make our non-colored elements, and leave everything else transparent. Then our HTML5 will take care of the color itself (via CSS, background-color). Our final game background will be something like this:

Ok, then. Let’s start the fun part.

Basic HTML + CSS

Since our target isn’t basic HTML itself, I just grab a copy of HTML5 Boilerplate with a few edits to make it cleaner:

<!DOCTYPE html>
<html lang="en">
  <meta charset="utf-8">

  <title> - Simon's day  ( game :D)</title>

  <link rel="stylesheet" href="css/style.css?v=2">
  <script src="js/libs/modernizr-1.7.min.js"></script>
  <div id="container">
    <div id="main">
	<!-- Game controls and deisgn -->
	<form id="search" action="#" method="get">
		<input type="text" name="query" id="query" />
		<input type="submit" value="search" id="submit" />
	<div id="options">
		<!-- game options -->

  <script src="//"></script>
  <script src="js/script.js"></script>

Now we need our gaming HTML stuff. As we’ve done it ready for different colors we will need to have two layers:

  • Background color- sets the color and will be animated when you activate a button
  • Link – activates all actions for each colored button.
  • Alerts – since they are part of the game itself, we’ll put them with all other game controls (level up, new game, game over)

Our HTML for this part will be something like this:

	<div id="main">
	<!-- lights -->
		<div id="box-0" class="box">&nbsp;</div>
		<div id="box-1" class="box">&nbsp;</div>
		<div id="box-2" class="box">&nbsp;</div>
		<div id="box-3" class="box">&nbsp;</div>
	<!-- buttons -->
		<a href="#" class="box btnTL" id="box-click-0">&nbsp;</a>
		<a href="#" class="box btnTR" id="box-click-1">&nbsp;</a>
		<a href="#" class="box btnBL" id="box-click-2">&nbsp;</a>
		<a href="#" class="box btnBR" id="box-click-3">&nbsp;</a>
	<!-- alerts -->
		<div id="letsRock" class="alert">
			<p>Ready? let's rock!</p>
		<div id="ohYes" class="alert">
			<p>Oh Yeah!</p>
		<div id="ohNoes" class="alert">
			<p>Oh Noes... Almost there! </p>

As you can see, the four “” elements are the background color for each button (red, blue, green, red).

So when someone clicks #box-click-0 it will “activate” the button #box-0. We have a lot of id’s because they result in better JS performance.

Our CSS for that will be:

#main {
	position: relative;
	left: 155px;
	width: 200px;
	height: 200px;
	.box {
		display: block;
		float: left;
		width: 100px;
		height: 100px;
	} {
		position: absolute;
		text-decoration: none;
		background-image: url("../img/bg_game.png");
		background-repeat: no-repeat;
	} {
		outline: none;
	.btnTL { background-position: top left; }
	.btnTR { background-position: top right; }
	.btnBL { background-position: bottom left; }
	.btnBR { background-position: bottom right; }
		 .btnTL, .btnTR {
			top: 0;
		 .btnBL, .btnBR {
			bottom: 0;
		 .btnTL, .btnBL {
			left: 0;
		 .btnTR, .btnBR {
			right: 0;
	#box-0 {
		background: #c00000;
	#box-1 {
		background: #1506a3;
	#box-2 {
		background: #046606;
	#box-3 {
		background: #ea8f0c;

Here is our effect: all our links have the console background, bg_game.png (positioned according to what it should be, of course). Since they are on top of divs, what we will see is the bg_game.png AND the element’s color ( #c00000, #1506a3…).

Ok, we won’t be long on this. Maybe this is enough topic for a single article :)

Search form

Have you noticed the recent (ok, maybe not that recent) Google’s switch to real time results? That’s pretty cool, yeah, I know. But it makes a little bit harder to link directly to a search results page.

Since our demo has a search form and we want to make it work, let’s put a little JS magic on it:

	<form id="search" action="#" method="get">
		<input type="text" name="query" id="query" />
		<input type="submit" value="search" id="submit" />


	$("#search").submit( function(event) { event.preventDefault(); googleRedirect(); } );
function googleRedirect() {
	var query = $("#query").attr('value');
	var url = "" + query + "&fp=1";
	window.location = url;

This way it will work ;)

Cookies? No, no, local storage instead!

Well, Cookies are great for some things, but this time they aren’t the very best option. Here we will make use of Local Storage. This is basically the same idea as Cookies, it allows you to store data related to your site, the difference is that it’s faster and very useful in some situations.

As its name suggest it is local, so it won’t be sent to the server (you save a few kbytes and processing). Cookies are limited to 4kB and 20 Cookies per domain. With local storage you can record up to 5MB of user data.

The only downside is that it works only on real browsers and IE8+. So, forget about IE7 this time (maybe later with some jQuery data fallback).

Another huge advantage is that it is surprisingly easy to set / remove;

localStorage["level"] = 15; // create it with 15 as value
var level = localStorage["level"];  //now var level is 15
localStorage.removeItem( "level" ); //remove it!

So, this is why we will use it this time.

A few options

Then we need to have a way to start the game, see which level we’re playing, these sort of trivial things. For this, we’ll just put a simple HTML box with Google’s logo:

<div id="options">
		<li>Level: <span id="levelCount">1</span></li>
		<li><a href="#" onclick="newGame()" >New Game</a></li>
		<li>High Score: <span id="hs">1</span></li>
		<li><a href="" target="_blank" >Credits</a></li>

Well, what is important here is that our counters have id’s wrapping them, so we can easily change their text.

Let the game begin

Random sequence

The very first thing to do when you start this game should be to generate a random sequence. Because this sequence will be the “right path” to be followed by players. We could generate it on-the-fly as our gamer reaches new levels, but it will be easier to do this way.

So we will create a simple function that just generate a random sequence with 50 digits (levels) and only with numbers from 0 to 3 (our colors!):

function randomSequence() {
	var chars = "0123"; // four colors!
	var string_length = 50; //pretty hard, isn't it?
	var sequence = "";
	for (var i=0; i < string_length; i++) { //we'll have from sequence[0] to sequence[49]
		var rnum = Math.floor(Math.random() * chars.length);
		sequence += chars.substring(rnum,rnum+1);
	return sequence;

Binding clicks and hovers

Now we need to prepare our all elements to recognize clicks and to animate properly our when you hover any of them.

This time we will need jQuery .hover() and .click() functions:

//caching our elements for better performance
box0 = $("#box-0");
box1 = $("#box-1");
box2 = $("#box-2");
box3 = $("#box-3");
clickbox0 = $("#box-click-0");
clickbox1 = $("#box-click-1");
clickbox2 = $("#box-click-2");
clickbox3 = $("#box-click-3");
var minHover = 0.7;
var maxHover = 1;
var timeHover = 500;
		box0.stop().animate({opacity: minHover}, timeHover);
	}, function() {
		box0.stop().animate({opacity: maxHover}, timeHover);
		box1.stop().animate({opacity: minHover}, timeHover);
	}, function() {
		box1.stop().animate({opacity: maxHover}, timeHover);
		box2.stop().animate({opacity: minHover}, timeHover);
	}, function() {
		box2.stop().animate({opacity: maxHover}, timeHover);
		box3.stop().animate({opacity: minHover}, timeHover);
	}, function() {
		box3.stop().animate({opacity: maxHover}, timeHover);

It is pretty important caching all our elements, since it improves a lot our performance.

Magical JS variable variables and easy error detection

At this point you have coded all the hover and click elements, but when you click them nothing happens, of course. Let’s fix it:

// yeah, someone is playing it!
function clicked( color ) {
	// refresh my memory, how long have you gone so far?
	var level = localStorage["level"]; // this is our current level
	var clicks = localStorage["clicks"]; //this is our current item INSIDE one level
	var speed = localStorage["speed"]; //to make it more fun, when you get right it goes faster
	// blink it!
	window['box' + color].stop().animate({ opacity: 0.3 }, (speed * 0.5) ).animate({ "opacity": "1" }, (speed * 0.3) ); //variable variables in js via window[varname] :)
	// well, this time you've got it right?
	if ( localStorage["sequence"][clicks] == color) {
		//oh, yeah!
		//have you finished this level?
		if ( level == clicks) {
	} else {
		//oh, noes!

Every variable in javascript can be accessed via its own name, like box1 OR as an index inside window array, just like window[‘box1′]. With this we can easily select which is the right element to blink (when you click any button, it should blink, right?).

Ok, you are right! Let’s go to the next level

When you get it right, the game should get you to the next level and the events should accelerate a little bit.

Then when you get it right you should also know which is the right sequence at your current level + 1, so let’s do it:

function nextLevel() {
	//Oh, Yes
	showBox("#ohYes", 1000);
	// you deserve it, let's move on

	localStorage["clicks"] = 0;
	//let's show you how it'll be
	current = 0; //since it's used just for animation, let's leave it as global var
	if ( localStorage["speed"] > 300 && (localStorage["level"] / 5) == 0 ) { //our maximum speed, and we'll only acelerate it each 5 levels
		localStorage["speed"] = localStorage["speed"] * 0.8;
	setTimeout( function() { rightPath(); } , localStorage["speed"] );

Function showBox just shows our div and hides it after one second.

As you can see this piece of code isn’t complete, we will need the function rightPath() to see what comes next. Let’s go:

function rightPath() {
	if ( current <= localStorage["level"] ) {
		var sel = localStorage["sequence"][current];
		window['box' + sel].stop().animate({ "opacity": "0.5" }, (localStorage["speed"] * 0.5) ).animate({ "opacity": "1" }, (localStorage["speed"] * 0.3) );
			function() {
			(localStorage["speed"] * (1.5) )
	for (var i=0; i <= localStorage["level"] ; i++) {
		var time = 1000 * (i + 1);
	i = 0;

This is kind of crazy, isn’t it? This is a simple recursive function. It will call itself, blink the right button for one position and then go to the next until we reach user’s current level.

What if you get it wrong?

Maybe instead of click the right button you can just click the wrong button. Then we need to punish you and ban you from the entire world wide web. Let’s see our function for that:

function endGame() {
	//let's see if you have a high score, and save it
	if ( localStorage["hs"] == undefined || localStorage["level"] > localStorage["hs"] ) {
		localStorage["hs"] = localStorage["level"];

	localStorage.removeItem( "level" );
	// Oh, noes!
	showBox("#ohNoes", 2000);

Well, here we just check if you’ve done something better than this play and then remove your current level so you can restart a new game and try a little harder :)

By the way, did I mention how will you start a game? No? Sorry, my bad.

Sorry, NOW the game will begin

What do we have to do in order to start a match is to reset almost anything we have here and then show what is the right path.

// just like starting over!
function newGame() {
	current = 0;
	//let's call our sequence and memorize it
	localStorage["sequence"] = randomSequence();
	//wow, we haven't got anything right until now :)
	localStorage["level"] = 0;
	//clicks binding
	localStorage["clicks"] = 0;
	//let's make things slow for now
	localStorage["speed"] = 1500;
	//let's show our welcome warning
	showBox("#letsRock", 2000);
	//and let's show the first color

What is your best score?

Hope you enjoy this quick HTML5 game tutorial and that you find some easter eggs, you know, since it’s a JS game we can’t hide a lot of things on it :)

But the most important thing here is: what is your best score?

Rochester Oliveira

I'm a web designer and entrepreneur from Itajubá (MG), Brasil. I love writing about obscure topics and doing some cool stuff. And also I do some FREE stuff, check it out:

15 Smart Tools To Help You Build Your Freelance Business

Discover the awesome tools we use in making our clients comfortable and happy in learning new things every day.

Download Now


  1. anon says

    I must be very, very stupid, because I don’t understand the game… can anyone explain it to me?

    • says

      Hi anon,
      In this game you must to do same thing as “Simmon”. So when you click in new game one color will blick. You should click it. If you get right (I hope so :D) then the same color will blink and another one too. So you must to click on first color then second, and so on. As you get right more colors will be added to your “right path”.

      For example:
      1 – Red.
      2 – Red, green.
      3 – Red, green, green.
      4 – Red, green, green, blue.
      5 – Red, green, green, blue, red…


  2. Josh Bedo says

    Awesome post those games are addicting! Thanks for informing me about local storage I knew it was possible but not that easy.

    • says

      Hi Karl, how are you?
      One tip, if you get stuck just type javascript:nextLevel(); in URL bar and you’ll go to next level ;)

      I’ve done 21 once, without cheating! :)))


  3. Joey says

    By the way… this synaxhighlighter popup that is appearing on both of my computer, every browser on this site is annoying… fix please? I want to read some articles! :D

  4. Gavin says

    This is brilliant. I found myself not being able to play it for long though as the colors don’t differ that much from on and off and there is no sounds. I do love the fact you have made this in HTML 5 and css, I’m sure there is other stuff that can be expanded on this to make it even more like the game.

    Excellent work though, really do enjoy these sorts of things, hopefully google will pick it as one of their doodles!?

    • says

      Hi Galvin,
      I really wanted to put some sound on it, but it would slow down too much, so for now we can’t do that.

      About the difference between on / off, there is 50% opacity change.. Maybe if you really want to play it, you could change this to 10%, but 50% it enough for most people…

      But true must to be said, this is just a start point.. I’ve seen myself several improvements that could be done on it!