Time to get hacking – Introducing Rec Room

It’s no secret that the best frameworks and tools are extracted, not created out of thin air. Since launching Firefox OS, Mozilla has been approached by countless app developers and web developers with a simple question: “How do I make apps for Firefox OS?” The answer: “It’s the web; use existing web technologies.” was—and still is—a good answer.

But if you don’t already have an existing toolchain as a web developer, I’ve been working on extracting something out of the way I’ve been creating web apps at Mozilla that you can use to write your next web app. From project creation to templating to deployment, Mozilla’s Rec Room will help you create awesome web apps in less time with more ease.

Rec Room is a Node.js utility belt you can wear to build client side web apps. It includes:

  • Brick to add components like appbars and buttons to your UI.
  • Ember for your app’s controllers, models, and views.
  • Handlebars to write your app’s templates.
  • Grunt to run the tasks for your app, including building for production.
  • I18n.js to localize your app.
  • Mocha to test your app.
  • Stylus to write your CSS.
  • Yeoman to scaffold new code for your app’s models and templates.

In this post I’ll walk through how to create a simple world clock web app with Rec Room, how to deploy it, and how you can try out Rec Room for yourself.

Where Does Rec Room Come From?

Much of Rec Room came from a recent rewrite of the HTML5 podcast app. I started working on this app well over a year ago, but its original version wasn’t as easy to work on; it had a lot of global state and a lot of by-hand data-binding. I liked the look of Ember for app development, but back when I started it didn’t quite feel mature enough. These days it’s much better, and I’ve tweaked it in Rec Room to work perfectly without a server.

I tried to take the best from that system and extract it into a set of tools and documentation that anyone can use.

Create your own Rec Room app

Rec Room has just recently been extracted from my experiences with Podcasts; it hasn’t been tested by more than a handful of developers. That said: we’d love your help trying to build your own app for Firefox OS using these tools. They integrate well with tools you probably already know and use–like Node.js and Firefox’s own Web IDE.

To get started, install Rec Room using Node.js:

npm install -g recroom

Clock App

We’ll create a simple clock app with (minimal) time zone support for our example. The app will let you have a clock and compare it with a few time zones.

The recroom binary is your entry point to all of the cool things Rec Room can do for you. First, create your app using recroom new world-clock. This creates the basic app structure. To see the basic app skeleton that Rec Room creates we can now enter that directory and run our app: cd world-clock and then type recroom run. The app will open in your default browser.

First, we’ll add the current time to the main tab. Rec Room supports Ember’s MVC app structure, but also offers simple “pages” for a controller without a 1:1 relationship to a model. We’ll generate a new page that will show our actual clock:

recroom generate page Clock

We can edit its template by opening app/templates/clock.hbs. Let’s change clock.hbs to include the variable that will output our local time:

<h2>Local Time: {{localTime}}</h2>

That won’t do much yet, so let’s add that variable to our ClockController, in app/scripts/controllers/clock_controller.js:

WorldClock.ClockController = Ember.ObjectController.extend({
    localTime: new Date().toLocaleTimeString()
});

You can see that any property inside the controller is accessible inside that controller’s template. We define the 1ocalTime property and it gets carried into our template context.

Now our clock app will show the current local time when we navigate to http://localhost:9000/#clock. Of course, it just shows the time it was when the controller was initialized; there is no live updating of the time. We should update the time every second inside the controller:

WorldClock.ClockController = Ember.ObjectController.extend({
    init: function() {
        // Update the time.
        this.updateTime();
 
    // Run other controller setup.
        this._super();
    },
 
    updateTime: function() {
        var _this = this;
 
        // Update the time every second.
        Ember.run.later(function() {
            _this.set('localTime', new Date().toLocaleTimeString());
            _this.updateTime();
        }, 1000);
    },
 
    localTime: new Date().toLocaleTimeString()
});

Now we can go to our clock URL and see our clock automatically updates every second. This is thanks to Ember’s data-binding between controllers and templates; if we change a value in a controller, model, or view that’s wired up to a template, the template will automatically change that data for us.

Adding Timezones

Next, we want to add a few timezones that the user can add to their own collection of timezones to compare against local time. This will help them schedule their meetings with friends in San Francisco, Buenos Aires, and London.

We can create a timezone model (and accompanying controllers/routes/templates) with the same generate command, but this time we’ll generate a model:

recroom generate model Timezone

We want each timezone we’re to include in our app to have a name and an offset value, so we should add them as model attributes. We use Ember Data for this, inside app/scripts/models/timezone_model.js:

WorldClock.Timezone = DS.Model.extend({
    name: DS.attr('string'),
    offset: DS.attr('number')
});

Next we’ll want a list of all timezones to offer the user. For this we’ll grab a copy of Moment Timezone. It’s an awesome JavaScript library for dealing with dates and times in JavaScript. We’ll install it with bower:

bower install moment-timezone --save

And then add it to our app inside app/index.html:

<!-- build:js(app) scripts/components.js -->
<!-- [Other script tags] -->
<script src="bower_components/moment/moment.js"></script>
<script src="bower_components/moment-timezone/builds/moment-timezone-with-data-2010-2020.js"></script>
<!-- endbuild -->

Adding that tag will automatically add moment-timezone-with-data-2010-2020.js to our built app. We’ll add a tab to the page that lets us edit our timezones, on a different screen than the clocks. To add a tab, we just need to open app/templates/application.hbs and add a tab. While we’re there, we’ll change the main tab from the useless {{#linkTo 'index'}} and point it to {{#linkTo 'clock'}}. The new application.hbs should look like this:

<x-layout>
  <header>
    <x-appbar>
      <h1>{{t app.title}}</h1>
    </x-appbar>
  </header>
  <section>
    {{outlet}}
  </section>
  <footer>
    <x-tabbar>
      <x-tabbar-tab>
        {{#link-to 'clock'}}Clock{{/link-to}}
      </x-tabbar-tab>
      <x-tabbar-tab>
        {{#link-to 'timezones'}}Timezones{{/link-to}}
      </x-tabbar-tab>
    </x-tabbar>
  </footer>
</x-layout>

Side note: notice the root URL points to a useless welcome page? We probably want the default route to be our ClockController, so we can set the index route to redirect to it. Let’s do that now, in app/scripts/routes/application_route.js:

WorldClock.ApplicationRoute = Ember.Route.extend({
    redirect: function() {
        this.transitionTo('clock');
    }
});

Interacting with Timezone models

We’ll keep things simple for our example and allow users to select a timezone from a <select> tag and add it with a button. It will show up in their list of timezones, and they can delete it if they want from there. The clock tab will show all times. First, we’ll add our timezone data from Moment.js into our TimezonesController in app/scripts/controllers/timezones_controller.js. We’re also going to implement two actions: “add” and “remove”. These will be used in our template:

WorldClock.TimezonesController = Ember.ObjectController.extend({
    init: function() {
        var timezones = [];
 
        for (var i in moment.tz._zones) {
          timezones.push({
              name: moment.tz._zones[i].name,
              offset: moment.tz._zones[i].offset[0]
          });
      }
 
      this.set('timezones', timezones);
 
      this._super();
  },
 
  selectedTimezone: null,
 
  actions: {
      add: function() {
          var timezone = this.store.createRecord('timezone', {
              name: this.get('selectedTimezone').name,
              offset: this.get('selectedTimezone').offset
          });
 
          timezone.save();
      },
 
      remove: function(timezone) {
          timezone.destroyRecord();
      }
  }
});

So we create a list of all available timezones with offsets. Then we add methods that allow us to add or remove timezones from our offline data store. Next we modify the timezones template in app/templates/timezones.hbs to use the actions and variables we created. All we need to utilize these variables is the Ember SelectView and the {{action}} helper to call our add and remove methods:

<h2>Add Timezone</h2>
 
<p>{{view Ember.Select content=timezones selection=selectedTimezone
       optionValuePath='content.offset' optionLabelPath='content.name'}}</p>
 
<p><button {{action add}}>Add Timezone</button></p>
 
<h2>My Timezones</h2>
 
<ul>
  {{#each model}}
    <li>{{name}} <button {{action remove this}}>Delete</button></li>
  {{/each}}
</ul>

Now we have a Timezones tab that allows us to add and remove Timezones we want to track. This data persists between app refreshes. The last thing we need to do is show these times relative to our local time in our clock tab. To do this we need to load all the Timezone models in the ClockRoute. They’re automatically loaded in the TimezonesRoute, but it’s easy to add them in the ClockRoute (in app/scripts/routes/clock_route.js):

WorldClock.ClockRoute = Ember.Route.extend({
    model: function() {
        return this.get('store').find('timezone');
    }
});

Because of the way our Ember app is wired up, we load all our models in the route and they are sent to the controller once the data store has asynchonously loaded all of the models. The request to find('timezone') actually returns a Promise object, but Ember’s router handles the Promise resolving for us automatically so we don’t have to manage callbacks or Promises ourselves.

Now we have access to all the user’s Timezones in the ClockController, so we can make times in each timezone the user has requested and show them in a list. First we’ll add each Timezone’s current time to our ClockController in app/scripts/controllers/clock_controller.js using Moment.js:

WorldClock.ClockController = Ember.ObjectController.extend({
    updateTime: function() {
        var _this = this;
 
        // Update the time every second.
        Ember.run.later(function() {
            _this.set('localTime', moment().format('h:mm:ss a'));
 
            _this.get('model').forEach(function(model) {
                model.set('time',
                          moment().tz(model.get('name')).format('h:mm:ss a'));
            });
 
            _this.updateTime();
        }, 1000);
    }.on('init'),
 
    localTime: moment().format('h:mm:ss a')
});

Our final app/templates/clock.hbs should look like this:

<h2>Local Time: {{localTime}}</h2>
 
<p>
  {{#each model}}
    <h3>{{name}}: {{time}}</h3>
  {{/each}}
</p>

And that’s it! Now we have an offline app that shows us time zones in various places, saves the data offline, and updates every second without us having to do much work!

Command Line Tools

The old Podcasts app used a (rather awful) Makefile. It wasn’t very useful, and I don’t think it ran on Windows without some serious effort. The new build system uses Node so it runs comfortably on Windows, Mac, and Linux. Commands are proxied via the recroom binary, also written in Node, so you don’t have to worry about the underlying system if you don’t need to modify build steps. recroom new my-app creates a new app; recroom serve serves up your new app, and recroom generate model Podcast creates a new model for you.

To build your app, you just need to run recroom build and a version with minified CSS, JS, and even HTML will be created for you in the dist/ folder. This version is ready to be packaged into a packaged app or uploaded to a server as a hosted app. You can even run recroom deploy to deploy directory to your git repository’s GitHub pages branch, if applicable.

See the app in action!

This entire sample app is available at worldclock.tofumatt.com and the source code is available on GitHub.

Try Using Rec Room for Your Next Web App

You can try out Rec Room on Github. Right now some docs and tools are still being abstracted and built, but you can start building apps today using it and filing bugs for missing features. We’d really love it if you could give it a try and let us know what’s missing. Together we can build a cohesive and polished solution to the all-too-common question: “How do I build a web app?”

About Matthew Riley MacPherson

Matthew Riley MacPherson (aka tofumatt) is a Rubyist living in a Pythonista's world. He's from Canada, so you'll find lots of odd spelling (like "colour" or "labour") in his writing. He has a serious penchant for pretty code, excellent coffee, and very fast motorcycles. Check out his code on GitHub or talk to him about motorcycles on Twitter.

More articles by Matthew Riley MacPherson…

About Robert Nyman [Editor emeritus]

Technical Evangelist & Editor of Mozilla Hacks. Gives talks & blogs about HTML5, JavaScript & the Open Web. Robert is a strong believer in HTML5 and the Open Web and has been working since 1999 with Front End development for the web - in Sweden and in New York City. He regularly also blogs at http://robertnyman.com and loves to travel and meet people.

More articles by Robert Nyman [Editor emeritus]…


23 comments

  1. Mario Valente

    Now all we need is for Mozilla to wake up and spin us a serverside JS environment out of Spidermonkey as an alternative to the asynchronous NodeJS callback hell.

    August 18th, 2014 at 11:05

    1. Fawad Hassan

      I also wish if we had a serverside technology like Node.js but I think starting such project is waste of effort.

      JavaScript do provide solutions for callback hell like Promises, Generators, and async/await (currently w3c draft). Take a look at Koa framework (koajs.com) which make of generators extensively to avoid complexities of async coding style.

      August 18th, 2014 at 11:30

    2. Nick Desaulniers

      Changing the runtime engine won’t change the language. See ES6 Promises.

      August 18th, 2014 at 16:11

  2. No Thanks

    Wow, I can’t wait to use all the popular web kludges to build a mobile app. Oh wait – yes I can. Web technology sucks and Mozilla should feel bad for perpetuating it’s usage.

    Why don’t you build a platform that is geared towards making applications instead of being a slave to the bad decisions of the past?

    August 18th, 2014 at 15:22

    1. Robert Nyman [Editor]

      We believe that the web, with standardized features and possibilities by all parties, is key to having a medium for everyone. We want the web to be available and a first-class citizen on all platforms.

      “Web technology sucks and Mozilla should feel bad” is quite a sweeping statement, but any constructive feedback that could help making web technologies better, let us know.

      August 19th, 2014 at 01:14

  3. sudarshan

    Hey I installed Mozilla’s Rec Room. But while running the command (recroom new world-clock) in current directory it always displays a recroom file instead of creating basic template.
    Can you provide us the Path which worked for you so that i can make a try on that again..!!
    Great one and Web OS is turning in to new steps.

    August 19th, 2014 at 05:43

    1. tofumatt

      I’d be happy to help fix this with you; would you mind reporting it as an issue (https://github.com/mozilla/recroom/issues/new)? If you can show what files are created when you run the commands that would be great. Thanks!

      August 19th, 2014 at 05:45

      1. WM

        I have the same problem, it just created a empty folder.
        And the command line output keep holding at:
        “Creating your Rec Room project. This may take some time…”

        August 19th, 2014 at 23:12

        1. tofumatt

          This looks like it might be a bug for first time yeoman users we’re tracking over on the issues page and I’m looking to roll out a fix today or tomorrow :-)

          August 20th, 2014 at 06:40

  4. Michael Niemann

    I’m not a programmer. Let me get that out of the way. I’ve made one app that’s in the marketplace and I made that with a text editor and the app manager in Firefox, writing each line and following the examples on a ton of websites (including MDN). I’ve used the flipbox module from Brick before it was changed it into something that required node.js

    I apologize for asking this question here since it is most likely not the right place. But I’m not sure where else to ask it. What does node.js and everything else that seems to require it actually do for me that is better than simply writing a js file, a css file and an html file?

    Maybe I should ask where I can ask this question.

    August 19th, 2014 at 15:04

    1. tofumatt

      Here is fine to ask! :-)

      It sounds like, for you, the simple solution of HTML, css, and JS is the best option and that’s great. I think for a LOT of people it will be, and of course it depends on the project. I think the templates that ship in the new WebIDE fit your description. But for many people I’ve heard that they want something more full featured. I know it’s what I need to be productive.

      For me, these requirements let me build offline apps with complex routing, model interactions, and more easily. If your needs are simple then you’re set, but if your needs are complex I’m hoping these tools simplify things.

      August 19th, 2014 at 15:24

      1. Michael Niemann

        Thanks for your reply. It clarified things for me. I’m interested in learning new ways of doing things, but I when I see posts like this one, I get this feeling I am missing something important. I guess I’ll know why my needs aren’t simple anymore.

        August 20th, 2014 at 08:19

    2. Andrew Fallows

      Much of the premise of tools like Node, Ember, Stylus, and the rest of the tools in collections like Rec Room comes down to one thing: Making the development process faster.

      Every single advanced, modern web application built on top of something like EmberJS could technically have been written in pure JavaScript with no extra tools on top. After all, once it reaches the browser, it’s nothing but HTML, CSS, and JS – all the stuff gets compiled and interpreted down. The advantage of the tools these is that it takes the developer less time to get to the same level of completeness/functionality.

      Naturally, the tradeoff is that it takes more time to learn the extra tools, it introduces more places for your development process to fail (compilation errors in addition to logic errors, etc).

      For people who have one specific goal, especially a small project, a lot of this stuff can be bloated overhead; learning the tool might take more time than solving problems without it. For people (like me) who regularly develop large applications with very common, repeated patterns in how we manage content, tools that simplify implementation of those patterns save us hours every week.

      August 21st, 2014 at 10:17

      1. Robert Nyman [Editor]

        Thanks Andrew for a very good description about needs and options!

        August 22nd, 2014 at 00:26

  5. Lucas

    Hello and thank you.
    I tried to follow this tutorial and when I try to access localhost:9000/#clock for the first time ember throws “The route clock was not found” in the console.
    I looked at your code on github and it had some stuff on “router.js” and some other files that mine didn’t.
    I don’t know if this is something “recroom generate page” should be doing or if it’s a step you skipped on this tutorial, but either way something probably needs fixing.

    I know my way around JS and would love to help contribute to this project, as it aims to solve a problem newcomers to webdev (such as myself) suffer. A “standard development kit” backed by mozilla is all I could ever hope for.

    I don’t understand much of ember and MVC in general but’ll try to follow the development of this project as close as I can. Thank you for your time devoted into this!

    August 20th, 2014 at 13:39

    1. Lucas

      I actually figured it out myself. The recroom script calls the main app instance “App” instead of “WorldClock”. Also you have to add

      this.resource(‘clock’);

      to your router.js.

      Thanks!

      August 20th, 2014 at 16:43

  6. gasolin

    FYR I’ve made webapp template that a bit similar to rec room but also support Chrome apps and per-commit lint check https://webapplate.github.io/

    August 24th, 2014 at 15:49

    1. Robert Nyman [Editor]

      Very cool! I’ve e-mailed you to talk more about it.

      August 25th, 2014 at 00:19

  7. Martin

    The EmberJS team is currently developing a tool with a similar mission as Rec Room: http://www.ember-cli.com/

    It should be easy to make a Rec Room using Ember CLI. As far as I understand, in comparison, it seems only the Brick and I18n.js integrations are missing. But those could be easily added using Bower. Also, they are using Broccoli instead of Grunt, which is said to perform better as an asset pipeline.

    Won’t it make more sense to join forces on this one in the future? So you can stand upon the shoulders of the (seemingly larger) EmberJS community.

    August 25th, 2014 at 00:27

    1. Robert Nyman [Editor]

      Thanks for the input! I’ll talk to tofumatt and we’ll get back to you.

      August 25th, 2014 at 01:22

    2. tofumatt

      Right now, Ember CLI is just too “beta” and in such active development that it wasn’t feasible to use *today*. The docs themselves state: Although potentially exciting, this is still really a WIP, use at your own risk. In the future maybe we can use ember-cli and integrate more with them, but for right now Grunt and Yeoman are more stable.

      Ember does a LOT of what I want recroom to be able to do, but I’m okay using something that works better right now over using bleeding edge Ember stuff that may be more idiomatic.

      Of course, as more people contribute to and use recroom we’ll evaluate changing out components. If I picked the wrong thing I hope people will correct it and make this thing better, and in the future I’d certainly like to contribute more to make Rec Room as close to the Ember stack so we can jointly solve problems. We have talked with the Ember folks briefly about this and in the future I think using Ember CLI will be what Rec Room does, but just not yet ^_^

      August 26th, 2014 at 10:29

  8. Adam

    Isn’t Ember.JS too bloated for Firefox OS? I prefer a minimalistic Riot.JS.
    How does Brick compare with Firefox OS Building Blocks?

    August 28th, 2014 at 15:01

  9. maitreya

    I can’t seem to get past the initial clock controller setup. There are a few
    variations between the tutorial and mine. Instead of the WorldClock.ClockController, I have App.ClockController in clock_controller.js.

    Not sure why this is happening. Oh and I noticed these two errors, in the console:
    “The route clock was not found” ember.js:3285
    “The URL ‘/clock.index’ did not match any routes in your application

    I would appreciate it someone can look into this.

    Thanks!

    September 6th, 2014 at 10:44

Comments are closed for this article.