Programming in Elm for Pebble watches

Over the past few weeks, I’ve been evolving a side project I’ve had in mind since last Elm Camp: programming in Elm for Pebble watches rather than web frontends.

As you may know, there are new Pebble watches running the original operating system, and they even support developing watch faces and apps in JavaScript. However, even a simple Elm worker compiles to JavaScript that is too large to run on the watch.

So here is what Elm Pebble includes so far:

  • an IDE built with Phoenix LiveView for Elm development of watch apps, watch faces, and companion apps (on the phone)
  • an Elm-to-C compiler (reference counting, no GC; tokenizer/parser generated via Leex/Yecc, with dead-code stripping to keep watch binaries small)
  • CodeMirror editor with LSP-backed formatting, completions, diagnostics, hover, and folding (and yes, VIM mode)
  • almost complete coverage of the Pebble C API via Elm packages
  • a three-root project layout: watch, protocol, and phone, with watch<->phone communication derived from shared Elm types
  • companion-app JS APIs exposed as Elm packages
  • integrated time-travel debugger that evaluates Elm code for both watch and phone, with timeline events, replay, snapshots, model/view inspection, and tick controls
  • project templates for watch faces, games, companion demos, and tutorials
  • automated publishing to the Pebble app store, including screenshot capture per watch model
  • embedded Pebble emulator for realistic app testing
  • experimental WASM Pebble emulator for browser-based emulation
  • companion (phone) app generated with the original Elm compiler
  • support for Elm packages (on the watch, HTTP/HTML packages are excluded)
  • (animated) vector graphics uploadable as SVG
  • GitHub integration for project persistence
  • MCP/ACP integration so coding agents can read, edit, and build projects through the IDE
  • hosted IDE at ide.elm-pebble.dev, or self-hosted via Docker
  • website with package documentation built with elm-pages at elm-pebble.dev

Let me know what you think, would be glad to see your Elm watch face in the app store!

15 Likes

Great effort. I also like how you list the Elm-to-C compiler as just part of the work achieved.

You mentioned this uses “tokenizer/parser generated via Leex/Yecc” - which makes me think is this a complete compiler rewrite starting even from parsing the .elm sources ? Does it re-implement typechecking too ? All the error message stuff ? I am just curious how much of a full rewrite this is and whether it can be used outside of the pebble watch context.

In the monorepo GitHub - synalysis/elm-pebble: IDE for developing Pebble apps and watch faces in Elm · GitHub I’ve intentionally kept the Elm tokenizer/parser elm_ex and Elm-to-C compiler elmc separate from the IDE, so at least elm_ex could be provided as a reusable package on hex.pm.

So yes, it’s a complete compiler rewrite in Elixir as I wanted to use AST et cetera for syntax highlighting, formatting, folding…
The error messages are not fully on the level of those the original Elm compiler emits but eventually that’s the goal.

The Elm-to-C compiler is quite specific for the Pebble target as it tries to minimize code size as much as possible. (Smaller programs can even run on the original Pebble models)

3 Likes

This is so cool!!

I got a Bangle.js 2 watch a while back to do some Elm programming for a watch-- but I was too impatient to write the Elm-to-BangleJS pipeline and ended up writing very procedural JS by hand

I revived the same project a few months ago on an Android watch, but those watchfaces are all in a rather limited XML format

Now you’ve got me wanting to make it a third time with Elm and Pebble :joy:

Thanks for sharing this project, super awesome work-- and always fun to see folks bring Elm into more cool spaces :heart:

3 Likes

Thank you, Elm is really the perfect fit for this application.

Especially I like the automatic generation of the AppMessage definition for the communication between watch app/watch face (C) to the companion app (JS within the Pebble app):

type Location
    = CurrentLocation
    | Berlin
    | Zurich
    | NewYork


type Temperature
    = Celsius Int
    | Fahrenheit Int


type WeatherCondition
    = Clear
    | Cloudy
    | Fog
    | Drizzle
    | Rain
    | Snow
    | Showers
    | Storm
    | UnknownWeather


type WatchToPhone
    = RequestWeather Location


type PhoneToWatch
    = ProvideTemperature Temperature
    | ProvideCondition WeatherCondition


2 Likes

Alright you have me sold-- here comes PokeWatchFace 3.0 :sweat_smile:

Here are some of my latest iterations for proof that I have a problem:

Planning on preordering the Pebble Round 2 model, and I will definitely let you know if I make the watchface with your cool project :heart:

8 Likes

@RyanNHG How is TRMNL treating you? :slight_smile:

I love it! Took some initial setup at first, the online service was nice, but I was debating whether to selfhost my API or hack the firmware to run everything on device

Ended up connecting to a Raspberry Pi on my local network and creating a minimal ExpressJS API that uses imagemagick directly (rather than doing the fancy HTML/CSS-to-browser-screenshot-to-image pipeline that is a part of the standard experience)

This PokeClock/PokeWatch project is always fun to do on a new device with different resolutions, color limitations, and IO differences

When the 2026-2027 bulls season schedule is released, I will have the start time of the next game in the top left corner so I can see that info too

Right now, the device just has a blank space there :sweat_smile:

1 Like

I just preordered my first Pebble, triggered by your post! Didn’t know they are back, and the new watches look awesome!

The prospect of using Elm to create apps and watchfaces is almost too good to be true :-). Thanks a lot for your efforts!

Did you speak to the Pebble devs about elm-pebble? Are there any plans to make Elm an officially supported language?

3 Likes

So far this is the only place where I’ve announced it, first I wanted to make it more mature.

Of course it would be great if Elm Pebble would be endorsed by Pebble - actually the project would allow to log in like on CloudPebble and publish apps and watchfaces with one click. Currently this is only possible when you operate Elm Pebble locally, on https://ide.elm-pebble.dev you have to download the .pbw and publish it manually.

In the past weeks quite some effort has been put into more compact code generation so that not too complex apps can even run on the old Pebble models with 24 KB RAM limit.

1 Like