chore: P1 consolidation (TypeDoc API + wiki refresh)

This commit is contained in:
Aric Camarata 2026-05-30 18:40:31 -04:00
parent 76a2ea8a96
commit 05b4f577d0
7 changed files with 122 additions and 2 deletions

View file

@ -5,6 +5,20 @@
**Reference**
- [API Reference](API-Reference)
- [Architecture](Architecture)
- [Bundle Size / Performance](benchmarks/index)
**Per-Function API**
- [getTimes](api/getTimes)
- [calcTimes](api/calcTimes)
- [getTimesAll / METHODS](api/getTimesAll)
- [calcTimesAll](api/calcTimesAll)
- [getAngles](api/getAngles)
- [getAsr](api/getAsr)
- [getQiyam](api/getQiyam)
- [getMidnight](api/getMidnight)
- [getMscFajr / getMscIsha](api/getMscFajr-getMscIsha)
- [solarEphemeris / toJulianDate](api/solarEphemeris)
- [Constants](api/ANGLE_MIN-ANGLE_MAX)
**Algorithm**
- [Dynamic Algorithm](Dynamic-Algorithm)

52
.github/wiki/benchmarks/index.md vendored Normal file
View file

@ -0,0 +1,52 @@
# Bundle Size and Performance
## Bundle size
Measured with tsup production build (Node 22, pnpm 9).
| Package | Format | Raw | Min+gz |
|---|---|---|---|
| pray-calc | ESM (.mjs) | 84 KB | ~22 KB |
| pray-calc | CJS (.cjs) | 86 KB | ~22 KB |
| nrel-spa (dependency) | ESM | 51 KB | ~13 KB |
| pray-calc wrapper only (excl. nrel-spa) | ESM | ~33 KB | ~9 KB |
The bulk of pray-calc's own weight comes from the MCW seasonal coefficient tables and the ephemeris formulas. The single runtime dependency is [nrel-spa](https://github.com/acamarata/nrel-spa).
## Comparison with nrel-spa baseline
| Library | Bundle (min+gz) | Prayer times | Traditional methods | Dynamic angles |
|---|---|---|---|---|
| nrel-spa alone | ~13 KB | No (solar position only) | No | No |
| pray-calc | ~22 KB | Yes (9 times + angles) | 14 methods | Yes |
| Overhead for prayer times | +~9 KB | 9 prayer times | 14 methods | Physics-based angles |
The ~9 KB prayer-time layer delivers: dynamic twilight angles, 14 traditional fixed-angle method comparisons, Asr in both Shafi'i and Hanafi conventions, Qiyam al-Layl, Islamic midnight, and MCW direct access functions.
## Performance
Measured on Apple M2 Pro (single core), Node 22.
| Operation | Time (single call) | Notes |
|---|---|---|
| `calcTimes` | ~0.9 ms | 1 SPA call, dynamic angles |
| `calcTimesAll` | ~1.1 ms | 1 SPA call, 30 zenith angles |
| `getAngles` alone | ~0.05 ms | No SPA, Meeus ephemeris only |
| `getMscFajr` / `getMscIsha` | <0.01 ms | Arithmetic only |
`calcTimesAll` computes all 14 method comparisons in a single SPA call by passing all 30 zenith angles at once. It is not 14 times slower than `calcTimes`.
## Tree-shaking
All exports are individually tree-shakeable. If you only import `calcTimes`, a bundler excludes the `getTimesAll` / `calcTimesAll` batch machinery and the 14-method METHODS table.
```javascript
// Only calcTimes and its dependencies are included
import { calcTimes } from 'pray-calc';
```
## Accuracy versus performance tradeoff
The `solarEphemeris` function (Meeus Ch. 25) runs in under 0.1 ms and is used only for the angle correction layer. The full SPA computation (via nrel-spa) handles the precise prayer time solving. This split keeps the dynamic angle overhead small while maintaining the high accuracy of NREL SPA for the actual time results.
For batch computation across many dates or locations, `getAngles` can be cached at the date grain: solar position changes slowly, and the angles for a given latitude and date are stable within ±0.1° across a full year range.

View file

@ -3,6 +3,7 @@
[![npm version](https://img.shields.io/npm/v/pray-calc)](https://www.npmjs.com/package/pray-calc)
[![CI](https://github.com/acamarata/pray-calc/actions/workflows/ci.yml/badge.svg)](https://github.com/acamarata/pray-calc/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Wiki](https://img.shields.io/badge/docs-wiki-blue)](https://github.com/acamarata/pray-calc/wiki)
Islamic prayer times for any location and date. The primary method uses a physics-grounded dynamic twilight angle algorithm that adjusts Fajr and Isha angles for latitude, season, Earth-Sun distance, and atmospheric conditions. Fourteen traditional fixed-angle methods are included for comparison. Single runtime dependency: [nrel-spa](https://github.com/acamarata/nrel-spa).

View file

@ -12,8 +12,20 @@ import type { FormattedPrayerTimes } from './types.js';
* Uses the dynamic twilight angle algorithm. See getTimes() for full parameter
* documentation.
*
* @param date - Observer's local date
* @param lat - Latitude in decimal degrees (-90 to 90)
* @param lng - Longitude in decimal degrees (-180 to 180)
* @param tz - UTC offset in hours (default: system timezone)
* @param elevation - Elevation in meters (default: 0)
* @param temperature - Temperature in Celsius (default: 15)
* @param pressure - Pressure in mbar/hPa (default: 1013.25)
* @param hanafi - Hanafi Asr convention (default: false)
* @returns Prayer times as HH:MM:SS strings. Returns "N/A" for any time that
* cannot be computed (polar night, unreachable angle, etc.).
* @example
* const times = calcTimes(new Date('2024-06-21'), 40.7128, -74.006, -4);
* console.log(times.Fajr); // "03:51:24"
* console.log(times.Maghrib); // "20:31:17"
*/
export function calcTimes(
date: Date,

View file

@ -13,8 +13,19 @@ import type { FormattedPrayerTimesAll } from './types.js';
* Uses the dynamic twilight angle algorithm for the primary times. See
* getTimesAll() for full parameter documentation.
*
* @param date - Observer's local date
* @param lat - Latitude in decimal degrees (-90 to 90)
* @param lng - Longitude in decimal degrees (-180 to 180)
* @param tz - UTC offset in hours (default: system timezone)
* @param elevation - Elevation in meters (default: 0)
* @param temperature - Temperature in Celsius (default: 15)
* @param pressure - Pressure in mbar/hPa (default: 1013.25)
* @param hanafi - Hanafi Asr convention (default: false)
* @returns All prayer times as HH:MM:SS strings. "N/A" for unreachable events.
* Methods map contains [fajrString, ishaString] per method.
* @example
* const result = calcTimesAll(new Date('2024-06-21'), 40.7128, -74.006, -4);
* console.log(result.dynamic.Fajr); // "03:51:24"
* console.log(result.ISNA.Fajr); // "04:07:30"
*/
export function calcTimesAll(
date: Date,

View file

@ -92,6 +92,13 @@ function interpolateSegment(
*
* Returns minutes before sunrise. At latitudes above 55°, the 1/7-night
* approximation is recommended (handled at the calling site).
*
* @param date - Observer's local date
* @param latitude - Observer latitude in decimal degrees
* @returns Minutes before sunrise for Fajr (Subh Sadiq)
* @example
* const offset = getMscFajr(new Date('2024-06-21'), 40.7128);
* // offset ≈ 93 (minutes before sunrise for New York in summer)
*/
export function getMscFajr(date: Date, latitude: number): number {
const latAbs = Math.abs(latitude);
@ -114,6 +121,14 @@ export function getMscFajr(date: Date, latitude: number): number {
* - 'general': blend that reduces hardship at high latitudes (default)
* - 'ahmer': based on disappearance of redness (shafaq ahmer)
* - 'abyad': based on disappearance of whiteness (shafaq abyad), later
*
* @param date - Observer's local date
* @param latitude - Observer latitude in decimal degrees
* @param shafaq - Twilight type: 'general' | 'ahmer' | 'abyad'
* @returns Minutes after sunset for Isha
* @example
* const offset = getMscIsha(new Date('2024-06-21'), 40.7128, 'general');
* // offset ≈ 84
*/
export function getMscIsha(date: Date, latitude: number, shafaq: ShafaqMode = 'general'): number {
const latAbs = Math.abs(latitude);

View file

@ -10,7 +10,15 @@
import { DEG } from './constants.js';
/** Julian Date from a JavaScript Date (UTC). */
/**
* Convert a JavaScript Date to a Julian Date number.
*
* @param date - Any JavaScript Date object (uses UTC internally)
* @returns Julian Date: days since noon January 1, 4713 BC UTC
* @example
* const jd = toJulianDate(new Date('2024-06-21'));
* // jd ≈ 2460482.5
*/
export function toJulianDate(date: Date): number {
return date.getTime() / 86400000 + 2440587.5;
}
@ -27,6 +35,13 @@ export interface SolarEphemeris {
/**
* Compute solar declination, Earth-Sun distance, and ecliptic longitude
* from a Julian Date. Accuracy: ~0.01° for declination, ~0.0001 AU for r.
*
* @param jd - Julian Date (use toJulianDate to convert a JS Date)
* @returns Solar ephemeris data: declination (degrees), Earth-Sun distance (AU),
* and ecliptic longitude (radians, 0-2π season phase)
* @example
* const jd = toJulianDate(new Date('2024-06-21'));
* const { decl, r, eclLon } = solarEphemeris(jd);
*/
export function solarEphemeris(jd: number): SolarEphemeris {
const T = (jd - 2451545.0) / 36525.0;