pebblejs
v1.0.0
Published
Pebble.js =========
Downloads
4
Keywords
Readme
Pebble.js
Pebble.js lets you write beautiful Pebble applications completely in JavaScript.
Pebble.js applications run on your phone. They have access to all the resources of your phone (internet connectivity, GPS, almost unlimited memory, etc). Because they are written in JavaScript they are also perfect to make HTTP requests and connect your Pebble to the internet.
Warning: Please be aware that as a result of Bluetooth round-trips for all actions, Pebble.js apps will use more power and respond slower to user interaction than a similar native app.
Pebble.js was announced during JSConf 2014!
Getting Started
The easiest way to use Pebble.js is to use the Pebble Package distributed on the NPM registry.
In CloudPebble
On the dependencies screen, enterpebblejs
and the version number of the package on npm that you wish to use.Next, add a C source file and add the following code to the C source file:
#include <pebble.h> #include <pebblejs/simply.h> int main(void) { Simply *simply = simply_create(); app_event_loop(); simply_destroy(simply); }
Now you're ready to start using Pebble.js APIs! Add a new JS source file to start adding your JS code.
With the Pebble SDK
Follow the Pebble SDK installation instructions to install the SDK on your computer. Run
pebble new-project --javascript <appname>
and in the package.json file for the project, underdependencies
, add an entry forpebblejs
. See the npm docs for more information on how to specify dependencies in your project.In your
src/c/<appname>.c
file, replace the template code with the following code:#include <pebble.h> #include <pebblejs/simply.h> int main(void) { Simply *simply = simply_create(); app_event_loop(); simply_destroy(simply); }
Now you're ready to start using Pebble.js APIs! A template JS source file was created for you at
src/pkjs/index.js
. Modify this file (removing template code) with your JS code that uses Pebble.js APIs.
Pebble.js applications follow modern JavaScript best practices. To get started, you just need to call require('pebblejs')
.
To load the UI module and start building user interfaces, call require('pebblejs/ui')
.
var UI = require('pebblejs/ui');
The basic block to build user interface is the Card. A Card is a type of Window that occupies the entire screen and allows you to display some text in a pre-structured way: a title at the top, a subtitle below it and a body area for larger paragraphs. Cards can be made scrollable to display large quantities of information. You can also add images next to the title, subtitle or in the body area.
var card = new UI.Card({
title: 'Hello World',
body: 'This is your first Pebble app!',
scrollable: true
});
After creating a card window, push it onto the screen with the show()
method.
card.show();
To interact with the users, use the buttons or the accelerometer. Add callbacks to a window with the .on()
method:
card.on('click', function(e) {
card.subtitle('Button ' + e.button + ' pressed.');
});
Making HTTP connections is very easy with the included ajax
library.
var ajax = require('pebblejs/lib/ajax');
ajax({ url: 'http://api.theysaidso.com/qod.json', type: 'json' },
function(data) {
card.body(data.contents.quotes[0].quote);
card.title(data.contents.quotes[0].author);
}
);
You can do much more with Pebble.js:
- Get accelerometer values
- Display complex UI mixing geometric elements, text and images
- Animate elements on the screen
- Display arbitrary long menus
- Use the GPS and LocalStorage on the phone
- etc!
Keep reading for the full API Reference.
Using Images
You can use images in your Pebble.js application. Currently all images must be embedded in your applications. They will be resized and converted to black and white when you build your project.
We recommend that you follow these guidelines when preparing your images for Pebble:
- Resize all images for the screen of Pebble. A fullscreen image will be 144 pixels wide by 168 pixels high.
- Use an image editor or HyperDither to dither your image in black and white.
- Remember that the maximum size for a Pebble application is 100kB. You will quickly reach that limit if you add too many images.
To add an image in your application, edit the package.json
file and add your image:
{
"type": "png",
"name": "IMAGE_CHOOSE_A_UNIQUE_IDENTIFIER",
"file": "images/your_image.png"
}
If you are using CloudPebble, you can add images in your project configuration.
To reference your image in Pebble.js, you can use the name
field or the file
field.
// These two examples are both valid ways to show the image declared above in a Card
card.icon('images/your_image.png');
card.icon('IMAGE_CHOOSE_A_UNIQUE_IDENTIFIER');
You can also display images with [Image] when using a dynamic Window.
// This is an example of using an image with Image and Window
var UI = require('pebblejs/ui');
var Vector2 = require('pebblejs/lib/vector2');
var wind = new UI.Window({ fullscreen: true });
var image = new UI.Image({
position: new Vector2(0, 0),
size: new Vector2(144, 168),
image: 'images/your_image.png'
});
wind.add(image);
wind.show();
Using Fonts
You can use any of the Pebble system fonts in your Pebble.js applications. Please refer to this Pebble Developer's blog post for a list of all the Pebble system fonts. When referring to a font, using lowercase with dashes is recommended. For example, GOTHIC_18_BOLD
becomes gothic-18-bold
.
var Vector2 = require('pebblejs/lib/vector2');
var wind = new UI.Window();
var textfield = new UI.Text({
position: new Vector2(0, 0),
size: new Vector2(144, 168),
font: 'gothic-18-bold',
text: 'Gothic 18 Bold'
});
wind.add(textfield);
wind.show();
Using Color
You can use color in your Pebble.js applications by specifying them in the supported Color Formats. Use the Pebble Color Picker to find colors to use. Be sure to maintain Readability and Contrast when developing your application.
Color Formats
Color can be specified in various ways in your Pebble.js application. The formats are named string, hexadecimal string, and hexadecimal number. Each format has different benefits.
The following table includes examples of all the supported formats in Pebble.js:
| Color Format | Examples |
| ------------ | :------: |
| Named String | 'green', 'sunset-orange'
|
| Hexadecimal String | '#00ff00', '#ff5555'
|
| Hexadecimal String (with alpha) | '#ff00ff00', '#ffff5555'
|
| Hexadecimal Number | 0x00ff00, 0xff5555
|
| Hexadecimal Number (with alpha) | 0xff00ff00, 0xffff5555
|
Named strings are convenient to remember and read more naturally. They however cannot have the alpha channel be specified with the exception of the named string color 'clear'
. All other named colors are at max opacity. Named colors can also be specified in multiple casing styles, such as hyphenated lowercase 'sunset-orange'
, C constant 'SUNSET_ORANGE'
, Pascal 'SunsetOrange'
, or camel case 'sunsetOrange'
. Use the casing most convenient for you, but do so consistently across your own codebase.
Hexadecimal strings can be used for specifying the exact color desired as Pebble.js will automatically round the color to the supported color of the current platform. Two hexadecimal digits are used to represent the three color channels red, green, blue in that order.
Hexadecimal strings (with alpha) specified with eight digits are parsed as having an alpha channel specified in the first two digits where 00
is clear and ff
is full opacity.
Hexadecimal numbers can be manipulated directly with the arithmetic and bitwise operators. This is also the format which the configurable framework Clay uses.
Hexadecimal numbers (with alpha) also have an alpha channel specified, but it is recommended to use hexadecimal strings instead for two reasons. The first reason is that 00
also represents full opacity since they are equivalent to six digit hexadecimal numbers which are implicitly at full opacity. The second is that when explicitly representing full opacity as ff
, some integer logic can cause a signed overflow, resulting in negative color values. Intermediate alpha channels such as 55
or aa
have no such caveats.
Various parts of the Pebble.js API support color. Parameters of the type Color can take any of the color formats mentioned in the above table.
var UI = require('pebblejs/ui');
var card = new UI.Card({
title: 'Using Color',
titleColor: 'sunset-orange', // Named string
subtitle: 'Color',
subtitleColor: '#00dd00', // 6-digit Hexadecimal string
body: 'Format',
bodyColor: 0x9a0036 // 6-digit Hexadecimal number
});
card.show();
Readability and Contrast
When using color or not, be mindful that your users may not have a Pebble supporting color or the reverse. Black and white Pebbles will display colors with medium luminance as a gray checkered pattern which makes text of any color difficult to read. In Pebble.js, you can use Feature.color() to use a different value depending on whether color is supported.
var UI = require('pebblejs/ui');
var Feature = require('pebblejs/platform/feature');
var card = new UI.Card({
title: 'Using Color',
titleColor: Feature.color('sunset-orange', 'black'),
subtitle: 'Readability',
subtitleColor: Feature.color('#00dd00', 'black'),
body: 'Contrast',
bodyColor: Feature.color(0x9a0036, 'black'),
backgroundColor: Feature.color('light-gray', 'white'),
});
card.show();
Whether you have a color Pebble or not, you will want to test your app in all platforms. You can see how your app looks in multiple platforms with the following local SDK command or by changing the current platform in CloudPebble.
pebble build && pebble install --emulator=aplite && pebble install --emulator=basalt && pebble install --emulator=chalk && pebble install --emulator=diorite
Using too much color such as in the previous example can be overwhelming however. Just using one color that stands out in a single place can have a more defined effect and remain readable.
var card = new UI.Card({
status: {
color: 'white',
backgroundColor: Feature.color('electric-ultramarine', 'black'),
separator: 'none',
},
title: 'Using Color',
subtitle: 'Readability',
body: 'Contrast',
});
Likewise, if introducing an action bar, you can remove all color from the status bar and instead apply color to the action bar.
var card = new UI.Card({
status: true,
action: {
backgroundColor: Feature.color('jazzberry-jam', 'black'),
},
title: 'Dialog',
subtitle: 'Action',
body: 'Button',
});
When changing the background color, note that the status bar also needs its background color changed too if you would like it to match.
var backgroundColor = Feature.color('light-gray', 'black');
var card = new UI.Card({
status: {
backgroundColor: backgroundColor,
separator: Feature.round('none', 'dotted'),
},
action: {
backgroundColor: 'black',
},
title: 'Music',
titleColor: Feature.color('orange', 'black'),
subtitle: 'Playing',
body: 'Current Track',
backgroundColor: backgroundColor,
});
For a menu, following this style of coloring, you would only set the highlightBackgroundColor
.
var menu = new UI.Menu({
status: {
separator: Feature.round('none', 'dotted'),
},
highlightBackgroundColor: Feature.color('vivid-violet', 'black'),
sections: [{
items: [{ title: 'One', subtitle: 'Using Color' },
{ title: 'Color', subtitle: 'Color Formats' },
{ title: 'Hightlight', subtitle: 'Readability' }],
}],
});
menu.show();
In the examples above, mostly black text on white or light gray is used which has the most contrast. Try to maintain this amount of contrast with text. Using dark gray on light gray for example can be unreadable at certain angles in the sunlight or in darkly lit areas.
Feature Detection
Pebble.js provides the Feature module so that you may perform feature detection. This allows you to change the presentation or behavior of your application based on the capabilities or characteristics of the current Pebble watch that the user is running your application with.
Using Feature
During the development of your Pebble.js application, you will want to test your application on all platforms. You can use the following local SDK command or change the current platform in CloudPebble.
pebble build && pebble install --emulator=aplite && pebble install --emulator=basalt && pebble install --emulator=chalk && pebble install --emulator=diorite
You'll notice that there are a few differing capabilities across platforms, such as having color support or having a round screen. You can use Feature.color() and Feature.round() respectively in order to test for these capabilities. Most capability functions also have a direct opposite, such as Feature.blackAndWhite() and Feature.rectangle() respectively.
The most common way to use Feature capability functions is to pass two parameters.
var UI = require('pebblejs/ui');
var Feature = require('pebblejs/platform/feature');
// Use 'red' if round, otherwise use 'blue'
var color = Feature.round('red', 'blue');
var card = new UI.Card({
title: 'Color',
titleColor: color,
});
card.show();
You can also call the Feature capability functions with no arguments. In these cases, the function will return either true
or false
based on whether the capability exists.
if (Feature.round()) {
// Perform round-only logic
console.log('This is a round device.');
}
Among all Pebble platforms, there are characteristics that exist on all platforms, such as the device resolution and the height of the status bar. Feature also provides methods which gives additional information about these characteristics, such as Feature.resolution() and Feature.statusBarHeight().
var res = Feature.resolution();
console.log('Current display height is ' + res.y);
Check out the Feature API Reference for all the capabilities it detects and characteristics it offers.
Feature vs Platform
Pebble.js offers both Feature detection and Platform detection which are different. When do you use Feature detection instead of just changing the logic based on the current Platform? Using feature detection allows you to minimize the concerns of your logic, allowing each section of logic to be a single unit that does not rely on anything else unrelated.
Consider the following Platform detection logic:
var UI = require('pebblejs/ui');
var Platform = require('pebblejs/platform');
var isAplite = (Platform.version() === 'aplite');
var isChalk = (Platform.version() === 'chalk');
var card = new UI.Card({
title: 'Example',
titleColor: isAplite ? 'black' : 'dark-green',
subtitle: isChalk ? 'Hello World!' : 'Hello!',
body: isAplite ? 'Press up or down' : 'Speak to me',
});
card.show();
The first issue has to do with future proofing. It is checking if the current Pebble has a round screen by seeing if it is on Chalk, however there may be future platforms that have round screens. It can instead use Feature.round() which will update to include newer platforms as they are introduced.
The second issue is unintentional entanglement of different concerns. In the example above, isAplite
is being used to both determine whether the Pebble is black and white and whether there is a microphone. It is harmless in this small example, but when the code grows, it could potentially change such that a function both sets up the color and interaction based on a single boolean isAplite
. This mixes color presentation logic with interaction logic.
Consider the same example using Feature detection instead:
var UI = require('pebblejs/ui');
var Feature = require('pebblejs/platform/feature');
var card = new UI.Card({
title: 'Example',
titleColor: Feature.color('dark-green', 'black'),
subtitle: Feature.round( 'Hello World!', 'Hello!'),
body: Feature.microphone('Speak to me', 'Press up or down'),
});
card.show();
Now, if it is necessary to separate the different logic in setting up the card, the individual units can be implemented in separate functions without anything unintentionally mixing the logic together. Feature is provided as a module, so it is always available where you decide to move your logic.
The two examples consist of units of logic that consist of one liners, but if each line was instead large blocks of logic with the isAplite
boolean used throughout, the entanglement issue would be more difficult to remove from your codebase, hence the recommendation to use Feature detection. Of course, for capabilities or characteristics that Feature is unable to allow you to discern, use Platform.
API Reference
Global namespace
require(path)
Loads another JavaScript file allowing you to write a multi-file project. Package loading follows the CommonJS format. path
is the path to the dependency.
// src/js/dependency.js
var dep = require('./dependency');
Exporting is possible by modifying or setting module.exports
within the required file. The module path is also available as module.filename
. require
will look for the module relative to the loading module, or in the project's node_modules folder.
Pebble
The Pebble
object from PebbleKit JavaScript is available as a global variable. Some of the methods it provides have Pebble.js equivalents. When available, it is recommended to use the Pebble.js equivalents as they have more documented features and cleaner interfaces.
This table lists the current Pebble.js equivalents:
| Pebble API | Pebble.js Equivalent |
| ------------ | :------: |
| Pebble.addEventListener('ready', ...)
| Your application automatically starts after it is ready. |
| Pebble.addEventListener('showConfiguration', ...)
| Settings.config() |
| Pebble.addEventListener('webviewclosed', ...)
| Settings.config() with close handler. |
Use Pebble
when there is no Pebble.js alternative. Currently, these are the Pebble
methods that have no direct Pebble.js alternative:
| Pebble API without Equivalents | Note |
| ------------ | :---: |
| Pebble.getAccountToken()
| |
| Pebble.getActiveWatchInfo()
| Use Platform.version() if only querying for the platform version. |
| Pebble.getTimelineToken()
| |
| Pebble.getWatchToken()
| |
| Pebble.showSimpleNotificationOnPebble()
| Consider presenting a Card or using Pebble Timeline instead. |
| Pebble.timelineSubscribe()
| |
| Pebble.timelineSubscriptions()
| |
| Pebble.timelineUnsubscribe()
| |
localStorage
localStorage
is available for your use, but consider using the Settings module instead which provides an alternative interface that can save and load JavaScript objects for you.
var Settings = require('pebblejs/settings');
Settings.data('playerInfo', { id: 1, name: 'Gordon Freeman' });
var playerInfo = Settings.data('playerInfo');
console.log("Player's name is " + playerInfo.name);
XMLHttpRequest
XMLHttpRequest
is available for your use, but consider using the [ajax] module instead which provides a jQuery-like ajax alternative to performing asynchronous and synchronous HTTP requests, with built in support for forms and headers.
var ajax = require('pebblejs/lib/ajax');
ajax({ url: 'http://api.theysaidso.com/qod.json', type: 'json' },
function(data, status, req) {
console.log('Quote of the day is: ' + data.contents.quotes[0].quote);
}
);
window -- browser
A window
object is provided with a subset of the standard APIs you would find in a normal browser. Its direct usage is discouraged because available functionalities may differ between the iOS and Android runtime environment.
More specifically:
- XHR and WebSocket are supported on iOS and Android
- The
<canvas>
element is not available on iOS
Clock
The Clock module makes working with the [Wakeup] module simpler with its provided time utility functions.
Clock
Clock
provides a single module of the same name Clock
.
var Clock = require('pebblejs/clock');
Clock.weekday(weekday, hour, minute[, seconds])
Calculates the seconds since the epoch until the next nearest moment of the given weekday and time parameters. weekday
can either be a string representation of the weekday name such as sunday
, or the 0-based index number, such as 0 for sunday. hour
is a number 0-23 with 0-12 indicating the morning or a.m. times. minute
and seconds
numbers 0-59. seconds
is optional.
The weekday is always the next occurrence and is not limited by the current week. For example, if today is Wednesday, and 'tuesday'
is given for weekday
, the resulting time will be referring to Tuesday of next week at least 5 days from now. Similarly, if today is Wednesday and 'Thursday'
is given, the time will be referring to tomorrow, the Thursday of the same week, between 0 to 2 days from now. This is useful for specifying the time for [Wakeup.schedule].
// Next Tuesday at 6:00 a.m.
var nextTime = Clock.weekday('tuesday', 6, 0);
console.log('Seconds until then: ' + (nextTime - Date.now()));
var Wakeup = require('pebblejs/wakeup');
// Schedule a wakeup event.
Wakeup.schedule(
{ time: nextTime },
function(e) {
if (e.failed) {
console.log('Wakeup set failed: ' + e.error);
} else {
console.log('Wakeup set! Event ID: ' + e.id);
}
}
)
Platform
Platform
provides a module of the same name Platform
and a feature detection module Feature.
Platform
The Platform module allows you to determine the current platform runtime on the watch through its Platform.version
method. This is to be used when the Feature module does not give enough ability to discern whether a feature exists or not.
var Platform = require('pebblejs/platform');
Platform.version()
Platform.version
returns the current platform version name as a lowercase string. This can be 'aplite'
, 'basalt'
, 'chalk'
or 'diorite'
. Use the following table to determine the platform that Platform.version
will return.
| Watch Model | Platform |
| ---- | :----: |
| Pebble Classic | 'aplite'
|
| Pebble Steel Classic | 'aplite'
|
| Pebble Time | 'basalt'
|
| Pebble Time Steel | 'basalt'
|
| Pebble Time Round | 'chalk'
|
| Pebble 2 | 'diorite'
|
console.log('Current platform is ' + Platform.version());
Feature
The Feature module under Platform allows you to perform feature detection, adjusting aspects of your application to the capabilities of the current watch model it is current running on. This allows you to consider the functionality of your application based on the current set of available capabilities or features. The Feature module also provides information about features that exist on all watch models such as Feature.resolution
which returns the resolution of the current watch model.
var Feature = require('pebblejs/platform/feature');
console.log('Color is ' + Feature.color('avaiable', 'not available'));
console.log('Display width is ' + Feature.resolution().x);
Feature.color([yes, no])
Feature.color
will return the yes
parameter if color is supported and no
if it is not. This is the opposite of Feature.blackAndWhite(). When given no parameters, it will return true or false respectively.
var textColor = Feature.color('oxford-blue', 'black');
if (Feature.color()) {
// Perform color-only operation
console.log('Color supported');
}
Feature.blackAndWhite([yes, no])
Feature.blackAndWhite
will return the yes
parameter if only black and white is supported and no
if it is not. This is the opposite of Feature.color(). When given no parameters, it will return true or false respectively.
var backgroundColor = Feature.blackAndWhite('white', 'clear');
if (Feature.blackAndWhite()) {
// Perform black-and-white-only operation
console.log('Black and white only');
}
Feature.rectangle([yes, no])
Feature.rectangle
will return the yes
parameter if the watch screen is rectangular and no
if it is not. This is the opposite of Feature.round(). When given no parameters, it will return true or false respectively.
var margin = Feature.rectangle(10, 20);
if (Feature.rectangle()) {
// Perform rectangular display only operation
console.log('Rectangular display');
}
Feature.round([yes, no])
Feature.round
will return the yes
parameter if the watch screen is round and no
if it is not. This is the opposite of Feature.rectangle(). When given no parameters, it will return true or false respectively.
var textAlign = Feature.round('center', 'left');
if (Feature.round()) {
// Perform round display only operation
console.log('Round display');
}
Feature.microphone([yes, no])
Feature.microphone
will return the yes
parameter if the watch has a microphone and no
if it does not. When given no parameters, it will return true or false respectively. Useful for determining whether the Voice
module will allow transcription or not and changing the UI accordingly.
var text = Feature.microphone('Say your command.',
'Select your command.');
if (Feature.microphone()) {
// Perform microphone only operation
console.log('Microphone available');
}
Feature.resolution()
Feature.resolution
returns a [Vector2] containing the display width as the x
component and the display height as the y
component. Use the following table to determine the resolution that Feature.resolution
will return on a given platform.
| Platform | Width | Height | Note | | ---- | :---: | :----: | ------ | | aplite | 144 | 168 | | | basalt | 144 | 168 | This is a rounded rectangle, therefore there is small set of pixels at each corner not available. | | chalk | 180 | 180 | This is a circular display, therefore not all pixels in a 180 by 180 square are available. | | diorite | 144 | 168 | |
NOTE: Windows also have a Window.size() method which returns its size as a [Vector2]. Use Window.size() when possible.
var res = Feature.resolution();
console.log('Current display is ' + res.x + 'x' + res.y);
Feature.actionBarWidth()
Feature.actionBarWidth
returns the action bar width based on the platform. This is 30
for rectangular displays and 40
for round displays. Useful for determining the remaining screen real estate in a dynamic Window with an action bar visible.
var rightMargin = Feature.actionBarWidth() + 5;
var elementWidth = Feature.resolution().x - rightMargin;
NOTE: Window.size() already takes the action bar into consideration, so use it instead when possible.
Feature.statusBarHeight()
Feature.statusBarHeight
returns the status bar height. This is 16
and can change accordingly if the Pebble Firmware theme ever changes. Useful for determining the remaining screen real estate in a dynamic Window with a status bar visible.
var topMargin = Feature.statusBarHeight() + 5;
var elementHeight = Feature.resolution().y - topMargin;
NOTE: Window.size() already takes the status bar into consideration, so use it instead when possible.
Settings
The Settings module allows you to add a configurable web view to your application and share options with it. Settings also provides two data accessors Settings.option
and Settings.data
which are backed by localStorage. Data stored in Settings.option
is automatically shared with the configurable web view.
Settings
Settings
provides a single module of the same name Settings
.
var Settings = require('pebblejs/settings');
Settings.config(options, [open,] close)
Settings.config
registers your configurable for use along with open
and close
handlers.
options
is an object with the following parameters:
| Name | Type | Argument | Default | Description |
| ---- | :----: | :--------: | --------- | ------------- |
| url
| string | | | The URL to the configurable. e.g. 'http://www.example.com?name=value' |
| autoSave
| boolean | (optional) | true | Whether to automatically save the web view response to options |
| hash
| boolean | (optional) | true | Whether to automatically concatenate the URI encoded json Settings
options to the URL as the hash component. |
open
is an optional callback used to perform any tasks before the webview is open, such as managing the options that will be passed to the web view.
// Set a configurable with the open callback
Settings.config(
{ url: 'http://www.example.com' },
function(e) {
console.log('opening configurable');
// Reset color to red before opening the webview
Settings.option('color', 'red');
},
function(e) {
console.log('closed configurable');
}
);
close
is a callback that is called when the webview is closed via pebblejs://close
. Any arguments passed to pebblejs://close
is parsed and passed as options to the handler. Settings
will attempt to parse the response first as URI encoded json and second as form encoded data if the first fails.
// Set a configurable with just the close callback
Settings.config(
{ url: 'http://www.example.com' },
function(e) {
console.log('closed configurable');
// Show the parsed response
console.log(JSON.stringify(e.options));
// Show the raw response if parsing failed
if (e.failed) {
console.log(e.response);
}
}
);
To pass options from your configurable to Settings.config
close
in your webview, URI encode your options json as the hash to pebblejs://close
. This will close your configurable, so you would perform this action in response to the user submitting their changes.
var options = { color: 'white', border: true };
document.location = 'pebblejs://close#' + encodeURIComponent(JSON.stringify(options));
Settings.option
Settings.option
is a data accessor built on localStorage that shares the options with the configurable web view.
Settings.option(field, value)
Saves value
to field
. It is recommended that value
be either a primitive or an object whose data is retained after going through JSON.stringify
and JSON.parse
.
Settings.option('color', 'red');
If value
is undefined or null, the field will be deleted.
Settings.option('color', null);
Settings.option(field)
Returns the value of the option in field
.
var player = Settings.option('player');
console.log(player.id);
Settings.option(options)
Sets multiple options given an options
object.
Settings.option({
color: 'blue',
border: false,
});
Settings.option()
Returns all options. The returned options can be modified, but if you want the modifications to be saved, you must call Settings.option
as a setter.
var options = Settings.option();
console.log(JSON.stringify(options));
options.counter = (options.counter || 0) + 1;
// Modifications are not saved until `Settings.option` is called as a setter
Settings.option(options);
Settings.data
Settings.data
is a data accessor similar to Settings.option
except it saves your data in a separate space. This is provided as a way to save data or options that you don't want to pass to a configurable web view.
While localStorage is still accessible, it is recommended to use Settings.data
.
Settings.data(field, value)
Saves value
to field
. It is recommended that value
be either a primitive or an object whose data is retained after going through JSON.stringify
and JSON.parse
.
Settings.data('player', { id: 1, x: 10, y: 10 });
If value
is undefined or null, the field will be deleted.
Settings.data('player', null);
Settings.data(field)
Returns the value of the data in field
.
var player = Settings.data('player');
console.log(player.id);
Settings.data(data)
Sets multiple data given an data
object.
Settings.data({
name: 'Pebble',
player: { id: 1, x: 0, y: 0 },
});
Settings.data()
Returns all data. The returned data can be modified, but if you want the modifications to be saved, you must call Settings.data
as a setter.
var data = Settings.data();
console.log(JSON.stringify(data));
data.counter = (data.counter || 0) + 1;
// Modifications are not saved until `Settings.data` is called as a setter
Settings.data(data);
UI
The UI framework contains all the classes needed to build the user interface of your Pebble applications and interact with the user.
Accel
The Accel
module allows you to get events from the accelerometer on Pebble.
You can use the accelerometer in two different ways:
- To detect tap events. Those events are triggered when the user flicks his wrist or tap on the Pebble. They are the same events that are used to turn the Pebble back-light on. Tap events come with a property to tell you in which direction the Pebble was shook. Tap events are very battery efficient because they are generated directly by the accelerometer inside Pebble.
- To continuously receive streaming data from the accelerometer. In this mode the Pebble will collect accelerometer samples at a specified frequency (from 10Hz to 100Hz), batch those events in an array and pass those to an event handler. Because the Pebble accelerometer needs to continuously transmit data to the processor and to the Bluetooth radio, this will drain the battery much faster.
var Accel = require('pebblejs/ui/accel');
Accel.config(accelConfig)
This function configures the accelerometer data
events to your liking. The tap
event requires no configuration for use. Configuring the accelerometer is a very error prone process, so it is recommended to not configure the accelerometer and use data
events with the default configuration without calling Accel.config
.
Accel.config
takes an accelConfig
object with the following properties:
| Name | Type | Argument | Default | Description |
| ---- | :----: | :--------: | --------- | ------------- |
| rate
| number | (optional) | 100 | The rate accelerometer data points are generated in hertz. Valid values are 10, 25, 50, and 100. |
| samples
| number | (optional) | 25 | The number of accelerometer data points to accumulate in a batch before calling the event handler. Valid values are 1 to 25 inclusive. |
| subscribe
| boolean | (optional) | automatic | Whether to subscribe to accelerometer data events. Accel.accelPeek cannot be used when subscribed. Pebble.js will automatically (un)subscribe for you depending on the amount of accelData handlers registered. |
The number of callbacks will depend on the configuration of the accelerometer. With the default rate of 100Hz and 25 samples, your callback will be called every 250ms with 25 samples each time.
Important: If you configure the accelerometer to send many data
events, you will overload the bluetooth connection. We recommend that you send at most 5 events per second.
Accel.peek(callback)
Peeks at the current accelerometer value. The callback function will be called with the data point as an event.
Accel.peek(function(e) {
console.log('Current acceleration on axis are: X=' + e.accel.x + ' Y=' + e.accel.y + ' Z=' + e.accel.z);
});
Accel.on('tap', callback)
Subscribe to the Accel
tap
event. The callback function will be passed an event with the following fields:
axis
: The axis the tap event occurred on: 'x', 'y', or 'z'.direction
: The direction of the tap along the axis: 1 or -1.
Accel.on('tap', function(e) {
console.log('Tap event on axis: ' + e.axis + ' and direction: ' + e.direction);
});
A Window may subscribe to the Accel
tap
event using the accelTap
event type. The callback function will only be called when the window is visible.
wind.on('accelTap', function(e) {
console.log('Tapped the window');
});
Accel.on('data', callback)
Subscribe to the accel 'data' event. The callback function will be passed an event with the following fields:
samples
: The number of accelerometer samples in this event.accel
: The first data point in the batch. This is provided for convenience.accels
: The accelerometer samples in an array.
One accelerometer data point is an object with the following properties:
| Property | Type | Description |
| -------- | :----: | ------------ |
| x
| Number | The acceleration across the x-axis (from left to right when facing your Pebble) |
| y
| Number | The acceleration across the y-axis (from the bottom of the screen to the top of the screen) |
| z
| Number | The acceleration across the z-axis (going through your Pebble from the back side of your Pebble to the front side - and then through your head if Pebble is facing you ;) |
| vibe
| boolean | A boolean indicating whether Pebble was vibrating when this sample was measured. |
| time
| Number | The amount of ticks in millisecond resolution when this point was measured. |
Accel.on('data', function(e) {
console.log('Just received ' + e.samples + ' from the accelerometer.');
});
A Window may also subscribe to the Accel
data
event using the accelData
event type. The callback function will only be called when the window is visible.
wind.on('accelData', function(e) {
console.log('Accel data: ' + JSON.stringify(e.accels));
});
Voice
The Voice
module allows you to interact with Pebble's dictation API on supported platforms (Basalt, Chalk and Diorite).
var Voice = require('pebblejs/ui/voice');
Voice.dictate('start', [confirmDialog,] callback)
This function starts the dictation UI, and invokes the callback upon completion. The callback is passed an event with the following fields:
err
: A string describing the error, ornull
on success.transcription
: The transcribed string.
An optional second parameter, confirmDialog
, can be passed to the Voice.dictate
method to control whether there should be a confirmation dialog displaying the transcription text after voice input. If confirmDialog
is set to false
, the confirmation dialog will be skipped. By default, there will be a confirmation dialog.
// Start a diction session and skip confirmation
Voice.dictate('start', false, function(e) {
if (e.err) {
console.log('Error: ' + e.err);
return;
}
main.subtitle('Success: ' + e.transcription);
});
NOTE: Only one dictation session can be active at any time. Trying to call Voice.dicate('start', ...)
while another dictation session is in progress will result in the callback being called with an event having the error "sessionAlreadyInProgress"
.
Voice.dictate('stop')
This function stops a dictation session that is currently in progress and prevents the session's callback from being invoked. If no session is in progress this method has no effect.
Voice.dictate('stop');
Window
Window
is the basic building block in your Pebble.js application. All windows share some common properties and methods.
Pebble.js provides three types of Windows:
- Card: Displays a title, a subtitle, a banner image and text on a screen. The position of the elements are fixed and cannot be changed.
- Menu: Displays a menu on the Pebble screen. This is similar to the standard system menu in Pebble.
- Window: The
Window
by itself is the most flexible. It allows you to add different Elements ([Circle], [Image], [Line], [Radial], [Rect], [Text], [TimeText]) and to specify a position and size for each of them. Elements can also be animated.
A Window
can have the following properties:
| Name | Type | Default | Description |
| ---- | :-------: | --------- | ------------- |
| clear
| boolean | | |
| action
| actionDef | None | An action bar will be shown when configured with an actionDef
. |
| fullscreen
| boolean | false | When true, the Pebble status bar will not be visible and the window will use the entire screen. |
| scrollable
| boolean | false | Whether the user can scroll this Window with the up and down button. When this is enabled, single and long click events on the up and down button will not be transmitted to your app. |
Window actionDef
A Window
action bar can be displayed by setting its Window action
property to an actionDef
.
An actionDef
has the following properties:
| Name | Type | Default | Description |
| ---- | :-------: | --------- | ------------- |
| up
| Image | None | An image to display in the action bar, next to the up button. |
| select
| Image | None | An image to display in the action bar, next to the select button. |
| down
| Image | None | An image to display in the action bar, next to the down button. |
| backgroundColor
| Color | 'black' | The background color of the action bar. You can set this to 'white' for windows with black backgrounds. |
// Set action properties during initialization
var card = new UI.Card({
action: {
up: 'images/action_icon_plus.png',
down: 'images/action_icon_minus.png'
}
});
// Set action properties after initialization
card.action({
up: 'images/action_icon_plus.png',
down: 'images/action_icon_minus.png'
});
// Set a single action property
card.action('select', 'images/action_icon_checkmark.png');
// Disable the action bar
card.action(false);
You will need to add images to your project according to the Using Images guide in order to display action bar icons.
Window statusDef
A Window
status bar can be displayed by setting its Window status
property to a statusDef
:
A statusDef
has the following properties:
| Name | Type | Default | Description |
| ---- | :-------: | --------- | ------------- |
| separator
| string | 'dotted' | The separate between the status bar and the content of the window. Can be 'dotted'
or 'none'
. |
| color
| Color | 'black' | The foreground color of the status bar used to display the separator and time text. |
| backgroundColor
| Color | 'white' | The background color of the status bar. You can set this to 'black' for windows with white backgrounds. |
// Set status properties during initialization
var card = new UI.Card({
status: {
color: 'white',
backgroundColor: 'black'
}
});
// Set status properties after initialization
card.status({
color: 'white',
backgroundColor: 'black'
});
// Set a single status property
card.status('separator', 'none');
// Disable the status bar
card.status(false);
Window.show()
This will push the window to the screen and display it. If user press the 'back' button, they will navigate to the previous screen.
Window.hide()
This hides the window.
If the window is currently displayed, this will take the user to the previously displayed window.
If the window is not currently displayed, this will remove it from the window stack. The user will not be able to get back to it with the back button.
var splashScreen = new UI.Card({ banner: 'images/splash.png' });
splashScreen.show();
var mainScreen = new UI.Menu();
setTimeout(function() {
// Display the mainScreen
mainScreen.show();
// Hide the splashScreen to avoid showing it when the user press Back.
splashScreen.hide();
}, 400);
Window.on('click', button, handler)
Registers a handler to call when button
is pressed.
wind.on('click', 'up', function() {
console.log('Up clicked!');
});
You can register a handler for the 'up', 'select', 'down', and 'back' buttons.
Note: You can also register button handlers for longClick
.
Window.on('longClick', button, handler)
Just like Window.on('click', button, handler)
but for 'longClick' events.
Window.on('show', handler)
Registers a handler to call when the window is shown. This is useful for knowing when a user returns to your window from another. This event is also emitted when programmatically showing the window. This does not include when a Pebble notification popup is exited, revealing your window.
// Define the handler before showing.
wind.on('show', function() {
console.log('Window is shown!');
});
// The show event will emit, and the handler will be called.
wind.show();
Window.on('hide', handler)
Registers a handler to call when the window is hidden. This is useful for knowing when a user exits out of your window or when your window is no longer visible because a different window is pushed on top. This event is also emitted when programmatically hiding the window. This does not include when a Pebble notification popup obstructs your window.
It is recommended to use this instead of overriding the back button when appropriate.
wind.on('hide', function() {
console.log('Window is hidden!');
});
Window.action(actionDef)
Nested accessor to the action
property which takes an actionDef
. Used to configure the action bar with a new actionDef
. See Window actionDef.
card.action({
up: 'images/action_icon_up.png',
down: 'images/action_icon_down.png'
});
To disable the action bar after enabling it, false
can be passed in place of an actionDef
.
// Disable the action bar
card.action(false);
Window.action(field, value)
Window.action
can also be called with two arguments, field
and value
, to set specific fields of the window's action
property. field
is the name of a Window actionDef property as a string and value
is the new property value.
card.action('select', 'images/action_icon_checkmark.png');
Window.status(statusDef)
Nested accessor to the status
property which takes a statusDef
. Used to configure the status bar with a new statusDef
. See Window statusDef.
card.status({
color: 'white',
backgroundColor: 'black'
});
To disable the status bar after enabling it, false
can be passed in place of statusDef
.
// Disable the status bar
card.status(false);
Similarly, true
can be used as a Window statusDef to represent a statusDef
with all default properties.
var card = new UI.Card({ status: true });
card.show();
Window.status(field, value)
Window.status
can also be called with two arguments, field
and value
, to set specific fields of the window's status
property. field
is the name of a Window statusDef property as a string and value
is the new property value.
card.status('separator', 'none');
Window.size()
Window.size
returns the size of the max viewable content size of the window as a [Vector2] taking into account whether there is an action bar and status bar. A Window will return a size that is shorter than a Window without for example.
If the automatic consideration of the action bar and status bar does not satisfy your use case, you can use Feature.resolution() to obtain the Pebble's screen resolution as a [Vector2].
var wind = new UI.Window({ status: true });
var size = wind.size();
var rect = new UI.Rect({ size: new Vector2(size.x / 4, size.y / 4) });
wind.add(rect);
wind.show();
Window (dynamic)
A Window instantiated directly is a dynamic window that can display a completely customizable user interface on the screen. Dynamic windows are initialized empty and will need Elements added to it. Card and Menu will not display elements added to them in this way.
// Create a dynamic window
var wind = new UI.Window();
// Add a rect element
var rect = new UI.Rect({ size: new Vector2(20, 20) });
wind.add(rect);
wind.show();
Window.add(element)
Adds an element to to the Window. The element will be immediately visible.
Window.insert(index, element)
Inserts an element at a specific index in the list of Element.
Window.remove(element)
Removes an element from the Window.
Window.index(element)
Returns the index of an element in the Window or -1 if the element is not in the window.
Window.each(callback)
Iterates over all the elements on the Window.
wind.each(function(element) {
console.log('Element: ' + JSON.stringify(element));
});
Card
A Card is a type of Window that allows you to display a title, a subtitle, an image and a body on the screen of Pebble.
Just like any window, you can initialize a Card by passing an object to the constructor or by calling accessors to change the properties.
var card = new UI.Card({
title: 'Hello People!'
});
card.body('This is the content of my card!');
The properties available on a Card are:
| Name | Type | Default | Description |
| ---- | :-------: | --------- | ------------- |
| title
| string | '' | Text to display in the title field at the top of the screen |
| titleColor
| Color | 'black' | Text color of the title field |
| subtitle
| string | '' | Text to display below the title |
| subtitleColor
| Color | 'black' | Text color of the subtitle field |
| body
| string | '' | Text to display in the body field |
| bodyColor
| Color | 'black' | Text color of the body field |
| icon
| Image | null | An image to display before the title text. Refer to Using Images for instructions on how to include images in your app. |
| subicon
| Image | null | An image to display before the subtitle text. Refer to Using Images for instructions on how to include images in your app. |
| banner
| Image | null | An image to display in the center of the screen. Refer to Using Images for instructions on how to include images in your app. |
| scrollable
| boolean | false | Whether the user can scroll this card with the up and down button. When this is enabled, single and long click events on the up and down button will not be transmitted to your app. |
| style
| string | 'small' | Selects the font used to display the body. This can be 'small', 'large' or 'mono' |
A Card is also a Window and thus also has Window properties.
The 'small'
and 'large
' styles correspond to the system notification styles. 'mono'
sets a monospace font for the body textfield, enabling more complex text UIs or ASCII art. The 'small'
and 'large'
styles were updated to match the Pebble firmware 3.x design during the 3.11 release. In order to use the older 2.x styles, you may specify 'classic-small'
and 'classic-large'
, however it is encouraged to use the newer styles.
Note that all text fields will automatically span multiple lines if needed and that you can use '\n' to insert line breaks.
Menu
A menu is a type of Window that displays a standard Pebble menu on the screen of Pebble.
Just like any window, you can initialize a Menu by passing an object to the constructor or by calling accessors to change the properties.
The properties available on a Menu are:
| Name | Type | Default | Description |
| ---- |:-------:|---------|-------------|
| sections
| Array | []
| A list of all the sections to display. |
| backgroundColor
| Color | white
| The background color of a menu item. |
| textColor
| Color | black
| The text color of a menu item. |
| highlightBackgroundColor
| Color | black
| The background color of a selected menu item. |
| highlightTextColor
| Color | white
| The text color of a selected menu item. |
A menu contains one or more sections.
The properties available on a section are:
| Name | Type | Default | Description |
| ---- |:-------:|---------|-------------|
| items
| Array | []
| A list of all the items to display. |
| title
| string | '' | Title text of the section header. |
| backgroundColor
| Color | white
| The background color of the section header. |
| textColor
| Color | black
| The text color of the section header. |
Each section has a title and contains zero or more items. An item must have a title. Items can also optionally have a subtitle and an icon.
var menu = new UI.Menu({
backgroundColor: 'black',
textColor: 'blue',
highlightBackgroundColor: 'blue',
highlightTextColor: 'black',
sections: [{
title: 'First section',
items: [{
title: 'First Item',
subtitle: 'Some subtitle',
icon: 'images/item_icon.png'
}, {
title: 'Second item'
}]
}]
});
Menu.section(sectionIndex, section)
Define the section to be displayed at sectionIndex
. See Menu for the properties of a section.
var section = {
title: 'Another section',
items: [{
title: 'With one item'
}]
};
menu.section(1, section);
When called with no section
, returns the section at the given sectionIndex
.
Menu.items(sectionIndex, items)
Define the items to display in a specific section. See Menu for the properties of an item.
menu.items(0, [ { title: 'new item1' }, { title: 'new item2' } ]);
Whell called with no items
, returns the items of the section at the given sectionIndex
.
Menu.item(sectionIndex, itemIndex, item)
Define the item to display at index itemIndex
in section sectionIndex
. See Menu for the properties of an item.
menu.item(0, 0, { title: 'A new item', subtitle: 'replacing the previous one' });
When called with no item
, returns the item at the given sectionIndex
and itemIndex
.
Menu.selection(callback)
Get the currently selected item and section. The callback function will be passed an event with the following fields:
menu
: The menu object.section
: The menu section object.sectionIndex
: The section index of the section of the selected item.item
: The menu item object.itemIndex
: The item index of the selected item.
menu.selection(function(e) {
console.log('Currently selected item is #' + e.itemIndex + ' of section #' + e.sectionIndex);
console.log('The item is titled "' + e.item.title + '"');
});
Menu.selection(sectionIndex, itemIndex)
Change the selected item and section.
// Set the menu selection to the first section's third menu item
menu.selection(0, 2);
Menu.on('select', callback)
Registers a callback called when an item in the menu is selected. The callback function will be passed an event with the following fields:
menu
: The menu object.section
: The menu section object.sectionIndex
: The section index of the section of the selected item.item
: The menu item object.itemIndex
: The item index of the selected item.
Note: You can also register a callback for 'longSelect' event, triggered when the user long clicks on an item.
menu.on('select', function(e) {
console.log('Selected item #' + e.itemIndex + ' of section #' + e.sectionIndex);
console.log('The item is titled "' + e.item.title + '"');
});
Menu.on('longSelect', callback)
Similar to the select callback, except for long select presses. See Menu.on('select', callback).
Element
There are seven types of Element that can be instantiated at the moment: [Circle], [Image], [Line], [Radial], [Rect], [Text], [TimeText].
Most elements share these common properties:
| Name | Type | Default | Description |
| ------------ | :-------: | --------- | ------------- |
| position
| Vector2 | | Position of this element in the window. |
| size
| Vector2 | | Size of this element in this window. [Circle] uses radius
instead. |
| borderWidth
| number | 0 | Width of the border of this element. [Line] uses strokeWidth
instead. |
| borderColor
| Color | 'clear' | Color of the border of this element. [Line] uses strokeColor
instead. |
| backgroundColor
| Color | 'white' | Background color of this element. [Line] has no background. |
All properties can be initialized by passing an object when creating the Element, and changed with accessors functions that have the same name as the properties. Calling an accessor without a parameter will return the current value.
var Vector2 = require('pebblejs/lib/vector2');
var element = new Text({
position: new Vector2(0, 0),
size: new Vector2(144, 168),
});
element.borderColor('white');
console.log('This element background color is: ' + element.backgroundColor());
Element.index()
Returns the index of the element in its Window or -1 if the element is not part of a window.
Element.remove()
Removes the element from its Window.