Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
7644408
feat(build): modernize for current Pebble SDK + add host unit tests
eldios Jun 4, 2026
49f99f2
feat(meta): rebrand to TimelyColor 3.0 and target new Core Devices wa…
eldios Jun 4, 2026
4d1f905
feat(color): accent the current-day cell on color platforms
eldios Jun 4, 2026
d167002
docs(readme): rebrand to TimelyColor, modern build/test docs, GPL att…
eldios Jun 4, 2026
bcc9a05
feat(layout): add tested responsive layout module + unify test suite
eldios Jun 4, 2026
f0fda2d
feat(layout): wire runtime responsive layout into the renderer
eldios Jun 4, 2026
c64dbd2
fix(layout): calendar grid is 4 rows (header + 3 weeks), not 3
eldios Jun 4, 2026
96d237b
refactor(calendar): extract the 3-week grid model into calendar.{c,h}
eldios Jun 4, 2026
31e2f19
refactor(vibes): extract pure period-window logic into vibes.{c,h}
eldios Jun 4, 2026
8c59993
refactor(state): encapsulate weather state behind weather_state()
eldios Jun 4, 2026
0ce8f1c
refactor(state): encapsulate settings + adv_settings behind accessors
eldios Jun 4, 2026
5a90a7c
refactor(state): encapsulate localization tables behind accessors
eldios Jun 4, 2026
fd3e7a7
refactor(state): encapsulate debug flags behind debug_get()
eldios Jun 4, 2026
d0840a1
refactor(view): extract color theme into theme.{c,h}
eldios Jun 4, 2026
cabb08c
refactor(view): move the weather render into weather.c
eldios Jun 4, 2026
08af60d
refactor(view): make weather a component that owns its layer
eldios Jun 4, 2026
1e58b76
refactor(view): calendar + splash as components owning their layers
eldios Jun 4, 2026
b2300d7
feat(theme): add a theme engine (palette-driven rendering)
eldios Jun 4, 2026
59840d5
chore: rename project to TimelyNG
eldios Jun 4, 2026
f76cf69
chore(dev): add Makefile/justfile task targets
eldios Jun 4, 2026
d8fe60c
feat(fonts): use DejaVu Sans Condensed for the unicode font
eldios Jun 4, 2026
910aca3
feat(fonts): crisp Roboto time font; drop unused futura + unifont
eldios Jun 4, 2026
cdfabc4
fix(calendar): vertically center day numbers in their cells
eldios Jun 4, 2026
29e7b8d
fix(calendar): nudge day numbers up 3px for true vertical centering
eldios Jun 4, 2026
c7d63b2
fix(calendar): make vertical centering proportional to font size
eldios Jun 4, 2026
82bde3d
feat(theme): functional weekend coloring in the calendar
eldios Jun 4, 2026
980de9e
feat(theme): warn color for low battery outline
eldios Jun 4, 2026
bf3e8e3
feat(theme): Auto mode uses real sunset/sunrise (suntimes module)
eldios Jun 4, 2026
14f9066
fix(theme): palette-driven text colors (light themes readable)
eldios Jun 4, 2026
410b29b
fix(theme): tint status icons to palette.fg (visible on any background)
eldios Jun 4, 2026
9b97008
feat(theme): wire theme/theme_mode config keys into settings
eldios Jun 4, 2026
acbd8d3
feat(config): self-contained Clay configuration page
eldios Jun 4, 2026
5e9d7b9
docs(readme): document the offline Clay configuration page
eldios Jun 4, 2026
e9337a6
build: guided emulator/config recipes (just config, just menu)
eldios Jun 4, 2026
dc65582
refactor(config): fully offline config page, drop Clay
eldios Jun 4, 2026
ff78b94
fix(config): read return_to from location.href so Save works
eldios Jun 4, 2026
8f9207f
fix(config): serve emulator config page as file:// so Save round-trips
eldios Jun 4, 2026
06fb92e
fix(js): expose SunCalc under the CommonJS bundler
eldios Jun 4, 2026
79f40e9
feat(config): restore the full settings set
eldios Jun 4, 2026
2ae4566
fix(weather): correct C/F units; feat(config): mode-based vibration &…
eldios Jun 4, 2026
4750d09
feat(weather): show the weather location as a below-time slot
eldios Jun 4, 2026
3bf3fc4
feat(config): unify slot complications and expand date formats
eldios Jun 4, 2026
2843a34
feat(vibration): add Follow Do Not Disturb hourly mode
eldios Jun 4, 2026
6765e4a
fix: Seconds complication value, Triple vibe fall-through, build warn…
eldios Jun 4, 2026
455a748
fix(config): send only changed settings (full dump exceeded close-URL)
eldios Jun 4, 2026
aca14dc
feat(weather): switch to Open-Meteo over HTTPS (no API key)
eldios Jun 4, 2026
032cf3c
fix(layout): confine the three complications to left/centre/right thirds
eldios Jun 4, 2026
fd638d8
feat(layout): bigger calendar on tall screens, larger complication text
eldios Jun 4, 2026
347b506
feat(config): language selector (Follow system / language / Custom)
eldios Jun 4, 2026
4ae23aa
feat(statusbar): show phone battery via the Web Battery API
eldios Jun 4, 2026
c2a0665
fix(config): merge saved settings; two complications above the calendar
eldios Jun 4, 2026
d01dbee
feat: Sunrise/Sunset complications and real Auto-theme location
eldios Jun 4, 2026
45b0140
feat(complication): moon phase
eldios Jun 4, 2026
3fbf98d
feat(complication): second time zone
eldios Jun 4, 2026
3103825
feat(statusbar): phone & watch icons by the battery readouts
eldios Jun 4, 2026
b5a4aa8
fix(build): include Timely.h with quotes for src/c cloud layout
eldios Jun 4, 2026
8c4e831
fix(layout): fit the top band on narrow screens; drop aplite
eldios Jun 4, 2026
25e684c
feat(complications): add watch/phone battery + Bluetooth as slot options
eldios Jun 4, 2026
abb4030
feat(statusbar): two configurable slots drawing from the unified menu
eldios Jun 4, 2026
8f9787d
feat(complications): add Date as a slot option
eldios Jun 4, 2026
b804436
feat(complications): configurable CENTER row + 1-full/2-halves for al…
eldios Jun 4, 2026
0aba332
feat(layout): adaptive rows + grouped complications + weather alignment
eldios Jun 4, 2026
cd5b7ea
fix(config): restore hourly vibration pattern; de-duplicate status-ba…
eldios Jun 5, 2026
7309c9a
feat(complications): selectable battery style (bar / text / icon+text)
eldios Jun 5, 2026
667ffa4
fix(layout): keep the date visible when the status bar is off; bar % …
eldios Jun 5, 2026
4787581
fix(build): const-correct time_font_key; add local strict-check mirro…
eldios Jun 5, 2026
8ad982d
feat: bigger emery weather, all-rows default, warning cleanup, strong…
eldios Jun 5, 2026
bc1bfd4
feat(complications): filling battery bar + dynamic single status slot
eldios Jun 5, 2026
87157ea
feat(complications): alphabetical menu, full-height battery fill, bar…
eldios Jun 5, 2026
14eb848
fix(statusbar): raise battery % (was clipping); left battery nib face…
eldios Jun 5, 2026
3c3d6d3
fix(calendar): lift the weekday header off the grid; align the post-t…
eldios Jun 5, 2026
c002262
fix(calendar): today's weekday header uses same-size bold, not the bi…
eldios Jun 5, 2026
65c8310
feat(layout): live relayout on config change
eldios Jun 5, 2026
1cf7708
chore(release): v0.0.1 — README.md homage/attribution, TODO, dead-cod…
eldios Jun 5, 2026
b17cd03
docs(release): modern README, GitHub Actions CI, appstore PUBLISHING.md
eldios Jun 5, 2026
278e6a9
docs(marketing): add per-platform store screenshots (native res, unfr…
eldios Jun 5, 2026
70f84d8
docs: list all 7 platforms (incl. not-supported/future); collect inhe…
eldios Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CI

on:
push:
branches: ["**"]
pull_request:

jobs:
test:
name: host tests + JS syntax
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# Pure-logic modules compile and run on the host (no Pebble SDK needed),
# covering layout, calendar, suntimes, time/date formatting, vibes and the
# clock-font selection. The full per-platform SDK build + warning-strict
# compile run locally via `tools/test.sh`.
- name: Host unit tests
run: |
gcc -std=c11 -DUNIT_TEST -Isrc -Itests tests/test_*.c \
src/layout.c src/calendar.c src/suntimes.c src/timefmt.c src/vibes.c src/math.c \
-lm -o timely_utest
./timely_utest

- uses: actions/setup-node@v4
with:
node-version: "20"

- name: PebbleKit JS syntax check
run: |
for f in src/js/*.js; do
echo "checking $f"
node --check "$f"
done
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ pebble-screenshot*

# Local-only workflow artifacts (brainstorming specs / plans)
docs/superpowers/

node_modules/
69 changes: 69 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Dev tasks for TimelyNG. Equivalent recipes exist in the justfile.
# Host unit tests: run inside `nix develop .#test` (needs a host cc)
# Pebble app + emulator: run inside `nix develop` (needs pebble CLI)

CC ?= cc
CFLAGS ?= -I src -I tests -Wall -Wextra -std=c11
BUILD := build
TEST_BIN := $(BUILD)/test_suite
TEST_SRC := $(wildcard tests/*.c) src/timefmt.c src/layout.c src/calendar.c src/vibes.c src/suntimes.c src/math.c

# emulator platform: aplite | basalt | chalk | diorite | emery | flint
EMU ?= emery
SHOT ?= $(BUILD)/screenshot-$(EMU).png

.PHONY: help test test-xml test-clean build install run shot config preview logs kill app-clean sdk

help:
@echo "Host tests (nix develop .#test): test test-xml test-clean"
@echo "Pebble (nix develop): build run config preview shot logs kill app-clean sdk"
@echo "Guided picker (just): just menu (or: just config)"
@echo "Vars: EMU=$(EMU) SHOT=$(SHOT)"

## ---- host unit tests ----
test: $(TEST_BIN)
$(TEST_BIN)

test-xml: $(TEST_BIN)
$(TEST_BIN) --output=$(BUILD)/test-results.xml

$(TEST_BIN): $(TEST_SRC) $(wildcard src/*.h tests/*.h)
mkdir -p $(BUILD)
$(CC) $(CFLAGS) $(TEST_SRC) -o $(TEST_BIN)

test-clean:
rm -f $(TEST_BIN) $(BUILD)/test-results.xml

## ---- Pebble app + emulator ----
build:
pebble build

run install: build ## build + (re)install on the emulator
pebble install --emulator $(EMU)

config: build ## build + install + open the offline config page (EMU=$(EMU); use `just menu` for a picker)
pebble install --emulator $(EMU)
node tools/gen-config-html.js $(BUILD)/config.html
pebble emu-app-config --emulator $(EMU) --file $(BUILD)/config.html

preview: ## render the config page to build/config.html to open in a browser
node tools/gen-config-html.js $(BUILD)/config.html
@echo "open $(BUILD)/config.html"

shot: build ## build + install + grab a screenshot to $(SHOT)
pebble install --emulator $(EMU)
sleep 4
pebble screenshot $(SHOT) --no-open
@echo "saved $(SHOT)"

logs: ## stream app logs from the emulator
pebble logs --emulator $(EMU)

kill: ## stop the running emulator
pebble kill

app-clean: ## pebble clean (forces SDK reconfigure)
pebble clean

sdk: ## install the Pebble SDK (first-time setup)
pebble sdk install latest
81 changes: 81 additions & 0 deletions PUBLISHING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Publishing TimelyNG to the Pebble / Rebble appstore

Listing copy and asset specs, ready to paste into the
[Rebble developer portal](https://dev-portal.rebble.io/). Field set per the
Rebble guides:
[Publishing an App](https://developer.rebble.io/guides/appstore-publishing/publishing-an-app/),
[Submit an app](https://help.rebble.io/appstore-submission/?viewall=true),
[Appstore assets](https://developer.rebble.io/guides/appstore-publishing/appstore-assets/).

## Basic details

- **Title:** TimelyNG
- **Type:** Watchface (no large/small icon step required for watchfaces)
- **Category:** Watchfaces
- **UUID:** `de253577-14c6-4ab2-9db6-65bda1c7c1d2`
- **Source code:** https://github.com/eldios/TimelyNG
- **Website:** https://github.com/eldios/TimelyNG
- **Support:** https://github.com/eldios/TimelyNG/issues (or a support email)

## Description

> A calendar watchface with complications you arrange yourself.
>
> TimelyNG shows the date, time and weather up top and a compact three‑week
> calendar (previous · current · next) below. Around them are three configurable
> rows — a status bar, a row above the time, and a row above the calendar — and
> each can hold one complication (centred) or two side by side.
>
> Pick from one shared menu for every slot: date, day, month, ISO week number,
> day‑of‑year / days‑left, seconds, AM/PM, timezone, a second time zone,
> sunrise, sunset, moon phase, weather location, watch battery, phone battery
> and Bluetooth. Battery can be a filling bar with the percentage inside, plain
> text, an icon with text, or a bar with an icon.
>
> The layout is adaptive: leave a row empty and the clock and calendar grow to
> use the space, with the clock font scaling to fit — and everything updates the
> moment you save your settings.
>
> Weather comes from Open‑Meteo over HTTPS (no API key). Configuration is 100 %
> offline — no server, no account. Vibration (hourly, connect/disconnect),
> Do‑Not‑Disturb, themes and full localization are all built in.
>
> Freely inspired by, and an homage to, the original Timely / PebbleTimely and
> the Timely‑2 and PebbleTimely community forks.

**Keywords / tags:** calendar, weather, complications, date, week number,
battery, moon phase, world time, minimal, localizable

## Release notes — v0.0.1

> First public release.
>
> • Configurable complication rows (status bar, above the time, above the
> calendar) — one centred or two side by side per row.
> • One shared, alphabetical menu for every slot, incl. watch/phone battery,
> Bluetooth and the date.
> • Adaptive layout that reflows live on save; clock font auto‑scales.
> • Battery as a filling bar (% inside), text, icon + text, or bar + icon.
> • Open‑Meteo weather (no API key); fully offline configuration.
> • Builds for Pebble Time 2 (emery), Pebble 2 Duo (flint), basalt and diorite.

## Assets

Create an asset collection per supported platform (`emery`, `basalt`,
`diorite`, `flint`). Per the Rebble guides:

- **Screenshots:** up to 5 per platform, at the watch's native resolution,
**unframed** (the listing must not use framed screenshots):
- `emery` — 200×228
- `basalt` / `diorite` / `flint` — 144×168
- Capture with `pebble screenshot --emulator <platform>`.
- **Marketing banner:** optional for watchfaces (required only for apps).
Templates: see the Rebble appstore‑assets guide.
- **Icons:** not required for watchfaces.

## Publish flow

1. `pebble build` → upload `build/TimelyNG.pbw` with the release notes above.
2. Add an asset collection (description + screenshots) for each platform.
3. Click **Publish** (or **Publish Privately**), then reload for the public
appstore link.
25 changes: 0 additions & 25 deletions README

This file was deleted.

105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<div align="center">

# ⌚ TimelyNG

**A calendar watchface for Pebble — date, time & weather up top, a 3‑week
calendar below, and fully configurable complication rows you arrange yourself.**

[![CI](https://github.com/eldios/TimelyNG/actions/workflows/ci.yml/badge.svg)](https://github.com/eldios/TimelyNG/actions/workflows/ci.yml)
![Version](https://img.shields.io/badge/version-0.0.1-blue)
![Platforms](https://img.shields.io/badge/Pebble-emery%20·%20flint%20·%20basalt%20·%20diorite-orange)
![Language](https://img.shields.io/badge/C-C99-555?logo=c)
![PebbleKit JS](https://img.shields.io/badge/config-PebbleKit%20JS-f5a623?logo=javascript&logoColor=white)
![SDK](https://img.shields.io/badge/Pebble%20SDK-4.x%20(Core%20Devices)-black)

</div>

---

## 🙏 Homage & inspiration

TimelyNG is **freely inspired by, and an homage to, the original *Timely* /
*PebbleTimely* watchface and its community forks** — in particular
[Andrew129260/Timely‑2](https://github.com/Andrew129260/Timely-2) and
[alan‑johnson/PebbleTimely](https://github.com/alan-johnson/PebbleTimely).
It carries forward their ideas and spirit (the calendar‑centric layout, the
localizable date/time, the complication slots), rebuilt for the modern
**Core Devices Pebble SDK** and the new hardware. All credit for the original
concept goes to those projects; any bugs here are mine.

## ✨ Why TimelyNG (what's different)

Compared to the classic Timely and its forks, TimelyNG adds:

- **Configurable complication *rows*, not fixed slots.** Three rows — status
bar, above the time, above the calendar — and each holds **one complication
(centred) or two (side by side)**.
- **One unified, alphabetical menu for every slot**, including things that used
to be hard‑wired: **watch battery, phone battery, Bluetooth, and the date
itself** — put any of them anywhere.
- **Adaptive layout that reflows live.** Empty a row and the freed space is
given back to the clock and calendar; the **clock font auto‑scales** to the
space available — and it all updates the moment you save the config, no
reload.
- **Multiple battery styles:** a filling bar with the % *inside*, plain text,
icon + text, or bar + icon.
- **Open‑Meteo weather over HTTPS, no API key**, sized per screen.
- **100 % offline configuration** — no server, no CDN, no external host.
- **Built for 2026 hardware** (Pebble Time 2, Pebble 2 Duo) on the current SDK,
with a local test gate that mirrors the cloud's strict build flags.

## 🧩 What it shows

- **Complications** (shared menu): date, day, month, week number,
day‑of‑year / days‑left, seconds, AM/PM, timezone, a second time zone,
sunrise, sunset, moon phase, weather location, watch/phone battery, Bluetooth.
- **Weather:** condition icon + temperature (Open‑Meteo).
- **Calendar:** previous / current / next week, today accented on colour
watches.
- Vibration (hourly, on disconnect / reconnect), Do‑Not‑Disturb, themes and
full localization — all from the config screen.

## ⌚ Platforms

| Platform | Watch | Screen | Status |
| --------- | -------------------------- | --------------- | ------ |
| `emery` | Pebble Time 2 | colour 200×228 | ✅ Supported |
| `flint` | Pebble 2 Duo / Core 2 Duo | B&W 144×168 | ✅ Supported |
| `basalt` | Pebble Time / Time Steel | colour 144×168 | ✅ Supported |
| `diorite` | Pebble 2 | B&W 144×168 | ✅ Supported |
| `aplite` | Pebble (2013) / Steel | B&W 144×168 | ⏳ Dropped — future (24 KB RAM, needs a code diet) |
| `chalk` | Pebble Time Round | colour 180×180 round | 🔜 Not supported — future (round layout) |
| `gabbro` | Core Time 2 | colour 260×260 round | 🔜 Not supported — future (round layout) |

The round platforms (`chalk` / `gabbro`) need a dedicated round layout — the
current design is rectangle‑centric. `aplite` was dropped for RAM. See
[`TODO.md`](TODO.md).

## 🔨 Building (Nix + official Pebble CLI)

```sh
nix develop # pebble CLI + ARM toolchain + emulator
pebble build # -> build/TimelyNG.pbw
pebble install --emulator emery # colour emulator (or basalt / diorite / flint)
```

Build/test exactly as the cloud does (catches the `-Werror` / warnings the
local build relaxes via `pbl_suppress_newer_gcc_warnings`):

```sh
nix develop -c sh tools/test.sh # host unit tests + build + strict per‑platform compile
```

## ⚙️ Configuration

The settings screen is fully offline. On `showConfiguration` the watch's
PebbleKit JS builds the page from `src/js/config.js` (the field spec) via
`src/js/configpage.js` and hands it to the phone as a `data:text/html` URI; the
page returns the chosen values via `pebblejs://close#`. Edit
`src/js/config.js` to change the options.

## 📦 Publishing

Store listing copy (description, release notes, categories, asset specs) lives
in [`PUBLISHING.md`](PUBLISHING.md), ready to paste into the
[Rebble developer portal](https://dev-portal.rebble.io/).
58 changes: 58 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# TODO

Future work for TimelyNG. Roughly ordered by priority.

## Platforms
- **Re-add `aplite`** (original 2013 Pebble, 24 KB app RAM). It was dropped
because the current feature set no longer fits (≈19 KB of code leaves almost
no heap, so it faulted on launch). Bringing it back needs an aplite-specific
code diet behind `#ifdef PBL_PLATFORM_APLITE` — trim optional complications,
extra icons and large fonts — and a build there that runs without faulting
before it goes back into `package.json` `targetPlatforms`.
- **Round platforms** (`chalk`, `gabbro`). The layout is rectangle-centric;
a round variant would need its own geometry in `layout.c`.

## Code cleanup
- **Remove the retired middle `day_layer`** complication slot. It is always
hidden (the row model is now left/right only) but still created, themed and
destroyed; also drop the now-unused `show_day` setting + `AK_STYLE_DAY`
handling and the `STAT_BT_ICON_*` defines left over from the old fixed BT icon.

## Features / polish
- More complications (e.g. step count / health, a configurable text label).
- Per-complication formatting options where it makes sense.
- Revisit weather error/backoff behaviour for flaky phone links.

## Project / infra
- **Add a `LICENSE`** (the upstream Timely/PebbleTimely license should be
checked and honoured; pick a compatible one).
- **CI: add the full SDK build** (per-platform `pebble build` + `tools/test.sh`
strict-check) once a stable Core Devices Pebble SDK container image is
available. CI currently runs the host unit tests + JS syntax check.
- Add appstore screenshots/banner under a `marketing/` folder (see
`PUBLISHING.md`).

## Known limitations
- The weather location name is only shown when picked as the "Location"
complication; there is no automatic fallback display.

## Inherited TODO (from the original Timely)

Carried over from `TODO`/`XXX` markers in the upstream code — features that were
stubbed but never finished. Decide per item whether to implement or remove the
dead scaffolding (message keys, settings fields).

- **Idle reminder** — a "you've been still, move" style reminder. The keys exist
but are unused: `idle_reminder`, `idle_vibe_patt`, `idle_message`,
`idle_start`, `idle_stop` (all marked `// TODO, UNUSED` in `Timely.c`).
Implement it or drop the keys + config.
- **Per-slot colour inversion** — `inv_slot_stat` / `inv_slot_top` /
`inv_slot_bot` are read but do nothing. Wire them up or remove.
- **`show_date` toggle** — the `show_date` key is read but unused (the date is a
complication now). Remove it, or repurpose as a quick date on/off.
- **Per-weekday hourly vibration** — `vibe_days` was meant to limit the hourly
buzz to chosen days; today it only encodes the schedule mode. Restore an
actual day-of-week picker, or document it as mode-only.
- **Real bold Unicode font** — non-Latin (e.g. RU) "today" header is faked with
a double-strike because there is no bold unicode font; add one for a clean
bold across all languages.
Loading
Loading