Lab

Things I'm currently building.

Cart

A collaborative grocery app for two. Shared lists plus a price book that normalises everything to $/100g — so sale prices and different pack sizes are comparable at a glance. Built with Expo so it runs natively on both our phones.

Expo React Native

Cookbook

A recipe site with ingredient scaling, nutrition tracking, and a cooking mode that keeps the screen on. Recipe apps have too many ads and none of them scale fractions correctly. Recipes are markdown files; Keystatic is the editor.

Next.js Tailwind

GymCat

A reference catalogue of equipment across Anytime Fitness gym locations in Singapore. Built from personal frustration with arriving at a gym that didn't have the rack I needed. Equipment is hand-curated as JSON and grouped by function.

HTML CSS JS

Ledger

A personal bookkeeping app that replaces spreadsheets. Imports bank statements, parses them into a SQLite ledger, and produces categorised reports. Locally it's a Python server against real data; the live site serves fictional demo data.

Python SQLite

Move

A personal activity analytics dashboard built on my gym visit data. This parses and visualises the data: monthly trends, time-of-day heatmaps, membership pauses.

HTML CSS JS Chart.js

WODGEN

A deterministic workout generator built for one athlete: me. Workout apps optimise for everyone, which means they work for no one in particular. This one encodes a specific rotation, equipment access, and fatigue logic. Fully client-side, no API.

HTML CSS JS
How I build

Anyone can ship an app right now. Not everyone governs what they've built.

Single source of truth, enforced

Schema owns the data model, design tokens own the visual layer, docs own the workflow. Anything duplicated drifts.

Audit for drift, not just bugs

Stale references and obsolete docs mislead more than missing ones. Gaps compound quietly.

Refactor before fragility sets in

Remove structural weaknesses before they become load-bearing. Good systems get easier to change over time, not harder.

Fix at the right layer

Data shape issues belong in the schema, not patched in the UI. Style decisions belong in the design system, not inline.

Scope is an architectural decision

A precise MVP with an explicit deferred list prevents accumulation. What you leave out matters as much as what you ship.