← cd ../projects

AlSalah — Cross-Platform Prayer Times

A Kotlin Multiplatform prayer-times app with a from-scratch astronomy engine that computes lunar-crescent visibility from the Odeh (2004) criterion.

Kotlin MultiplatformComposeKtorRoomKoin

Overview

AlSalah ships to Android, iOS, and Desktop from one shared Kotlin Multiplatform codebase — a Compose Multiplatform UI, Room persistence, and Koin dependency injection, backed by a Ktor server (Netty, Exposed ORM, SQLite, HikariCP) packaged as a WAR on Tomcat 11.

The interesting part isn't the app shell — it's the calendar underneath it.

The Hijri calendar problem

The Islamic month begins when the new lunar crescent (hilāl) first becomes visible from a given location — which is a genuine astronomy problem, not a lookup table. AlSalah computes month boundaries from per-location crescent visibility, implementing the peer-reviewed Odeh (2004) criterion on top of custom sun and moon ephemeris code.

Odeh's test reduces visibility to a single parameter, V, from the crescent's arc of vision and its width, and sorts each sighting into four zones — from "visible to the naked eye" down to "not visible even with optical aid." But the calendar doesn't stop at the criterion: it computes the day's prayer times and that evening's crescent visibility from real ephemeris, per location. Pick a date and a city and watch both respond:

prayer-times · makkah
horizonFZAI
  • Tahajjud01:18
  • Fajr04:24
  • Shurooq05:47
  • Dhoha06:08
  • Zawaal12:21
  • Zuhr12:31
  • Asr17:02
  • Maghrib19:06
  • Ahmar20:16
  • Isha20:29

AlSalah · Hanafi Asr · local time (Asia/Riyadh)

crescent-visibility · odeh (2004)
horizonsun
ARCV
24.1°
W
2.19′
ARCL
30.8°
lag
+112m

V = 28.38

zone A Visible to the naked eye

Visibility is a global question, though — the same young crescent is an easy naked-eye sighting in one country and impossible in another the same evening. This globe bakes Odeh's zones over the whole Earth for the first evenings after upcoming new moons (precomputed at build time), so you can watch the visibility band sweep across longitudes:

crescent-globe · global visibility
  • A · naked eye
  • B · perfect conditions
  • C · optical aid
  • D · not visible
computing zones…
drag to rotate — precomputed at build time from the Odeh (2004) criterion.

Getting the math right

An engine like this is only worth anything if it's correct, so it ships with a 150+ test validation suite:

  • Checked against NASA and JPL HORIZONS ephemeris data and textbook reference values.
  • End-to-end checks against 22 years of published crescent-sighting records.

On top of the calendar, I built Python observability tooling so the team gets real-time visibility into application health and faster fault detection.

What I learned

Correctness has to be designed in, not tested in afterward. Building the validation suite alongside the ephemeris code — with authoritative references as the oracle — is what made it safe to trust the calendar for something people actually rely on.