panchang-ts 2.4.0 → 3.0.1

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
@@ -2,30 +2,10 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/panchang-ts)](https://www.npmjs.com/package/panchang-ts)
4
4
 
5
- Pure TypeScript Hindu Panchang (almanac) calculations. Zero native dependencies.
6
- Works offline in React Native (Hermes), Node.js, and browsers.
5
+ Pure TypeScript Hindu Panchang (almanac), Jyotish, and Birth Chart calculations.
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)
9
-
10
- ---
11
-
12
- ## Table of Contents
13
-
14
- - [Install](#install)
15
- - [Quick Start](#quick-start)
16
- - [Features](#features)
17
- - [API Reference](#api-reference)
18
- - [`getDailyPanchang`](#getdailypanchangdate-location-options)
19
- - [`getInstantPanchang`](#getinstantpanchangdate-location-options)
20
- - [When to use `getInstantPanchang` vs `getDailyPanchang`](#when-to-use-getinstantpanchang-vs-getdailypanchang)
21
- - [Options](#options)
22
- - [Low-level Utilities](#low-level-utilities)
23
- - [Types](#types)
24
- - [React Native / Hermes](#react-native--hermes)
25
- - [Accuracy](#accuracy)
26
- - [Performance](#performance)
27
- - [Error Handling](#error-handling)
28
- - [Compatibility](#compatibility)
8
+ **Fast** (~0.1 ms names-only, ~0.5 ms full) | **Typed** (full TypeScript types) | **Offline** (pure JS math, no network) | **6,912 tests**
29
9
 
30
10
  ---
31
11
 
@@ -39,6 +19,41 @@ pnpm add panchang-ts
39
19
  yarn add panchang-ts
40
20
  ```
41
21
 
22
+ ---
23
+
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 (Rashi), D9 (Navamsa), Planetary Dignity | [↓](#14-birth-chart-kundli) |
45
+ | **Compatibility & Doshas** | Ashtakoot Guna Milan (36-point), Mangal Dosha (Manglik) | [↓](#15-compatibility--doshas) |
46
+ | **Localization** | English + Hindi (Devanagari) on every returned name | [↓](#16-localization) |
47
+ | **Configuration** | 5 ayanamsas (Lahiri, Raman, KP, True Chitrapaksha, Thirukanitham), 2 masa systems, 3 house systems, 21 regional festival scopes | [↓](#17-configuration) |
48
+
49
+ ---
50
+
51
+ ## Used By
52
+
53
+ - [dharmagya.app](https://dharmagya.app) — Daily Panchang and Hindu calendar
54
+
55
+ ---
56
+
42
57
  ## Quick Start
43
58
 
44
59
  ```typescript
@@ -52,57 +67,17 @@ const result = getDailyPanchang(
52
67
  // result is `DailyPanchangResult | null` — null only at polar latitudes
53
68
  // where sunrise can't be computed. Anywhere else, narrow with `if (!result) return;`
54
69
 
55
- // Pancha Anga
56
70
  console.log(result.tithis[0].name); // "Krishna Chaturdashi"
57
71
  console.log(result.nakshatras[0].name); // "Mrigashira"
58
72
  console.log(result.vara.name); // "Mangalawara"
59
-
60
- // Lunar calendar (Purnimanta by default)
61
73
  console.log(result.chandramasa.name); // "Magha"
62
- console.log(result.chandramasa.amantaName); // "Pausha" (South Indian)
63
74
  console.log(result.samvat.vikramSamvat); // 2081
64
-
65
- // Zodiac
66
- console.log(result.chandraRashi.name); // "Mithuna" (Moon in Gemini)
67
- console.log(result.suryaNakshatra.name); // "Uttara Ashadha"
68
-
69
- // Astronomical events
70
- console.log(result.sunrise); // Date (read via getUTC*)
71
- console.log(result.moonrise); // Date | null
72
-
73
- // Muhurta & inauspicious periods
74
- console.log(result.brahmaMuhurta); // { start: Date, end: Date }
75
- console.log(result.madhyahna); // solar noon ±24 min
76
- console.log(result.rahuKalam); // { start: Date, end: Date }
77
- console.log(result.anandadiYoga.name); // "Ananda" (Vara × Nakshatra cycle)
78
- console.log(result.gandaMula.active); // false (or true with severity)
79
- console.log(result.varjyam); // { start, end } | null
80
-
81
- // Choghadiya — 8 daytime slots
82
- result.choghadiya.day.forEach(slot => {
83
- console.log(slot.name, slot.qualityName); // "Amrit", "Auspicious"
84
- });
85
-
86
- // Gowri Panchangam — 8 daytime slots
87
- result.gowriPanchangam.day.forEach(slot => {
88
- console.log(slot.name, slot.qualityName); // "Amrit", "Auspicious"
89
- });
90
-
91
- // Special Yogas active today
92
- result.specialYogas.forEach(yoga => {
93
- console.log(yoga.name, yoga.type); // "Guru Pushya Yoga", "guru_pushya"
94
- });
95
-
96
- // Festivals today
97
- result.festivals.forEach(f => {
98
- console.log(f.name, f.type); // "Makar Sankranti", "major"
99
- });
100
75
  ```
101
76
 
102
77
  ### Reading Output Times
103
78
 
104
- All `Date` objects in the result are **offset-adjusted** to the requested timezone.
105
- Always read time components via `getUTC*` methods:
79
+ All `Date` objects in the result are **offset-adjusted** to the requested timezone. Always
80
+ read time components via `getUTC*` methods — `.getHours()` would use your system zone:
106
81
 
107
82
  ```typescript
108
83
  const sunrise = result.sunrise;
@@ -110,7 +85,6 @@ const h = sunrise.getUTCHours(); // 7
110
85
  const m = sunrise.getUTCMinutes(); // 4
111
86
  // → Sunrise at 07:04 local time
112
87
 
113
- // Format helper:
114
88
  function fmt(d: Date) {
115
89
  const h = d.getUTCHours(), m = d.getUTCMinutes();
116
90
  return `${h}:${String(m).padStart(2, '0')}`;
@@ -118,368 +92,494 @@ function fmt(d: Date) {
118
92
  fmt(result.rahuKalam.start); // "09:04"
119
93
  ```
120
94
 
121
- Do **not** use `.getHours()` — it uses your system timezone, which may differ.
95
+ `moonrise` and `moonset` can be `null`the Moon occasionally does not rise or set on a
96
+ given calendar day, which is normal.
122
97
 
123
- `moonrise` and `moonset` can be `null` — the Moon occasionally does not rise or set
124
- on a given calendar day, which is normal.
98
+ ### `getDailyPanchang` vs `getInstantPanchang`
125
99
 
126
- ### Language & Masa System
100
+ | Use case | Recommended | Why |
101
+ |----------|-------------|-----|
102
+ | "What Panchang elements are active right now?" | `getInstantPanchang` | Single-moment snapshot; no sunrise needed |
103
+ | Birth chart / muhurta picking at a specific instant | `getInstantPanchang` | Exact element at that UTC moment |
104
+ | Daily calendar / almanac row for a date | `getDailyPanchang` | Lists all element transitions for the day |
105
+ | Today's festivals & observances | `getDailyPanchang` | Full canonical-time festival refinement |
106
+ | Rahu Kalam / Choghadiya / Gowri / Hora / muhurtas | `getDailyPanchang` | Computed from sunrise, sunset, day length |
107
+ | Eclipse detection with sutak window | `getDailyPanchang` | Overlapping the day needs the day window |
108
+
109
+ `getInstantPanchang` does emit `festivals`, but evaluates rules against the elements at the
110
+ given instant only. It does not run canonical-time refinements (madhyahna / pradosha /
111
+ nishita / chandrodaya), transit-based Sankranti, Ekadashi viddha (Smarta/Vaishnava split),
112
+ or Bhadra-aware Raksha Bandhan exclusion. For reliable festival dating, use
113
+ `getDailyPanchang`.
114
+
115
+ ---
116
+
117
+ # Feature Reference
118
+
119
+ Each section below shows how to access one feature category. Every feature is also
120
+ returned as a field on the unified `DailyPanchangResult` from `getDailyPanchang(…)` if you
121
+ prefer one call over the per-feature helpers.
122
+
123
+ ## 1. Pancha Anga — the Five Limbs
124
+
125
+ Tithi, Nakshatra, Yoga, Karana, Vara — with start / end times for every transition during
126
+ the Hindu day.
127
127
 
128
128
  ```typescript
129
- // Hindi names (Devanagari)
130
- const hi = getDailyPanchang(date, location, {
131
- timezone: 330,
132
- language: 'hi',
133
- });
134
- console.log(hi.tithis[0].name); // "कृष्ण चतुर्दशी"
135
- console.log(hi.vara.name); // "मंगलवार"
129
+ import { getDailyPanchang } from 'panchang-ts';
136
130
 
137
- // Amanta (South Indian) masa system
138
- const amanta = getDailyPanchang(date, location, {
139
- timezone: 330,
140
- masaSystem: 'amanta',
131
+ const r = getDailyPanchang(date, location, { timezone: 330 })!;
132
+
133
+ // Tithis active during the day (usually 1-2)
134
+ r.tithis.forEach(t => {
135
+ console.log(t.name, t.paksha, t.completionPercentage, t.endTime);
141
136
  });
142
- console.log(amanta.chandramasa.name); // Amanta month name
143
- console.log(amanta.chandramasa.system); // "amanta"
144
- ```
145
137
 
146
- ### Regional Festival Filtering
138
+ // Nakshatras (with pada)
139
+ r.nakshatras.forEach(n => console.log(n.name, n.pada, n.endTime));
147
140
 
148
- The `region` option scopes regional festival variants to one Indian state.
149
- Pan-Indian festivals (Diwali, Holi, Raksha Bandhan, the canonical
150
- `sankranti` event, …) emit regardless.
141
+ // Yogas (27-name lunisolar cycle)
142
+ r.yogas.forEach(y => console.log(y.name, y.endTime));
143
+
144
+ // Karanas (half-tithi; usually 2-4 per day)
145
+ r.karanas.forEach(k => console.log(k.name, k.type, k.endTime));
146
+
147
+ // Vara (weekday)
148
+ console.log(r.vara.name, r.vara.englishName); // "Mangalawara", "Tuesday"
149
+ ```
150
+
151
+ For a single-instant snapshot use `getInstantPanchang`:
151
152
 
152
153
  ```typescript
153
- // Default every regional variant emits on Makar Sankranti day:
154
- const all = getDailyPanchang(jan14, chennai, { timezone: 330 });
155
- all.festivals.map(f => f.name);
156
- // → ["Sankranti", "Makar Sankranti", "Pongal", "Uttarayan",
157
- // "Magh Bihu", "Ayyappa Makara Jyothi"]
154
+ import { getInstantPanchang } from 'panchang-ts';
158
155
 
159
- // Scope to Tamil Nadu — drops Bihu/Ayyappa/Uttarayan:
160
- const tn = getDailyPanchang(jan14, chennai, { timezone: 330, region: 'tamil-nadu' });
161
- tn.festivals.map(f => f.name);
162
- // → ["Sankranti", "Makar Sankranti", "Pongal"]
156
+ const i = getInstantPanchang(new Date(), location)!;
157
+ console.log(i.tithi.name, i.nakshatra.name, i.yoga.name, i.karana.name, i.vara.name);
158
+ ```
163
159
 
164
- // Lohri fires on the Hindu day BEFORE Makara transit, scoped to Punjab/
165
- // Haryana/Himachal — no extra wiring required, just the region option:
166
- const lohri = getDailyPanchang(jan13, amritsar, { timezone: 330, region: 'punjab' });
167
- lohri.festivals.some(f => f.name === 'Lohri'); // true
160
+ ## 2. Lunar Calendar
168
161
 
169
- // Pre-v2.1 region values still work but log a one-shot deprecation warning:
170
- getDailyPanchang(date, loc, { timezone: 330, region: 'tamil' });
171
- // console.warn: [panchang-ts] FestivalRegion 'tamil' is deprecated;
172
- // use 'tamil-nadu'. Legacy value will be removed in v3.
162
+ Chandra Masa with **Purnimanta** (North Indian, default) and **Amanta** (South Indian)
163
+ naming, **Adhika** (leap-month) detection, **Vikram** and **Shaka** samvat year numbers.
164
+
165
+ ```typescript
166
+ const r = getDailyPanchang(date, loc, { timezone: 330, masaSystem: 'purnimanta' })!;
167
+
168
+ console.log(r.chandramasa.name); // "Magha" (active system)
169
+ console.log(r.chandramasa.amantaName); // "Pausha" (South Indian)
170
+ console.log(r.chandramasa.purnimantaName); // "Magha" (North Indian)
171
+ console.log(r.chandramasa.isAdhika); // false (true during leap months)
172
+
173
+ console.log(r.samvat.vikramSamvat); // 2081
174
+ console.log(r.samvat.shakaSamvat); // 1946
173
175
  ```
174
176
 
175
- See [`FestivalRegion`](#types) for the full state-slug list (21 states + `'nepal'`).
177
+ ## 3. Solar Calendar
176
178
 
177
- ---
179
+ Saura Masa (solar month), Surya Nakshatra (the Sun's nakshatra, ~13–14 day transit),
180
+ Sankranti (solar-month boundary, transit-based — emitted as a festival).
178
181
 
179
- ## Features
182
+ ```typescript
183
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
180
184
 
181
- ### Pancha Anga (5 Limbs)
182
- Tithi, Nakshatra, Yoga, Karana, Vara — with transition times throughout the day.
185
+ console.log(r.masa.name); // "Makara" (current solar month)
186
+ console.log(r.suryaNakshatra.name); // "Uttara Ashadha"
187
+ console.log(r.chandraRashi.name); // "Mithuna" (Moon sign)
183
188
 
184
- ### Lunar Calendar
185
- Chandra Masa with Adhika (leap month) detection, both **Purnimanta** (North Indian, default) and **Amanta** (South Indian) systems, Vikram Samvat, Shaka Samvat.
189
+ // Sankranti and its regional variants emit through r.festivals — see §9.
190
+ ```
186
191
 
187
- ### Muhurta & Auspicious Timing
188
- Brahma Muhurta, Abhijit Muhurta, Vijaya Muhurta (11th day-muhurta), Godhuli (sunset muhurta), Nishita (midnight muhurta, used for Shivaratri), **Madhyahna** (solar noon ±24 min ritual window), **Pratah Sandhya** / **Sayahna Sandhya** (asymmetric dawn / dusk twilight windows, width = `nightDuration / 10` — ~62–81 min depending on season, ending *at* sunrise / starting *at* sunset; matches DrikPanchang within ±2 min), classical aliases `dinamanaMinutes` / `ratrimanaMinutes`, nakshatra-keyed Amrit Kala. Choghadiya (16 slots), Gowri Panchangam / Nalla Neram (16 slots), Hora (24 planetary hours), Dur Muhurta (2 inauspicious windows), **Do Ghati Muhurta** (15 day + 15 night ~48-min slots, deity-keyed, no vara rotation), **Panchaka Rahita Muhurta** (slices of the day free of Panchaka), **Anandadi Yoga** (28-name Vara × Nakshatra cycle).
192
+ ## 4. Sun & Moon
189
193
 
190
- ### Inauspicious Periods
191
- Rahu Kalam, Gulika Kalam, Yamaganda, Panchaka detection, Bhadra Kala (Vishti karana window with earth / heaven / paatal location), **Varjyam** (BPHS-keyed forbidden ~96-min window per nakshatra), **Ganda Mula** (Moon in the 6 root nakshatras — Ashwini / Ashlesha / Magha / Jyeshtha / Mula / Revati — with `mild` / `severe` severity).
194
+ Sunrise, sunset, moonrise, moonset (Meeus apparent-upper-limb), plus Chandra Rashi
195
+ (Moon's zodiac sign).
192
196
 
193
- ### Special Yogas & Festivals
194
- Amrit Siddhi, Sarvartha Siddhi, Ravi Pushya, Guru Pushya, **Dwipushkar**, **Tripushkar**, **Jwalamukhi**, **Aadal**, **Vidaal**, **Ravi** yoga detection.
197
+ ```typescript
198
+ import { getSunrise, getSunset, getMoonrise, getMoonset } from 'panchang-ts';
195
199
 
196
- **80+ festivals** spanning pan-Indian, regional, and classical observances:
200
+ const loc = { latitude: 28.6139, longitude: 77.2090 }; // New Delhi
197
201
 
198
- - **Ekadashi** 26 named variants (Putrada, Shat Tila, Nirjala, Devshayani, etc.) with **Smarta / Vaishnava split** via Dashami-viddha rule; Smarta fast emits a `deferralDate` for Dwadashi.
199
- - **Pradosha** — 7 weekday-qualified variants (Som Pradosh, Bhauma Pradosh, Shani Pradosh, etc.) firing on both Shukla & Krishna paksha.
200
- - **Sankranti** — transit-based solar-month boundary detection plus regional variants (**Pongal**, **Vishu**, **Baisakhi**, **Pohela Boishakh**, **Bohag Bihu**, **Magh Bihu**, **Kati Bihu**, **Uttarayan**, **Ayyappa Makara Jyothi**, **Raja Sankranti**, **Harela**, **Sair**, **Singh Sankranti**) scoped by the `region` option. **Lohri** fires on the Hindu day immediately preceding Makara Sankranti under Punjab/Haryana/Himachal scopes.
201
- - **Canonical-time classical festivals** — Ganesh Chaturthi (madhyahna), Shivaratri (nishita), Diwali, Holi, Raksha Bandhan (Bhadra-aware, suppressed when Bhadra straddles Purnima), Karva Chauth (chandrodaya), Janmashtami, Dussehra, Navaratri, Ram Navami, Hanuman Jayanti, **Akshaya Tritiya & Parashurama Jayanti** (madhyahna-vyapini, co-emitted on Vaishakha Shukla Tritiya), Makar Sankranti.
202
- - **Regional festivals (v2.1)** — **Gudi Padwa** (Maharashtra/Goa), **Gangaur** (Rajasthan), **Karaga** (Karnataka), **Bonalu** (Telangana, recurring Sundays in Ashadha), **Varamahalakshmi** (last Friday of Shravana Shukla before Purnima, Karnataka/AP/Telangana/Tamil Nadu), **Bathukamma** (Telangana — Engili Pula + Saddula markers), **Hariyali / Kajari / Hartalika Teej**, **Govardhan Puja**, **Bhai Dooj**, **Phagli** (Himachal), **Jagannath Rath Yatra** (pan-Indian, Ashadha Shukla Dwitiya), **Raja Parba** 3-day arc (Odisha — Pahili / Sankranti / Basi) — all filtered by per-state allow-lists on the rule.
203
- - **Regional & seasonal** — Chhath (4-day sequence), Vat Savitri, Upakarma (3 shakha variants via nakshatra+chandraMasa), Onam (nakshatra+solarMasa).
204
- - **Monthly observances** — Masik Shivaratri, Vinayaka Chaturthi (suppressed in Maha-month), **Masik Karthigai** (any day Krittika nakshatra prevails — sampled at sunrise / midday / sunset / nishita), Pushya days, Shravan Somvar and other month+weekday patterns.
205
- - Adhika (leap) months auto-skipped for tithi-based rules; Purnimanta naming respected.
202
+ const sunrise = getSunrise(localMidnightUtc, loc);
203
+ const sunset = getSunset(sunrise, loc);
206
204
 
207
- ### Eclipses (Grahan)
208
- Solar & lunar eclipse detection with subtype (partial / total / annular / penumbral), magnitude at peak, observer-horizon visibility, and pre-eclipse **sutak** impurity window.
205
+ // Moonrise / moonset can be null on days the Moon doesn't rise/set
206
+ const moonrise = getMoonrise(localMidnightUtc, loc);
207
+ const moonset = getMoonset(localMidnightUtc, loc);
209
208
 
210
- ### Jyotish (Vedic Astrology)
211
- All 9 graha positions (geocentric, sidereal) with rashi, nakshatra, pada, and retrograde status. Vimshottari Dasha with Antardasha breakdown — from a birth moment alone or from an explicit Moon longitude. Chandra Balam (transit-Moon favorability relative to janma rashi). **Tarabala** (9-tara cycle — Janma, Sampat, Vipat, Kshema, Pratyari, Sadhaka, Vadha, Mitra, Ati-Mitra — keyed off janma nakshatra; parallel to Chandra Balam).
209
+ // Or read all of them off the daily result:
210
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
211
+ console.log(r.sunrise, r.sunset, r.moonrise, r.moonset, r.nextSunrise);
212
+ console.log(r.dayDurationMinutes, r.nightDurationMinutes);
213
+ ```
212
214
 
213
- ### Astronomy
214
- Sunrise, Sunset, Moonrise, Moonset, Chandra Rashi (Moon sign), Surya Nakshatra. Cross-verified across diaspora locations (New York, London, Sydney, Dubai, Singapore) including DST transitions via IANA timezone strings.
215
+ ## 5. Auspicious Muhurta
215
216
 
216
- ### Localization
217
- 2 languages: **English** and **Hindi** (Devanagari). All returned display strings respect the `language` option.
217
+ Classical auspicious time windows: Brahma, Abhijit, Vijaya, Godhuli, Nishita, Madhyahna,
218
+ Pratah / Sayahna Sandhya, and nakshatra-keyed Amrit Kala.
218
219
 
219
- ### Configuration
220
- 3 ayanamsa systems (Lahiri, B.V. Raman, KP), 2 masa systems (Purnimanta, Amanta), adjustable precision, optional fast mode (`computeEndTimes: false` for ~5x speedup).
220
+ ```typescript
221
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
222
+
223
+ r.brahmaMuhurta; // two muhurtas before sunrise
224
+ r.abhijitMuhurta; // 8th day-muhurta — universally auspicious
225
+ r.vijayaMuhurta; // 11th day-muhurta — auspicious for success
226
+ r.godhuliMuhurta; // "cow-dust" — sunset muhurta
227
+ r.nishitaMuhurta; // midnight muhurta (Shivaratri)
228
+ r.madhyahna; // solar noon ±24 min
229
+ r.pratahSandhya; // dawn twilight, ends *at* sunrise
230
+ r.sayahnaSandhya; // dusk twilight, starts *at* sunset
231
+ r.amritKala; // nakshatra-specific window (null when nakshatra has none)
232
+
233
+ // Direct helpers:
234
+ import {
235
+ computeBrahmaMuhurta, computeAbhijitMuhurta, computeVijayaMuhurta,
236
+ computeGodhuliMuhurta, computeNishitaMuhurta, computeMadhyahna,
237
+ computePratahSandhya, computeSayahnaSandhya, computeAmritKala,
238
+ } from 'panchang-ts';
239
+ ```
221
240
 
222
- ---
241
+ `pratahSandhya` and `sayahnaSandhya` are asymmetric — width = `nightDuration / 10`
242
+ (~62–81 min depending on season), matching DrikPanchang within ±2 min.
243
+
244
+ ## 6. Inauspicious Periods
245
+
246
+ Rahu Kalam, Gulika Kalam, Yamaganda, Dur Muhurta (2 windows), Varjyam (BPHS-keyed
247
+ ~96-min forbidden window), Ganda Mula (Moon in root nakshatras), Bhadra Kala (Vishti
248
+ karana with earth/heaven/paatal location), Panchaka.
223
249
 
224
- ## API Reference
250
+ ```typescript
251
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
252
+
253
+ r.rahuKalam; // { start, end }
254
+ r.gulikaKalam; // { start, end }
255
+ r.yamaganda; // { start, end }
256
+ r.durMuhurta; // [TimePeriod, TimePeriod] — two ~48-min windows
257
+ r.varjyam; // { start, end } | null
258
+ r.gandaMula; // { active: boolean, severity: 'mild' | 'severe' | null, ... }
259
+ r.bhadra; // { start, end, location: 'earth'|'heaven'|'paatal', isActive } | null
260
+ r.panchaka; // boolean — Moon in last 5 nakshatras
261
+
262
+ // Direct helpers (varaIndex: 0=Sun ... 6=Sat):
263
+ import {
264
+ computeRahuKalam, computeGulikaKalam, computeYamaganda,
265
+ computeVarjyam, computeGandaMula,
266
+ } from 'panchang-ts';
267
+
268
+ const rahu = computeRahuKalam(sunrise, sunset, varaIndex);
269
+ ```
225
270
 
226
- ### `getDailyPanchang(date, location, options)`
271
+ ## 7. Time-Slot Systems
227
272
 
228
- Returns the full Hindu day from sunrise to next sunrise, with all element transitions.
273
+ Four parallel slot systems covering the Hindu day:
229
274
 
230
275
  ```typescript
231
- import { getDailyPanchang } from 'panchang-ts';
276
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
232
277
 
233
- const result = getDailyPanchang(
234
- date, // Date any moment within the local calendar day
235
- location, // GeoLocation — { latitude, longitude, elevation? }
236
- options, // PanchangOptions — { timezone, ayanamsa?, language?, ... }
237
- );
278
+ // Choghadiya 8 day + 8 night slots, each named (Amrit, Kaal, Shubh, Rog, ...) and rated
279
+ r.choghadiya.day.forEach(s => console.log(s.name, s.qualityName, s.start, s.end));
280
+ r.choghadiya.night.forEach(s => console.log(s.name, s.qualityName));
281
+
282
+ // Gowri Panchangam (Tamil "Nalla Neram") — 8 day + 8 night slots
283
+ r.gowriPanchangam.day.forEach(s => console.log(s.name, s.qualityName));
284
+
285
+ // Hora — 12 day + 12 night planetary hours (Chaldean order)
286
+ r.hora.day.forEach(h => console.log(h.planet, h.start, h.end));
287
+
288
+ // Do Ghati Muhurta — 15 day + 15 night ~48-min deity-keyed slots (no vara rotation)
289
+ r.doGhatiMuhurta.day.forEach(g => console.log(g.name, g.start, g.end));
290
+
291
+ // Panchaka Rahita — slices of the day FREE of Panchaka ([] when Panchaka pervades)
292
+ r.panchakaRahita.forEach(slice => console.log(slice.start, slice.end));
238
293
  ```
239
294
 
240
- **Returns: `DailyPanchangResult | null`**
241
-
242
- `null` is returned for polar locations on dates where sunrise or sunset cannot be computed (midnight sun, polar night). On every other location/date the function returns a populated result.
243
-
244
- | Field | Type | Description |
245
- |-------|------|-------------|
246
- | `date` | `Date` | Input date |
247
- | `location` | `GeoLocation` | Input location |
248
- | `timezone` | `number` | Resolved UTC offset in minutes |
249
- | `sunrise` | `Date` | Sunrise (offset-adjusted) |
250
- | `sunset` | `Date` | Sunset (offset-adjusted) |
251
- | `nextSunrise` | `Date` | Following day's sunrise (offset-adjusted) |
252
- | `dayDurationMinutes` | `number` | Length of daytime in minutes |
253
- | `nightDurationMinutes` | `number` | Length of night in minutes |
254
- | `tithis` | `DailyTithiInfo[]` | Tithis active during the day (usually 1-2) |
255
- | `nakshatras` | `DailyNakshatraInfo[]` | Nakshatras active during the day |
256
- | `yogas` | `DailyYogaInfo[]` | Yogas active during the day |
257
- | `karanas` | `DailyKaranaInfo[]` | Karanas active during the day (usually 2-4) |
258
- | `vara` | `VaraInfo` | Weekday (Vara) |
259
- | `rahuKalam` | `TimePeriod` | Rahu Kalam start/end |
260
- | `gulikaKalam` | `TimePeriod` | Gulika Kalam start/end |
261
- | `yamaganda` | `TimePeriod` | Yamaganda start/end |
262
- | `abhijitMuhurta` | `TimePeriod` | Abhijit Muhurta start/end |
263
- | `brahmaMuhurta` | `TimePeriod` | Brahma Muhurta — two muhurtas before sunrise |
264
- | `masa` | `MasaInfo` | Solar month (Saura Masa) |
265
- | `chandramasa` | `ChandraMasaInfo` | Lunar month + Adhika (leap) flag |
266
- | `samvat` | `SamvatInfo` | Vikram Samvat and Shaka Samvat year numbers |
267
- | `chandraRashi` | `RashiInfo` | Moon's zodiac sign (changes every ~2.5 days) |
268
- | `suryaNakshatra` | `RashiInfo` | Sun's nakshatra (changes every ~13-14 days) |
269
- | `choghadiya` | `ChoghadiyaInfo` | 8 day + 8 night slots, each named and rated |
270
- | `gowriPanchangam` | `GowriInfo` | 8 day + 8 night Gowri Nalla Neram slots |
271
- | `hora` | `HoraInfo` | 12 day + 12 night horas, each with ruling planet |
272
- | `moonrise` | `Date \| null` | Moonrise; `null` if none that day |
273
- | `moonset` | `Date \| null` | Moonset; `null` if none that day |
274
- | `panchaka` | `boolean` | `true` when Moon is in last 5 nakshatras |
275
- | `panchakaRahita` | `TimePeriod[]` | Slices of the Hindu day FREE of Panchaka; `[]` when Panchaka pervades the entire day |
276
- | `doGhatiMuhurta` | `DoGhatiInfo` | 15 day + 15 night ~48-min deity-keyed slots covering sunrise→sunset and sunset→nextSunrise |
277
- | `gandaMula` | `GandaMulaInfo` | Moon-in-root-nakshatra detection at sunrise; `active: false` for the 21 non-root nakshatras |
278
- | `anandadiYoga` | `AnandadiYogaInfo` | Vara × Nakshatra 28-name cycle yoga at sunrise |
279
- | `specialYogas` | `SpecialYogaInfo[]` | Auspicious yogas active today |
280
- | `durMuhurta` | `[TimePeriod, TimePeriod]` | Two inauspicious ~48-min windows |
281
- | `vijayaMuhurta` | `TimePeriod` | Vijaya Muhurta — 11th day-muhurta, auspicious for success |
282
- | `godhuliMuhurta` | `TimePeriod` | Godhuli ("cow-dust") — sunset muhurta, auspicious for ceremonies |
283
- | `nishitaMuhurta` | `TimePeriod` | Nishita — midnight muhurta, used for Shivaratri and nocturnal rites |
284
- | `madhyahna` | `TimePeriod` | Madhyahna — solar noon as a ±24-min ritual window (one classical muhurta wide) |
285
- | `pratahSandhya` | `TimePeriod` | Dawn-twilight ritual window — three nighttime ghatikas ending *at* sunrise (asymmetric; width = `nightDuration / 10` ≈ 62–81 min) |
286
- | `sayahnaSandhya` | `TimePeriod` | Dusk-twilight ritual window — three nighttime ghatikas starting *at* sunset (asymmetric; width = `nightDuration / 10`) |
287
- | `dinamanaMinutes` | `number` | Classical alias of `dayDurationMinutes` (sunrise → sunset) |
288
- | `ratrimanaMinutes` | `number` | Classical alias of `nightDurationMinutes` (sunset → next sunrise) |
289
- | `amritKala` | `TimePeriod \| null` | Amrit Kala — nakshatra-specific auspicious window (null when nakshatra has none) |
290
- | `varjyam` | `TimePeriod \| null` | Varjyam (Vishaghati / Nakshatra Thyajyam) — BPHS-keyed forbidden ~96-min window; `null` when none overlaps the Hindu day |
291
- | `bhadra` | `BhadraInfo \| null` | Bhadra Kala (Vishti karana) window overlapping this Hindu day, or `null` |
292
- | `eclipse` | `EclipseInfo \| null` | Solar/lunar eclipse overlapping this Hindu day with sutak window, or `null` |
293
- | `festivals` | `FestivalInfo[]` | Festivals / observances today (filtered by `region` option) |
294
- | `chandraBalam` | `ChandraBalamInfo?` | Transit-Moon favorability — only present when `janmaRashi` option is passed |
295
- | `tarabala` | `TarabalaInfo?` | 9-tara cycle position — only present when `janmaNakshatra` option is passed |
296
- | `ayanamsa` | `number` | Ayanamsa in degrees at sunrise |
297
- | `siderealSunAtSunrise` | `number` | Sun sidereal longitude at sunrise (degrees) |
298
- | `siderealMoonAtSunrise` | `number` | Moon sidereal longitude at sunrise (degrees) |
295
+ ## 8. Special Yogas
299
296
 
300
- ---
297
+ Auspicious / inauspicious yogas formed by Vara × Tithi × Nakshatra combinations and
298
+ Moon-from-Sun nakshatra-distance rules. The 28-name **Anandadi Yoga** cycle is also
299
+ returned at sunrise.
301
300
 
302
- ### `getInstantPanchang(date, location, options?)`
301
+ ```typescript
302
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
303
+
304
+ // Anandadi Yoga (Vara × Nakshatra cycle of 28 names)
305
+ console.log(r.anandadiYoga.name); // "Ananda"
306
+
307
+ // Special yogas active today
308
+ r.specialYogas.forEach(y => {
309
+ console.log(y.name, y.type);
310
+ // type: 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya'
311
+ // | 'dwipushkar' | 'tripushkar' ← actions doubled / tripled
312
+ // | 'jwalamukhi' ← inauspicious (Muhurta-chintamani 6.32)
313
+ // | 'aadal' | 'vidaal' | 'ravi' ← Moon-from-Sun nakshatra-distance rules
314
+ });
315
+ ```
303
316
 
304
- Returns the single Panchang element active at an exact UTC moment.
317
+ ## 9. Festivals
318
+
319
+ **80+ festivals** spanning pan-Indian, regional, and classical observances:
320
+
321
+ - **Ekadashi** — 26 named variants (Putrada, Shat Tila, Nirjala, Devshayani, …) with
322
+ **Smarta / Vaishnava split** via Dashami-viddha rule; Smarta fast emits a `deferralDate`
323
+ for Dwadashi.
324
+ - **Pradosha** — 7 weekday-qualified variants (Som, Bhauma, Shani, …) on both pakshas.
325
+ - **Sankranti** — transit-based detection plus regional variants (Pongal, Vishu, Baisakhi,
326
+ Pohela Boishakh, Bohag / Magh / Kati Bihu, Uttarayan, Ayyappa Makara Jyothi, Raja
327
+ Sankranti, Harela, Sair, Singh Sankranti). **Lohri** fires on the Hindu day immediately
328
+ preceding Makara Sankranti under Punjab / Haryana / Himachal scopes.
329
+ - **Canonical-time classical festivals** — Ganesh Chaturthi (madhyahna), Shivaratri
330
+ (nishita), Diwali, Holi, Raksha Bandhan (Bhadra-aware), Karva Chauth (chandrodaya),
331
+ Janmashtami, Dussehra, Navaratri, Ram Navami, Hanuman Jayanti, Akshaya Tritiya &
332
+ Parashurama Jayanti (madhyahna-vyapini), Makar Sankranti.
333
+ - **Regional festivals** — Gudi Padwa, Gangaur, Karaga, Bonalu, Varamahalakshmi,
334
+ Bathukamma, Hariyali / Kajari / Hartalika Teej, Govardhan Puja, Bhai Dooj, Phagli,
335
+ Jagannath Rath Yatra, Raja Parba 3-day arc.
336
+ - **Regional & seasonal** — Chhath (4-day sequence), Vat Savitri, Upakarma, Onam.
337
+ - **Monthly observances** — Masik Shivaratri, Vinayaka Chaturthi, Masik Karthigai, Pushya
338
+ days, Shravan Somvar, and other month + weekday patterns.
305
339
 
306
340
  ```typescript
307
- import { getInstantPanchang } from 'panchang-ts';
341
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
308
342
 
309
- const result = getInstantPanchang(
310
- new Date('2025-01-14T03:00:00Z'), // UTC moment
311
- { latitude: 18.5204, longitude: 73.8567 },
312
- { language: 'hi' }, // Hindi (Devanagari) names
313
- );
343
+ r.festivals.forEach(f => {
344
+ console.log(f.name, f.type, f.deferralDate);
345
+ // type: 'major' | 'minor' | 'ekadashi'
346
+ // | 'smarta_ekadashi' | 'vaishnava_ekadashi' Smarta sets deferralDate
347
+ // | 'pradosha' | 'sankranti' | 'eclipse'
348
+ });
349
+ ```
314
350
 
315
- console.log(result.tithi.name); // "कृष्ण चतुर्दशी"
316
- console.log(result.nakshatra.name); // "मृगशिरा"
317
- console.log(result.chandramasa.name); // "माघ"
318
- console.log(result.chandraRashi.name); // "मिथुन"
319
- console.log(result.samvat.vikramSamvat); // 2081
320
- console.log(result.panchaka); // false
321
- ```
322
-
323
- **Returns: `InstantPanchangResult | null`**
324
-
325
- `null` is returned for polar locations where sunrise can't be computed (the Hindu-day weekday is undefined). On every other location/date the function returns a populated result.
326
-
327
- | Field | Type | Description |
328
- |-------|------|-------------|
329
- | `timestamp` | `Date` | Input UTC moment |
330
- | `location` | `GeoLocation` | Input location |
331
- | `tithi` | `TithiInfo` | Active Tithi with paksha, number, completion % |
332
- | `nakshatra` | `NakshatraInfo` | Active Nakshatra with pada, degrees |
333
- | `yoga` | `YogaInfo` | Active Yoga |
334
- | `karana` | `KaranaInfo` | Active Karana (movable or fixed) |
335
- | `vara` | `VaraInfo` | Active Vara (weekday) |
336
- | `chandramasa` | `ChandraMasaInfo` | Lunar month + Adhika flag |
337
- | `samvat` | `SamvatInfo` | Vikram Samvat and Shaka Samvat year numbers |
338
- | `chandraRashi` | `RashiInfo` | Moon's zodiac sign |
339
- | `suryaNakshatra` | `RashiInfo` | Sun's nakshatra |
340
- | `panchaka` | `boolean` | `true` when Moon is in last 5 nakshatras |
341
- | `gandaMula` | `GandaMulaInfo` | Moon-in-root-nakshatra detection at the queried instant |
342
- | `anandadiYoga` | `AnandadiYogaInfo` | Vara × Nakshatra 28-name cycle yoga at the queried instant |
343
- | `specialYogas` | `SpecialYogaInfo[]` | Auspicious yogas at this moment |
344
- | `festivals` | `FestivalInfo[]` | Festivals / observances at this moment (see caveat below) |
345
- | `chandraBalam` | `ChandraBalamInfo?` | Transit-Moon favorability — only present when `janmaRashi` option is passed |
346
- | `tarabala` | `TarabalaInfo?` | 9-tara cycle position — only present when `janmaNakshatra` option is passed |
347
- | `ayanamsa` | `number` | Ayanamsa in degrees |
348
- | `siderealSun` | `number` | Sun sidereal longitude (degrees) |
349
- | `siderealMoon` | `number` | Moon sidereal longitude (degrees) |
351
+ ### Regional festival scoping
350
352
 
351
- ---
353
+ The `region` option scopes regional festival variants to one Indian state. Pan-Indian
354
+ festivals (Diwali, Holi, Raksha Bandhan, the canonical `sankranti` event) emit regardless.
352
355
 
353
- ### When to use `getInstantPanchang` vs `getDailyPanchang`
356
+ ```typescript
357
+ // Default — every regional variant emits on Makar Sankranti day:
358
+ const all = getDailyPanchang(jan14, chennai, { timezone: 330 })!;
359
+ all.festivals.map(f => f.name);
360
+ // → ["Sankranti", "Makar Sankranti", "Pongal", "Uttarayan",
361
+ // "Magh Bihu", "Ayyappa Makara Jyothi"]
354
362
 
355
- Both functions share the same core astronomy, but `getDailyPanchang` operates on the full Vedic day (local sunrise → next sunrise) while `getInstantPanchang` samples a single UTC moment. That distinction matters most for **festivals** and classical rules that reference a specific canonical time of the Hindu day.
363
+ // Scope to Tamil Nadu drops Bihu/Ayyappa/Uttarayan:
364
+ const tn = getDailyPanchang(jan14, chennai, { timezone: 330, region: 'tamil-nadu' })!;
365
+ tn.festivals.map(f => f.name);
366
+ // → ["Sankranti", "Makar Sankranti", "Pongal"]
356
367
 
357
- | Use case | Recommended | Why |
358
- |----------|-------------|-----|
359
- | "What Panchang elements are active right now?" | `getInstantPanchang` | Single-moment snapshot; no sunrise needed. |
360
- | Birth chart / muhurta picking at a specific instant | `getInstantPanchang` | Exact element at that UTC moment. |
361
- | Daily calendar / almanac row for a date | `getDailyPanchang` | Lists all element transitions for the day. |
362
- | Displaying today's festivals & observances | `getDailyPanchang` | Full canonical-time festival refinement. |
363
- | Sankranti / solar-month boundary dates | `getDailyPanchang` | Uses sunrise-to-next-sunrise transit detection. |
364
- | Ekadashi (Smarta vs Vaishnava), Shivaratri, Ganesh Chaturthi, Karva Chauth | `getDailyPanchang` | Requires madhyahna / pradosha / nishita / chandrodaya refinement. |
365
- | Raksha Bandhan date (Bhadra-aware) / long-tithi dedupe | `getDailyPanchang` | Rules key off the Hindu day window, not an instant. |
366
- | Rahu Kalam / Gulika / Choghadiya / Gowri / Hora / Durmuhurta | `getDailyPanchang` | Computed from sunrise, sunset, and day length. |
367
- | Eclipse (Grahan) detection with sutak window | `getDailyPanchang` | Overlapping the day needs the day window. |
368
-
369
- **Instant-mode festival caveat:** `getInstantPanchang` does emit `festivals`, but it evaluates rules against the tithi / nakshatra / chandraMasa at the given instant only. It **does not** run the canonical-time refinements (madhyahna / pradosha / nishita / chandrodaya), transit-based Sankranti, Ekadashi viddha (Smarta/Vaishnava split), or Bhadra-aware Raksha Bandhan exclusion — those require the full sunrise-to-next-sunrise Hindu day window and are only available in `getDailyPanchang`. If you need reliable festival dating, use `getDailyPanchang`.
368
+ // Lohri fires on the Hindu day BEFORE Makara transit, scoped to Punjab/Haryana/Himachal
369
+ const lohri = getDailyPanchang(jan13, amritsar, { timezone: 330, region: 'punjab' })!;
370
+ lohri.festivals.some(f => f.name === 'Lohri'); // true
371
+ ```
370
372
 
371
- ---
373
+ `FestivalRegion` covers 21 Indian states + `'nepal'` + `'all'` (default). See
374
+ [Types](#types--exports) for the full slug list.
375
+
376
+ ## 10. Eclipses
377
+
378
+ Solar / lunar eclipse detection with subtype, magnitude, observer-horizon visibility, and
379
+ classical pre-eclipse **sutak** impurity window.
372
380
 
373
- ### Options
381
+ ```typescript
382
+ const r = getDailyPanchang(date, loc, { timezone: 330 })!;
383
+
384
+ if (r.eclipse) {
385
+ console.log(r.eclipse.kind); // 'solar' | 'lunar'
386
+ console.log(r.eclipse.subtype); // 'partial' | 'total' | 'annular' | 'penumbral'
387
+ console.log(r.eclipse.magnitude); // 0..1 fraction of disc obscured at peak
388
+ console.log(r.eclipse.visibleFromLocation); // body above horizon at peak?
389
+ console.log(r.eclipse.start, r.eclipse.peak, r.eclipse.end);
390
+ console.log(r.eclipse.sutakStart, r.eclipse.sutakEnd);
391
+ // Sutak: 12 h (4 prahara) before solar, 9 h (3 prahara) before lunar
392
+ }
374
393
 
375
- **`PanchangOptions`** (required for `getDailyPanchang`):
394
+ // Or look ahead:
395
+ import { getUpcomingSolarEclipse, getUpcomingLunarEclipse } from 'panchang-ts';
396
+ const next = getUpcomingSolarEclipse(new Date(), loc, /* withinDays */ 365);
397
+ ```
376
398
 
377
- | Option | Type | Default | Description |
378
- |--------|------|---------|-------------|
379
- | `timezone` | `number \| string` | **required** | UTC offset in minutes (330 for IST) **or** IANA zone name (`'America/New_York'`). IANA strings require `Intl` — use a number on older Hermes. DST resolves automatically for IANA zones via the reference date. |
380
- | `ayanamsa` | `'lahiri' \| 'raman' \| 'krishnamurti'` | `'lahiri'` | Ayanamsa system |
381
- | `language` | `'en' \| 'hi'` | `'en'` | Language for all element names (English or Hindi Devanagari). |
382
- | `computeEndTimes` | `boolean` | `true` | Set `false` for ~5x faster, names-only output |
383
- | `precision` | `'standard' \| 'high'` | `'standard'` | Binary-search iterations (15 vs 25). High precision is rarely needed. |
384
- | `masaSystem` | `'purnimanta' \| 'amanta'` | `'purnimanta'` | Lunar month naming system. Purnimanta (North Indian) or Amanta (South Indian). |
385
- | `region` | `FestivalRegion` | `'all'` | Scopes regional festival variants (Pongal, Vishu, Gudi Padwa, Lohri, Govardhan Puja, Bonalu, …) to a specific Indian state. See [`FestivalRegion`](#types) for the full list. Pre-v2.1 values (`'tamil'`, `'bengal'`, `'north-india'`) are still accepted but emit a deprecation warning; removal in v3. Pan-Indian festivals and the canonical `sankranti` event emit regardless of this setting. |
386
- | `janmaRashi` | `number` | _(omitted)_ | Native's birth Moon rashi index (0 = Mesha … 11 = Meena). When provided, the result includes `chandraBalam`. |
387
- | `janmaNakshatra` | `number` | _(omitted)_ | Native's birth Moon nakshatra index (0 = Ashwini … 26 = Revati). When provided, the result includes `tarabala`. |
399
+ ## 11. Planetary Positions
388
400
 
389
- **`InstantPanchangOptions`** (optional for `getInstantPanchang`): same as above but without `timezone` (instant mode works in UTC).
401
+ All 9 grahas (Sun Saturn + Rahu / Ketu) geocentric, sidereal with rashi, nakshatra,
402
+ pada, retrograde flag. Optional `nodeType: 'true'` upgrades Rahu / Ketu from mean node
403
+ (±2° worst-case) to Meeus's dominant periodic correction (~±0.6°).
390
404
 
391
- ---
405
+ ```typescript
406
+ import { computePlanetaryPositions, GRAHA_ABBR } from 'panchang-ts';
407
+
408
+ const grahas = computePlanetaryPositions(new Date(), 'lahiri');
409
+ console.log(grahas.jupiter.rashi.name); // "Dhanu"
410
+ console.log(grahas.jupiter.degreeInRashi); // 18.42
411
+ console.log(grahas.jupiter.nakshatra.name); // "Purva Ashadha"
412
+ console.log(grahas.jupiter.nakshatra.pada); // 3
413
+ console.log(grahas.saturn.isRetrograde); // true / false
414
+ console.log(GRAHA_ABBR['Jupiter']); // "Ju"
415
+
416
+ // True node (more accurate Rahu / Ketu)
417
+ const grahasTrue = computePlanetaryPositions(new Date(), 'lahiri', undefined, 'true');
418
+ ```
392
419
 
393
- ### Low-level Utilities
420
+ ## 12. Vimshottari Dasha
394
421
 
395
- Exported for advanced use cases building custom tools, visualizations, or Jyotish applications.
422
+ Maha Antar Pratyantar (3-level) breakdown, derived from a birth moment alone or from
423
+ an explicit Moon longitude.
396
424
 
397
425
  ```typescript
398
426
  import {
399
- getSunrise, getSunset,
400
- getMoonrise, getMoonset,
401
- getSiderealSunLongitude, getSiderealMoonLongitude,
402
- getAyanamsa,
403
- computeRahuKalam, computeGulikaKalam, computeYamaganda,
404
- computeAbhijitMuhurta, computeBrahmaMuhurta,
405
- computeVijayaMuhurta, computeGodhuliMuhurta,
406
- computeNishitaMuhurta, computeAmritKala,
407
- // Phase 28 — daily-parity muhurtas + nakshatra-keyed inauspicious windows
408
- computeMadhyahna, computePratahSandhya, computeSayahnaSandhya,
409
- computeVarjyam, computeGandaMula,
410
- computeAnandadiYoga, computePanchakaRahita, computeDoGhati,
411
- computeGowriPanchangam,
412
- // Eclipses (signature: (fromUtc, location, withinDays))
413
- getUpcomingSolarEclipse, getUpcomingLunarEclipse, getEclipseDuringDay,
414
- // Jyotish
415
- computePlanetaryPositions,
416
427
  computeVimshottariDasha, computeVimshottariDashaFromBirth,
417
- computeChandraBalam,
418
- computeTarabala,
419
- GRAHA_ABBR,
428
+ computeVimshottariPratyantar, getSiderealMoonLongitude,
420
429
  } from 'panchang-ts';
421
430
 
422
- // Sunrise/sunset
423
- const sunrise = getSunrise(localMidnightUtc, { latitude: 28.6, longitude: 77.2 });
424
- const sunset = getSunset(sunrise, { latitude: 28.6, longitude: 77.2 });
431
+ // Convenience: from birth date alone (Moon longitude derived)
432
+ const dasha = computeVimshottariDashaFromBirth(birthDate, 'lahiri');
433
+ console.log(dasha.currentMahaDashaLord); // "Rahu"
434
+ console.log(dasha.mahaDashas[0]!.antarDashas[0]!.lord); // "Rahu"
435
+
436
+ // Or pass an explicit Moon sidereal longitude
437
+ const moonLon = getSiderealMoonLongitude(birthDate, 'lahiri');
438
+ const dasha2 = computeVimshottariDasha(birthDate, moonLon);
439
+
440
+ // Pratyantar — third-level sub-sub-periods within an Antardasha
441
+ const firstAntar = dasha.mahaDashas[0]!.antarDashas[0]!;
442
+ const pratyantars = computeVimshottariPratyantar(firstAntar); // PratyantarDasha[9]
443
+ ```
444
+
445
+ ## 13. Personal Transits
425
446
 
426
- // Moonrise/moonset return null when the Moon doesn't rise/set that day
427
- const moonrise = getMoonrise(localMidnightUtc, { latitude: 28.6, longitude: 77.2 });
428
- const moonset = getMoonset(localMidnightUtc, { latitude: 28.6, longitude: 77.2 });
447
+ Daily transit-based favorability relative to the native's birth Moon. Pass `janmaRashi`
448
+ or `janmaNakshatra` to `getDailyPanchang` and the corresponding field is added to the
449
+ result; or call the helpers directly.
450
+
451
+ ```typescript
452
+ const r = getDailyPanchang(date, loc, {
453
+ timezone: 330,
454
+ janmaRashi: 3, // 0 = Mesha ... 11 = Meena
455
+ janmaNakshatra: 0, // 0 = Ashwini ... 26 = Revati
456
+ })!;
429
457
 
430
- // Sidereal longitudes
431
- const moonLon = getSiderealMoonLongitude(new Date(), 'lahiri'); // degrees [0, 360)
432
- const sunLon = getSiderealSunLongitude(new Date(), 'lahiri');
458
+ r.chandraBalam!; // { house, quality: 'strong' | 'weak', name, englishName }
459
+ r.tarabala!; // { taraIndex, name, englishName, quality }
433
460
 
434
- // Ayanamsa
435
- const ayan = getAyanamsa(new Date(), 'lahiri'); // e.g. 24.10
461
+ // Direct helpers:
462
+ import { computeChandraBalam, computeTarabala, computeSadeSati } from 'panchang-ts';
436
463
 
437
- // Inauspicious periods (varaIndex: 0=Sun ... 6=Sat)
438
- const rahu = computeRahuKalam(sunrise, sunset, varaIndex); // { start, end }
439
- const gulika = computeGulikaKalam(sunrise, sunset, varaIndex);
440
- const yama = computeYamaganda(sunrise, sunset, varaIndex);
464
+ computeChandraBalam(3 /* janma */, 6 /* transit Moon rashi */);
465
+ computeTarabala(0 /* janma nakshatra */, 4 /* transit Moon nakshatra */);
441
466
 
442
- // Muhurta
443
- const abhijit = computeAbhijitMuhurta(sunrise, sunset); // { start, end }
444
- const brahma = computeBrahmaMuhurta(sunrise, sunset); // { start, end }
467
+ // Sade Sati — Saturn currently transiting 12th, 1st, or 2nd from natal Moon
468
+ const sadeSati = computeSadeSati(natalMoonRashiIndex, new Date());
469
+ // { active, phase: 1|2|3|null, currentArcStart, currentArcEnd, nextArcStart }
445
470
  ```
446
471
 
447
- **Jyotish (Vedic Astrology):**
472
+ ## 14. Birth Chart (Kundli)
473
+
474
+ Sidereal **Lagna**, **Bhava** under three house systems, **D1 (Rashi)** and **D9
475
+ (Navamsa)** charts placing all 9 grahas, and **Planetary Dignity**.
448
476
 
449
477
  ```typescript
450
- // All 9 graha positions (sidereal — Rahu/Ketu use mean node)
451
- const grahas = computePlanetaryPositions(birthDate, 'lahiri');
452
- console.log(grahas.jupiter.rashi.name); // "Dhanu"
453
- console.log(grahas.saturn.isRetrograde); // true/false
454
- console.log(GRAHA_ABBR['Jupiter']); // "Ju"
478
+ import {
479
+ computeLagna, computeBhava, computeRashiChart, computeNavamsa,
480
+ computeDignity,
481
+ } from 'panchang-ts';
455
482
 
456
- // Vimshottari Dasha — convenience form: birth date only (Moon longitude derived)
457
- const dasha = computeVimshottariDashaFromBirth(birthDate, 'lahiri');
458
- console.log(dasha.currentMahaDashaLord); // "Rahu"
459
- console.log(dasha.mahaDashas[0]!.antarDashas[0]!.lord); // "Rahu"
483
+ const birth = new Date('1995-08-15T05:30:00Z');
484
+ const loc = { latitude: 28.6139, longitude: 77.2090 };
460
485
 
461
- // Or pass an explicit Moon sidereal longitude (useful when you already have one)
462
- const moonLon = getSiderealMoonLongitude(birthDate, 'lahiri');
463
- const dasha2 = computeVimshottariDasha(birthDate, moonLon);
486
+ // 1. Lagna (sidereal ascendant)
487
+ const lagna = computeLagna(birth, loc, 'lahiri', 'en');
488
+ // → { siderealLongitude, rashi, degreeInRashi, nakshatra, pada }
464
489
 
465
- // Chandra Balam transit Moon's favorability vs. janma rashi
466
- // janmaRashi and transitMoonRashi are 0-indexed (0 = Mesha ... 11 = Meena)
467
- const cb = computeChandraBalam(3 /* Karka */, 6 /* Tula */);
468
- console.log(cb.house); // 4
469
- console.log(cb.quality); // "weak"
470
- console.log(cb.englishName); // "Ashubha"
490
+ // 2. Bhava (12 houses)
491
+ // - 'whole-sign' (default classical Vedic) each rashi is one house
492
+ // - 'equal' — each house spans 30° starting at lagna's exact degree
493
+ // - 'placidus-kp' — true cuspal positions; throws PanchangError('CIRCUMPOLAR') > ±66.5°
494
+ const houses = computeBhava(birth, loc, { houseSystem: 'whole-sign' });
471
495
 
472
- // Tarabala9-tara cycle from janma nakshatra transit Moon nakshatra.
473
- // Inputs are 0-indexed nakshatra (0 = Ashwini ... 26 = Revati).
474
- const tb = computeTarabala(0 /* janma: Ashwini */, 4 /* transit: Mrigashira */);
475
- console.log(tb.taraIndex); // 4
476
- console.log(tb.englishName); // "Pratyari"
477
- console.log(tb.quality); // "inauspicious"
496
+ // 3. D1 (Rashi) chart lagna + bhava + 9 grahas with house placement
497
+ const d1 = computeRashiChart(birth, loc, { houseSystem: 'whole-sign' });
498
+ d1.planets.find(p => p.planet === 'Jupiter')?.house; // e.g. 5
499
+ d1.planets.find(p => p.planet === 'Saturn')?.isRetrograde;
500
+
501
+ // 4. D9 (Navamsa) chart — classical sign-based per-rashi-type rule
502
+ const d9 = computeNavamsa(birth, loc);
503
+
504
+ // 5. Planetary dignity (BPHS Ch.3-4)
505
+ computeDignity('Mars', 0); // 'moolatrikona' (Aries)
506
+ computeDignity('Mars', 9); // 'exalted' (Capricorn)
507
+ computeDignity('Sun', 6); // 'debilitated' (Libra)
478
508
  ```
479
509
 
510
+ Birth-chart helpers accept the full ayanamsa set including `'true-chitra'` (True
511
+ Chitrapaksha) and `'thirukanitham'` (Tamil-Vakya). Pass via `options.ayanamsa` or the
512
+ ayanamsa positional arg.
513
+
514
+ ## 15. Compatibility & Doshas
515
+
516
+ **Ashtakoot Guna Milan** (36-point marriage compatibility) and **Mangal Dosha** (Manglik
517
+ affliction with cancellations).
518
+
519
+ ```typescript
520
+ import { computeAshtakoot, computeMangalDosha } from 'panchang-ts';
521
+
522
+ // Ashtakoot — from natal Moons
523
+ const match = computeAshtakoot(
524
+ { rashi: 4, nakshatra: 9 }, // boy: Simha / Magha
525
+ { rashi: 0, nakshatra: 1 }, // girl: Mesha / Bharani
526
+ );
527
+ // → { totalScore: 0..36, koots: KootScore[8], cancellations: string[] }
528
+ // Koots in canonical order: Varna, Vashya, Tara, Yoni, Graha Maitri, Gana, Bhakoot, Nadi
529
+ // (max scores 1, 2, 3, 4, 5, 6, 7, 8 respectively)
530
+
531
+ // Mangal Dosha — checks Mars from lagna, Moon, and Venus
532
+ const mangal = computeMangalDosha(d1);
533
+ // → { afflicted, fromLagna, fromMoon, fromVenus, cancellations }
534
+ ```
535
+
536
+ **Documented limitations** — Mangal Dosha cancellations only cover Mars in own sign
537
+ (Aries / Scorpio) or exalted (Capricorn); other classical cancellations (mutual Mangalik,
538
+ Mars-Jupiter aspect, Mars-Saturn conjunction) are not applied. Ashtakoot Vashya koot is
539
+ simplified to single-vashya per rashi.
540
+
541
+ ## 16. Localization
542
+
543
+ All returned display names respect the `language` option. **English** and **Hindi
544
+ (Devanagari)** are supported.
545
+
546
+ ```typescript
547
+ const hi = getDailyPanchang(date, loc, { timezone: 330, language: 'hi' })!;
548
+
549
+ console.log(hi.tithis[0].name); // "कृष्ण चतुर्दशी"
550
+ console.log(hi.vara.name); // "मंगलवार"
551
+ console.log(hi.chandramasa.name); // "माघ"
552
+ console.log(hi.choghadiya.day[0].name); // "अमृत"
553
+
554
+ // englishName is always English on Vara / Tarabala / Chandra Balam
555
+ console.log(hi.vara.englishName); // "Tuesday"
556
+ ```
557
+
558
+ ## 17. Configuration
559
+
560
+ ```typescript
561
+ const r = getDailyPanchang(date, loc, {
562
+ timezone: 330, // number (UTC offset in min) or IANA string
563
+ ayanamsa: 'lahiri', // 'lahiri' | 'raman' | 'krishnamurti'
564
+ // | 'true-chitra' | 'thirukanitham'
565
+ language: 'en', // 'en' | 'hi'
566
+ masaSystem: 'purnimanta', // 'purnimanta' | 'amanta'
567
+ region: 'all', // 21 state slugs + 'nepal' + 'all'
568
+ computeEndTimes: true, // false → ~5x speedup, names only
569
+ precision: 'standard', // 'standard' (15 iter) | 'high' (25 iter)
570
+ janmaRashi: undefined, // pass to add r.chandraBalam
571
+ janmaNakshatra: undefined, // pass to add r.tarabala
572
+ });
573
+ ```
574
+
575
+ **Timezone handling** — `timezone` accepts either a number (UTC offset in minutes, e.g.
576
+ `330` for IST) or an IANA zone name (e.g. `'America/New_York'`). IANA strings need `Intl`,
577
+ which older Hermes versions don't fully support — pass a number on those targets. DST
578
+ resolves automatically for IANA zones via the reference date.
579
+
480
580
  ---
481
581
 
482
- ## Types
582
+ ## Types & Exports
483
583
 
484
584
  <details>
485
585
  <summary><strong>Core Types</strong> — GeoLocation, TimePeriod</summary>
@@ -505,7 +605,7 @@ interface TimePeriod {
505
605
  interface TithiInfo {
506
606
  index: number; // 0-29
507
607
  name: string; // e.g. "Shukla Pratipada"
508
- paksha: string; // "Shukla"/"Krishna" (en), "शुक्ल"/"कृष्ण" (sa/hi)
608
+ paksha: string; // "Shukla"/"Krishna" (en), "शुक्ल"/"कृष्ण" (hi)
509
609
  number: number; // 1-15 within the paksha
510
610
  completionPercentage: number;
511
611
  endTime: Date | null;
@@ -522,10 +622,10 @@ interface NakshatraInfo {
522
622
 
523
623
  interface DailyTithiInfo extends TithiInfo {
524
624
  startTime: Date | null; // null when isActiveAtSunrise is true
525
- isActiveAtSunrise: boolean; // true = present at sunrise; false = started mid-day
625
+ isActiveAtSunrise: boolean;
526
626
  }
527
627
 
528
- // DailyNakshatraInfo, DailyYogaInfo, DailyKaranaInfo follow the same pattern
628
+ // DailyNakshatraInfo, DailyYogaInfo, DailyKaranaInfo follow the same pattern.
529
629
 
530
630
  interface VaraInfo {
531
631
  index: number; // 0 = Sunday ... 6 = Saturday
@@ -542,12 +642,12 @@ interface KaranaInfo {
542
642
  type: 'fixed' | 'movable';
543
643
  }
544
644
 
545
- // Note: endTime and startTime are null when computeEndTimes: false.
645
+ // endTime / startTime are null when computeEndTimes: false.
546
646
  ```
547
647
  </details>
548
648
 
549
649
  <details>
550
- <summary><strong>Lunar Calendar</strong> — ChandraMasaInfo, SamvatInfo, MasaInfo</summary>
650
+ <summary><strong>Lunar Calendar</strong> — ChandraMasaInfo, SamvatInfo, MasaInfo, RashiInfo</summary>
551
651
 
552
652
  ```typescript
553
653
  interface ChandraMasaInfo {
@@ -555,10 +655,10 @@ interface ChandraMasaInfo {
555
655
  name: string; // follows masaSystem option
556
656
  isAdhika: boolean; // true = leap/intercalary month
557
657
  system: 'purnimanta' | 'amanta';
558
- amantaIndex: number; // month index in Amanta system
559
- amantaName: string; // month name in Amanta system
560
- purnimantaIndex: number; // month index in Purnimanta system
561
- purnimantaName: string; // month name in Purnimanta system
658
+ amantaIndex: number;
659
+ amantaName: string;
660
+ purnimantaIndex: number;
661
+ purnimantaName: string;
562
662
  }
563
663
 
564
664
  interface SamvatInfo {
@@ -579,7 +679,7 @@ interface RashiInfo {
579
679
  </details>
580
680
 
581
681
  <details>
582
- <summary><strong>Time Slots</strong> — Choghadiya, Gowri Panchangam, Hora</summary>
682
+ <summary><strong>Time Slots</strong> — Choghadiya, Gowri, Hora, Do Ghati</summary>
583
683
 
584
684
  ```typescript
585
685
  type ChoghadiyaQuality = 'auspicious' | 'inauspicious' | 'neutral';
@@ -588,34 +688,29 @@ interface ChoghadiyaSlot extends TimePeriod {
588
688
  index: number;
589
689
  name: string; // e.g. "Amrit", "Kaal" (localized)
590
690
  quality: ChoghadiyaQuality;
591
- qualityName: string; // localized: "Auspicious", "शुभ", "शुभम्"
691
+ qualityName: string; // localized: "Auspicious", "शुभ"
592
692
  }
593
693
 
594
694
  interface ChoghadiyaInfo {
595
- day: ChoghadiyaSlot[]; // 8 slots (sunrise -> sunset)
596
- night: ChoghadiyaSlot[]; // 8 slots (sunset -> next sunrise)
597
- }
598
-
599
- interface GowriSlot extends TimePeriod {
600
- index: number; // 0-7 within the 8-name cycle
601
- name: string; // e.g. "Amrit", "Kaal" (localized)
602
- quality: ChoghadiyaQuality;
603
- qualityName: string;
695
+ day: ChoghadiyaSlot[]; // 8 slots (sunrise -> sunset)
696
+ night: ChoghadiyaSlot[]; // 8 slots (sunset -> next sunrise)
604
697
  }
605
698
 
606
- interface GowriInfo {
607
- day: GowriSlot[]; // 8 slots (sunrise -> sunset)
608
- night: GowriSlot[]; // 8 slots (sunset -> next sunrise)
609
- }
699
+ // GowriSlot / GowriInfo mirror Choghadiya.
610
700
 
611
701
  interface HoraSlot extends TimePeriod {
612
- planet: string; // e.g. "Sun", "Venus", "Mercury"
702
+ planet: string; // "Sun", "Venus", "Mercury", ...
613
703
  planetIndex: number; // 0-6 in Chaldean order
614
704
  }
615
705
 
616
706
  interface HoraInfo {
617
- day: HoraSlot[]; // 12 slots (sunrise -> sunset)
618
- night: HoraSlot[]; // 12 slots (sunset -> next sunrise)
707
+ day: HoraSlot[]; // 12 slots (sunrise -> sunset)
708
+ night: HoraSlot[]; // 12 slots (sunset -> next sunrise)
709
+ }
710
+
711
+ interface DoGhatiInfo {
712
+ day: DoGhatiSlot[]; // 15 ~48-min deity-keyed slots
713
+ night: DoGhatiSlot[]; // 15 ~48-min deity-keyed slots
619
714
  }
620
715
  ```
621
716
  </details>
@@ -625,37 +720,28 @@ interface HoraInfo {
625
720
 
626
721
  ```typescript
627
722
  interface SpecialYogaInfo {
628
- name: string; // e.g. "Guru Pushya Yoga", "Dwipushkar Yoga"
723
+ name: string;
629
724
  type:
630
725
  | 'amrit_siddhi' | 'sarvartha_siddhi' | 'ravi_pushya' | 'guru_pushya'
631
- // Phase 28-6 Vara × Tithi × Nakshatra patterns + Moon-from-Sun distance yogas
632
- | 'dwipushkar' // Bhadra-tithi + Bhadra-vara + nakshatra ∈ {Mrigashira, Chitra, Dhanishtha} — actions doubled
633
- | 'tripushkar' // same Bhadra-tithi/vara + nakshatra {Krittika, Punarvasu, U.Phalguni, Vishakha, U.Ashadha, P.Bhadrapada} — actions tripled
634
- | 'jwalamukhi' // inauspicioustithi × nakshatra lookup per Muhurta-chintamani 6.32
635
- | 'aadal' // auspicious — Moon-from-Sun nakshatra-distance (28-scheme) ∈ {2,7,9,14,16,21,23,28}
636
- | 'vidaal' // inauspicious — Moon-from-Sun nakshatra-distance (28-scheme) ∈ {3,6,10,13,17,20,24,27}
637
- | 'ravi'; // auspicious — Moon-from-Sun nakshatra-distance (27-scheme) ∈ {4,6,9,10,13,20}
726
+ | 'dwipushkar' // Bhadra-tithi + vara + nakshatra {Mrig, Chitra, Dhan} doubled
727
+ | 'tripushkar' // same Bhadra rules + nakshatra ∈ {Krit, Punar, U.Phal, Vish, U.Ash, P.Bhad} — tripled
728
+ | 'jwalamukhi' // inauspicious tithi × nakshatra (Muhurta-chintamani 6.32)
729
+ | 'aadal' // auspiciousMoon-from-Sun nakshatra distance
730
+ | 'vidaal' // inauspicious — Moon-from-Sun nakshatra distance
731
+ | 'ravi'; // auspicious — Moon-from-Sun nakshatra distance (27-scheme)
638
732
  }
639
733
 
640
734
  interface FestivalInfo {
641
- name: string; // e.g. "Diwali", "Putrada Ekadashi", "Som Pradosh"
735
+ name: string;
642
736
  type:
643
- | 'major' // Diwali, Holi, Raksha Bandhan, Navaratri, Sankranti variants ...
644
- | 'minor' // Masik Shivaratri, Vinayaka Chaturthi, Pushya days, Shravan Somvar ...
645
- | 'ekadashi' // Generic Ekadashi (when Smarta/Vaishnava split doesn't apply)
646
- | 'smarta_ekadashi' // Smarta fast day; emits `deferralDate` when Dashami-viddha
647
- | 'vaishnava_ekadashi' // Vaishnava fast day (observed on following day if Smarta defers)
648
- | 'pradosha' // Weekday-qualified Pradosha (Som / Bhauma / Shani / etc.)
649
- | 'sankranti' // Solar-month boundary (pan-Indian + regional variants)
650
- | 'eclipse'; // Solar or lunar Grahan
737
+ | 'major' | 'minor'
738
+ | 'ekadashi' | 'smarta_ekadashi' | 'vaishnava_ekadashi'
739
+ | 'pradosha' | 'sankranti' | 'eclipse';
651
740
  description?: string;
652
741
  /** Smarta-only: when Ekadashi is Dashami-viddha, the Dwadashi fast date. */
653
742
  deferralDate?: Date;
654
743
  }
655
744
 
656
- // State-slug scheme. A caller sets `region` to limit regional variants to
657
- // their state; pan-Indian festivals (Holi, Diwali, Sankranti itself, …)
658
- // emit regardless.
659
745
  type FestivalRegion =
660
746
  | 'all' // default — emits every regional variant
661
747
  // South
@@ -670,21 +756,19 @@ type FestivalRegion =
670
756
  // Neighbour
671
757
  | 'nepal';
672
758
 
673
- // Pre-v2.1 identifiers. Accepted as input and mapped at call time; a
674
- // one-shot console warning fires per distinct legacy value. Removal in v3.
759
+ // Pre-v2.1 identifiers accepted with a one-shot deprecation warning. Removed in v3.
675
760
  // 'tamil' → 'tamil-nadu'
676
761
  // 'bengal' → 'west-bengal'
677
- // 'north-india' → 'all' (Makar Sankranti is pan-Indian; use state
678
- // slugs for Lohri / Govardhan / Bhai Dooj)
762
+ // 'north-india' → 'all'
679
763
  type LegacyFestivalRegion = 'tamil' | 'bengal' | 'north-india';
680
764
  ```
681
765
 
682
- **Region-scoped festivals** (non-exhaustive — see `src/core/festivals.ts`):
766
+ **Region-scoped festivals** (non-exhaustive):
683
767
 
684
768
  | Region | Festival names (keys) |
685
769
  |---|---|
686
770
  | `tamil-nadu` | pongal, puthandu, varamahalakshmi |
687
- | `kerala` | vishu, ayyappa_makara_jyothi, onam *(solar-nakshatra)* |
771
+ | `kerala` | vishu, ayyappa_makara_jyothi, onam |
688
772
  | `karnataka` | karaga, varamahalakshmi |
689
773
  | `andhra-pradesh` | varamahalakshmi |
690
774
  | `telangana` | bonalu, varamahalakshmi, bathukamma_start, bathukamma_saddula |
@@ -717,9 +801,9 @@ interface EclipseInfo {
717
801
  start: Date; // UTC — observable phase begins
718
802
  peak: Date; // UTC — greatest eclipse
719
803
  end: Date; // UTC — observable phase ends
720
- visibleFromLocation: boolean; // body above horizon at peak for observer
804
+ visibleFromLocation: boolean;
721
805
  magnitude: number; // fraction of disc obscured at peak, [0, 1]
722
- sutakStart: Date; // pre-eclipse impurity window begins — 12 h (4 prahara) before for solar, 9 h (3 prahara) before for lunar, per classical Smarta convention
806
+ sutakStart: Date; // 12 h before solar / 9 h before lunar
723
807
  sutakEnd: Date; // coincides with eclipse end (moksha)
724
808
  description: string;
725
809
  }
@@ -733,7 +817,7 @@ interface EclipseInfo {
733
817
  interface BhadraInfo {
734
818
  start: Date;
735
819
  end: Date;
736
- /** Loka: 'earth' = malefic for all work; 'heaven' / 'paatal' = non-terrestrial, milder. */
820
+ /** 'earth' = malefic for all work; 'heaven' / 'paatal' = non-terrestrial, milder. */
737
821
  location: 'earth' | 'heaven' | 'paatal';
738
822
  /** True when Bhadra is active at some point during the Hindu day window. */
739
823
  isActive: boolean;
@@ -742,7 +826,7 @@ interface BhadraInfo {
742
826
  </details>
743
827
 
744
828
  <details>
745
- <summary><strong>Jyotish (Vedic Astrology)</strong> — Graha positions, Vimshottari Dasha</summary>
829
+ <summary><strong>Jyotish</strong> — Graha positions, Vimshottari Dasha, Chandra Balam, Tarabala</summary>
746
830
 
747
831
  ```typescript
748
832
  type GrahaName = 'Sun' | 'Moon' | 'Mars' | 'Mercury' | 'Jupiter'
@@ -751,9 +835,9 @@ type GrahaName = 'Sun' | 'Moon' | 'Mars' | 'Mercury' | 'Jupiter'
751
835
  interface GrahaPosition {
752
836
  planet: GrahaName;
753
837
  siderealLongitude: number; // degrees [0, 360)
754
- rashi: RashiInfo; // zodiac sign
755
- degreeInRashi: number; // degrees within sign [0, 30)
756
- nakshatra: NakshatraInfo; // nakshatra + pada + completion %
838
+ rashi: RashiInfo;
839
+ degreeInRashi: number; // [0, 30)
840
+ nakshatra: NakshatraInfo;
757
841
  isRetrograde: boolean; // always false for Sun/Moon; always true for Rahu/Ketu
758
842
  }
759
843
 
@@ -766,24 +850,13 @@ interface PlanetaryPositions {
766
850
  type DashaLord = 'Ketu' | 'Venus' | 'Sun' | 'Moon' | 'Mars'
767
851
  | 'Rahu' | 'Jupiter' | 'Saturn' | 'Mercury';
768
852
 
769
- interface AntarDasha {
770
- lord: DashaLord;
771
- startDate: Date;
772
- endDate: Date;
773
- }
774
-
775
- interface MahaDasha {
776
- lord: DashaLord;
777
- startDate: Date;
778
- endDate: Date;
779
- years: number;
780
- antarDashas: AntarDasha[];
781
- }
782
-
853
+ interface AntarDasha { lord: DashaLord; startDate: Date; endDate: Date; }
854
+ interface MahaDasha { lord: DashaLord; startDate: Date; endDate: Date;
855
+ years: number; antarDashas: AntarDasha[]; }
783
856
  interface VimshottariDashaResult {
784
857
  currentMahaDashaLord: DashaLord;
785
858
  currentIndex: number;
786
- mahaDashas: MahaDasha[]; // 9-entry sequence starting from birth
859
+ mahaDashas: MahaDasha[]; // 9-entry sequence starting from birth
787
860
  }
788
861
 
789
862
  interface ChandraBalamInfo {
@@ -794,23 +867,54 @@ interface ChandraBalamInfo {
794
867
  }
795
868
 
796
869
  interface TarabalaInfo {
797
- taraIndex: number; // 0..8 — position in the 9-tara cycle from janma nakshatra
870
+ taraIndex: number; // 0..8 in the 9-tara cycle from janma nakshatra
798
871
  englishName: string; // "Janma" | "Sampat" | "Vipat" | "Kshema" | "Pratyari"
799
872
  // | "Sadhaka" | "Vadha" | "Mitra" | "Ati-Mitra"
800
- name: string; // localized
873
+ name: string;
801
874
  quality: 'auspicious' | 'inauspicious';
802
- // 'inauspicious' for Vipat (2) / Pratyari (4) / Vadha (6); rest auspicious
803
875
  }
804
876
  ```
805
877
  </details>
806
878
 
879
+ ### Full export list
880
+
881
+ ```typescript
882
+ // Primary entry points
883
+ getDailyPanchang, getInstantPanchang
884
+
885
+ // Astronomy
886
+ getSunrise, getSunset, getMoonrise, getMoonset
887
+ getSiderealSunLongitude, getSiderealMoonLongitude, getAyanamsa
888
+
889
+ // Inauspicious / Muhurta
890
+ computeRahuKalam, computeGulikaKalam, computeYamaganda
891
+ computeVarjyam, computeGandaMula, computeAnandadiYoga
892
+ computePanchakaRahita, computeDoGhati, computeGowriPanchangam
893
+ computeAbhijitMuhurta, computeBrahmaMuhurta, computeVijayaMuhurta
894
+ computeGodhuliMuhurta, computeNishitaMuhurta, computeAmritKala
895
+ computeMadhyahna, computePratahSandhya, computeSayahnaSandhya
896
+
897
+ // Eclipses
898
+ getUpcomingSolarEclipse, getUpcomingLunarEclipse, getEclipseDuringDay
899
+
900
+ // Jyotish
901
+ computePlanetaryPositions, GRAHA_ABBR
902
+ computeVimshottariDasha, computeVimshottariDashaFromBirth, computeVimshottariPratyantar
903
+ computeChandraBalam, computeTarabala
904
+ computeLagna, computeBhava, computeRashiChart, computeNavamsa
905
+ computeAshtakoot, computeMangalDosha, computeSadeSati, computeDignity
906
+
907
+ // Errors
908
+ PanchangError
909
+ ```
910
+
807
911
  ---
808
912
 
809
913
  ## React Native / Hermes
810
914
 
811
- Works with Expo and bare React Native (Hermes engine). Pass `timezone` as a **number**
812
- IANA timezone strings (`'Asia/Kolkata'`) require `Intl`, which older Hermes versions
813
- don't fully support.
915
+ Works with Expo and bare React Native (Hermes engine). Pass `timezone` as a **number**
916
+ IANA timezone strings (`'Asia/Kolkata'`) require `Intl`, which older Hermes versions don't
917
+ fully support.
814
918
 
815
919
  **Two-pass rendering** for smooth UI:
816
920
 
@@ -836,38 +940,47 @@ InteractionManager.runAfterInteractions(() => {
836
940
 
837
941
  ## Accuracy
838
942
 
839
- 6,048 tests passing across 61 files, including fixtures cross-verified
840
- against reference panchang calculations spanning 2025–2026 across 10
841
- Indian cities (Phase 28 cross-verify) plus New York, London, Sydney,
842
- Dubai, and Singapore (diaspora fixtures cover DST transitions on
943
+ 6,912 tests passing across 74 files, including fixtures cross-verified against reference
944
+ panchang calculations spanning 2025–2026 across 10 Indian cities, plus New York, London,
945
+ Sydney, Dubai, and Singapore (diaspora fixtures cover DST transitions on
843
946
  `America/New_York`).
844
947
 
845
948
  | Element | Accuracy | Validation |
846
949
  |---------|----------|------------|
847
- | Sunrise / Sunset | **≤29 s observed vs reference minute-midpoint** (±45 s tolerance) | 16 assertions |
848
- | Moonrise / Moonset | Meeus apparent-upper-limb convention (refraction + parallax); ~3–5 min disagreement vs panchang authorities that use a simpler horizon model is expected and documented | Strict fixtures |
950
+ | Sunrise / Sunset | 29 s observed vs reference minute-midpoint (±45 s tolerance) | 16 assertions |
951
+ | Moonrise / Moonset | Meeus apparent-upper-limb (refraction + parallax); ~3–5 min vs simpler-horizon authorities is expected | Strict fixtures |
849
952
  | Tithi, Nakshatra, Yoga, Karana names | Exact match vs reference | Strict fixtures |
850
- | Tithi / Nakshatra / Yoga / Karana end-times | **±3 min tolerance, max 2.01 min observed** | 20 assertions |
953
+ | Tithi / Nakshatra / Yoga / Karana end-times | ±3 min tolerance, max 2.01 min observed | 20 assertions |
851
954
  | Ayanamsa | ±0.005° vs Swiss Ephemeris | Unit tests |
852
- | Planetary positions (Sun–Saturn) | **±0.02° vs reference sidereal** | Fixtures |
853
- | Planetary positions (Rahu/Ketu, mean node) | ≤0.5° typical; ±2° tolerance to absorb mean-vs-true drift | Fixtures |
955
+ | Planetary positions (Sun–Saturn) | ±0.02° vs reference sidereal | Fixtures |
956
+ | Planetary positions (Rahu/Ketu, mean node) | ≤0.5° typical; ±2° tolerance | Fixtures |
957
+ | Planetary positions (Rahu/Ketu, true node) | ≤0.6° typical (Meeus periodic correction) | Fixtures |
854
958
  | Rashi / Nakshatra / Retrograde flag | Exact match vs reference | Fixtures |
855
959
  | Festival dates | 12 cross-verified festivals (2025–2026) — see caveats below | Fixtures |
856
960
  | Choghadiya / Hora / Gowri slots | Derived from sunrise/sunset — inherits ±2 min | — |
857
- | Madhyahna midpoint, Anandadi Yoga name, Ganda Mula active flag | **Exact match across 50 Drik fixtures** (10 cities × 5 dates) | [phase28-cross-verify](tests/validation/phase28-cross-verify.test.ts) |
858
- | Pratah / Sayahna Sandhya start + end | **±2 min vs Drik** across all 50 fixtures | [phase28-cross-verify](tests/validation/phase28-cross-verify.test.ts) |
859
- | Varjyam start + end | **±2 min vs Drik** on every fixture where the library emits a non-null window (≥30 of 50 emit; transition days return `null` by design) | [phase28-cross-verify](tests/validation/phase28-cross-verify.test.ts) |
860
-
861
- **Phase 28 sourcing notes** (see [phase28-cross-verify.test.ts](tests/validation/phase28-cross-verify.test.ts) for per-feature findings): **Aadal / Vidaal** follow the classical Moon-from-Sun nakshatra-distance rule (AstroShastra, HoraSarvam, Ernst Wilhelm), NOT the popular Tamil-Vakya weekday rule used by some online panchangs — Drik publishes no algorithmic rule text for these and may use the weekday rule, so the library's output may differ from Drik's Aadal/Vidaal occurrence pages by design. **Varjyam** emits the sunrise-anchored nakshatra's window only (single-window contract per [src/core/varjyam.ts:31-38](src/core/varjyam.ts#L31-L38)) — printed panchangs may show a second window on nakshatra-transition days. **Do Ghati Muhurta** does not rotate by weekday: the same 30-name deity-keyed sequence applies every day, verified against drikpanchang.com/muhurat/daily/do-ghati-muhurat.html for two distinct weekdays. Sourcing is cited inline in [src/core/doGhati.ts:3-21](src/core/doGhati.ts#L3-L21).
961
+ | Madhyahna midpoint, Anandadi Yoga, Ganda Mula active flag | Exact match across 50 reference fixtures | Cross-verify suite |
962
+ | Pratah / Sayahna Sandhya start + end | ±2 min across all 50 fixtures | Cross-verify suite |
963
+ | Varjyam start + end | ±2 min on every emit (transition days return `null` by design) | Cross-verify suite |
964
+ | Lagna sidereal longitude | Cross-checked against Jagannath Hora reference charts | Birth-chart fixtures |
965
+ | D1 (Rashi) & D9 (Navamsa) house placements | Exact match vs reference for 9-graha placement | Birth-chart fixtures |
966
+ | Ashtakoot Guna Milan total score | ±1 point per pair across 30+ matched pairs | Match fixtures |
967
+ | Sade Sati arc start / end | ±1–2 days vs authoritative ephemerides | Saturn-transit fixtures |
968
+
969
+ **Detection sourcing notes.** **Aadal / Vidaal** follow the classical Moon-from-Sun
970
+ nakshatra-distance rule (AstroShastra, HoraSarvam, Ernst Wilhelm), NOT the popular
971
+ Tamil-Vakya weekday rule used by some online panchangs — output may differ from sites that
972
+ use the weekday rule. **Varjyam** emits the sunrise-anchored nakshatra's window only —
973
+ printed panchangs may show a second window on nakshatra-transition days. **Do Ghati
974
+ Muhurta** does not rotate by weekday: the same 30-name deity-keyed sequence applies every
975
+ day, verified against multiple reference sources for distinct weekdays.
862
976
 
863
977
  ### Festival Detection — Documented Tradeoff
864
978
 
865
- The library uses **tithi-at-sunrise** to resolve a festival to a calendar
866
- day. Some traditional panchang authorities apply other classical rules
867
- (tithi-at-midnight, madhyahna-vyapini, kshaya-tithi handling) for certain
868
- festivals; where those rules pick a different day, our output can drift
869
- ±1 day. This is a rule-choice tradeoff, not a computation bug — it is
870
- documented and deliberately surfaced rather than hidden.
979
+ The library uses **tithi-at-sunrise** to resolve a festival to a calendar day. Some
980
+ traditional panchang authorities apply other classical rules (tithi-at-midnight,
981
+ madhyahna-vyapini, kshaya-tithi handling) for certain festivals; where those rules pick a
982
+ different day, our output can drift ±1 day. This is a rule-choice tradeoff, not a
983
+ computation bug.
871
984
 
872
985
  | Alternative classical rule | Festivals affected |
873
986
  |----------------------------|--------------------|
@@ -875,11 +988,11 @@ documented and deliberately surfaced rather than hidden.
875
988
  | Madhyahna-vyapini (tithi overlapping noon) | Ganesh Chaturthi on edge years, Akshaya Tritiya 2026 |
876
989
  | Kshaya-tithi handling (tithi never at sunrise) | Ugadi 2026-03-19 (Pratipada is Kshaya) |
877
990
 
878
- If strict parity with a specific panchang authority matters for your use
879
- case, cross-check the above festival set for the target year. Everything
880
- else — Holi, Ugadi (non-Kshaya years), Rama Navami, Raksha Bandhan,
881
- Ganesh Chaturthi (normal years), Navaratri, Dussehra, Karva Chauth,
882
- Hanuman Jayanti — matches the canonical date across 2025 and 2026 fixtures.
991
+ If strict parity with a specific panchang authority matters for your use case, cross-check
992
+ the above festival set for the target year. Everything else — Holi, Ugadi (non-Kshaya
993
+ years), Rama Navami, Raksha Bandhan, Ganesh Chaturthi (normal years), Navaratri,
994
+ Dussehra, Karva Chauth, Hanuman Jayanti matches the canonical date across 2025 and 2026
995
+ fixtures.
883
996
 
884
997
  ---
885
998
 
@@ -890,6 +1003,9 @@ Hanuman Jayanti — matches the canonical date across 2025 and 2026 fixtures.
890
1003
  | Names-only (`computeEndTimes: false`) | ~0.1 ms | <100 ms |
891
1004
  | Full with end-times | ~0.5 ms | <500 ms |
892
1005
 
1006
+ Birth-chart helpers are independent — calling them does not add work to
1007
+ `getDailyPanchang`.
1008
+
893
1009
  ---
894
1010
 
895
1011
  ## Error Handling
@@ -907,15 +1023,15 @@ try {
907
1023
  }
908
1024
  ```
909
1025
 
910
- Error codes: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`,
911
- `INVALID_ELEVATION`, `INVALID_TIMEZONE`, `INVALID_AYANAMSA`, `TIMEZONE_RESOLUTION_FAILED`,
912
- `NO_SUNRISE`, `NO_SUNSET`, `SEARCH_DIVERGED`.
1026
+ Error codes: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`, `INVALID_ELEVATION`,
1027
+ `INVALID_TIMEZONE`, `INVALID_AYANAMSA`, `TIMEZONE_RESOLUTION_FAILED`, `NO_SUNRISE`,
1028
+ `NO_SUNSET`, `SEARCH_DIVERGED`, `CIRCUMPOLAR` (Placidus-KP houses above ±66.5°).
913
1029
 
914
1030
  **Polar locations (no sunrise / no sunset):** `getDailyPanchang` and `getInstantPanchang`
915
1031
  return `null` rather than throwing — the Hindu day is undefined when sunrise can't be
916
- computed. The low-level `computeSunrise` / `computeSunset` primitives still throw
917
- `PanchangError(NO_SUNRISE)` / `PanchangError(NO_SUNSET)` for direct callers who need
918
- the precise reason. `getMoonrise` / `getMoonset` return `null` (normal for the Moon).
1032
+ computed. The low-level `getSunrise` / `getSunset` primitives still throw
1033
+ `PanchangError(NO_SUNRISE)` / `PanchangError(NO_SUNSET)` for direct callers who need the
1034
+ precise reason. `getMoonrise` / `getMoonset` return `null` (normal for the Moon).
919
1035
 
920
1036
  ---
921
1037
 
@@ -931,13 +1047,10 @@ the precise reason. `getMoonrise` / `getMoonset` return `null` (normal for the M
931
1047
 
932
1048
  ---
933
1049
 
934
- ## Used By
935
-
936
- - [dharmagya.app](https://dharmagya.app) — Daily Panchang and Hindu calendar
937
-
938
1050
  ## Acknowledgements
939
1051
 
940
- [astronomy-engine](https://github.com/cosinekitty/astronomy) by Don Cross — the sole runtime dependency. MIT licensed.
1052
+ [astronomy-engine](https://github.com/cosinekitty/astronomy) by Don Cross — the sole
1053
+ runtime dependency. MIT licensed.
941
1054
 
942
1055
  ## License
943
1056