miqāt (ميقات) — Arabic: "an appointed time." The word names the boundaries between prayers, the seasons of the hajj, the moment a shadow equals its height.
A serene, local-first desktop app for prayer times, Qibla, Hijri calendar, and Athan playback. Works offline. Ships at miqaaat.com.
| Feature | Details |
|---|---|
| Prayer times | Fajr, Sunrise, Dhuhr, Asr, Maghrib, Isha · 12/24h · live countdown |
| Offline-first | Computed locally with adhan, synced with Aladhan when online |
| Location | Geolocation + worldwide city search (Nominatim) · saved locations |
| Athan player | Four reciters (Makkah/Madina/Al-Aqsa/Egypt), Dua after Athan, volume, progress |
| Calculation | All Aladhan methods · Shafi / Maliki / Hanbali / Hanafi madhab |
| Hijri | Umm al-Qura via Intl (offline) · converter |
| Qibla | Bearing arrow + MapLibre map with line to Makkah |
| Themes | Miqāt (default) · Light · Dark · Paper |
| Notifications | Per-prayer toggles · 0/5/10/15/30 min pre-alerts · auto-launch on login |
| Kinetic identity | Wordmark rotates with the Sundial Mark and becomes the Held Note during Athan playback |
| Desktop | Tray, always-on-top widget (?mode=widget), auto-updater, ZIP build |
| i18n | English · Français · العربية (with RTL) |
Three faces, one state machine:
| State | Mark |
|---|---|
| Idle | miqāt wordmark — the macron over the ā is the horizon |
| Rotation | Sundial Mark — a dot on an arc, positioned by current time within today's Fajr→Isha window |
| Athan playing | Held Note — animated waveform that decays into stillness |
See docs/brand.md for the full system, palette, and typography.
┌────────────── Electron (main.ts) ──────────────┐
│ port-scan · DB path · resolve-shim · tray │
│ auto-updater · IPC · widget window │
│ │ │
│ ▼ in-process require() │
│ ┌───────────────┐ │
│ │ NestJS │ HTTP :3001 │
│ │ SQLite (WAL) │ CORS locked │
│ └───────────────┘ │
│ │ │
│ ▼ window.__API_URL__ │
│ ┌───────────────────────────────┐ │
│ │ React 18 + Vite + shadcn/ui │ │
│ │ TanStack Query · TickContext │ │
│ │ Miqāt theme + Instrument Serif │ │
│ └───────────────────────────────┘ │
└────────────────────────────────────────────────┘
npm install
npm run dev # NestJS :3001 + Vite :5173 + Electron
npm run fetch:audio # download Athan MP3s to client/public/audio/
npm test # offline tests (14)
npm run test:online # adds 250-case Aladhan parity sweep
npm run package # ZIP build via electron-builderSee docs/getting-started.md for setup, docs/desktop-builds.md for packaging, docs/auto-updater.md for release workflow.
- Backend: NestJS 10 · SQLite (
better-sqlite3, raw SQL) · adhan 4 · axios · luxon - Frontend: React 18 · Vite 6 · TanStack Query 5 · Tailwind CSS 4 · shadcn/ui · MapLibre GL · lucide-react · zustand
- Desktop: Electron 34 · electron-builder (ZIP) · electron-updater
Issues, PRs, and translation contributions all welcome. The codebase intentionally stays small and readable — please match the existing style (TypeScript strict, Tailwind 4, raw SQL with prepared statements on the server side).
If you're translating: most user-facing strings live in
client/src/i18n/dict.ts. Add your locale
alongside en/fr/ar and open a PR.
- Pair-programmed with Claude (Anthropic) throughout design, implementation, and review.
- Prayer-time computation:
adhan - Online verification: Aladhan API
- Geocoding: OpenStreetMap Nominatim
- IP geolocation: ipapi.co
- Map tiles: OpenStreetMap
- Fonts: Instrument Serif, Inter, JetBrains Mono, Caveat, Amiri (all via Fontsource)
- Brand + product direction: Develop Better Solutions