Loanly.
A home-loan calculator for India. EMI, PMAY, tax. One tool, built to replace the eight browser tabs every homebuyer ends up with.
Buying a home shouldn't feel like being the only person in the room without a spreadsheet.
01 / The Problem
I started Loanly the month I began seriously looking at home loans for myself. I had eight browser tabs open: one for the bank's EMI calculator, one for a government subsidy page, one for tax deductions, one for the state registrar's stamp-duty table, a forum thread on floating vs fixed rates, two news articles explaining the latest RBI LTV caps, and a spreadsheet where I was trying to reconcile all of it.
Most online calculators couldn't do what I needed. They'd give me a monthly EMI, but ignored the three biggest variables in an Indian home purchase: the PMAY subsidy (a government interest subsidy that changes the effective rate by up to 2.67%), state-level stamp duty and GST (which can add several lakhs to the closing cost, with different rates by state and by the buyer's gender), and tax deductions under Sections 80C, 24(b), and 80EEA, which differ again between the old and new tax regimes.
The calculators that did try to handle these were either US-centric tools retrofitted with a rupee sign, or decade-old WordPress widgets that hadn't been updated since the 2017 tax reform. None of them talked to each other. If you changed the loan amount, you had to recompute the subsidy, the tax saving, the stamp duty, and the EMI by hand.
Loanly is what I wish had existed that month. One tool, all the pieces, showing its work.
02 / The Approach
Two design rules shaped everything:
Show the math. A home loan is the single largest financial decision most people make, and a black-box calculator asks them to trust a number they can't verify. Every result in Loanly links back to the formula that produced it. The EMI tab shows the amortisation schedule month by month, the PMAY tab shows both the market-rate EMI and the subsidised EMI side by side, and the tax tab shows which sections contributed what. Users leave understanding why, not just what.
Separate calculation from interface. All the financial logic lives in pure TypeScript modules under src/lib/calculations, one file each for EMI, floating rate, hybrid rate, PMAY, prepayment, tax, stamp duty, and affordability. No React, no side effects, no DOM. The UI layer calls these functions and charts their output; the formulas are independently testable and could be lifted into any other app.
The EMI module is a good example of how tight the boundary is:
export function calculateEMI(
principal: number,
annualRate: number,
tenureYears: number,
): number {
if (principal <= 0 || tenureYears <= 0) return 0;
const monthlyRate = annualRate / 12 / 100;
const numPayments = tenureYears * 12;
if (monthlyRate === 0) return principal / numPayments;
const multiplier = Math.pow(1 + monthlyRate, numPayments);
return (principal * monthlyRate * multiplier) / (multiplier - 1);
}
No framework assumptions. No hook. Just the formula from a textbook, guarded for the edge cases a spreadsheet wouldn't survive (zero interest, zero tenure, NaN inputs from bad form parsing).
That discipline paid off when I layered the harder calculators on top. The affordability calculator inverts the EMI formula. Given what you can pay per month, what's the largest principal you could afford? The PMAY calculator runs EMI twice (market rate and subsidised rate) and discounts the difference to a net present value. The floating-rate calculator runs EMI every time the rate resets and stitches together the amortisation from the segments. Each of those is ten to thirty lines because EMI itself is five lines.
On the interface side, I leaned on three things: real-time recalculation so users can drag a slider and watch numbers update, charts that make abstract money concrete (a stacked bar showing how each EMI payment is split between principal and interest helps in a way a table doesn't), and WCAG 2.1 compliance so the tool works with a keyboard and a screen reader on day one rather than as an afterthought.
03 / The Stack
React 19 + TypeScript + Vite. Lean and fast. Strict TS config catches the kind of edge case that, in a financial app, ends up costing someone real money.
TanStack Router. File-based routes with full type inference. /emi, /pmay, /prepayment each read as their own small app, and I never had to maintain a router config by hand.
React Hook Form + Zod. Every input validates at the schema level before anything touches the calculation modules. Error messages are tied to the schema, not scattered through the components.
Recharts. The amortisation, rate projection, and scenario comparison views are all the same Recharts primitives configured differently. Cheap to add new visualisations.
Tailwind v4 + Tippy.js. Utility-first for the dashboard density Loanly needs, Tippy for the explainer tooltips next to every obscure term ("What's FOIR?", "Why does this rate cap depend on the loan size?").
No backend. Everything runs client-side. No account, no history, no data leaving the browser. For a tool people use while punching in their salary and city, that mattered.
04 / What I'd Do Differently
Add persistence, but keep it local. The hard part about Loanly isn't running the calculators, it's entering the inputs: your salary, your city's stamp duty rate, your existing obligations for FOIR. A user who comes back tomorrow has to type it all again. Local storage and an "export scenario" button would solve most of this without introducing accounts.
Treat explainers as product, not garnish. The tooltips help, but a homebuyer confronting floating vs fixed rates for the first time needs a short essay, not a tooltip. A handful of inline explainers, things like "why does the RBI cap LTV at 75% above ₹75L?" or "when does Section 80EEA apply?", would do more for trust than another chart.
Mobile deserves its own layout. The calculator pages scale down, but they weren't designed bottom-up for a phone, and it shows. Sliders are finicky on touch, and a multi-column comparison table becomes a side-scroll. A mobile-first pass on the three or four most-used pages would move the needle more than any new feature.
Ship it as a browser extension. The scenario I keep coming back to is this: you're on a property listing, it shows "EMI starting at ₹45,000". Right now you'd open Loanly in another tab and retype everything. A browser extension that tagged price fields on listing sites and offered "run this through Loanly" inline would move it from a tool people remember to visit, to a tool that shows up when they need it.
OnePortal.
A micro-frontend shell that replaced dozens of disjointed SharePoint tools with one unified portal: shared auth, shared design, and a path off SPFx for every team that needed it.