Create a Native Application with NW.js

Creating a Desktop App with HTML, CSS and JavaScript


March 18, 2015 Jean-Philippe Côté
published in

The NW.js project lets you create apps with full native capabilities in HTML, CSS and JavaScript. Even better, it lets you access all Node.js modules directly from the browser environment. This means your web-platform-based application can now retrieve input from sensors or control hardware devices. This is the perfect environment for physical computing projects!

About NW.js

NW.js (previously know as node-webkit) “lets you call all Node.js modules directly from DOM and enables a new way of writing applications with all Web technologies”. Basically, NW.js lets you create native-looking desktop apps (Mac, Windows & Linux) that can be written entirely using HTML, CSS and JavaScript. Because it is based on Google Chrome’s V8 engine and Node.js, you can use regular browser/DOM JavaScript code enhanced with any Node.js-compatible modules. What is so great about Node.js modules, at least from a physical computing standpoint, is that they provides access to external sensing and actuating devices. For instance, there are modules to talk to MIDI devices, connect to microcontrollers, use all sorts of sensors, control robots and drones, etc. Furthermore, you get full access to the local file system and native windowing without any of the security hassles usually imposed by the browser’s security sandbox. This is pretty amazing stuff. 

Coding

For the sake of the demonstration, we will be coding a simple app that draws a big red dot on screen. Moving the mouse’s cursor up shrinks the red dot, moving it down enlarges it. It is a super simple project but it will allow us to go through all the basic steps. First, let’s create a folder for our project. In that folder, we need to create an HTML page that will be the entry point into the app. Let’s create one with a single fullscreen  canvas element:

Then let’s write some JavaScript code in the linked script.js file to draw our red dot on screen (and control its size):

Testing

Once our page and script are ready, we must add a package.json manifest file to configure how NW.js will display our app:

The options listed above are pretty self-explanatory. There are many more if you need specialized behaviour but only the first two ( main and name) are needed. Obviously, the “main” directive must point to your primary HTML page. If you want a fullscreen window, as is often the case with physical computing projects, simply set "fullscreen": true  in the “window” section. You also have the option to enter kiosk mode through the  package.json  file with "kiosk": true.

Once configuration is done, we are left with a project folder containing three files:

  • index.html
  • script.js
  • package.json

To be able to easily launch our application we are only missing one thing: the  nw  executable files. Download them for your platform. Once downloaded, you need to copy the necessary files within your project folder. On Mac OS X, simply copy the  nwjs.app file to the project folder. On Linux and Windows, copy all files extracted from the downloaded package to the project folder. Once this is done, if you are on Mac or Windows, you simply need to double-click the executable ( nwjs.app or  nw.exe) to start your application. If you are on Linux, run  nw from the command line. That’s it!

There are more details on how to manually run and package apps for distribution on the GitHub wiki.

Debugging

To debug the application, you can open Chromium’s Developer Tools by clicking on the icon in the top right of the window (version 0.12 and below) or pressing the F12 key on Windows/Linux or CMD-ALT-I on Mac (version 0.13 and above):Developer Tools on MacDevelopment Tools on WindowsAlternatively, it is possible to programmatically open the developer tools. Here’s how to do it in version 0.12 an below:

For version 0.13 an above:

Windows & Screens

NW.js will let you create native chrome or chromeless-windows very easily. NW.js’ window object extends EventEmitter. This means you can use  Window.on() to listen for native events. Here are a few things you can do:

The  Window.open() method accepts, as a second parameter, an object containing configuration options. Any option that can be used in the manifest file’s ( package.json) window property can be used here. You can get all details about using windows here. Something that’s very common in physical computing is to have multiple video outputs. The Screen API provides information about all available screens. This makes it possible to position windows to match the actual video output configuration. The  Screen object is a singleton that needs to be initialized. Once initialized, you can retrieve an array of all screens through its screens property:

Each screen in the array has the following structure and information:

The bounds represent the physical screen resolution. The positions do not necessarily start at 0 and can be negative depending on the screen arrangement. The  Screen object also extends  EventEmitter which means it dispatches events ( displayAdded, displayRemoved, displayBoundsChanged ) that can be listened to with the  gui.Screen.on() method.

And more…

All of that is already pretty amazing and we have not even mentioned the built-in or third-party Node modules. Just to give you an idea, the built-in modules cover areas such as:

  • filesystem access
  • sockets
  • process management
  • cryptography
  • etc.

But, perhaps, even more exciting are the countless third-party modules. There are so many that it makes your head spin. Here are a few examples of particular interest to those who foray into the physical computing world:

  • cylon: a framework to interact with robots, drones, and various devices such as the LeapMotion controller, Skynet communication network, Tessel microcontroller, Nest thermostat, Neurosky biosensor, Pebble watch, etc;
  • opencv: a set of bindings to the very capable open source computer vision library;
  • serialport: a library to work with the serial port;
  • johnny-five: a hardware programming framework that can be used with Arduino, Electric Imp, Beagle Bone, Intel Galileo & Edison, Linino One, Pinoccio, Raspberry Pi, Spark Core, TI Launchpad and more;
  • webmidi: an easier way to use the Web MIDI API to send and receive MIDI commands;
  • tuio: support for the TUIO protocol particularly used with multitouch and tactile interaction devices;
  • osc: support for the Open Sound Control protocol very common in musical software and instruments;
  • phidgets : support for Phidgets interface boards which can be used to connect various sensors and actuators.

… and about a gazillion more!

Conclusion

As you can probably tell by now, most of the fun with NW.js comes from the fact that  it lets you combine the power of browser libraries and Node.js modules. This means you could, for instance, gather sensor input with the phidgets Node module and dynamically generate 3D objects with Three.js. Or, you could gather geographical data through the Google Maps API and fly an ARDrone quadcopter with cylon.js. Crazy stuff…

If you are curious to see know how to do the same with Electron, Esdras Lopez ported the code in this tutorial to Electron. Check it out on GitHub.

Downloads

If you want, you can download the full source code (for NW.js version 0.12) of the above example as a zip package.


The background shapes in the header image are from Frederik Vanhoutte and are used in accordance with the Creative Commons license.


7 Comments

  • Marcus

    Hey this is a great tutorial thanks for that!

    There is a little mistake in the package.json in line 19 after fullscreen is a comma which shouldnt be there i guess. At least my nw instance complained about it and after i removed it everything worked just fine.

    Thanks again for your work

  • EL

    Easy to follow and very well explained. Thanks for the great tutorial Jean!

Post a comment

Your email address will not be published.