All work
Extension

Islamic Companion

An Islamic Chrome extension that displays the Hijri date, prayer times and Quranic verses right inside your browser.

What makes it good

  • 1Shows the Hijri (Islamic) date
  • 2Daily prayer times at a glance
  • 3Rotating Quranic verses

How it works

How it works

Prayer times come from the Aladhan API, resolved either from coordinates or from a city or country name. Results are cached per day and location, so opening the popup repeatedly costs nothing.

The timezone problem

This is the detail that quietly breaks most prayer-time extensions. The API returns times in the location's timezone — "05:10" for Cairo. Feeding that to Date.setHours() interprets it in the browser's timezone, so a traveller, a VPN user, or anyone tracking a city they are not in gets alarms off by the difference between the two.

Comparing minutes-since-midnight *inside* the target zone sidesteps the conversion entirely — the gap between two wall-clock readings in the same zone is the same number of real minutes anywhere on earth:

js
export function minutesUntil(hhmm, timeZone) {
  const [h, m] = hhmm.split(':').map(Number);

  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone, hour12: false, hour: '2-digit', minute: '2-digit',
  }).formatToParts(new Date());

  const get = (t) => Number(parts.find((p) => p.type === t)?.value);
  const now = (get('hour') % 24) * 60 + get('minute');

  let delta = h * 60 + m - now;
  if (delta < 0) delta += 1440; // already passed today → tomorrow
  return delta;
}

Alarms that survive the day

A service worker is not a running process; it is woken by events. Scheduling every prayer once at install means the alarms expire after a single day and never come back. Instead a daily alarm just after midnight recomputes the schedule, and each prayer alarm re-arms itself for the next occurrence as soon as it fires.

js
chrome.alarms.create('dailyRefresh', { when: nextMidnight, periodInMinutes: 1440 });

// after a prayer alarm fires, schedule the next one
const delay = minutesUntil(timings[prayer], timezone);
chrome.alarms.create(alarm.name, { delayInMinutes: Math.max(delay, 1) });

Qibla

The direction to the Kaaba is a great-circle initial bearing, not a heading off a flat map. The difference is not academic — from Jakarta or the Americas a flat bearing is wrong by tens of degrees.

js
export function qiblaBearing(lat, lng) {
  const phi1 = toRad(lat), phi2 = toRad(KAABA.lat);
  const dLambda = toRad(KAABA.lng - lng);

  const y = Math.sin(dLambda);
  const x = Math.cos(phi1) * Math.tan(phi2)
          - Math.sin(phi1) * Math.cos(dLambda);

  return (toDeg(Math.atan2(y, x)) + 360) % 360;
}

Checked against published bearings for seven cities across the globe, all within one degree: Cairo 136.8°, Riyadh 244.5°, Jakarta 295.1°, London 119.2°, New York 58.6°, Istanbul 152.1°, Cape Town 23.2°.

The rest

A tasbih counter with a ring that fills toward each dhikr's traditional target, a prayer tracker with a streak that does not count an unfinished today as a failure, the Hijri date with a ±2 day adjustment for local moon sighting, and a toolbar badge counting down to the next prayer — because the popup is closed almost all of the time.