Category Archives: 13-pebbleclock

Matthew Kellogg – Pebble – Snowfall

I originally wanted to make a water droplet fall into the screen each second, filling the screen each hour, but I quickly ran into trouble with the memory restrictions on the Pebble. I took a long time considering possibilities of what I could do with little to no memory. I wanted to make something visually pleasing. I thought about what could be easier than water and remembered a simple snow screensaver I had made in my Introduction to Computer Programming class in high school. I was probably reminded of this due to the weather conditions. After making the snow work on the screen, I realized what I’d made did not tell time. For this reason, I added a ground which would accumulate and be relieved of snow on an hourly basis. I then added a sun and moon that would pass through the sky telling the time of day. I based the sun and moon motion based on a sunrise and sunset at 6 AM and 6 PM with the moon taking the other half of the day.

I am happy with the final project. I enjoy the simplicity of how I’ve shown the progress through the day because it is divorced from our numeric concept of time.

At 2:10 PM:
At 3:40 AM:
At 6:50 AM:


These are sketches for my final and original idea.


Here is the final code:

//Snow Clock
// by: Matthew Kellogg
// date: January 27, 2015
// Copyright 2015 Matthew Kellogg

#include "pebble.h"

static Window *window;

static GRect window_frame;

static Layer *root_layer;

#define WIDTH 144
#define HEIGHT 168

//An array of the x positions of the snowflakes
// there is one snowflake at each y coordinate
static uint8_t flakes_x[HEIGHT];

//This is called whenever the layer needs redrawn.
//This draws all of the scene
static void layer_update_callback(Layer *me, GContext *ctx) {
  graphics_context_set_fill_color(ctx, GColorBlack);
  graphics_fill_rect(ctx, window_frame, 0, GCornerNone);
  //get time
  time_t t = time(NULL);
  struct tm* time = localtime(&t);
  int buffer = 76;
  int done = ((HEIGHT-buffer)*((60*time->tm_min) + time->tm_sec)) / 3600;
  //draw snow base
  GRect snow_rect = GRect(0, HEIGHT-done, WIDTH, done);
  graphics_context_set_fill_color(ctx, GColorWhite);
  graphics_fill_rect(ctx, snow_rect,0 , GCornerNone);
  //draw sun/ moon
  // sun rise at 6AM set at 6PM, moon rise and set at 6 PM and 6 AM
  int sunx = (WIDTH*(((time->tm_hour+6)%12))*60 +time->tm_min)/(12*60);
  graphics_fill_circle(ctx,GPoint(sunx,56), 20);
  if (time->tm_hour >= 18 || time->tm_hour<6){
    graphics_context_set_fill_color(ctx, GColorBlack);
    graphics_fill_circle(ctx, GPoint(sunx+10,56), 14);
    graphics_context_set_fill_color(ctx, GColorWhite);
  //draw flakes
  graphics_context_set_stroke_color(ctx, GColorWhite);
  int i,y;
  for (i=0;i<HEIGHT; i++){     y = i%HEIGHT;     graphics_fill_circle(ctx,GPoint(flakes_x[y],y),2);   } } //This is called once per second //It updates snowflake positions and marks the layer for redraw static void timer_callback(struct tm *tick_time, TimeUnits units_changed){   //update   int i;   for (i = HEIGHT -1; i >= 0; i--){
    flakes_x[(i+1)%HEIGHT] = (int)flakes_x[i]-1+(rand()%3);
//This initializes the snowflake array with random coordinates
static void flakes_init(){
  int i;
  for (i = 0; i< HEIGHT; i++){
    flakes_x[i] = rand()%HEIGHT;

//This is called when the window is available
// It gets the layer and sets the update function
static void window_load(Window *window) {
  root_layer = window_get_root_layer(window);
  window_frame = layer_get_frame(root_layer);
  layer_set_update_proc(root_layer, layer_update_callback);

//This function is empty because no dynamic memory is used
static void window_unload(Window *window) {

//This method is called when the app is being initialized
static void init(void) {
  window = window_create();
  window_set_window_handlers(window, (WindowHandlers) {
    .load = window_load,
    .unload = window_unload
  window_stack_push(window, true /* Animated */);
  window_set_background_color(window, GColorBlack);

  //initialize flakes
  tick_timer_service_subscribe(SECOND_UNIT, timer_callback);

static void deinit(void) {

int main(void) {


27 Jan 2015

res / ponder from Miles Peyton on Vimeo.

I used the Pebble watch for a few days to get a sense of its functionality. During this trial period I noticed that I would zone out during social interactions and read texts on the Pebble instead. Feeling texts vibrate into existence on my wrist gave them an urgency and physicality that sometimes made the texts more compelling than my friends.

“res / ponder” visualizes texts that you haven’t responded to. The texts behave as fluid that becomes more viscous the longer you wait to respond.

To make the app, I made a companion Android app that informs the Pebble when texts are sent and received.

The Pebble program uses accelerometer data to calculate the motion of the texts.




Thomas Langerak

27 Jan 2015

This was part of the first assignment and the first time that I really had a look at the C language. I was working on this project together with Maddy Varner. As she is an experienced programmer and I just started we divided the tasks according to skill, so both could learn from it. Personally I was responsible for the time management and getting the circles from the minutes and hours. Though this was initially difficult for me I am not happy with the amount of work I did in the end. Though I came more familiar with the programming language C, it could have been far more. I will carry a heavier workload in the future to alter this.

The clock itself is based on an hourglass and can display either minutes or hours. The amount of ‘grains’ correspond to the amount of minutes/hours. The fall down according to the watch orientation measured with the accelerometer. We started from the example involving the accelerometer and made changes and additions along the way. A video can be found here: .

The code can be found here:

Sylvia Kosowski

27 Jan 2015

The size of the Pebble Watch reminded me of the Tamagotchi toys I used to play with as a kid, so I decided to make a project featuring a Time Monster, which the owner of the watch must look after. It also functions as a watch of sorts, though it only really works with telling relative time. Every minute, the monster will become sad and the watch will buzz. The monster will demand some sort of display of affection from the user. To make the monster happy again, the user can shake the watch. The monster demands the same thing every minute, but every 15, 30, 45, and 60 minutes, it will demand something unique. By following the pattern of these unique demands, the user is able to gain a relative sense of how much time has passed within an hour.

The concept for this Time Monster also stemmed from the fact that people are constantly checking the time throughout the day in order to make plans, arrive at destinations, etc. Time is a very demanding entity, so I wanted to personify this quality in the form of a demanding pet to look after.



“Hug Me” is displayed at the 15 min mark of each hour.

"Feed me" is displayed at the 30 min mark of an hour.

“Feed me” is displayed at the 30 min mark of an hour.

"Tell me a story" is displayed at the 45 min mark of an hour.

“Tell me a story” is displayed at the 45 min mark of an hour.

"Love me" is displayed every hour.

“Love me” is displayed every hour.

"Wanna play?" is displayed every minute which is not one of the 0-15-30-45 min markers.

“Wanna play?” is displayed every minute which is not one of the 0-15-30-45 min markers.

This shows when the monster is content, between minutes.

This shows when the monster is content, between minutes.

Concept sketch

Concept sketch

Below is the code:

#include <pebble.h>

static Window *s_main_window;

static BitmapLayer *s_image_layer;
static GBitmap *bestFriend;
static GBitmap *feedMe;
static GBitmap *hugMe;
static GBitmap *loveMe;
static GBitmap *tellMeStory;
static GBitmap *playWithMe;

bool isDemanding;

static void update_time() {
 // Get a tm structure
 time_t temp = time(NULL); 
 struct tm *tick_time = localtime(&temp);
 if(tick_time->tm_min == 0) {
 bitmap_layer_set_bitmap(s_image_layer, loveMe);
 isDemanding = true;
 } else if(tick_time->tm_min == 15) {
 bitmap_layer_set_bitmap(s_image_layer, hugMe);
 isDemanding = true;
 } else if(tick_time->tm_min == 30) {
 bitmap_layer_set_bitmap(s_image_layer, tellMeStory);
 isDemanding = true;
 } else if(tick_time->tm_min == 45) {
 bitmap_layer_set_bitmap(s_image_layer, feedMe);
 isDemanding = true;
 } else if(tick_time->tm_sec == 0) {
 bitmap_layer_set_bitmap(s_image_layer, playWithMe);
 isDemanding = true;

//Handles the time
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {

//Handles accelerometer stuff
static void tap_handler(AccelAxisType axis, int32_t direction) {
 if(isDemanding) {
 if(direction != 0) {
 isDemanding = false;
 bitmap_layer_set_bitmap(s_image_layer, bestFriend);

static void main_window_load(Window *window) {
 bestFriend = gbitmap_create_with_resource(RESOURCE_ID_BEST_FRIEND);
 feedMe = gbitmap_create_with_resource(RESOURCE_ID_FEED_ME);
 hugMe = gbitmap_create_with_resource(RESOURCE_ID_HUG_ME);
 loveMe = gbitmap_create_with_resource(RESOURCE_ID_LOVE_ME);
 tellMeStory = gbitmap_create_with_resource(RESOURCE_ID_TELL_ME_STORY);
 playWithMe = gbitmap_create_with_resource(RESOURCE_ID_PLAY_WITH_ME);
 s_image_layer = bitmap_layer_create(GRect(0, 0, 144, 168));
 bitmap_layer_set_bitmap(s_image_layer, bestFriend);
 layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(s_image_layer));


static void main_window_unload(Window *window) {
 // Destroy GBitmaps
 // Destroy BitmapLayer

static void init() {
 isDemanding = false;
 //Register with TickTimerService
 tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
 //Register with Accelerometer tap event service
 //Create main Window element and assign to pointer
 s_main_window = window_create();
 //Set handlers to manage the elements inside the Window
 window_set_window_handlers(s_main_window, (WindowHandlers) {
 .load = main_window_load,
 .unload = main_window_unload
 //Show the Window on the watch, with animated=true
 window_stack_push(s_main_window, true);

static void deinit() {
 //Destroy Window

int main(void) {

Amy Friedman

27 Jan 2015


This watch face addresses the amount of minutes utilized to make up an hour. We are focused on numbers and this watch face shows the usage of minutes and the hours increase over a 24 hour period. The rectangles associate time with space and geometric shapes as our buildings, books, phones, cars, are created for the most part by geometry rather than organic features. Many times geometry is affiliated with rigidity and order as it is easy to control the possibilities, this watchface standardizes a structure for time to follow.

IMG_1742 copy

The face is split into two for representation of hours. From 12:00AM until 11: 59AM the hour indicator spans the width of the watch face and expands downward from the top of the watch face until the bottom. From 12:00 PM until 11:59 PM the hours expand upward as time increases. For both faces the minutes span from the length of the watchface and expand left to right using a rectangular indicator, after 60 minutes the rectangle restarts from the beginning and its height depreciates as the hours increase in the morning hours it decreases downward, in the night hours it decreases upward.


Pebble Watch from Amy Friedman on Vimeo.


// Amy Friedman Copyright Jan 2015
//Used help for get_display_hour from Github Pebble SDK Examples & PhilPlckthun
//Used Pebble App/DisplayandAnimations/Drawing for help also


static Window *s_main_window;
static Layer *s_canvas_layer;

unsigned short get_display_hour(unsigned short hour) {
if (clock_is_24h_style()) {
return hour;
unsigned short display_hour = hour % 12;
return display_hour ? display_hour : 12;

static void canvas_update_proc(Layer *this_layer, GContext *ctx) {

//use current time
time_t now = time(NULL);
struct tm *t = localtime(&now);

int display_hour = get_display_hour(t->tm_hour);
int minute = t->tm_min;

float min_size = ((144-2)/60);
float hr_size = ((168-2)/12);
//if its 12 then everything changes

graphics_context_set_fill_color(ctx, GColorBlack);
if (display_hour<11){
graphics_fill_rect(ctx, GRect(1, 2+(hr_size*display_hour), min_size*minute, 165-(hr_size*display_hour)), 0, GCornerNone);
graphics_fill_rect(ctx, GRect(1, 1,142, hr_size*display_hour), 0, GCornerNone);}
display_hour = display_hour-12;
graphics_fill_rect(ctx, GRect(1, 1, min_size*minute, 165-(hr_size*display_hour)), 0, GCornerNone);
graphics_fill_rect(ctx, GRect(1, 167-(hr_size*display_hour),142, hr_size*display_hour), 0, GCornerNone);}

//tester rect
// graphics_fill_rect(ctx, GRect(1, 1, 142, 150), 0, GCornerNone);

static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {

static void main_window_load(Window *window) {
Layer *window_layer = window_get_root_layer(window);
GRect window_bounds = layer_get_bounds(window_layer);

// Create Layer
s_canvas_layer = layer_create(GRect(0, 0, window_bounds.size.w, window_bounds.size.h));
layer_add_child(window_layer, s_canvas_layer);

// Set the update_proc
layer_set_update_proc(s_canvas_layer, canvas_update_proc);