Skip to content
Product Design · Self-built2026

Spendly

A calm money tracker for a life lived in two currencies. Spending, subscriptions, goals, and debt in one place, every number instantly readable in LKR or USD.

Visit site

Why I built it

I built the tool I needed.

I live my financial life across two currencies, LKR and USD. Salary and rent in one, subscriptions and freelance income in the other. Every budgeting app I tried treated that as an edge case, so I was always doing conversions in my head just to answer a simple question: how am I actually doing this month.

The apps that did exist were either built for accountants or were just a transaction list with no way to plan ahead. I wanted something calm enough to open daily, that treats two currencies as normal, and that helps me look forward, not just log the past.

The problem, framed as a designer

Three things had to be true, and no existing app got all three:

Dual currency as a first-class idea, not a setting.

Every amount had to carry its own currency, and one tap had to convert the entire app, so a number is never ambiguous.

Calm enough to open every day.

Personal finance is stressful. A loud, red-and-green, spreadsheet-dense interface makes you avoid it. The design had to lower the temperature, not raise it.

Forward-looking, not just a ledger.

Recording the past is table stakes. The harder, more useful job is helping someone decide what to do next.

The decisions that shaped it

Currency is a first-class citizen.

Every amount carries its own currency, and a single tap converts the whole app between LKR and USD at a live rate. Where a transaction's native currency differs from the display one, both show. Nothing is ever left for the user to calculate.

Calm over busy.

A muted, low-saturation palette. Generous space. No traffic-light overload. The numbers are the hero and the interface gets out of their way. This is the core feeling, and every visual choice serves it.

Privacy you can see, not just a backend promise.

A hide-balances toggle sits in the header at all times, so the app is usable in public without shoulder-surfing risk. The privacy message appears before you even log in. For sensitive money data, trust has to be visible in the UI.

Plan, don't just record.

Beyond the ledger, the product helps you decide: a “What if?” simulator with two sliders showing the real effect of cutting spending or paying down debt, an avalanche-vs-snowball debt comparison with a real payoff date, and per-goal contribution math. All computed live, no placeholder text.

Empty states as a real first-run surface.

Every panel has a purpose-written empty state with a clear next action, never a blank box or leftover demo data. The first five minutes of a new account were designed, not left to chance.

Mobile first, for real.

Bottom tab bar, floating add button, full-width sheets on phones. The desktop sidebar is the enhancement, not the starting point. It's built to live on a home screen as an installed app.

Problems I solved

The part of the work that doesn't show in a screenshot. Real issues that came up in daily use, and how I fixed them.

Modals opening off-screen on iPhone.

Add-transaction sheets sometimes rendered below the visible screen on iOS Safari when the page was scrolled. I traced it to a CSS animation on a page wrapper creating an unintended positioning context. Fixed by portaling every sheet to the document body and locking the background scroll, then restoring the exact scroll position on close. Verified with real before-and-after measurements, not just eyeballing it.

An auto-calculated amount that felt presumptuous.

The savings-goal card first offered a single “add this month's amount” button with a number I calculated for the user. It felt like the app telling them what they saved. I replaced it with a small field where they enter what they actually put away. A tiny change that respects the user's real financial life instead of guessing at it.

Demo data bleeding into real accounts.

New sign-ups were landing on pre-filled example transactions instead of a clean slate. I gave every new account a genuinely empty start and built the empty states so “nothing here yet” reads as intentional, never broken.

Native form fields that felt inconsistent.

Date and dropdown fields leaned on each browser's default chrome, which on iOS has no visible icon and an unreliable tap target. I rebuilt them as custom fields with a consistent icon and a tap-anywhere handler. Small fix, meaningfully better felt-quality on mobile.

Design system

Because I designed and built this, the system is real and shipped, not a style tile.

Color.

Light and dark, both hand-tuned rather than auto-inverted, so mood and contrast hold in each. A restrained green brand accent, with amber and red reserved for genuine caution and danger, never decoration. Driven entirely by CSS variables swapped on a theme attribute, one component tree, no duplicated markup.

Type.

Geist for UI, Geist Mono for numbers, so figures line up cleanly in a tabular context. Tight letter-spacing on large numbers for a confident, number-forward feel.

Icons.

Lucide throughout, one stroke weight, no mixed families. Icons carry meaning (up-right for expense, down-left for income) rather than decorating.

Shape, depth, motion.

A clear small-medium-large radius rhythm, soft low-opacity shadows for depth without harshness, and deliberately minimal motion that collapses to near-zero when a user asks for reduced motion.

Outcome

Spendly is live and in daily personal use, real transactions, real budgets, real currency conversion on a live rate. It's installable as a home-screen app, and it went through a full quality pass: a data-loss edge case closed, a missing mobile logout added, a database security warning hardened, and a daily automated backup shipped so history can't just vanish.

That last part matters to how I think. A backup system sounds like a backend chore, but for a finance app it's a trust decision, and trust is a design problem. This is the clearest example in my portfolio of designing a product end to end and caring about the parts no one sees.

Deliberate scope

Things I chose not to build, so the story stays honest:

  • 01

    Single currency pair (LKR/USD) rather than arbitrary multi-currency, to keep the mental model simple for the real use case.

  • 02

    Invite-only rather than open sign-up, a deliberate privacy choice for personal money data.

  • 03

    No bank-linking or auto-import, transactions are entered by hand by design, so the data stays fully user-controlled.