Rocky.js – Pebble watch coding in JavaScript

Pebble never ceases to amaze. And every time you think – this is it, they reached the pinnacle of awesomeness – they surprise you again. This time they did pretty much the impossible – ported their C SDK to JavaScript, by creating Rocky.JS project. Ultimate goal is to run JS directly on the watch hardware – this will open way to huge number of new developers who hesitate to dive into depth of C. Meanwhile it provides ability to run Pebble code directly in a browser! It’s a lot of fun and as a bonus you can insert Pebble watchfaces directly into your website as evident by living watchface you see here.
Watchface you see running above is called Meyer Object it’s been available for Pebble watch for a while and I decided to port it to Rocky.JS

Original C source is available here (under original name “Nazar Frames”). Perusing Rocky.JS documentation and original examples I came up with this:

// GPATH COORDINATES

var MINUTE_HAND_POINTS = [
    [ -3, 0 ],  
    [ 3, 0 ],   
    [ 3, -50 ],    
    [ 50, -50],    
    [ 50, 50],    
    [ -50, 50 ],        
    [ -50, -50],      
    [ -3, -50 ]      
  ];

var HOUR_HAND_POINTS = [
    [ -5, -50 ], 
    [ -5, 0 ],    
    [ 5, 0 ],      
    [ 5, -50 ],      
    [ 50, -50],      
    [ 50, 50],     
    [ -50, 50 ],      
    [ -50, -50 ]      
];
       
var SECOND_HAND_POINTS = [
    [ 0, -50 ],
    [ 0, 0 ],    
    [ 0, -50 ],      
    [ 50, -50],      
    [ 50, 50],      
    [ -50, 50 ],      
    [ -50, -50 ]      
];       


(function () {
        var rocky = Rocky.bindCanvas(document.getElementById('pebble'));
        rocky.export_global_c_symbols();
        
        var minute_arrow = gpath_create(MINUTE_HAND_POINTS);
        var hour_arrow = gpath_create(HOUR_HAND_POINTS);
        var second_arrow = gpath_create(SECOND_HAND_POINTS);

        rocky.update_proc = function (ctx, bounds) {
        
            gpath_move_to(minute_arrow, [bounds.w / 2, bounds.h / 2]);
            gpath_move_to(hour_arrow, [bounds.w / 2, bounds.h / 2]);
            gpath_move_to(second_arrow, [bounds.w / 2, bounds.h / 2]);
            
            //background
            graphics_context_set_fill_color(ctx, GColorBlack);
            graphics_fill_rect(ctx, [0,0,bounds.w, bounds.h]);
            
            //time 
            var date = new Date;
            var tm_hour = date.getHours();
            var tm_min = date.getMinutes();
            var tm_sec = date.getSeconds();
                        
            //hours
            graphics_context_set_stroke_color(ctx, GColorGreen);
            graphics_context_set_stroke_width(ctx, 2);
            gpath_rotate_to(hour_arrow, (2*Math.PI * (((tm_hour % 12) * 6) + (tm_min / 10))) / (12 * 6)); 
            gpath_draw_outline(ctx, hour_arrow)
            
            //minutes
            graphics_context_set_stroke_color(ctx, GColorYellow);
    	    graphics_context_set_stroke_width(ctx, 2);
            gpath_rotate_to(minute_arrow, 2*Math.PI * tm_min / 60);    
            gpath_draw_outline(ctx, minute_arrow)
            
            //seconds
            graphics_context_set_stroke_color(ctx, GColorWhite);
            graphics_context_set_stroke_width(ctx, 1);
            gpath_rotate_to(second_arrow, 2*Math.PI * tm_sec / 60);
            gpath_draw_outline(ctx, second_arrow)
            
            //dot in the middle
            graphics_context_set_fill_color(ctx, GColorRed);
    	    graphics_fill_circle(ctx, [bounds.w / 2, bounds.h / 2] , 8);
    	    graphics_context_set_fill_color(ctx, GColorDarkCandyAppleRed);
    	    graphics_fill_circle(ctx, [bounds.w / 2, bounds.h / 2] , 3);
            
        };
        
       setInterval(function () {
            rocky.mark_dirty();
        }, 1000);
    })();

If you’re familiar with Pebble C SDK and look at the original C Source of the watchface, you’ll notice striking similarities. That is because the code is almost identical.
Lines 03-33 create arrays of points (similar to GPathInfo of C SDK).
Lines 37-38 create Pebble graphics context out of HTML5 Canvas and export global symbols for easy access.
Lines 40-42 create 3 GPath objects to represent 3 wire-frames for hour, minute ans second hands.
Line 44 defines a handler for graphics update – it’s called every time canvas is marked dirty.
Lines 46-48 move all 3 GPath objects to the center of canvas.
Lines 51-52 draw a full-canvas black rectangle to serve as the background
Lines 55-58 get current time in hours, minutes and seconds
Lines 61-76 set the color, width and rotation angle for each of the frames. Note that instead of TRIG_MAX_ANGLE that represent maximum avalaible angle value in C SDK, here we use 2*π instead
Lines 86-88 set a timer interval (replacement for C’s TickTimerService to mark canvas dirty every second, causing frames to redraw.

That’s it, all pretty straightforward. If you want to play with code yourself – JSFiddle of Meyer Objects is available

One reply

Leave a Reply

Your email address will not be published. Required fields are marked *