Building HTML5 games

with PhoneGap,
JavaScript, and CSS3

Jason Kadrmas

Who am I?

University of Minnnesota
Sr. Software Developer

Random Fact

I have done a cfdump followed by a cfflush.

What is this talk not about?

Sorry, we will not be building Halo today.

Ok, then what is this talk about?

I don't want to give it away but think less Halo.

HTML5 Gaming 101


  • Bitmap based
  • Pixels are rgba (0-255)
    [255, 255, 255, 255]
  • Easiest to redraw every frame
  • You do the work
  • Performance issues

HTML5 Gaming 101

DOM - Document object model

  • Representation of objects within a HTML document
  • Browser does the work
  • Build the same as a web app!

HTML5 Gaming 101

Crazy Movements
Crazy Detail
  Simple Transforms
Simple Detail

Choosing your stack

  • DOM Manipulation
  • State Management
  • Animation/Game Engine
  • Templating

Choosing your stack

Crazy amount of options!

DOM State Animation Template
Zepto Backbone Zepto underscore
jQuery Spine Mobile jQuery jQuery tmpl
Native Sencha Crafty.js mustache
jQuery Mobile Impact handlebars

My Usual Stack

Note: this is my personal preference.
Like a favorite ice cream cone.
If you have a great combo feel free to disregard.

DOM State Animation Template
Zepto Backbone Zepto underscore

But Why?

DOM Animation
Zepto Zepto

	// Zepto: Small about 7.4k, Better performance for mobile.
	// jQuery Mobile: 4640 function calls at startup.

	// Touch Events (tap, swipe, pinch)
	$('some selector').swipe(function(){ ... });

	// Animation uses CSS3 transforms under the hood
	$('some selector').animate({scale: '0'}, 10000, 'ease-in', callback);

	// Environmental Info, dirty UA sniff but can be useful
	$.os.ios      // => true if running on Apple iOS
	$  // => true if running on Android

But Why?

State Template
Backbone Underscore

	// Backbone has a built in routing system. Adds much needed structure.
	var MyGameRoutes = Backbone.Router.extend({
		routes: {
		  "help": "help",
		  "game": "game"

		help: function() { /* Help screen logic */ },
		game: function() { /* Game play logic */ } 

	// MVC architecture on the client.
	var GameView = Backbone.View.extend({});
	var GameModel = Backbone.Model.extend({});

	// Underscore provides ERB Style templates.
	var list = "<% _.each(enemies, function(name) { %> <li><%= name %></li> <% }); %>";
	_.template(list, {enemies : ['Goomba', 'Koopa Troopa', 'Bowser']});

	=> HTML output from above
	<li>Koopa Troopa</li>


For all those things you cannot do WELL with
HTML, CSS, and JavaScript.


Accelerometer, Geolocation, Camera,
Media, Push Notifications, etc.

    document.addEventListener("deviceready", onDeviceReady, false);

    function onDeviceReady() {
        // Now safe to use the PhoneGap API

Note: before using any PhoneGap feature be sure to listen for the ready event.

PhoneGap API

Setting up a development environment

Doesn't everyone code like this?

Same as building a web app

Use whatever IDE, tools, processes that
you are comfortable with.

Mobile Boilerplate

  • Cross-platform compatible (Android, iOS)
  • Fights against blank page syndrome

 * Author: Jason Kadrmas
 * Style.css

/* NOW WHAT? */


Set up a local project domain

Separating work and play.

Hosts File

	// Edit hosts file, Mac: /etc/hosts, Win: c:\windows\system32\drivers\etc\hosts mario.local

Virtual Host - Apache

	// Add a virtual host to apache.
	<VirtualHost *:80>
		DocumentRoot "/Users/kadrm002/Sites/mario_game"
		ServerName mario.local

Testing on Mobile

  1. Webkit inspector
  2. Simulators
  3. Live on device

Each harder to debug than the previous.
Continually testing at all stages will help.

Quick & dirty Ant build script

A target for each device

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="mario_game">
<property name="publish.revision" value="1.0"/>
<property name="project-name" value="mario_game" />
<property name="iphone.dir" value="${basedir}/../../iOS Workspace/mario/www" />
<property name="android.dir" value="${basedir}/../../workspace/mario/www" />
<property name="src.dir" value="${basedir}/www" />
<target name="android_deploy" description="Deploys to Android based PhoneGap project.">
    <echo message="Copying to ${android.dir}" />
    <copy todir="${android.dir}">
        <fileset dir="${src.dir}">
            <exclude name="**/.svn/**" />
            <exclude name="**/.gitignore/**" />
            <exclude name="**/build.xml" />

<target name="iphone_deploy" description="Deploys to iOS based PhoneGap project.">
    <echo message="Copying to ${iphone.dir}" />
    <copy todir="${iphone.dir}">
        <fileset dir="${src.dir}">
            <exclude name="**/.svn/**" />
            <exclude name="**/.gitignore/**" />
            <exclude name="**/build.xml" />
            <exclude name="**/phonegap-1.4.0.js" />

Building a game


  • Devices are not the same size!
  • Typography use em's. Not pixels
  • CSS percentages / independent grid system


	var APP = {
	  width: window.innerWidth,
	  height: window.innerHeight,

	  calcWidth: function(pct) { return Math.floor(APP.width * pct); },
	  calcHeight: function(pct) { return Math.floor(APP.height * pct); },

	  resize: function(w, h) {
		APP.width = Math.floor(w);
		APP.height = Math.floor(h);

	// --------------------------------------
	// Create bee at 6% the size of game.
	// --------------------------------------

	var beeSize = APP.calcWidth(0.06),
            bee = $('#bee');
        bee.css({width:beeSize, height:beeSize});


Simple example of viewport scaling

Looking for more detail?

Backbone Stage Manager


Spelling Bees Demo

Organize your game into scenes


<script id="gameover_tmpl" type="text/x-jquery-tmpl">
    <div class="gameoverSection">
        <h3>Game Over</h3>
        <div class="hiscore">Congrats new high score!</div>
        <div class="gameoverMenu">
            <a href="javascript://" id="restartLevel">Restart Level</a>
            <a href="javascript://" id="backToMain">Back to Main Menu</a>

<script id="levelhiscore_tmpl" type="text/x-jquery-tmpl">
    <div class="level-hiscore">High Score : <%=hiscore%></div>
    <div class="level-hiscore">Overall High Score : <%=overallhiscore%></div>

// Invoking template from javascript.
var template = document.getElementById('levelhiscore_tmpl').innerHTML;
_.template(template, { hiscore:500, overallhiscore: 1000 });

Sample "Game Over" screen templates

Game Animation

  • Transitions
  • Sprite Sheets
  • Game Loop

Game Animation


  • Uses CSS entirely to animate
  • Progress info not available

#mario-transition {
  -webkit-transition: all 1s ease-out;  /* Saf3.2+, Chrome */
     -moz-transition: all 1s ease-out;  /* FF4+ */
      -ms-transition: all 1s ease-out;  /* IE10 */
       -o-transition: all 1s ease-out;  /* Opera 10.5+ */
          transition: all 1s ease-out;

    /* Omitting other prefixes for clarity */
    -webkit-transform: rotate(0deg) scale(1.0); 

#mario-transition:hover {
    -webkit-transform: rotate(-360deg) scale(1.7); 

Game Animation

Sprite Sheets

Uses CSS background-position
property to animate with JavaScript.

/* Starting frame to stand left. */
background-position: -50px 0;

/* Frames to animate running right. */
background-position: -300px 0;
background-position: -325px 0;
background-position: -350px 0;
background-position: -375px 0;

Game Animation

Game Loop

When simple animation won't do.

    // Shim for cross browser animation.
    window.requestAnimFrame = (function(){
      return  window.requestAnimationFrame       || 
              window.webkitRequestAnimationFrame || 
              window.mozRequestAnimationFrame    || 
              window.oRequestAnimationFrame      || 
              window.msRequestAnimationFrame     || 
              function( callback ){
                window.setTimeout(callback, 1000 / 60);
    // Animation loop that keeps requesting a new animation frame
    function animloop(){

    // Render one frame of the game
    function render() {

    	// Update our game elements
    	mario.x += 5;
    	world.x -= 5;


Game Animation

Putting it all together


Saving data


  • Local Storage or Web SQL Adapters
  • Makes client storage easy
  • Written by brianleroux (nitobi)

var chair = new Lawnchair({name:'mario_game'}, function(store) {

    // Save an object{
	key: 'game_state',

// Access it later... Yes even after a page refresh!
chair.get('game_state', function(game_state) {

Performance Tips

Consider Library size

HW Acceleration

    // Magic Bullet						

    // Chrome

    // iOS Simulator
    CA_COLOR_OPAQUE=1 /Developer/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone\\ Simulator

Deploying your game

Apple App Store

  • $99/year developer license
  • Mangage through iTunes Connect
  • Choose keywords wisely!
  • 3 - 4 days to publish


  • $25 on Android Market, free for nook, Kindle Fire
  • Instant publish on Android Market
  • 1 month publish to Nook
    1 week publish to Fire


Related Links