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

Selapan

A Javanese calendar that converts any date to its weton and shows the cited arithmetic behind every number

Screenshots
interlocking cycles, each traced to a cited source
4
reckonings shown side by side, Aboge and Asapon
2
earliest date the lunar calendar accepts
1633 CE
consecutive days checked for exact cycles
36,524
On this page

The problem

Across Java, families use a person's weton, their birth-day in the Javanese cycles, to plan naming ceremonies, weddings and the days of remembrance after a death. It looks like a table lookup. In fact it combines four cycles: the 5-day pasaran, the 7-day week, the 210-day wuku, and a lunar year that begins in 1633 CE. A correction system called the kurup also shifts the lunar count every 120 years.

Existing weton sites are ad-supported, cite nothing and disagree with each other. They fix the current kurup, so historical dates come out wrong. They convert dates before 1633, when the lunar system didn't exist. They show no working, so a reader can't catch a mistake. Communities that follow the older Aboge rule sometimes observe Idul Fitri a day after the national date. No site shows that difference.

What I built

Every answer shows its working

Each figure on the page opens to show how it was computed: the reference date, the number of days since, the cycle length, the result and the source. Anyone can redo the answer by hand from the screen. I built the calendar engine so it returns this working for every value. A figure without it can't be displayed at all, so the page can't drift from the arithmetic.

Reference dates come from cited sources

Each cycle is counted from a reference date that lives in a data file with its source and where to find it. The build fails if a reference date has no citation or doesn't match its own stated date. Where a value is inferred from other sources, it is marked unverified, shown in grey, and listed on a public sources-and-gaps page.

It refuses dates it can't answer

Each cycle has its own valid range. Ask for a date in 1500 CE and the lunar calendar declines, with the reason, while the pasaran and wuku still answer, because those cycles run continuously. I counted every date as a plain whole number of days, with no time zones or clocks involved. The same input always gives the same answer.

Aboge and Asapon side by side

The divergence view reckons the same date under both rules and shows the mechanism that separates them. For one example date, Asapon reads 21 Sapar and Aboge reads 20 Sapar. Aboge communities see their own reckoning next to the national one, and the site doesn't call either one wrong.

Calculation and interpretation are kept apart

Weton feeds primbon: character readings, marriage matches and auspicious days. Many people take it seriously and many reject it. I gave computed values one colour, indigo, and traditional material another, a red taken from printed almanacs. I held back the interpretation layer entirely. Its rules already run at build time, but it won't ship until a reviewer familiar with Javanese practice agrees to check it.

Result

Selapan is live in Indonesian and English, with seven pages in each language. Beyond conversion, it has cycle wheels that realign every 35 days (the selapan) and every 210, a wall-calendar month view and the traditional farming calendar (pranata mangsa). It also counts the dates of the mourning ceremonies as plain cited arithmetic, with no interpretation. It checks exact cycles over 36,524 consecutive days. The site presents itself as a personal project, not an authority, and says that practice varies by region. I built it in one day, on 6 August 2026.

Under the hoodTechnical detail for engineers
  • Julian Day Number is the only internal date representation. There is no Date object anywhere in lib/; "today" is resolved in the UI and passed in. No date library, because date-fns, Luxon and Temporal all carry time-zone semantics that are wrong for a cycle-modulo calendar.
  • Engine signature is (jdn, options) → CalendarTrace. Each value carries a Derivation: anchor id, anchor JDN, offset, modulus, result, source and verified status.
  • Refusals are typed objects, { subsystem, reason, validFrom, validTo }, never a thrown string, a null or a nearest-match guess.
  • Anchors live in data/anchors/ as JSON with source, locator and verification date. A 226-line validator recomputes each anchor's JDN from its Gregorian date and rejects mismatches, and rejects any verified claim without an independent cross-check. It gates both pnpm build and CI.
  • Cited data: 4 anchors, 5 kurup definitions, the neptu table and the pranata mangsa table. Documented gaps: the single-source wuku epoch, kurup.anenhing.1987 as a forward projection, the inferred 72-year Ajumgi span, and Dal-year month lengths.
  • The 1936 Asapon transition is cross-checked in the data file itself: 24 March 1936, Selasa Pon.
  • The primbon (M6) schema already enforces citations, attributions that start with "Menurut", and no second-person phrasing or scoring.
  • Colours: indigo #2B4470 for computed values, rubric #A83C28 for traditional material, grey for out-of-range and unverified.
  • Next.js 14 static export, 7 routes × 2 locales, four production dependencies (next, react, react-dom, zod). Deploy pipeline: data:validate → typecheck → lint → test:run → build.
  • 126 Vitest tests across 8 suites; the kurup suite is heaviest at 29. The longest invariant covers 36,524 consecutive days. About 6,300 lines, 28 commits in roughly 3 hours 45 minutes.
  • Emitted JS is about 880 KB uncompressed across all chunks, against a PRD target of 200 KB gzipped for the app payload.

Screenshots

Beranda
Ubah Tanggal
Kalender Bulanan
Selapanan
Mangsa
Kurup

Hiring, or building something similar?

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