Skip to content
Bangle.js App Loader (and Apps)
JavaScript HTML
Branch: master
Clone or download
Latest commit a70182d Feb 13, 2020

Bangle.js App Loader (and Apps)

Try it live at

How does it work?

  • A list of apps is in apps.json
  • Each element references an app in apps/<id> which is uploaded
  • When it starts, BangleAppLoader checks the JSON and compares it with the files it sees in the watch's storage.
  • To upload an app, BangleAppLoader checks the files that are listed in apps.json, loads them, and sends them over Web Bluetooth.

What filenames are used

Filenames in storage are limited to 8 characters. To easily distinguish between file types, we use the following:

  • +stuff is JSON for an app
  • *stuff is an image
  • -stuff is JS code
  • =stuff is JS code for stuff that is run at boot time - eg. handling settings or creating widgets on the clock screen
  • @stuff is used for JSON settings for an app

Developing your own app

  • Head over to the Web IDE and ensure Save on Send in settings set to the default setting of To RAM
  • We'd recommend that you start off using code from 'Example Applications' (below) to get started...
  • Load app.js or widget.js into the IDE and start developing.
  • The Upload button will load your app to Bangle.js temporarily

Adding your app to the menu

  • Come up with a unique 7 character name, we'll assume 7chname
  • Create a folder called apps/<id>, lets assume apps/7chname
  • We'd recommend that you copy files from 'Example Applications' (below) as a base, or...
  • apps/7chname/app.png should be a 48px icon
  • Use to create apps/7chname/app-icon.js, using a 1 bit, 4 bit or 8 bit Web Palette "Image String"
  • Create an entry in apps/7chname/app.json as follows:
  "name":"Short Name",

See app.json / widget.json below for more info on the correct format.

  • Create an entry in apps.json as follows:
{ "id": "7chname",
  "name": "My app's human readable name",
  "icon": "app.png",
  "description": "A detailed description of my great app",
  "tags": "",
  "storage": [



This is the best way to test...

  • Fork the git repository
  • Add your files
  • Go to GitHub Settings and activate GitHub Pages
  • Run your personal Bangle App Loader at https://<your-github-username> to load apps onto your device
  • Your apps should be inside it - if there are problems, check your web browser's 'developer console' for errors

Be aware of the delay between commits and updates on - it can take a few minutes (and a 'hard refresh' of your browser) for changes to take effect.


You can add the following to the Espruino Web IDE:

// replace with your 7chname app name
var appname = "mygreat";

  // place app-icon.js contents here

  "name":"My Great App","type":"",

// place contents of app.js here
// be aware of double-quoting templated strings

When you upload code this way, your app will be uploaded to Bangle.js's menu without you having to use the Bangle App Loader

Example Applications

To make the process easier we've come up with some example applications that you can use as a base when creating your own. Just come up with a unique 7 character name, copy apps/_example_app or apps/_example_widget to apps/7chname, and add apps/_example_X/add_to_apps.json to apps.json.

App Example

The app example is available in apps/_example_app

Apps are listed in the Bangle.js menu, accessible from a clock app via the middle button.

  • add_to_apps.json - insert into apps.json, describes the widget to bootloader and loader
  • app.png - app icon - 48x48px
  • app-icon.js - JS version of the icon (made with for use in Bangle.js's menu
  • app.json - short app name for Bangle.js menu and storage filenames
  • app.js - app code


The icon image and short description is used in the menu entry as selection posibility.

Use the Espruino image converter and upload your app.png file.

Follow this steps to create a readable icon as image string.

  1. upload a png file
  2. set X Use Compression
  3. set X Transparency (optional)
  4. set Diffusion: flat
  5. set Colours: 1 bit, 4 bit or 8 bit Web Palette
  6. set Output as: Image String

Replace this line with the image converter output:


Keep in mind to use this converter for creating images you like to draw with g.drawImage() with your app.

Widget Example

The widget example is available in apps/_example_widget

  • add_to_apps.json - insert into apps.json, describes the widget to bootloader and loader
  • widget.json - short widget name and storage names
  • widget.js - widget code

app.json / widget.json format

This is the file that's loaded onto Bangle.js, which gives information about the app.

  "name":"Short Name", // for Bangle.js menu
  "icon":"*7chname", // for Bangle.js menu
  "src":"-7chname", // source file
  "type":"widget/clock/app", // optional, default "app"
     // if this is 'widget' then it's not displayed in the menu
     // if it's 'clock' then it'll be loaded by default at boot time
     // added by BangleApps loader on upload based on apps.json
     // added by BangleApps loader on upload - lists all files
     // that belong to the app so it can be deleted

apps.json format

{ "id": "appid",              // 7 character app id
  "name": "Readable name",    // readable name
  "icon": "icon.png",         // icon in apps/
  "description": "...",       // long description
  "type":"...",               // optional(if app) - 'app'/'widget'/'launch'
  "tags": "",                 // comma separated tag list for searching

  "custom": "custom.html",    // if supplied, apps/custom.html is loaded in an
                              // iframe, and it must post back an 'app' structure
                              // like this one with 'storage','name' and 'id' set up
                              // see below for more info

  "interface": "interface.html",   // if supplied, apps/interface.html is loaded in an
                              // iframe, and it may interact with the connected Bangle
                              // to retrieve information from it
                              // see below for more info

  "allow_emulator":true,      // if 'app.js' will run in the emulator, set to true to
                              // add an icon to allow your app to be tested

  "storage": [                // list of files to add to storage
    {"name":"-appid",         // filename to use in storage
     "url":"",                // URL of file to load (currently relative to apps/)
     "content":"..."          // if supplied, this content is loaded directly
     "evaluate":true          // if supplied, data isn't quoted into a String before upload
                              // (eg it's evaluated as JS)
  "sortorder" : 0,            // optional - choose where in the list this goes.
                              // this should only really be used to put system
                              // stuff at the top
  • name, icon and description present the app in the app loader.
  • tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are tool, system, clock, game, sound, gps, widget, launcher or empty.
  • storage is used to identify the app files and how to handle them

apps.json: custom element

Apps that can be customised need to define a custom element in apps.json, which names an HTML file in that app's folder.

When custom is defined, the 'upload' button is replaced by a customize button, and when clicked it opens the HTML page specified in an iframe.

In that HTML file you're then responsible for handling a button press and calling sendCustomizedApp with your own customised version of what's in apps.json:

    <link rel="stylesheet" href="../../css/spectre.min.css">
    <p><button id="upload" class="btn btn-primary">Upload</button></p>
    <script src="../../lib/customize.js"></script>
      document.getElementById("upload").addEventListener("click", function() {
          id : "7chname",
            {name:"-7chname", content:app_source_code},
            {name:"+7chname", content:JSON.stringify({
              name:"My app's name",
            {name:"*7chname", content:'require("heatshrink").decompress(atob("mEwg...4"))', evaluate:true},

This'll then be loaded in to the watch. See [apps/qrcode/grcode.html](the QR Code app) for a clean example.

apps.json: interface element

Apps that create data that can be read back can define a interface element in apps.json, which names an HTML file in that app's folder.

When interface is defined, a Download from App button is added to the app's description, and when clicked it opens the HTML page specified in an iframe.

    <link rel="stylesheet" href="../../css/spectre.min.css">
    <script src="../../lib/interface.js"></script>
    <div id="t">Loading...</div>
      function onInit() {
        Puck.eval("E.getTemperature()", temp=> {
          document.getElementById("t").innerHTML = temp;

When the page is ready a function called onInit is called, and in that you can call Puck.write and Puck.eval to get the data you require from Bangle.js.

See [apps/gpsrec/interface.html](the GPS Recorder) for a full example.

Coding hints

  • Need to save state? Use the E.on('kill',...) event to save JSON to a file called @7chname, then load it at startup.

  • use g.setFont(.., size) to multiply the font size, eg ("6x8",3) : "18x24"

  • use g.drawString(text,x,y,true) to draw with background color to overwrite existing text

  • use g.clearRect() to clear parts of the screen, instead of using g.clear()

  • use g.fillPoly() or g.drawImage() for complex graphic elements

  • using g.clear() can cause screen flicker

  • using g.setLCDBrightness() can save you power during long periods with lcd on

  • chaining graphics methods, eg g.setColor(0xFD20).setFontAlign(0,0).setfont("6x8",3)

Graphic areas

The screen is parted in a widget and app area for lcd mode direct(default).

areas as rectangle or point
Widget (0,0,239,23)
Apps (0,24,239,239)
BTN1 (230, 55)
BTN2 (230, 140)
BTN3 (230, 210)
BTN4 (0,0,119, 239)
BTN5 (120,0,239,239)
  • Use g.setFontAlign(0, 0, 3) to draw rotated string to BTN1-BTN3 with g.drawString().

  • For BTN4-5 the touch area is named

Available colors

You can use g.setColor(r,g,b) OR g.setColor(16bitnumber) - some common 16 bit colors are below:

color-name color-value
Black 0x0000
Navy 0x000F
DarkGreen 0x03E0
DarkCyan 0x03EF
Maroon 0x7800
Purple 0x780F
Olive 0x7BE0
LightGray 0xC618
DarkGrey 0x7BEF
Blue 0x001F
Green 0x07E0
Cyan 0x07FF
RED 0xF800
Magenta 0xF81F
Yellow 0xFFE0
White 0xFFFF
Orange 0xFD20
GreenYellow 0xAFE5
Pink 0xF81F

API Reference


Bangle Class

Graphics Class

'Testing' folder

The testing folder contains snippets of code that might be useful for your apps.

  • testing/colors.js - 16 bit colors as name value pairs
  • testing/gpstrack.js - code to store a GPS track in Bangle.js storage and output it back to the console
  • testing/map - code for splitting an image into map tiles and then displaying them


The majority of icons used for these apps are from Icons8 - we have a commercial license but icons are also free for Open Source projects.

You can’t perform that action at this time.