A Pebble watchface featuring a lighthouse with a rotating beam that sweeps across the sea.
Supported platforms:
- Gabbro (Pebble Round 2, 260×260 round)
- Emery (Pebble Time 2, 200×228 rectangle — background center-cropped)
- Pebble SDK v4.9+ installed
pebbleCLI available in$PATH- Python 3
# Build (all target platforms)
pebble build
# Install on emulator
pebble install --emulator gabbro # Pebble Round 2
pebble install --emulator emery # Pebble Time 2
# View logs
pebble logs --emulator gabbro| #0 | #1 | #2 | #3 | #4 |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
| #5 | #6 | #7 | #8 | #9 |
![]() |
![]() |
![]() |
![]() |
![]() |
| #0 | #1 | #2 | #3 | #4 |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
| #5 | #6 | #7 | #8 | #9 |
![]() |
![]() |
![]() |
![]() |
![]() |
The QEMU flash image can get corrupted after repeated install/uninstall cycles.
Fix (run each command on its own — don't chain with &&):
# 1. Kill any stale processes
pkill -f qemu-pebble
pkill -f pebble
# 2. Wipe the emulator's flash storage
pebble wipe
# 3. Rebuild
pebble build
# 4. Install
pebble install --emulator gabbroThe emulator sometimes needs time to boot fully:
# Wait 20s for boot, then retry
sleep 20
pebble install --emulator gabbropebble kill
pebble wipe
pebble build
pebble install --emulator gabbropebble sdk list
# Active SDK should be 4.9.x
# If missing: pebble sdk activate 4.9.169lighthouse/
├── package.json # Pebble project manifest
├── wscript # Build config
├── resources/
│ └── img/
│ ├── merged_pebble.png # Pre-merged background (260×260)
│ ├── bottle.png # Entity sprites (80×80, alpha PNG)
│ ├── chest.png
│ ├── fish.png
│ ├── shark.png
│ ├── ship.png
│ ├── siren.png
│ └── tentacle.png
├── assets/
│ ├── sprites/ # Source sprite images (pre-conversion)
│ ├── sea.png # Source background layers
│ └── lighthouse.png
├── src/
│ ├── c/
│ │ └── lighthouse.c # Watchface C source
│ └── pkjs/
│ └── index.js # Phone-side JS (empty)
├── COLOR_GUIDES.md # Color reference links
├── screenshot/ # Screenshots
└── build/ # Build output
└── lighthouse.pbw # Installable package (multi-platform)
Sprites (entities that appear on the sea) need to be converted to Pebble's exact 64-color palette before they work correctly on the watchface. The conversion preserves both the dithering quality and the alpha transparency.
- ImageMagick (
convert) installed - Official Pebble 64-color palette at
/tmp/pebble_colors_64.gif
# 1. Extract binary alpha mask (threshold 5% to capture anti-aliased edges)
convert assets/sprites/ship.png \
-resize 80x80 \
-alpha extract \
-threshold 5% \
/tmp/ship_alpha.png
# 2. Quantize color channels to Pebble's 64-color palette
convert assets/sprites/ship.png \
-resize 80x80 \
-alpha off \
-dither FloydSteinberg \
-remap /tmp/pebble_colors_64.gif \
/tmp/ship_color.png
# 3. Combine quantized colors + binary alpha
convert /tmp/ship_color.png \
/tmp/ship_alpha.png \
-alpha off \
-compose CopyOpacity \
-composite \
resources/img/ship_sprite.pngfor f in assets/sprites/*.png; do
name=$(basename "$f" .png)
convert "$f" -resize 80x80 -alpha extract -threshold 5% "/tmp/${name}_alpha.png"
convert "$f" -resize 80x80 -alpha off \
-dither FloydSteinberg -remap /tmp/pebble_colors_64.gif "/tmp/${name}_color.png"
convert "/tmp/${name}_color.png" "/tmp/${name}_alpha.png" \
-alpha off -compose CopyOpacity -composite "resources/img/${name}_sprite.png"
doneThe official palette (one swatch per Pebble color) can be downloaded from:
curl -sL -o /tmp/pebble_colors_64.gif \
"https://developer.repebble.com/assets/other/pebble_colors_64.gif"In package.json, sprite resources must use storageFormat: "png" (not "pbi") so the Pebble runtime's PNG decoder handles alpha transparency natively:
{
"type": "bitmap",
"name": "IMAGE_SHIP_SPRITE",
"file": "img/ship_sprite.png",
"memoryFormat": "8Bit",
"storageFormat": "png"
}Sprites with alpha should be drawn using GCompOpSet compositing mode so only opaque pixels overwrite the background:
graphics_context_set_compositing_mode(ctx, GCompOpSet);
graphics_draw_bitmap_in_rect(ctx, s_ship_bmp, (GRect){{x, y}, {80, 80}});
graphics_context_set_compositing_mode(ctx, GCompOpAssign);- Sea: 260×260 RGB PNG — full-screen background
- Lighthouse: 260×260 RGBA PNG — composited with alpha transparency
- Transparent areas (alpha < 3) will be invisible on Pebble
- The C code uses
GCompOpSetcompositing mode for proper alpha rendering
On Emery (Pebble Time 2, 200×228 rectangle), the 260×260 background is
center-cropped at draw time — no additional assets needed. Entity placement,
beam rendering, and clock text all adapt dynamically to the display size via
s_cx/s_cy (center coordinates computed from layer_get_bounds()).
To generate screenshots with varied beam positions and a guaranteed entity:
- In
src/c/lighthouse.c, set#define SCREENSHOT_MODE 1 - Build:
pebble build - Install:
pebble install --emulator gabbro - The beam rotates through all 24 hours (advancing every 5 seconds)
- The ship entity is guaranteed to spawn each day (all other entities follow normal probability)
- Snap screenshots at desired moments:
pebble screenshot --no-open screenshot/01.png - Reset
#define SCREENSHOT_MODE 0and rebuild for production



















