Get in touch

From the workshop

SkyGames

Tiny screen. Big fun.

A growing catalogue of pixel-perfect arcade games for Garmin watches.

Live Web Garmin
Monkey C Connect IQ Laravel backend
The build story
  • SkyRunner

    Visit →

    Retro endless runner. Jump, dodge, sprint through pixel-perfect obstacles.

    Featured by Garmin Connect IQ

  • SkyLander

    Visit →

    Space trading across the solar system. Upgrade your ship, trade goods, dock at 25+ stations.

  • SkyRift

    Visit →

    A full action RPG on your wrist. Ten quests across floating islands, permadeath, no phone needed.

  • SkyLing

    Visit →

    A virtual pet on your wrist. Hatch eggs, raise creatures, discover dozens of species.

The build story

Fifteen frames per second.

A Garmin watch is a spectacularly bad games console. The frame budget is 67 milliseconds, 15 FPS on a good day. The memory ceiling is measured in double-digit kilobytes, and the screen is a circle. SkyGames exists because that sounded like a fun set of rules rather than a reason not to try. It is now a catalogue: SkyRunner (endless runner, 50 handcrafted levels), SkyLander (space trading), SkyLing (a virtual pet on your wrist) and SkyRift (a full action RPG, which took two goes), all sharing one Laravel backend and one set of hard-won lessons.

Every pixel goes through the budget office

SkyRunner’s game loop runs player movement, two spawning systems, six kinds of collision detection and a full render pass inside that 67ms window, with a profiler wrapped around each stage so a regression shows up as a number rather than a feeling. Between them the games target dozens of watch models across nine screen sizes, from a 218-pixel Forerunner to a 466-pixel Fenix 9 Pro. Everything is authored once at the largest size, and every pixel literal in the codebase passes through a scale manager at runtime.

218 Forerunner 255S 240 Fenix 7S 260 Fenix 7 280 Fenix 7X 360 Forerunner 265S 390 Venu 3S 416 Epix 2 454 Fenix 8 466 Fenix 9 Pro drawn once at the largest size, scaled down for the rest, hitboxes included

Levels are plain text files, compiled by a Python step into Monkey C data arrays before every build. The watch never parses a level. It reads structs that were code all along.

Shipped, then shipped again

SkyRunner hit the Connect IQ store in November 2025. The online level editor (build a level in the browser, play it on your wrist) followed eleven days later. By January the Pro paywall was gone and everything went free. By April there was an in-game diamond shop. Somewhere in there Garmin featured it on Connect IQ, and the player counts at the top of this page stopped being hypothetical. They are live numbers from the same events pipeline the games report into, from players in 160-odd countries.

A virtual pet needs a backend

SkyLing pushed the catalogue somewhere stranger: a pet that keeps living while the watch sleeps. Hunger and mood are extrapolated server-side, capped at 24 hours and politely paused during your sleep window. Its companion watch face syncs through a pairing scheme built for a device that cannot hold secrets: a one-time four-digit code, rate-limited hard so the tiny keyspace cannot be scanned, swapped on first use for a long-lived 96-bit key. The analytics behind all three games had a growth moment of their own. The day the events table got big enough to OOM the dashboard, aggregation moved from PHP into SQL, and my phone now pings at every fiftieth new device.

The last three percent

SkyRift: Relics of the Aether was 97% of a game for five months. It is a real-time action RPG set in the SkyLands world: a ten-quest campaign across procedurally generated floating islands, a town hub with a shop, an inn and three quest givers, eight enemy types with a boss at the end of every quest, 12 weapons and 14 armour pieces across five tiers, 13 rings, fog-of-war exploration, permadeath runs kept on a local scoreboard, and save and resume anywhere. No phone, no account, no network.

What it was not, for those five months, was playable. On a real watch the frame rate sat near six per second where the simulator flew, the watchdog timer killed island generation before a map finished building, and the render cache meant to share sprites between entities quietly refused to cache anything.

All three were fixable, and fixing them was the whole second half of the project. Island generation was sliced into async chunks behind a loading screen, and start-up split into phases, so the watchdog always gets a breath. The sprite cache was repaired, then given pre-scaled wall tiles and cached font handles so the hot path stops asking the system for things it already has. Last, the render loop stopped allocating: a reusable camera bounds object instead of one per call, reusable buffers for the depth sort instead of a fresh array and a tuple per entity per frame, a 680-line bitmap font system deleted outright because every supported watch has vector fonts, and release builds compiled with full optimisation. Frame time went from 83ms to 66ms. Six frames per second became fifteen, which on this platform is all there is.

SkyRift key art: a lone Sky-Strider on a floating island above the Aether

It went to the Connect IQ store in September 2026, free, no ads and nothing to buy, for 44 touchscreen AMOLED watches from 390x390 up to the 466x466 Fenix 9 Pro. MIP screens and button-only watches sat this release out, deliberately: you move by touching where you want to go, and a small monochrome screen cannot hold an RPG. SkyRift on Connect IQ.

Four games, four rabbit holes

None of these shipped in a straight line. A mascot got fired, a ship grew five new bodies, a virtual pet refused to get hungry, a font had to be drawn one pixel at a time for the cheaper watches, and an RPG spent five months at 97%. Below is each game’s development as it happened: the turns, redesigns and platform fights, pulled from the commit history. Each track scrolls sideways.

SkyRunner

Endless runner · from Oct 2025
Oct 2025 Rendering
▦
One scale manager, 70 watches

Every Garmin model has a different screen, so a single scale manager was built to size every sprite, font and hitbox off the device resolution: a 4,500-line refactor that made multi-resolution support possible at all.

Oct 2025 Art
Not a monkey. A test sprite
Not a monkey. A test sprite

The Garmin starter project shipped with a sample “monkey” asset that never actually rendered. The first real player was this scrappy little hand-drawn runner, dropped in just to start testing.

Oct 2025 Physics
New Zealand wildlife, as hazards
New Zealand wildlife, as hazards

Sheep, kiwi, kākā and a bee joined the obstacle roster, each needing a hand-tuned hitbox so collisions matched the visible pixels, not the bounding box.

Nov 2025 Levels
Levels become a compiled format
Levels become a compiled format

A Python step compiles authored levels into Monkey C data the watch just reads, plus auto-generated preview images and a stack of validation rules for ledge spacing, reachable jumps and safe landings.

Dec 2025 Art
The dude gets a remaster, before → The dude gets a remaster, after
The dude gets a remaster

v1.4.0 redrew the dude, and every other sprite, into a proper six-frame run cycle with new celebrate, death, jump and slide states. Same scrappy runner, glow-up applied.

Jan 2026 Launch
Tearing down the paywall
Tearing down the paywall

For a while the free version literally hit a wall: a brick paywall that spawned across the track at 9.8km and stopped Lite players cold. v1.5.0 tore it down: every Pro licence check ripped out, all levels and the browser editor unlocked for everyone.

Apr 2026 Economy
The Diamond Shop opens
The Diamond Shop opens

The diamonds players had been hoarding finally became a currency: a shop selling Endless-Mode power-ups like the slingshot, bubble and extra life. (A wallet bug shipped with it, hot-fixed two weeks later.)

SkyLander

Space trading · from Nov 2025
Nov 2025 Ship
First spacecraft sprites land
First spacecraft sprites land

The opening art drop: three workhorse ships (the nimble Mosquito, the cargo Mule and the Vector) drawn through a custom AI asset pipeline and packed across seven watch resolutions.

Dec 2025 Physics
Ships that bank into their turns
Ships that bank into their turns

Flight feel jumped when the ship started rotating to face its velocity vector, with the thrust flames re-aligned to match. Flat top-down drifting suddenly read as real flying.

Dec 2025 Economy
Fuel becomes a real budget
Fuel becomes a real budget

The economy moved from flat zone multipliers to fuel-cost-per-AU, progressive distance burn, cargo-weight penalties and a mandatory landing reserve, so every trade route became a fuel-vs-profit sum.

Jan 2026 Ship
Five faces of the Mosquito, before → Five faces of the Mosquito, after
Five faces of the Mosquito

The Mosquito grew a five-tier upgrade ladder (Reinforced, Racer, Combat, Elite, Legendary), each a distinct sprite, the plain grey fighter becoming a gold-and-purple cruiser.

Jan 2026 Economy
◆
The 100,000-credit oopsie

To test buying every skin, starting credits got bumped from 1,000 to 100,000, then sheepishly walked back to 1,000 the same day. Leftover debug money, narrowly un-shipped.

Jan 2026 Typography
Hand-built bitmap fonts
Hand-built bitmap fonts

Cheaper watches like the Venu 3 have no scalable fonts, so a font manager rendering 5×7 and 6×9 pixel glyphs was written from scratch, later given borders and shadows to stay legible.

Jan 2026 UI
⚠
The “Too Many Timers” bug

The new toast notifications spawned a timer each and hit Garmin’s hard timer limit; the fix routed every auto-dismiss through one shared timer. A very watch-platform kind of war story.

SkyLing

Virtual pet · from Dec 2025
Dec 2025 Creatures
First it was a dragon
First it was a dragon

SkyLing didn’t start as a roster. It started as Drago, a single red dragon, the art-pipeline guinea pig. A cast of named characters followed (including Zorro, the family border collie) before the whole lot was cut and rethought.

Dec 2025 Hatching
One egg to rule them all
One egg to rule them all

Those named characters, and a three-egg picker, got scrapped for a single Mystery Egg. Every Skyling now starts identical, and which of ~27 species you get is decided at hatch time by how active you’ve been.

Dec 2025 Simulation
∿
Why won’t it get hungry?

An eight-hour offline test exposed that hunger never decayed while the app was closed. The fix pinned the real-time-to-game-time ratio and hardened the decay maths against nulls: the first real offline-simulation milestone.

Dec 2025 Creatures
Thirteen creatures in a day
Thirteen creatures in a day

A single batch generated configs and sprites for thirteen new Skylings at once, growing the roster toward its eventual ~27 species across bio, cosmic, synthetic and oddball families.

Jan 2026 Creatures
Buzz gets a glow-up, before → Buzz gets a glow-up, after
Buzz gets a glow-up

A wholesale art pass regenerated every frame of the Buzz creature (idle, eat, emerge) for a clean before/after on the very same sprite.

Jan 2026 Typography
Aa
Fonts for the font-less

Older watches were rendering text wrong, so a font manager and bitmap fonts were added with per-context scaling (menu, important, detail) to keep type sharp across the device zoo.

May 2026 Pairing
⧉
Type a code, mirror your pet

The companion watch face arrived: the app makes a short pairing code, pushes signed state to the backend, and the face polls to mirror your live pet. The code shrank from six letters to a four-digit PIN to make it typeable on Garmin Connect.

May 2026 Simulation
∿
Let sleeping pets lie

Friendly Mode (reduced decay, no death) and Pause-During-Sleep landed, so your Skyling’s hunger and mood freeze overnight, with a 24-hour cap so a long-unsynced pet can never come back already starved.

SkyRift

Action RPG · from Jan 2026
Jan 2026 Rendering
▦
A profiler before a second enemy

Frame timing and draw-call counts went in during the first week, before the game had a shop, a quest or a second kind of monster. Every performance decision after that was a number rather than an opinion.

Jan 2026 Levels
▤
The watchdog kept killing the island

Generating a whole island in one go took longer than Garmin lets an app think, so the watchdog shot it. Generation was cut into async chunks behind a loading screen, and start-up into phases, so the map builds a slice at a time.

Jan 2026 Rendering
One cache for every sprite
One cache for every sprite

Each entity had been loading its own bitmaps. A shared sprite cache preloads them once, joined by pre-scaled wall tiles and cached font handles, which is most of the gap between the simulator and the wrist.

Feb 2026 UI
Permadeath earns a scoreboard
Permadeath earns a scoreboard

Death is permanent, so death needed a screen worth reading: level, kills, quests completed and time survived, and a local high-score table where a winning run is marked in gold.

Jul 2026 Rendering
▦
83 milliseconds becomes 66

The frame-rate fight, won in one sitting: reusable camera bounds and depth-sort buffers instead of per-frame allocations, a 680-line bitmap font system deleted because every supported watch has vector fonts, and release builds compiled with full optimisation.

Jul 2026 Physics
◈
Playtesters versus the pack

Round one of feedback was all about bodies: enemies stopped walking onto the player, packmates sidestep instead of freezing, blocked enemies get one budgeted A* detour a frame, and a teleport got an animation so it stopped reading as lag.

Sep 2026 Launch
Forty-four watches and a white strip
Forty-four watches and a white strip

The Fenix 9 Pro 51mm brought a new 466x466 screen and caught an old bug: backgrounds were scaled by width only, leaving 12 pixels of white along the bottom. Art regenerated per resolution, 44 devices verified, submitted to the store.

The one that hasn’t made the cut

SkyRift came out of the SkyLands universe, a dark-fantasy world of islands shattered across a breathable void that I built out far past any single game. One other swing at that world is still sitting on the bench, and it is the bigger of the two. Parked, not dead.

Key art for SkyLands
shelved · scope

SkyLands

Endless text RPG · Darklands-inspired

A data-driven, endless RPG in the spirit of Darklands: branching vignettes, reputation, turn-based combat, all authored as data and compiled onto the watch. The engine works. What ran away was the world: a 500,000-word lore bible across 200-odd wiki pages, declared ‘complete’ three days in and promising six hundred quests, against a game with exactly one quest and one location actually playable. It didn’t get out of hand so much as start out of hand. Shelved, with enormous fondness.

SkyRift proved the world reads on a wrist. SkyLands is the version of it I still intend to come back to.

Why bother?

Because constraints are a forcing function. There is no room for a framework, an asset store or an unconsidered allocation. Every feature has to justify its bytes. The catalogue keeps growing, with more Sky-somethings in various stages of playable, and every one of them starts from the question that started SkyRunner: how much fun fits in 67 milliseconds?

Working with a brutal platform constraint that still has to feel effortless? Here’s how we could work together.

Visit SkyGames