Skip to content

projects

9 shipped · full write-ups on click
  • Tidewatch Card

    Tidewatch (IN PROGRESS) active

    Tidewatch is a portrait, one-thumb tower-defence game for iPhone and Android, set on a chain of tidal islands where the sea itself moves: towers built on the flats go dark at hi…

    • Typescript
    • PixiJS
    • Preact
    • Vite
    • Capacitor
    • Vitest
    • Playwright
    • Github Actions
    full write-up

    Tidewatch is a portrait, one-thumb tower-defence game for iPhone and Android, set on a chain of tidal islands where the sea itself moves: towers built on the flats go dark at high water, buoys only fire when it comes in, and the light you defend is a lighthouse. Free, ad-free, no in-app purchases. Built solo — design, balance system, art pipeline and a deterministic simulation verified across engines.

  • Sourdough Planner

    Sourdough Planner active

    Sourdough Planner is a small web app that plans one bulk batch of sourdough and splits it into several bakes: rolls, loaves, pizza bases, or whatever you keep as presets. It wor…

    • React 19
    • TypeScript
    • Vite
    • Node 22
    full write-up

    Sourdough Planner is a small web app that plans one bulk batch of sourdough and splits it into several bakes: rolls, loaves, pizza bases, or whatever you keep as presets. It works out the flour, water, starter and salt, the weight per piece, and a clock-time schedule from mixing to baking with a lane per item.


    Enter the starter you have and it sizes the batch and spreads the dough across your items, or enter the items you want and it tells you how much starter to have ready. Every percentage uses true hydration, counting the flour and water already inside the starter, and flex presets absorb any surplus or deficit in priority order. Built for a phone or tablet on the kitchen counter, with a keep-awake kitchen mode, dark mode, and print layout; everything is stored in the browser and the app ships as a zero-egress multi-arch container for the homelab.


    Built to solve the Saturday-morning problem of turning one jar of starter into pizzas, rolls and loaves without a spreadsheet and a calculator.

  • Suoku puzzler screenshot

    Sudoku Puzzler active

    Sudoku Puzzler is a sudoku generator, solver and difficulty rater, with a web app to play what it makes and a training section that teaches the techniques. Every puzzle it serve…

    • TypeScript
    • React
    • Fastify
    • SQLite
    • Playwright
    • Vite
    full write-up

    Sudoku Puzzler is a sudoku generator, solver and difficulty rater, with a web app to play what it makes and a training section that teaches the techniques. Every puzzle it serves is 9x9 with exactly one solution, rated across six levels from beginner to diabolical.


    Run it with docker compose up --build and open localhost:8080: one image, one process, one port, and a SQLite file on a named volume. Rating a puzzle means solving it the way a person would, cheapest technique first, up to swordfish, on sudokuoftheday.com's cumulative technique-cost scale. That makes the rater's output a step-by-step explanation, so the fourteen technique pages in Training explain each one in our own words, show it on a position mined from a real generated puzzle, then ask you to find it yourself. The server owns the game and the browser only renders it, so digits, pencil marks and elapsed time are rows in SQLite, not tab state.


    Built to have a puzzle that survives a reload, a second device and a week away, and to get better at the hard ones.

  • finance-planner-card

    Finance Planner active

    Finance Planner is a self-hosted web app for planning savings toward upcoming payments. Record your income and your bills, goals and recurring payments, and it tells you how muc…

    • React
    • Vite
    • Fastify
    • PostgreSQL
    • Turborepo
    • Zod
    • Kubernetes
    • AI-Assisted Development
    full write-up

    Finance Planner is a self-hosted web app for planning savings toward upcoming payments. Record your income and your bills, goals and recurring payments, and it tells you how much to set aside each month per goal to hit its date — and what's left over, per account, per person, and across a household.

    The core idea is that the unit of planning is the person, not the account. A bills pot fed by a current account can't be planned on its own, so one funding pass covers everything you own, and every screen — account page, household plan, flow diagram, forecast — is a view of that single pass. Income is money arriving from outside; a transfer between two of your own accounts is just your own money moving, and the two are never double-counted. Expenses are always funded before savings, funding loops are detected and reported rather than refused, and goals can be paced by a target date or driven by a fixed monthly contribution.

    Households are an attribution layer over the same engine: tag accounts as shared or personal, set each member's contribution share, mark expenses shared or personal, and the app splits shared costs, funds everything by priority and works out the transfers each person should make. The plan is grounded in reality by a contributions ledger — record what you actually set aside, check in real balances, tick off transfers and close your month — and from that history it projects twelve months forward.

    I built the whole thing: domain engine, multi-service backend, React PWA, and deployment. It's a pnpm/Turborepo monorepo with a pure TypeScript domain package (the savings engine, pinned to the penny by parity tests across every view), Fastify services for API, auth and calculation, Postgres via Drizzle, Zod contracts shared end to end, OpenTelemetry tracing across the service hops, and cloud-agnostic Kubernetes deployment via Helm. Most of the implementation was orchestrated across parallel AI agents from plan documents I wrote, with CI gating every wave.

  • tf-import-blocks card

    tf-import-blocks active

    tf-import-blocks is a command-line tool and TypeScript library that generates Terraform import blocks for every resource in a Terraform state file, using the id each resource ty…

    • TypeScript
    • Node.js
    • Terraform
    • AWS
    • HCL
    • Github Actions
    full write-up

    tf-import-blocks is a command-line tool and TypeScript library that generates Terraform import blocks for every resource in a Terraform state file, using the id each resource type actually imports by — which is frequently not the id sitting in the state.

    Point it at a *.tfstate, terraform state pull output, or terraform show -json output and it writes one import block per resource (npx tf-import-blocks prod.tfstate > imports.tf). Several files merge into one document sorted by address, a --filter flag moves a single module subtree, and stdout carries pure HCL so redirecting it is always safe. No AWS credentials, no network, no runtime dependencies.

    The asset is a per-type rule table covering ~250 AWS resource types: aws_sqs_queue imports by queue URL while the state holds the ARN, aws_ecs_service by cluster/service, and aws_route's state id is a synthetic hash that is never a valid import id at all. A naive "use the id" generator looks right on a demo and silently emits garbage for the composite and attachment resources that make up most of a real state; anything without a rule is flagged # VERIFY rather than guessed. The same rules also resolve resources from a scanned inventory, and golden tests assert both paths produce identical ids.

    Built to produce the half of Terraform's adoption workflow it leaves you to write by hand: the import blocks that terraform plan -generate-config-out needs before it can generate the resource configuration for you.

  • AWS Network Atlas

    AWS Network Atlas active

    AWS Network Atlas scans AWS accounts read-only and renders an accurate, interactive, committable network and security diagram — the full traffic path plus security-group posture…

    • Typescript
    • AWS SDK
    • React
    • Vite
    full write-up

    AWS Network Atlas scans AWS accounts read-only and renders an accurate, interactive, committable network and security diagram — the full traffic path plus security-group posture, identity, and a searchable inventory of everything in the account.

    Point it at one or more AWS profiles and it stitches a picture of your estate across accounts and regions: VPCs, Transit Gateways, peering, VPN, Direct Connect, load balancers, edge/DNS, IAM, KMS, WAF, and more. Every snapshot is plain text, so the whole diagram is diffable and lives in git alongside your code.

    A synthetic demo estate ships with the repo, so you can open the viewer in a browser with no AWS account and no scan.

    Built to solve the problem of wanting an actively maintained accurate AWS estate diagram, without needing to grant 3rd party access to your account.

  • url utilities admin card

    URL Utilities Admin active

    url-utilities-admin is a server-rendered admin UI for the headless url-utilities URL shortener that lets you list, search, create, edit, delete and QR-code shortened links from …

    • TypeScript
    • Fastify
    • HTMX
    • EJS
    • Vitest
    • Docker (Multi-Arch)
    • Kubernetes
    full write-up

    url-utilities-admin is a server-rendered admin UI for the headless url-utilities URL shortener that lets you list, search, create, edit, delete and QR-code shortened links from a browser.

    Point it at a running url-utilities core (≥ v2.2.0) with CORE_URL and CORE_API_KEY, then npm run dev and open http://localhost:4000/urls. It ships as a multi-arch (amd64 + arm64) GHCR image with a Helm chart that mirrors the core's layout — non-root pod, read-only root FS, liveness/readiness probes, optional Ingress and HPA, and a /metrics Prometheus endpoint.

    The deliberate choice is to stay thin: no SPA bundler and no client-side router — HTMX swaps Fastify-rendered EJS partials, and the UI never touches Postgres, consuming only the core's /api/admin/* endpoints under a documented cross-repo contract. Auth is delegated to the ingress or network, while the UI still authenticates outward with an API key so the core stays protected even if the admin pod is compromised. Tests run against a real core and Postgres via testcontainers rather than mocks.

    Built to solve the gap of administering a headless shortener running on a Raspberry Pi 5 Kubernetes cluster without bolting a full frontend stack onto a homelab tool.

  • url utilities card image

    URL Utilities active

    URL Utilities is a headless URL shortener and QR-code API that turns any long link into a 10-character alias and a scannable PNG, served from a single small container.

    • TypeScript
    • Fastify
    • Drizzle ORM
    • PostgresSQL
    • Vitest
    • Docker
    • Helm
    • AI-Assisted Development
    full write-up

    URL Utilities is a headless URL shortener and QR-code API that turns any long link into a 10-character alias and a scannable PNG, served from a single small container.

    You point it at a Postgres database (local, Supabase, Neon — anything), set three environment variables, and call it: curl -X POST $APP_URL/api/qr -H "x-api-key: $API_KEY" -d '{"url":"https://example.com"}' returns the short link plus a base64 QR data URL. GET /r/:alias 301-redirects and bumps the click counter. Authenticated /api/admin/* routes provide list/search/sort/paginate, update, delete, QR regeneration, and a stats summary for operators.

    The deliberate decision is that there is no UI in the core. It started on Next.js and was rewritten to plain Fastify so the service is just an API with one shared secret and one schema — an operator dashboard lives in a separate microservice that talks to the admin endpoints. That keeps the image tiny, makes it trivially embeddable in other apps, and lets the same build ship as a Docker/Helm deployment (including linux/arm64 for a Raspberry Pi) or as a Vercel serverless function. Behaviour is pinned down by an end-to-end Vitest suite running against a real Postgres via Testcontainers.

    Built to solve the problem of wanting short links and QR codes across several personal projects without depending on a third-party shortener or dragging a frontend framework into every deployment.

archived (1)
  • BMAD-Manager (MVP) archived

    BMAD Manager is a Tauri desktop application that provides a visual interface for managing AI-assisted software development workflows.

    • Rust
    • Tauri
    • Svelte
    • TypeScript
    • SQLite
    • WebdriverIO
    • AI-Assisted Development
    full write-up

    BMAD Manager is a Tauri desktop application that provides a visual interface for managing AI-assisted software development workflows.

    It integrates with Claude CLI to spawn terminal sessions with specialised agent personas, visualises project workflow phases (planning → design → implementation), displays sprint/story status in a kanban board, and manages git worktrees for parallel story development.

    Built with Rust backend and Svelte frontend, it turns the BMAD methodology into a GUI-driven experience for developers working with AI coding assistants.

    Built using the BMAD process and Claude to gain a better understanding of the BMAD workflow process.


    This tool was built as a way of learning BMAD methodology and understanding how it works further, it was never designed to go past MVP