--- # 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: tutorials/tutorial tutorial: watchface tutorial_part: 2 title: Customizing Your Watchface description: A guide to personalizing your new Pebble watchface permalink: /tutorials/watchface-tutorial/part2/ generate_toc: true platform_choice: true --- In the previous page of the tutorial, you learned how to create a new Pebble project, set it up as a basic watchface and use ``TickTimerService`` to display the current time. However, the design was pretty basic, so let's improve it with some customization! In order to do this we will be using some new Pebble SDK concepts, including: - Resource management - Custom fonts (using ``GFont``) - Images (using ``GBitmap`` and ``BitmapLayer``) These will allow us to completely change the look and feel of the watchface. We will provide some sample materials to use, but once you understand the process be sure to replace these with your own to truly make it your own! Once we're done, you should end up with a watchface looking like this: {% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/2-final.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %} ## First Steps To continue from the last part, you can either modify your existing Pebble project or create a new one, using the code from that project's main `.c` file as a starting template. For reference, that should look [something like this](https://gist.github.com/pebble-gists/9b9d50b990d742a3ae34). ^CP^ You can create a new CloudPebble project from this template by [clicking here]({{ site.links.cloudpebble }}ide/gist/9b9d50b990d742a3ae34). The result of the first part should look something like this - a basic time display: {% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/1-time.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %} Let's improve it! ## Adding a Custom Font ^CP^ To add a custom font resource to use for the time display ``TextLayer``, click 'Add New' on the left of the CloudPebble editor. Set the 'Resource Type' to 'TrueType font' and upload a font file. Choose an 'Identifier', which is the value we will use to refer to the font resource in the `.c` file. This must end with the desired font size, which must be small enough to show a wide time such as '23:50' in the ``TextLayer``. If it does not fit, you can always return here to try another size. Click save and the font will be added to your project. ^LC^ App resources (fonts and images etc.) are managed in the `package.json` file in the project's root directory, as detailed in [*App Resources*](/guides/app-resources/). All image files and fonts must reside in subfolders of the `/resources` folder of your project. Below is an example entry in the `media` array:
{% highlight {} %} "media": [ { "type": "font", "name": "FONT_PERFECT_DOS_48", "file": "fonts/perfect-dos-vga.ttf", "compatibility":"2.7" } ] {% endhighlight %}
^LC^ In the example above, we would place our `perfect-dos-vga.ttf` file in the `/resources/fonts/` folder of our project. A custom font file must be a [TrueType](http://en.wikipedia.org/wiki/TrueType) font in the `.ttf` file format. [Here is an example font to use]({{ site.asset_path }}/fonts/getting-started/watchface-tutorial/perfect-dos-vga.ttf) ([source](http://www.dafont.com/perfect-dos-vga-437.font)). Now we will substitute the system font used before (`FONT_KEY_BITHAM_42_BOLD`) for our newly imported one. To do this, we will declare a ``GFont`` globally. ```c // Declare globally static GFont s_time_font; ``` Next, we add the creation and substitution of the new ``GFont`` in the existing call to ``text_layer_set_font()`` in `main_window_load()`. Shown here is an example identifier used when uploading the font earlier, `FONT_PERFECT_DOS_48`, which is always pre-fixed with `RESOURCE_ID_`: ```c void main_window_load() { // ... // Create GFont s_time_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_PERFECT_DOS_48)); // Apply to TextLayer text_layer_set_font(s_time_layer, s_time_font); // ... } ``` And finally, safe destruction of the ``GFont`` in `main_window_unload()`: ```c void main_window_unload() { // ... // Unload GFont fonts_unload_custom_font(s_time_font); // ... } ``` ^CP^ After re-compiling and re-installing (either by using the green 'Play' button to the top right of the CloudPebble editor, or by clicking 'Run Build' and 'Install and Run' on the 'Compilation' screen), the watchface should feature a much more interesting font. ^LC^ After re-compiling and re-installing with `pebble build && pebble install`, the watchface should feature a much more interesting font. An example screenshot is shown below: {% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/2-custom-font.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %} ## Adding a Bitmap The Pebble SDK also allows you to use a 2-color (black and white) bitmap image in your watchface project. You can ensure that you meet this requirement by checking the export settings in your graphics package, or by purely using only white (`#FFFFFF`) and black (`#000000`) in the image's creation. Another alternative is to use a dithering tool such as [HyperDither](http://2002-2010.tinrocket.com/software/hyperdither/index.html). This will be loaded from the watchface's resources into a ``GBitmap`` data structure before being displayed using a ``BitmapLayer`` element. These two behave in a similar fashion to ``GFont`` and ``TextLayer``, so let's get started. ^CP^ The first step is the same as using a custom font; import the bitmap into CloudPebble as a resource by clicking 'Add New' next to 'Resources' on the left of the CloudPebble project screen. Ensure the 'Resource Type' is 'Bitmap image', choose an identifier for the resource and upload your file. ^LC^ You add a bitmap to the `package.json` file in the [same way](/guides/app-resources/fonts) as a font, except the new `media` array object will have a `type` of `bitmap`. Below is an example:
{% highlight {} %} { "type": "bitmap", "name": "IMAGE_BACKGROUND", "file": "images/background.png" } {% endhighlight %}
As before, here is an example bitmap we have created for you to use, which looks like this: [![background](/images/getting-started/watchface-tutorial/background.png "background")]({{ site.asset_path }}/images/getting-started/watchface-tutorial/background.png) Once this has been added to the project, return to your `.c` file and declare two more pointers, one each of ``GBitmap`` and ``BitmapLayer`` near the top of the file: ```c static BitmapLayer *s_background_layer; static GBitmap *s_background_bitmap; ``` Now we will create both of these in `main_window_load()`. After both elements are created, we set the ``BitmapLayer`` to use our ``GBitmap`` and then add it as a child of the main ``Window`` as we did for the ``TextLayer``. However, is should be noted that the ``BitmapLayer`` must be added to the ``Window`` before the ``TextLayer``. This will ensure that the text is drawn *on top of* the image. Otherwise, the text will be drawn behind the image and remain invisible to us. Here is that process in full, to be as clear as possible: ```c // Create GBitmap s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_BACKGROUND); // Create BitmapLayer to display the GBitmap s_background_layer = bitmap_layer_create(bounds); // Set the bitmap onto the layer and add to the window bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap); layer_add_child(window_layer, bitmap_layer_get_layer(s_background_layer)); ``` As always, the final step should be to ensure we free up the memory consumed by these new elements in `main_window_unload()`: ```c // Destroy GBitmap gbitmap_destroy(s_background_bitmap); // Destroy BitmapLayer bitmap_layer_destroy(s_background_layer); ``` The final step is to set the background color of the main ``Window`` to match the background image. Do this in `init()`: ```c window_set_background_color(s_main_window, GColorBlack); ``` With all this in place, the example background image should nicely frame the time and match the style of the new custom font. Of course, if you have used your own font and bitmap (highly recommended!) then your watchface will not look exactly like this. {% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/2-final.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %} ## Conclusion After adding a custom font and a background image, our new watchface now looks much nicer. If you want to go a bit further, try adding a new ``TextLayer`` in the same way as the time display one to show the current date (hint: look at the [formatting options](http://www.cplusplus.com/reference/ctime/strftime/) available for `strftime()`!) As with last time, you can compare your own code to the example source code using the button below. ^CP^ [Edit in CloudPebble >{center,bg-lightblue,fg-white}]({{ site.links.cloudpebble }}ide/gist/d216d9e0b840ed296539) ^LC^ [View Source Code >{center,bg-lightblue,fg-white}](https://gist.github.com/d216d9e0b840ed296539) ## What's Next? The next section of the tutorial will introduce PebbleKit JS for adding web-based content to your watchface. [Go to Part 3 → >{wide,bg-dark-red,fg-white}](/tutorials/watchface-tutorial/part3/)