I build small apps, games, and tools.
I'm a former Apple engineer building independent apps, AI tools, and the occasional hardware experiment. I write about what works, what fails, and the code behind it.
Active Projects all projects →
Canopy
The premium, offline-first digital logbook for paragliders.
Atlas
A native macOS AI client unifying local and cloud language models under a single interface.
Pixel Edit Lite
A tiny, offline, finger-first pixel art / sprite sheet editor for PICO-8 and TIC-80 — "make a sprite anywhere," not a mobile Aseprite.
Orion
A command-line AI assistant that dynamically routes queries to specialized local and external language models based on intent.
Dots N Bars
Match the color. Beat the drop. A genuinely intense, modern iOS arcade game.
Space Jam Lite
An arcade style game where you pilot a craft and dodge oncoming planes or missiles at varying speeds.
The Documentation (Notes & Tactics) read all →
Sep 7, 2026
Dots N Bars (post-1.2.1 build) — I changed the plank to start at 2 segments and grow to 3 then 4 as score crosses fixed thresholds, instead of always being 4. I also added the project’s first test target — 31 unit tests covering the new scoring and matching rules, written as plain functions so they run without SpriteKit or a simulator.
Sep 7, 2026
Canopy build 9 (unreleased, pending merge) — Fixed a data-loss bug where an involuntarily interrupted recording (permission revoked mid-flight) could be silently wiped by the next tap of “Record,” and a trim-tool bug that let both handles land on the same point and save, collapsing the flight to a single point with no recovery path in the UI.
Sep 6, 2026
Dots N Bars (post-1.2.1 build) — Added a drop type that matches no color currently on the plank — touching it now ends the run, and letting it fall through is the correct play. While building this I found the existing plank-drag clamp was mathematically too narrow to ever dodge a drop (its radius was smaller than the plank’s own width), so I widened it.
Sep 5, 2026
Pixel Edit Lite v1.4.0 (build 12) — Sharing a sprite saved it as .com.apple.Foundation.NSItemProvider.P48iCO.png — the generic fallback name iOS assigns when a shared item has no filename of its own. I fixed it by switching from DataRepresentation to FileRepresentation, writing a real temp file first, so shares now save as PixelEdit-Sprite-8x8-2026-09-05-091600.png.
Sep 4, 2026
Pixel Edit Lite v1.4.0 (build 12) — New Sprite Sheet used to wipe the sprite sheet outright behind a confirm dialog. I changed it to silently save the outgoing sheet to disk via a security-scoped bookmark before clearing, so the action needs no confirmation now and nothing is lost — the same check runs before Import and before reopening a past file too.