Wear OS Watch Faces
30 paid watch faces on Google Play, generated from Python









01 The story
A catalog of Wear OS watch faces written in Google's Watch Face Format. Python generates each face, renders its art, checks it against Play's rules and publishes it through the Play Developer API. 30 faces are live on Google Play at $0.99 each.
It started with one face, Pulse, built for my Pixel Watch 3: a big time pill, rings and pills above and below it, and four rim arcs, with 16 accent colors, six dial tones and four time styles. It's defined in Google's declarative Watch Face Format (WFF v2) and written out by a Python script rather than by hand.
That script grew into a small toolkit (wff.py) and a production line. There are 164 face folders, each with a gen.py that writes the face's XML and often an art.py that draws its artwork. The collections include rendered stainless-steel dress watches, nixie and split-flap clocks, neon signs, aurora skies, moon-phase almanacs, cat, dog and dinosaur scenes that move with your steps, and data dashboards for nurses, pilots and heart-rate training.
To sell them, I folded 105 faces into 60 store products. Animated 'Solo' variants became layouts, and look-alike families merged into one face with a picker setting, so the catalog would pass Play's repetitive-content policy. Every product has its own name, checked against existing trademarks and Play titles, plus a description, icon, feature graphic and screenshots generated from emulator captures.
Before release, each face goes through automated checks. Its XML is validated against Google's official WFF schemas, which are XSD 1.1 while lxml only supports 1.0, so the validator relaxes xs:all groups and re-checks the required-child rules by hand. Memory is estimated against Play's 10 MB always-on and 100 MB interactive limits, and text sizes are measured against worst-case strings like 'Partly cloudy'. Builds go through aapt2 and bundletool with no Gradle, and a command-line publisher talks to the Play Developer API.
As of November 2026, 30 faces are live on Google Play under my own name, released in batches from mid-October because Play allows about 15 new apps a week. Signed bundles for the other 30 products are built and waiting. A small GitHub Pages site hosts the privacy policy and support pages the listings link to.
02 What it does
- 01
30 paid faces on Google Play ($0.99 each) for Wear OS 5+ watches such as Pixel Watch and Galaxy Watch; watch face only, no phone app
- 02
Deep customization: accent colors (16 on most faces), dial or background tones, time fonts and finishes, layouts, up to 8 complications
- 03
Weather, chance of rain, UV, moon phase, sunrise/sunset and battery built in, so no complication starts empty
- 04
Designed always-on modes: true black by default, lighting less than 10% of pixels in the faces that state it
- 05
Animated details: a vault combination ring that clicks with the seconds, split-flap cards that flip on the minute, nixie tubes that re-light
- 06
Step-powered scenes (dinosaur trek, aquarium, garden, penguins, a virtual pet) and Holiday Magic, which redecorates itself through the year
- 07
Tap shortcuts on the face's own data in about 60 faces, like heart rate opening the health app
03 How it's built
There is no backend. Each face is a resource-only APK (hasCode=false) that the Wear OS watch-face runtime renders from declarative XML. All the logic lives in the build pipeline that generates, validates, packages and publishes the faces.
All 9 connections, as text
- wff.py helpers + metal/tiger/cat art kits → Per-face generator (gen.py + art.py): imported
- Per-face generator (gen.py + art.py) → wff_conform + XSD validator + memory check: watchface.xml + PNGs
- wff_conform + XSD validator + memory check → aapt2 / bundletool build (no Gradle): valid WFF
- aapt2 / bundletool build (no Gradle) → Wear OS emulator / Pixel Watch: install, activate, screenshot
- Wear OS emulator / Pixel Watch → Store art: icon, feature graphic, screens: captures
- aapt2 / bundletool build (no Gradle) → playpub.py (Play Developer API): signed .aab
- Store art: icon, feature graphic, screens → playpub.py (Play Developer API): listing art
- playpub.py (Play Developer API) → Google Play (Wear OS): release + listing
- Google Play (Wear OS) → GitHub Pages privacy/support site: privacy/support links
04 Engineering notes
Faces are code: a Python helper library writes Watch Face Format XML (groups, arcs, complication slots, config lists), and each face's generator draws its own PNG art. Builds use aapt2 and bundletool directly with hasCode=false, no Gradle
wff_conform rewrites generated XML until it validates against Google's official WFF XSDs without changing what the face draws. The XSDs are 1.1 and lxml supports 1.0, so the validator relaxes xs:all groups and re-checks required children by hand
Per-product PASS/FAIL store check: memory footprint (Google's evaluator, or a worst-configuration estimate), at most 8 complication slots, font sizes against worst-case text like '12:59 PM', and no brand strings a buyer can see
metal.py renders procedural stainless steel at 2x and downsamples it: sunburst, tapisserie, azurage, frosted, brushed and mirror finishes, faceted indices and heat-blued hands. tigerkit.py draws a symmetric tiger-stripe coat
A command-line Play publisher (Play Developer API v3) reports track status, uploads bundles and listing art, and refuses to change anything unless --commit or --hold is passed
Checked on the real WFF runtime in the emulator, motion verified from adb screen recordings, and a three-part review per face: visual design, glanceability, 'would I keep it'
05 By the numbers
- 30
- Faces live on Google Play
- $0.99
- Price per face (Personalization category)
- 60
- Store products with signed bundles built
- 164
- Face folders in the repo (158 without six '_store' variants)
- 105
- Faces folded into the 60 store products
- 16
- Accent colors on most faces
06 Stack
App
- Watch Face Format (WFF v2; a few faces use WFF 3/4)
- Wear OS 5+ (minSdk 33)
- Google Sans Flex (SIL OFL)
Infrastructure
- Google Play Console (Wear OS production track)
- GitHub Pages (privacy and support site)
Tooling
- Python generators and procedural art
- lxml + Google's official WFF XSDs
- Google Memory Footprint Evaluator
- aapt2 / bundletool / apksigner
- PowerShell build scripts
- Wear OS emulator + adb screenrecord
- Google Play Developer API v3 (google-api-python-client)
Lines of code (approx.)
- Python184,061
- PowerShell1,473
≈ 185,534 lines
Repositories
- wearos-watchfacesprivate
- watchfaces ↗public
Both repos are single-commit snapshots. wearos-watchfaces is an initial backup (2026-11-09) copied from a Windows working folder with no git history; watchfaces, the support site, has one commit on 2026-10-11. The real timeline comes from dated files: earliest internal brief 2026-09-27, catalog plan 2026-10-06, first signed Play bundles 2026-10-11, first listings updated 2026-10-16, later batches 2026-10-23 to 2026-10-29, latest bundle 2026-11-05.