Import the pebble dev site into devsite/

This commit is contained in:
Katharine Berry 2025-02-17 17:02:33 -08:00
parent 3b92768480
commit 527858cf4c
1359 changed files with 265431 additions and 0 deletions

View file

@ -0,0 +1,224 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: App Metadata
description: |
Details of the metadata that describes the app, such as its name,
resources and capabilities.
guide_group: tools-and-resources
order: 0
---
{% alert notice %}
This page applies only to developers using the SDK on their local machine;
CloudPebble allows you to manages this part of development in 'Settings'.
{% endalert %}
## Project Defaults
After creating a new local SDK Pebble project, additional setup of the project
behavior and metadata can be performed in the `package.json` file. By default,
the `pebble new-project` command will create a template `package.json` metadata
file, which can then be modified as required.
The generated `package.json` metadata looks like this:
```js
{
"name": "example-app",
"author": "MakeAwesomeHappen",
"version": "1.0.0",
"keywords": ["pebble-app"],
"private": true,
"dependencies": {},
"pebble": {
"displayName": "example-app",
"uuid": "5e5b3966-60b3-453a-a83b-591a13ae47d5",
"sdkVersion": "3",
"enableMultiJS": true,
"targetPlatforms": [
"aplite",
"basalt",
"chalk"
],
"watchapp": {
"watchface": false
},
"messageKeys": [
"dummy"
],
"resources": {
"media": []
}
}
}
```
{% alert notice %}
Older projects might have an `appinfo.json` file instead of a `package.json`.
You can run `pebble convert-project` to update these projects.
{% endalert %}
> Note: The `uuid` (Universally Unique IDentifier) field should be unique (as
> the name implies) and always properly generated. To do this on Mac OS X or
> Linux, use the `uuidgen` tool or a web service. Due to format requirements,
> these should never be manually modified.
## Available Properties
Options defined in `package.json` (Required fields shown in **bold**) are
listed in the table below:
| Property | Type | Default Value |Description |
|:---------|:----:|:--------------|:------------|
| **`pebble.uuid`** | UUID | Developer-defined | Unique identifier [(UUID v4)](http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29) for the app. Generated by `pebble new-project`. |
| **`name`** | String | Developer-defined | App's short name. This is only used by npm and can't contain any non-URL-safe characters. |
| **`pebble.displayName`** | String | Developer-defined | App's long name. This is what the app will appear as on the appstore, phone and watch. |
| **`author`** | String | `"MakeAwesomeHappen"` | Name of the app's developer. |
| **`version`** | String | `"1.0.0"` | Version label for the app. Must use the format `major.minor.0`. |
| **`pebble.sdkVersion`** | String | `"3"` | The major version of the SDK that this app is being written for. |
| `pebble.targetPlatforms` | Array of strings | `["aplite", "basalt", "chalk"]` | Specify which platforms to build this app for. Read {% guide_link tools-and-resources/hardware-information %} for a list of available platforms. Defaults to all if omitted. |
| `pebble.enableMultiJS` | Boolean | `true` | Enables [use of multiple JS files](/blog/2016/01/29/Multiple-JavaScript-Files/) in a project with a CommonJS-style `require` syntax. |
| **`pebble.watchapp`** | Object | N/A | Used to configure the app behavior on the watch. See below for an example object. |
| **`.watchface`** | Boolean | `false` | Field of `watchapp`. Set to `false` to behave as a watchapp. |
| `.hiddenApp` | Boolean | `false` | Field of `watchapp`. Set to `true` to prevent the app from appearing in the system menu. |
| `.onlyShownOnCommunication` | Boolean | `false` | Field of `watchapp`. Set to `true` to hide the app unless communicated with from a companion app. |
| `pebble.capabilities` | Array of strings | None | List of capabilities that the app requires. The supported capabilities are `location`, `configurable` (detailed in {% guide_link communication/using-pebblekit-js %}), and `health` (detailed in {% guide_link events-and-services/health %}). |
| `pebble.messageKeys` | Object | `["dummy"]` | Keys used for ``AppMessage`` and ``AppSync``. This is either a list of mapping of ``AppMessage`` keys. See {% guide_link communication/using-pebblekit-js %} for more information. |
| `pebble.resources.media` | Object | `[]` | Contains an array of all of the media resources to be bundled with the app (Maximum 256 per app). See {% guide_link app-resources %} for more information. |
| `pebble.resources.publishedMedia` | Object | | Used for {% guide_link user-interfaces/appglance-c "AppGlance Slices" %} and {% guide_link pebble-timeline/pin-structure "Timeline Pins" %}. See [Published Media](#published-media) for more information.
> Note: `hiddenApp` and `onlyShownOnCommunication` are mutually exclusive.
> `hiddenApp` will always take preference.
## Hidden Watchapp
The example below shows an example `watchapp` object for a watchapp that is
hidden until communicated with from a companion app.
```js
"watchapp": {
"watchface": false,
"hiddenApp": false,
"onlyShownOnCommunication": true
}
```
## Published Media
Introduced in SDK 4.0, `publishedMedia` provides a mechanism for applications to
specify image resources which can be used within
{% guide_link user-interfaces/appglance-c "AppGlance Slices" %} or
{% guide_link pebble-timeline/pin-structure "Timeline Pins" %}.
The `publishedMedia` object allows your watchapp, Pebble mobile application and
Pebble web services to determine which image resources to use, based on a static
ID. Without this lookup table, the components would not be able to establish the
correct resources to use after an update to the watchapp.
Let's take a look at the structure of `publishedMedia` in more detail.
We'll start by declaring some image resources which we can reference in
`publishedMedia` later. In this example we have 'hot' and 'cold' icons, in 3
different sizes.
```js
"resources": {
"media": [
{
"name": "WEATHER_HOT_ICON_TINY",
"type": "bitmap",
"file": "hot_tiny.png"
},
{
"name": "WEATHER_HOT_ICON_SMALL",
"type": "bitmap",
"file": "hot_small.png"
},
{
"name": "WEATHER_HOT_ICON_LARGE",
"type": "bitmap",
"file": "hot_large.png"
},
{
"name": "WEATHER_COLD_ICON_TINY",
"type": "bitmap",
"file": "cold_tiny.png"
},
{
"name": "WEATHER_COLD_ICON_SMALL",
"type": "bitmap",
"file": "cold_small.png"
},
{
"name": "WEATHER_COLD_ICON_LARGE",
"type": "bitmap",
"file": "cold_large.png"
}
]
}
```
Next we declare the `publishedMedia`:
```js
"resources": {
// .....
"publishedMedia": [
{
"name": "WEATHER_HOT",
"id": 1,
"glance": "WEATHER_HOT_ICON_TINY",
"timeline": {
"tiny": "WEATHER_HOT_ICON_TINY",
"small": "WEATHER_HOT_ICON_SMALL",
"large": "WEATHER_HOT_ICON_LARGE"
}
}, {
"name": "WEATHER_COLD",
"id": 2,
"glance": "WEATHER_COLD_ICON_TINY",
"timeline": {
"tiny": "WEATHER_COLD_ICON_TINY",
"small": "WEATHER_COLD_ICON_SMALL",
"large": "WEATHER_COLD_ICON_LARGE"
}
}
]
}
```
As you can see above, we can declare multiple entries in `publishedMedia`.
Let's look at the properties in more detail:
* `name` - This must be a unique alias to reference each entry of the
`publishedMedia` object. We use the `name` for the AppGlanceSlice
icon or Timeline Pin icon, and the system will load the appropriate resource
when required. The naming convention varies depending on where it's being used.
For example, the AppGlance C API prefixes the name: `PUBLISHED_ID_WEATHER_HOT`
but the other APIs use: `app://images/WEATHER_HOT`.
* `id` - This must be a unique number within the set of `publishedMedia`. It
must be greater than 0.
* `glance` - Optional. This references the `resource` image which will be
displayed if this `publishedMedia` is used as the `icon` of an
``AppGlanceSlice``. Size: 25x25.
* `timeline` - Optional. This references the `resource` images which will be
displayed if this `publishedMedia` is used for the various sizes of a timeline
icon. All three sizes must be specified. Sizes: Tiny 25x25, Small 50x50, Large
80x80.
> Your `publishedMedia` entry must include either `glance`, `timeline`, or both.
> If you specify `glance` and `timeline`, the `glance` must be the same resource
> as `timeline.tiny`.
> If you remove a `publishedMedia` entry, you must not re-use the ID.

View file

@ -0,0 +1,309 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: CloudPebble
description: |
How to use CloudPebble to create apps with no installation required.
guide_group: tools-and-resources
order: 1
---
[CloudPebble]({{ site.data.links.cloudpebble }}) is an online-only IDE
(Integrated Development Environment) for easy creation of Pebble apps.
It can be used as an alternative to the local SDK on Mac OSX and Linux, and is
the recommended app development option for Windows users. Features include:
* All-in-one project management, code editing, compilation, and installation.
* Intelligent real-time code completion including project symbols.
* Browser-based emulators for testing apps and generating screenshots without
physical hardware.
* Integration with GitHub.
To get started, log in with a Pebble Account. This is the same account as is
used for the Pebble Forums and the local SDK. Once logged in, a list of projects
will be displayed.
## Creating a Project
To create a new project, click the 'Create' button.
![create-project](/images/guides/tools-and-resources/create-project.png =480x)
Fill out the form including the name of the project, which type of project it
is, as well as the SDK version. Optionally begin with a project template. When
done, click 'Create'.
## Code Editor
The next screen will contain the empty project, unless a template was chosen.
This is the code editor screen, with the main area on the right being used to
write source files.
![empty-project](/images/guides/tools-and-resources/empty-project.png)
The left-hand menu contains links to other useful screens:
* Settings - Manage the metadata and behavior of the project as an analogue to
the local SDK's `package.json` file.
* Timeline - Test inserting and deleting
{% guide_link pebble-timeline "Pebble timeline" %} pins.
* Compilation - Compile and install the project, view app logs and screenshots.
This screen also contains the emulator.
* GitHub - Configure GitHub integration for this project.
In addition, the 'Source Files' and 'Resources' sections will list the
respective files as they are added to the project. As code is written, automatic
code completion will suggest completed symbols as appropriate.
## Writing Some Code
To begin an app from a blank project, click 'Add New' next to 'Source Files'.
Choose an appropriate name for the first file (such as `main.c`), leave the
target as 'App/Watchface', and click 'Create'.
The main area of the code editor will now display the code in the new file,
which begins with the standard include statement for the Pebble SDK:
```c
#include <pebble.h>
```
To begin a runnable Pebble app, simply add the bare bones functions for
initialization, the event loop, and deinitialization. From here everything else
can be constructed:
```c
void init() {
}
void deinit() {
}
int main() {
init();
app_event_loop();
deinit();
}
```
The right-hand side of the code editor screen contains convenient buttons for
use during development.
| Button | Description |
|:------:|:------------|
| ![](/images/guides/tools-and-resources/icon-play.png) | Build and run the app as configured on the 'Compilation' screen. By default this will be the Basalt emulator. |
| ![](/images/guides/tools-and-resources/icon-save.png) | Save the currently open file. |
| ![](/images/guides/tools-and-resources/icon-reload.png) | Reload the currently open file. |
| ![](/images/guides/tools-and-resources/icon-rename.png) | Rename the currently open file. |
| ![](/images/guides/tools-and-resources/icon-delete.png) | Delete the currently open file. |
## Adding Project Resources
Adding a resource (such as a bitmap or font) can be done in a similar manner as
a new code file, by clicking 'Add New' next to 'Resources' in the left-hand
pane. Choose the appropriate 'Resource Type' and choose an 'Identifier', which
will be available in code, prefixed with `RESOURCE_ID_`.
Depending on the chosen 'Resource Type', the remaining fields will vary:
* If a bitmap, the options pertaining to storage and optimization will be
displayed. It is recommended to use the 'Best' settings, but more information
on specific optimization options can be found in the
[*Bitmap Resources*](/blog/2015/12/02/Bitmap-Resources/#quot-bitmap-quot-to-the-rescue)
blog post.
* If a font, the specific characters to include (in regex form) and tracking
adjust options are available to adjust the font, as well as a compatibility
option that is best left to 'Latest'.
* If a raw resource, no extra options are available, save the 'Target Platforms'
option.
Once the new resource has been configured, browse the the file itself and upload
it by clicking 'Save'.
## Installing and Running Apps
The app under development can be compiled and run using the 'play' button on the
right-hand side of the code editor screen. If the compilation was successful,
the app will be run as configured. If not, the 'Compilation' screen will be
opened and the reason for failure can be seen by clicking 'Build Log' next to
the appropriate item in the build log. The 'Compilation' screen can be thought
of a comprehensive view of what the 'play' buttons does, with more control. Once
all code errors have been fixed, clicking 'Run Build' will do just that.
When the build is complete, options to install and run the app are presented.
Clicking one of the hardware platform buttons will run the app on an emulator of
that platform, while choosing 'Phone' and 'Install and Run' will install and run
the app on a physical watch connected to any phone logged in with the same
Pebble account.
In addition to running apps, the 'Compilation' screen also offers the ability to
view app log output and capture screenshots with the appropriate buttons.
Lastly, the `.pbw` bundle can also be obtained for testing and distribution in
the [Developer Portal](https://dev-portal.getpebble.com/).
### Interacting with the Emulator
Once an app is installed and running in the emulator, button input can be
simulated using the highlighted regions of the emulator view decoration. There
are also additional options available under the 'gear' button.
![](/images/guides/tools-and-resources/gear-options.png)
From this panel, muliple forms of input can be simulated:
* Adjust the charge level of the emulated battery with the 'Battery' slider.
* Set whether the emulated battery is in the charging state with the 'Charging'
checkbox.
* Set whether the Bluetooth connection is connected with the 'Bluetooth'
checkbox.
* Set whether the emulated watch is set to use 24- or 12-hour time format with
the '24-hour' checkbox.
* Open the app's configuration page (if applicable) with the 'App Config'
button. This will use the URL passed to `Pebble.openURL()`. See
{% guide_link user-interfaces/app-configuration %} for more information.
* Emulate live input of the accelerometer and compass using a mobile device by
clicking the 'Sensors' button and following the instructions.
* Shut down the emulated watch with the 'Shut Down' button.
## UI Editor
In addition to adding new code files and resources, it is also possible to
create ``Window`` layouts using a GUI interface with the UI editor. To use this
feature, create a new code file by clicking 'Add New' next to 'Source Files' and
set the 'File Type' to 'Window Layout'. Choose a name for the window and click
'Create'.
The main UI Editor screen will be displayed. This includes a preview of the
window's layout, as well as details about the current element and a toolkit of
new elements. This is shown in the image below:
![ui-editor](/images/guides/publishing-tools/ui-editor.png)
Since the only UI element that exists at the moment is the window itself, the
editor shows the options available for customizing this element's properties,
e.g. its background color and whether or not it is fullscreen.
### Adding More UI
Add a new UI element to the window by clicking on 'Toolkit', which contains a
set of standard UI elements. Choose a ``TextLayer`` element, and all the
available properties of the ``Layer`` to change its appearence and position will
be displayed:
![ui-editor-textlayer](/images/guides/publishing-tools/ui-editor-textlayer.png)
In addition to manually typing in the ``Layer``'s dimensions, use the anchor
points on the preview of the ``Layer`` on the left of the editor to click and
drag the size and position of the ``TextLayer``.
![ui-editor-drag](/images/guides/publishing-tools/ui-editor-drag.gif =148x)
When satisfied with the new ``TextLayer``'s configuration, use the 'UI Editor'
button on the right-hand side of the screen to switch back to the normal code
editor screen, where the C code that represents the ``Layer`` just set up
visually can be seen. An example of this generated code is shown below, along
with the preview of that layout.
```c
// BEGIN AUTO-GENERATED UI CODE; DO NOT MODIFY
static Window *s_window;
static GFont s_res_gothic_24_bold;
static TextLayer *s_textlayer_1;
static void initialise_ui(void) {
s_window = window_create();
window_set_fullscreen(s_window, false);
s_res_gothic_24_bold = fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD);
// s_textlayer_1
s_textlayer_1 = text_layer_create(GRect(0, 0, 144, 40));
text_layer_set_text(s_textlayer_1, "Hello, CloudPebble!");
text_layer_set_text_alignment(s_textlayer_1, GTextAlignmentCenter);
text_layer_set_font(s_textlayer_1, s_res_gothic_24_bold);
layer_add_child(window_get_root_layer(s_window), (Layer *)s_textlayer_1);
}
static void destroy_ui(void) {
window_destroy(s_window);
text_layer_destroy(s_textlayer_1);
}
// END AUTO-GENERATED UI CODE
```
![ui-editor-preview](/images/guides/publishing-tools/ui-editor-preview.png =148x)
> Note: As marked above, the automatically generated code should **not** be
> modified, otherwise it will not be possible to continue editing it with the
> CloudPebble UI Editor.
### Using the New Window
After using the UI Editor to create the ``Window``'s layout, use the two
functions provided in the generated `.h` file to include it in the app:
`main_window.h`
```c
void show_main_window(void);
void hide_main_window(void);
```
For example, call the `show_` function as part of the app's initialization
procedure and the `hide_` function as part of its deinitialization. Be sure to
include the new header file after `pebble.h`:
```c
#include <pebble.h>
#include "main_window.h"
void init() {
show_main_window();
}
void deinit() {
hide_main_window();
}
int main(void) {
init();
app_event_loop();
deinit();
}
```

View file

@ -0,0 +1,91 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
layout: guides/wide
title: Color Picker Tool
description: |
Preview all the colors available on Pebble with the associated SDK contants
and HTML codes.
guide_group: tools-and-resources
order: 5
scripts:
- tools/color-dict
- tools/color-picker
- tools/color-mapping-sunlight
---
<p>
Click a hexagon in the color map to see its SDK constant and how to use
it in your Pebble app.
</p>
<div class="row">
<div class="col-m-6">
{% include tools/color-picker-map.svg %}
</div>
<div class="col-m-6">
<div class="white-box">
<div class="row">
<div class="col-m-6"><a href="javascript:void(0)" class="btn btn--fg-white btn--bg-purple btn--wide js-btn-colormap" data-colormap="none">Uncorrected</a></div>
<div class="col-m-6"><a href="javascript:void(0)" class="btn btn--fg-white btn--bg-purple btn--wide js-btn-colormap" data-colormap="sunlight">Sunlight</a></div>
</div>
</div>
<div class="white-box">
<table class="table--skinny">
<tbody>
<tr>
<th style="width: 40%;">Name:</th>
<td class="text-right"><a href="#" id="js-picker-name"></a><span id="js-picker-name-no-url"></span></td>
</tr>
<tr>
<th>Sample:</th>
<td id="js-picker-block"></td>
</tr>
<tr>
<th>HTML code:</th>
<td class="text-right"><code id="js-picker-html"></code></td>
</tr>
<tr>
<th>Uncorrected HTML code:</th>
<td class="text-right"><code id="js-picker-html-uncorrected"></code></td>
</tr>
<tr>
<th>SDK Constant:</th>
<td class="text-right"><code id="js-picker-constant"></code></td>
</tr>
<tr>
<th>Code (RGB):</th>
<td class="text-right"><code id="js-picker-rgb"></code></td>
</tr>
<tr>
<th>Code (Hex):</th>
<td class="text-right"><code id="js-picker-hex"></code></td>
</tr>
</tbody>
</table>
<p></p>
<h4>Example Code Segment</h4>
<div id="js-picker-sample"></div>
</div>
<div class="gray-box">
<p>
See the
<a href="/guides/app-resources/images/#color-palettes">
<i>Images</i>
</a>
guide to get compatible palette files for popular image editing
programs.
</p>
</div>
</div>
</div>

View file

@ -0,0 +1,73 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: Developer Connection
description: |
How to enable and use the Pebble Developer Connection to install and debug
apps directly from a computer.
guide_group: tools-and-resources
order: 3
---
In order to install apps from the local SDK using the `pebble` tool or from
[CloudPebble]({{ site.links.cloudpebble }}), the Pebble Android or iOS app must
be set up to allow a connection from the computer to the watch. This enables
viewing logs and installing apps directly from the development environment,
speeding up development.
Follow the steps illustrated below to get started.
## Android Instructions
In the Pebble mobile app:
* Open the overflow menu by tapping the three dot icon at the top right and tap
*Settings*.
![](/images/guides/publishing-tools/enable-dev-android-1.png =300x)
* Enable the *Developer Mode* option.
![](/images/guides/publishing-tools/enable-dev-android-2.png =300x)
* Tap *Developer Connection* and enable the developer connection using the
toggle at the top right.
![](/images/guides/publishing-tools/enable-dev-android-4.png =300x)
* If using the `pebble` tool, make note of the 'Server IP'. If using
CloudPebble, this will be handled automatically.
## iOS Instructions
In the Pebble mobile app:
* Open the left-hand menu and tap the *Settings* item.
![](/images/guides/publishing-tools/enable-dev-ios-1.png =300x)
* Enable the Developer Mode using the toggle.
![](/images/guides/publishing-tools/enable-dev-ios-2.png =300x)
* Return to the menu, then tap the *Developer* item. Enable the Developer
Connection using the toggle at the top-right.
![](/images/guides/publishing-tools/enable-dev-ios-3.png =300x)
* If using the `pebble` tool, make note of the phone's 'Listening on' IP
address. If using CloudPebble, this will be handled automatically.

View file

@ -0,0 +1,37 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: Hardware Information
description: |
Details of the the capabilities of the various Pebble hardware platforms.
guide_group: tools-and-resources
order: 4
---
The Pebble watch family comprises of multiple generations of hardware, each with
unique sets of features and capabilities. Developers wishing to reach the
maximum number of users will want to account for these differences when
developing their apps.
The table below details the differences between hardware platforms:
{% include hardware-platforms.html %}
See
{% guide_link best-practices/building-for-every-pebble#available-defines-and-macros "Available Defines and Macros" %}
for a complete list of compile-time defines available.
**NOTE:** We'll be updating the "Building for Every Pebble Guide" and "Available
Defines and Macros" list when we release the first preview version of SDK 4.0.

View file

@ -0,0 +1,36 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: Tools and Resources
description: |
Information on all the software tools available when writing Pebble apps, as
well as other resources.
guide_group: tools-and-resources
menu: false
permalink: /guides/tools-and-resources/
generate_toc: false
hide_comments: true
---
This section of the developer guides contains information and resources
surrounding management of SDK projects themselves, as well as additional
information on using the Pebble emulator, CloudPebble, and the local SDK
command-line utility. Developers looking to add internationalization support can
also find information and tools for that purpose here.
## Contents
{% include guides/contents-group.md group=page.group_data %}

View file

@ -0,0 +1,270 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: Internationalization
description: |
How to localize an app to multiple languages.
guide_group: tools-and-resources
order: 5
---
When distributing an app in the Pebble appstore, it can be downloaded by Pebble
users all over the world. Depending on the app, this means that developers may
want to internationalize their apps for a varierty of different locales. The
locale is the region in the world in which the user may be using an app. The
strings used in the app to convey information should be available as
translations in locales where the app is used by speakers of a different
language. This is the process of localization. For example, users in France may
prefer to see an app in French, if the translation is available.
## Internationalization on Pebble
The Pebble SDK allows an app to be localized with the ``Internationalization``
API. Developers can use this to adjust how their app displays and behaves to
cater for users in non-English speaking countries. By default all apps are
assumed to be in English. Choose the user selected locale using
``i18n_get_system_locale()`` or to force one using ``setlocale()``.
> Note: The app's locale also affects ``strftime()``, which will output
> different strings for different languages. Bear in mind that these strings may
> be different lengths and use different character sets, so the app's layout
> should scale accordingly.
## Locales Supported By Pebble
This is the set of locales that are currently supported:
| Language | Region | Value returned by ``i18n_get_system_locale()`` |
|----------|--------|------------------------------------------------|
| English | United States | `"en_US"` |
| French | France | `"fr_FR"` |
| German | Germany | `"de_DE"` |
| Spanish | Spain | `"es_ES"` |
| Italian | Italy | `"it_IT"` |
| Portuguese | Portugal | `"pt_PT"` |
| Chinese | China | `"en_CN"` |
| Chinese | Taiwan | `"en_TW"` |
When the user's preferred language is set using the Pebble Time mobile app, the
required characters will be loaded onto Pebble and will be used by the
compatible system fonts. **This means that any custom fonts used should include
the necessary locale-specific characters in order to display correctly.**
## Translating an App
By calling `setlocale(LC_ALL, "")`, the app can tell the system that it supports
internationalization. Use the value returned by ``setlocale()`` to translate any
app strings. The implementation follows the
[libc convention](https://www.gnu.org/software/libc/manual/html_node/Setting-the-Locale.html#Setting-the-Locale).
Users may expect text strings, images, time display formats, and numbers to
change if they use an app in a certain language.
Below is a simple approach to providing a translation:
```c
// Use selocale() to obtain the system locale for translation
char *sys_locale = setlocale(LC_ALL, "");
// Set the TextLayer's contents depending on locale
if (strcmp("fr_FR", sys_locale) == 0) {
text_layer_set_text(s_output_layer, "Bonjour tout le monde!");
} else if ( /* Next locale string comparison */ ) {
/* other language cases... */
} else {
// Fall back to English
text_layer_set_text(s_output_layer, "Hello, world!");
}
```
The above method is most suitable for a few strings in a small number of
languages, but may become unwieldly if an app uses many strings. A more
streamlined approach for these situations is given below in
[*Using Locale Dictionaries*](#using-locale-dictionaries).
## Using the Locale in JavaScript
Determine the language used by the user's phone in PebbleKit JS using the
standard
[`navigator`](http://www.w3schools.com/jsref/prop_nav_language.asp) property:
```js
console.log('Phone language is ' + navigator.language);
```
```
[INFO ] js-i18n-example__1.0/index.js:19 Phone language is en-US
```
This will reflect the user's choice of 'Language & Input' -> 'Language' on
Android and 'General' -> 'Language & Region' -> 'i[Pod or Phone] Language' on
iOS.
> Note: Changing the language on these platforms will require a force close of
> the Pebble app or device restart before changes take effect.
## Choosing the App's Locale
It is also possible to explicitly set an app's locale using ``setlocale()``.
This is useful for providing a language selection option for users who wish to
do so. This function takes two arguments; the `category` and the `locale`
string. To set localization **only** for the current time, use `LC_TIME` as the
`category`, else use `LC_ALL`. The `locale` argument accepts the ISO locale
code, such as `"fr_FR"`. Alternatively, set `locale` to `NULL` to query the
current locale or `""` (an empty string) to set the app's locale to the system
default.
```c
// Force the app's locale to French
setlocale(LC_ALL, "fr_FR");
```
To adapt the way an application displays time, call `setlocale(LC_TIME, "")`.
This will change the locale used to display time and dates in ``strftime()``
without translating any strings.
## Effect of Setting a Locale
Besides returning the value of the current system locale, calling
``setlocale()`` will have a few other effects:
* Translate month and day names returned by ``strftime()`` `%a`, `%A`, `%b`, and
`%B`.
* Translate the date and time representation returned by ``strftime()`` `%c`.
* Translate the date representation returned by ``strftime()`` `%x`.
Note that currently the SDK will not change the decimal separator added by the
`printf()` family of functions when the locale changes; it will always be a `.`
regardless of the currently selected locale.
## Using Locale Dictionaries
A more advanced method to include multiple translations of strings in an app
(without needing a large number of `if`, `else` statements) is to use the
[Locale Framework](https://github.com/pebble-hacks/locale_framework). This
framework works by wrapping every string in the project's `src` directory in
the `_()` and replacing it with with a hashed value, which is then used with
the current locale to look up the translated string from a binary resource file
for that language.
Instructions for using this framework are as follows:
* Add `hash.h`, `localize.h` and `localize.c` to the project. This will be the
`src` directory in the native SDK.
* Include `localize.h` in any file to be localized:
```c
#include "localize.h"
```
* Initalize the framework at the start of the app's execution:
```c
int main(void) {
// Init locale framework
locale_init();
/** Other app setup code **/
}
```
* For every string in each source file to be translated, wrap it in `_()`:
```c
text_layer_set_text(some_layer, _("Meal application"));
```
* Save all source files (this will require downloading and extracting the
project from 'Settings' on CloudPebble), then run `get_dict.py` from the
project root directory to get a JSON file containing the hashed strings to be
translated. This file will look like the one below:
```
{
"1204784839": "Breakfast Time",
"1383429240": "Meal application",
"1426781285": "A fine meal with family",
"1674248270": "Lunch Time",
"1753964326": "Healthy in a hurry",
"1879903262": "Start your day right",
"2100983732": "Dinner Time"
}
```
* Create a copy of the JSON file and perform translation of each string, keeping
the equivalent hash values the same. Name the file according to the language,
such as `locale_french.json`.
* Convert both JSON files into app binary resource files:
```
$ python dict2bin.py locale_english.json
$ python dict2bin.py locale_french.json
```
* Add the output binary files as project resources as described in
{% guide_link app-resources/raw-data-files %}.
When the app is compiled and run, the `_()` macro will be replaced with calls
to `locale_str()`, which will use the app's locale to load the translated string
out of the binary resource files.
> Note: If the translation lookup fails, the framework will fall back to the
> English binary resource file.
## Publishing Localized Apps
The appstore does not yet support localizing an app's resources (such as name,
description, images etc), so use this guide to prepare the app itself. To cater
for users viewing appstore listings in a different locale, include a list of
supported languages in the listing description, which itself can be written in
multiple languages.
The format for a multi-lingual appstore description should display the supported
languages at the top and a include a copy in each language, as shown in the
example below:
> Now supports - French, German and Spanish.
>
> This compass app allows you to navigate in any directions from your wrist!
> Simply open the app and tilt to show the layout you prefer.
>
> Français
>
> Cette application de la boussole vous permet de naviguer dans toutes les
> directions à partir de votre poignet! Il suffit d'ouvrir l'application et de
> l'inclinaison pour montrer la disposition que vous préférez.
>
> Deutsch
>
> Dieser Kompass App ermöglicht es Ihnen, in jeder Richtung vom Handgelenk zu
> navigieren! Öffnen Sie einfach die App und kippen, um das Layout Sie
> bevorzugen zu zeigen.
>
> Español
>
> Esta aplicación brújula le permite navegar en cualquier dirección de la muñeca
> ! Basta con abrir la aplicación y la inclinación para mostrar el diseño que
> prefiera.

View file

@ -0,0 +1,633 @@
---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
title: Command Line Tool
description: |
How to use the Pebble command line tool to build, debug, and emulate apps.
guide_group: tools-and-resources
order: 2
toc_max_depth: 2
---
{% alert notice %}
This page applies only to developers using the SDK on their local machine;
CloudPebble allows you to use many of these features in 'Compilation'.
{% endalert %}
The Pebble SDK includes a command line tool called `pebble`. This tool allows
developers to create new projects, build projects, install apps on a watch and debug
them. This tool is part of the SDK, but many of these functions are made
available on [CloudPebble]({{ site.links.cloudpebble }}).
## Enabling the Developer Connection
Most `pebble` commands allow interaction with a Pebble watch. This relies on a
communication channel opened between the `pebble` tool on a computer and the
Pebble mobile application on the phone.
The `pebble` tool requires two configuration steps:
1. Enable the {% guide_link tools-and-resources/developer-connection %} in the
Pebble mobile application.
2. Give the phone IP address to the `pebble` tool as shown below to communicate
with a watch. This is not required when using the emulator or connecting via
CloudPebble.
## Connecting to a Pebble
There are four connection types possible with the command line tool. These can
be used with any command that involves a watch, for example `install`.
Connect to a physical watch connected to a phone on the same Wi-Fi network with
`IP` [IP address](#enabling-the-developer-connection):
```nc|text
$ pebble install --phone IP
```
Connect to an already running QEMU instance available on the `HOST` and `PORT`
provided:
```nc|text
$ pebble install --qemu HOST:PORT
```
Connect directly to a watch using a local Bluetooth connection, where `SERIAL`
is the path to the device file. On OS X, this is similar to
`/dev/cu.PebbleTimeXXXX-SerialPo` or `/dev/cu.PebbleXXXX-SerialPortSe`:
> Note: Replace 'XXXX' with the actual value for the watch in question.
```nc|text
$ pebble install --serial SERIAL
```
Alternatively, connect to a watch connected to the phone via the CloudPebble
proxy, instead of local Wi-Fi. This removes the need for local inter-device
communication, but still requires an internet connection on both devices:
```nc|text
$ pebble install --cloudpebble
```
## Configure the Pebble Tool
Save the IP address of the phone in an environment variable:
```text
$ export PEBBLE_PHONE=192.168.1.42
```
Save the default choice of emulator platform:
```text
$ export PEBBLE_EMULATOR=aplite
```
Save the default instance of QEMU:
```text
$ export PEBBLE_QEMU=localhost:12344
```
{% comment %}
Always use the CloudPebble proxy:
```text
$ export PEBBLE_CLOUDPEBBLE
```
{% endcomment %}
## Debugging Output
Get up to four levels of `pebble` tool log verbosity. This is available for all
commands:
```nc|text
# Minimum level of verbosity
$ pebble install -v
# Maximum logging verbosity
$ pebble install -vvvv
```
## Installing Watchapps
In addition to interacting with a physical Pebble watch, the Pebble emulator
included in the local SDK (as well as on CloudPebble) can be used to run and
debug apps without any physical hardware.
Build an app, then use `pebble install` with the `--emulator` flag to choose
between an emulator platform with `aplite`, `basalt`, or `chalk`. This allows
developers to test out apps on all platforms before publishing to the Pebble
appstore. For example, to emulate Pebble Time or Pebble Time Steel:
```nc|text
$ pebble install --emulator basalt
```
> Note: If no `--emulator` parameter is specified, the running emulator will
> be used.
With a suitable color app installed, the emulator will load and display it:
![](/images/guides/publishing-tools/emulator.png)
The Pebble physical buttons are emulated with the following mapping:
* Back - Left arrow key
* Up - Up arrow key
* Select - Right arrow key
* Down - Down arrow key
## Pebble Timeline in the Emulator
With the emulator, it is also possible to view any past and future pins on the
Pebble timeline by pressing Up or Down from the main watchface screen:
<table>
<tr>
<td><img src="/assets/images/guides/publishing-tools/timeline-past.png"/></td>
<td><img src="/assets/images/guides/publishing-tools/timeline-future.png"/></td>
</tr>
<tr style="text-align: center;">
<td>Timeline, past view</td><td>Timeline, future view</td>
</tr>
</table>
## Commands
This section summarizes the available commands that can be used in conjunction
with the `pebble` tool, on the applicable SDK versions. Most are designed to
interact with a watch with `--phone` or the emulator with `--emulator`.
### Project Management
#### new-project
```nc|text
$ pebble new-project [--simple] [--javascript] [--worker] [--rocky] NAME
```
Create a new project called `NAME`. This will create a directory in the
location the command is used, containing all essential project files.
There are also a number of optional parameters that allow developers to choose
features of the generated project to be created automatically:
* `--simple` - Initializes the main `.c` file with a minimal app template.
* `--javascript` - Creates a new application including a `./src/pkjs/index.js` file
to quickly start an app with a PebbleKit JS component. Read
{% guide_link communication/using-pebblekit-js %} for more information.
* `--worker` - Creates a new application including a `
./worker_src/NAME_worker.c` file to quickly start an app with a background
worker. Read {% guide_link events-and-services/background-worker %} for more
information.
* `--rocky` - Creates a new Rocky.js application. Do not use any other optional
parameters with this command. Read
[Rocky.js documentation](/docs/rockyjs/) for more information.
#### build
```nc|text
$ pebble build
```
Compile and build the project into a `.pbw` file that can be installed on a
watch or the emulator.
#### install
```nc|text
$ pebble install [FILE]
```
Install the current project to the watch connected to the phone with the given
`IP` address, or to the emulator on the `PLATFORM`. See
{% guide_link tools-and-resources/hardware-information %} for a list of
available platforms.
For example, the Aplite platform is specified as follows:
```nc|text
$ pebble install --emulator aplite
```
It is also possible to use this command to install a pre-compiled `.pbw` `FILE`.
In this case, the specified file will be installed instead of the current
project.
> Note: A `FILE` parameter is not required if running `pebble install` from
> inside a buildable project directory. In this case, the `.pbw` package is
> found automatically in `./build`.
#### clean
```nc|text
$ pebble clean
```
Delete all build files in `./build` to prepare for a clean build, which can
resolve some state inconsistencies that may prevent the project from building.
#### convert-project
```nc|text
$ pebble convert-project
```
Convert an existing Pebble project to the current SDK.
> Note: This will only convert the project, the source code will still have to
> updated to match any new APIs.
### Pebble Interaction
#### logs
```nc|text
$ pebble logs
```
Continuously display app logs from the watch connected to the phone with the
given `IP` address, or from a running emulator.
App log output is colorized according to log level. This behavior can be forced
on or off by specifying `--color` or `--no-color` respectively.
#### screenshot
```nc|text
$ pebble screenshot [FILENAME]
```
Take a screenshot of the watch connected to the phone with the given `IP`
address, or from any running emulator. If provided, the output is saved to
`FILENAME`.
Color correction may be disabled by specifying `--no-correction`. The
auto-opening of screenshots may also be disabled by specifying `--no-open`.
#### ping
```nc|text
$ pebble ping
```
Send a `ping` to the watch connected to the phone with the given `IP` address,
or to any running emulator.
#### repl
```nc|text
$ pebble repl
```
Launch an interactive python shell with a `pebble` object to execute methods on,
using the watch connected to the phone with the given `IP` address, or to any
running emulator.
#### data-logging
##### list
```nc|text
$ pebble data-logging list
```
List the current data logging sessions on the watch.
##### download
```nc|text
$ pebble data-logging download --session-id SESSION-ID FILENAME
```
Downloads the contents of the data logging session with the given ID
(as given by `pebble data-logging list`) to the given filename.
##### disable-sends
```nc|text
pebble data-logging disable-sends
```
Disables automatically sending data logging to the phone. This enables
downloading data logging information without the phone's interference.
It will also suspend any other app depending on data logging, which
includes some firmware functionality. You should remember to enable
it once you are done testing.
##### enable-sends
```nc|text
pebble data-logging enable-sends
```
Re-enables automatically sending data logging information to the phone.
##### get-sends-enabled
```nc|text
pebble data-logging get-sends-enabled
```
Indicates whether data logging is automatically sent to the phone. Change
state with `enable-sends` and `disable-sends`.
### Emulator Interaction
#### gdb
```nc|text
$ pebble gdb
```
Use [GDB](https://www.gnu.org/software/gdb/) to step through and debug an app
running in an emulator. Some useful commands are displayed in a cheat sheet
when run with `--help` and summarized in the table below:
> Note: Emulator commands that rely on interaction with the emulator (e.g.
> `emu-app-config`) will not work while execution is paused with GDB.
| Command | Description |
|---------|-------------|
| ctrl-C | Pause app execution. |
| `continue` or `c` | Continue app execution. The app is paused while a `(gdb)` prompt is available. |
| ctrl-D or `quit` | Quit gdb. |
| `break` or `b` | Set a breakpoint. This can be either a symbol or a position: <br/>- `b function_name` to break when entering a function.<br/>- `b file_name.c:45` to break on line 45 of `file_name.c`. |
| `step` or `s` | Step forward one line. |
| `next` or `n` | Step *over* the current line, avoiding stopping for any functions it calls into. |
| `finish` | Run forward until exiting the current stack frame. |
| `backtrace` or `bt` | Print out the current call stack. |
| `p [expression]` | Print the result of evaluating the given `expression`. |
| `info args` | Show the values of arguments to the current function. |
| `info locals` | Show local variables in the current frame. |
| `bt full` | Show all local variables in all stack frames. |
| `info break` | List break points (#1 is `<app_crashed>`, and is inserted by the `pebble` tool). |
| `delete [n]` | Delete breakpoint #n. |
Read {% guide_link debugging/debugging-with-gdb %} for help on using GDB to
debug app.
#### emu-control
```nc|text
$ pebble emu-control [--port PORT]
```
Send near real-time accelerometer and compass readings from a phone, tablet, or
computer to the emulator. When run, a QR code will be displayed in the terminal
containing the IP address the device should connect to. Scanning the code will
open this address in the device's browser. The IP address itself is also printed
in the terminal for manual entry. `PORT` may be specified in order to make
bookmarking the page easier.
![qr-code](/images/guides/publishing-tools/qr-code.png =450x)
After connecting, the device's browser will display a UI with two modes of
operation.
![accel-ui](/images/guides/publishing-tools/accel-ui.png =300x)
The default mode will transmit sensor readings to the emulator as they are
recorded. By unchecking the 'Use built-in sensors?' checkbox, manual values for
the compass bearing and each of the accelerometer axes can be transmitted to the
emulator by manipulating the compass rose or axis sliders. Using these UI
elements will automatically uncheck the aforementioned checkbox.
The values shown in bold are the Pebble SDK values, scaled relative to
``TRIG_MAX_ANGLE`` in the case of the compass bearing value, and in the range of
+/-4000 (+/- 4g) for the accelerometer values. The physical measurements with
associated units are shown beside in parentheses.
#### emu-app-config
```nc|text
$ pebble emu-app-config [--file FILE]
```
Open the app configuration page associated with the running app, if any. Uses
the HTML configuration `FILE` if provided.
See {% guide_link user-interfaces/app-configuration %} to learn about emulator-
specific configuration behavior.
#### emu-tap
```nc|text
$ pebble emu-tap [--direction DIRECTION]
```
Send an accelerometer tap event to any running emulator. `DIRECTION` can be one
of `x+`, `x-`, `y+`, `y-`, `z+`, or `z-`.
#### emu-bt-connection
```nc|text
$ pebble emu-bt-connection --connected STATE
```
Send a Bluetooth connection event to any running emulator. `STATE` can be either
`yes` or `no` for connected and disconnected events respectively.
> Note: The disconnected event may take a few seconds to occur.
#### emu-compass
```nc|text
$ pebble emu-compass --heading BEARING [--uncalibrated | --calibrating | --calibrated]
```
Send a compass update event to any running emulator. `BEARING` must be a number
between `0` and `360` to be the desired compass bearing. Use any of
`--uncalibrated`, `--calibrating`, or `--calibrated` to set the calibration
state.
#### emu-battery
```nc|text
$ pebble emu-battery [--percent LEVEL] [--charging]
```
Send a battery update event to any running emulator. `LEVEL` must be a number
between `0` and `100` to represent the new battery level. The presence of
`--charging` will determine whether the charging cable is plugged in.
#### emu-accel
```nc|text
$ pebble emu-accel DIRECTION [--file FILE]
```
Send accelerometer data events to any running emulator. `DIRECTION` can be any
of `tilt_left`, `tilt_right`, `tilt_forward`, `tilt_back`, `gravity+x`,
`gravity-x`, `gravity+y`, `gravity-y`, `gravity+z`, `gravity-z` , and `custom`.
If `custom` is selected, specify a `FILE` of comma-separated x, y, and z
readings.
#### transcribe
```nc|text
$ pebble transcribe [message] [--error {connectivity,disabled,no-speech-detected}]
```
Run a server that will act as a transcription service. Run it before
invoking the ``Dictation`` service in an app. If `message` is provided,
the dictation will be successful and that message will be provided.
If `--error` is provided, the dictation will fail with the given error.
`--error` and `message` are mutually exclusive.
```nc|text
$ pebble transcribe "Hello, Pebble!"
```
#### kill
```nc|text
$ pebble kill
```
Kill both the Pebble emulator and phone simulator.
#### emu-time-format
```nc|text
pebble emu-time-format --format FORMAT
```
Set the time format of the emulator to either 12-hour or 24-hour format, with a
`FORMAT` value of `12h` or `24h` respectively.
#### emu-set-timeline-quick-view
```nc|text
$ pebble emu-set-timeline-quick-view STATE
```
Show or hide the Timeline Quick View system overlay. STATE can be `on` or `off`.
#### wipe
```nc|text
$ pebble wipe
```
Wipe data stored for the Pebble emulator, but not the logged in Pebble account.
To wipe **all** data, specify `--everything` when running this command.
### Pebble Account Management
#### login
```nc|text
$ pebble login
```
Launces a browser to log into a Pebble account, enabling use of `pebble` tool
features such as pushing timeline pins.
#### logout
```nc|text
$ pebble logout
```
Logs out the currently logged in Pebble account from this instance of the
command line tool.
### Pebble Timeline Interaction
#### insert-pin
```nc|text
$ pebble insert-pin FILE [--id ID]
```
Push a JSON pin `FILE` to the Pebble timeline. Specify the pin `id` in the
`FILE` as `ID`.
#### delete-pin
```nc|text
$ pebble delete-pin FILE [--id ID]
```
Delete a pin previously pushed with `insert-pin`, specifying the same pin `ID`.
## Data Collection for Analytics
When first run, the `pebble` tool will ask for permission to collect usage
information such as which tools are used and the most common errors. Nothing
personally identifiable is collected.
This information will help us improve the SDK and is extremely useful for us,
allowing us to focus our time on the most important parts of the SDK as
discovered through these analytics.
To disable analytics collection, run the following command to stop sending
information:
```text
# Mac OSX
$ touch ~/Library/Application\ Support/Pebble\ SDK/NO_TRACKING
# Other platforms
$ touch ~/.pebble-sdk/NO_TRACKING
```