Mozilla

Featured Articles

Sort by:

View:

  1. Getting Started With HTML5 Game Development

    There are plenty of valid ways to create an HTML5 game, and quite a bit of material on the technical aspect of each, so for this article I’ll be giving more of a broad overview of HTML5 game development. How “HTML5″ can be better than native, where to start with the development process, where to go when you’re stuck, and how to monetize and distribute games.

    Benefits of HTML5

    Most of the audience here already sees the value in HTML5, but I want to re-iterate why you should be building an HTML5 game. If you are just targeting iOS for your game, write the game in Objective-C, the cons outweigh the benefits in that scenario… but if you want to build a game that works on a multitude of platforms, HTML5 is the way to go.

    Cross-Platform

    One of the more obvious advantages of HTML5 for games is that the games will work on any modern device. Yes, you will have to put extra thought into how your game will respond to various screen sizes and input types, and yes, you might have to do a bit of ‘personalization’ in the code per platform (the main inhibitor being audio); but it’s far better than the alternative of completely porting the game each time.

    I see too many games that don’t work on mobile and tablets, and in most instances that really is a huge mistake to make when developing your game – keep mobile in mind when developing your HTML5 game!

    Unique Distribution

    Most HTML5 games that have been developed to this point are built in the same manner as Flash and native mobile games. To some extent this makes sense, but what’s overlooked is the actual benefits The Web as a platform adds. It’s like if an iOS developer were to build a game that doesn’t take advantage of how touch is different from a mouse – or if Doodle Jump was built with arrow keys at the bottom of the screen instead of using the device’s accelerator.

    It’s so easy to fall into the mindset of doing what has worked in the past, but that stifles innovation. It’s a trap I’ve fallen into – trying to 100% emulate what has been successful on iOS, Android, and Flash – and it wasn’t until chatting with former Mozillian Rob Hawkes before I fully realized it. While emulating what worked in the past is necessary to an extent, The Open Web is a different vehicle for games, and innovation can only happen when taking a risk and trying something new.

    Distribution for HTML5 games is often thought of as a weakness, but that’s just because we’ve been looking at it in the same sense as native mobile games, where a marketplace is the only way to find games. With HTML5 games you have the incredible powerful hyperlink. Links can so easily be distributed across the web and mobile devices (think of how many links you click in the Facebook and Twitter apps), and it certainly should not just be limited to the main page for the game. The technology is there to be able to link to your game and do more interesting things like jump to a specific point in a game, try to beat a friend’s score, or play real-time against that friend – use it to your advantage!

    Take a good look at was has worked for the virality of websites and apply those same principles to your games.

    Quicker Development Process

    No waiting for compilation, updates and debugging in real-time, and once the game is done, you can push out the update immediately.

    Choosing a Game Engine

    Game engines are just one more level of abstraction that take care of a few of the more tedious tasks of game development. Most take care of asset loading, input, physics, audio, sprite maps and animation, but they vary quite a bit. Some engines are pretty barebones, while some (ImpactJS for example) go as far as including a 2D level editor and debug tools.

    Decide Whether or Not You Need a Game Engine

    This is largely a personal decision. Game Engines will almost always reduce the time it takes for you to create a fully-functional game, but I know some folks just like the process of building everything from the ground up so they can better understand every component of the game.

    For simple games, it really isn’t difficult to build from scratch (assuming you have a JavaScript background and understand how games work). Slime Volley (source) for example was built without having a game engine, and none of the components were rocket science. Of course, Slime Volley is a very basic game, building an RPG from the ground up would likely lead to more hair pulling.

    Choosing Between a “Game Engine” and a “Game Maker”

    Most of the typical audience of Mozilla Hacks are probably going to lean toward using a game engine or building from scratch, but there is also the alternative of using a “Game Maker” like Construct 2. Using a Game Maker means you won’t actually write in JavaScript; instead, you create code-like events in the editor. It’s a trade of ease-of-use and quickness to prototype/develop vs customization and control over the end result. I’ve seen some very impressive games built with either, but as a developer-type, I tend to favor writing from scratch / using an engine.

    Finding the Right Game Engine / Game Maker for you

    There are so many HTML5 game engines out there, which in part is a good thing, but can also be a bad thing since a large percentage have either already stopped being maintained, or will soon stop being maintained. You definitely want to pick an engine that will continually be updated and improved over the years to come.

    HTML5GameEngine.com is a great place to start your search because the hundreds of game engines are narrowed down to about 20 that are established, actively maintained, and have actual games being developed with them.

    For a more complete list of engines (meaning there can be some junk to sift through), this list on GitHub is your best bet.

    Learning Tools

    If you’re going with a game engine, typically their site is the best resource with tutorials and documentation.

    Technical Tutorials

    Game Design Tutorials

    With game development, the technical aspect isn’t everything – what’s more important is that the game actually be fun. Below are a few places to start when learning about game mechanics.

    Helpful Game Tools

    User Retention, Monetization and more

    Full disclosure here: I am a co-founder at Clay.io.

    Making a game function is just part of the equation. You also want players to play longer, come back, tell their friends about it, and maybe even buy something. Common elements in games that focus on these areas are features like user accounts, high scores, achievements, social integration, and in-game payments. On the surface most are typically easy enough to implement, but there are often many cross-platform issues and intricacies that are overlooked. There is also value in having a central service running these across many games – for example, players genuinely care about achievements on Xbox Live because Gamerscore matters to them.

    • Clay.io – user accounts, high scores, achievements, in-game payments, analytics, distribution, and more.
    • Scoreoid – similar to above.

    Development Tools

    • stats.js – A JavaScript performance monitor. Displays framerate, and performance over time.
    • Socket.IO – realtime client-server communication (if you’re going to have a backend for your game).
    • pixi.js – A canvas and WebGL rendering engine.
    • CocoonJS – Improves HTML5 game performance on iOS and Android with an accelerated canvas bound to OpenGL ES.

    Motivation

    Regardless of what you’re building, extra motivation is always helpful. For games, that motivation often comes from surrounding yourself with others who are in the same boat as you – working on games.

    js13kGames

    js13kGames is a competition that is currently taking place at the time of this writing. You have until September 13th, 2013 to develop an HTML5 game that, when compressed, is less than 13kb.

    Mozilla Game On

    Mozilla runs a game competition every year from December through February with some fantastic prizes – last year’s was an all-expense paid, red carpet trip to San Francisco for GDC 2013.

    Clay.io’s “Got Game?”

    Clay.io (full disclosure, I am a founder) runs an annual HTML5 game development competition for students. Last year was the first year and we had over 70 games submitted. The next competition is planned for February / March 2014.

    Ludum Dare

    Ludum Dare isn’t for tangible prizes, nor is is specific to HTML5 games, but there are plenty of HTML5 developers that participate.

    One Game a Month

    One Game a Month isn’t so much a competition as it is an accountability tool. This isn’t restricted to HTML5 games, but many of the participants work with HTML5. The goal is to crank out one game every month. I wouldn’t recommend this long-term since one month is too short of a time to create a great game, but it’s good when learning to force yourself to develop and finish simple games.

    Help From the Community

    HTML5GameDevs.com

    HTML5GameDevs has quickly become the most active community of HTML5 game developers. Most folks are very friendly and willing to help with any issues you run into.

    #BBG

    #BBG is the go-to IRC channel for HTML5 games – you’ll even find quite a few Mozillians hanging around.

    How to Make Money

    In-Game Purchases

    In-game payments, in my opinion, are the way to go for HTML5 game in the long-term. For now, most HTML5 games don’t have enough quality content, nor the game mechanics in place to get player purchasing items.

    This is the revenue model with the highest potential, but it’s also the most difficult to achieve by far – not technically, but having the right game. I’d say the best way to learn how to properly monetize your game in this aspect is to take a look at games that do it really well on Flash and Mobile – games from King.com and Zynga typically have this nailed down pretty well. There’s also some good reading material, like The Top F2P Monetization Tricks on Gamasutra.

    Licensing

    Where we’re at right now with HTML5 games, licensing games is the strongest, most consistent way to make money – if and only if your game works well on mobile devices.

    There are countless “Flash Game Portals” that receive organic mobile traffic, but can’t monetize it with the Flash games they have. Their solution is to go out and find HTML5 games to buy non-exclusive licenses (the right to put the game on their site, often making small adjustments) to offer their mobile visitors.

    Typically non-exclusive HTML5 game licenses (meaning you can sell to more than one site) go for $500-$1,000 depending on the game and publisher. Some publishers will do a revenue share model instead where you’ll get a 40-50% share on any advertising revenue, but no up-front money.

    Licensing is the safest way to make money right now, but the cap is limited – the most you’re going to make with a single game is in the $5,000-$6,000 range, but it is easier to hit that mark than it is with in-game payments or advertising.

    Advertising

    Advertising is the middle-ground between in-game payments and licensing. It’s easier than in-game payments to make money and with a higher potential cap than licensing (but probably less than in-game payments). It’s easy enough to implement ads: just pick your ad network of choice (be wary of Adsense’s strict terms) and implement them either surrounding the game, or at various stopping points.

    The commonly used ad networks are LeadBolt for mobile and CPMStar for desktop. You can also use Clay.io which makes it a bit easier to implement advertising, and tries to maximize the revenue by using different ad networks depending on the device used and other factors.

    Distribution

    The final stage in a game’s development is distribution. The game is done, now you want people playing the game! Fortunately, with HTML5 there are plenty of places to have your game (many of which often go unused).

    More and more marketplaces these days are accepting HTML5 games as-is. Each has their own requirements (Facebook requires SSL, most require a differently formatted manifest file, etc…), but the time it takes to get into each is typically less than 30 minutes. If you want to reduce that even more, Clay.io helps auto-generate the manifest files and promotional image assets you’ll need (as well as takes care of the SSL requirement) – documentation on that here.

    Some marketplaces you’ll need to have a native wrapper for your game – primarily the iOS App Store and Google Play. A wrapper like PhoneGap is one option, but the native webviews have pretty terrible JavaScript engines, so for now you’re better off with tools like CocoonJS and Ejecta.

    Now it’s up to you to go forth and make a great, innovative web game – I’m looking forward to see what’s on the horizon in the coming months and years!

  2. New Features of Firefox Developer Tools: Episode 25

    Firefox 25 was just uplifted to the Aurora release channel which means we are back to report about new features in Firefox Developer Tools.

    Here’s a summary of some of the most exciting new features, and to get the whole picture you can check the complete list of resolved bugzilla tickets.

    Black box libraries in the Debugger

    In modern web development, we often rely on libraries like JQuery, Ember, or Angular, and 99% of the time we can safely assume that they “just work”. We don’t care about the internal implementation of these libraries: we treat them like a black box. However, a library’s abstraction leaks during debugging sessions when you are forced to step through its stack frames in order to reach your own code. To alleviate this problem, we introduced black boxing: a feature where you can tell the debugger to ignore the details of selected sources.

    To black box a source, you can either mark them one at a time by disabling the little eyeball next to it in the sources list:
    eyeball

    Or you can black box many sources at once by bringing up the developer toolbar with Shift+F2 and using the dbg blackbox command:

    dbg blackbox --glob *-min.js[source]

    When a source is black boxed:

    • Any breakpoints it may have are disabled.
    • When “pause on exceptions” is enabled, the debugger won’t pause when an exception is thrown in the black boxed source; instead it will wait until (and if) the stack unwinds to a frame in a source that isn’t black boxed.
    • The debugger will skip through black boxed sources when stepping.

    To see this in action and learn more about the details, check out the black boxing screencast on YouTube.

    Replay and edit requests in the Network Monitor

    You can now debug a network request by modifying headers before resending it. Right-click on an existing request and select the “resend” context menu item:

    resend request

    Now you can tweak the HTTP method, URL, headers, and request body before sending the request off again:

    tweak

    CSS Autocompletion in the inspector

    Writing CSS in the inspector is now much easier as we enabled autocompletion of CSS properties and values.

    autocomplete

    What’s more, it even works on inline style attributes

    inline

    Aside: this feature was implemented by contributors Girish Sharma and Mina Almasry. If you want to take your tools into your own hands too, check out our wiki page on how to get involved with developer tools.

    Execute JS in the current paused frame

    One request we’ve heard repeatedly is the ability to execute JS from the webconsole in the scope of the current paused frame in the debugger rather than the global scope. This is now possible. Using the webconsole to execute JS in the current frame can make it much easier to debug your apps.

    Edit: The webconsole has actually been executing in the current frame since Firefox 23, in Firefox 25 the scratchpad will execute in the current frame as well.

    Import and export profiled data in the Profiler

    Hacking on a shared project and think you found a performance regression in some bit of code owned by one of your friends? Don’t just file a github issue with steps to reproduce the slowness, export and attach a profile of the code that shows exactly how much slowness there is, and where it occurs. Your friend will thank you when he or she is trying to reproduce and debug the regression. Click the “import” button next to the start profiling button to load a profile from disk, and hit “save” on an existing profile to export it.

    profileimport

    When can I use these features?

    All of these features and more are available in the Aurora release channel. In another 12 weeks, these features will roll over into Firefox stable.

    Have some feedback about devtools? Ping @FirefoxDevTools on Twitter, or swing by #devtools on irc.mozilla.org.

  3. WebRTC and the Early API

    In my last article, WebRTC and the Ocean of Acryonyms, I went over the networking terminology behind WebRTC. In this sequel of sorts, I will go over the new WebRTC API in great laboring detail. By the end of it you should have working peer-to-peer DataChannels and Media.

    Shims

    As you can imagine, with such an early API, you must use the browser prefixes and shim it to a common variable.

    var PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
    var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
    var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
    navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;

    PeerConnection

    This is the starting point to creating a connection with a peer. It accepts information about which servers to use and options for the type of connection.

    var pc = new PeerConnection(server, options);

    server

    The server object contains information about which TURN and/or STUN servers to use. This is required to ensure most users can actually create a connection by avoiding restrictions in NAT and firewalls.

    var server = {
        iceServers: [
            {url: "stun:23.21.150.121"},
            {url: "stun:stun.l.google.com:19302"},
            {url: "turn:numb.viagenie.ca", credential: "webrtcdemo", username: "louis%40mozilla.com"}
        ]
    }

    Google runs a public STUN server that we can use. I also created an account at http://numb.viagenie.ca/ for a free TURN server to access. You may want to do the same and replace with your own credentials.

    options

    Depending on the type of connection, you will need to pass some options.

    var options = {
        optional: [
            {DtlsSrtpKeyAgreement: true},
            {RtpDataChannels: true}
        ]
    }

    DtlsSrtpKeyAgreement is required for Chrome and Firefox to interoperate.

    RtpDataChannels is required if we want to make use of the DataChannels API on Firefox.

    ICECandidate

    After creating the PeerConnection and passing in the available STUN and TURN servers, an event will be fired once the ICE framework has found some “candidates” that will allow you to connect with a peer. This is known as an ICE Candidate and will execute a callback function on PeerConnection#onicecandidate.

    pc.onicecandidate = function (e) {
        // candidate exists in e.candidate
        if (e.candidate == null) { return }
        send("icecandidate", JSON.stringify(e.candidate));
        pc.onicecandidate = null;
    };

    When the callback is executed, we must use the signal channel to send the Candidate to the peer. On Chrome, multiple ICE candidates are usually found, we only need one so I typically send the first one then remove the handler. Firefox includes the Candidate in the Offer SDP.

    Signal Channel

    Now that we have an ICE candidate, we need to send that to our peer so they know how to connect with us. However this leaves us with a chicken and egg situation; we want PeerConnection to send data to a peer but before that we need to send them metadata…

    This is where the signal channel comes in. It’s any method of data transport that allows two peers to exchange information. In this article, we’re going to use FireBase because it’s incredibly easy to setup and doesn’t require any hosting or server-code.

    For now just imagine two methods exist: send() will take a key and assign data to it and recv() will call a handler when a key has a value.

    The structure of the database will look like this:

    {
        "<roomId>": {
            "candidate:<peerType>": …
            "offer": …
            "answer": … 
        }
    }

    Connections are divided by a roomId and will store 4 pieces of information, the ICE candidate from the offerer, the ICE candidate from the answerer, the offer SDP and the answer SDP.

    Offer

    An Offer SDP (Session Description Protocol) is metadata that describes to the other peer the format to expect (video, formats, codecs, encryption, resolution, size, etc etc).

    An exchange requires an offer from a peer, then the other peer must receive the offer and provide back an answer.

    pc.createOffer(function (offer) {
        pc.setLocalDescription(offer);
     
        send("offer", JSON.stringify(offer));
    }, errorHandler, constraints);

    errorHandler

    If there was an issue generating an offer, this method will be executed with error details as the first argument.

    var errorHandler = function (err) {
        console.error(err);
    };

    constraints

    Options for the offer SDP.

    var constraints = {
        mandatory: {
            OfferToReceiveAudio: true,
            OfferToReceiveVideo: true
        }
    };

    OfferToReceiveAudio/Video tells the other peer that you would like to receive video or audio from them. This is not needed for DataChannels.

    Once the offer has been generated we must set the local SDP to the new offer and send it through the signal channel to the other peer and await their Answer SDP.

    Answer

    An Answer SDP is just like an offer but a response; sort of like answering the phone. We can only generate an answer once we have received an offer.

    recv("offer", function (offer) {
        offer = new SessionDescription(JSON.parse(offer))
        pc.setRemoteDescription(offer);
     
        pc.createAnswer(function (answer) {
            pc.setLocalDescription(answer);
     
            send("answer", JSON.stringify(answer));
        }, errorHandler, constraints);
    });

    DataChannel

    I will first explain how to use PeerConnection for the DataChannels API and transferring arbitrary data between peers.

    Note: At the time of this article, interoperability between Chrome and Firefox is not possible with DataChannels. Chrome supports a similar but private protocol and will be supporting the standard protocol soon.

    var channel = pc.createDataChannel(channelName, channelOptions);

    The offerer should be the peer who creates the channel. The answerer will receive the channel in the callback ondatachannel on PeerConnection. You must call createDataChannel() once before creating the offer.

    channelName

    This is a string that acts as a label for your channel name. Warning: Make sure your channel name has no spaces or Chrome will fail on createAnswer().

    channelOptions

    var channelOptions = {};

    Currently these options are not well supported on Chrome so you can leave this empty for now. Check the RFC for more information about the options.

    Channel Events and Methods

    onopen

    Executed when the connection is established.

    onerror

    Executed if there is an error creating the connection. First argument is an error object.

    channel.onerror = function (err) {
        console.error("Channel Error:", err);
    };

    onmessage

    channel.onmessage = function (e) {
        console.log("Got message:", e.data);
    }

    The heart of the connection. When you receive a message, this method will execute. The first argument is an event object which contains the data, time received and other information.

    onclose

    Executed if the other peer closes the connection.

    Binding the Events

    If you were the creator of the channel (meaning the offerer), you can bind events directly to the DataChannel you created with createChannel. If you are the answerer, you must use the ondatachannel callback on PeerConnection to access the same channel.

    pc.ondatachannel = function (e) {
        e.channel.onmessage = function () {};
    };

    The channel is available in the event object passed into the handler as e.channel.

    send()

    channel.send("Hi Peer!");

    This method allows you to send data directly to the peer! Amazing. You must send either String, Blob, ArrayBuffer or ArrayBufferView, so be sure to stringify objects.

    close()

    Close the channel once the connection should end. It is recommended to do this on page unload.

    Media

    Now we will cover transmitting media such as audio and video. To display the video and audio you must include a <video> tag on the document with the attribute autoplay.

    Get User Media

    <video id="preview" autoplay></video>
     
    var video = document.getElementById("preview");
    navigator.getUserMedia(mediaOptions, function (stream) {
        video.src = URL.createObjectURL(stream);
    }, errorHandler);

    mediaOptions

    Constraints on what media types you want to return from the user.

    var mediaOptions = {
        video: true,
        audio: true
    };

    If you just want an audio chat, remove the video key.

    errorHandler

    Executed if there is an error returning the requested media.

    Media Events and Methods

    addStream

    Add the stream from getUserMedia to the PeerConnection.

    pc.addStream(stream);

    onaddstream

    Executed when the connection has been setup and the other peer has added the stream to the peer connection with addStream. You need another <video> tag to display the other peer’s media.

    <video id="otherPeer" autoplay></video>
     
    var otherPeer = document.getElementById("otherPeer");
    pc.onaddstream = function (e) {
        otherPeer.src = URL.createObjectURL(e.stream);
    };

    The first argument is an event object with the other peer’s media stream.

    View the Source already

    You can see the source built up from all the snippets in this article at my WebRTC repo.

  4. Don’t miss out on the real-time fun! Use Firefox OS Push Notifications

    Firefox OS v1.1 introduces Push Notifications to Open Web Apps, allowing web developers to take advantage of real-time updates without implementing difficult polling logic themselves. Native Push Notifications support means
    that only one connection has to be maintained by Firefox OS devices, and applications can be shutdown, improving battery life, and device responsiveness, while still offering immediate updates to users.

    Firefox OS Push Notifications are designed for one thing – waking up apps. They do not deal with data, desktop notifications and other features, since there are other Web APIs that provide them. In this Hacks article, we’ll take a look at building a small chat application that uses Push Notifications to update the conversation.

    Scope and workflow

    Before we start on the application, it is a good idea to take a look at the scope and work flow of Push Notifications.

    No polling

    The scope of Push Notifications is to notify web applications on clients that something on the network has changed, so that the data the client has should be updated to the latest data on a remote server. Rather than the application having to constantly poll using XHR or use WebSockets, Push takes over responsibility and notifies the application of the change. This data is usually stored on the application server (in the cloud) and shared on multiple devices distributed amongst one or more user.

    For example, a user can have a personal calendar, which is shared between a laptop, a mobile and a tablet. In addition the user may have a work calendar that is shared with co-workers. A good calendar application on these devices will keep the devices in sync with the ‘master’ calendar on the server. With Push Notifications, Firefox OS devices can now do this sync immediately and be very responsive.

    No data

    Firefox OS Push Notifications do not support sending messages over push. From the very beginning Push Notifications was designed to explicitly not carry a payload. This might seem absurd, but it falls in line with Mozilla’s mission of ensuring its user’s privacy. Multiple organizations will be running Push Servers, and if data was to be allowed on the Push protocol, this data ends up in the hands of these third parties. It is very easy to accidentally leak confidential user data. For example if the chat application sent the actual messages over Push, and a user decided to send his credit card number to another user, the credit card number is now in the hands of the Push Server operator.

    To prevent this, the protocol simply does not allow data. The only application specific data allowed is a version number (optional). This version number is useful for collaborative applications. If a version number is sent, and the client device has already received a message with the same or older version number, it will not be notified again. The version number can be used to merge changes made by the user on this device with changes received from the server.

    Workflow

    Continuing with the calendar example, the flow of push notifications works like this. The mobile application registers for a push endpoint. This push endpoint is a unique URL that represents one channel for receiving updates. These URLs point to a third party Push Server, which is set on the device and may be operated by Mozilla or other organizations or individuals. Each application can have multiple push endpoints (imagine one for each calendar the user has). The mobile application then sends this endpoint to the application server. A calendar server would associate this endpoint with the user and the specific calendar. Every calendar would have a set of endpoints, one for every device of every user that is subscribed to the calendar.

    When any user changes the calendar on his device, the application saves those changes to the server. This is the point at which Push Notifications kick in. The application server will make a HTTP request to every one of the endpoints in the set for the calendar that was modified. Each Push Server now takes responsibility for delivering messages to the devices. When each device receives the notification, it starts the calendar application on the device and notifies it. The calendar app can then go and fetch all the changes from the calendar server.

    NOTE: This URL should be treated as opaque and your application and application server should not make any assumptions about them, nor edit them.

    What happens if my application is not running?

    Push notifications aren’t just a convenience, they are essential to mobile applications that need to keep in sync but may not always be running. If your application is not running when a push notification is received, the application will be started, navigated to the handling page and the message delivered to it. If you open the application switcher after receiving a push, you’ll be able to see the application running in the background.

    Setting up the environment

    There are many resources on writing applications for Firefox OS with proper tooling and using all the facilities provided by the system. The two part hacks series Building a Todo app for Firefox OS is a great example. The chat application will instead be very bare bones. We’ll not concern ourselves with extra tooling like Volo. Nor will the app be very good looking by using standard UX elements. We’ll stick to simple HTML and JavaScript, with only jQuery and Bootstrap to for a few utilities.

    The server will be written in Python, using the Flask framework, which is small and should be easy to understand even if you haven’t used Python before. In addition the server uses Redis for a persistent data store.

    All the code is available on Github.

    Since Push Notifications is available on Firefox OS v1.1 onwards, you’ll currently need preview builds of the Firefox OS Simulator (please note that these are experimental, and not all might work as expected). Paste the URL for your platform into Firefox, install the Simulator add-on and you should be good to go with using Push.

    The stable builds of the simulator on addons.mozilla.org DO NOT have push.

    The app manifest

    Using Push Notifications requires three important entries in the applications manifest.

    The push permission allows the application to use Push Notifications. We also request desktop-notification permission so we can show a notification when a user is mentioned in the chat.

    The messages entries specify which page of the application should be notified when a push notification is received. In this case, since our application is a single page application, we set it to /. Firefox OS v1.1 only allows the page that registers for Push Notifications to recieve them, so you cannot have / call navigator.push.register() and have /push.html be the receiver that uses navigator.mozSetMessageHandler().

    The push message is the message delivered when an actual notification is recieved. The push-register message is a error recovery mechanism. In rare cases the Push Server may suffer data loss or it may decide to free up some old endpoints. In either case, if your application’s endpoints are no longer valid, it will receive a push-register message, in which case your application should register for new endpoints and update the app server.

    The main page

    Our chat application will be a single page application with the latest 50 messages, followed by a field to enter a new message.

    The unordered list chat will hold the chat messages, which will be loaded by JavaScript. theform is used to submit messages. The div nickPrompt is used as a modal dialog to ask the user’s nickname the first time the application is run. Finally we include the various scripts that drive the application.

    Offline web apps

    As web applications are used on mobile devices, it is important to design them such that they can be used offline as much as possible. A common pattern in such a case is to have persistent storage on the client side using localStorage or IndexedDB. This storage is updated when a network connection is available, and the user content is displayed solely from this offline copy. This way the user can always interact with content that is already on the device. Our application follows a similar model. The latest chat messages are stored on the device using IndexedDB. A push notification will first update this local data and then update the UI.

    Chat Database

    The storage is implemented in model.js which abstracts an IndexedDB database to support the operations a simple chat implementation requires. Every message is stored as a object:

    {
      "id": 5, // Integer message ID. Unique for every message.
      "nick": "EdwardSnowden", // The sender of the message.
      "message": "The NSA is spying!" // The actual text.
    }

    Only the latest 50 messages are stored on both the server and the client in a bid to compete against Snapchat.

    The id field is a perfect candidate to use as the version field of the push notifications. In the case of a chat, every message will be new, so the version field is not so important, but we’ll use it for the purposes of demonstration.

    Installing the application

    In Firefox OS v1.1, Push Notifications are only available to applications and not to web pages loaded in the browser. So when the user visits our application in the browser, it will prompt to install the app.

    Registering for Push Notifications

    When the user starts the application, go() is called. This prompts the user for a nickname on the first run, and populates the chat list using any existing messages already available offline.

    The important bit for Push Notifications is this:

    navigator.push is the PushManager object that provides the Push Notifications operations. You can check for

    if ('push' in navigator) {
    }

    to see if the page can use Push Notifications.

    registrations() is used to check if the application has existing endpoints registered. Like several other Firefox OS APIs it returns a DOMRequest object since it is a async operation. On success, the result is a list of PushRegistration objects. A PushRegistration has the following fields:

    interface PushRegistration {
      string pushEndpoint; // A URL specifying the endpoint.
      unsigned long int version; // The latest known version.
    }

    If we have no registrations, we ask for a new registration using navigator.push.register(). On a successful registration, the result field of the DOMRequest will be a URL, which is the endpoint for this registration. Now that we have a endpoint, we use XHR to send it to our server.

    On the server, lets just store all the endpoints in one list called endpoints:

    In addition we send a quick ping to the new endpoint that was added. We use the great Requests library for this, and you can see how easy it is to use Push Notifications on the server. Just do a HTTP PUT request to the endpoint with the body of the request being:

    version=&lt;number&gt;

    The call to navigator.push.register() can fail due to several reasons. The most common is that the device does not have network connectivity. The DOMRequest’s onerror handler will be fired in such a case and the request’s
    error will have a short descriptive name of the error.

    Dispatching notifications

    Every time a new message is posted to the chat, we want to notify all clients via push notifications. When a form is submitted:

    the server is sent the message text and the sender’s nickname.

    We request an id for the message from Redis using the INCR atomic command. We also want to enforce two things on the server:

    1. Keep the messages sorted by this message id, so we can quickly serve messages from a certain ID onwards. For this we use Redis’ sorted sets with the score as the message id. This keeps it sorted, and allows us to quickly fetch messages from a certain ID onwards, so that clients do not have to download all messages but we do not have to maintain individual queues for clients.
    2. Restrict the messages to the latest 50 (MAX_MESSAGES). We do this by truncating the set using ZREMRANGEBYRANK.

    We use redis-py‘s pipeline system to do both of these atomically so that if adding fails, so does removing older messages. Your language/framework will have similar operations to achieve this consistency.

    The message itself is stored as a string of the JSON representation so that sending messages to clients is just a matter of extracting elements and concatenating them into a JSON list.

    After that we put the new message id in the notification_queue. This brings us to a best practice when using push notifications. The application server will often be notifying multiple endpoints about changes. In such a case, blocking the main server is a bad idea, Instead you should have a dedicated thread or process that can ping endpoints. This can even be moved off to a dedicated machine. The version number system allows you to parallelize the pinging.

    In this simple server, we’re using Python’s builtin Queue which lets us implement a producer-consumer system. The thread that notifies the push server is started in app.py and runs the notify() function:

    The notify() function blocks on the notification_queue. When a new message id is available, it loops through all the endpoints and notifies them of the new version.

    A successful PUT will result in a 200 OK response from the endpoint. This means the notification has been queued for delivery. When the device is online and connected to the Push Server, delivery happens within a few seconds.

    The server’s job is done! Now the application has to handle the push notification.

    Receiving push notifications

    Receiving push notifications is done by setting a function to be invoked when the ‘push’ message is received. This is done using mozSetMessageHandler. NOTE: The page that sets the receiver and the page listed as the message
    receiver in the manifest file must match!

    After the model is successfully initialized we set the handler. message will be a:

    interface PushMessage {
      string pushEndpoint; // The push endpoint that changed.
      unsigned long int version; // The new version.
    }

    The pushEndpoint allows the app to identify which endpoint (among the many it
    may have registered) has changed.

    In this case, we just want to use this version to download new chat messages if required.

    model.latest() returns the latest message ID in our local storage, and we download new messages only if the version of the push notification is newer.

    The server has a /message/<id> REST interface, which given a message ID will return all the messages after it:

    It simply uses the message ID as the sorted set score and returns a JSON response.

    On the client, we update the local storage. To handle mentions, we also loop through the new messages received and check if any of the messages have the user’s nickname. If one is found, a desktop notification is created containing the message, so that the user notices a presumably important message.

    Finally the UI is updated:

    Since old messages have to be removed from view, we remove all the list items and add new ones. Modern Web Runtimes will do only one repaint even if multiple new elements are added to the DOM, as long as they are all added at once. So there is no flickering. Here too, we give messages mentioning the user a different colour.

    A little thing to handle is the push-register message. If you remember, I mentioned that this is a error recovery mechanism that may be invoked.

    Our demo application simply shows an error to the user, but ideally you’d silently register for new endpoints in the background.

    Unregistering

    A very common design pattern with push notifications is to associate one endpoint per user, where the user has a unique ID in your application and application server (such as an email ID). In that case your application may be designed to support switching users. In this case you no longer want to receive notifications when something of interest to the old user happens. There may be other situations in which you are no longer interested in a push endpoint. The way to express this lack of interest is to use navigator.push.unregister().

    // Assuming pushEndpoint1 is the endpoint associated with an old user
    var request = navigator.push.unregister(pushEndpoint1);

    unregister() returns a DOMRequest whose onsuccess will fire as soon as the registration is deleted by Firefox OS. It is extremely unlikely that a call to unregister() will fail. The most likely cause of failure is that the endpoint is not a valid endpoint that was issued to the application by Firefox OS.

    Good design: Decouple Push from the user flow

    Although the most common use of Push Notifications for web apps will be to show a desktop notification to the user, the process of push registration, receiving pushes, and unregistering should be kept out of the user’s UI flow as
    much as possible. This is most applicable during registration.

    Similar to progressive enhancement of the Web Application user experience, your app should be ready to deal with lack of Push notifications. For example, you should not block the user from signing into your application simply because navigator.push.register() failed due to lack of connectivity. Instead, let the user continue to use the offline part of your application and queue the registration request to try again after some time. The Alarm API is useful to wake your application up later to finish such ‘background’ tasks.

    Similarly, data heavy applications should not wait around for the user to respond to a desktop notification before they fetch data. A good calendar application will immediately go and update its local storage on receiving a push. Only then will it pop up any reminders so that as soon as the user launches the application, he immediately sees new events and changes. At the same time it should unregister() endpoints if the user selects a manual sync option.

    Important security considerations

    The push endpoint obtained from register() should be kept secret! The best way to do this is:

    1) Always send endpoints to the application server over a secure (https) connection. Otherwise an attacker could perform a man-in-the-middle attack and capture endpoints going over the wire.

    2) Keep your database secure. The endpoints should be just as well protected as users personal data.

    If an attacker were to gain access to endpoints, he or she could affect devices that have those endpoints. For example they could cause your application to run frequently, affecting the user experience. Or they could do a push to the endpoint with a very high version number so that subsequent valid pushes that your application server does will not be passed on to the app.

    Connections between the Push Server and the devices are always over a secure connection and thus there can be a reasonable expectation of safety on that part of the exchange.

    With that we’ve taken a short tour of the Firefox OS Push Notifications API. It will be exciting to see how you developers will leverage this to create fantastic web applications.

    The Push Notifications team may be reached on the #push IRC channel on irc.mozilla.org.

    Extras

    Push Notification delivery guarantees

    Push Notifications is a best effort system. The Push Server will try to inform a device of the latest version it has received for an endpoint. This means that updates are collapsed. If a endpoint is updated to version 254 while the device is offline, and then updated to 255, and then the device comes online, it will receive only the update for 255. When device and server end up in a inconsistent state that cannot be fixed, push-register is usually fired to allow applications to reset itself. Despite these precautions, there are rare situations in which:

    Notifications may fail to be delivered

    If the device has been offline for more than a few days (a week or more), the Push Server may drop pending notifications to conserve its resources. In such a case, the device will not receive updates after it comes back online until the application server sends new updates. This is possible if the user is travelling on roaming and switches off mobile data.

    If the device battery dies or the device crashes just as the notification is being delivered to the application, the application will miss that notification. This is extremely rare.

    push-register may not be delivered

    push-register may not be delivered even after the Push Server has reached an inconsistent state with the device.

    If the device was offline when the Push Server lost state, the Push Server may not be able to inform the device that all state was lost when it comes back online.

    For most applications the above should not be a problem since they will occur very rarely. If your application requires more reliability, you can mitigate the above possibilities by using a few other methods to sync. One way is to acquire new endpoints periodically rather than waiting for a push-register. The other way is to use the Alarm API to do an unconditional synchronization with the application server after an extended period of time. For example, the application would use push to receive regular updates, but set an alarm for midnight every day when it would go and fetch updates regardless of the push status.

    Statuatory warning about experimental nature

    The Push Notifications API for Firefox OS is experimental. One of the major changes coming in newer versions of Firefox OS will be a switch away from DOMRequest to Promises. Until Bug 800431 is fixed, the page calling register() will have to be the same one that handles the notifications (‘push’ system message). In the future we would like to add support for background services or workers to handle notifications instead. This will ensure that no UI is launched unless the application requests it. There may be additional features added and in an extremely rare case, existing APIs may change.

    While Mozilla will do its best to not break existing applications, developers should be aware of and plan for changes that may be required to their applications.

  5. WebRTC and the Ocean of Acronyms

    My experience getting started with WebRTC can be summarised in a three letter acronym so I decided to write this article dedicated to answering my many questions. I’ve always said, if you don’t know an acronym, it’s probably a networking protocol.

    What is ICE?

    Interactive Connectivity Establishment (ICE) is a framework to allow your web browser to connect with peers. There are many reasons why a straight up connection from Peer A to Peer B simply won’t work. It needs to bypass firewalls that would prevent opening connections, give you a unique address if like most situations your device doesn’t have a public IP address, and relay data through a server if your router doesn’t allow you to directly connect with peers. ICE uses some of the following techniques described below to achieve this:

    What is STUN?

    Session Traversal Utilities for NAT (STUN) (acronym within an acronym) is a protocol to discover your public address and determine any restrictions in your router that would prevent a direct connection with a peer.

    The client will send a request to a STUN server on the internet who will reply with the client’s public address and whether or not the client is accessible behind the router’s NAT.

    What is NAT?

    Network Address Translation (NAT) is used to give your device a public IP address. A router will have a public IP address and every device connected to the router will have a private IP address. Requests will be translated from the device’s private IP to the router’s public IP with a unique port. That way you don’t need a unique public IP for each device but can still be discovered on the internet.

    Some routers will have restrictions on who can connect to devices on the network. This can mean that even though we have the public IP address found by the STUN server, not anyone can create a connection. In this situation we need to turn to TURN.

    What is TURN?

    Some routers using NAT employ a restriction called ‘Symmetric NAT’. This means the router will only accept connections from peers you’ve previously connected to.

    Traversal Using Relays around NAT (TURN) is meant to bypass the Symmetric NAT restriction by opening a connection with a TURN server and relaying all information through that server. You would create a connection with a TURN server and tell all peers to send packets to the server which will then be forwarded to you. This obviously comes with some overhead so is only used if there are no other alternatives.

    What is SDP?

    Session Description Protocol (SDP) is a standard for describing the multimedia content of the connection such as resolution, formats, codecs, encryption, etc so that both peers can understand each other once the data is transferring. This is not the media itself but more the metadata.

    What is an Offer/Answer and Signal Channel?

    Unfortunately WebRTC can’t create connections without some sort of server in the middle. We call this the Signal Channel. It’s any sort of channel of communication to exchange information before setting up a connection, whether by email, post card or a carrier pigeon… it’s up to you.

    The information we need to exchange is the Offer and Answer which just contains the SDP mentioned above.

    Peer A who will be the initiator of the connection, will create an Offer. They will then send this offer to Peer B using the chosen signal channel. Peer B will receive the Offer from the signal channel and create an Answer. They will then send this back to Peer A along the signal channel.

    What is an ICE candidate?

    As well as exchanging information about the media (discussed above in Offer/Answer and SDP), peers must exchange information about the network connection. This is know as an ICE candidate and details the available methods the peer is able to communicate (directly or through a TURN server).

    The entire exchange in a complicated diagram

    image

  6. Firefox OS Simulator 4.0 released

    It’s a good day for Firefox OS developers as we are releasing version 4.0 of the Firefox OS Simulator to the masses. In particular, this release is a boon for those developers that want to make money using their app in the Marketplace.

    What’s New in 4.0

    4.0 Updated Simulator Dashboard
    An overview shot of the revised Dashboard

    New Connect Button

    There is a new ‘Connect’ button for each app that opens a developer toolbox connected to that specific app. This means that you won’t have to search through messages in the Console or filter through scripts in the Debugger in order to find information specific to your app.

    Testing Receipts for Paid Apps

    There is now a dropdown menu in each app’s dashboard where you can select a receipt type. The simulator add-on will then download a test receipt from a Marketplace receipt service and reinstall the app using it. This way you can test receipt verification with the various types of receipts that you may require – valid, invalid, and refunded.

    4.0 Updated Simulator Dashboard Buttons
    The new Connect button, Refresh Button, and Receipts drop-down

    Remote CSS Styling

    If you connect to an app while using a Nightly or Aurora build of Firefox, there is a Style Editor tool you can use to edit the style sheets for your app. Changes are applied instantaneously.

    4.0 Updated Simulator Live Style Editing
    Live editing the Firefox OS Boilerplate app to have a less than charming red background

    Simulated Touch Events

    Gaia’s touch events simulation has been integrated such that interacting with the Simulator using a mouse now generates real touch events. This fixes a myriad of issues in core Gaia apps that assume touch interactions. It also means you can test third party apps that rely on touch events without needing to fall back to mouse events.

    Hidden Feature: Shift-Ctrl/Cmd-R

    When using the keyboard shortcut Ctrl-R (Cmd-R on Mac) to refresh an app, if you also hold down the Shift key, then the Simulator will clear persistent data such as AppCache, localStorage, sessionStorage, and IndexedDB while refreshing the app.

    Check Out The Simulator Walkthrough

    Still want to get into grittier details? Check out the simulator walkthrough to get a deep dive into the details of the Simulator, and the MDN documentation here.

    Download and Install the Simulator

    You can install or update the Simulator from the add-ons website.

    Bugs? Feedback?

    Leave general feedback in the comments below, we’re listening! If you encounter a bug we would be grateful if you could file it here.

  7. Firefox OS devices officially released!

    Almost two years ago, we announced Boot to Gecko (B2G) here on Mozilla Hacks. We discussed the aims of the project and the work we were planning to do. Today, all that work has paid off and we now have official Firefox OS devices in store!

    Last week the first Firefox OS phones went out in stores in Madrid, Spain, for sale by Telefónica. These phones are a great example of a low-cost telephone built on Open Web Technologies.

    Firefox OS launch pics, Madrid, Spain

    It means that if you haven’t gotten started at looking how to build your apps or your content with HTML5 and Responsive Design, now is the time, to have the chance to be among the early options in a brand new market.

    Coming to more countries

    Telefonica’s launch in Spain was the first for Firefox OS, but Poland, Colombia and Venezuela also have upcoming launches soon. It doesn’t stop there, though, look out for more countries coming soon.

    Open Web Apps

    Firefox OS runs the web and has a web browser, but if you want to offer an app-like experience, get access to more hardware and APIs and more, building an Open Web App could be a perfect option for you.

    Firefox OS launch pics, Madrid, Spain

    Reuse your existing HTML5 skills and content and just package it up. We’ve outlined Open Web Apps and new possibilities in detail in previous articles:

    The Firefox OS Simulator

    Tool-wise, we believe the Firefox OS Simulator is a great option to quickly test your apps.

    Version 4 is just about to be released – more details in the announcement this Thursday, July 11th – but the list of highlights include:

    • New Connect Button, to have a developer toolbox connected to your specific app(s)
    • Remote Style Editor, enable remote style editing
    • Hidden Feature: Shift + Ctrl/Cmd-R, refreshing the app and clearing persistent data (AppCache, localStorage, sessionStorage, and IndexedDB)
    • Updated Dashboard Design, reduced clutter and improved usability
    • Touch Events, integrating Gaia’s touch events simulation, so interacting with the Simulator using a mouse now generates real touch events

    Introducing payments

    As part of the Firefox OS offering, we have the Firefox Marketplace, where you can upload and share your apps. We are also happy to say that if you are interested in accepting payments for your app, this is the place!

    They are described in the Payments page as part of the Developer Hub aimed at app developers, and we’ve also written about them here before in Building A Paid App For Firefox OS.

    We have two kinds of payment options in the Firefox Marketplace:

    • Purchase an app
    • In-app payments

    Firefox OS is here

    All in all, Firefox OS is here available on released devices, and we hope the capabilities for you as an Open Web Developer to offer good content and experiences sound good. We are continuously working on making the options and possibilities as good as we can for you!

  8. Network Monitor, now in Firefox Beta

    The Firefox Developer Tools team is particularly proud announce that Firefox 23 (in Firefox Beta, to be released today) ships with an initial but very functional Network Monitor tool that not only provides similar functionality to other tool sets, but in many improves on them. This important step is the result of lots of hard work from the entire team, but in particular Victor Porof and Mihai Sucan.

    Let’s get started

    To give you the best idea of how the network monitor works, here’s a series of steps to follow:

    1. Download, install and run Firefox 23 beta if you haven’t already (or Firefox Aurora or Firefox Nightly – more on Firefox and the release channels).
    2. Open the Network Monitor tool:
      • from the menu: Tools => Web Developer => Network
      • from the keyboard: Ctrl + Alt + Q (Windows/Linux) or Cmd + Alt + Q (Mac OS X)
    3. Load an interesting site.

    As Firefox loads the page you’ll see each individual request get added as a row, much as you would expect from other tools. In particular it is now very easy to visualize not just how quickly parts of the page load and in what order, but also where problems are: missing assets, slow web servers, buggy apis.

    As you get used to using the Network Monitor, you’ll also notice that you don’t need to necessarily hit refresh on a page that is already loaded, once you open the network tool any subsequent requests that happen will be logged. For example, if you’re interested in xhr requests made by an app, just open the monitor and start clicking buttons – you should see any api calls logged as normal without needing to reload.

    Status at a glance

    One thing you should notice right away about the way the Network tool displays a page load is that we’ve taken care to provide both information and design cues to show you what is happening at a glance as the page loads:

    We’ve tried to create a clean UI that delivers key aspects of how an entire page loads without creating too much visual clutter:

    • An error such as a 404 are colored dark red to make them stand out visually from the green successful or yellow cached requests.
    • The url is parsed out and only the file name and domain are shown.
    • By default the load is sorted in chronological order, but you can also sort by any of the top columns, for example by domain or filename.
    • You can easily see the type of request, whether it be html content, an image or an API request.
    • You can click on the column headers to sort requests by method, file name, domain, type or size.

    It’s all in the details

    Once all the page’s assets have been loaded, clicking on a single request opens up the sidebar view which provides detailed information about that request, broken down into panels that display different aspects of a given request: Headers, Cookies, Parameters, Response and Timings. Similar to how the Inspector tool works, this panel is responsive and will neatly pop down below the request list if you’ve docked the tools to the right side:

    A quick tour

    The Headers panel is particularly useful for debugging asset caching problems, and this panel provides parsed lists for both the request and response headers that also supports filtering based on either name or value:

    The Timings panel gives you a detailed, visual breakdown of where time was spent for the selected request. Is it DNS? Is it the server itself?

    If you’re debugging API requests or form posts, you’ll really like how we’ve parsed out the url parameters in the Params panel:

    Are you using a lot of API calls to improve the responsiveness of your app? JSON responses are parsed and displayed as a navigable object in the Response panel to make it easy to check on the data coming back from the server. You can filter the data based on JSON values as well.

    Next Steps

    It’s great to deliver the Network Monitor to a much wider set of developers in Firefox 23 Beta but we haven’t stopped adding new features in the meantime. Firefox 24 ( now in the Aurora channel ) features several notable improvements that have landed in the last 6 weeks or so:

    • You can now filter requests based on the request ‘type’, including XHR, images, html.
    • POST request parameters are supported in the Params panel.
    • You can browse the list of requests via the Up/Down arrow keys.
    • Many more bug fixes and refinements!
  9. WebRTC comes to Firefox

    As we mentioned in the Hacks blog back in April , WebRTC will be on by default in Firefox 22. getUserMedia (gUM) has been on by default since Firefox 20. PeerConnection and DataChannel, which enable video/audio calling and peer-to-peer data sharing, are what’s new in Firefox 22 (due to be released today).

    WebRTC brings real-time communication to the web for the first time ever, and we’re excited to get this new technology into the hands of developers. We believe the industry has only scratched the surface of what’s possible with WebRTC, and only by getting it into the hands of developers and early adopters will we see this technology’s true potential.

    Known issues/limitations

    There are a few known issues/limitations in the early releases:

    • We are initially focused on getting 1:1 calling working well. We’ve done nothing to prevent conference or mesh calling, but depending on the capabilities of your device, video calls with multiple participants may be sluggish. We will be improving multi-person calling in future releases. Our roadmap includes full support for multi-person/conference/mesh calling and we expect to improve the experience in future releases.
    • You may hear echo on calls when you or the party you’re talking to is playing sound over your computer speakers. We’re working on improving echo cancellation but for the time being, try wearing headphones if you experience this problem.
    • On some systems, you may experience audio delay relative to the video. We’ve isolated the problem and are working on a fix for a near-term Firefox release.
    • If you are behind a particularly restrictive NAT or firewall, you may have trouble connecting. We are adding support for media relaying (TURN) in Firefox 23, so you should find this improving soon.

    Trying WebRTC support today

    If you’d like to try out Firefox’s WebRTC support today, here are some sites that support WebRTC calling:

    NOTE: most of these sites support 3 or more callers. We expect basic 1:1 (2-person) calling to perform well enough for developer and early adopter use. As mentioned above, you may find that your mileage may vary with 3-or-more person calling using the current release.

    If you’re a developer interested in embedding WebRTC video chat into your website, please check out article on that.

    Testing DataChannels

    You can also try out DataChannels in Firefox, which is the first browser to launch a spec-compliant implementation of DataChannels to the market. Some sites and projects that use DataChannels:

    Using Firefox Nightly to test the latest

    I still encourage developers to use Firefox Nightly because it has the latest and greatest code and improvements, and we will be continuing to improve existing features and add new ones as we get feedback from developers and users and as the WebRTC standard itself evolves.

    Rapid progress!

    We expect new WebRTC sites, supporting PeerConnection and DataChannels, to come online rapidly over the next several months. We’ll keep you updated on our progress and on WebRTC’s progress here on Mozilla Hacks.

  10. Optimizing your JavaScript game for Firefox OS

    When developing on a quad core processor with 16 gigabytes of RAM you can easily forget to consider how it will perform on a mobile device. This article will detail some best practices and things to consider for moving a game to Firefox OS or any similar hardware target.

    Making the best of 256 Mb RAM/800 Mhz CPU

    There are many areas of focus to keep in mind while developing a game. When your goal is to draw 60 times a second, garbage collection and inefficient drawing calls start to get in your way. Let’s start with the basics…

    Don’t over-optimize

    This might sound counter-intuitive in an article about game optimization but optimization is the last step; performed on complete, working code. While it’s never a bad idea to keep these tips and tricks in mind, you don’t know whether you’ll need them until you’ve finished the game and played it on a device.

    Optimize Drawing

    Drawing on HTML5 2D canvas is the biggest bottleneck in most JavaScript games, as all other updates are usually just algebra without touching the DOM. Canvas operations are hardware accelerated, which can give you some extra room to breath.

    Use whole-pixel rendering

    Sub-pixel rendering occurs when you render objects on a canvas without whole values.

    ctx.drawImage(myImage, 0.3, 0.5)

    This causes the browser to do extra calculations to create the anti-aliasing effect. To avoid this, make sure to round all co-ordinates used in calls to drawImage using Math.floor or as you’ll reader further in the article, bitwse operators.

    jsPerf – drawImage whole pixels.

    Cache drawing in an offscreen canvas

    If you find yourself with complex drawing operations on each frame, consider creating an offscreen canvas, draw to it once (or whenever it changes) on the offscreen canvas, then on each frame draw the offscreen canvas.

    myEntity.offscreenCanvas = document.createElement(“canvas”);
    myEntity.offscreenCanvas.width = myEntity.width;
    myEntity.offscreenCanvas.height = myEntity.height;
    myEntity.offscreenContext = myEntity.offscreenCanvas.getContext(“2d”);
     
    myEntity.render(myEntity.offscreenContext);

    Use moz-opaque on the canvas tag (Firefox Only)

    If your game uses canvas and doesn’t need to be transparent, set the moz-opaque attribute on the canvas tag. This information can be used internally to optimize rendering.

    <canvas id="mycanvas" moz-opaque></canvas>

    Described more in Bug 430906 – Add moz-opaque attribute on canvas.

    Scaling canvas using CSS3 transform

    CSS3 transforms are faster by using the GPU. Best case is to not scale the canvas or have a smaller canvas and scale up rather than a bigger canvas and scale down. For Firefox OS, target 480 x 320 px.

    var scaleX = canvas.width / window.innerWidth;
    var scaleY = canvas.height / window.innerHeight;
     
    var scaleToFit = Math.min(scaleX, scaleY);
    var scaleToCover = Math.max(scaleX, scaleY);
     
    stage.style.transformOrigin = "0 0"; //scale from top left
    stage.style.transform = "scale(" + scaleToFit + ")";

    See it working in this jsFiddle.

    Nearest-neighbour rendering for scaling pixel-art

    Leading on from the last point, if your game is themed with pixel-art, you should use one of the following techniques when scaling the canvas. The default resizing algorithm creates a blurry effect and ruins the beautiful pixels.

    canvas {
      image-rendering: crisp-edges;
      image-rendering: -moz-crisp-edges;
      image-rendering: -webkit-optimize-contrast;
      -ms-interpolation-mode: nearest-neighbor;
    }

    or

    var context = canvas.getContext(‘2d’);
    context.webkitImageSmoothingEnabled = false;
    context.mozImageSmoothingEnabled = false;
    context.imageSmoothingEnabled = false;

    More documentation is available on MDN for image-rendering.

    CSS for large background images

    If like most games you have a static background image, use a plain DIV element with a CSS background property and position it under the canvas. This will avoid drawing a large image to the canvas on every tick.

    Multiple canvases for layers

    Similar to the last point, you may find you have some elements that are frequently changing and moving around whereas other things (like UI) never change. An optimization in this situation is to create layers using multiple canvas elements.

    For example you could create a UI layer that sits on top of everything and is only drawn during user input. You could create game layer where the frequently updating entities exist and a background layer for entities that rarely update.


    Don’t scale images in drawImage

    Cache various sizes of your images on an offscreen canvas when loading as opposed to constantly scaling them in drawImage.

    jsPerf – Canvas drawImage Scaling Performance.

    Be careful with heavy physics libraries

    If possible, roll your own physics as libraries like Box2D don’t perform well on low-end Firefox OS devices.

    When asm.js support lands in Firefox OS, Emscripten-compiled libraries can take advantage of near-native performance. More reading in Box2d Revisited.

    Use WebGL instead of Context 2D

    Easier said than done but giving all the heavy graphics lifting to the GPU will free up the CPU for greater good. Even though WebGL is 3D, you can use it to draw 2D surfaces. There are some libraries out there that aim to abstract the drawing contexts.

    Minimize Garbage Collection

    JavaScript can spoil us when it comes to memory management. We generally don’t need to worry about memory leaks or conservatively allocating memory. But if we’ve allocated too much and garbage collection occurs in the middle of a frame, that can take up valuable time and result in a visible drop in FPS.

    Pool common objects and classes

    To minimise the amount of objects being cleaned during garbage collection, use a pre-initialised pool of objects and reuse them rather than creating new objects all the time.

    Code example of generic object pool:


    Avoid internal methods creating garbage

    There are various JavaScript methods that create new objects rather than modifying the existing one. This includes: Array.slice, Array.splice, Function.bind.

    Read more about JavaScript garbage collection

    Avoid frequent calls to localStorage

    LocalStorage uses file IO and blocks the main thread to retrieve and save data. Use an in-memory object to cache the values of localStorage and even save writes for when the player is not mid-game.

    Code example of an abstract storage object:


    Async localStorage API with IndexedDB

    IndexedDB is a non-blocking API for storing data on the client but may be overkill for small and simple data. Gaia’s library to make localStorage API asynchronous, using IndexedDB is available on Github: async_storage.js.

    Miscellaneous micro-optimization

    Sometimes when you’ve exhausted all your options and it just won’t go any faster, you can try some micro-optimizations below. However do note that these only start to make a difference in heavy usage when every millisecond counts. Look for them in your hot game loops.

    Use x | 0 instead of Math.floor
    Clear arrays with .length = 0 to avoid creating a new Array
    Sacrifice some CPU time to avoid creating garbage.
    Use if .. else over switch
    jsPerf – switch vs if-else
    Date.now() over (+ new Date)
    jsPerf – Date.now vs new Date().getTime() vs +new Date
    Or performance.now() for a sub-millisecond solution
    Use TypedArrays for floats or integers (e.g. vectors and matrices)
    gl-matrix – Javascript Matrix and Vector library for High Performance WebGL apps

    Conclusion

    Building for mobile devices and not-so-strong hardware is a good and creative exercise, and we hope you will want to make sure your games work well on all platforms!