Apps

Apps

Screenshots live on the Software sheet — this page is the architecture and the reasoning

Two iOS apps, built solo, developed entirely on Windows and tested on a physical iPhone through Expo Go — no Mac in the loop until Apple's own build service takes over. What each app does, how it's put together, what turned out to be hard, and where it goes next.

SFT‑02

UK Tax Companion app icon — a white pound sign on tealUK Tax Companion

Calculators, planners and a personalised HMRC news feed — understand what you keep, and stay ahead of what's changing

Status Live · App Store Stack Expo SDK 54 · React Native · TypeScript Started May 2026 Tests 144, across 13 files Store App Store

Why this app

The Big 4 mobile apps in this space (BDO Germany, Deloitte Germany among them) are content-heavy lead-gen funnels for the firm's consulting business — useful in theory, but built to redirect you into an engagement. I wanted the opposite incentive: something genuinely useful on its own, that never tries to sell you anything. Started as a calculator with a news feed bolted on; the news feed turned out to be the more interesting problem.

Inside the code

The tax logic lives entirely in lib/tax/uk/ as pure, dependency-free TypeScript — no UI code touches a rate or a threshold directly. A cluster of calculation engines covers Income Tax (a full stacked model: salary, other income, savings and dividends, with the Personal Allowance taper worked through correctly) and Take-Home Pay, Capital Gains Tax (Annual Exempt Amount, current-year vs brought-forward loss rules per HS227), Corporation Tax with marginal relief and employer NIC, SDLT, Student Loan repayment, VAT (including the Flat Rate Scheme), a Pension Planner, and a Sole Trader vs Company comparison that models retained profit as a company-only lever rather than treating "take out of the company" as the whole picture.

Above that sits a decision-tool layer — IR35 status, Self Assessment requirement, side-hustle/trading-allowance, a VAT-registration check, a short Tax Health Check quiz — each one exportable as a PDF via expo-print and expo-sharing, which is the feature that separates this from a plain calculator: a client-shareable output with the working shown, not just a verdict.

The other half is Tax Radar: the live gov.uk Content API feed, tagged by a rule-based engine (lib/updates/tagging.ts) into life-situation topics — self-employment, property, pensions, PAYE, VAT, CGT — with a relevance score that boosts high-signal formats and followed topics while down-ranking routine "page updated" churn. A personalisation profile (employee / self-employed / director / landlord / investor, multi-select) seeds followed topics automatically and filters the Deadlines list to what's relevant. No backend, no cron job: the feed is fetched live, tagged and scored entirely on-device, with a bundled seed fallback so the tab is never empty even offline or the first time gov.uk's API is slow.

What was hard

Getting the calculators right was the easy part — the rules are published, and 144 tests pin every band, taper and edge case against HMRC's own figures. The harder problem was restraint: an early "salary vs dividend" scenario tool was trivially "always pay yourself the minimum salary," so it was reframed into Sole Trader vs Company, and even that needed retained-profit modelling once it became clear that full extraction at current dividend rates no longer favours incorporating the way it used to. A "unified position" screen that let you enter your numbers once was built, then dropped — it duplicated the existing calculators without propagating anything into them, so it was just another screen pretending to be a shortcut.

The other real constraint was privacy as a design rule, not a slogan: no accounts, everything local via AsyncStorage, crash reporting (Sentry) gated to production only and limited to crash diagnostics — no analytics, no tracking identifiers. That rule killed a planned Face ID lock outright, once it became clear that nothing persisted was sensitive enough to need one.

What's next

  • Curated plain-English summaries layered onto significant Radar items — authored offline, human-reviewed, no runtime LLM cost.
  • A home-screen widget and deadline notifications — both need the same move off Expo Go onto a custom EAS dev build, so they're batched together.
  • Scottish income tax bands (rUK-only at launch) and a standalone UK Corporation Tax calculator.
  • Weighing a light freemium model (PDF export / scenario save-compare as the paid tier) against keeping the whole thing free — undecided.

Short write-up ← · Screenshots on the Software sheet →

SFT‑01

Brilliancy app icon — a cream chess queen on a dark maroon groundBrilliancy

A curated collection of the greatest combinations in chess history — play the finishing blow from a real, celebrated game, and solving it unlocks the story behind it

Status Submitted · awaiting review Stack Expo SDK 54 · chess.js · react-native-svg Started Jul 2026 Tests 90, incl. PGN verification per puzzle Code GitHub

Why this app

Most chess-puzzle apps serve you a randomly generated tactic stripped of context: solve it, forget it, next. Brilliancy inverts that — every position is the real finish of a game that actually happened, with the history attached. Morphy at the opera, the Immortal Game, Fischer at thirteen: solve the position and you get the story, not just a green checkmark. The first version of the brief called for a daily-puzzle-with-a-streak format; that framing was deliberately dropped mid-build (see below) in favour of a collection explored at your own pace.

Inside the code

Every puzzle is defined once, as a move list and metadata, in src/puzzles/catalogue.ts. Nothing is hand-written from there on: chess.js replays the moves to derive the FEN and verify legality, and a vitest suite checks, for every one of the 28 entries, that the position is legal, the solution line is forced, and the final move actually delivers the stated goal — mate, in every case so far. That rule (no FEN from memory) exists because the app's entire value proposition is that the positions are genuine; a single wrong square would undermine the whole premise.

The board itself is hand-drawn SVG (react-native-svg) rather than an image-tile board, tap-to-move with legal-move dots and capture rings, animated with React Native's Animated API and haptic feedback on each move. The screen flow — masthead → player cameos → prologue → solve → epilogue — is deliberately paced like reading a short piece about the game, not a puzzle-of-the-day widget. Progress (points, solved count) is stored locally via AsyncStorage; there's no account and nothing leaves the device.

What was hard

Two decisions turned out to matter more than any line of code. First, licensing: the piece-art sets suggested in the original brief (Staunty, Fresca, Cardinal, Gioco) all turned out to be CC BY-NC-SA — non-commercial — and couldn't ship. The set actually used, Chessnut, is Apache-2.0, retinted for the app's dark, candlelit palette by a small generation script (scripts/gen-pieces.mjs); every portrait is public-domain, sourced and recorded in CREDITS.md. Second, framing: the app was originally briefed as a daily puzzle with a streak, and that was deliberately removed once it became clear it would force a permanent content-publishing obligation onto a solo, unpaid hobby project — the opposite of the calm, browse-the-greats feel the app is actually going for. Home is now the next unsolved puzzle, "where you left off," not "today's puzzle."

What's next

  • Drag-to-move (currently tap-to-move only) — gesture-handler and Reanimated are already wired in, it needs the worklets babel plugin and a root gesture handler.
  • Growing the verified set from 28 towards the full 150-game backlog.
  • VoiceOver labels on the board ("knight on d7") — reduced-motion is already handled, full screen-reader support isn't yet.
  • An Android build — the package identifier is already configured, just not built or tested.

Short write-up ← · Screenshots on the Software sheet →