panchang-ts 3.1.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  Pure TypeScript Hindu Panchang (almanac), Jyotish, and Birth Chart calculations.
6
6
  Zero native dependencies. Works offline in React Native (Hermes), Node.js, and browsers.
7
7
 
8
- **Fast** (~0.1 ms names-only, ~0.5 ms full) | **Typed** (full TypeScript types) | **Offline** (pure JS math, no network) | **7,156 tests**
8
+ **Fast** (~0.1 ms names-only, ~0.5 ms full) · **Typed** (full TypeScript) · **Offline** (pure JS math) · **8,103 tests across 96 files**
9
9
 
10
10
  ---
11
11
 
@@ -13,51 +13,11 @@ Zero native dependencies. Works offline in React Native (Hermes), Node.js, and b
13
13
 
14
14
  ```bash
15
15
  npm install panchang-ts
16
- # or
17
- pnpm add panchang-ts
18
- # or
19
- yarn add panchang-ts
16
+ # or: pnpm add panchang-ts / yarn add panchang-ts
20
17
  ```
21
18
 
22
19
  ---
23
20
 
24
- ## Features at a Glance
25
-
26
- Every category below is implemented end-to-end, cross-verified against reference panchang
27
- sources, and exposed through the public API. Click a row to jump to its usage example.
28
-
29
- | Category | Features | Jump to |
30
- |----------|----------|---------|
31
- | **Pancha Anga (5 limbs)** | Tithi, Nakshatra, Yoga, Karana, Vara — with all transitions through the day | [↓](#1-pancha-anga--the-five-limbs) |
32
- | **Lunar Calendar** | Chandra Masa (Purnimanta + Amanta), Adhika (leap-month) detection, Vikram Samvat, Shaka Samvat | [↓](#2-lunar-calendar) |
33
- | **Solar Calendar** | Saura Masa, Surya Nakshatra, Sankranti (transit-based) | [↓](#3-solar-calendar) |
34
- | **Sun & Moon** | Sunrise, Sunset, Moonrise, Moonset, Chandra Rashi (Moon sign) | [↓](#4-sun--moon) |
35
- | **Auspicious Muhurta** | Brahma, Abhijit, Vijaya, Godhuli, Nishita, Madhyahna, Pratah / Sayahna Sandhya, Amrit Kala | [↓](#5-auspicious-muhurta) |
36
- | **Inauspicious Periods** | Rahu Kalam, Gulika Kalam, Yamaganda, Dur Muhurta, Varjyam, Ganda Mula, Bhadra Kala, Panchaka | [↓](#6-inauspicious-periods) |
37
- | **Time-Slot Systems** | Choghadiya (16), Gowri Panchangam / Nalla Neram (16), Hora (24), Do Ghati (30), Panchaka Rahita | [↓](#7-time-slot-systems) |
38
- | **Special Yogas** | Anandadi (28-name cycle), Amrit Siddhi, Sarvartha Siddhi, Ravi / Guru Pushya, Dwipushkar, Tripushkar, Jwalamukhi, Aadal, Vidaal, Ravi | [↓](#8-special-yogas) |
39
- | **Festivals (80+)** | Ekadashi (Smarta + Vaishnava split), Pradosha, Sankranti variants, classical festivals (Diwali, Holi, Shivaratri…), regional festivals across 21 states + Nepal | [↓](#9-festivals) |
40
- | **Eclipses (Grahan)** | Solar + lunar detection, subtype, magnitude, observer-horizon visibility, sutak window | [↓](#10-eclipses) |
41
- | **Planetary Positions** | All 9 grahas (sidereal) with rashi, nakshatra, pada, retrograde — mean or true Rahu/Ketu | [↓](#11-planetary-positions) |
42
- | **Vimshottari Dasha** | Maha → Antar → Pratyantar (3-level) breakdown from birth | [↓](#12-vimshottari-dasha) |
43
- | **Personal Transits** | Chandra Balam, Tarabala (9-tara cycle), Sade Sati (Saturn arc) | [↓](#13-personal-transits) |
44
- | **Birth Chart (Kundli)** | Lagna (sidereal), Bhava under 3 house systems, D1 / D2 / D3 / D7 / D9 / D10 / D12 / D30 charts, Planetary Dignity | [↓](#14-birth-chart-kundli) |
45
- | **Compatibility & Doshas** | Ashtakoot Guna Milan (36-point), Mangal Dosha, Kaal Sarp Dosha (12 subtypes), Pitru Dosha | [↓](#15-compatibility--doshas) |
46
- | **Aspects & Strength** | Drishti (graha aspects), Shadbala (six-fold strength) | [↓](#16-aspects--strength) |
47
- | **Dasha Systems** | Vimshottari (Maha→Antar→Pratyantar), Ashtottari, Yogini, Chara (Jaimini) | [↓](#17-dasha-systems) |
48
- | **Muhurta Engine** | Configurable scoring + 13 stock occasions (vivah, griha pravesh, namakarana, …) | [↓](#18-muhurta-engine) |
49
- | **Calendar Conversion** | Gregorian↔Hindu, Kali Yuga year, Hindu New Year, yearly Ekadashi / Sankranti / festival listings | [↓](#19-calendar-conversion) |
50
- | **Localization** | English + Hindi (Devanagari) on every returned name | [↓](#20-localization) |
51
- | **Configuration** | 5 ayanamsas (Lahiri, Raman, KP, True Chitrapaksha, Thirukanitham), 2 masa systems, 3 house systems, 21 regional festival scopes | [↓](#21-configuration) |
52
-
53
- ---
54
-
55
- ## Used By
56
-
57
- - [dharmagya.app](https://dharmagya.app) — Daily Panchang and Hindu calendar
58
-
59
- ---
60
-
61
21
  ## Quick Start
62
22
 
63
23
  ```typescript
@@ -68,222 +28,172 @@ const result = getDailyPanchang(
68
28
  { latitude: 23.1765, longitude: 75.7885 }, // Ujjain, India
69
29
  { timezone: 330 }, // IST = UTC+5:30 = 330 minutes
70
30
  );
71
- // result is `DailyPanchangResult | null` null only at polar latitudes
72
- // where sunrise can't be computed. Anywhere else, narrow with `if (!result) return;`
73
-
74
- console.log(result.tithis[0].name); // "Krishna Chaturdashi"
75
- console.log(result.nakshatras[0].name); // "Mrigashira"
76
- console.log(result.vara.name); // "Mangalawara"
77
- console.log(result.chandramasa.name); // "Magha"
78
- console.log(result.samvat.vikramSamvat); // 2081
31
+ // DailyPanchangResult | null. Null only at polar latitudes where
32
+ // sunrise can't be computed. Anywhere else, narrow with `if (!result) return;`.
33
+
34
+ console.log(result!.tithis[0].name); // "Krishna Chaturdashi"
35
+ console.log(result!.nakshatras[0].name); // "Mrigashira"
36
+ console.log(result!.vara.name); // "Mangalawara"
37
+ console.log(result!.chandramasa.name); // "Magha"
38
+ console.log(result!.samvat.vikramSamvat); // 2081
79
39
  ```
80
40
 
81
41
  ### Reading Output Times
82
42
 
83
- All `Date` objects in the result are **offset-adjusted** to the requested timezone. Always
84
- read time components via `getUTC*` methods — `.getHours()` would use your system zone:
43
+ All `Date` objects are **offset-adjusted** to the requested timezone. Read time
44
+ components via `getUTC*` — `.getHours()` would use your system zone:
85
45
 
86
46
  ```typescript
87
- const sunrise = result.sunrise;
47
+ const sunrise = result!.sunrise;
88
48
  const h = sunrise.getUTCHours(); // 7
89
- const m = sunrise.getUTCMinutes(); // 4
90
- // → Sunrise at 07:04 local time
91
-
92
- function fmt(d: Date) {
93
- const h = d.getUTCHours(), m = d.getUTCMinutes();
94
- return `${h}:${String(m).padStart(2, '0')}`;
95
- }
96
- fmt(result.rahuKalam.start); // "09:04"
49
+ const m = sunrise.getUTCMinutes(); // 4 → 07:04 local time
97
50
  ```
98
51
 
99
- `moonrise` and `moonset` can be `null` — the Moon occasionally does not rise or set on a
100
- given calendar day, which is normal.
52
+ `moonrise` / `moonset` can be `null` — the Moon occasionally does not rise or
53
+ set on a given calendar day, which is normal.
101
54
 
102
55
  ### `getDailyPanchang` vs `getInstantPanchang`
103
56
 
104
- | Use case | Recommended | Why |
105
- |----------|-------------|-----|
106
- | "What Panchang elements are active right now?" | `getInstantPanchang` | Single-moment snapshot; no sunrise needed |
107
- | Birth chart / muhurta picking at a specific instant | `getInstantPanchang` | Exact element at that UTC moment |
108
- | Daily calendar / almanac row for a date | `getDailyPanchang` | Lists all element transitions for the day |
109
- | Today's festivals & observances | `getDailyPanchang` | Full canonical-time festival refinement |
110
- | Rahu Kalam / Choghadiya / Gowri / Hora / muhurtas | `getDailyPanchang` | Computed from sunrise, sunset, day length |
111
- | Eclipse detection with sutak window | `getDailyPanchang` | Overlapping the day needs the day window |
112
-
113
- `getInstantPanchang` does emit `festivals`, but evaluates rules against the elements at the
114
- given instant only. It does not run canonical-time refinements (madhyahna / pradosha /
115
- nishita / chandrodaya), transit-based Sankranti, Ekadashi viddha (Smarta/Vaishnava split),
116
- or Bhadra-aware Raksha Bandhan exclusion. For reliable festival dating, use
117
- `getDailyPanchang`.
57
+ | Use case | Use |
58
+ |---|---|
59
+ | Daily calendar, festivals, muhurtas, time-slots (Choghadiya/Hora/Gowri), eclipses with sutak | `getDailyPanchang` |
60
+ | Single-moment snapshot ("what's active right now?") or birth-chart casting | `getInstantPanchang` |
118
61
 
119
- ---
62
+ `getInstantPanchang` emits a `festivals` field but only checks rule predicates
63
+ at the given instant — it skips canonical-time refinements (madhyahna /
64
+ pradosha / nishita / chandrodaya), transit-based Sankranti, and Smarta/Vaishnava
65
+ Ekadashi split. For reliable festival dating, use `getDailyPanchang`.
120
66
 
121
- # Feature Reference
67
+ ---
122
68
 
123
- Each section below shows how to access one feature category. Every feature is also
124
- returned as a field on the unified `DailyPanchangResult` from `getDailyPanchang(…)` if you
125
- prefer one call over the per-feature helpers.
69
+ ## Features at a Glance
126
70
 
127
- ## 1. Pancha Anga — the Five Limbs
71
+ | Category | Features |
72
+ |---|---|
73
+ | **Pancha Anga** | Tithi, Nakshatra, Yoga, Karana, Vara — with all intra-day transitions |
74
+ | **Lunar Calendar** | Chandra Masa (Purnimanta + Amanta), Adhika (leap) detection, Vikram + Shaka Samvat |
75
+ | **Solar Calendar** | Saura Masa, Surya Nakshatra, Sankranti (transit-based) |
76
+ | **Sun & Moon** | Sunrise, Sunset, Moonrise, Moonset (Meeus apparent-upper-limb), Chandra Rashi |
77
+ | **Auspicious Muhurta** | Brahma, Abhijit, Vijaya, Godhuli, Nishita, Madhyahna, Pratah/Sayahna Sandhya, Amrit Kala |
78
+ | **Inauspicious Periods** | Rahu Kalam, Gulika Kalam, Yamaganda, Dur Muhurta, Varjyam, Ganda Mula, Bhadra Kala, Panchaka |
79
+ | **Time-Slot Systems** | Choghadiya, Gowri Panchangam (Tamil "Nalla Neram"), Hora, Do Ghati, Panchaka Rahita |
80
+ | **Special Yogas** | Anandadi (28-cycle), Amrit Siddhi, Sarvartha Siddhi, Ravi/Guru Pushya, Dwi-/Tripushkar, Jwalamukhi, Aadal, Vidaal, Ravi |
81
+ | **Festivals (80+)** | Ekadashi (Smarta/Vaishnava split), Pradosha, Sankranti, classical (Diwali/Holi/Shivaratri…), regional across 21 states + Nepal |
82
+ | **Eclipses** | Solar/lunar detection, subtype, magnitude, horizon visibility, sutak window |
83
+ | **Planetary Positions** | All 9 grahas (sidereal) with rashi, nakshatra, pada, retrograde — mean or true Rahu/Ketu |
84
+ | **Dashas** | Vimshottari (3-level), Ashtottari, Yogini, Chara, Narayan |
85
+ | **Personal Transits** | Chandra Balam, Tarabala (9-cycle), Sade Sati |
86
+ | **Birth Chart** | Lagna, Bhava under 3 house systems, D1/D2/D3/D7/D9/D10/D12/D30, Planetary Dignity |
87
+ | **Compatibility & Doshas** | Ashtakoot (36-point), Pathu Porutham (Tamil 10-fold), Mangal, Kaal Sarp (12 subtypes), Pitru |
88
+ | **Strength & Aspects** | Drishti, Shadbala (6-fold), Ashtakavarga (Bhinna + Sarva, with reductions), Bhava Bala, Argala |
89
+ | **Yogas & Karakas** | 25 named yogas (with cancellations), 7- and 8-Karaka Jaimini |
90
+ | **Annual & Sensitive** | Varshaphala (Tajik + 27 Sahams), Tithi Pravesha, Arudha padas, Hora/Ghati/Bhava/Sripati lagnas, Upagrahas |
91
+ | **KP & Prashna** | KP sub-lord at any longitude, Placidus-KP cuspal sub-lords, KP significators, Prashna chart |
92
+ | **Muhurta Engine** | Configurable scoring + 13 stock occasions (vivah, griha pravesh, namakarana, …) |
93
+ | **Calendar Conversion** | Gregorian↔Hindu, Kali Yuga year, Hindu New Year, yearly Ekadashi/Sankranti/festival listings |
94
+ | **Localization** | English + Hindi (Devanagari) |
95
+ | **Configuration** | 5 ayanamsas (Lahiri, Raman, KP, True Chitrapaksha, Thirukanitham), 2 masa systems, 3 house systems |
128
96
 
129
- Tithi, Nakshatra, Yoga, Karana, Vara — with start / end times for every transition during
130
- the Hindu day.
97
+ ---
131
98
 
132
- ```typescript
133
- import { getDailyPanchang } from 'panchang-ts';
99
+ ## Used By
134
100
 
135
- const r = getDailyPanchang(date, location, { timezone: 330 })!;
101
+ - [dharmagya.app](https://dharmagya.app) Daily Panchang and Hindu calendar ([Play Store](https://play.google.com/store/apps/details?id=com.ishank1995.dharmagya))
136
102
 
137
- // Tithis active during the day (usually 1-2)
138
- r.tithis.forEach(t => {
139
- console.log(t.name, t.paksha, t.completionPercentage, t.endTime);
140
- });
103
+ ---
141
104
 
142
- // Nakshatras (with pada)
143
- r.nakshatras.forEach(n => console.log(n.name, n.pada, n.endTime));
105
+ # Feature Reference
144
106
 
145
- // Yogas (27-name lunisolar cycle)
146
- r.yogas.forEach(y => console.log(y.name, y.endTime));
107
+ Each daily field is also returned from `getDailyPanchang` if you prefer one call
108
+ over per-feature helpers.
147
109
 
148
- // Karanas (half-tithi; usually 2-4 per day)
149
- r.karanas.forEach(k => console.log(k.name, k.type, k.endTime));
110
+ ## Pancha Anga
150
111
 
151
- // Vara (weekday)
152
- console.log(r.vara.name, r.vara.englishName); // "Mangalawara", "Tuesday"
153
- ```
112
+ ```typescript
113
+ const r = getDailyPanchang(date, location, { timezone: 330 })!;
154
114
 
155
- For a single-instant snapshot use `getInstantPanchang`:
115
+ r.tithis.forEach(t => console.log(t.name, t.paksha, t.completionPercentage, t.endTime));
116
+ r.nakshatras.forEach(n => console.log(n.name, n.pada, n.endTime));
117
+ r.yogas.forEach(y => console.log(y.name, y.endTime));
118
+ r.karanas.forEach(k => console.log(k.name, k.type, k.endTime));
119
+ console.log(r.vara.name, r.vara.englishName); // "Mangalawara", "Tuesday"
156
120
 
157
- ```typescript
121
+ // Single-instant snapshot:
158
122
  import { getInstantPanchang } from 'panchang-ts';
159
-
160
123
  const i = getInstantPanchang(new Date(), location)!;
161
124
  console.log(i.tithi.name, i.nakshatra.name, i.yoga.name, i.karana.name, i.vara.name);
162
125
  ```
163
126
 
164
- ## 2. Lunar Calendar
165
-
166
- Chandra Masa with **Purnimanta** (North Indian, default) and **Amanta** (South Indian)
167
- naming, **Adhika** (leap-month) detection, **Vikram** and **Shaka** samvat year numbers.
127
+ ## Lunar & Solar Calendar
168
128
 
169
129
  ```typescript
170
130
  const r = getDailyPanchang(date, loc, { timezone: 330, masaSystem: 'purnimanta' })!;
171
131
 
172
- console.log(r.chandramasa.name); // "Magha" (active system)
173
- console.log(r.chandramasa.amantaName); // "Pausha" (South Indian)
174
- console.log(r.chandramasa.purnimantaName); // "Magha" (North Indian)
175
- console.log(r.chandramasa.isAdhika); // false (true during leap months)
132
+ r.chandramasa.name; // active system (default: Purnimanta / North Indian)
133
+ r.chandramasa.amantaName; // South Indian
134
+ r.chandramasa.purnimantaName; // North Indian
135
+ r.chandramasa.isAdhika; // true during leap months
136
+ r.samvat.vikramSamvat; // 2081
137
+ r.samvat.shakaSamvat; // 1946
176
138
 
177
- console.log(r.samvat.vikramSamvat); // 2081
178
- console.log(r.samvat.shakaSamvat); // 1946
139
+ r.masa.name; // current solar month (Mesha … Meena)
140
+ r.suryaNakshatra.name; // Sun's nakshatra
141
+ r.chandraRashi.name; // Moon sign
179
142
  ```
180
143
 
181
- ## 3. Solar Calendar
182
-
183
- Saura Masa (solar month), Surya Nakshatra (the Sun's nakshatra, ~13–14 day transit),
184
- Sankranti (solar-month boundary, transit-based — emitted as a festival).
185
-
186
- ```typescript
187
- const r = getDailyPanchang(date, loc, { timezone: 330 })!;
188
-
189
- console.log(r.masa.name); // "Makara" (current solar month)
190
- console.log(r.suryaNakshatra.name); // "Uttara Ashadha"
191
- console.log(r.chandraRashi.name); // "Mithuna" (Moon sign)
192
-
193
- // Sankranti and its regional variants emit through r.festivals — see §9.
194
- ```
195
-
196
- ## 4. Sun & Moon
197
-
198
- Sunrise, sunset, moonrise, moonset (Meeus apparent-upper-limb), plus Chandra Rashi
199
- (Moon's zodiac sign).
144
+ ## Sun, Moon & Muhurta
200
145
 
201
146
  ```typescript
202
147
  import { getSunrise, getSunset, getMoonrise, getMoonset } from 'panchang-ts';
203
148
 
204
- const loc = { latitude: 28.6139, longitude: 77.2090 }; // New Delhi
205
-
206
- const sunrise = getSunrise(localMidnightUtc, loc);
207
- const sunset = getSunset(sunrise, loc);
208
-
209
- // Moonrise / moonset can be null on days the Moon doesn't rise/set
210
- const moonrise = getMoonrise(localMidnightUtc, loc);
149
+ const sunrise = getSunrise(localMidnightUtc, loc);
150
+ const sunset = getSunset(sunrise, loc);
151
+ const moonrise = getMoonrise(localMidnightUtc, loc); // null on some days (normal)
211
152
  const moonset = getMoonset(localMidnightUtc, loc);
212
153
 
213
- // Or read all of them off the daily result:
214
- const r = getDailyPanchang(date, loc, { timezone: 330 })!;
215
- console.log(r.sunrise, r.sunset, r.moonrise, r.moonset, r.nextSunrise);
216
- console.log(r.dayDurationMinutes, r.nightDurationMinutes);
217
- ```
218
-
219
- ## 5. Auspicious Muhurta
220
-
221
- Classical auspicious time windows: Brahma, Abhijit, Vijaya, Godhuli, Nishita, Madhyahna,
222
- Pratah / Sayahna Sandhya, and nakshatra-keyed Amrit Kala.
223
-
224
- ```typescript
154
+ // Or read off the daily result:
225
155
  const r = getDailyPanchang(date, loc, { timezone: 330 })!;
156
+ r.sunrise; r.sunset; r.moonrise; r.moonset; r.nextSunrise;
157
+ r.dayDurationMinutes; r.nightDurationMinutes;
226
158
 
159
+ // Auspicious muhurtas
227
160
  r.brahmaMuhurta; // two muhurtas before sunrise
228
- r.abhijitMuhurta; // 8th day-muhurta universally auspicious
229
- r.vijayaMuhurta; // 11th day-muhurta — auspicious for success
230
- r.godhuliMuhurta; // "cow-dust" sunset muhurta
161
+ r.abhijitMuhurta; // 8th day-muhurta; null on Wednesday (Drik convention)
162
+ r.vijayaMuhurta; // 11th day-muhurta
163
+ r.godhuliMuhurta; // "cow-dust" sunset muhurta
231
164
  r.nishitaMuhurta; // midnight muhurta (Shivaratri)
232
165
  r.madhyahna; // solar noon ±24 min
233
- r.pratahSandhya; // dawn twilight, ends *at* sunrise
234
- r.sayahnaSandhya; // dusk twilight, starts *at* sunset
166
+ r.pratahSandhya; // dawn twilight, ends at sunrise
167
+ r.sayahnaSandhya; // dusk twilight, starts at sunset
235
168
  r.amritKala; // nakshatra-specific window (null when nakshatra has none)
236
-
237
- // Direct helpers:
238
- import {
239
- computeBrahmaMuhurta, computeAbhijitMuhurta, computeVijayaMuhurta,
240
- computeGodhuliMuhurta, computeNishitaMuhurta, computeMadhyahna,
241
- computePratahSandhya, computeSayahnaSandhya, computeAmritKala,
242
- } from 'panchang-ts';
243
169
  ```
244
170
 
245
- `pratahSandhya` and `sayahnaSandhya` are asymmetric — width = `nightDuration / 10`
246
- (~62–81 min depending on season), matching DrikPanchang within ±2 min.
247
-
248
- ## 6. Inauspicious Periods
171
+ `pratahSandhya` / `sayahnaSandhya` width = `nightDuration / 10` (~62–81 min).
249
172
 
250
- Rahu Kalam, Gulika Kalam, Yamaganda, Dur Muhurta (2 windows), Varjyam (BPHS-keyed
251
- ~96-min forbidden window), Ganda Mula (Moon in root nakshatras), Bhadra Kala (Vishti
252
- karana with earth/heaven/paatal location), Panchaka.
173
+ ## Inauspicious Periods
253
174
 
254
175
  ```typescript
255
176
  const r = getDailyPanchang(date, loc, { timezone: 330 })!;
256
177
 
257
178
  r.rahuKalam; // { start, end }
258
- r.gulikaKalam; // { start, end }
259
- r.yamaganda; // { start, end }
260
- r.durMuhurta; // [TimePeriod, TimePeriod] — two ~48-min windows
179
+ r.gulikaKalam;
180
+ r.yamaganda;
181
+ r.durMuhurta; // two ~48-min windows
261
182
  r.varjyam; // { start, end } | null
262
- r.gandaMula; // { active: boolean, severity: 'mild' | 'severe' | null, ... }
183
+ r.gandaMula; // { active, severity: 'mild'|'severe'|null, ... }
263
184
  r.bhadra; // { start, end, location: 'earth'|'heaven'|'paatal', isActive } | null
264
185
  r.panchaka; // boolean — Moon in last 5 nakshatras
265
-
266
- // Direct helpers (varaIndex: 0=Sun ... 6=Sat):
267
- import {
268
- computeRahuKalam, computeGulikaKalam, computeYamaganda,
269
- computeVarjyam, computeGandaMula,
270
- } from 'panchang-ts';
271
-
272
- const rahu = computeRahuKalam(sunrise, sunset, varaIndex);
273
186
  ```
274
187
 
275
- ## 7. Time-Slot Systems
276
-
277
- Four parallel slot systems covering the Hindu day:
188
+ ## Time-Slot Systems
278
189
 
279
190
  ```typescript
280
191
  const r = getDailyPanchang(date, loc, { timezone: 330 })!;
281
192
 
282
- // Choghadiya — 8 day + 8 night slots, each named (Amrit, Kaal, Shubh, Rog, ...) and rated
193
+ // Choghadiya — 8 day + 8 night named, rated slots (Amrit, Kaal, Shubh, Rog, )
283
194
  r.choghadiya.day.forEach(s => console.log(s.name, s.qualityName, s.start, s.end));
284
- r.choghadiya.night.forEach(s => console.log(s.name, s.qualityName));
285
195
 
286
- // Gowri Panchangam (Tamil "Nalla Neram") — 8 day + 8 night slots
196
+ // Gowri Panchangam ("Nalla Neram") — 8 day + 8 night Tamil slots
287
197
  r.gowriPanchangam.day.forEach(s => console.log(s.name, s.qualityName));
288
198
 
289
199
  // Hora — 12 day + 12 night planetary hours (Chaldean order)
@@ -292,193 +202,157 @@ r.hora.day.forEach(h => console.log(h.planet, h.start, h.end));
292
202
  // Do Ghati Muhurta — 15 day + 15 night ~48-min deity-keyed slots (no vara rotation)
293
203
  r.doGhatiMuhurta.day.forEach(g => console.log(g.name, g.start, g.end));
294
204
 
295
- // Panchaka Rahita — slices of the day FREE of Panchaka ([] when Panchaka pervades)
205
+ // Panchaka Rahita — slices of the day FREE of Panchaka ([] when it pervades)
296
206
  r.panchakaRahita.forEach(slice => console.log(slice.start, slice.end));
297
207
  ```
298
208
 
299
- ## 8. Special Yogas
300
-
301
- Auspicious / inauspicious yogas formed by Vara × Tithi × Nakshatra combinations and
302
- Moon-from-Sun nakshatra-distance rules. The 28-name **Anandadi Yoga** cycle is also
303
- returned at sunrise.
209
+ ## Special Yogas
304
210
 
305
211
  ```typescript
306
212
  const r = getDailyPanchang(date, loc, { timezone: 330 })!;
307
213
 
308
- // Anandadi Yoga (Vara × Nakshatra cycle of 28 names)
309
- console.log(r.anandadiYoga.name); // "Ananda"
310
-
311
- // Special yogas active today
214
+ r.anandadiYoga.name; // 28-cycle name e.g. "Ananda"
312
215
  r.specialYogas.forEach(y => {
216
+ // type: amrit_siddhi | sarvartha_siddhi | ravi_pushya | guru_pushya
217
+ // | dwipushkar | tripushkar | jwalamukhi (inauspicious)
218
+ // | aadal | vidaal | ravi (Moon-from-Sun nakshatra-distance rules)
313
219
  console.log(y.name, y.type);
314
- // type: 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya'
315
- // | 'dwipushkar' | 'tripushkar' ← actions doubled / tripled
316
- // | 'jwalamukhi' ← inauspicious (Muhurta-chintamani 6.32)
317
- // | 'aadal' | 'vidaal' | 'ravi' ← Moon-from-Sun nakshatra-distance rules
318
220
  });
319
221
  ```
320
222
 
321
- ## 9. Festivals
322
-
323
- **80+ festivals** spanning pan-Indian, regional, and classical observances:
324
-
325
- - **Ekadashi** — 26 named variants (Putrada, Shat Tila, Nirjala, Devshayani, …) with
326
- **Smarta / Vaishnava split** via Dashami-viddha rule; Smarta fast emits a `deferralDate`
327
- for Dwadashi.
328
- - **Pradosha** — 7 weekday-qualified variants (Som, Bhauma, Shani, …) on both pakshas.
329
- - **Sankranti** — transit-based detection plus regional variants (Pongal, Vishu, Baisakhi,
330
- Pohela Boishakh, Bohag / Magh / Kati Bihu, Uttarayan, Ayyappa Makara Jyothi, Raja
331
- Sankranti, Harela, Sair, Singh Sankranti). **Lohri** fires on the Hindu day immediately
332
- preceding Makara Sankranti under Punjab / Haryana / Himachal scopes.
333
- - **Canonical-time classical festivals** — Ganesh Chaturthi (madhyahna), Shivaratri
334
- (nishita), Diwali, Holi, Raksha Bandhan (Bhadra-aware), Karva Chauth (chandrodaya),
335
- Janmashtami, Dussehra, Navaratri, Ram Navami, Hanuman Jayanti, Akshaya Tritiya &
336
- Parashurama Jayanti (madhyahna-vyapini), Makar Sankranti.
337
- - **Regional festivals** — Gudi Padwa, Gangaur, Karaga, Bonalu, Varamahalakshmi,
338
- Bathukamma, Hariyali / Kajari / Hartalika Teej, Govardhan Puja, Bhai Dooj, Phagli,
339
- Jagannath Rath Yatra, Raja Parba 3-day arc.
340
- - **Regional & seasonal** — Chhath (4-day sequence), Vat Savitri, Upakarma, Onam.
341
- - **Monthly observances** — Masik Shivaratri, Vinayaka Chaturthi, Masik Karthigai, Pushya
342
- days, Shravan Somvar, and other month + weekday patterns.
223
+ ## Festivals (80+)
343
224
 
344
- ```typescript
345
- const r = getDailyPanchang(date, loc, { timezone: 330 })!;
225
+ Covers Ekadashi (26 variants, Smarta/Vaishnava split via Dashami-viddha; Smarta
226
+ fast emits a `deferralDate` for Dwadashi), Pradosha, Sankranti + regional
227
+ variants (Pongal, Vishu, Baisakhi, Pohela Boishakh, Bihu, Uttarayan, Lohri…),
228
+ canonical-time classical (Janmashtami, Shivaratri, Ganesh Chaturthi, Diwali,
229
+ Holi, Raksha Bandhan — Bhadra-aware, Karva Chauth, Akshaya Tritiya…),
230
+ regional (Gudi Padwa, Gangaur, Teej variants, Onam, Chhath…), monthly
231
+ observances (Masik Shivaratri, Pushya days, Shravan Somvar…).
346
232
 
233
+ ```typescript
347
234
  r.festivals.forEach(f => {
235
+ // type: major | minor | ekadashi | smarta_ekadashi | vaishnava_ekadashi
236
+ // | pradosha | sankranti | eclipse
348
237
  console.log(f.name, f.type, f.deferralDate);
349
- // type: 'major' | 'minor' | 'ekadashi'
350
- // | 'smarta_ekadashi' | 'vaishnava_ekadashi' ← Smarta sets deferralDate
351
- // | 'pradosha' | 'sankranti' | 'eclipse'
352
238
  });
353
239
  ```
354
240
 
355
- ### Regional festival scoping
241
+ ### Regional scoping
356
242
 
357
- The `region` option scopes regional festival variants to one Indian state. Pan-Indian
358
- festivals (Diwali, Holi, Raksha Bandhan, the canonical `sankranti` event) emit regardless.
243
+ `region` scopes regional variants to one Indian state. Pan-Indian festivals
244
+ emit regardless.
359
245
 
360
246
  ```typescript
361
- // Default — every regional variant emits on Makar Sankranti day:
362
- const all = getDailyPanchang(jan14, chennai, { timezone: 330 })!;
363
- all.festivals.map(f => f.name);
364
- // → ["Sankranti", "Makar Sankranti", "Pongal", "Uttarayan",
365
- // "Magh Bihu", "Ayyappa Makara Jyothi"]
366
-
367
- // Scope to Tamil Nadu — drops Bihu/Ayyappa/Uttarayan:
368
- const tn = getDailyPanchang(jan14, chennai, { timezone: 330, region: 'tamil-nadu' })!;
369
- tn.festivals.map(f => f.name);
370
- // ["Sankranti", "Makar Sankranti", "Pongal"]
371
-
372
- // Lohri fires on the Hindu day BEFORE Makara transit, scoped to Punjab/Haryana/Himachal
373
- const lohri = getDailyPanchang(jan13, amritsar, { timezone: 330, region: 'punjab' })!;
374
- lohri.festivals.some(f => f.name === 'Lohri'); // true
247
+ // All regional variants (default):
248
+ getDailyPanchang(jan14, chennai, { timezone: 330 })!.festivals.map(f => f.name);
249
+ // ["Sankranti","Makar Sankranti","Pongal","Uttarayan","Magh Bihu","Ayyappa Makara Jyothi"]
250
+
251
+ // Tamil Nadu only:
252
+ getDailyPanchang(jan14, chennai, { timezone: 330, region: 'tamil-nadu' })!
253
+ .festivals.map(f => f.name);
254
+ // ["Sankranti","Makar Sankranti","Pongal"]
255
+
256
+ // Lohri fires on the Hindu day BEFORE Makara transit, in Punjab/Haryana/Himachal scope:
257
+ getDailyPanchang(jan13, amritsar, { timezone: 330, region: 'punjab' })!
258
+ .festivals.some(f => f.name === 'Lohri'); // true
375
259
  ```
376
260
 
377
- `FestivalRegion` covers 21 Indian states + `'nepal'` + `'all'` (default). See
378
- [Types](#types--exports) for the full slug list.
261
+ `FestivalRegion` covers 21 Indian states + `'nepal'` + `'all'` (default). The
262
+ legacy slugs `'tamil'`, `'bengal'`, `'north-india'` are still accepted and
263
+ mapped internally.
379
264
 
380
- ## 10. Eclipses
381
-
382
- Solar / lunar eclipse detection with subtype, magnitude, observer-horizon visibility, and
383
- classical pre-eclipse **sutak** impurity window.
265
+ ## Eclipses
384
266
 
385
267
  ```typescript
386
268
  const r = getDailyPanchang(date, loc, { timezone: 330 })!;
387
-
388
269
  if (r.eclipse) {
389
- console.log(r.eclipse.kind); // 'solar' | 'lunar'
390
- console.log(r.eclipse.subtype); // 'partial' | 'total' | 'annular' | 'penumbral'
391
- console.log(r.eclipse.magnitude); // 0..1 fraction of disc obscured at peak
392
- console.log(r.eclipse.visibleFromLocation); // body above horizon at peak?
393
- console.log(r.eclipse.start, r.eclipse.peak, r.eclipse.end);
394
- console.log(r.eclipse.sutakStart, r.eclipse.sutakEnd);
270
+ r.eclipse.kind; // 'solar' | 'lunar'
271
+ r.eclipse.subtype; // 'partial' | 'total' | 'annular' | 'penumbral'
272
+ r.eclipse.magnitude; // 0..1 fraction obscured at peak
273
+ r.eclipse.visibleFromLocation; // body above horizon at peak?
274
+ r.eclipse.start; r.eclipse.peak; r.eclipse.end;
275
+ r.eclipse.sutakStart; r.eclipse.sutakEnd;
395
276
  // Sutak: 12 h (4 prahara) before solar, 9 h (3 prahara) before lunar
396
277
  }
397
278
 
398
- // Or look ahead:
399
279
  import { getUpcomingSolarEclipse, getUpcomingLunarEclipse } from 'panchang-ts';
400
- const next = getUpcomingSolarEclipse(new Date(), loc, /* withinDays */ 365);
280
+ const next = getUpcomingSolarEclipse(new Date(), loc, 365 /* days */);
401
281
  ```
402
282
 
403
- ## 11. Planetary Positions
404
-
405
- All 9 grahas (Sun → Saturn + Rahu / Ketu) — geocentric, sidereal — with rashi, nakshatra,
406
- pada, retrograde flag. Optional `nodeType: 'true'` upgrades Rahu / Ketu from mean node
407
- (±2° worst-case) to Meeus's dominant periodic correction (~±0.6°).
283
+ ## Planetary Positions
408
284
 
409
285
  ```typescript
410
286
  import { computePlanetaryPositions, GRAHA_ABBR } from 'panchang-ts';
411
287
 
412
- const grahas = computePlanetaryPositions(new Date(), 'lahiri');
413
- console.log(grahas.jupiter.rashi.name); // "Dhanu"
414
- console.log(grahas.jupiter.degreeInRashi); // 18.42
415
- console.log(grahas.jupiter.nakshatra.name); // "Purva Ashadha"
416
- console.log(grahas.jupiter.nakshatra.pada); // 3
417
- console.log(grahas.saturn.isRetrograde); // true / false
418
- console.log(GRAHA_ABBR['Jupiter']); // "Ju"
288
+ const g = computePlanetaryPositions(new Date(), 'lahiri');
289
+ g.jupiter.rashi.name; // "Dhanu"
290
+ g.jupiter.degreeInRashi; // 18.42
291
+ g.jupiter.nakshatra.name; // "Purva Ashadha"
292
+ g.jupiter.nakshatra.pada; // 3
293
+ g.saturn.isRetrograde;
294
+ GRAHA_ABBR['Jupiter']; // "Ju"
419
295
 
420
- // True node (more accurate Rahu / Ketu)
421
- const grahasTrue = computePlanetaryPositions(new Date(), 'lahiri', undefined, 'true');
296
+ // True node (sharper Rahu/Ketu via Meeus periodic correction)
297
+ const gT = computePlanetaryPositions(new Date(), 'lahiri', undefined, 'true');
422
298
  ```
423
299
 
424
- ## 12. Vimshottari Dasha
300
+ ## Dashas
425
301
 
426
- Maha Antar → Pratyantar (3-level) breakdown, derived from a birth moment alone or from
427
- an explicit Moon longitude.
302
+ Five classical systems:
428
303
 
429
304
  ```typescript
430
305
  import {
431
- computeVimshottariDasha, computeVimshottariDashaFromBirth,
432
- computeVimshottariPratyantar, getSiderealMoonLongitude,
306
+ computeVimshottariDashaFromBirth, computeVimshottariPratyantar,
307
+ computeAshtottariDasha, computeYoginiDasha, computeCharaDasha, computeNarayanDasha,
433
308
  } from 'panchang-ts';
434
309
 
435
- // Convenience: from birth date alone (Moon longitude derived)
436
- const dasha = computeVimshottariDashaFromBirth(birthDate, 'lahiri');
437
- console.log(dasha.currentMahaDashaLord); // "Rahu"
438
- console.log(dasha.mahaDashas[0]!.antarDashas[0]!.lord); // "Rahu"
310
+ // 1. Vimshottari 120-year, 9-lord, with 3-level Maha→Antar→Pratyantar.
311
+ const vim = computeVimshottariDashaFromBirth(birth, 'lahiri');
312
+ const pratyantars = computeVimshottariPratyantar(vim.mahaDashas[0]!.antarDashas[0]!);
439
313
 
440
- // Or pass an explicit Moon sidereal longitude
441
- const moonLon = getSiderealMoonLongitude(birthDate, 'lahiri');
442
- const dasha2 = computeVimshottariDasha(birthDate, moonLon);
314
+ // 2. Ashtottari 108-year, 8-lord cycle (no Ketu).
315
+ const ash = computeAshtottariDasha(birth, moonLon);
443
316
 
444
- // Pratyantarthird-level sub-sub-periods within an Antardasha
445
- const firstAntar = dasha.mahaDashas[0]!.antarDashas[0]!;
446
- const pratyantars = computeVimshottariPratyantar(firstAntar); // PratyantarDasha[9]
447
- ```
317
+ // 3. Yogini 36-year, 8 yoginis.
318
+ const yog = computeYoginiDasha(birth, moonLon);
319
+ yog.mahaDashas[0]!.yogini; // 'Dhanya'
320
+ yog.mahaDashas[0]!.lord; // 'Jupiter'
321
+
322
+ // 4. Chara (Jaimini) — sign-based, 9-8-7 years per modality, forward only.
323
+ const cha = computeCharaDasha(birth, loc);
324
+
325
+ // 5. Narayan (Jaimini) — sign-based, parity-based direction.
326
+ // Vishama-pada lagna {Aries, Taurus, Gemini, Libra, Scorpio, Sag} → forward
327
+ // Sama-pada lagna {Cancer, Leo, Virgo, Capricorn, Aquarius, Pisces} → backward
328
+ const nar = computeNarayanDasha(birth, loc);
329
+ nar.direction; // 'forward' | 'backward'
448
330
 
449
- ## 13. Personal Transits
331
+ // Narayan variable-duration variant (Sanjay Rath):
332
+ const narV = computeNarayanDasha(birth, loc, 'lahiri', { duration: 'variable' });
333
+ narV.mahaDashas[0]!.years; // 0..12 from rashi-to-lord count (+1 exalt, -1 debil)
334
+ ```
450
335
 
451
- Daily transit-based favorability relative to the native's birth Moon. Pass `janmaRashi`
452
- or `janmaNakshatra` to `getDailyPanchang` and the corresponding field is added to the
453
- result; or call the helpers directly.
336
+ ## Personal Transits
454
337
 
455
338
  ```typescript
456
339
  const r = getDailyPanchang(date, loc, {
457
340
  timezone: 330,
458
- janmaRashi: 3, // 0 = Mesha ... 11 = Meena
459
- janmaNakshatra: 0, // 0 = Ashwini ... 26 = Revati
341
+ janmaRashi: 3, // 0 = Mesha 11 = Meena
342
+ janmaNakshatra: 0, // 0 = Ashwini 26 = Revati
460
343
  })!;
461
-
462
- r.chandraBalam!; // { house, quality: 'strong' | 'weak', name, englishName }
344
+ r.chandraBalam!; // { house, quality: 'strong'|'weak', name, englishName }
463
345
  r.tarabala!; // { taraIndex, name, englishName, quality }
464
346
 
465
- // Direct helpers:
466
- import { computeChandraBalam, computeTarabala, computeSadeSati } from 'panchang-ts';
467
-
468
- computeChandraBalam(3 /* janma */, 6 /* transit Moon rashi */);
469
- computeTarabala(0 /* janma nakshatra */, 4 /* transit Moon nakshatra */);
470
-
471
- // Sade Sati — Saturn currently transiting 12th, 1st, or 2nd from natal Moon
472
- const sadeSati = computeSadeSati(natalMoonRashiIndex, new Date());
347
+ import { computeSadeSati } from 'panchang-ts';
348
+ const ss = computeSadeSati(natalMoonRashiIndex, new Date());
473
349
  // → { active, phase: 1|2|3|null, currentArcStart, currentArcEnd, nextArcStart }
474
350
  ```
475
351
 
476
- ## 14. Birth Chart (Kundli)
352
+ ## Birth Chart
477
353
 
478
- Sidereal **Lagna**, **Bhava** under three house systems, **D1 (Rashi)** + six classical
479
- divisional charts (**D2 Hora**, **D3 Drekkana**, **D7 Saptamsa**, **D9 Navamsa**, **D10
480
- Dasamsa**, **D12 Dwadasamsa**, **D30 Trimsamsa**) placing all 9 grahas, and **Planetary
481
- Dignity**.
354
+ Sidereal Lagna, Bhava under three house systems, D1 + six classical divisional
355
+ charts (D2/D3/D7/D9/D10/D12/D30), and Planetary Dignity.
482
356
 
483
357
  ```typescript
484
358
  import {
@@ -489,206 +363,291 @@ import {
489
363
  const birth = new Date('1995-08-15T05:30:00Z');
490
364
  const loc = { latitude: 28.6139, longitude: 77.2090 };
491
365
 
492
- // 1. Lagna (sidereal ascendant)
493
366
  const lagna = computeLagna(birth, loc, 'lahiri', 'en');
494
- // → { siderealLongitude, rashi, degreeInRashi, nakshatra, pada }
495
367
 
496
- // 2. Bhava (12 houses)
497
- // - 'whole-sign' (default classical Vedic) each rashi is one house
498
- // - 'equal' — each house spans 30° starting at lagna's exact degree
499
- // - 'placidus-kp' — true cuspal positions; throws PanchangError('CIRCUMPOLAR') > ±66.5°
368
+ // Bhava — 'whole-sign' (default) | 'equal' | 'placidus-kp'.
369
+ // Placidus-KP throws PanchangError('CIRCUMPOLAR') beyond ±66.5°.
500
370
  const houses = computeBhava(birth, loc, { houseSystem: 'whole-sign' });
501
371
 
502
- // 3. D1 (Rashi) chart lagna + bhava + 9 grahas with house placement
372
+ // D1 — full Rashi chart with 9-graha house placement.
503
373
  const d1 = computeRashiChart(birth, loc, { houseSystem: 'whole-sign' });
504
- d1.planets.find(p => p.planet === 'Jupiter')?.house; // e.g. 5
374
+ d1.planets.find(p => p.planet === 'Jupiter')?.house;
505
375
  d1.planets.find(p => p.planet === 'Saturn')?.isRetrograde;
506
376
 
507
- // 4. D9 (Navamsa) chart classical sign-based per-rashi-type rule
508
- const d9 = computeNavamsa(birth, loc);
377
+ // Divisional charts (D2 Hora, D3 Drekkana, D7 Saptamsa, D9 Navamsa,
378
+ // D10 Dasamsa, D12 Dwadasamsa, D30 Trimsamsa).
379
+ const d9 = computeNavamsa(birth, loc);
380
+ const d10 = computeDivisionalChart(birth, loc, 'D10');
381
+ const d30 = computeDivisionalChart(birth, loc, 'D30');
509
382
 
510
- // 5. Divisional charts (D2/D3/D7/D10/D12/D30) via the unified API
511
- const d10 = computeDivisionalChart(birth, loc, 'D10'); // career
512
- const d30 = computeDivisionalChart(birth, loc, 'D30'); // misfortune
513
- // { divisional: 'D10', lagnaRashi, planets[] }
514
-
515
- // 6. Planetary dignity (BPHS Ch.3-4)
516
- computeDignity('Mars', 0); // 'moolatrikona' (Aries)
517
- computeDignity('Mars', 9); // 'exalted' (Capricorn)
518
- computeDignity('Sun', 6); // 'debilitated' (Libra)
383
+ // Planetary dignity (BPHS Ch.3-4).
384
+ computeDignity('Mars', 0); // 'moolatrikona' (Aries)
385
+ computeDignity('Mars', 9); // 'exalted' (Capricorn)
386
+ computeDignity('Sun', 6); // 'debilitated' (Libra)
519
387
  ```
520
388
 
521
- The seven divisional kinds are: **D2 Hora** (wealth), **D3 Drekkana** (siblings),
522
- **D7 Saptamsa** (children), **D9 Navamsa** (partner / dharma), **D10 Dasamsa** (career),
523
- **D12 Dwadasamsa** (parents), **D30 Trimsamsa** (misfortune). Each follows its classical
524
- per-rashi-type mapping per BPHS Ch. 6; D30 uses the non-uniform 5-segment split with
525
- Mars / Saturn / Jupiter / Mercury / Venus rulership (no Sun / Moon segments).
526
-
527
- Birth-chart helpers accept the full ayanamsa set including `'true-chitra'` (True
528
- Chitrapaksha) and `'thirukanitham'` (Tamil-Vakya). Pass via `options.ayanamsa` or the
529
- ayanamsa positional arg.
530
-
531
- ## 15. Compatibility & Doshas
389
+ Birth-chart helpers accept the full ayanamsa set including `'true-chitra'` and
390
+ `'thirukanitham'`.
532
391
 
533
- **Ashtakoot Guna Milan** (36-point marriage compatibility), **Mangal Dosha** (Manglik
534
- with cancellations), **Kaal Sarp Dosha** (12 named subtypes by Rahu's house), and
535
- **Pitru Dosha** (ancestral affliction triggers).
392
+ ## Compatibility & Doshas
536
393
 
537
394
  ```typescript
538
395
  import {
539
- computeAshtakoot, computeMangalDosha,
540
- computeKaalSarp, computePitruDosha,
396
+ computeAshtakoot, computePathuPorutham,
397
+ computeMangalDosha, computeKaalSarp, computePitruDosha,
541
398
  } from 'panchang-ts';
542
399
 
543
- // Ashtakoot — from natal Moons
400
+ // Ashtakoot (North Indian, 36-point) Varna, Vashya, Tara, Yoni,
401
+ // Graha Maitri, Gana, Bhakoot, Nadi (max 1/2/3/4/5/6/7/8).
544
402
  const match = computeAshtakoot(
545
- { rashi: 4, nakshatra: 9 }, // boy: Simha / Magha
546
- { rashi: 0, nakshatra: 1 }, // girl: Mesha / Bharani
403
+ { rashi: 4, nakshatra: 9 },
404
+ { rashi: 0, nakshatra: 1 },
547
405
  );
548
406
  // → { totalScore: 0..36, koots: KootScore[8], cancellations: string[] }
549
- // Koots in canonical order: Varna, Vashya, Tara, Yoni, Graha Maitri, Gana, Bhakoot, Nadi
550
- // (max scores 1, 2, 3, 4, 5, 6, 7, 8 respectively)
551
-
552
- // Mangal Dosha — checks Mars from lagna, Moon, and Venus
553
- const mangal = computeMangalDosha(d1);
554
- // → { afflicted, fromLagna, fromMoon, fromVenus, cancellations }
555
-
556
- // Kaal Sarp Dosha — all 7 visible planets between Rahu and Ketu axis
557
- const ksd = computeKaalSarp(d1);
558
- // → { afflicted, subtype, partial, rahuHouse, ketuHouse }
559
- // subtype is one of: anant, kulik, vasuki, shankhpal, padma, mahapadma,
560
- // takshak, karkotak, shankhachud, ghatak, vishdhar, sheshnag — by Rahu's house.
561
-
562
- // Pitru Dosha — Sun + Rahu/Ketu in same house, OR Sun + Saturn in 9th
563
- const pitru = computePitruDosha(d1);
564
- // → { afflicted, reasons: string[] }
565
- ```
566
407
 
567
- **Documented limitations** Mangal Dosha cancellations only cover Mars in own sign
568
- (Aries / Scorpio) or exalted (Capricorn); other classical cancellations (mutual Mangalik,
569
- Mars-Jupiter aspect, Mars-Saturn conjunction) are not applied. Ashtakoot Vashya koot is
570
- simplified to single-vashya per rashi. Pitru Dosha surfaces the two highest-frequency
571
- classical triggers (Sun + node, Sun + Saturn in 9th); the full BPHS catalog of triggers
572
- (debilitated 9th lord, 9th lord in dusthana, etc.) is out of scope.
408
+ // Opt-in Bhakoot cancellations need extra natal data:
409
+ // `lagnaRashi` enables same-lagna-lord + same-7th-lord rules;
410
+ // `navamsaRashi` enables the same-Navamsa-lord rule.
411
+ const richer = computeAshtakoot(
412
+ { rashi: 4, nakshatra: 9, lagnaRashi: 7, navamsaRashi: 2 },
413
+ { rashi: 0, nakshatra: 1, lagnaRashi: 1, navamsaRashi: 5 },
414
+ );
415
+
416
+ // Pathu Porutham (Tamil/Kerala, 10-fold) — binary pass/fail per koot.
417
+ // Three vetoes (Yoni, Rajju, Vedha) flip `recommended` regardless of count.
418
+ const tp = computePathuPorutham(
419
+ { rashi: 4, nakshatra: 9 },
420
+ { rashi: 0, nakshatra: 1 },
421
+ );
422
+ tp.totalPasses; // 0..10
423
+ tp.recommended; // no veto + ≥5 passes
424
+
425
+ // Doshas
426
+ computeMangalDosha(d1);
427
+ // Mars in 1/2/4/7/8/12 from Lagna, Moon, AND Venus (Drik rule set).
428
+ // Cancellations: Mars in own sign/exalted, conjunct Jup/Moon/Venus,
429
+ // or aspected by Jupiter (5/7/9 sign-aspect).
430
+ // Severity (anshik/purna) is computed pre-cancellation.
431
+
432
+ computeKaalSarp(d1);
433
+ // 12 subtypes by Rahu's house: anant, kulik, vasuki, shankhpal, padma,
434
+ // mahapadma, takshak, karkotak, shankhachud, ghatak, vishdhar, sheshnag.
435
+
436
+ computePitruDosha(d1);
437
+ // 9-rule classical catalog: Sun+Rahu/Ketu/Saturn in 9th; 9th lord
438
+ // debilitated/combust/dusthana; Saturn or nodes in 9th from natal Moon;
439
+ // malefics (Mars/Saturn/Rahu/Ketu) in 5th from natal Moon.
440
+ ```
573
441
 
574
- ## 16. Aspects & Strength
442
+ **Limitations.** Ashtakoot Vashya koot uses single-vashya per rashi.
443
+ Bhakoot Parivartana (rashi-lord exchange) cancellation needs per-graha
444
+ position data not carried by the `NatalMoon` shape and is not modelled.
575
445
 
576
- **Drishti** (planetary aspects per BPHS Ch. 26) and **Shadbala** (six-fold strength per
577
- BPHS Ch. 27).
446
+ ## Strength & Aspects
578
447
 
579
448
  ```typescript
580
- import { computeAspects, computeShadbala } from 'panchang-ts';
581
-
582
- // Aspects — every graha aspects the 7th house from itself; malefics gain
583
- // extra special aspects (Mars 4 + 8, Jupiter 5 + 9, Saturn 3 + 10).
584
- const aspects = computeAspects(d1);
585
- // { Sun: [houses…], Moon: [...], …, Saturn: [...], Rahu: [...], Ketu: [...] }
586
- //
587
- // Default treats Rahu/Ketu with the 7th-only BPHS-literal rule. Pass
588
- // { nodeAspects: '5-and-9' } to extend nodes with Jupiter-like 5/9 aspects
589
- // (BV Raman / KP convention).
590
-
591
- // Shadbala 7 visible grahas, 6 components per planet, in Virupas (60 V = 1 Rupa).
449
+ import {
450
+ computeAspects, computeShadbala, computeBhavaBala, computeAshtakavarga,
451
+ } from 'panchang-ts';
452
+
453
+ // Drishti — every graha aspects the 7th; malefics gain extras
454
+ // (Mars 4+8, Jupiter 5+9, Saturn 3+10). Node aspect mode is configurable:
455
+ const aspects = computeAspects(d1); // BPHS 7th-only on nodes
456
+ const aspExt = computeAspects(d1, { nodeAspects: '5-and-9' }); // KP/BV Raman extension
457
+
458
+ // Shadbala — 7 visible grahas, 6 components, in Virupas (60 V = 1 Rupa).
459
+ // Sthana = Uchcha + Saptavargaja (D1/D2/D3/D7/D9/D12/D30 dignity sum)
460
+ // + Ojha-Yugma (rashi+navamsa parity) + Drekkana (gender decanate).
461
+ // Range [0, 420 V]. Dig is directional cusp; Kala = Nathonatha + Paksha;
462
+ // Chesta is retrograde-bucket; Naisargika is fixed rank; Drik is weighted aspects.
592
463
  const bala = computeShadbala(birth, loc);
593
- // → { Sun: { sthana, dig, kala, chesta, naisargika, drik, total }, Moon: …, … }
594
- //
595
- // Components implemented at the simplified-model level used by ProKerala /
596
- // PyJHora Uchcha-only Sthana, Dig from directional cusp, Nathonatha + Paksha
597
- // for Kala, retrograde-bucket Chesta, fixed Naisargika rank, weighted Drik.
464
+
465
+ // Bhava Bala — 12-bhava strength built on top of Shadbala.
466
+ // Per-bhava: { bhavadhipati, dik, drik, sthana, total }.
467
+ const bhavaBala = computeBhavaBala(birth, loc);
468
+
469
+ // Ashtakavarga — 12-rashi bindu grids (BPHS Ch. 66).
470
+ const av = computeAshtakavarga(d1);
471
+ av.sarvashtaka; // 12 cells, each 0..56, total 336
472
+ av.bhinnashtaka.Jupiter; // 12-cell grid; Jupiter total = 56 (chart-invariant)
473
+ // Other invariants: Sun=47, Moon=49, Mars=39, Mercury=54, Venus=52, Saturn=39.
474
+
475
+ // Trikona + Ekadhipatya Sodhana reductions (BPHS Ch. 67):
476
+ const avR = computeAshtakavarga(d1, { reductions: true });
477
+ avR.reduced!.sarvashtaka;
598
478
  ```
599
479
 
600
- Both functions return additive surface they do **not** modify the
601
- `getDailyPanchang` / birth-chart pipelines. Call them on demand.
480
+ Rahu and Ketu are not Ashtakavarga receivers or contributors (classical
481
+ Parashara scheme).
602
482
 
603
- ## 17. Dasha Systems
483
+ ## Yogas & Karakas
604
484
 
605
- Four classical dasha systems are exposed:
485
+ ```typescript
486
+ import { computeYogas, computeJaiminiKarakas } from 'panchang-ts';
487
+
488
+ // ~25 named yogas — Pancha Mahapurusha (Ruchaka/Bhadra/Hamsa/Malavya/Sasha),
489
+ // lunar (Gajakesari, Sunapha, Anapha, Durudhura, Kemadruma), solar
490
+ // (Budha-Aditya, Veshi, Vasi, Ubhayachari), Raja (kendra/trikona-lord,
491
+ // Dharma-Karmadhipati, Vipareeta, Lakshmi), Dhana (2-11, 5-9, Vasumati),
492
+ // Vargottama, Yogakaraka, Neecha Bhanga, Daridra.
493
+ const yogas = computeYogas(d1);
494
+ // → [{ name, type, reasons[], bhanga?: { applies, reasons[] } }, …]
495
+
496
+ // Optional cancellation annotations: 5 Pancha Mahapurusha + Gajakesari
497
+ // surface `bhanga` (Sun/Moon conjunct or Jupiter combust/debilitated).
498
+ // Neecha Bhanga: dispositor in kendra from Lagna OR Moon; lord-of-
499
+ // exaltation-rashi in kendra from Lagna or Moon; mutual exchange;
500
+ // dispositor aspecting the debilitated planet.
501
+
502
+ // Filter by type / pass D9 for Vargottama:
503
+ const d9 = computeNavamsa(birth, loc);
504
+ const all = computeYogas(d1, { types: ['raja','dhana'], navamsa: d9 });
505
+
506
+ // Jaimini Karakas — Atmakaraka (highest degree-in-rashi) … Darakaraka (lowest).
507
+ const k7 = computeJaiminiKarakas(d1); // 7-graha Parashara default
508
+ const k8 = computeJaiminiKarakas(d1, { variant: '8-jaimini' }); // adds Rahu (degree reversed),
509
+ // inserts Pitrukaraka at 5th
510
+ ```
511
+
512
+ Yoga and Karaka names are English/transliterated proper nouns and intentionally
513
+ **not** locale-resolved.
514
+
515
+ ## Annual & Sensitive Layers
606
516
 
607
517
  ```typescript
608
518
  import {
609
- computeVimshottariDashaFromBirth, computeVimshottariPratyantar,
610
- computeAshtottariDasha, computeYoginiDasha, computeCharaDasha,
519
+ computeVarshaphala, computeTithiPravesha, computeArudhas,
520
+ computeHoraLagna, computeGhatiLagna, computeBhavaLagna, computeSripatiLagna,
521
+ computeUpagrahas, computeArgala,
611
522
  } from 'panchang-ts';
612
523
 
613
- const birth = new Date('1995-08-15T05:30:00Z');
614
- const loc = { latitude: 28.6139, longitude: 77.2090 };
524
+ // Varshaphala Tajik annual chart for the Nth solar return.
525
+ const v = computeVarshaphala(birth, 30, loc);
526
+ v.solarReturnInstant;
527
+ v.varshaLagna.rashi.name;
528
+ v.muntha.rashi; v.muntha.house; // muntha = (natalLagnaRashi + 30) mod 12
529
+ v.yearLord; // strongest of 4 candidates by Shadbala
530
+ v.sahams.Punya.house;
531
+ v.sahams.Vivaha.rashi;
532
+ // 27 Sahams: Punya, Vidya, Yasas, Mitra, Karma, Vivaha, Putra, Roga, Marana,
533
+ // Rajya, Raja, Bandhu, Dharma, Gnati, Apamrityu, Bhratri, Matri, Pitri, Sama,
534
+ // Bandhana, Karyasiddhi, Vyapara, Sastra, Asha, Labha, Susha, Tapas.
535
+
536
+ // Tithi Pravesha — annual chart cast when Sun is in natal sidereal sign AND
537
+ // Sun-Moon separation equals natal separation. Preserves natal tithi exactly.
538
+ const tp = computeTithiPravesha(birth, 30, loc);
539
+ tp.natalTithi === tp.praveshTithi; // always true
540
+
541
+ // Arudha padas — image/reflection of each bhava. Arudha[0] = Arudha Lagna (AL).
542
+ const a = computeArudhas(d1);
543
+ a[0]!.bhava; // 1 — AL
544
+ a[0]!.arudhaRashi; // 0..11
545
+ a[6]!.bhava; // 7 — Darapada (spouse pada)
546
+
547
+ // Special lagnas — time-derived sensitive points from sunrise on/before birth.
548
+ computeHoraLagna(birth, loc); // 30°/hour (1 rashi/hour)
549
+ computeGhatiLagna(birth, loc); // 75°/hour (1 rashi/24 min)
550
+ computeBhavaLagna(birth, loc); // 15°/hour (1 rashi/2 hours)
551
+ computeSripatiLagna(birth, loc); // = natal lagna (cusp 1)
552
+
553
+ // Sripati cusps 2–12 (opt-in) — 4 angular cusps + trisected intermediates.
554
+ // Defined at every latitude (unlike Placidus).
555
+ const sripati = computeSripatiLagna(birth, loc, 'lahiri', 'en', { includeCusps: true });
556
+ sripati.cusps; // number[12] of bhava madhyas; cusps[0/3/6/9] = ASC/IC/DSC/MC
557
+
558
+ // Upagrahas — Gulika, Mandi (rising-asc at Saturn segment start/midpoint),
559
+ // plus Sun-derived Dhuma, Vyatipata, Parivesha, Indrachapa, Upaketu.
560
+ const u = computeUpagrahas(birth, loc);
561
+ u.gulika.longitude; u.gulika.rashi; u.gulika.house;
562
+
563
+ // Argala (Jaimini) — planets in 2/4/11 from a bhava form Argala (intervention);
564
+ // 3/10/12 form Virodhargala (counter). Each planet hits exactly 6 of 12 bhavas.
565
+ const arg = computeArgala(d1);
566
+ arg[0]!.argala; arg[0]!.virodhargala;
567
+
568
+ // Trikonargala (5/9 trine, opt-in) — Ketu reversal: 5th-from → virodhaka,
569
+ // 9th-from → source.
570
+ const argT = computeArgala(d1, { includeTrikonargala: true });
571
+ argT[0]!.trikona!.sources;
572
+ argT[0]!.trikona!.virodhakas;
573
+ ```
615
574
 
616
- // 1. Vimshottari (120-year, 9-lord) — already in v1; pratyantar (3-level) added in v3
617
- const vim = computeVimshottariDashaFromBirth(birth);
618
- const pratyantars = computeVimshottariPratyantar(vim.mahaDashas[0].antarDashas[0]);
575
+ ## KP & Prashna
619
576
 
620
- // 2. Ashtottari (108-year, 8-lord, no Ketu) — used when Moon in Krishna Paksha
621
- const moonLon = /* sidereal Moon longitude */ 145.7;
622
- const ash = computeAshtottariDasha(birth, moonLon);
623
- // → mahaDashas[0..7], lord cycle Sun(6)→Moon(15)→Mars(8)→Mercury(17)→
624
- // Saturn(10)→Jupiter(19)→Rahu(12)→Venus(21)
625
-
626
- // 3. Yogini (36-year, 8 yoginis with planetary lords)
627
- const yog = computeYoginiDasha(birth, moonLon);
628
- yog.mahaDashas[0].yogini; // 'Dhanya' (Magha → nakshatra 10, 10 % 8 = 2)
629
- yog.mahaDashas[0].lord; // 'Jupiter' (Dhanya's planet)
577
+ ```typescript
578
+ import {
579
+ computeKpSubLord, computeKpCuspalSubLords, computeKpSignificators,
580
+ computePrashnaChart,
581
+ } from 'panchang-ts';
630
582
 
631
- // 4. Chara (Jaimini, sign-based, 9-8-7 years per modality)
632
- const cha = computeCharaDasha(birth, loc);
633
- cha.mahaDashas[0].rashi; // lagna's rashi
634
- cha.mahaDashas[0].lord; // sign-lord planet
635
- cha.mahaDashas[0].years; // 9 (movable) | 8 (fixed) | 7 (dual)
583
+ // KP sub-lord at any sidereal longitude (243 sub-divisions across the zodiac,
584
+ // proportional to Vimshottari years).
585
+ const info = computeKpSubLord(45.5); // 15°30' Taurus
586
+ info.signLord; // 'Venus'
587
+ info.starLord; // 'Moon'
588
+ info.subLord;
589
+
590
+ // Cuspal sub-lords (always Placidus-KP — KP's anchor scheme).
591
+ const cusps = computeKpCuspalSubLords(birth, loc);
592
+ cusps.cusps[0]!.subLord; // ascendant
593
+ cusps.cusps[6]!.subLord; // descendant
594
+
595
+ // Significators — for each planet, the houses it signifies via the 4-fold KP rule
596
+ // (occupant + star-lord-occupant + owner + star-lord-owner).
597
+ const sig = computeKpSignificators(d1);
598
+ sig.byPlanet.Sun;
599
+ sig.byHouse[10];
600
+
601
+ // Prashna (horary) chart — cast at question moment from querent's location.
602
+ const pchart = computePrashnaChart(
603
+ new Date('2026-05-09T14:30:00Z'),
604
+ { latitude: 19.0760, longitude: 72.8777 },
605
+ );
606
+ pchart.lagna.rashi.name;
607
+ pchart.bhava.system; // 'placidus-kp' by default (KP horary anchor)
608
+ pchart.planets[1]!.house; // Moon — primary mind significator
636
609
  ```
637
610
 
638
- **Sourcing:** Vimshottari per Parashara (BPHS Ch. 51); Ashtottari per Satya Acharya;
639
- Yogini per Sanjay Rath (1999) / Charak; Chara per Jaimini Sutras Ch. 1 (9-8-7 years
640
- variant). Documented limitations: Chara uses the forward zodiacal direction
641
- unconditionally (Sundar / Achyutananda variant); the reverse-direction rule for
642
- even-rashi lagnas is not currently exposed.
611
+ Same return shape as a natal `BirthChart`. Pass `{ houseSystem: 'whole-sign' }`
612
+ to `computePrashnaChart` for traditional Vedic Prashna.
643
613
 
644
- ## 18. Muhurta Engine
645
-
646
- A configurable rule + scoring engine for picking auspicious dates. Ships with **13 stock
647
- rules** (vivah, griha pravesh, namakarana, vidyarambh, vahan kharidi, annaprashan,
648
- mundan, upanayanam, karnavedha, aksharabhyasam, seemantham, shop opening, travel
649
- start). Each rule is a pure data declaration — write your own without touching the
650
- engine.
614
+ ## Muhurta Engine
651
615
 
652
616
  ```typescript
653
617
  import { scoreMuhurta, findAuspiciousDates, vivahRule } from 'panchang-ts';
654
618
 
655
- // Score a single date
656
619
  const r = scoreMuhurta(new Date('2026-05-12'), DELHI, vivahRule, { timezone: 330 });
657
620
  // → { date, score: 0..100, passes: boolean, reasons: string[] }
658
621
 
659
- // Find all auspicious dates in a range, sorted by score descending
660
622
  const dates = findAuspiciousDates(
661
623
  vivahRule,
662
624
  new Date('2026-05-01'),
663
625
  new Date('2026-05-31'),
664
626
  DELHI,
665
627
  { timezone: 330 },
666
- );
667
- // → MuhurtaDay[] with full panchang attached for each result
628
+ ); // MuhurtaDay[] sorted by score desc; full panchang attached
668
629
 
669
- // Custom rule
630
+ // Custom rule (pure data, no engine code needed)
670
631
  const myRule: MuhurtaRule = {
671
632
  occasion: 'launch_party',
672
- auspiciousVaras: [3, 4, 5], // Wed/Thu/Fri
673
- auspiciousNakshatras: [11, 12, 21], // Uttara Phalguni / Hasta / Shravana
633
+ auspiciousVaras: [3, 4, 5],
634
+ auspiciousNakshatras: [11, 12, 21],
674
635
  excludeBhadra: true,
675
636
  excludeEkadashi: true,
676
637
  excludeAdhikaMasa: true,
677
638
  };
678
639
  ```
679
640
 
680
- Scoring model: starts at 50 (neutral), +10 per matching auspicious axis (tithi,
681
- nakshatra, vara, yoga), -15 per matching inauspicious axis, hard exclusions
682
- (`excludeBhadra` / `excludeEkadashi` / `excludeEclipse` / `excludeAdhikaMasa` /
683
- `excludeGandaMula` / `excludePanchaka` / `requirePaksha` mismatch) zero the score.
684
- Special yogas — Amrit Siddhi, Sarvartha Siddhi, Ravi Pushya, Guru Pushya — add +5;
685
- Jwalamukhi yoga subtracts -10. Final score clamped to 0..100; `passes: true` when
686
- score ≥ 50.
641
+ 13 stock rules: vivah, griha pravesh, namakarana, vidyarambh, vahan kharidi,
642
+ annaprashan, mundan, upanayanam, karnavedha, aksharabhyasam, seemantham, shop
643
+ opening, travel start.
687
644
 
688
- ## 19. Calendar Conversion
645
+ Scoring: starts at 50; +10 per matching auspicious axis (tithi / nakshatra /
646
+ vara / yoga), -15 per inauspicious axis, hard exclusions zero the score.
647
+ Special yogas (Amrit Siddhi, Sarvartha Siddhi, Ravi/Guru Pushya) add +5;
648
+ Jwalamukhi subtracts -10. Clamped 0..100; `passes: true` when score ≥ 50.
689
649
 
690
- Gregorian↔Hindu lunar coordinates, Kali Yuga year, regional Hindu New Year, and
691
- yearly listings of Ekadashis / Sankrantis / festivals / eclipses.
650
+ ## Calendar Conversion
692
651
 
693
652
  ```typescript
694
653
  import {
@@ -698,323 +657,136 @@ import {
698
657
  getFestivalsInRange, getUpcomingEclipses,
699
658
  } from 'panchang-ts';
700
659
 
701
- // Gregorian → Hindu coordinates at sunrise
660
+ // Gregorian → Hindu coords at sunrise
702
661
  const h = convertGregorianToHindu(new Date('2026-04-15'), DELHI, { timezone: 330 });
703
- // → { tithiName, tithi (1..30), pakshaTithi (1..15), paksha,
704
- // masaName, masaIndex, isAdhika, vikramSamvat, shakaSamvat,
705
- // varaName, varaIndex }
706
662
 
707
- // Hindu → Gregorian: which Gregorian dates correspond to a (samvat, masa, paksha, tithi)?
663
+ // Hindu → Gregorian
708
664
  const dates = convertHinduToGregorian(
709
665
  { vikramSamvat: 2083, masaIndex: 0, paksha: 'shukla', pakshaTithi: 9 },
710
666
  DELHI, { timezone: 330 },
711
- );
712
- // dates[0] → Rama Navami in VS 2083
667
+ ); // → Rama Navami in VS 2083
713
668
 
714
- getKaliYugaYear(new Date('2026-04-01')); // 5127
715
- getHinduNewYear(2026, 'tamil-nadu', DELHI, { timezone: 330 }); // Puthandu
669
+ getKaliYugaYear(new Date('2026-04-01')); // 5127
670
+ getHinduNewYear(2026, 'tamil-nadu', DELHI, { timezone: 330 }); // Puthandu
716
671
 
717
- // Yearly listings
718
- getEkadashiDatesForYear(2026, DELHI, { timezone: 330 }); // ~24 Date[]
719
- getSankrantisForYear(2026, DELHI, { timezone: 330 }); // 12 SankrantiEvent[]
720
- getFestivalsInRange(start, end, DELHI, { timezone: 330 }); // FestivalDay[]
721
- getUpcomingEclipses(new Date(), DELHI, 5); // 5 EclipseInfo[]
672
+ getEkadashiDatesForYear(2026, DELHI, { timezone: 330 }); // ~24 Date[]
673
+ getSankrantisForYear(2026, DELHI, { timezone: 330 }); // 12 SankrantiEvent[]
674
+ getFestivalsInRange(start, end, DELHI, { timezone: 330 }); // FestivalDay[]
675
+ getUpcomingEclipses(new Date(), DELHI, 5);
722
676
  ```
723
677
 
724
- `getHinduNewYear` is region-aware: Tamil Nadu / Kerala / Punjab / Bengal / Assam use
725
- the **solar** (Mesha Sankranti) anchor; everywhere else uses **Chaitra Shukla Pratipada**
726
- (Ugadi / Gudi Padwa / Cheti Chand). When the Pratipada is a kshaya tithi (e.g. Ugadi
727
- 2026), the function falls back to the Amanta-Chaitra-masa boundary.
678
+ `getHinduNewYear` is region-aware: Tamil Nadu / Kerala / Punjab / Bengal / Assam
679
+ use the **solar** (Mesha Sankranti) anchor; elsewhere uses **Chaitra Shukla
680
+ Pratipada** (Ugadi / Gudi Padwa / Cheti Chand). When Pratipada is a kshaya
681
+ tithi (e.g. Ugadi 2026), falls back to the Amanta-Chaitra-masa boundary.
728
682
 
729
- ## 20. Localization
730
-
731
- All returned display names respect the `language` option. **English** and **Hindi
732
- (Devanagari)** are supported.
683
+ ## Localization & Configuration
733
684
 
734
685
  ```typescript
735
686
  const hi = getDailyPanchang(date, loc, { timezone: 330, language: 'hi' })!;
687
+ hi.tithis[0].name; // "कृष्ण चतुर्दशी"
688
+ hi.vara.name; // "मंगलवार"
689
+ hi.chandramasa.name; // "माघ"
690
+ hi.choghadiya.day[0].name; // "अमृत"
691
+ hi.vara.englishName; // "Tuesday" — englishName always English
736
692
 
737
- console.log(hi.tithis[0].name); // "कृष्ण चतुर्दशी"
738
- console.log(hi.vara.name); // "मंगलवार"
739
- console.log(hi.chandramasa.name); // "माघ"
740
- console.log(hi.choghadiya.day[0].name); // "अमृत"
741
-
742
- // englishName is always English on Vara / Tarabala / Chandra Balam
743
- console.log(hi.vara.englishName); // "Tuesday"
744
- ```
745
-
746
- ## 21. Configuration
747
-
748
- ```typescript
693
+ // All options:
749
694
  const r = getDailyPanchang(date, loc, {
750
- timezone: 330, // number (UTC offset in min) or IANA string
751
- ayanamsa: 'lahiri', // 'lahiri' | 'raman' | 'krishnamurti'
752
- // | 'true-chitra' | 'thirukanitham'
753
- language: 'en', // 'en' | 'hi'
754
- masaSystem: 'purnimanta', // 'purnimanta' | 'amanta'
695
+ timezone: 330, // number (UTC offset min) or IANA string
696
+ ayanamsa: 'lahiri', // lahiri | raman | krishnamurti | true-chitra | thirukanitham
697
+ language: 'en', // en | hi
698
+ masaSystem: 'purnimanta', // purnimanta | amanta
755
699
  region: 'all', // 21 state slugs + 'nepal' + 'all'
756
700
  computeEndTimes: true, // false → ~5x speedup, names only
757
- precision: 'standard', // 'standard' (15 iter) | 'high' (25 iter)
701
+ precision: 'standard', // standard (15 iter) | high (25 iter)
758
702
  janmaRashi: undefined, // pass to add r.chandraBalam
759
703
  janmaNakshatra: undefined, // pass to add r.tarabala
760
704
  });
761
705
  ```
762
706
 
763
- **Timezone handling** `timezone` accepts either a number (UTC offset in minutes, e.g.
764
- `330` for IST) or an IANA zone name (e.g. `'America/New_York'`). IANA strings need `Intl`,
765
- which older Hermes versions don't fully support — pass a number on those targets. DST
766
- resolves automatically for IANA zones via the reference date.
707
+ **Timezone.** Number (minutes from UTC, e.g. `330` for IST) or an IANA zone
708
+ name (e.g. `'America/New_York'`). IANA strings need `Intl`, which older Hermes
709
+ versions lack — pass a number on those targets. DST resolves automatically for
710
+ IANA zones.
767
711
 
768
712
  ---
769
713
 
770
714
  ## Types & Exports
771
715
 
772
716
  <details>
773
- <summary><strong>Core Types</strong> — GeoLocation, TimePeriod</summary>
717
+ <summary><strong>Core, Pancha Anga, Festivals</strong></summary>
774
718
 
775
719
  ```typescript
776
- interface GeoLocation {
777
- latitude: number; // -90 to 90
778
- longitude: number; // -180 to 180
779
- elevation?: number; // metres, default 0
780
- }
781
-
782
- interface TimePeriod {
783
- start: Date;
784
- end: Date;
785
- }
786
- ```
787
- </details>
788
-
789
- <details>
790
- <summary><strong>Pancha Anga</strong> — TithiInfo, NakshatraInfo, YogaInfo, KaranaInfo, VaraInfo</summary>
720
+ interface GeoLocation { latitude: number; longitude: number; elevation?: number; }
721
+ interface TimePeriod { start: Date; end: Date; }
791
722
 
792
- ```typescript
793
723
  interface TithiInfo {
794
724
  index: number; // 0-29
795
- name: string; // e.g. "Shukla Pratipada"
725
+ name: string;
796
726
  paksha: string; // "Shukla"/"Krishna" (en), "शुक्ल"/"कृष्ण" (hi)
797
727
  number: number; // 1-15 within the paksha
798
728
  completionPercentage: number;
799
729
  endTime: Date | null;
800
730
  }
801
-
802
- interface NakshatraInfo {
803
- index: number; // 0-26
804
- name: string;
805
- pada: number; // 1-4
806
- degreesInNakshatra: number;
807
- completionPercentage: number;
808
- endTime: Date | null;
809
- }
810
-
811
- interface DailyTithiInfo extends TithiInfo {
812
- startTime: Date | null; // null when isActiveAtSunrise is true
813
- isActiveAtSunrise: boolean;
814
- }
815
-
816
- // DailyNakshatraInfo, DailyYogaInfo, DailyKaranaInfo follow the same pattern.
731
+ // NakshatraInfo, YogaInfo, KaranaInfo follow the same pattern.
732
+ // DailyTithiInfo extends with startTime + isActiveAtSunrise.
817
733
 
818
734
  interface VaraInfo {
819
- index: number; // 0 = Sunday ... 6 = Saturday
820
- name: string; // e.g. "Raviwara" (localized)
821
- shortName: string; // e.g. "Ravi" (localized)
822
- englishName: string; // e.g. "Sunday" (always English)
823
- }
824
-
825
- interface KaranaInfo {
826
- index: number;
827
- name: string;
828
- completionPercentage: number;
829
- endTime: Date | null;
830
- type: 'fixed' | 'movable';
831
- }
832
-
833
- // endTime / startTime are null when computeEndTimes: false.
834
- ```
835
- </details>
836
-
837
- <details>
838
- <summary><strong>Lunar Calendar</strong> — ChandraMasaInfo, SamvatInfo, MasaInfo, RashiInfo</summary>
839
-
840
- ```typescript
841
- interface ChandraMasaInfo {
842
- index: number; // 0 = Chaitra ... 11 = Phalguna (in the active system)
843
- name: string; // follows masaSystem option
844
- isAdhika: boolean; // true = leap/intercalary month
845
- system: 'purnimanta' | 'amanta';
846
- amantaIndex: number;
847
- amantaName: string;
848
- purnimantaIndex: number;
849
- purnimantaName: string;
850
- }
851
-
852
- interface SamvatInfo {
853
- vikramSamvat: number; // e.g. 2081
854
- shakaSamvat: number; // e.g. 1946
855
- }
856
-
857
- interface MasaInfo {
858
- index: number; // 0 = Mesha ... 11 = Meena (solar month)
859
- name: string;
860
- }
861
-
862
- interface RashiInfo {
863
- index: number; // 0 = Mesha ... 11 = Meena
864
- name: string;
865
- }
866
- ```
867
- </details>
868
-
869
- <details>
870
- <summary><strong>Time Slots</strong> — Choghadiya, Gowri, Hora, Do Ghati</summary>
871
-
872
- ```typescript
873
- type ChoghadiyaQuality = 'auspicious' | 'inauspicious' | 'neutral';
874
-
875
- interface ChoghadiyaSlot extends TimePeriod {
876
- index: number;
877
- name: string; // e.g. "Amrit", "Kaal" (localized)
878
- quality: ChoghadiyaQuality;
879
- qualityName: string; // localized: "Auspicious", "शुभ"
880
- }
881
-
882
- interface ChoghadiyaInfo {
883
- day: ChoghadiyaSlot[]; // 8 slots (sunrise -> sunset)
884
- night: ChoghadiyaSlot[]; // 8 slots (sunset -> next sunrise)
885
- }
886
-
887
- // GowriSlot / GowriInfo mirror Choghadiya.
888
-
889
- interface HoraSlot extends TimePeriod {
890
- planet: string; // "Sun", "Venus", "Mercury", ...
891
- planetIndex: number; // 0-6 in Chaldean order
892
- }
893
-
894
- interface HoraInfo {
895
- day: HoraSlot[]; // 12 slots (sunrise -> sunset)
896
- night: HoraSlot[]; // 12 slots (sunset -> next sunrise)
897
- }
898
-
899
- interface DoGhatiInfo {
900
- day: DoGhatiSlot[]; // 15 ~48-min deity-keyed slots
901
- night: DoGhatiSlot[]; // 15 ~48-min deity-keyed slots
902
- }
903
- ```
904
- </details>
905
-
906
- <details>
907
- <summary><strong>Special Yogas & Festivals</strong></summary>
908
-
909
- ```typescript
910
- interface SpecialYogaInfo {
911
- name: string;
912
- type:
913
- | 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya'
914
- | 'dwipushkar' // Bhadra-tithi + vara + nakshatra ∈ {Mrig, Chitra, Dhan} — doubled
915
- | 'tripushkar' // same Bhadra rules + nakshatra ∈ {Krit, Punar, U.Phal, Vish, U.Ash, P.Bhad} — tripled
916
- | 'jwalamukhi' // inauspicious — tithi × nakshatra (Muhurta-chintamani 6.32)
917
- | 'aadal' // auspicious — Moon-from-Sun nakshatra distance
918
- | 'vidaal' // inauspicious — Moon-from-Sun nakshatra distance
919
- | 'ravi'; // auspicious — Moon-from-Sun nakshatra distance (27-scheme)
735
+ index: number; // 0 = Sunday 6 = Saturday
736
+ name: string; // localized (e.g. "Raviwara")
737
+ shortName: string;
738
+ englishName: string; // always English
920
739
  }
921
740
 
922
741
  interface FestivalInfo {
923
742
  name: string;
924
- type:
925
- | 'major' | 'minor'
926
- | 'ekadashi' | 'smarta_ekadashi' | 'vaishnava_ekadashi'
927
- | 'pradosha' | 'sankranti' | 'eclipse';
743
+ type: 'major' | 'minor' | 'ekadashi' | 'smarta_ekadashi' | 'vaishnava_ekadashi'
744
+ | 'pradosha' | 'sankranti' | 'eclipse';
928
745
  description?: string;
929
- /** Smarta-only: when Ekadashi is Dashami-viddha, the Dwadashi fast date. */
930
- deferralDate?: Date;
746
+ deferralDate?: Date; // Smarta Ekadashi Dwadashi fast date
931
747
  }
932
748
 
933
749
  type FestivalRegion =
934
- | 'all' // default — emits every regional variant
935
- // South
750
+ | 'all'
936
751
  | 'tamil-nadu' | 'kerala' | 'karnataka' | 'andhra-pradesh' | 'telangana'
937
- // East
938
752
  | 'west-bengal' | 'odisha' | 'assam' | 'bihar' | 'jharkhand'
939
- // West
940
753
  | 'gujarat' | 'maharashtra' | 'goa' | 'rajasthan'
941
- // North / Central
942
754
  | 'punjab' | 'haryana' | 'himachal-pradesh' | 'uttarakhand'
943
755
  | 'uttar-pradesh' | 'madhya-pradesh'
944
- // Neighbour
945
756
  | 'nepal';
946
757
 
947
- // Pre-v2.1 identifiers accepted with a one-shot deprecation warning. Removed in v3.
948
- // 'tamil' → 'tamil-nadu'
949
- // 'bengal' → 'west-bengal'
950
- // 'north-india' → 'all'
951
- type LegacyFestivalRegion = 'tamil' | 'bengal' | 'north-india';
758
+ // Legacy slugs accepted (mapped internally): 'tamil' 'tamil-nadu',
759
+ // 'bengal' → 'west-bengal', 'north-india' → 'all'.
952
760
  ```
953
761
 
954
- **Region-scoped festivals** (non-exhaustive):
955
-
956
- | Region | Festival names (keys) |
957
- |---|---|
958
- | `tamil-nadu` | pongal, puthandu, varamahalakshmi |
959
- | `kerala` | vishu, ayyappa_makara_jyothi, onam |
960
- | `karnataka` | karaga, varamahalakshmi |
961
- | `andhra-pradesh` | varamahalakshmi |
962
- | `telangana` | bonalu, varamahalakshmi, bathukamma_start, bathukamma_saddula |
963
- | `west-bengal` | pohela_boishakh, bhai_dooj |
964
- | `odisha` | singh_sankranti, raja_pahili, raja_sankranti, raja_basi |
965
- | `assam` | bohag_bihu, magh_bihu, kati_bihu |
966
- | `bihar` | singh_sankranti, hariyali_teej, govardhan_puja, bhai_dooj |
967
- | `gujarat` | uttarayan, govardhan_puja, bhai_dooj |
968
- | `maharashtra` | gudi_padwa, hartalika_teej, bhai_dooj |
969
- | `goa` | gudi_padwa |
970
- | `rajasthan` | gangaur, hariyali_teej, kajari_teej, hartalika_teej, govardhan_puja, bhai_dooj |
971
- | `punjab` | baisakhi, lohri, govardhan_puja |
972
- | `haryana` | baisakhi, lohri, govardhan_puja, bhai_dooj |
973
- | `himachal-pradesh` | sair, phagli, lohri |
974
- | `uttarakhand` | harela |
975
- | `uttar-pradesh` | hariyali_teej, kajari_teej, hartalika_teej, govardhan_puja, bhai_dooj |
976
- | `madhya-pradesh` | hariyali_teej, kajari_teej, hartalika_teej |
977
- | `nepal` | singh_sankranti, bhai_dooj |
978
762
  </details>
979
763
 
980
764
  <details>
981
- <summary><strong>Eclipses (Grahan)</strong> — EclipseInfo</summary>
765
+ <summary><strong>Eclipses & Bhadra</strong></summary>
982
766
 
983
767
  ```typescript
984
- type EclipseSubtype = 'partial' | 'total' | 'annular' | 'penumbral';
985
-
986
768
  interface EclipseInfo {
987
769
  kind: 'solar' | 'lunar';
988
- subtype: EclipseSubtype;
989
- start: Date; // UTC observable phase begins
990
- peak: Date; // UTC — greatest eclipse
991
- end: Date; // UTC — observable phase ends
770
+ subtype: 'partial' | 'total' | 'annular' | 'penumbral';
771
+ start: Date; peak: Date; end: Date;
992
772
  visibleFromLocation: boolean;
993
- magnitude: number; // fraction of disc obscured at peak, [0, 1]
994
- sutakStart: Date; // 12 h before solar / 9 h before lunar
995
- sutakEnd: Date; // coincides with eclipse end (moksha)
773
+ magnitude: number; // [0, 1] at peak
774
+ sutakStart: Date; // 12 h pre-solar / 9 h pre-lunar
775
+ sutakEnd: Date;
996
776
  description: string;
997
777
  }
998
- ```
999
- </details>
1000
-
1001
- <details>
1002
- <summary><strong>Bhadra Kala</strong> — BhadraInfo</summary>
1003
778
 
1004
- ```typescript
1005
779
  interface BhadraInfo {
1006
- start: Date;
1007
- end: Date;
1008
- /** 'earth' = malefic for all work; 'heaven' / 'paatal' = non-terrestrial, milder. */
1009
- location: 'earth' | 'heaven' | 'paatal';
1010
- /** True when Bhadra is active at some point during the Hindu day window. */
780
+ start: Date; end: Date;
781
+ location: 'earth' | 'heaven' | 'paatal'; // 'earth' = malefic for all work
1011
782
  isActive: boolean;
1012
783
  }
1013
784
  ```
785
+
1014
786
  </details>
1015
787
 
1016
788
  <details>
1017
- <summary><strong>Jyotish</strong> — Graha positions, Vimshottari Dasha, Chandra Balam, Tarabala</summary>
789
+ <summary><strong>Jyotish</strong></summary>
1018
790
 
1019
791
  ```typescript
1020
792
  type GrahaName = 'Sun' | 'Moon' | 'Mars' | 'Mercury' | 'Jupiter'
@@ -1022,49 +794,44 @@ type GrahaName = 'Sun' | 'Moon' | 'Mars' | 'Mercury' | 'Jupiter'
1022
794
 
1023
795
  interface GrahaPosition {
1024
796
  planet: GrahaName;
1025
- siderealLongitude: number; // degrees [0, 360)
797
+ siderealLongitude: number;
1026
798
  rashi: RashiInfo;
1027
- degreeInRashi: number; // [0, 30)
799
+ degreeInRashi: number;
1028
800
  nakshatra: NakshatraInfo;
1029
- isRetrograde: boolean; // always false for Sun/Moon; always true for Rahu/Ketu
1030
- }
1031
-
1032
- interface PlanetaryPositions {
1033
- sun: GrahaPosition; moon: GrahaPosition; mars: GrahaPosition;
1034
- mercury: GrahaPosition; jupiter: GrahaPosition; venus: GrahaPosition;
1035
- saturn: GrahaPosition; rahu: GrahaPosition; ketu: GrahaPosition;
801
+ isRetrograde: boolean; // always false for Sun/Moon; always true for Rahu/Ketu
1036
802
  }
1037
803
 
1038
804
  type DashaLord = 'Ketu' | 'Venus' | 'Sun' | 'Moon' | 'Mars'
1039
805
  | 'Rahu' | 'Jupiter' | 'Saturn' | 'Mercury';
1040
806
 
1041
- interface AntarDasha { lord: DashaLord; startDate: Date; endDate: Date; }
1042
- interface MahaDasha { lord: DashaLord; startDate: Date; endDate: Date;
1043
- years: number; antarDashas: AntarDasha[]; }
807
+ interface MahaDasha { lord: DashaLord; startDate: Date; endDate: Date;
808
+ years: number; antarDashas: AntarDasha[]; }
1044
809
  interface VimshottariDashaResult {
1045
810
  currentMahaDashaLord: DashaLord;
1046
811
  currentIndex: number;
1047
- mahaDashas: MahaDasha[]; // 9-entry sequence starting from birth
812
+ mahaDashas: MahaDasha[];
1048
813
  }
1049
814
 
1050
815
  interface ChandraBalamInfo {
1051
- house: number; // 1 = janma rashi; 12 = rashi before janma
1052
- quality: 'strong' | 'weak'; // Shubha houses = 1,3,6,7,10,11
1053
- englishName: string; // "Shubha" | "Ashubha"
1054
- name: string; // localized
816
+ house: number; // 1 = janma rashi; 12 = rashi before janma
817
+ quality: 'strong' | 'weak'; // Shubha houses = 1,3,6,7,10,11
818
+ englishName: string; // "Shubha" | "Ashubha"
819
+ name: string;
1055
820
  }
1056
821
 
1057
822
  interface TarabalaInfo {
1058
- taraIndex: number; // 0..8 in the 9-tara cycle from janma nakshatra
1059
- englishName: string; // "Janma" | "Sampat" | "Vipat" | "Kshema" | "Pratyari"
1060
- // | "Sadhaka" | "Vadha" | "Mitra" | "Ati-Mitra"
823
+ taraIndex: number; // 0..8 in 9-tara cycle from janma nakshatra
824
+ englishName: string; // Janma | Sampat | Vipat | Kshema | Pratyari
825
+ // | Sadhaka | Vadha | Mitra | Ati-Mitra
1061
826
  name: string;
1062
827
  quality: 'auspicious' | 'inauspicious';
1063
828
  }
1064
829
  ```
830
+
1065
831
  </details>
1066
832
 
1067
- ### Full export list
833
+ <details>
834
+ <summary><strong>Full export list</strong></summary>
1068
835
 
1069
836
  ```typescript
1070
837
  // Primary entry points
@@ -1085,15 +852,29 @@ computeMadhyahna, computePratahSandhya, computeSayahnaSandhya
1085
852
  // Eclipses
1086
853
  getUpcomingSolarEclipse, getUpcomingLunarEclipse, getEclipseDuringDay
1087
854
 
1088
- // Jyotish
855
+ // Jyotish — planets, dashas, transits
1089
856
  computePlanetaryPositions, GRAHA_ABBR
1090
857
  computeVimshottariDasha, computeVimshottariDashaFromBirth, computeVimshottariPratyantar
1091
- computeAshtottariDasha, computeYoginiDasha, computeCharaDasha
1092
- computeChandraBalam, computeTarabala
858
+ computeAshtottariDasha, computeYoginiDasha, computeCharaDasha, computeNarayanDasha
859
+ computeChandraBalam, computeTarabala, computeSadeSati
860
+
861
+ // Jyotish — chart
1093
862
  computeLagna, computeBhava, computeRashiChart, computeNavamsa, computeDivisionalChart
1094
- computeAspects, computeShadbala
1095
- computeAshtakoot, computeMangalDosha, computeKaalSarp, computePitruDosha
1096
- computeSadeSati, computeDignity
863
+ computeHoraLagna, computeGhatiLagna, computeBhavaLagna, computeSripatiLagna
864
+ computeDignity
865
+
866
+ // Jyotish — strength, yogas, sensitive
867
+ computeAspects, computeShadbala, computeBhavaBala, computeAshtakavarga
868
+ computeYogas, computeJaiminiKarakas
869
+ computeVarshaphala, computeTithiPravesha, computeArudhas, computeUpagrahas, computeArgala
870
+
871
+ // Jyotish — compatibility, doshas
872
+ computeAshtakoot, computePathuPorutham
873
+ computeMangalDosha, computeKaalSarp, computePitruDosha
874
+
875
+ // KP / Prashna
876
+ computeKpSubLord, computeKpCuspalSubLords, computeKpSignificators
877
+ computePrashnaChart
1097
878
 
1098
879
  // Muhurta engine
1099
880
  scoreMuhurta, findAuspiciousDates, STOCK_MUHURTA_RULES
@@ -1110,31 +891,31 @@ getEkadashiDatesForYear, getSankrantisForYear, getFestivalsInRange, getUpcomingE
1110
891
  PanchangError
1111
892
  ```
1112
893
 
894
+ </details>
895
+
1113
896
  ---
1114
897
 
1115
898
  ## React Native / Hermes
1116
899
 
1117
- Works with Expo and bare React Native (Hermes engine). Pass `timezone` as a **number** —
1118
- IANA timezone strings (`'Asia/Kolkata'`) require `Intl`, which older Hermes versions don't
1119
- fully support.
900
+ Works with Expo and bare React Native (Hermes engine). Pass `timezone` as a
901
+ **number** — IANA strings need `Intl`, which older Hermes versions lack.
1120
902
 
1121
- **Two-pass rendering** for smooth UI:
903
+ Two-pass rendering pattern for smooth UI:
1122
904
 
1123
905
  ```typescript
1124
906
  import { getDailyPanchang } from 'panchang-ts';
1125
907
  import { InteractionManager } from 'react-native';
1126
908
 
1127
- // Pass 1 — instant, names only (~0.1 ms on Node, <100 ms on Hermes)
909
+ // Pass 1 — instant, names only (~0.1 ms Node, <100 ms Hermes)
1128
910
  const fast = getDailyPanchang(date, location, {
1129
911
  timezone: 330,
1130
912
  computeEndTimes: false,
1131
913
  });
1132
- setState(fast); // show names immediately
914
+ setState(fast);
1133
915
 
1134
- // Pass 2 — background, full with end-times (~0.5 ms on Node, <500 ms on Hermes)
916
+ // Pass 2 — background, full with end-times (~0.5 ms Node, <500 ms Hermes)
1135
917
  InteractionManager.runAfterInteractions(() => {
1136
- const full = getDailyPanchang(date, location, { timezone: 330 });
1137
- setState(full); // update with transition times
918
+ setState(getDailyPanchang(date, location, { timezone: 330 }));
1138
919
  });
1139
920
  ```
1140
921
 
@@ -1142,66 +923,54 @@ InteractionManager.runAfterInteractions(() => {
1142
923
 
1143
924
  ## Accuracy
1144
925
 
1145
- 7,156 tests passing across 81 files, including fixtures cross-verified against reference
1146
- panchang calculations spanning 2025–2026 across 10 Indian cities, plus New York, London,
1147
- Sydney, Dubai, and Singapore (diaspora fixtures cover DST transitions on
926
+ 8,103 tests across 96 files, including fixtures cross-verified against reference
927
+ panchang calculations spanning 2025–2026 across 10 Indian cities plus New York,
928
+ London, Sydney, Dubai, Singapore (diaspora fixtures cover DST on
1148
929
  `America/New_York`).
1149
930
 
1150
- | Element | Accuracy | Validation |
1151
- |---------|----------|------------|
1152
- | Sunrise / Sunset | ≤29 s observed vs reference minute-midpoint (±45 s tolerance) | 16 assertions |
1153
- | Moonrise / Moonset | Meeus apparent-upper-limb (refraction + parallax); ~3–5 min vs simpler-horizon authorities is expected | Strict fixtures |
1154
- | Tithi, Nakshatra, Yoga, Karana names | Exact match vs reference | Strict fixtures |
1155
- | Tithi / Nakshatra / Yoga / Karana end-times | ±3 min tolerance, max 2.01 min observed | 20 assertions |
1156
- | Ayanamsa | ±0.005° vs Swiss Ephemeris | Unit tests |
1157
- | Planetary positions (Sun–Saturn) | ±0.02° vs reference sidereal | Fixtures |
1158
- | Planetary positions (Rahu/Ketu, mean node) | ≤0.5° typical; ±2° tolerance | Fixtures |
1159
- | Planetary positions (Rahu/Ketu, true node) | ≤0.6° typical (Meeus periodic correction) | Fixtures |
1160
- | Rashi / Nakshatra / Retrograde flag | Exact match vs reference | Fixtures |
1161
- | Festival dates | 12 cross-verified festivals (2025–2026) see caveats below | Fixtures |
1162
- | Choghadiya / Hora / Gowri slots | Derived from sunrise/sunset inherits ±2 min | |
1163
- | Madhyahna midpoint, Anandadi Yoga, Ganda Mula active flag | Exact match across 50 reference fixtures | Cross-verify suite |
1164
- | Pratah / Sayahna Sandhya start + end | ±2 min across all 50 fixtures | Cross-verify suite |
1165
- | Varjyam start + end | ±2 min on every emit (transition days return `null` by design) | Cross-verify suite |
1166
- | Lagna sidereal longitude | Cross-checked against Jagannath Hora reference charts | Birth-chart fixtures |
1167
- | D1 (Rashi) & D9 (Navamsa) house placements | Exact match vs reference for 9-graha placement | Birth-chart fixtures |
1168
- | Ashtakoot Guna Milan total score | ±1 point per pair across 30+ matched pairs | Match fixtures |
1169
- | Sade Sati arc start / end | ±1–2 days vs authoritative ephemerides | Saturn-transit fixtures |
1170
-
1171
- **Detection sourcing notes.** **Aadal / Vidaal** follow the classical Moon-from-Sun
1172
- nakshatra-distance rule (AstroShastra, HoraSarvam, Ernst Wilhelm), NOT the popular
1173
- Tamil-Vakya weekday rule used by some online panchangs — output may differ from sites that
1174
- use the weekday rule. **Varjyam** emits the sunrise-anchored nakshatra's window only —
1175
- printed panchangs may show a second window on nakshatra-transition days. **Do Ghati
1176
- Muhurta** does not rotate by weekday: the same 30-name deity-keyed sequence applies every
1177
- day, verified against multiple reference sources for distinct weekdays.
931
+ | Element | Accuracy |
932
+ |---|---|
933
+ | Sunrise / Sunset | ≤29 s observed vs reference minute-midpoint (±45 s tolerance) |
934
+ | Moonrise / Moonset | Meeus apparent-upper-limb (refraction + parallax); ~3–5 min vs simpler-horizon authorities is expected |
935
+ | Tithi / Nakshatra / Yoga / Karana names | Exact match vs reference |
936
+ | Tithi / Nakshatra / Yoga / Karana end-times | ±3 min tolerance, max 2.01 min observed |
937
+ | Ayanamsa | ±0.005° vs Swiss Ephemeris |
938
+ | Planetary positions (Sun–Saturn) | ±0.02° sidereal |
939
+ | Planetary positions (Rahu/Ketu, mean node) | ≤0.5° typical; ±2° tolerance |
940
+ | Planetary positions (Rahu/Ketu, true node) | ≤0.6° typical (Meeus periodic correction) |
941
+ | Lagna sidereal longitude | Cross-checked against Jagannath Hora reference charts |
942
+ | D1 / D9 house placement | Exact match vs reference for 9-graha placement |
943
+ | Ashtakoot total | ±1 point per pair across 30+ matched pairs |
944
+ | Sade Sati arc start/end | ±1–2 days vs authoritative ephemerides |
945
+
946
+ **Detection notes.** **Aadal / Vidaal** follow the classical Moon-from-Sun
947
+ nakshatra-distance rule (AstroShastra, HoraSarvam, Ernst Wilhelm), NOT the
948
+ Tamil-Vakya weekday rule used by some online panchangs. **Varjyam** emits the
949
+ sunrise-anchored nakshatra's window only. **Do Ghati Muhurta** does not rotate
950
+ by weekday the same 30-name deity-keyed sequence applies every day.
1178
951
 
1179
952
  ### Festival Detection — Documented Tradeoff
1180
953
 
1181
- The library uses **tithi-at-sunrise** to resolve a festival to a calendar day. Some
1182
- traditional panchang authorities apply other classical rules (tithi-at-midnight,
1183
- madhyahna-vyapini, kshaya-tithi handling) for certain festivals; where those rules pick a
1184
- different day, our output can drift ±1 day. This is a rule-choice tradeoff, not a
1185
- computation bug.
954
+ The library uses **tithi-at-sunrise** to resolve a festival to a calendar day.
955
+ Some authorities use other classical rules for certain festivals; where those
956
+ rules pick a different day, output can drift ±1 day:
1186
957
 
1187
- | Alternative classical rule | Festivals affected |
1188
- |----------------------------|--------------------|
958
+ | Alternative rule | Affects |
959
+ |---|---|
1189
960
  | Tithi-at-midnight | Krishna Janmashtami, Maha Shivaratri, Diwali / Lakshmi Puja |
1190
- | Madhyahna-vyapini (tithi overlapping noon) | Ganesh Chaturthi on edge years, Akshaya Tritiya 2026 |
1191
- | Kshaya-tithi handling (tithi never at sunrise) | Ugadi 2026-03-19 (Pratipada is Kshaya) |
961
+ | Madhyahna-vyapini | Ganesh Chaturthi (edge years), Akshaya Tritiya 2026 |
962
+ | Kshaya-tithi handling | Ugadi 2026-03-19 (Pratipada is Kshaya) |
1192
963
 
1193
- If strict parity with a specific panchang authority matters for your use case, cross-check
1194
- the above festival set for the target year. Everything else — Holi, Ugadi (non-Kshaya
1195
- years), Rama Navami, Raksha Bandhan, Ganesh Chaturthi (normal years), Navaratri,
1196
- Dussehra, Karva Chauth, Hanuman Jayanti — matches the canonical date across 2025 and 2026
1197
- fixtures.
964
+ Everything else Holi, Ugadi (non-Kshaya years), Rama Navami, Raksha Bandhan,
965
+ Ganesh Chaturthi (normal years), Navaratri, Dussehra, Karva Chauth, Hanuman
966
+ Jayanti matches the canonical date across 2025 and 2026 fixtures.
1198
967
 
1199
968
  ---
1200
969
 
1201
970
  ## Performance
1202
971
 
1203
972
  | Mode | Node.js | Hermes (budget Android) |
1204
- |------|---------|------------------------|
973
+ |---|---|---|
1205
974
  | Names-only (`computeEndTimes: false`) | ~0.1 ms | <100 ms |
1206
975
  | Full with end-times | ~0.5 ms | <500 ms |
1207
976
 
@@ -1219,40 +988,42 @@ try {
1219
988
  getDailyPanchang(date, location, options);
1220
989
  } catch (e) {
1221
990
  if (e instanceof PanchangError) {
1222
- console.error(e.code); // e.g. 'INVALID_LATITUDE', 'INVALID_TIMEZONE'
991
+ console.error(e.code); // e.g. 'INVALID_LATITUDE', 'INVALID_TIMEZONE'
1223
992
  console.error(e.message);
1224
993
  }
1225
994
  }
1226
995
  ```
1227
996
 
1228
- Error codes: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`, `INVALID_ELEVATION`,
1229
- `INVALID_TIMEZONE`, `INVALID_AYANAMSA`, `TIMEZONE_RESOLUTION_FAILED`, `NO_SUNRISE`,
1230
- `NO_SUNSET`, `SEARCH_DIVERGED`, `CIRCUMPOLAR` (Placidus-KP houses above ±66.5°).
997
+ Error codes: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`,
998
+ `INVALID_ELEVATION`, `INVALID_TIMEZONE`, `INVALID_AYANAMSA`,
999
+ `TIMEZONE_RESOLUTION_FAILED`, `NO_SUNRISE`, `NO_SUNSET`, `SEARCH_DIVERGED`,
1000
+ `CIRCUMPOLAR` (Placidus-KP houses above ±66.5°).
1231
1001
 
1232
- **Polar locations (no sunrise / no sunset):** `getDailyPanchang` and `getInstantPanchang`
1233
- return `null` rather than throwing — the Hindu day is undefined when sunrise can't be
1002
+ **Polar locations.** `getDailyPanchang` and `getInstantPanchang` return `null`
1003
+ rather than throwing — the Hindu day is undefined when sunrise can't be
1234
1004
  computed. The low-level `getSunrise` / `getSunset` primitives still throw
1235
- `PanchangError(NO_SUNRISE)` / `PanchangError(NO_SUNSET)` for direct callers who need the
1236
- precise reason. `getMoonrise` / `getMoonset` return `null` (normal for the Moon).
1005
+ `PanchangError(NO_SUNRISE)` / `PanchangError(NO_SUNSET)` for direct callers
1006
+ who need the precise reason. `getMoonrise` / `getMoonset` return `null` (normal
1007
+ for the Moon).
1237
1008
 
1238
1009
  ---
1239
1010
 
1240
1011
  ## Compatibility
1241
1012
 
1242
1013
  | Environment | Support |
1243
- |-------------|---------|
1014
+ |---|---|
1244
1015
  | Node.js 18+ | Supported |
1245
1016
  | React Native (Hermes) | Supported (pass `timezone` as number) |
1246
1017
  | Expo (managed + bare) | Supported |
1247
- | Browser (modern) | Supported (ESM build) |
1018
+ | Browser (modern, ESM) | Supported |
1248
1019
  | Browser (legacy / IE) | Not supported |
1249
1020
 
1250
1021
  ---
1251
1022
 
1252
1023
  ## Acknowledgements
1253
1024
 
1254
- [astronomy-engine](https://github.com/cosinekitty/astronomy) by Don Cross — the sole
1255
- runtime dependency. MIT licensed.
1025
+ [astronomy-engine](https://github.com/cosinekitty/astronomy) by Don Cross — the
1026
+ sole runtime dependency. MIT licensed.
1256
1027
 
1257
1028
  ## License
1258
1029