- Dharmagya
- panchang-ts docs
- Muhurta Engine
Muhurta Engine
panchang-ts · v5.0.0 · MIT
Score any date against 13 stock occasions or your own rule, understand the scoring model and Vara × Tithi yogas, and ship pre-computed muhurta tables.
Scoring a date
import { scoreMuhurta, computeAuspiciousDatesInRange, vivahRule } from 'panchang-ts';
const r = scoreMuhurta(new Date('2026-05-12'), DELHI, vivahRule, { timezone: 330 });
// → { date, score: 0..100, passes: boolean,
// reasons: string[], // diagnostic English
// factors: MuhurtaFactor[] } // { code, axis, index?, delta } — stable
r.factors.filter(f => f.delta < 0); // what cost the day points
r.factors.some(f => f.axis === 'exclusion'); // hard-excluded?
const dates = computeAuspiciousDatesInRange(
vivahRule,
new Date('2026-05-01'),
new Date('2026-05-31'),
DELHI,
{ timezone: 330 },
); // MuhurtaDay[] sorted by score desc; full panchang attached
// Single year, the shape most callers reach for first:
computeAuspiciousDatesForYear(2027, vivahRule, DELHI, { timezone: 330 });Scoring model: starts at 50; +10 per matching auspicious axis (tithi / nakshatra / vara / yoga), −15 per inauspicious axis, hard exclusions zero the score. Special yogas (Amrit Siddhi, Sarvartha Siddhi, Ravi/Guru Pushya) add +5; Jwalamukhi subtracts 10. Clamped 0..100; passes: true when score ≥ 50.
scoreMuhurta computes only the sections it actually scores against, so it is cheaper than a full getDailyPanchang. computeAuspiciousDatesInRange does not narrow — each returned day carries its complete panchang for callers to drill into.
Rules — 13 stock occasions, or your own
Stock rules: vivahRule, grihaPraveshRule, namakaranaRule, vidyarambhRule, vahanKharidiRule, annaprashanRule, mundanRule, upanayanamRule, karnavedhaRule, aksharabhyasamRule, seemanthamRule, shopOpeningRule, travelStartRule — or all of them as STOCK_MUHURTA_RULES. A rule is pure data:
const myRule: MuhurtaRule = {
occasion: 'launch_party',
auspiciousVaras: [3, 4, 5],
auspiciousNakshatras: [11, 12, 21],
bhadra: 'penalize', // 'ignore' | 'penalize' | 'exclude'
excludeEkadashi: true,
excludeAdhikaMasa: true,
};Tithi and vara are scored jointly
The classical Vara × Tithi yogas — Siddha, Amrita, Dagdha, Visha, Hutasana, Krakacha, Samvartaka — are applied to every rule, so a Rikta tithi landing on a Saturday is partly redeemed by Siddha yoga rather than flatly penalised. Set varaTithiYogas: false for the older per-anga-only scoring, or call computeVaraTithiYogas(vara, tithi) directly. Where an auspicious and an inauspicious yoga both fire — a documented ambiguity in the sources — both are surfaced as separate factors and allowed to net out.
Handling Bhadra
bhadra defaults to 'ignore'; the stock rules use 'penalize'. A whole-day 'exclude' is rarely what you want: Vishti karana sits at fixed positions in the tithi cycle, so vetoing the day removes seven tithis outright — among them Shukla Ekadashi, which the same sources list as preferred for vivah. Read panchang.inauspicious.bhadra for the window and schedule around it. excludeBhadra: true still works as an alias for bhadra: 'exclude'.
Pre-computed table — build your own and cache it
Scoring a year of days runs the engine ~365 times. If your app asks the same question repeatedly, compute the answer once and ship the JSON — the same pattern the festival, eclipse and moon-phase tables use.
import { buildMuhurtaTable, vivahRule } from 'panchang-ts';
const table = buildMuhurtaTable({
rule: vivahRule,
location: { latitude: 25.3176, longitude: 82.9739 },
timezoneOffsetMinutes: 330,
startYear: 2026,
endYear: 2031,
referenceLocation: 'Varanasi',
});
// persist JSON.stringify(table) — 6 years of vivah dates is ~74 KBRead it back through the engine-free panchang-ts/muhurta entry (~1.7 KB, no astronomy code in your bundle):
import {
readMuhurtaForYear,
readMuhurtaForDate,
readMuhurtaYearRange,
readMuhurtaOccasion,
readBestMuhurtaDays,
} from 'panchang-ts/muhurta';
const table = JSON.parse(await (await fetch('/muhurta-vivah.json')).text());
readMuhurtaOccasion(table); // 'vivah'
readMuhurtaYearRange(table); // { start: 2026, end: 2031 }
readMuhurtaForYear(table, 2026); // MuhurtaTableDay[] — passing days, by date
readMuhurtaForDate(table, '2026-11-11');
readBestMuhurtaDays(table, 5); // top 5 across the table, highest firstOnly days that pass the rule are stored by default; pass includeFailures: true to keep every day with its score. Scores are location- and rule-dependent, so a table built for Varanasi and vivah says nothing about another place or occasion. The repo's npm run muhurta:gen script is a worked example:
npm run muhurta:gen -- muhurta-vivah.json vivahRelated helpers
| Function | Returns |
|---|---|
computePanchaka(instant, loc) | whether the Moon sits in the last five nakshatras at an instant |
classifyPanchaka / isPanchakaDosha / findPanchakaOnset | the named Panchaka type from its onset vara — see the daily-result note |
computeVaraTithiYogas(vara, tithi) | the Vara × Tithi yogas firing for that pair |
