panchang-ts 5.0.0 → 5.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 +163 -1186
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
# panchang-ts
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/panchang-ts)
|
|
4
|
+
[](./LICENSE)
|
|
4
5
|
|
|
5
6
|
Pure TypeScript Hindu Panchang (almanac), Jyotish, and Birth Chart calculations.
|
|
6
|
-
Zero
|
|
7
|
+
Zero runtime dependencies. Works offline in React Native (Hermes), Node.js, and browsers.
|
|
7
8
|
|
|
8
9
|
**Fast** (~0.25 ms trimmed, ~0.41 ms full) · **Typed** (full TypeScript) · **Offline** (pure JS math) · **8,368 tests across 121 files**
|
|
9
10
|
|
|
11
|
+
> 📖 **Full documentation: [dharmagya.app/docs/panchang-ts](https://dharmagya.app/docs/panchang-ts)**
|
|
12
|
+
> This README covers install, quick start, and the 4.x → 5 migration in full, plus a per-feature
|
|
13
|
+
> quick reference. The complete reference — every option, result field, table format, accuracy
|
|
14
|
+
> bound and performance note — lives on the docs site.
|
|
15
|
+
|
|
10
16
|
---
|
|
11
17
|
|
|
12
18
|
## Install
|
|
@@ -318,10 +324,8 @@ a `*Local` companion: `sun.riseLocal`, `inauspicious.rahuKalam.startLocal`,
|
|
|
318
324
|
timezone, so there is no zone to render a wall clock in.
|
|
319
325
|
|
|
320
326
|
**Cost:** rendering the strings adds ~0.04 ms per daily panchang — invisible on
|
|
321
|
-
a cold call
|
|
322
|
-
|
|
323
|
-
change landed, mid-Phase-36; the release finally warms to **0.17 ms**, against
|
|
324
|
-
published 4.3.1's **6.20 ms**.
|
|
327
|
+
a cold call and ~20% of a fully cached warm one. The release warms to
|
|
328
|
+
**0.17 ms**, against published 4.3.1's **6.20 ms**.
|
|
325
329
|
|
|
326
330
|
### `result.timezone` is now an object
|
|
327
331
|
|
|
@@ -485,1109 +489,221 @@ the **lunar** one, which was previously left to guesswork.
|
|
|
485
489
|
|
|
486
490
|
# Feature Reference
|
|
487
491
|
|
|
488
|
-
|
|
489
|
-
|
|
492
|
+
A quick tour with runnable snippets. **Each section links to its full page on
|
|
493
|
+
the docs site** — every option, field, and caveat lives there.
|
|
494
|
+
|
|
495
|
+
## Pancha Anga & the daily result
|
|
490
496
|
|
|
491
|
-
|
|
497
|
+
📖 [Daily Panchang →](https://dharmagya.app/docs/panchang-ts/daily-panchang)
|
|
492
498
|
|
|
493
499
|
```typescript
|
|
494
500
|
const r = getDailyPanchang(date, location, { timezone: 330 })!;
|
|
495
501
|
|
|
496
|
-
r.angas.tithis.forEach(t => console.log(t.name, t.paksha, t.
|
|
497
|
-
r.angas.
|
|
498
|
-
r.
|
|
499
|
-
r.
|
|
500
|
-
|
|
502
|
+
r.angas.tithis.forEach(t => console.log(t.name, t.paksha, t.endTime));
|
|
503
|
+
r.angas.vara.name; // "Mangalawara"
|
|
504
|
+
r.calendar.chandramasa.isAdhika; // true during leap months
|
|
505
|
+
r.muhurtas.brahma; // TimePeriod | null — and 9 more muhurtas
|
|
506
|
+
r.inauspicious.rahuKalam; // { start, end } — and 9 more windows
|
|
507
|
+
r.periods.choghadiya.day[0].name; // 16 Choghadiya + Gowri + 24 Hora slots
|
|
508
|
+
r.anandadiYoga.name; r.specialYogas; // Anandadi + Amrit/Sarvartha Siddhi, …
|
|
501
509
|
|
|
502
510
|
// Single-instant snapshot:
|
|
503
511
|
import { getInstantPanchang } from 'panchang-ts';
|
|
504
512
|
const i = getInstantPanchang(new Date(), location)!;
|
|
505
|
-
console.log(i.angas.tithi.name, i.angas.nakshatra.name
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
## Lunar & Solar Calendar
|
|
509
|
-
|
|
510
|
-
```typescript
|
|
511
|
-
const r = getDailyPanchang(date, loc, { timezone: 330, masaSystem: 'purnimanta' })!;
|
|
512
|
-
|
|
513
|
-
r.calendar.chandramasa.name; // active system (default: Purnimanta / North Indian)
|
|
514
|
-
r.calendar.chandramasa.amantaName; // South Indian
|
|
515
|
-
r.calendar.chandramasa.purnimantaName; // North Indian
|
|
516
|
-
r.calendar.chandramasa.isAdhika; // true during leap months
|
|
517
|
-
r.calendar.samvat.vikramSamvat; // 2081
|
|
518
|
-
r.calendar.samvat.shakaSamvat; // 1946
|
|
519
|
-
|
|
520
|
-
r.calendar.masa.name; // current solar month (Mesha … Meena)
|
|
521
|
-
r.sun.nakshatra.name; // Sun's nakshatra
|
|
522
|
-
r.moon.rashi.name; // Moon sign
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
## Sun, Moon & Muhurta
|
|
526
|
-
|
|
527
|
-
```typescript
|
|
528
|
-
import { getSunrise, getSunset, getMoonrise, getMoonset } from 'panchang-ts';
|
|
529
|
-
|
|
530
|
-
const sunrise = getSunrise(localMidnightUtc, loc);
|
|
531
|
-
const sunset = getSunset(sunrise, loc);
|
|
532
|
-
const moonrise = getMoonrise(localMidnightUtc, loc); // null on some days (normal)
|
|
533
|
-
const moonset = getMoonset(localMidnightUtc, loc);
|
|
534
|
-
|
|
535
|
-
// Or read off the daily result:
|
|
536
|
-
const r = getDailyPanchang(date, loc, { timezone: 330 })!;
|
|
537
|
-
r.sun.rise; r.sun.set; r.moon.rise; r.moon.set; r.sun.nextRise;
|
|
538
|
-
r.sun.dayDurationMinutes; r.sun.nightDurationMinutes;
|
|
539
|
-
|
|
540
|
-
// Auspicious muhurtas
|
|
541
|
-
r.muhurtas.brahma; // two muhurtas before sunrise
|
|
542
|
-
r.muhurtas.abhijit; // 8th day-muhurta; null on Wednesday (Drik convention)
|
|
543
|
-
r.muhurtas.vijaya; // 11th day-muhurta
|
|
544
|
-
r.muhurtas.godhuli; // "cow-dust" sunset muhurta
|
|
545
|
-
r.muhurtas.nishita; // midnight muhurta (Shivaratri)
|
|
546
|
-
r.muhurtas.madhyahna; // solar noon ±24 min
|
|
547
|
-
r.muhurtas.pratahSandhya; // dawn twilight, ends at sunrise
|
|
548
|
-
r.muhurtas.sayahnaSandhya; // dusk twilight, starts at sunset
|
|
549
|
-
r.muhurtas.amritKala; // nakshatra-specific window (null when nakshatra has none)
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
`muhurtas.pratahSandhya` / `muhurtas.sayahnaSandhya` width =
|
|
553
|
-
`sun.nightDurationMinutes / 10` (~62–81 min).
|
|
554
|
-
|
|
555
|
-
## Inauspicious Periods
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
const r = getDailyPanchang(date, loc, { timezone: 330 })!;
|
|
559
|
-
|
|
560
|
-
r.inauspicious.rahuKalam; // { start, end }
|
|
561
|
-
r.inauspicious.gulikaKalam;
|
|
562
|
-
r.inauspicious.yamaganda;
|
|
563
|
-
r.inauspicious.durMuhurta; // two ~48-min windows
|
|
564
|
-
r.inauspicious.varjyam; // { start, end } | null
|
|
565
|
-
r.inauspicious.gandaMula; // { active, severity: 'mild'|'severe'|null, ... }
|
|
566
|
-
r.inauspicious.bhadra; // { start, end, location: 'earth'|'heaven'|'paatal', isActive } | null
|
|
567
|
-
r.inauspicious.panchaka; // boolean — Moon in last 5 nakshatras
|
|
568
|
-
r.inauspicious.panchakaInfo; // which of the five, and whether it's a dosha
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
Panchaka is not one undifferentiated affliction. The tradition names five and
|
|
572
|
-
picks between them by **the weekday the spell began on** — so the type belongs
|
|
573
|
-
to the spell, not the day, and two days with identical tithi, nakshatra and
|
|
574
|
-
vara can carry different ones. A spell begun on a Wednesday or Thursday
|
|
575
|
-
(`'samanya'`) carries no named affliction at all:
|
|
576
|
-
|
|
577
|
-
```typescript
|
|
578
|
-
const pk = r.inauspicious.panchakaInfo;
|
|
579
|
-
if (pk.active && pk.isDosha) {
|
|
580
|
-
console.log(pk.name, '— began on vara', pk.onsetVara); // e.g. "Mrityu Panchaka"
|
|
581
|
-
}
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
## Time-Slot Systems
|
|
585
|
-
|
|
586
|
-
```typescript
|
|
587
|
-
const r = getDailyPanchang(date, loc, { timezone: 330 })!;
|
|
588
|
-
|
|
589
|
-
// Choghadiya — 8 day + 8 night named, rated slots (Amrit, Kaal, Shubh, Rog, …)
|
|
590
|
-
r.periods.choghadiya.day.forEach(s => console.log(s.name, s.qualityName, s.start, s.end));
|
|
591
|
-
|
|
592
|
-
// Gowri Panchangam ("Nalla Neram") — 8 day + 8 night Tamil slots
|
|
593
|
-
r.periods.gowri.day.forEach(s => console.log(s.name, s.qualityName));
|
|
594
|
-
|
|
595
|
-
// Hora — 12 day + 12 night planetary hours (Chaldean order)
|
|
596
|
-
r.periods.hora.day.forEach(h => console.log(h.planet, h.start, h.end));
|
|
597
|
-
|
|
598
|
-
// Do Ghati Muhurta — 15 day + 15 night ~48-min deity-keyed slots (no vara rotation)
|
|
599
|
-
r.muhurtas.doGhati.day.forEach(g => console.log(g.name, g.start, g.end));
|
|
600
|
-
|
|
601
|
-
// Panchaka Rahita — slices of the day FREE of Panchaka ([] when it pervades)
|
|
602
|
-
r.inauspicious.panchakaRahita.forEach(slice => console.log(slice.start, slice.end));
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
## Special Yogas
|
|
606
|
-
|
|
607
|
-
```typescript
|
|
608
|
-
const r = getDailyPanchang(date, loc, { timezone: 330 })!;
|
|
609
|
-
|
|
610
|
-
r.anandadiYoga.name; // 28-cycle name e.g. "Ananda"
|
|
611
|
-
r.specialYogas.forEach(y => {
|
|
612
|
-
// type: amrit_siddhi | sarvartha_siddhi | ravi_pushya | guru_pushya
|
|
613
|
-
// | dwipushkar | tripushkar | jwalamukhi (inauspicious)
|
|
614
|
-
// | aadal | vidaal | ravi (Moon-from-Sun nakshatra-distance rules)
|
|
615
|
-
console.log(y.name, y.type);
|
|
616
|
-
});
|
|
513
|
+
console.log(i.angas.tithi.name, i.angas.nakshatra.name);
|
|
617
514
|
```
|
|
618
515
|
|
|
619
516
|
## Festivals (80+)
|
|
620
517
|
|
|
621
|
-
|
|
622
|
-
fast emits a `deferralDate` for Dwadashi), Pradosha, Sankranti + regional
|
|
623
|
-
variants (Pongal, Vishu, Baisakhi, Pohela Boishakh, Bihu, Uttarayan, Lohri…),
|
|
624
|
-
canonical-time classical (Janmashtami, Shivaratri, Ganesh Chaturthi, Diwali,
|
|
625
|
-
Holi, Raksha Bandhan — Bhadra-aware, Karva Chauth, Akshaya Tritiya…),
|
|
626
|
-
regional (Gudi Padwa, Gangaur, Teej variants, Onam, Chhath…), monthly
|
|
627
|
-
observances (Masik Shivaratri, Pushya days, Shravan Somvar…).
|
|
518
|
+
📖 [Festivals →](https://dharmagya.app/docs/panchang-ts/festivals)
|
|
628
519
|
|
|
629
520
|
```typescript
|
|
630
|
-
r.festivals.forEach(f =>
|
|
631
|
-
|
|
632
|
-
// type: major | minor | ekadashi | smarta_ekadashi | vaishnava_ekadashi
|
|
633
|
-
// | pradosha | sankranti | eclipse
|
|
634
|
-
console.log(f.key, f.name, f.type, f.deferralDate);
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
// `name` is localized, so match on `key` — never on `name`.
|
|
521
|
+
r.festivals.forEach(f => console.log(f.key, f.name, f.type, f.deferralDate));
|
|
522
|
+
// `name` is localized, so match on `key` — never on `name`:
|
|
638
523
|
const hasDiwali = r.festivals.some(f => f.key === 'diwali');
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
`key` is on engine results (`getDailyPanchang`, `getInstantPanchang`,
|
|
642
|
-
`computeFestivalsInRange`). Entries read back out of a `buildFestivalsTable` table
|
|
643
|
-
carry `name` / `type` / `description` only.
|
|
644
|
-
|
|
645
|
-
### Regional scoping
|
|
646
524
|
|
|
647
|
-
|
|
648
|
-
|
|
525
|
+
// Scope regional variants: 21 state slugs + 'nepal' + 'all' (default)
|
|
526
|
+
getDailyPanchang(jan14, chennai, { timezone: 330, region: 'tamil-nadu' });
|
|
649
527
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
// → ["Sankranti","Makar Sankranti","Pongal","Uttarayan","Magh Bihu","Ayyappa Makara Jyothi"]
|
|
654
|
-
|
|
655
|
-
// Tamil Nadu only:
|
|
656
|
-
getDailyPanchang(jan14, chennai, { timezone: 330, region: 'tamil-nadu' })!
|
|
657
|
-
.festivals.map(f => f.name);
|
|
658
|
-
// → ["Sankranti","Makar Sankranti","Pongal"]
|
|
659
|
-
|
|
660
|
-
// Lohri fires on the Hindu day BEFORE Makara transit, in Punjab/Haryana/Himachal scope:
|
|
661
|
-
getDailyPanchang(jan13, amritsar, { timezone: 330, region: 'punjab' })!
|
|
662
|
-
.festivals.some(f => f.name === 'Lohri'); // true
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
`FestivalRegion` covers 21 Indian states + `'nepal'` + `'all'` (default). The
|
|
666
|
-
legacy slugs `'tamil'`, `'bengal'`, `'north-india'` are still accepted and
|
|
667
|
-
mapped internally.
|
|
668
|
-
|
|
669
|
-
### Pre-computed table — build your own and cache it
|
|
670
|
-
|
|
671
|
-
If you want festival *dates* without running the engine in your app, compute a
|
|
672
|
-
table once with `buildFestivalsTable`, cache the JSON, and read it back through
|
|
673
|
-
the engine-free `panchang-ts/festivals` entry point.
|
|
674
|
-
|
|
675
|
-
**The library ships no pre-computed table.** Festival dates are
|
|
676
|
-
observer-dependent — canonical times (nishita / pradosha / chandrodaya …) shift
|
|
677
|
-
with the timezone offset, so a table built for one place can be ±1 day wrong
|
|
678
|
-
elsewhere — and any table baked into the package would also go stale. Building
|
|
679
|
-
your own means it is correct for *your* users and covers whatever years you
|
|
680
|
-
want.
|
|
681
|
-
|
|
682
|
-
```typescript
|
|
683
|
-
import { buildFestivalsTable } from 'panchang-ts'; // uses the engine
|
|
684
|
-
import {
|
|
685
|
-
readFestivalsForYear,
|
|
686
|
-
readFestivalsForDate,
|
|
687
|
-
readFestivalsYearRange,
|
|
688
|
-
} from 'panchang-ts/festivals'; // engine-free
|
|
689
|
-
|
|
690
|
-
// Build once — at your build time, or on first launch in the background.
|
|
691
|
-
const table = buildFestivalsTable({
|
|
692
|
-
location: { latitude: 25.3176, longitude: 82.9739 }, // Varanasi
|
|
693
|
-
timezoneOffsetMinutes: 330, // IST; -300 = US Eastern, 0 = UK
|
|
694
|
-
startYear: 2024,
|
|
695
|
-
endYear: 2031,
|
|
696
|
-
languages: ['en', 'hi'], // drop 'hi' to halve the size
|
|
697
|
-
referenceLocation: 'Varanasi',
|
|
698
|
-
});
|
|
699
|
-
// …persist `table` as JSON (disk / MMKV / your bundler's asset pipeline).
|
|
700
|
-
|
|
701
|
-
// Later reads are instant lookups — no engine, no ephemeris.
|
|
702
|
-
readFestivalsYearRange(table); // { start: 2024, end: 2031 }
|
|
703
|
-
readFestivalsForYear(table, 2026)!.length; // ~150 festival days
|
|
704
|
-
const diwali = readFestivalsForYear(table, 2026)!
|
|
705
|
-
.find(d => d.festivals.some(f => f.name === 'Diwali'))!.date;
|
|
706
|
-
readFestivalsForDate(table, diwali); // [Narak Chaturdashi, Diwali]
|
|
707
|
-
readFestivalsForDate(table, diwali, 'hi'); // [नरक चतुर्दशी, दिवाली]
|
|
528
|
+
// Pre-computed table: build once, cache the JSON, read engine-free.
|
|
529
|
+
import { buildFestivalsTable } from 'panchang-ts';
|
|
530
|
+
import { readFestivalsForYear, readFestivalsForDate } from 'panchang-ts/festivals';
|
|
708
531
|
```
|
|
709
532
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
JSON.
|
|
714
|
-
|
|
715
|
-
Eclipses are excluded here — visibility is location-dependent, so they get their
|
|
716
|
-
own table at `panchang-ts/eclipses` (see [Eclipses](#eclipses)).
|
|
533
|
+
No table ships with the package — festival dates are observer-dependent, so you
|
|
534
|
+
build one for your users' location and years (`npm run festivals:gen` is a
|
|
535
|
+
worked example).
|
|
717
536
|
|
|
718
|
-
|
|
719
|
-
rolling 2-past / 5-future window to `./festivals.json` (or a path you pass).
|
|
537
|
+
## Eclipses & Moon Phases
|
|
720
538
|
|
|
721
|
-
|
|
722
|
-
naming.
|
|
723
|
-
|
|
724
|
-
## Eclipses
|
|
539
|
+
📖 [Eclipses & Moon Phases →](https://dharmagya.app/docs/panchang-ts/eclipses-moon-phases)
|
|
725
540
|
|
|
726
541
|
```typescript
|
|
727
|
-
const r = getDailyPanchang(date, loc, { timezone: 330 })!;
|
|
728
542
|
if (r.eclipse) {
|
|
729
|
-
r.eclipse.kind;
|
|
730
|
-
r.eclipse.
|
|
731
|
-
r.eclipse.
|
|
732
|
-
r.eclipse.magnitude; // catalogue magnitude — DIAMETER fraction;
|
|
733
|
-
// >1 when total, negative when penumbral
|
|
734
|
-
r.eclipse.visibleFromLocation; // body above horizon at peak?
|
|
735
|
-
r.eclipse.start; r.eclipse.peak; r.eclipse.end;
|
|
543
|
+
r.eclipse.kind; r.eclipse.subtype; // 'solar'|'lunar', 'partial'|'total'|…
|
|
544
|
+
r.eclipse.obscuration; // disc AREA covered, 0..1
|
|
545
|
+
r.eclipse.magnitude; // catalogue DIAMETER fraction
|
|
736
546
|
r.eclipse.sutakStart; r.eclipse.sutakEnd;
|
|
737
|
-
// Sutak: 12 h (4 prahara) before solar, 9 h (3 prahara) before lunar
|
|
738
547
|
}
|
|
739
548
|
|
|
740
|
-
import { getUpcomingSolarEclipse,
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
### Pre-computed table — build your own and cache it
|
|
549
|
+
import { getUpcomingSolarEclipse, computeMoonPhasesInRange } from 'panchang-ts';
|
|
550
|
+
getUpcomingSolarEclipse(new Date(), loc, 365);
|
|
551
|
+
computeMoonPhasesInRange(start, end); // precise new/quarter/full instants
|
|
745
552
|
|
|
746
|
-
|
|
747
|
-
read it back through the engine-free `panchang-ts/eclipses` entry point.
|
|
748
|
-
|
|
749
|
-
**No table is bundled.** Which eclipses are visible — and therefore which carry
|
|
750
|
-
`sutak` — is location-dependent, so a table is only meaningful for the place it
|
|
751
|
-
was built for.
|
|
752
|
-
|
|
753
|
-
```typescript
|
|
754
|
-
import { buildEclipsesTable } from 'panchang-ts'; // uses the engine
|
|
755
|
-
import {
|
|
756
|
-
readEclipsesForYear,
|
|
757
|
-
readEclipsesForDate,
|
|
758
|
-
readEclipsesYearRange,
|
|
759
|
-
} from 'panchang-ts/eclipses'; // engine-free
|
|
760
|
-
|
|
761
|
-
const table = buildEclipsesTable({
|
|
762
|
-
location: { latitude: 25.3176, longitude: 82.9739 }, // Varanasi
|
|
763
|
-
timezoneOffsetMinutes: 330,
|
|
764
|
-
startYear: 2024,
|
|
765
|
-
endYear: 2031,
|
|
766
|
-
languages: ['en', 'hi'],
|
|
767
|
-
// visibleOnly: false → also include eclipses below the horizon (no sutak)
|
|
768
|
-
});
|
|
769
|
-
// …persist `table` as JSON, then:
|
|
770
|
-
|
|
771
|
-
readEclipsesYearRange(table); // { start: 2024, end: 2031 }
|
|
772
|
-
const e = readEclipsesForYear(table, 2025)![0].eclipses[0];
|
|
773
|
-
e.kind; // 'lunar'
|
|
774
|
-
e.subtype; // 'total'
|
|
775
|
-
e.start; e.peak; e.end; // ISO UTC strings
|
|
776
|
-
e.obscuration; // 0..1 disc area covered at peak
|
|
777
|
-
e.magnitude; // catalogue magnitude (diameter); >1 total, <0 penumbral
|
|
778
|
-
e.visibleFromLocation; // visible during any phase?
|
|
779
|
-
e.visibleAtPeak; // is greatest eclipse itself above the horizon?
|
|
780
|
-
e.sutak; // { start, end } — see note below
|
|
781
|
-
readEclipsesForDate(table, '2025-09-07', 'hi'); // [पूर्ण चंद्र ग्रहण]
|
|
553
|
+
// Engine-free tables: panchang-ts/eclipses and panchang-ts/moon-phases
|
|
782
554
|
```
|
|
783
555
|
|
|
784
|
-
|
|
785
|
-
phase** (so one already in progress at moon/sunrise or moon/sunset is included);
|
|
786
|
-
`visibleAtPeak` tells you whether greatest eclipse itself is observable.
|
|
787
|
-
|
|
788
|
-
Solar eclipses report the subtype seen **locally** (a globally-total eclipse may
|
|
789
|
-
read `partial` from a given place). The `sutak` window is present only where it
|
|
790
|
-
applies — all visible solar eclipses and visible **umbral** (partial/total)
|
|
791
|
-
lunar eclipses; **penumbral** lunar eclipses carry no `sutak` and are not
|
|
792
|
-
religiously observed (drik / pandit consensus).
|
|
793
|
-
|
|
794
|
-
For one-off astronomical detail without building a table, use
|
|
795
|
-
`getUpcomingEclipses` / `computeEclipsesInRange` from the main entry.
|
|
796
|
-
|
|
797
|
-
`npm run eclipses:gen` is a worked example; it writes a rolling 2-past /
|
|
798
|
-
5-future window to `./eclipses.json` (or a path you pass).
|
|
799
|
-
|
|
800
|
-
## Moon Phases
|
|
556
|
+
## Muhurta Engine
|
|
801
557
|
|
|
802
|
-
|
|
803
|
-
**full** (Purnima), **last quarter** — as precise instants. (These are the
|
|
804
|
-
astronomical quarter moments, distinct from the same-named *tithis*, which are
|
|
805
|
-
~24h windows.)
|
|
558
|
+
📖 [Muhurta Engine →](https://dharmagya.app/docs/panchang-ts/muhurta)
|
|
806
559
|
|
|
807
560
|
```typescript
|
|
808
|
-
import {
|
|
809
|
-
const phases = computeMoonPhasesInRange(new Date('2026-01-01'), new Date('2026-12-31'));
|
|
810
|
-
phases.forEach(p => console.log(p.phase, p.time.toISOString())); // ~49 / year
|
|
811
|
-
```
|
|
812
|
-
|
|
813
|
-
### Pre-computed table — build your own and cache it
|
|
814
|
-
|
|
815
|
-
Same pattern again, at `panchang-ts/moon-phases`. Phases are **global instants**,
|
|
816
|
-
so `buildMoonPhasesTable` takes only a `timezoneOffsetMinutes` (no coordinates)
|
|
817
|
-
— the timezone just decides which calendar date each instant lands on (a new
|
|
818
|
-
moon at 19:52 UTC on Jan 18 is listed under Jan 19 in IST).
|
|
561
|
+
import { scoreMuhurta, computeAuspiciousDatesInRange, vivahRule } from 'panchang-ts';
|
|
819
562
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
readMoonPhasesForDate,
|
|
825
|
-
readMoonPhasesYearRange,
|
|
826
|
-
} from 'panchang-ts/moon-phases'; // engine-free
|
|
827
|
-
|
|
828
|
-
const table = buildMoonPhasesTable({
|
|
829
|
-
timezoneOffsetMinutes: 330, // IST; -300 = US Eastern
|
|
830
|
-
startYear: 2024,
|
|
831
|
-
endYear: 2031,
|
|
832
|
-
languages: ['en', 'hi'],
|
|
833
|
-
});
|
|
834
|
-
// …persist `table` as JSON, then:
|
|
563
|
+
const s = scoreMuhurta(new Date('2026-05-12'), DELHI, vivahRule, { timezone: 330 });
|
|
564
|
+
s.score; // 0..100; passes when ≥ 50
|
|
565
|
+
s.factors; // structured, stable codes — localize/filter on these
|
|
566
|
+
s.reasons; // diagnostic English
|
|
835
567
|
|
|
836
|
-
|
|
837
|
-
readMoonPhasesForYear(table, 2026)!.length; // ~49 phase days
|
|
838
|
-
readMoonPhasesForDate(table, '2026-01-03'); // [{ phase: 'full', name: 'Full Moon', … }]
|
|
839
|
-
readMoonPhasesForDate(table, '2026-01-03', 'hi'); // [{ phase: 'full', name: 'पूर्णिमा', … }]
|
|
568
|
+
computeAuspiciousDatesInRange(vivahRule, start, end, DELHI, { timezone: 330 });
|
|
840
569
|
```
|
|
841
570
|
|
|
842
|
-
|
|
571
|
+
13 stock rules (vivah, griha pravesh, namakarana, …) or your own pure-data
|
|
572
|
+
`MuhurtaRule`. Vara × Tithi yogas (Siddha, Amrita, Dagdha, …) are scored
|
|
573
|
+
jointly. Pre-compute a table with `buildMuhurtaTable` and read it back through
|
|
574
|
+
`panchang-ts/muhurta` (~1.7 KB, no astronomy code).
|
|
843
575
|
|
|
844
|
-
|
|
845
|
-
5-future window to `./moonPhases.json` (or a path you pass).
|
|
576
|
+
## Planetary Positions & Birth Charts
|
|
846
577
|
|
|
847
|
-
|
|
578
|
+
📖 [Birth Charts →](https://dharmagya.app/docs/panchang-ts/birth-chart)
|
|
848
579
|
|
|
849
580
|
```typescript
|
|
850
|
-
import {
|
|
581
|
+
import {
|
|
582
|
+
computePlanetaryPositions, computeLagna, computeBhava,
|
|
583
|
+
computeRashiChart, computeNavamsa, computeDivisionalChart, computeDignity,
|
|
584
|
+
} from 'panchang-ts';
|
|
851
585
|
|
|
852
586
|
const g = computePlanetaryPositions(new Date(), 'lahiri');
|
|
853
|
-
g.jupiter.rashi.name;
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
// True node (sharper Rahu/Ketu via Meeus periodic correction)
|
|
861
|
-
const gT = computePlanetaryPositions(new Date(), 'lahiri', undefined, 'true');
|
|
587
|
+
g.jupiter.rashi.name; g.jupiter.nakshatra.pada; g.saturn.isRetrograde;
|
|
588
|
+
|
|
589
|
+
const d1 = computeRashiChart(birth, loc); // houseSystem: whole-sign | equal | placidus-kp
|
|
590
|
+
d1.byPlanet.Mars.house; // keyed lookup, no linear scan
|
|
591
|
+
const d9 = computeNavamsa(birth, loc); // + D2/D3/D7/D10/D12/D30
|
|
592
|
+
computeDignity('Mars', 9); // 'exalted'
|
|
862
593
|
```
|
|
863
594
|
|
|
864
|
-
## Dashas
|
|
595
|
+
## Dashas & Personal Transits
|
|
865
596
|
|
|
866
|
-
|
|
597
|
+
📖 [Dashas & Transits →](https://dharmagya.app/docs/panchang-ts/dashas)
|
|
867
598
|
|
|
868
599
|
```typescript
|
|
869
600
|
import {
|
|
870
601
|
computeVimshottariDashaFromBirth, computeVimshottariPratyantar,
|
|
871
|
-
computeAshtottariDasha, computeYoginiDasha, computeCharaDasha,
|
|
602
|
+
computeAshtottariDasha, computeYoginiDasha, computeCharaDasha,
|
|
603
|
+
computeNarayanDasha, computeSadeSati,
|
|
872
604
|
} from 'panchang-ts';
|
|
873
605
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
// 2. Ashtottari — 108-year, 8-lord cycle (no Ketu).
|
|
879
|
-
const ash = computeAshtottariDasha(birth, moonLon);
|
|
880
|
-
|
|
881
|
-
// 3. Yogini — 36-year, 8 yoginis.
|
|
882
|
-
const yog = computeYoginiDasha(birth, moonLon);
|
|
883
|
-
yog.mahaDashas[0]!.yogini; // 'Dhanya'
|
|
884
|
-
yog.mahaDashas[0]!.lord; // 'Jupiter'
|
|
885
|
-
|
|
886
|
-
// 4. Chara (Jaimini) — sign-based, 9-8-7 years per modality, forward only.
|
|
887
|
-
const cha = computeCharaDasha(birth, loc);
|
|
888
|
-
|
|
889
|
-
// 5. Narayan (Jaimini) — sign-based, parity-based direction.
|
|
890
|
-
// Vishama-pada lagna {Aries, Taurus, Gemini, Libra, Scorpio, Sag} → forward
|
|
891
|
-
// Sama-pada lagna {Cancer, Leo, Virgo, Capricorn, Aquarius, Pisces} → backward
|
|
892
|
-
const nar = computeNarayanDasha(birth, loc);
|
|
893
|
-
nar.direction; // 'forward' | 'backward'
|
|
894
|
-
|
|
895
|
-
// Narayan variable-duration variant (Sanjay Rath):
|
|
896
|
-
const narV = computeNarayanDasha(birth, loc, 'lahiri', { duration: 'variable' });
|
|
897
|
-
narV.mahaDashas[0]!.years; // 0..12 from rashi-to-lord count (+1 exalt, -1 debil)
|
|
898
|
-
```
|
|
899
|
-
|
|
900
|
-
## Personal Transits
|
|
901
|
-
|
|
902
|
-
```typescript
|
|
903
|
-
const r = getDailyPanchang(date, loc, {
|
|
904
|
-
timezone: 330,
|
|
905
|
-
janmaRashi: 3, // 0 = Mesha … 11 = Meena
|
|
906
|
-
janmaNakshatra: 0, // 0 = Ashwini … 26 = Revati
|
|
907
|
-
})!;
|
|
908
|
-
r.chandraBalam; // { house, quality: 'strong'|'weak', name, englishName } — null without janmaRashi
|
|
909
|
-
r.tarabala; // { taraIndex, name, englishName, quality } — null without janmaNakshatra
|
|
910
|
-
|
|
911
|
-
import { computeSadeSati } from 'panchang-ts';
|
|
912
|
-
const ss = computeSadeSati(natalMoonRashiIndex, new Date());
|
|
913
|
-
// → { active, phase: 1|2|3|null, currentArcStart, currentArcEnd, nextArcStart }
|
|
606
|
+
const vim = computeVimshottariDashaFromBirth(birth, 'lahiri'); // 3-level
|
|
607
|
+
computeSadeSati(natalMoonRashiIndex, new Date());
|
|
608
|
+
// Daily transits: pass janmaRashi / janmaNakshatra to getDailyPanchang
|
|
609
|
+
// and read r.chandraBalam / r.tarabala.
|
|
914
610
|
```
|
|
915
611
|
|
|
916
|
-
##
|
|
612
|
+
## Strength, Yogas & Karakas
|
|
917
613
|
|
|
918
|
-
|
|
919
|
-
charts (D2/D3/D7/D9/D10/D12/D30), and Planetary Dignity.
|
|
614
|
+
📖 [Strength, Yogas & Karakas →](https://dharmagya.app/docs/panchang-ts/strength-yogas)
|
|
920
615
|
|
|
921
616
|
```typescript
|
|
922
617
|
import {
|
|
923
|
-
|
|
924
|
-
|
|
618
|
+
computeAspects, computeShadbala, computeBhavaBala,
|
|
619
|
+
computeAshtakavarga, computeYogas, computeJaiminiKarakas,
|
|
925
620
|
} from 'panchang-ts';
|
|
926
621
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
// Bhava — 'whole-sign' (default) | 'equal' | 'placidus-kp'.
|
|
933
|
-
// Placidus-KP throws PanchangError('CIRCUMPOLAR') beyond ±66.5°.
|
|
934
|
-
const houses = computeBhava(birth, loc, { houseSystem: 'whole-sign' });
|
|
935
|
-
|
|
936
|
-
// `chart.planets` is the ordered list; `chart.byPlanet` is the same nine
|
|
937
|
-
// placements keyed by graha, for direct lookup without a linear scan.
|
|
938
|
-
const chart = computeRashiChart(birth, loc);
|
|
939
|
-
chart.byPlanet.Mars.house; // instead of chart.planets.find(...)!
|
|
940
|
-
chart.planets.map(p => p.rashi); // iterate the list as before
|
|
941
|
-
|
|
942
|
-
// D1 — full Rashi chart with 9-graha house placement.
|
|
943
|
-
const d1 = computeRashiChart(birth, loc, { houseSystem: 'whole-sign' });
|
|
944
|
-
d1.planets.find(p => p.planet === 'Jupiter')?.house;
|
|
945
|
-
d1.planets.find(p => p.planet === 'Saturn')?.isRetrograde;
|
|
946
|
-
|
|
947
|
-
// Divisional charts (D2 Hora, D3 Drekkana, D7 Saptamsa, D9 Navamsa,
|
|
948
|
-
// D10 Dasamsa, D12 Dwadasamsa, D30 Trimsamsa).
|
|
949
|
-
const d9 = computeNavamsa(birth, loc);
|
|
950
|
-
const d10 = computeDivisionalChart(birth, loc, 'D10');
|
|
951
|
-
const d30 = computeDivisionalChart(birth, loc, 'D30');
|
|
952
|
-
|
|
953
|
-
// Planetary dignity (BPHS Ch.3-4).
|
|
954
|
-
computeDignity('Mars', 0); // 'moolatrikona' (Aries)
|
|
955
|
-
computeDignity('Mars', 9); // 'exalted' (Capricorn)
|
|
956
|
-
computeDignity('Sun', 6); // 'debilitated' (Libra)
|
|
622
|
+
computeShadbala(birth, loc); // 6-fold, in Virupas
|
|
623
|
+
computeAshtakavarga(d1, { reductions: true }); // Bhinna + Sarva + Sodhana
|
|
624
|
+
computeYogas(d1); // ~25 named, with bhanga
|
|
625
|
+
computeJaiminiKarakas(d1, { variant: '8-jaimini' });
|
|
957
626
|
```
|
|
958
627
|
|
|
959
|
-
Birth-chart helpers accept the full ayanamsa set including `'true-chitra'` and
|
|
960
|
-
`'thirukanitham'`.
|
|
961
|
-
|
|
962
628
|
## Compatibility & Doshas
|
|
963
629
|
|
|
630
|
+
📖 [Matching & Doshas →](https://dharmagya.app/docs/panchang-ts/matching-doshas)
|
|
631
|
+
|
|
964
632
|
```typescript
|
|
965
633
|
import {
|
|
966
634
|
computeAshtakoot, computePathuPorutham,
|
|
967
|
-
computeMangalDosha, computeKaalSarp, computePitruDosha,
|
|
635
|
+
computeMangalDosha, computeMangalCompatibility, computeKaalSarp, computePitruDosha,
|
|
968
636
|
} from 'panchang-ts';
|
|
969
637
|
|
|
970
|
-
|
|
971
|
-
// Graha Maitri, Gana, Bhakoot, Nadi (max 1/2/3/4/5/6/7/8).
|
|
972
|
-
const match = computeAshtakoot(
|
|
973
|
-
{ rashi: 4, nakshatra: 9 },
|
|
974
|
-
{ rashi: 0, nakshatra: 1 },
|
|
975
|
-
);
|
|
638
|
+
computeAshtakoot({ rashi: 4, nakshatra: 9 }, { rashi: 0, nakshatra: 1 });
|
|
976
639
|
// → { totalScore: 0..36, koots: KootScore[8], cancellations: string[] }
|
|
977
640
|
|
|
978
|
-
//
|
|
979
|
-
//
|
|
980
|
-
// `navamsaRashi` enables the same-Navamsa-lord rule.
|
|
981
|
-
const richer = computeAshtakoot(
|
|
982
|
-
{ rashi: 4, nakshatra: 9, lagnaRashi: 7, navamsaRashi: 2 },
|
|
983
|
-
{ rashi: 0, nakshatra: 1, lagnaRashi: 1, navamsaRashi: 5 },
|
|
984
|
-
);
|
|
985
|
-
|
|
986
|
-
// Manglik is a PAIRWISE verdict, not a per-chart one: when both partners are
|
|
987
|
-
// Manglik the two afflictions neutralise each other, so the pair is clean
|
|
988
|
-
// where a Manglik/non-Manglik pair is not.
|
|
989
|
-
const m = computeMangalCompatibility(boyChart, girlChart);
|
|
990
|
-
m.afflicted; // false when neither is Manglik AND when both are
|
|
991
|
-
m.cancellations; // ['both natives Manglik — mutual cancellation']
|
|
992
|
-
m.boy; m.girl; // each native's own MangalDoshaInfo, severity included
|
|
993
|
-
|
|
994
|
-
// Pathu Porutham (Tamil/Kerala, 10-fold) — binary pass/fail per koot.
|
|
995
|
-
// Three vetoes (Yoni, Rajju, Vedha) flip `recommended` regardless of count.
|
|
996
|
-
const tp = computePathuPorutham(
|
|
997
|
-
{ rashi: 4, nakshatra: 9 },
|
|
998
|
-
{ rashi: 0, nakshatra: 1 },
|
|
999
|
-
);
|
|
1000
|
-
tp.totalPasses; // 0..10
|
|
1001
|
-
tp.recommended; // no veto + ≥5 passes
|
|
1002
|
-
|
|
1003
|
-
// Doshas
|
|
1004
|
-
computeMangalDosha(d1);
|
|
1005
|
-
// Mars in 1/2/4/7/8/12 from Lagna, Moon, AND Venus (Drik rule set).
|
|
1006
|
-
// Cancellations: Mars in own sign/exalted, conjunct Jup/Moon/Venus,
|
|
1007
|
-
// or aspected by Jupiter (5/7/9 sign-aspect).
|
|
1008
|
-
// Severity (anshik/purna) is computed pre-cancellation.
|
|
1009
|
-
|
|
1010
|
-
computeKaalSarp(d1);
|
|
1011
|
-
// 12 subtypes by Rahu's house: anant, kulik, vasuki, shankhpal, padma,
|
|
1012
|
-
// mahapadma, takshak, karkotak, shankhachud, ghatak, vishdhar, sheshnag.
|
|
1013
|
-
|
|
1014
|
-
computePitruDosha(d1);
|
|
1015
|
-
// Pandit-consensus 4-trigger set (rules cited by ≥3 of 6 surveyed
|
|
1016
|
-
// pandit sources): Sun+Rahu conjunction (any house), Sun+Saturn
|
|
1017
|
-
// conjunction (any house), Rahu in 9th house, 9th-lord conjunct Rahu.
|
|
1018
|
-
// Drik panchang publishes no Pitru calculator; minority/expansive
|
|
1019
|
-
// rules (Sun in 9th alone, Ketu in 4th, 9th lord in dusthana, etc.)
|
|
1020
|
-
// are intentionally excluded.
|
|
1021
|
-
```
|
|
1022
|
-
|
|
1023
|
-
**Limitations.** Ashtakoot Vashya koot uses single-vashya per rashi.
|
|
1024
|
-
Bhakoot Parivartana (rashi-lord exchange) cancellation needs per-graha
|
|
1025
|
-
position data not carried by the `NatalMoon` shape and is not modelled.
|
|
1026
|
-
|
|
1027
|
-
## Strength & Aspects
|
|
1028
|
-
|
|
1029
|
-
```typescript
|
|
1030
|
-
import {
|
|
1031
|
-
computeAspects, computeShadbala, computeBhavaBala, computeAshtakavarga,
|
|
1032
|
-
} from 'panchang-ts';
|
|
1033
|
-
|
|
1034
|
-
// Drishti — every graha aspects the 7th; malefics gain extras
|
|
1035
|
-
// (Mars 4+8, Jupiter 5+9, Saturn 3+10). Node aspect mode is configurable:
|
|
1036
|
-
const aspects = computeAspects(d1); // BPHS 7th-only on nodes
|
|
1037
|
-
const aspExt = computeAspects(d1, { nodeAspects: '5-and-9' }); // KP/BV Raman extension
|
|
1038
|
-
|
|
1039
|
-
// Shadbala — 7 visible grahas, 6 components, in Virupas (60 V = 1 Rupa).
|
|
1040
|
-
// Sthana = Uchcha + Saptavargaja (D1/D2/D3/D7/D9/D12/D30 dignity sum)
|
|
1041
|
-
// + Ojha-Yugma (rashi+navamsa parity) + Drekkana (gender decanate).
|
|
1042
|
-
// Range [0, 420 V]. Dig is directional cusp; Kala = Nathonatha + Paksha;
|
|
1043
|
-
// Chesta is retrograde-bucket; Naisargika is fixed rank; Drik is weighted aspects.
|
|
1044
|
-
const bala = computeShadbala(birth, loc);
|
|
1045
|
-
|
|
1046
|
-
// Bhava Bala — 12-bhava strength built on top of Shadbala.
|
|
1047
|
-
// Per-bhava: { bhavadhipati, dik, drik, sthana, total }.
|
|
1048
|
-
const bhavaBala = computeBhavaBala(birth, loc);
|
|
1049
|
-
|
|
1050
|
-
// Ashtakavarga — 12-rashi bindu grids (BPHS Ch. 66).
|
|
1051
|
-
const av = computeAshtakavarga(d1);
|
|
1052
|
-
av.sarvashtaka; // 12 cells, each 0..56, total 336
|
|
1053
|
-
av.bhinnashtaka.Jupiter; // 12-cell grid; Jupiter total = 56 (chart-invariant)
|
|
1054
|
-
// Other invariants: Sun=47, Moon=49, Mars=39, Mercury=54, Venus=52, Saturn=39.
|
|
1055
|
-
|
|
1056
|
-
// Trikona + Ekadhipatya Sodhana reductions (BPHS Ch. 67):
|
|
1057
|
-
const avR = computeAshtakavarga(d1, { reductions: true });
|
|
1058
|
-
avR.reduced!.sarvashtaka;
|
|
641
|
+
computeMangalCompatibility(boyChart, girlChart); // Manglik is a PAIRWISE verdict
|
|
642
|
+
computeKaalSarp(d1); // 12 subtypes by Rahu's house
|
|
1059
643
|
```
|
|
1060
644
|
|
|
1061
|
-
|
|
1062
|
-
Parashara scheme).
|
|
645
|
+
## Annual Charts, Sensitive Points, KP & Prashna
|
|
1063
646
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
```typescript
|
|
1067
|
-
import { computeYogas, computeJaiminiKarakas } from 'panchang-ts';
|
|
1068
|
-
|
|
1069
|
-
// ~25 named yogas — Pancha Mahapurusha (Ruchaka/Bhadra/Hamsa/Malavya/Sasha),
|
|
1070
|
-
// lunar (Gajakesari, Sunapha, Anapha, Durudhura, Kemadruma), solar
|
|
1071
|
-
// (Budha-Aditya, Veshi, Vasi, Ubhayachari), Raja (kendra/trikona-lord,
|
|
1072
|
-
// Dharma-Karmadhipati, Vipareeta, Lakshmi), Dhana (2-11, 5-9, Vasumati),
|
|
1073
|
-
// Vargottama, Yogakaraka, Neecha Bhanga, Daridra.
|
|
1074
|
-
const yogas = computeYogas(d1);
|
|
1075
|
-
// → [{ name, type, reasons[], bhanga?: { applies, reasons[] } }, …]
|
|
1076
|
-
|
|
1077
|
-
// Optional cancellation annotations: 5 Pancha Mahapurusha + Gajakesari
|
|
1078
|
-
// surface `bhanga` (Sun/Moon conjunct or Jupiter combust/debilitated).
|
|
1079
|
-
// Neecha Bhanga: dispositor in kendra from Lagna OR Moon; lord-of-
|
|
1080
|
-
// exaltation-rashi in kendra from Lagna or Moon; mutual exchange;
|
|
1081
|
-
// dispositor aspecting the debilitated planet.
|
|
1082
|
-
|
|
1083
|
-
// Filter by type / pass D9 for Vargottama:
|
|
1084
|
-
const d9 = computeNavamsa(birth, loc);
|
|
1085
|
-
const all = computeYogas(d1, { types: ['raja','dhana'], navamsa: d9 });
|
|
1086
|
-
|
|
1087
|
-
// Jaimini Karakas — Atmakaraka (highest degree-in-rashi) … Darakaraka (lowest).
|
|
1088
|
-
const k7 = computeJaiminiKarakas(d1); // 7-graha Parashara default
|
|
1089
|
-
const k8 = computeJaiminiKarakas(d1, { variant: '8-jaimini' }); // adds Rahu (degree reversed),
|
|
1090
|
-
// inserts Pitrukaraka at 5th
|
|
1091
|
-
```
|
|
1092
|
-
|
|
1093
|
-
Yoga and Karaka names are English/transliterated proper nouns and intentionally
|
|
1094
|
-
**not** locale-resolved.
|
|
1095
|
-
|
|
1096
|
-
## Annual & Sensitive Layers
|
|
647
|
+
📖 [Annual Charts →](https://dharmagya.app/docs/panchang-ts/annual-charts) ·
|
|
648
|
+
[KP & Prashna →](https://dharmagya.app/docs/panchang-ts/kp-prashna)
|
|
1097
649
|
|
|
1098
650
|
```typescript
|
|
1099
651
|
import {
|
|
1100
652
|
computeVarshaphala, computeTithiPravesha, computeArudhas,
|
|
1101
653
|
computeHoraLagna, computeGhatiLagna, computeBhavaLagna, computeSripatiLagna,
|
|
1102
654
|
computeUpagrahas, computeArgala,
|
|
1103
|
-
} from 'panchang-ts';
|
|
1104
|
-
|
|
1105
|
-
// Varshaphala — Tajik annual chart for the Nth solar return.
|
|
1106
|
-
const v = computeVarshaphala(birth, 30, loc);
|
|
1107
|
-
v.solarReturnInstant;
|
|
1108
|
-
v.varshaLagna.rashi.name;
|
|
1109
|
-
v.muntha.rashi; v.muntha.house; // muntha = (natalLagnaRashi + 30) mod 12
|
|
1110
|
-
v.yearLord; // strongest of 4 candidates by Shadbala
|
|
1111
|
-
v.sahams.Punya.house;
|
|
1112
|
-
v.sahams.Vivaha.rashi;
|
|
1113
|
-
// 27 Sahams: Punya, Vidya, Yasas, Mitra, Karma, Vivaha, Putra, Roga, Marana,
|
|
1114
|
-
// Rajya, Raja, Bandhu, Dharma, Gnati, Apamrityu, Bhratri, Matri, Pitri, Sama,
|
|
1115
|
-
// Bandhana, Karyasiddhi, Vyapara, Sastra, Asha, Labha, Susha, Tapas.
|
|
1116
|
-
|
|
1117
|
-
// Tithi Pravesha — annual chart cast when Sun is in natal sidereal sign AND
|
|
1118
|
-
// Sun-Moon separation equals natal separation. Preserves natal tithi exactly.
|
|
1119
|
-
const tp = computeTithiPravesha(birth, 30, loc);
|
|
1120
|
-
tp.natalTithi === tp.praveshTithi; // always true
|
|
1121
|
-
|
|
1122
|
-
// Arudha padas — image/reflection of each bhava. Arudha[0] = Arudha Lagna (AL).
|
|
1123
|
-
const a = computeArudhas(d1);
|
|
1124
|
-
a[0]!.bhava; // 1 — AL
|
|
1125
|
-
a[0]!.arudhaRashi; // 0..11
|
|
1126
|
-
a[6]!.bhava; // 7 — Darapada (spouse pada)
|
|
1127
|
-
|
|
1128
|
-
// Special lagnas — time-derived sensitive points from sunrise on/before birth.
|
|
1129
|
-
computeHoraLagna(birth, loc); // 30°/hour (1 rashi/hour)
|
|
1130
|
-
computeGhatiLagna(birth, loc); // 75°/hour (1 rashi/24 min)
|
|
1131
|
-
computeBhavaLagna(birth, loc); // 15°/hour (1 rashi/2 hours)
|
|
1132
|
-
computeSripatiLagna(birth, loc); // = natal lagna (cusp 1)
|
|
1133
|
-
|
|
1134
|
-
// Sripati cusps 2–12 (opt-in) — 4 angular cusps + trisected intermediates.
|
|
1135
|
-
// Defined at every latitude (unlike Placidus).
|
|
1136
|
-
const sripati = computeSripatiLagna(birth, loc, 'lahiri', 'en', { includeCusps: true });
|
|
1137
|
-
sripati.cusps; // number[12] of bhava madhyas; cusps[0/3/6/9] = ASC/IC/DSC/MC
|
|
1138
|
-
|
|
1139
|
-
// Upagrahas — Gulika, Mandi (rising-asc at Saturn segment start/midpoint),
|
|
1140
|
-
// plus Sun-derived Dhuma, Vyatipata, Parivesha, Indrachapa, Upaketu.
|
|
1141
|
-
const u = computeUpagrahas(birth, loc);
|
|
1142
|
-
u.gulika.longitude; u.gulika.rashi; u.gulika.house;
|
|
1143
|
-
|
|
1144
|
-
// Argala (Jaimini) — planets in 2/4/11 from a bhava form Argala (intervention);
|
|
1145
|
-
// 3/10/12 form Virodhargala (counter). Each planet hits exactly 6 of 12 bhavas.
|
|
1146
|
-
const arg = computeArgala(d1);
|
|
1147
|
-
arg[0]!.argala; arg[0]!.virodhargala;
|
|
1148
|
-
|
|
1149
|
-
// Trikonargala (5/9 trine, opt-in) — Ketu reversal: 5th-from → virodhaka,
|
|
1150
|
-
// 9th-from → source.
|
|
1151
|
-
const argT = computeArgala(d1, { includeTrikonargala: true });
|
|
1152
|
-
argT[0]!.trikona!.sources;
|
|
1153
|
-
argT[0]!.trikona!.virodhakas;
|
|
1154
|
-
```
|
|
1155
|
-
|
|
1156
|
-
## KP & Prashna
|
|
1157
|
-
|
|
1158
|
-
```typescript
|
|
1159
|
-
import {
|
|
1160
655
|
computeKpSubLord, computeKpCuspalSubLords, computeKpSignificators,
|
|
1161
656
|
computePrashnaChart,
|
|
1162
657
|
} from 'panchang-ts';
|
|
1163
658
|
|
|
1164
|
-
|
|
1165
|
-
//
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
info.starLord; // 'Moon'
|
|
1169
|
-
info.subLord;
|
|
1170
|
-
|
|
1171
|
-
// Cuspal sub-lords (always Placidus-KP — KP's anchor scheme).
|
|
1172
|
-
const cusps = computeKpCuspalSubLords(birth, loc);
|
|
1173
|
-
cusps.cusps[0]!.subLord; // ascendant
|
|
1174
|
-
cusps.cusps[6]!.subLord; // descendant
|
|
1175
|
-
|
|
1176
|
-
// Significators — for each planet, the houses it signifies via the 4-fold KP rule
|
|
1177
|
-
// (occupant + star-lord-occupant + owner + star-lord-owner).
|
|
1178
|
-
const sig = computeKpSignificators(d1);
|
|
1179
|
-
sig.byPlanet.Sun;
|
|
1180
|
-
sig.byHouse[10];
|
|
1181
|
-
|
|
1182
|
-
// Prashna (horary) chart — cast at question moment from querent's location.
|
|
1183
|
-
const pchart = computePrashnaChart(
|
|
1184
|
-
new Date('2026-05-09T14:30:00Z'),
|
|
1185
|
-
{ latitude: 19.0760, longitude: 72.8777 },
|
|
1186
|
-
);
|
|
1187
|
-
pchart.lagna.rashi.name;
|
|
1188
|
-
pchart.bhava.system; // 'placidus-kp' by default (KP horary anchor)
|
|
1189
|
-
pchart.planets[1]!.house; // Moon — primary mind significator
|
|
1190
|
-
```
|
|
1191
|
-
|
|
1192
|
-
Same return shape as a natal `BirthChart`. Pass `{ houseSystem: 'whole-sign' }`
|
|
1193
|
-
to `computePrashnaChart` for traditional Vedic Prashna.
|
|
1194
|
-
|
|
1195
|
-
## Muhurta Engine
|
|
1196
|
-
|
|
1197
|
-
```typescript
|
|
1198
|
-
import { scoreMuhurta, computeAuspiciousDatesInRange, vivahRule } from 'panchang-ts';
|
|
1199
|
-
|
|
1200
|
-
const r = scoreMuhurta(new Date('2026-05-12'), DELHI, vivahRule, { timezone: 330 });
|
|
1201
|
-
// → { date, score: 0..100, passes: boolean,
|
|
1202
|
-
// reasons: string[], // diagnostic English
|
|
1203
|
-
// factors: MuhurtaFactor[] } // { code, axis, index?, delta } — stable
|
|
1204
|
-
|
|
1205
|
-
r.factors.filter(f => f.delta < 0); // what cost the day points
|
|
1206
|
-
r.factors.some(f => f.axis === 'exclusion'); // hard-excluded?
|
|
1207
|
-
|
|
1208
|
-
const dates = computeAuspiciousDatesInRange(
|
|
1209
|
-
vivahRule,
|
|
1210
|
-
new Date('2026-05-01'),
|
|
1211
|
-
new Date('2026-05-31'),
|
|
1212
|
-
DELHI,
|
|
1213
|
-
{ timezone: 330 },
|
|
1214
|
-
); // MuhurtaDay[] sorted by score desc; full panchang attached
|
|
1215
|
-
|
|
1216
|
-
// Custom rule (pure data, no engine code needed)
|
|
1217
|
-
const myRule: MuhurtaRule = {
|
|
1218
|
-
occasion: 'launch_party',
|
|
1219
|
-
auspiciousVaras: [3, 4, 5],
|
|
1220
|
-
auspiciousNakshatras: [11, 12, 21],
|
|
1221
|
-
bhadra: 'penalize', // 'ignore' | 'penalize' | 'exclude'
|
|
1222
|
-
excludeEkadashi: true,
|
|
1223
|
-
excludeAdhikaMasa: true,
|
|
1224
|
-
};
|
|
659
|
+
const v = computeVarshaphala(birth, 30, loc); // Tajik + Muntha + 27 Sahams
|
|
660
|
+
computeTithiPravesha(birth, 30, loc); // preserves natal tithi exactly
|
|
661
|
+
computeKpSubLord(45.5).subLord; // 243 sub-divisions
|
|
662
|
+
computePrashnaChart(questionTime, querentLoc); // horary, Placidus-KP default
|
|
1225
663
|
```
|
|
1226
664
|
|
|
1227
|
-
**Tithi and vara are scored jointly, not just per-anga.** The classical Vara ×
|
|
1228
|
-
Tithi yogas — Siddha, Amrita, Dagdha, Visha, Hutasana, Krakacha, Samvartaka —
|
|
1229
|
-
are applied to every rule, so a Rikta tithi landing on a Saturday is partly
|
|
1230
|
-
redeemed by Siddha yoga rather than flatly penalised. Set
|
|
1231
|
-
`varaTithiYogas: false` for the older per-anga-only scoring, or call
|
|
1232
|
-
`computeVaraTithiYogas(vara, tithi)` directly. Where an auspicious and an
|
|
1233
|
-
inauspicious yoga both fire — a documented ambiguity in the sources — both are
|
|
1234
|
-
surfaced as separate factors and allowed to net out.
|
|
1235
|
-
|
|
1236
|
-
`bhadra` defaults to `'ignore'`; the stock rules use `'penalize'`. A whole-day
|
|
1237
|
-
`'exclude'` is rarely what you want: Vishti karana sits at fixed positions in
|
|
1238
|
-
the tithi cycle, so vetoing the day removes seven tithis outright — among them
|
|
1239
|
-
Shukla Ekadashi, which the same sources list as *preferred* for vivah. Read
|
|
1240
|
-
`panchang.inauspicious.bhadra` for the window and schedule around it.
|
|
1241
|
-
`excludeBhadra: true` still works as an alias for `bhadra: 'exclude'`.
|
|
1242
|
-
|
|
1243
|
-
13 stock rules: vivah, griha pravesh, namakarana, vidyarambh, vahan kharidi,
|
|
1244
|
-
annaprashan, mundan, upanayanam, karnavedha, aksharabhyasam, seemantham, shop
|
|
1245
|
-
opening, travel start.
|
|
1246
|
-
|
|
1247
|
-
### Pre-computed table — build your own and cache it
|
|
1248
|
-
|
|
1249
|
-
Scoring a year of days runs the engine ~365 times. If your app asks the same
|
|
1250
|
-
question repeatedly, compute the answer once and ship the JSON — the same
|
|
1251
|
-
pattern the festival, eclipse and Moon-phase tables use.
|
|
1252
|
-
|
|
1253
|
-
```typescript
|
|
1254
|
-
import { buildMuhurtaTable, vivahRule } from 'panchang-ts';
|
|
1255
|
-
|
|
1256
|
-
const table = buildMuhurtaTable({
|
|
1257
|
-
rule: vivahRule,
|
|
1258
|
-
location: { latitude: 25.3176, longitude: 82.9739 },
|
|
1259
|
-
timezoneOffsetMinutes: 330,
|
|
1260
|
-
startYear: 2026,
|
|
1261
|
-
endYear: 2031,
|
|
1262
|
-
referenceLocation: 'Varanasi',
|
|
1263
|
-
});
|
|
1264
|
-
// persist JSON.stringify(table) — 6 years of vivah dates is ~74 KB
|
|
1265
|
-
```
|
|
1266
|
-
|
|
1267
|
-
Read it back through the engine-free `panchang-ts/muhurta` entry (~1.7 KB, no
|
|
1268
|
-
astronomy code in your bundle):
|
|
1269
|
-
|
|
1270
|
-
```typescript
|
|
1271
|
-
import {
|
|
1272
|
-
readMuhurtaForYear,
|
|
1273
|
-
readMuhurtaForDate,
|
|
1274
|
-
readMuhurtaYearRange,
|
|
1275
|
-
readMuhurtaOccasion,
|
|
1276
|
-
readBestMuhurtaDays,
|
|
1277
|
-
} from 'panchang-ts/muhurta';
|
|
1278
|
-
|
|
1279
|
-
const table = JSON.parse(await (await fetch('/muhurta-vivah.json')).text());
|
|
1280
|
-
|
|
1281
|
-
readMuhurtaOccasion(table); // 'vivah'
|
|
1282
|
-
readMuhurtaYearRange(table); // { start: 2026, end: 2031 }
|
|
1283
|
-
readMuhurtaForYear(table, 2026); // MuhurtaTableDay[] — passing days, by date
|
|
1284
|
-
readMuhurtaForDate(table, '2026-11-11');
|
|
1285
|
-
readBestMuhurtaDays(table, 5); // top 5 across the table, highest first
|
|
1286
|
-
```
|
|
1287
|
-
|
|
1288
|
-
Only days that **pass** the rule are stored by default; pass
|
|
1289
|
-
`includeFailures: true` to keep every day with its score. Scores are location-
|
|
1290
|
-
*and* rule-dependent, so a table built for Varanasi and `vivah` says nothing
|
|
1291
|
-
about another place or occasion.
|
|
1292
|
-
|
|
1293
|
-
`npm run muhurta:gen` is a worked example script
|
|
1294
|
-
([scripts/generate-muhurta-json.ts](scripts/generate-muhurta-json.ts)):
|
|
1295
|
-
|
|
1296
|
-
```bash
|
|
1297
|
-
npm run muhurta:gen -- muhurta-vivah.json vivah
|
|
1298
|
-
```
|
|
1299
|
-
|
|
1300
|
-
Scoring: starts at 50; +10 per matching auspicious axis (tithi / nakshatra /
|
|
1301
|
-
vara / yoga), -15 per inauspicious axis, hard exclusions zero the score.
|
|
1302
|
-
Special yogas (Amrit Siddhi, Sarvartha Siddhi, Ravi/Guru Pushya) add +5;
|
|
1303
|
-
Jwalamukhi subtracts -10. Clamped 0..100; `passes: true` when score ≥ 50.
|
|
1304
|
-
|
|
1305
|
-
Every scoring input appears in both `reasons` (English prose, diagnostic, not a
|
|
1306
|
-
stable format) and `factors` (structured, with a stable `code`). Localize and
|
|
1307
|
-
filter on `factors`.
|
|
1308
|
-
|
|
1309
|
-
`scoreMuhurta` computes only the sections it actually scores against, so it is
|
|
1310
|
-
cheaper than a full `getDailyPanchang`. `computeAuspiciousDatesInRange` does not narrow —
|
|
1311
|
-
each returned day carries its complete `panchang` for callers to drill into.
|
|
1312
|
-
|
|
1313
665
|
## Calendar Conversion
|
|
1314
666
|
|
|
667
|
+
📖 [Calendar Conversion →](https://dharmagya.app/docs/panchang-ts/calendar-conversion)
|
|
668
|
+
|
|
1315
669
|
```typescript
|
|
1316
670
|
import {
|
|
1317
671
|
convertGregorianToHindu, convertHinduToGregorian,
|
|
1318
672
|
getKaliYugaYear, getHinduNewYear,
|
|
1319
673
|
computeEkadashiDatesForYear, computeSankrantisForYear,
|
|
1320
|
-
computeFestivalsInRange, getUpcomingEclipses, computeEclipsesInRange,
|
|
1321
674
|
} from 'panchang-ts';
|
|
1322
675
|
|
|
1323
|
-
|
|
1324
|
-
const h = convertGregorianToHindu(new Date('2026-04-15'), DELHI, { timezone: 330 });
|
|
1325
|
-
|
|
1326
|
-
// Hindu → Gregorian
|
|
1327
|
-
const dates = convertHinduToGregorian(
|
|
676
|
+
convertHinduToGregorian(
|
|
1328
677
|
{ vikramSamvat: 2083, masaIndex: 0, paksha: 'shukla', pakshaTithi: 9 },
|
|
1329
678
|
DELHI, { timezone: 330 },
|
|
1330
|
-
);
|
|
1331
|
-
|
|
1332
|
-
getKaliYugaYear(new Date('2026-04-01')); // 5127
|
|
1333
|
-
getHinduNewYear(2026, 'tamil-nadu', DELHI, { timezone: 330 }); // Puthandu
|
|
1334
|
-
|
|
1335
|
-
computeEkadashiDatesForYear(2026, DELHI, { timezone: 330 }); // ~24 Date[]
|
|
1336
|
-
computeSankrantisForYear(2026, DELHI, { timezone: 330 }); // 12 SankrantiEvent[]
|
|
1337
|
-
computeFestivalsInRange(start, end, DELHI, { timezone: 330 }); // FestivalDay[]
|
|
1338
|
-
getUpcomingEclipses(new Date(), DELHI, 5);
|
|
679
|
+
); // → Date[] (Rama Navami VS 2083)
|
|
680
|
+
getHinduNewYear(2026, 'tamil-nadu', DELHI, { timezone: 330 }); // region-aware
|
|
1339
681
|
```
|
|
1340
682
|
|
|
1341
|
-
`getHinduNewYear` is region-aware: Tamil Nadu / Kerala / Punjab / Bengal / Assam
|
|
1342
|
-
use the **solar** (Mesha Sankranti) anchor; elsewhere uses **Chaitra Shukla
|
|
1343
|
-
Pratipada** (Ugadi / Gudi Padwa / Cheti Chand). When Pratipada is a kshaya
|
|
1344
|
-
tithi (e.g. Ugadi 2026), falls back to the Amanta-Chaitra-masa boundary.
|
|
1345
|
-
|
|
1346
683
|
## Localization & Configuration
|
|
1347
684
|
|
|
1348
|
-
|
|
1349
|
-
const hi = getDailyPanchang(date, loc, { timezone: 330, language: 'hi' })!;
|
|
1350
|
-
hi.angas.tithis[0].name; // "कृष्ण चतुर्दशी"
|
|
1351
|
-
hi.angas.vara.name; // "मंगलवार"
|
|
1352
|
-
hi.calendar.chandramasa.name; // "माघ"
|
|
1353
|
-
hi.periods.choghadiya.day[0].name; // "अमृत"
|
|
1354
|
-
hi.angas.vara.englishName; // "Tuesday" — englishName always English
|
|
1355
|
-
|
|
1356
|
-
// All options:
|
|
1357
|
-
const r = getDailyPanchang(date, loc, {
|
|
1358
|
-
timezone: 330, // number (UTC offset min) or IANA string
|
|
1359
|
-
ayanamsa: 'lahiri', // lahiri | raman | krishnamurti | true-chitra | thirukanitham
|
|
1360
|
-
language: 'en', // en | hi
|
|
1361
|
-
masaSystem: 'purnimanta', // purnimanta | amanta
|
|
1362
|
-
region: 'all', // 21 state slugs + 'nepal' + 'all'
|
|
1363
|
-
computeEndTimes: true, // false → skip transition searches
|
|
1364
|
-
sections: undefined, // undefined = all; see Performance
|
|
1365
|
-
janmaRashi: undefined, // pass to populate r.chandraBalam (else null)
|
|
1366
|
-
janmaNakshatra: undefined, // pass to populate r.tarabala (else null)
|
|
1367
|
-
});
|
|
1368
|
-
```
|
|
1369
|
-
|
|
1370
|
-
**Timezone.** Number (minutes from UTC, e.g. `330` for IST) or an IANA zone
|
|
1371
|
-
name (e.g. `'America/New_York'`). IANA strings need `Intl`, which older Hermes
|
|
1372
|
-
versions lack — pass a number on those targets. DST resolves automatically for
|
|
1373
|
-
IANA zones.
|
|
1374
|
-
|
|
1375
|
-
---
|
|
1376
|
-
|
|
1377
|
-
### Localized vs machine-readable fields
|
|
1378
|
-
|
|
1379
|
-
Every user-facing string follows `language`. Where a value is also meaningful to
|
|
1380
|
-
code, the two are separate fields — the stable key never changes with language:
|
|
1381
|
-
|
|
1382
|
-
| Machine-readable | Localized display |
|
|
1383
|
-
|---|---|
|
|
1384
|
-
| `festival.key` (`'diwali'`) | `festival.name` (`"दिवाली"`) |
|
|
1385
|
-
| `bhadra.location` (`'paatal'`) | `bhadra.locationName` (`"पाताल"`) |
|
|
1386
|
-
| `eclipse.kind` / `eclipse.subtype` | `eclipse.description` |
|
|
1387
|
-
| `muhurtaScore.factors[].code` | `muhurtaScore.reasons` (English only) |
|
|
1388
|
-
|
|
1389
|
-
`MuhurtaScore.reasons` is diagnostic English and not a stable format; use
|
|
1390
|
-
`factors` for anything shown to a user or branched on in code.
|
|
1391
|
-
|
|
1392
|
-
## Types & Exports
|
|
1393
|
-
|
|
1394
|
-
<details>
|
|
1395
|
-
<summary><strong>Core, Pancha Anga, Festivals</strong></summary>
|
|
1396
|
-
|
|
1397
|
-
```typescript
|
|
1398
|
-
interface GeoLocation { latitude: number; longitude: number; elevation?: number; }
|
|
1399
|
-
interface TimePeriod { start: Date; end: Date; }
|
|
1400
|
-
|
|
1401
|
-
interface TithiInfo {
|
|
1402
|
-
index: number; // 0-29
|
|
1403
|
-
name: string;
|
|
1404
|
-
paksha: string; // "Shukla"/"Krishna" (en), "शुक्ल"/"कृष्ण" (hi)
|
|
1405
|
-
number: number; // 1-15 within the paksha
|
|
1406
|
-
completionPercentage: number;
|
|
1407
|
-
endTime: Date | null;
|
|
1408
|
-
}
|
|
1409
|
-
// NakshatraInfo, YogaInfo, KaranaInfo follow the same pattern.
|
|
1410
|
-
// DailyTithiInfo extends with startTime + isActiveAtSunrise.
|
|
1411
|
-
|
|
1412
|
-
interface VaraInfo {
|
|
1413
|
-
index: number; // 0 = Sunday … 6 = Saturday
|
|
1414
|
-
name: string; // localized (e.g. "Raviwara")
|
|
1415
|
-
shortName: string;
|
|
1416
|
-
englishName: string; // always English
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
interface FestivalInfo {
|
|
1420
|
-
key: string; // stable, language-independent id — match on this
|
|
1421
|
-
name: string; // localized — display only
|
|
1422
|
-
type: 'major' | 'minor' | 'ekadashi' | 'smarta_ekadashi' | 'vaishnava_ekadashi'
|
|
1423
|
-
| 'pradosha' | 'sankranti' | 'eclipse';
|
|
1424
|
-
description?: string;
|
|
1425
|
-
deferralDate?: Date; // Smarta Ekadashi → Dwadashi fast date
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
type FestivalRegion =
|
|
1429
|
-
| 'all'
|
|
1430
|
-
| 'tamil-nadu' | 'kerala' | 'karnataka' | 'andhra-pradesh' | 'telangana'
|
|
1431
|
-
| 'west-bengal' | 'odisha' | 'assam' | 'bihar' | 'jharkhand'
|
|
1432
|
-
| 'gujarat' | 'maharashtra' | 'goa' | 'rajasthan'
|
|
1433
|
-
| 'punjab' | 'haryana' | 'himachal-pradesh' | 'uttarakhand'
|
|
1434
|
-
| 'uttar-pradesh' | 'madhya-pradesh'
|
|
1435
|
-
| 'nepal';
|
|
1436
|
-
|
|
1437
|
-
// Legacy slugs accepted (mapped internally): 'tamil' → 'tamil-nadu',
|
|
1438
|
-
// 'bengal' → 'west-bengal', 'north-india' → 'all'.
|
|
1439
|
-
```
|
|
1440
|
-
|
|
1441
|
-
</details>
|
|
1442
|
-
|
|
1443
|
-
<details>
|
|
1444
|
-
<summary><strong>Eclipses & Bhadra</strong></summary>
|
|
1445
|
-
|
|
1446
|
-
```typescript
|
|
1447
|
-
interface EclipseInfo {
|
|
1448
|
-
kind: 'solar' | 'lunar';
|
|
1449
|
-
subtype: 'partial' | 'total' | 'annular' | 'penumbral';
|
|
1450
|
-
start: Date; peak: Date; end: Date;
|
|
1451
|
-
visibleFromLocation: boolean;
|
|
1452
|
-
obscuration: number; // disc AREA covered at peak, [0, 1]
|
|
1453
|
-
magnitude: number; // catalogue magnitude — disc DIAMETER covered.
|
|
1454
|
-
// Not [0, 1]: >1 for a total eclipse, negative
|
|
1455
|
-
// for a penumbral lunar one (the Moon misses
|
|
1456
|
-
// the umbra), exactly as NASA's canon prints it.
|
|
1457
|
-
sutakStart: Date; // 12 h pre-solar / 9 h pre-lunar
|
|
1458
|
-
sutakEnd: Date;
|
|
1459
|
-
description: string;
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
interface BhadraInfo {
|
|
1463
|
-
start: Date; end: Date;
|
|
1464
|
-
location: 'earth' | 'heaven' | 'paatal'; // 'earth' = malefic for all work
|
|
1465
|
-
locationName: string; // localized display name
|
|
1466
|
-
isActive: boolean;
|
|
1467
|
-
}
|
|
1468
|
-
```
|
|
1469
|
-
|
|
1470
|
-
</details>
|
|
1471
|
-
|
|
1472
|
-
<details>
|
|
1473
|
-
<summary><strong>Jyotish</strong></summary>
|
|
685
|
+
📖 [Options & Localization →](https://dharmagya.app/docs/panchang-ts/localization)
|
|
1474
686
|
|
|
1475
687
|
```typescript
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
interface GrahaPosition {
|
|
1480
|
-
planet: GrahaName;
|
|
1481
|
-
siderealLongitude: number;
|
|
1482
|
-
rashi: RashiInfo;
|
|
1483
|
-
degreeInRashi: number;
|
|
1484
|
-
nakshatra: NakshatraInfo;
|
|
1485
|
-
isRetrograde: boolean; // always false for Sun/Moon; always true for Rahu/Ketu
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
type DashaLord = 'Ketu' | 'Venus' | 'Sun' | 'Moon' | 'Mars'
|
|
1489
|
-
| 'Rahu' | 'Jupiter' | 'Saturn' | 'Mercury';
|
|
1490
|
-
|
|
1491
|
-
interface MahaDasha { lord: DashaLord; startDate: Date; endDate: Date;
|
|
1492
|
-
years: number; antarDashas: AntarDasha[]; }
|
|
1493
|
-
interface VimshottariDashaResult {
|
|
1494
|
-
currentMahaDashaLord: DashaLord;
|
|
1495
|
-
currentIndex: number;
|
|
1496
|
-
mahaDashas: MahaDasha[];
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
interface ChandraBalamInfo {
|
|
1500
|
-
house: number; // 1 = janma rashi; 12 = rashi before janma
|
|
1501
|
-
quality: 'strong' | 'weak'; // Shubha houses = 1,3,6,7,10,11
|
|
1502
|
-
englishName: string; // "Shubha" | "Ashubha"
|
|
1503
|
-
name: string;
|
|
1504
|
-
}
|
|
688
|
+
const hi = getDailyPanchang(date, loc, { timezone: 330, language: 'hi' })!;
|
|
689
|
+
hi.angas.tithis[0].name; // "कृष्ण चतुर्दशी"
|
|
690
|
+
hi.angas.vara.englishName; // "Tuesday" — englishName always English
|
|
1505
691
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
// | Sadhaka | Vadha | Mitra | Ati-Mitra
|
|
1510
|
-
name: string;
|
|
1511
|
-
quality: 'auspicious' | 'inauspicious';
|
|
1512
|
-
}
|
|
692
|
+
// All options: timezone (number | IANA string), ayanamsa (5), language (en|hi),
|
|
693
|
+
// masaSystem (purnimanta|amanta), region, computeEndTimes, sections,
|
|
694
|
+
// janmaRashi, janmaNakshatra.
|
|
1513
695
|
```
|
|
1514
696
|
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
<summary><strong>Full export list</strong></summary>
|
|
697
|
+
Machine-readable keys never change with language: match on `festival.key`,
|
|
698
|
+
`bhadra.location`, `eclipse.kind`, `factors[].code` — render `name` /
|
|
699
|
+
`locationName` / `description` / `reasons`.
|
|
1519
700
|
|
|
1520
|
-
|
|
1521
|
-
// Primary entry points
|
|
1522
|
-
getDailyPanchang, getInstantPanchang
|
|
1523
|
-
|
|
1524
|
-
// Astronomy
|
|
1525
|
-
getSunrise, getSunset, getMoonrise, getMoonset
|
|
1526
|
-
getSiderealSunLongitude, getSiderealMoonLongitude, getAyanamsa
|
|
1527
|
-
|
|
1528
|
-
// Inauspicious / Muhurta
|
|
1529
|
-
computeRahuKalam, computeGulikaKalam, computeYamaganda
|
|
1530
|
-
computeVarjyam, computeGandaMula, computeAnandadiYoga
|
|
1531
|
-
computePanchakaRahita, computeDoGhati, computeGowriPanchangam
|
|
1532
|
-
computePanchaka, classifyPanchaka, isPanchakaDosha, findPanchakaOnset
|
|
1533
|
-
computeAbhijitMuhurta, computeBrahmaMuhurta, computeVijayaMuhurta
|
|
1534
|
-
computeGodhuliMuhurta, computeNishitaMuhurta, computeAmritKala
|
|
1535
|
-
computeMadhyahna, computePratahSandhya, computeSayahnaSandhya
|
|
1536
|
-
|
|
1537
|
-
// Eclipses
|
|
1538
|
-
getUpcomingSolarEclipse, getUpcomingLunarEclipse, getEclipseDuringDay
|
|
1539
|
-
isEclipseVisibleAnyPhase
|
|
1540
|
-
|
|
1541
|
-
// Moon phases (new / quarters / full as precise instants)
|
|
1542
|
-
computeMoonPhasesInRange
|
|
1543
|
-
|
|
1544
|
-
// Jyotish — planets, dashas, transits
|
|
1545
|
-
computePlanetaryPositions, GRAHA_ABBR
|
|
1546
|
-
computeVimshottariDasha, computeVimshottariDashaFromBirth, computeVimshottariPratyantar
|
|
1547
|
-
computeAshtottariDasha, computeYoginiDasha, computeCharaDasha, computeNarayanDasha
|
|
1548
|
-
computeChandraBalam, computeTarabala, computeSadeSati
|
|
1549
|
-
|
|
1550
|
-
// Jyotish — chart
|
|
1551
|
-
computeLagna, computeBhava, computeRashiChart, computeNavamsa, computeDivisionalChart
|
|
1552
|
-
computeHoraLagna, computeGhatiLagna, computeBhavaLagna, computeSripatiLagna
|
|
1553
|
-
computeDignity
|
|
1554
|
-
|
|
1555
|
-
// Jyotish — strength, yogas, sensitive
|
|
1556
|
-
computeAspects, computeShadbala, computeBhavaBala, computeAshtakavarga
|
|
1557
|
-
computeYogas, computeJaiminiKarakas
|
|
1558
|
-
computeVarshaphala, computeTithiPravesha, computeArudhas, computeUpagrahas, computeArgala
|
|
1559
|
-
|
|
1560
|
-
// Jyotish — compatibility, doshas
|
|
1561
|
-
computeAshtakoot, computePathuPorutham
|
|
1562
|
-
computeMangalDosha, computeMangalCompatibility, computeKaalSarp, computePitruDosha
|
|
1563
|
-
|
|
1564
|
-
// KP / Prashna
|
|
1565
|
-
computeKpSubLord, computeKpCuspalSubLords, computeKpSignificators
|
|
1566
|
-
computePrashnaChart
|
|
1567
|
-
|
|
1568
|
-
// Muhurta engine
|
|
1569
|
-
scoreMuhurta, computeAuspiciousDatesInRange, STOCK_MUHURTA_RULES
|
|
1570
|
-
computeVaraTithiYogas
|
|
1571
|
-
vivahRule, grihaPraveshRule, namakaranaRule, vidyarambhRule, vahanKharidiRule
|
|
1572
|
-
annaprashanRule, mundanRule, upanayanamRule, karnavedhaRule
|
|
1573
|
-
aksharabhyasamRule, seemanthamRule, shopOpeningRule, travelStartRule
|
|
1574
|
-
|
|
1575
|
-
// Calendar conversion + yearly listings
|
|
1576
|
-
convertGregorianToHindu, convertHinduToGregorian
|
|
1577
|
-
getKaliYugaYear, getHinduNewYear, computeSamvat
|
|
1578
|
-
computeEkadashiDatesForYear, computeSankrantisForYear, computeFestivalsInRange
|
|
1579
|
-
getUpcomingEclipses, computeEclipsesInRange
|
|
1580
|
-
|
|
1581
|
-
// Static data tables — build one, cache the JSON, then read it back through
|
|
1582
|
-
// the engine-free panchang-ts/festivals · /eclipses · /moon-phases entries.
|
|
1583
|
-
// No table ships with the package.
|
|
1584
|
-
buildFestivalsTable, buildEclipsesTable, buildMoonPhasesTable
|
|
1585
|
-
|
|
1586
|
-
// Errors
|
|
1587
|
-
PanchangError
|
|
1588
|
-
```
|
|
701
|
+
## Types & Exports
|
|
1589
702
|
|
|
1590
|
-
|
|
703
|
+
📖 [Types & Exports →](https://dharmagya.app/docs/panchang-ts/types) — the key
|
|
704
|
+
interfaces (`TithiInfo`, `FestivalInfo`, `EclipseInfo`, `GrahaPosition`, …) and
|
|
705
|
+
the complete export list of the main entry and the four engine-free subpaths
|
|
706
|
+
(`panchang-ts/festivals`, `/eclipses`, `/moon-phases`, `/muhurta`).
|
|
1591
707
|
|
|
1592
708
|
---
|
|
1593
709
|
|
|
@@ -1602,10 +718,7 @@ Two-pass rendering pattern for smooth UI:
|
|
|
1602
718
|
import { getDailyPanchang } from 'panchang-ts';
|
|
1603
719
|
import { InteractionManager } from 'react-native';
|
|
1604
720
|
|
|
1605
|
-
// Pass 1 — cheapest useful result: elements, slots, muhurtas
|
|
1606
|
-
// (~0.25 ms Node on a new date, ~0.14 ms on one already seen).
|
|
1607
|
-
// `sections` is the lever; `computeEndTimes: false` only helps once it is
|
|
1608
|
-
// narrowed, and slightly hurts on a full-section call.
|
|
721
|
+
// Pass 1 — cheapest useful result: elements, slots, muhurtas (~0.25 ms).
|
|
1609
722
|
const fast = getDailyPanchang(date, location, {
|
|
1610
723
|
timezone: 330,
|
|
1611
724
|
sections: [],
|
|
@@ -1613,7 +726,7 @@ const fast = getDailyPanchang(date, location, {
|
|
|
1613
726
|
});
|
|
1614
727
|
setState(fast);
|
|
1615
728
|
|
|
1616
|
-
// Pass 2 — background, everything (~0.41 ms
|
|
729
|
+
// Pass 2 — background, everything (~0.41 ms).
|
|
1617
730
|
InteractionManager.runAfterInteractions(() => {
|
|
1618
731
|
setState(getDailyPanchang(date, location, { timezone: 330 }));
|
|
1619
732
|
});
|
|
@@ -1623,6 +736,8 @@ InteractionManager.runAfterInteractions(() => {
|
|
|
1623
736
|
|
|
1624
737
|
## Accuracy
|
|
1625
738
|
|
|
739
|
+
📖 [Full accuracy notes →](https://dharmagya.app/docs/panchang-ts/accuracy)
|
|
740
|
+
|
|
1626
741
|
8,368 tests across 121 files, including fixtures cross-verified against reference
|
|
1627
742
|
panchang calculations spanning 2025–2026 across 10 Indian cities plus New York,
|
|
1628
743
|
London, Sydney, Dubai, Singapore (diaspora fixtures cover DST on
|
|
@@ -1633,213 +748,68 @@ London, Sydney, Dubai, Singapore (diaspora fixtures cover DST on
|
|
|
1633
748
|
| Sunrise / Sunset | ≤29 s observed vs reference minute-midpoint (±45 s tolerance) |
|
|
1634
749
|
| Moonrise / Moonset | Meeus apparent-upper-limb (refraction + parallax); ~3–5 min vs simpler-horizon authorities is expected |
|
|
1635
750
|
| Tithi / Nakshatra / Yoga / Karana names | Exact match vs reference |
|
|
1636
|
-
| Tithi / Nakshatra / Yoga / Karana end-times | ≤60 s vs Drik across all 20 audited comparisons
|
|
751
|
+
| Tithi / Nakshatra / Yoga / Karana end-times | ≤60 s vs Drik across all 20 audited comparisons |
|
|
1637
752
|
| Ayanamsa (Lahiri) | Reproduces DrikPanchang's published value to ~0.01″ across 1950–2050 |
|
|
1638
753
|
| Planetary positions (Sun–Saturn) | ±0.02° sidereal |
|
|
1639
|
-
| Planetary positions (Rahu/Ketu
|
|
1640
|
-
| Planetary positions (Rahu/Ketu, true node) | ≤0.6° typical (Meeus periodic correction) |
|
|
754
|
+
| Planetary positions (Rahu/Ketu) | ≤0.5° mean node, ≤0.6° true node (typical) |
|
|
1641
755
|
| Lagna sidereal longitude | Cross-checked against Jagannath Hora reference charts |
|
|
1642
756
|
| D1 / D9 house placement | Exact match vs reference for 9-graha placement |
|
|
1643
757
|
| Ashtakoot total | ±1 point per pair across 30+ matched pairs |
|
|
1644
758
|
| Sade Sati arc start/end | ±1–2 days vs authoritative ephemerides |
|
|
1645
759
|
|
|
1646
|
-
**
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
(`tests/validation/element-endtime-audit.test.ts` carries the working).
|
|
1652
|
-
|
|
1653
|
-
**Ayanamsa.** Only Lahiri is verified against an external reference — Drik
|
|
1654
|
-
publishes no value for the other four. Raman, KP, True Chitrapaksha and
|
|
1655
|
-
Thirukanitham are held at their historical offsets from Lahiri, so correcting
|
|
1656
|
-
Lahiri carried them along rather than silently changing how each relates to it.
|
|
760
|
+
**Festival dating** uses tithi-at-sunrise; a few festivals have authorities on
|
|
761
|
+
other rules (tithi-at-midnight for Janmashtami / Shivaratri / Diwali,
|
|
762
|
+
madhyahna-vyapini for Ganesh Chaturthi edge years) where output can drift
|
|
763
|
+
±1 day — the exact list is
|
|
764
|
+
[documented](https://dharmagya.app/docs/panchang-ts/accuracy#festival-tradeoff).
|
|
1657
765
|
|
|
1658
|
-
**Detection
|
|
1659
|
-
nakshatra-distance rule
|
|
1660
|
-
|
|
1661
|
-
sunrise-anchored nakshatra's window only. **Do Ghati Muhurta** does not rotate
|
|
1662
|
-
by weekday — the same 30-name deity-keyed sequence applies every day.
|
|
1663
|
-
|
|
1664
|
-
### Festival Detection — Documented Tradeoff
|
|
1665
|
-
|
|
1666
|
-
The library uses **tithi-at-sunrise** to resolve a festival to a calendar day.
|
|
1667
|
-
Some authorities use other classical rules for certain festivals; where those
|
|
1668
|
-
rules pick a different day, output can drift ±1 day:
|
|
1669
|
-
|
|
1670
|
-
| Alternative rule | Affects |
|
|
1671
|
-
|---|---|
|
|
1672
|
-
| Tithi-at-midnight | Krishna Janmashtami, Maha Shivaratri, Diwali / Lakshmi Puja |
|
|
1673
|
-
| Madhyahna-vyapini | Ganesh Chaturthi (edge years), Akshaya Tritiya 2026 |
|
|
1674
|
-
| Kshaya-tithi handling | Ugadi 2026-03-19 (Pratipada is Kshaya) |
|
|
1675
|
-
|
|
1676
|
-
Everything else — Holi, Ugadi (non-Kshaya years), Rama Navami, Raksha Bandhan,
|
|
1677
|
-
Ganesh Chaturthi (normal years), Navaratri, Dussehra, Karva Chauth, Hanuman
|
|
1678
|
-
Jayanti — matches the canonical date across 2025 and 2026 fixtures.
|
|
766
|
+
**Detection conventions:** Aadal / Vidaal follow the classical Moon-from-Sun
|
|
767
|
+
nakshatra-distance rule, not the Tamil-Vakya weekday rule. Varjyam emits the
|
|
768
|
+
sunrise-anchored nakshatra's window only. Do Ghati does not rotate by weekday.
|
|
1679
769
|
|
|
1680
770
|
---
|
|
1681
771
|
|
|
1682
772
|
## Performance
|
|
1683
773
|
|
|
1684
|
-
|
|
1685
|
-
processes per configuration. Treat them as relative guidance, not a spec — they
|
|
1686
|
-
move with hardware, latitude and date.
|
|
774
|
+
📖 [Full performance notes →](https://dharmagya.app/docs/panchang-ts/performance)
|
|
1687
775
|
|
|
1688
|
-
|
|
1689
|
-
calendar-scan cost
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
and benchmarked beside this one.
|
|
776
|
+
Measured at Pune, Apple M-series, Node — median of 11 processes. **Distinct
|
|
777
|
+
days** is the calendar-scan cost; **same day repeated** is what a UI
|
|
778
|
+
re-rendering one date sees. Last column is published 4.3.1, benchmarked beside
|
|
779
|
+
this release.
|
|
1693
780
|
|
|
1694
781
|
| `getDailyPanchang` call | Distinct days | Same day repeated | 4.3.1 (distinct) |
|
|
1695
782
|
|---|---|---|---|
|
|
1696
783
|
| Default (all sections + end-times) | **~0.41 ms** | **~0.17 ms** | ~6.06 ms |
|
|
1697
|
-
| `computeEndTimes: false` | ~0.39 ms | ~0.15 ms | ~5.63 ms |
|
|
1698
|
-
| Without `'festivals'` | ~0.39 ms | — | n/a |
|
|
1699
|
-
| `sections: ['festivals', 'eclipse']` | ~0.40 ms | — | n/a |
|
|
1700
|
-
| `sections: []` | ~0.27 ms | — | n/a |
|
|
1701
784
|
| `sections: []` + `computeEndTimes: false` | ~0.25 ms | ~0.14 ms | n/a |
|
|
1702
785
|
| `getInstantPanchang` | ~0.21 ms | ~0.10 ms | ~0.43 ms |
|
|
1703
786
|
|
|
1704
|
-
|
|
1705
|
-
counterpart — passing it to 4.3.1 is silently ignored and you get a full run.
|
|
1706
|
-
|
|
1707
|
-
**A default day is ~15× cheaper than in 4.3.1**, and a repeated day ~37×. Most
|
|
1708
|
-
of that is not tuning: 4.3.1 ran `astronomy-engine`'s full lunar theory inside
|
|
1709
|
-
the eclipse search on every day containing a syzygy, and had no cache that
|
|
1710
|
-
survived a call.
|
|
1711
|
-
|
|
1712
|
-
One surface moved the other way, and it is deliberate: the **raw longitude
|
|
1713
|
-
getters** (`getSiderealSunLongitude`, `getSiderealMoonLongitude`) cost about
|
|
1714
|
-
twice what they did in 4.3.1 per call — ~14 µs against ~7 µs for the Moon,
|
|
1715
|
-
~2.8 µs against ~1.4 µs for the Sun — because the own-ephemeris series keep
|
|
1716
|
-
roughly three times `astronomy-engine`'s accuracy against JPL DE441, and the
|
|
1717
|
-
evaluation is sine-bound, so more terms cost proportionally more. Every
|
|
1718
|
-
documented workflow (`getDailyPanchang`, `getInstantPanchang`, the year/range
|
|
1719
|
-
APIs, the static tables) amortizes those reads through caches and is faster
|
|
1720
|
-
than 4.3.1 by the factors above; the per-call price is only visible to code
|
|
1721
|
-
calling the raw getters in a tight loop over distinct instants. For scanning
|
|
1722
|
-
workloads, prefer the range APIs or `getDailyPanchang` — they read through
|
|
1723
|
-
interpolated longitude blocks precisely so that this cost is paid once per day
|
|
1724
|
-
rather than once per read.
|
|
1725
|
-
|
|
1726
|
-
The same trade surfaces once more in the birth-chart *primitives*:
|
|
1727
|
-
`computeRashiChart` and `computeNavamsa` measure ~0.31 ms against ~0.09 ms on
|
|
1728
|
-
published 4.3.1 — a chart is fifteen full-accuracy planet evaluations (three
|
|
1729
|
-
per planet, for the retrograde probes) and nothing amortizes them. The deeper
|
|
1730
|
-
chart stack inverts it again: `computeShadbala` and `computeBhavaBala` come
|
|
1731
|
-
out ~2× *faster* than 4.3.1, because v5 computes the positions once and reuses
|
|
1732
|
-
them. At a third of a millisecond per chart this is irrelevant interactively;
|
|
1733
|
-
it is visible only to code building thousands of charts in a batch.
|
|
1734
|
-
|
|
1735
|
-
Cost is dominated by ephemeris evaluations, so the lever that matters is the one
|
|
1736
|
-
that avoids them:
|
|
1737
|
-
|
|
1738
|
-
- **`sections`** — skip the optional ephemeris-backed blocks you don't need.
|
|
1739
|
-
Dropping `'festivals'` takes a default call from ~0.41 ms to ~0.39 ms cold,
|
|
1740
|
-
and dropping everything takes it to ~0.27 ms. See
|
|
1741
|
-
[Narrowing the work](#narrowing-the-work).
|
|
1742
|
-
- **`computeEndTimes: false`** — a small win, never a large one. It skips the
|
|
1743
|
-
transition searches, but those read through the same interpolated longitude
|
|
1744
|
-
blocks the rest of the call has already built, so what it saves is arithmetic
|
|
1745
|
-
rather than ephemeris: ~5% cold, ~10% warm. Use it to drop `endTime` fields
|
|
1746
|
-
you don't want, not to go faster.
|
|
1747
|
-
|
|
1748
|
-
*Changed in v5.* Both entry points now always interpolate, so output depends
|
|
1749
|
-
on neither `sections` nor `computeEndTimes` — see `INTERPOLATE_ALWAYS` in
|
|
1750
|
-
`src/core/panchang.ts`. Earlier development builds chose the longitude cache's
|
|
1751
|
-
mode from `computeEndTimes`, which made asking for *less* output cost *more*
|
|
1752
|
-
on a full call; that is gone.
|
|
1753
|
-
|
|
1754
|
-
Repeated calls for the same location-day are cheaper because solar rise/set
|
|
1755
|
-
events are cached process-wide, keyed on `(direction, lat, lon, elevation, UTC
|
|
1756
|
-
day)` and bounded at 20,000 entries. The cache makes sunrise single-valued as
|
|
1757
|
-
well as fast — see [Upgrading from 4.x](#sunrise-is-single-valued-per-location-day).
|
|
1758
|
-
It does not make a *single* cold rise/set call cheaper — against 4.3.1
|
|
1759
|
-
`getSunrise` is +1.8%, `getSunset` +8.8%, `getMoonrise` +5.5% and `getMoonset`
|
|
1760
|
-
+6.6%, i.e. unchanged to slightly worse — what it removes is the second and
|
|
1761
|
-
every later call for the same day.
|
|
1762
|
-
|
|
1763
|
-
Range helpers apply the same narrowing internally:
|
|
1764
|
-
`computeEkadashiDatesForYear` reads only the tithi at sunrise and so runs with
|
|
1765
|
-
every optional section off (**~18 ms** for a full year, against ~2,360 ms in
|
|
1766
|
-
4.3.1); `computeFestivalsInRange` keeps only `'festivals'` and `'eclipse'`
|
|
1767
|
-
(**~131 ms/year**, against ~2,180); `computeSankrantisForYear` needs only the
|
|
1768
|
-
Sun, so it scans one solar longitude per day and bisects the 12 transits rather
|
|
1769
|
-
than building a panchang each day (**~3.3 ms/year**, against ~154).
|
|
1770
|
-
|
|
1771
|
-
Birth-chart helpers are independent — calling them does not add work to
|
|
1772
|
-
`getDailyPanchang`. Within them, `computeShadbala` and `computeBhavaBala` build
|
|
1773
|
-
the natal positions once and derive all seven charts from them (~0.33 ms each,
|
|
1774
|
-
against ~0.72 in 4.3.1).
|
|
1775
|
-
|
|
1776
|
-
**Charts are the one place v5 is slower.** `computeRashiChart` and
|
|
1777
|
-
`computeNavamsa` cost **~0.32 ms** against ~0.10 in 4.3.1 — 3.3×, entirely the
|
|
1778
|
-
planetary ephemeris, and the deliberate price of an order-of-magnitude accuracy
|
|
1779
|
-
gain against JPL DE441 (Mercury 6.50″ → 0.30″, Venus 19.59″ → 0.86″). If you
|
|
1780
|
-
build many charts and do not need that precision, 4.x was cheaper; nothing else
|
|
1781
|
-
in the library regressed.
|
|
1782
|
-
|
|
1783
|
-
### Narrowing the work
|
|
1784
|
-
|
|
1785
|
-
`PanchangSection` lists the four optional blocks. Everything else a daily
|
|
1786
|
-
panchang returns — the five elements, slot systems, muhurtas, inauspicious
|
|
1787
|
-
periods, masa / samvat / rashi — is arithmetic over the sunrise / sunset /
|
|
1788
|
-
next-sunrise triplet and is always computed, because skipping it would save
|
|
1789
|
-
nothing.
|
|
1790
|
-
|
|
1791
|
-
| Section | Covers | Fields when omitted |
|
|
1792
|
-
|---|---|---|
|
|
1793
|
-
| `'festivals'` | Festival detection — needs the prior day's sunrise/sunset, the next day's transit, per-kala tithi anchors, and the prior day's Chandra Masa | `festivals: []` — but an eclipse entry is still prepended when `'eclipse'` is on |
|
|
1794
|
-
| `'eclipse'` | Eclipse overlapping the Hindu day | `eclipse: null` |
|
|
1795
|
-
| `'moonTimes'` | `moon.rise` / `moon.set` | `null` |
|
|
1796
|
-
| `'lunarWindows'` | Bhadra, Varjyam, Panchaka-Rahita — each binary-searches lunar longitude across the day | `null` / `[]` |
|
|
1797
|
-
|
|
1798
|
-
```typescript
|
|
1799
|
-
// Everything (default).
|
|
1800
|
-
getDailyPanchang(date, loc, { timezone: 330 });
|
|
1801
|
-
|
|
1802
|
-
// Festivals only — no moon times, no Bhadra/Varjyam windows.
|
|
1803
|
-
getDailyPanchang(date, loc, {
|
|
1804
|
-
timezone: 330,
|
|
1805
|
-
sections: ['festivals', 'eclipse'],
|
|
1806
|
-
});
|
|
1807
|
-
|
|
1808
|
-
// Cheapest useful call: elements, slots, muhurtas and inauspicious periods
|
|
1809
|
-
// only. Those are arithmetic on the sunrise triplet and are always computed.
|
|
1810
|
-
getDailyPanchang(date, loc, {
|
|
1811
|
-
timezone: 330,
|
|
1812
|
-
sections: [],
|
|
1813
|
-
computeEndTimes: false,
|
|
1814
|
-
});
|
|
1815
|
-
```
|
|
1816
|
-
|
|
1817
|
-
Omitting a section leaves its fields at their documented empty value (`null`
|
|
1818
|
-
or `[]`) — never a half-filled one.
|
|
787
|
+
**A default day is ~15× cheaper than 4.3.1**, a repeated day ~37×. The levers:
|
|
1819
788
|
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
789
|
+
- **`sections`** — skip the optional ephemeris-backed blocks (`'festivals'`,
|
|
790
|
+
`'eclipse'`, `'moonTimes'`, `'lunarWindows'`). Narrowing is exactly
|
|
791
|
+
output-neutral: every field a narrowed call computes is identical to the full
|
|
792
|
+
call's; omitted sections sit at their documented `null` / `[]`.
|
|
793
|
+
- **`computeEndTimes: false`** — drops the `endTime` transition searches;
|
|
794
|
+
~5–10% — use it to drop fields you don't want, not to go faster.
|
|
1826
795
|
|
|
1827
|
-
|
|
796
|
+
Range helpers narrow internally: `computeEkadashiDatesForYear` **~18 ms/year**
|
|
797
|
+
(4.3.1: ~2,360), `computeFestivalsInRange` **~131 ms/year** (~2,180),
|
|
798
|
+
`computeSankrantisForYear` **~3.3 ms/year** (~154). Solar rise/set events are
|
|
799
|
+
cached process-wide (bounded, 20k entries), which also makes them
|
|
800
|
+
single-valued.
|
|
1828
801
|
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
published here once they are actually measured on device.
|
|
1834
|
-
|
|
1835
|
-
What does carry over is the shape of the cost: it is dominated by ephemeris
|
|
1836
|
-
math, so the `sections` and `computeEndTimes` levers above have the same
|
|
1837
|
-
proportional effect on any runtime.
|
|
802
|
+
One deliberate regression: raw chart primitives (`computeRashiChart`,
|
|
803
|
+
`computeNavamsa`) cost ~0.32 ms vs ~0.10 in 4.3.1 — the price of an
|
|
804
|
+
order-of-magnitude accuracy gain against JPL DE441. `computeShadbala` /
|
|
805
|
+
`computeBhavaBala` went the other way, ~2× faster.
|
|
1838
806
|
|
|
1839
807
|
---
|
|
1840
808
|
|
|
1841
809
|
## Error Handling
|
|
1842
810
|
|
|
811
|
+
📖 [Errors & Compatibility →](https://dharmagya.app/docs/panchang-ts/errors)
|
|
812
|
+
|
|
1843
813
|
```typescript
|
|
1844
814
|
import { PanchangError } from 'panchang-ts';
|
|
1845
815
|
|
|
@@ -1854,7 +824,7 @@ try {
|
|
|
1854
824
|
```
|
|
1855
825
|
|
|
1856
826
|
Error codes: `INVALID_DATE`, `INVALID_LATITUDE`, `INVALID_LONGITUDE`,
|
|
1857
|
-
`INVALID_ELEVATION`, `INVALID_TIMEZONE`, `INVALID_AYANAMSA`,
|
|
827
|
+
`INVALID_ELEVATION`, `INVALID_TIMEZONE`, `INVALID_AYANAMSA`, `INVALID_INPUT`,
|
|
1858
828
|
`TIMEZONE_RESOLUTION_FAILED`, `NO_SUNRISE`, `NO_SUNSET`, `SEARCH_DIVERGED`,
|
|
1859
829
|
`CIRCUMPOLAR` (Placidus-KP houses above ±66.5°).
|
|
1860
830
|
|
|
@@ -1871,18 +841,25 @@ for the Moon).
|
|
|
1871
841
|
|
|
1872
842
|
| Environment | Support |
|
|
1873
843
|
|---|---|
|
|
1874
|
-
| Node.js
|
|
844
|
+
| Node.js ≥ 22 (per the package `engines` field) | Supported |
|
|
1875
845
|
| React Native (Hermes) | Supported (pass `timezone` as number) |
|
|
1876
846
|
| Expo (managed + bare) | Supported |
|
|
1877
847
|
| Browser (modern, ESM) | Supported |
|
|
1878
848
|
| Browser (legacy / IE) | Not supported |
|
|
1879
849
|
|
|
850
|
+
The build targets ES2020 (ESM + CJS, full `.d.ts`), has **zero runtime
|
|
851
|
+
dependencies**, and is `sideEffects: false`.
|
|
852
|
+
|
|
1880
853
|
---
|
|
1881
854
|
|
|
1882
855
|
## Acknowledgements
|
|
1883
856
|
|
|
1884
|
-
|
|
1885
|
-
|
|
857
|
+
As of v5 the package has **no runtime dependencies** — the ephemeris, ΔT model
|
|
858
|
+
and event searches are the library's own. Two projects still deserve credit:
|
|
859
|
+
[astronomy-engine](https://github.com/cosinekitty/astronomy) by Don Cross (MIT),
|
|
860
|
+
the runtime engine through 4.x and now the dev-time baseline the own ephemeris
|
|
861
|
+
is tested against, and the algorithms of Jean Meeus's *Astronomical Algorithms*,
|
|
862
|
+
which underpin the rise/set and node models.
|
|
1886
863
|
|
|
1887
864
|
## License
|
|
1888
865
|
|