Skip to content
AFM Studio
  • Pages

    AFM Studio
  • Work
  • Lab
  • About
  • CV
  • Contact
  • Projects

    AksaraA searchable library for Otorita IKN's knowledge, where the server checks every reader's access across three levels
  • Daily TaqwaTamper-resistant prayer attendance system for ~2,000 OIKN government employees at Masjid Negara IKN
  • Lantara v2A permit engine for Otorita IKN where administrators add new permit types from a screen, without a developer
  • eKiosk IKNTwo control rooms for Nusantara: kiosk content management and live bus tracking with arrival times that grade themselves
  • E-Monev IKNA monitoring platform for Nusantara's 23-year build, tracking every unit's quarterly progress against 24 national KPIs
  • JDIH OIKNOIKN's public legal document portal, with a controlled publishing workflow and AI summaries that never leave the server
  • Jejak PenanamanA check-in app for IKN tree-planting events that proves each participant was on site with a geofenced selfie
  • Dashboard SAKTIA nightly pipeline and dashboard that replaces OIKN's manual budget downloads for all six of its budget units
  • DoseRxA bedside dose calculator for 127 drugs that rounds each dose to tablets and syrups Indonesian pharmacies sell
  • CubiqA speedcubing trainer with competition-grade timing and a solver I wrote for each of the 8 major puzzles
  • ScimotionAn interactive science library of 86 articles, each explained next to animations the reader can control
  • WA Daily Scrum BotA WhatsApp bot that chases missing standup reports for a 14-person team and flags tasks stuck for days

↑ ↓ to move · Enter to open · Esc to close

KPR Simulator

An ad-free Indonesian mortgage calculator showing what happens after the fixed rate ends, and where instalments break

Screenshots
regulated figures cited to their source
27
unknown figures refused by name
7
network requests; figures stay in the link
0
effective rate of flat 5% over 20 years
7.95%
On this page

The problem

A KPR, an Indonesian home mortgage, is the largest financial commitment most households will ever make. Banks quote a fixed rate for two or three years, and then the loan floats. A family that budgets around Rp3.2 juta a month can face Rp4.8 juta in year four. Every calculator I found assumed one rate for the whole twenty years, so it hid the biggest risk in the loan.

The calculators had other gaps too. "Flat" and "efektif" interest are both advertised, they can't be compared directly, and most borrowers can't tell which one they are being quoted. The calculators show a number with no working. And nearly every one in Indonesian search results exists to collect leads for a bank or a property portal.

What I built

The page answers the question a borrower can take to the bank

I changed what the calculator asks. "Can I afford Rp3.2 juta?" becomes "My loan breaks at, say, 13.4%. My bank doesn't publish its margin over the base rate, so what is it?" The threshold page finds the exact floating rate at which the instalment passes a share of income you choose. Two edge cases get their own plain answers: already over the limit at a zero rate, and still affordable above the highest rate searched.

Every rupiah can be traced

Money is always a whole number of rupiah. Rounding is its own labelled step in the working, and it names the convention it follows. That step is where calculators drift a few rupiah from bank statements, so I made it visible. The engine never reads today's date; the month is always passed in. The same inputs give the same result forever, which matters when someone checks it against a bank statement six months later.

Two separate calculations check each other

The effective rate is worked out twice, by two routines that share no code. If they shared a helper, they could share a bug. This check also corrected my own brief. The PRD said a flat 5% is roughly a 9% effective rate. That holds over one to five years, but over twenty years the computed figure is 7.95%. The app states the computed number, and I fixed the brief.

Unknown figures are refused by name

Every regulated figure, such as the subsidy rate, price ceilings, income ceilings and tax rates, is stored with its legal basis, source link and verification date. The build fails if one has no citation. When I couldn't trace loan-to-value ratios, the minimum down payment or the subsidised loan tenor to a regulation still in force, I didn't guess. They became seven declared gaps the app names and explains in both languages. Amber marks the floating-rate band and every assumed value, and red marks the affordability limit. Nothing else uses those colours.

Your figures never leave the browser

Income and loan amounts are stored in the part of the link after the hash sign, which browsers never send to a server. The site makes no network requests and has no analytics or ads. A build check confirms the exported site calls nothing external.

Result

KPR Simulator is live, public and free of ads, in Indonesian first and English second. It shows the full payment schedule with an amber band where the rate becomes unknown. It covers the threshold rate, flat and efektif side by side, and the subsidised FLPP path with a check that names which criterion fails. It adds total cost of ownership and an extra-payment simulator. A parameter page lists all 27 cited figures. I built it alone over two days in August 2026.

The app never advises, ranks or names a bank. It states in the interface that it is not financial advice, that the floating rate is unknown and unpublished, that bank fees vary, that loan approval is not modelled, and that figures should be confirmed with the bank.

Under the hoodTechnical detail for engineers
  • The engine is (inputs, product, rulePacks) => Schedule, with no React, DOM or new Date() in lib/. Periods are explicit { year, month } integers.
  • Hand-written annuity and flat amortisation, prepayment with an early-settlement penalty, effective-rate derivation, and bisection for the threshold (lib/rate/threshold.ts). lib/rate/irr.ts and lib/rate/effective.ts share no code; the IRR solver feeds both the tests and the displayed figure.
  • Flat 5% converts to 9.11%–9.32% effective over one to five years, and 7.95% at twenty years.
  • Rule packs live in data/rules/ (FLPP ceilings, BPHTB and PPh rates, traced to Kepmen PUPR, Permen PKP and tax law), validated with Zod. The seven gaps are in data/gaps.json: LTV ratios, FLPP tenor, minimum down payment, SBUM, per-kabupaten NPOPTKP, bank fees and base-rate snapshots. data/sbdk/snapshots.json ships empty on purpose.
  • The FLPP 5% rate rests on a ministry statement, not an article traced to its clause, and the parameter page says so.
  • Research overturned the PRD: Bank Indonesia had relaxed LTV to 100% and, for a first home, left the maximum to bank discretion.
  • The conservation assertion and trace types were committed before the amortisation loop, and the rule validator before any rule data.
  • 1,614 assertions across 14 test files run in about two seconds; 1,186 are the conservation sweep over tenors, rates and principals.
  • Four production dependencies: Next.js 14.2.15 (output: 'export'), React 18.3.1, React DOM and Zod 3.23.8. No finance, currency, date or charting library; the schedule elevation is hand-built SVG and Intl.NumberFormat handles display. check:offline asserts zero external requests.
  • Six routes (hitung, ambang, subsidi, banding, biaya, parameter) in two locales, plus home. Shipped JS is about 964 KB raw, above the 200 KB gzipped target.
  • actions/deploy-pages hung at deployment_in_progress for about ten hours with no change on my side, then deployed in fourteen seconds on 7 August 2026. The diagnosis is written into CLAUDE.md.
  • A late UX pass collapsed an eleven-control form into three named steps.
  • About 9,500 source lines and 37 commits on 6–7 August 2026.

Screenshots

Beranda
Hitung Angsuran
Batas Anda
KPR Subsidi
Bandingkan
Biaya Awal

Hiring, or building something similar?

I'm open to full-time roles and select freelance work.