Ajax Bestiary: A Javascript Field Guide
 
Ajax Bestiary: A Javascript Field Guide
 
 

On the Viability of HTML5 Games

Posted by Dave Mahon

There is sometimes significant rancor within the web development community as we transition from Flash to HTML5/JS for our audio-visual and interactive web content.

Let’s look at what went into a real-world game of Cut The Rope. While it was implemented as a promotional tool for the Windows 8 Store and IE9, ZengaLabs reports that it does work reasonably well on all HTML5-friendly desktop browsers.

First, we have the libraries. They chose jQuery 1.7, plus the FancyBox and the jQuery Easing plugins. To this, they added SoundManager 2 and Modernizr 2.0.6. These weighed in at just under 62KB.

Of course, no website is complete without tracking (Google Analytics in this case), as well as Facebook and Twitter integration, but those libraries are typically hosted remotely and are outside of our control.

This leaves us with a 69.7KB minified JavaScript file, ctr.js. This file contains significant swaths that look like

a.lineTo(32.7,183.4);
a.bezierCurveTo(31.8,176.3,31,168.9,30.3,161.3);


and

$("#resultStar3").removeClass("starEmpty").addClass("star");

What of the HTML? At a scant 4KB, it is largely boilerplate. Of particular interest is this snippet:

// html5 audio is unreliable in many browsers so its only enabled by default on
// IE9 or greater. You can force html5 audio by setting the querystring:
// http://www.cuttherope.ie/?html5audio=true
soundManager.useHTML5Audio = (isIE9OrGreater() || ZeptoLab.ctr.forceHTML5Audio);
soundManager.preferFlash = !soundManager.useHTML5Audio;
 
// initialize the game
ZeptoLab.ctr.run();


Note that we’re still resorting to browser-specific hard hacks. This is an understandable trade-off, though falling back to Flash doesn’t work if you also want to function in mobile environments. Our AV content is still forcing us to produce multiple formats.

It is also interesting to see the game effectively self-enclosed inside of a single object following a Java-like naming convention. This not only exhibits best practices, but also encloses it within a closure, making it harder for the code to be attacked.

The developers also reported another concern. Since the code can easily run before all of the required image and audio assets are loaded and the full game weighs in at 6MB, they needed a loader (much like what you have seen in traditional Flash environments). Happily, they released this original code as PxLoader under an MIT license.

Additional overhead is spent tracking the frame-rate to caution the user when performance suffers.

So what lessons can be drawn from this?

For the most part, once ActionScript developers become familiar with JavaScript development, the code they eventually produce will be fairly straightforward. Libraries abstract out most browser incompatibilities, although concurrent Flash and HTML5 development is still a fact of life unless you can be sure your users are on Internet Explorer 9+, Firefox 4+, Safari 5+, Opera 10+ or Chrome 10+.

It is unfortunate that patents on media formats are actually encumbering innovation among the people who would use them. Effectively, all media must be encoded in a minimum of 4 versions: traditional Flash, Chrome, Safari and MPEG. This is a drain on developer time and resources.

Finally, modern browsers do offer sufficient performance to implement complex interactive content natively within JavaScript. Plugins are no longer required to get work done.

Vibration API coming to Firefox 11

Posted by Dave Mahon

The current Aurora release of Firefox includes the Vibration API, a very simple system for making devices rumble.

The API consists of a single call to navigator.mozVibrate().

The function accepts a single parameter. Pass a positive integer to indicate the number of milliseconds the device should vibrate. Pass an array of these integers to create a vibrate pattern. Finally, pass 0 to stop any current vibration.

navigator.mozVibrate(2000);
//Vibrate for 2 seconds
 
navigator.mozVibrate([1000, 1000, 500]);
//Vibrate for a second.
//Then pause for a second.
//Then vibrate for another half-second.
 
navigator.mozVibrate(0); //An empty array is also valid
//Stop vibrating

Obviously, this is only meaningful on devices that support vibration, like mobile phones, tablets and game controllers. However, in both the Firefox implementation and pending W3C specification, calls are silently ignored when the device does not support vibration or vibration is not allowed.

The W3C added a NotSupportedError that is thrown when invalid values are passed to the function. Obviously, it has also generalized mozVibrate() to navigator.vibrate().

The specification also checks document.hidden before the rumble begins and at any time the visibilitychange event is triggered. If document.hidden is false, any requested vibrations must be ignored and any current vibration must cease immediately. No feedback is provided to your code in either of these events.

This means that spam pages can’t drain your battery (unless you leave the offending page up), a concern expressed on the WebKit mailing list and is implemented as navigator.webkitVibrate() in the development builds of the WebKit core.

Enyo released

Posted by Dave Mahon

HP is slowly open sourcing webOS. Yesterday, they released the Enyo framework with cross-browser support.

The heart of Enyo is the enyo.kind() method which dynamically generates a reusable page component which can be referenced in the global namespace like so:

enyo.kind({
    name: "Hello",
    kind: enyo.Control,
    components: [
        {name: "hello", content: "Hello From Enyo", ontap: "helloTap"},
        {tag: "hr"}
    ],
    helloTap: function() {
        this.$.hello.addStyles("color: red");
    }
};
 
// make two, they're small
new Hello().write();
new Hello().write();

At first glance, this seems like a lot of extra code to create a bit of color-changing text with a horizontal rule. However, you can also define custom properties, events and methods, which suddenly makes this an elegant way to create what jQuery calls plugins. Since you can also encapsulate other generated kinds, this could also be an interesting way of creating entire actors within a game.

While it’s not so performant as to empower, say, a first-person shooter, they do provide a simple demo of a game.

HTTP Header Issue in Mobile Safari Can Break AJAX

Posted by Dave Mahon

Mike Swieton has reported a bug in Mobile Safari on iOS 5.1.

The bug occurs on AJAX-heavy sites that let you download content. Specifically, he experienced it when he clicked to view a PDF inside Mobile Safari and then used the back button to return to the site. Subsequent AJAX requests had the OPTIONS verb instead of the expected GET, something the web server obviously would not expect.

Fortunately, he came up with a fix. If you change the Content-Disposition HTTP header from attachment to inline, the browser does not lose track of the current domain and thus does not change the verb used for AJAX requests.

Page Visibility API

Posted by Dave Mahon

To date, it has not been easy to tell, using JavaScript, whether the user can see your page or not. Sure, we have load, focus, blur and unload, but these have proven quirky and inconsistent in the past. Certain environments give us the ability to jump between windows and tabs, and even scroll pages without giving focus to the browser window. Automatic lock screens leave your web page active, but inaccessible. Further, Google is developing a feature for Chrome wherein a page can load and render before it is made visible to the end user.

If you’ve ever received a message on Facebook when it was the selected tab, but not necessarily the selected window and application, and it hasn’t made a noise, you’ve experienced some of this quirkiness.

So what can you do with this new API? You can slow down your application, suspend timers and clocks, and generally make your page behave better in a cooperative multitasking environment. In short, still more of what used to require Flash to implement no longer does.

Chrome introduced this new, simple API in 13 and the W3C has a group standardizing it. Firefox and IE will both see it added in their respective version 10 browsers.

To use it, you really only need to know two properties and one event.

The document.visibilityState property can be any one of four values, but the two most common (and only required) ones are hidden and visible. Now, when the page loads, you can know whether your content is actually exposed to the user or not.

The document.hidden provides a simple boolean.

Happily, the standards do partially specify how other applications can interact with these properties:

As examples, the attribute returns true when:

  • The User Agent is minimized.
  • The User Agent is not minimized, but the page is on a background tab.
  • The Operating System lock screen is shown.
  • The User Agent is minimized and a preview is shown.

The visibilityChange event will fire when this state changes after the initial page load, so you needn’t check it obsessively.

Note that Chrome uses the webkit prefix for this API, its properties and its event. Firefox and IE are expected to use the W3C version, without prefixes.

HTML5 Interactive Maps for Both Mobile and Desktop

Posted by Dave Mahon

When you think maps, you probably think Google or MapQuest, both of which have interactive maps that are really only optimized for desktop browsers. You have to jump out to a separate app for geo-interactivity (yes, that is an invented word).

That is perhaps why CloudMade released Leaflet, putting it under the BSD license.

As you would expect, it supports tile layers, polylines, markers, popups and image layers. However, it also has native support for panning and zooming on mobile browsers. It also uses CSS3, so you can stylize pins, popups and controls. It’s also fast – noticeably faster than Google Maps – though that is partially because its source data, OpenStreetMap, doesn’t contain quite as much data.

At this time, supports most desktop browsers well, but on mobile environments, it requires iOS 3+ or Android 2.2+.

Implementing a map is very straightforward:

// create a CloudMade tile layer
var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/YOUR-API-KEY/997/256/{z}/{x}/{y}.png',
    cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade',
    cloudmade = new L.TileLayer(cloudmadeUrl, {maxZoom: 18, attribution: cloudmadeAttribution});
 
// initialize the map on the "map" div
var map = new L.Map('map');
 
// set the map view to a given center and zoom and add the CloudMade layer
map.setView(new L.LatLng(51.505, -0.09), 13).addLayer(cloudmade);
 
// create a marker in the given location and add it to the map
var marker = new L.Marker(new L.LatLng(51.5, -0.09));
map.addLayer(marker);
 
// attach a given HTML content to the marker and immediately open it
marker.bindPopup("A pretty CSS3 popup.<br />Easily customizable.").openPopup();

Leaflet generated map

Remote console for mobile web diagnosis

Posted by Dave Mahon

Remy Sharp has developed a tool for remotely debugging web pages. This works using code injection, so be very sure to keep it out of production environments. However, when you need to diagnosis issues remotely, say, because it’s on a mobile device, with limited console support, or because a client is reporting problems that you can’t repeat locally.

Implementing this is a snap!

:listen

This returns an UUID which you will need to insert into the page markup:

&lt;script src="http://jsconsole.com/remote.js?FAE031CD-74A0-46D3-AE36-757BAB262BEA" type="text/javascript"&gt;&lt;/script&gt;

From then on, calls to console.log() will return their output to your listening machine.

The really handy library has one more trick up its sleeve. You can specify the UUID to which you will listen.

:listen FAE031CD-74A0-46D3-AE36-757BAB262BEA

When the remote device loads the debugging module, you’ll see something like this in your console:

:listen FAE031CD-74A0-46D3-AE36-757BAB262BEA
Creating connection...
Connected to "FAE031CD-74A0-46D3-AE36-757BAB262BEA"
Connection established with Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8

Incremental MD5 with AMD support

Posted by Dave Mahon

As we all know, MD5 is a fast hashing algorithm. While its numerous security holes make it undesirable for encryption, it is pervasive and convenient for quickly generating quasi-unique ID’s.

While JavaScript has no built-in support for hashing algorithms, this wheel has been re-invented a lot. So why discuss it here? Most implementations to date have littered the namespace with variables or offered poorer performance than their rivals.

SparkMD5 attempts to remedy this situation. Based on the JKM md5 implementation, it is fast. However, it also keeps namespace pollution to a minimum, with its use of closures and OOP.

In addition, it has two neat tricks up its sleeve.

First, you can incrementally hash strings:

var spark = new SparkMD5();
spark.append('Hi');
spark.append(' there');
var hexHash = spark.end();                    // hex hash
var rawHash = spark.end(true);                // OR raw hash

This is particularly handy for large strings, like what you might get using the FileReader API. Conveniently, Andre Cruz, the developer of SparkMD5, has included the code to do this in the GitHub README.

Second, it optionally supports Asynchronous Module Definition, which can reduce the initial load-time of pages and helps isolate your code from your markup. While AMD is certainly controversial, asynchronous loading of code does seem to be a prevailing trend.

TWSS: Naive Bayes Classifier and k-Nearest Neighbor library for NodeJS

Posted by Dave Mahon

TWSS is an acronym that stands for That’s What She Said, a joke frequently abused by the character Michael Scott on the US version of The Office. Why would anyone write a library that tells you whether or not "That’s what she said!" is an "appropriate" response to a given sentence? Frankly, I don’t know. However, during implementation, he created a generalized document NBC and k-NN tool that runs cleanly inside NodeJS.

In effect, with different training material, this is a powerful tool with an MIT license. Its also potentially very expandable.

So let’s see it in action.

Set the algorithm:

twss.algo = 'nbc';

Set the tolerance threshold:

twss.threshold = 0.5;
twss.is("You're hardly my first."); // false
 
twss.threshold = 0.3;
twss.is("You're hardly my first."); // true

Or, for your customized tool, return the probability:

twss.prob("The juice keeps coming out of the wrong hole!"); // 0.9961630818418142

How do we expand our algorithm selection? Look in /lib/twss.js:

var classify = {
  nbc: require('./classifier/nbc'),
  knn: require('./classifier/knn')
};

As you can see, adding algorithms is primarily a matter of a new file in the classifier subdirectory and adding a member element to the classify object. The new classifier must implement getTwssProbability() and isTwss().

However, you will have to lightly edit exports.probability() and exports.is() to recognize your custom algorithm.

UPDATE My apologies for the links to Wikipedia on the day of the SOPA blackout.

jQ.Mobi: Less compatible, but better performance

Posted by Dave Mahon

The plain reality is that the vast majority of mobile web traffic is on Android and iOS devices. BlackBerry users have, by and large, been so disappointed by the poor web experience out of the box that they tend not to go on the web. Windows smartphones are still a small slice of the mobile market, especially when you focus on 3G and LTE devices, which use the lion’s share of the traffic, at least until Nokia ramps up its smartphone production.

With that in mind, jQ.Mobi saw its first public release on Monday. Its developer, appMobi, calls it a beta.

The core engine and UI is 15KB gripped, which means that even when your user drops to EDGE, they’ll still have a good experience, since you still have 10KB leeway for images and markup. It is also optimized for simulating apps, including support for integration in tools like PhoneGap.

Further, it’s designed to make the interface as consistent as possible between Android and iOS devices, including fixed headers and footers and smooth CSS3 transitions. It’s not quite ready for tablet devices. If you watch the video, the interface during the Kindle Fire segment feels clunky, but they say they are working on tablet-optimized CSS.

In terms of syntax, jQuery users will feel at home. Still, be cautious with jQuery plugins, because while they should be run, many are still optimized for desktop environments and jQ.mobi is not intended for desktop use.

Welcome Developers

Search for what you're looking for or take advantage of the Tools & Resources we’ve assembled to jump start your next project.

 
Tools & Resources