caelus 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/accuracy.json +1 -1
- package/dist/src/ashtottari.d.ts +50 -0
- package/dist/src/ashtottari.js +71 -0
- package/dist/src/directions.d.ts +42 -0
- package/dist/src/directions.js +119 -0
- package/dist/src/firdaria.d.ts +49 -0
- package/dist/src/firdaria.js +62 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +11 -0
- package/dist/src/lots.d.ts +18 -0
- package/dist/src/lots.js +52 -0
- package/dist/src/profections.d.ts +27 -0
- package/dist/src/profections.js +49 -0
- package/dist/src/rajayoga.d.ts +50 -0
- package/dist/src/rajayoga.js +105 -0
- package/dist/src/releasing.d.ts +32 -0
- package/dist/src/releasing.js +109 -0
- package/dist/src/vargas.d.ts +32 -0
- package/dist/src/vargas.js +76 -0
- package/dist/src/vedic.d.ts +66 -0
- package/dist/src/vedic.js +101 -0
- package/dist/src/yogas.d.ts +37 -0
- package/dist/src/yogas.js +68 -0
- package/dist/src/yogini.d.ts +54 -0
- package/dist/src/yogini.js +63 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -100,4 +100,4 @@ test/golden.test.ts conformance suite vs Python fixtures
|
|
|
100
100
|
- caelus — this package
|
|
101
101
|
- [caelus-birth](https://www.npmjs.com/package/caelus-birth) — local birth time + place → UT (charts take UT; use this)
|
|
102
102
|
- [caelus-wheel](https://www.npmjs.com/package/caelus-wheel) — React SVG chart wheel
|
|
103
|
-
- [caelus-mcp](https://www.npmjs.com/package/caelus-mcp) — MCP server,
|
|
103
|
+
- [caelus-mcp](https://www.npmjs.com/package/caelus-mcp) — MCP server, twenty-two chart tools over stdio
|
package/accuracy.json
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine ashtottari -- the Ashtottari dasha, a 108-year conditional dasha.
|
|
3
|
+
*
|
|
4
|
+
* Eight lords rule in order -- Sun 6, Moon 15, Mars 8, Mercury 17, Saturn 10,
|
|
5
|
+
* Jupiter 19, Rahu 12, Venus 21 years (totalling 108). Unlike Vimshottari the
|
|
6
|
+
* nakshatra-to-lord mapping is in irregular groups, and the elapsed portion of
|
|
7
|
+
* the first period is measured across the lord's whole multi-nakshatra span.
|
|
8
|
+
*
|
|
9
|
+
* Convention: the JHora/PVR Narasimha Rao mapping (the PyJHora implementation),
|
|
10
|
+
* which the texts vary around; the lord ranges and across-span balance are
|
|
11
|
+
* reproduced from it, validated against the named source in `validate_jyotish`
|
|
12
|
+
* rather than asserted. Mirrors the Python reference (astroengine/ashtottari.py);
|
|
13
|
+
* the golden fixtures pin the two together.
|
|
14
|
+
*/
|
|
15
|
+
import { Engine, Zodiac } from "./chart.js";
|
|
16
|
+
export declare const ASHTOTTARI_ORDER: readonly ["sun", "moon", "mars", "mercury", "saturn", "jupiter", "rahu", "venus"];
|
|
17
|
+
export declare const ASHTOTTARI_YEARS: Record<(typeof ASHTOTTARI_ORDER)[number], number>;
|
|
18
|
+
/** The Ashtottari dasha lord governing a nakshatra index (0-based). */
|
|
19
|
+
export declare function ashtottariLord(nakIndex: number): string;
|
|
20
|
+
export interface AshtottariSub {
|
|
21
|
+
lord: string;
|
|
22
|
+
start: number;
|
|
23
|
+
end: number;
|
|
24
|
+
}
|
|
25
|
+
export interface AshtottariPeriod {
|
|
26
|
+
level: number;
|
|
27
|
+
lord: string;
|
|
28
|
+
years: number;
|
|
29
|
+
start: number;
|
|
30
|
+
end: number;
|
|
31
|
+
sub: AshtottariSub[];
|
|
32
|
+
}
|
|
33
|
+
export interface AshtottariTimeline {
|
|
34
|
+
start_lord: string;
|
|
35
|
+
balance_years: number;
|
|
36
|
+
dashas: AshtottariPeriod[];
|
|
37
|
+
}
|
|
38
|
+
/** The Ashtottari dasha timeline from the Moon's sidereal longitude. */
|
|
39
|
+
export declare function ashtottariDashas(moonLon: number, natalJd: number, levels?: number, yearLength?: number, count?: number): AshtottariTimeline;
|
|
40
|
+
export interface AshtottariActive {
|
|
41
|
+
maha: string;
|
|
42
|
+
antar: string | null;
|
|
43
|
+
}
|
|
44
|
+
/** The maha and antar lord active at targetJd; null before the first period. */
|
|
45
|
+
export declare function ashtottariActive(moonLon: number, natalJd: number, targetJd: number, yearLength?: number): AshtottariActive | null;
|
|
46
|
+
/** Ashtottari dasha active at targetJd, from the natal Moon's nakshatra. */
|
|
47
|
+
export declare function ashtottariAt(engine: Engine, natalJd: number, targetJd: number, zodiac?: Zodiac, yearLength?: number): {
|
|
48
|
+
moon_nakshatra: string;
|
|
49
|
+
start_lord: string;
|
|
50
|
+
} & Partial<AshtottariActive>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { nakshatra, NAK_SPAN, DASHA_YEAR } from "./vedic.js";
|
|
2
|
+
export const ASHTOTTARI_ORDER = [
|
|
3
|
+
"sun", "moon", "mars", "mercury", "saturn", "jupiter", "rahu", "venus",
|
|
4
|
+
];
|
|
5
|
+
export const ASHTOTTARI_YEARS = {
|
|
6
|
+
sun: 6, moon: 15, mars: 8, mercury: 17, saturn: 10, jupiter: 19, rahu: 12, venus: 21,
|
|
7
|
+
};
|
|
8
|
+
const ASHTOTTARI_TOTAL = 108;
|
|
9
|
+
// Each lord's nakshatra group: [lord, start nakshatra index, span]. Rahu wraps
|
|
10
|
+
// past 27 (nakshatras 26, 0, 1, 2).
|
|
11
|
+
const ASHTOTTARI_RANGES = [
|
|
12
|
+
["sun", 6, 4], ["moon", 10, 3], ["mars", 13, 4], ["mercury", 17, 3],
|
|
13
|
+
["saturn", 20, 3], ["jupiter", 23, 3], ["rahu", 26, 4], ["venus", 3, 3],
|
|
14
|
+
];
|
|
15
|
+
/** The Ashtottari dasha lord governing a nakshatra index (0-based). */
|
|
16
|
+
export function ashtottariLord(nakIndex) {
|
|
17
|
+
for (const [lord, start, span] of ASHTOTTARI_RANGES) {
|
|
18
|
+
if (((nakIndex - start) % 27 + 27) % 27 < span)
|
|
19
|
+
return lord;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`no Ashtottari lord for nakshatra ${nakIndex}`);
|
|
22
|
+
}
|
|
23
|
+
/** The Ashtottari dasha timeline from the Moon's sidereal longitude. */
|
|
24
|
+
export function ashtottariDashas(moonLon, natalJd, levels = 2, yearLength = DASHA_YEAR, count = 8) {
|
|
25
|
+
const lon = ((moonLon % 360) + 360) % 360;
|
|
26
|
+
const nakI = Math.floor(lon / NAK_SPAN) % 27;
|
|
27
|
+
const startLord = ashtottariLord(nakI);
|
|
28
|
+
const [, startNak, spanNak] = ASHTOTTARI_RANGES.find((r) => r[0] === startLord);
|
|
29
|
+
const lordStartDeg = startNak * NAK_SPAN;
|
|
30
|
+
const spanDeg = spanNak * NAK_SPAN;
|
|
31
|
+
const elapsed = (((lon - lordStartDeg) % 360) + 360) % 360 / spanDeg;
|
|
32
|
+
const y0 = ASHTOTTARI_YEARS[startLord];
|
|
33
|
+
const li = ASHTOTTARI_ORDER.indexOf(startLord);
|
|
34
|
+
let t = natalJd - elapsed * y0 * yearLength;
|
|
35
|
+
const dashas = [];
|
|
36
|
+
for (let k = 0; k < count; k++) {
|
|
37
|
+
const lord = ASHTOTTARI_ORDER[(li + k) % 8];
|
|
38
|
+
const years = ASHTOTTARI_YEARS[lord];
|
|
39
|
+
const span = years * yearLength;
|
|
40
|
+
const maha = { level: 1, lord, years, start: t, end: t + span, sub: [] };
|
|
41
|
+
if (levels >= 2) {
|
|
42
|
+
const sli = ASHTOTTARI_ORDER.indexOf(lord);
|
|
43
|
+
let st = t;
|
|
44
|
+
for (let j = 0; j < 8; j++) {
|
|
45
|
+
const sl = ASHTOTTARI_ORDER[(sli + j) % 8];
|
|
46
|
+
const subSpan = (years * ASHTOTTARI_YEARS[sl] / ASHTOTTARI_TOTAL) * yearLength;
|
|
47
|
+
maha.sub.push({ lord: sl, start: st, end: st + subSpan });
|
|
48
|
+
st += subSpan;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
dashas.push(maha);
|
|
52
|
+
t += span;
|
|
53
|
+
}
|
|
54
|
+
return { start_lord: startLord, balance_years: (1 - elapsed) * y0, dashas };
|
|
55
|
+
}
|
|
56
|
+
/** The maha and antar lord active at targetJd; null before the first period. */
|
|
57
|
+
export function ashtottariActive(moonLon, natalJd, targetJd, yearLength = DASHA_YEAR) {
|
|
58
|
+
const timeline = ashtottariDashas(moonLon, natalJd, 2, yearLength, 16).dashas;
|
|
59
|
+
const maha = timeline.find((p) => p.start <= targetJd && targetJd < p.end);
|
|
60
|
+
if (!maha)
|
|
61
|
+
return null;
|
|
62
|
+
const antar = maha.sub.find((s) => s.start <= targetJd && targetJd < s.end);
|
|
63
|
+
return { maha: maha.lord, antar: antar ? antar.lord : null };
|
|
64
|
+
}
|
|
65
|
+
/** Ashtottari dasha active at targetJd, from the natal Moon's nakshatra. */
|
|
66
|
+
export function ashtottariAt(engine, natalJd, targetJd, zodiac = "sidereal:lahiri", yearLength = DASHA_YEAR) {
|
|
67
|
+
const moonLon = engine.longitude("moon", natalJd, { zodiac });
|
|
68
|
+
const nak = nakshatra(moonLon);
|
|
69
|
+
const active = ashtottariActive(moonLon, natalJd, targetJd, yearLength) ?? {};
|
|
70
|
+
return { moon_nakshatra: nak.name, start_lord: ashtottariLord(nak.index), ...active };
|
|
71
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Engine, BodyId } from "./chart.js";
|
|
2
|
+
/** Degrees of arc that equal one year of life, per time key. */
|
|
3
|
+
export declare const KEYS: Record<string, number>;
|
|
4
|
+
export declare const TRADITIONAL: BodyId[];
|
|
5
|
+
export interface DirectionArcs {
|
|
6
|
+
mc: number;
|
|
7
|
+
ic: number;
|
|
8
|
+
asc: number | null;
|
|
9
|
+
dsc: number | null;
|
|
10
|
+
}
|
|
11
|
+
/** Direct primary-direction arcs (degrees, [0, 360)) of a body at right
|
|
12
|
+
* ascension `alpha` and declination `delta` to the four angles, for latitude
|
|
13
|
+
* `phi` and right ascension of the MC `ramc`. `asc`/`dsc` are null when the
|
|
14
|
+
* body is circumpolar. */
|
|
15
|
+
export declare function directionArcs(alpha: number, delta: number, ramc: number, phi: number): DirectionArcs;
|
|
16
|
+
/** Years of life corresponding to an arc of direction under a time key. */
|
|
17
|
+
export declare function directionYears(arc: number, key?: string): number;
|
|
18
|
+
/** Placidus semi-arc mundane directional arc (degrees) for promissor P to
|
|
19
|
+
* significator S: arc = MD_p - (MD_s / SA_s) * SA_p. null if either body is
|
|
20
|
+
* circumpolar. Reduces to the to-MC arc when S is on the meridian, and to 0
|
|
21
|
+
* when P and S coincide. */
|
|
22
|
+
export declare function mundaneDirectionArc(alphaP: number, deltaP: number, alphaS: number, deltaS: number, ramc: number, phi: number): number | null;
|
|
23
|
+
export interface MundaneDirection {
|
|
24
|
+
promissor: string;
|
|
25
|
+
significator: string;
|
|
26
|
+
arc: number;
|
|
27
|
+
years: number;
|
|
28
|
+
jd: number;
|
|
29
|
+
}
|
|
30
|
+
/** Direct mundane (Placidus semi-arc) directions of each promissor to each other
|
|
31
|
+
* significator within `maxYears`, sorted by years. */
|
|
32
|
+
export declare function mundaneDirections(engine: Engine, natalJd: number, lat: number, lonEast: number, bodies?: BodyId[], key?: string, maxYears?: number, yearLength?: number): MundaneDirection[];
|
|
33
|
+
export interface PrimaryDirection {
|
|
34
|
+
body: string;
|
|
35
|
+
angle: "MC" | "IC" | "ASC" | "DSC";
|
|
36
|
+
arc: number;
|
|
37
|
+
years: number;
|
|
38
|
+
jd: number;
|
|
39
|
+
}
|
|
40
|
+
/** Direct primary directions of the bodies to the four angles within
|
|
41
|
+
* `maxYears`, by the given time key, sorted by years. */
|
|
42
|
+
export declare function primaryDirections(engine: Engine, natalJd: number, lat: number, lonEast: number, bodies?: BodyId[], key?: string, maxYears?: number, yearLength?: number): PrimaryDirection[];
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine directions -- primary directions to the angles.
|
|
3
|
+
*
|
|
4
|
+
* Primary (mundane) directions carry a planet, by the diurnal rotation of the
|
|
5
|
+
* sphere, to one of the four angles; the arc of rotation, converted by a time
|
|
6
|
+
* key, gives the age of the direction. This covers the well-defined subset:
|
|
7
|
+
* direct directions of a body to the MC, IC, Ascendant, and Descendant.
|
|
8
|
+
*
|
|
9
|
+
* For a body at right ascension alpha and declination delta, latitude phi, and
|
|
10
|
+
* right ascension of the MC (ramc): arc to MC = alpha - ramc; to IC = that
|
|
11
|
+
* - 180; to the Ascendant = alpha - AD - ramc - 90; to the Descendant =
|
|
12
|
+
* alpha + AD - ramc + 90, where AD = asin(tan phi * tan delta) is the
|
|
13
|
+
* ascensional difference. A circumpolar body (|tan phi * tan delta| > 1) has no
|
|
14
|
+
* oblique ascension, so its Ascendant/Descendant directions are undefined. Time
|
|
15
|
+
* keys: Ptolemy 1 deg = 1 year, Naibod 0.9856473 deg = 1 year. Mirrors the
|
|
16
|
+
* Python reference (astroengine/directions.py); the golden fixtures pin them.
|
|
17
|
+
*/
|
|
18
|
+
import { angles } from "./houses.js";
|
|
19
|
+
const RAD = Math.PI / 180;
|
|
20
|
+
const DEG = 180 / Math.PI;
|
|
21
|
+
/** Degrees of arc that equal one year of life, per time key. */
|
|
22
|
+
export const KEYS = { ptolemy: 1.0, naibod: 0.9856473 };
|
|
23
|
+
export const TRADITIONAL = ["sun", "moon", "mercury", "venus", "mars", "jupiter", "saturn"];
|
|
24
|
+
const YEAR_DAYS = 365.2422;
|
|
25
|
+
const mod360 = (x) => ((x % 360) + 360) % 360;
|
|
26
|
+
/** Direct primary-direction arcs (degrees, [0, 360)) of a body at right
|
|
27
|
+
* ascension `alpha` and declination `delta` to the four angles, for latitude
|
|
28
|
+
* `phi` and right ascension of the MC `ramc`. `asc`/`dsc` are null when the
|
|
29
|
+
* body is circumpolar. */
|
|
30
|
+
export function directionArcs(alpha, delta, ramc, phi) {
|
|
31
|
+
const arcMc = mod360(alpha - ramc);
|
|
32
|
+
const arcIc = mod360(alpha - ramc - 180);
|
|
33
|
+
const t = Math.tan(phi * RAD) * Math.tan(delta * RAD);
|
|
34
|
+
if (Math.abs(t) > 1)
|
|
35
|
+
return { mc: arcMc, ic: arcIc, asc: null, dsc: null };
|
|
36
|
+
const ad = Math.asin(t) * DEG;
|
|
37
|
+
return {
|
|
38
|
+
mc: arcMc, ic: arcIc,
|
|
39
|
+
asc: mod360(alpha - ad - ramc - 90),
|
|
40
|
+
dsc: mod360(alpha + ad - ramc + 90),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Years of life corresponding to an arc of direction under a time key. */
|
|
44
|
+
export function directionYears(arc, key = "naibod") {
|
|
45
|
+
return arc / KEYS[key];
|
|
46
|
+
}
|
|
47
|
+
/** A body's signed meridian distance from its nearest meridian and the matching
|
|
48
|
+
* semi-arc, [MD, SA] in degrees; null when circumpolar. */
|
|
49
|
+
function semiArcPosition(alpha, delta, ramc, phi) {
|
|
50
|
+
const t = Math.tan(phi * RAD) * Math.tan(delta * RAD);
|
|
51
|
+
if (Math.abs(t) > 1)
|
|
52
|
+
return null;
|
|
53
|
+
const ad = Math.asin(t) * DEG;
|
|
54
|
+
const mdu = ((alpha - ramc + 180) % 360 + 360) % 360 - 180; // upper meridian distance
|
|
55
|
+
if (Math.abs(mdu) <= 90 + ad)
|
|
56
|
+
return [mdu, 90 + ad];
|
|
57
|
+
const sign = mdu >= 0 ? 1 : -1;
|
|
58
|
+
return [sign * (180 - Math.abs(mdu)), 90 - ad];
|
|
59
|
+
}
|
|
60
|
+
/** Placidus semi-arc mundane directional arc (degrees) for promissor P to
|
|
61
|
+
* significator S: arc = MD_p - (MD_s / SA_s) * SA_p. null if either body is
|
|
62
|
+
* circumpolar. Reduces to the to-MC arc when S is on the meridian, and to 0
|
|
63
|
+
* when P and S coincide. */
|
|
64
|
+
export function mundaneDirectionArc(alphaP, deltaP, alphaS, deltaS, ramc, phi) {
|
|
65
|
+
const pp = semiArcPosition(alphaP, deltaP, ramc, phi);
|
|
66
|
+
const ps = semiArcPosition(alphaS, deltaS, ramc, phi);
|
|
67
|
+
if (pp === null || ps === null)
|
|
68
|
+
return null;
|
|
69
|
+
const [mdP, saP] = pp;
|
|
70
|
+
const [mdS, saS] = ps;
|
|
71
|
+
return mdP - (mdS / saS) * saP;
|
|
72
|
+
}
|
|
73
|
+
/** Direct mundane (Placidus semi-arc) directions of each promissor to each other
|
|
74
|
+
* significator within `maxYears`, sorted by years. */
|
|
75
|
+
export function mundaneDirections(engine, natalJd, lat, lonEast, bodies = TRADITIONAL, key = "naibod", maxYears = 90, yearLength = YEAR_DAYS) {
|
|
76
|
+
const ramc = angles(engine.data, natalJd, lat, lonEast)[2] * DEG;
|
|
77
|
+
const pos = {};
|
|
78
|
+
for (const b of bodies)
|
|
79
|
+
pos[b] = engine.position(b, natalJd);
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const p of bodies) {
|
|
82
|
+
for (const s of bodies) {
|
|
83
|
+
if (p === s)
|
|
84
|
+
continue;
|
|
85
|
+
const arc = mundaneDirectionArc(pos[p].ra, pos[p].dec, pos[s].ra, pos[s].dec, ramc, lat);
|
|
86
|
+
if (arc === null)
|
|
87
|
+
continue;
|
|
88
|
+
const years = directionYears(arc, key);
|
|
89
|
+
if (years >= 0 && years <= maxYears) {
|
|
90
|
+
out.push({ promissor: p, significator: s, arc, years, jd: natalJd + years * yearLength });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
out.sort((a, b) => a.years - b.years);
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/** Direct primary directions of the bodies to the four angles within
|
|
98
|
+
* `maxYears`, by the given time key, sorted by years. */
|
|
99
|
+
export function primaryDirections(engine, natalJd, lat, lonEast, bodies = TRADITIONAL, key = "naibod", maxYears = 90, yearLength = YEAR_DAYS) {
|
|
100
|
+
const armc = angles(engine.data, natalJd, lat, lonEast)[2];
|
|
101
|
+
const ramc = armc * DEG;
|
|
102
|
+
const out = [];
|
|
103
|
+
const ANGLES = ["mc", "ic", "asc", "dsc"];
|
|
104
|
+
for (const b of bodies) {
|
|
105
|
+
const p = engine.position(b, natalJd);
|
|
106
|
+
const arcs = directionArcs(p.ra, p.dec, ramc, lat);
|
|
107
|
+
for (const angle of ANGLES) {
|
|
108
|
+
const arc = arcs[angle];
|
|
109
|
+
if (arc === null)
|
|
110
|
+
continue;
|
|
111
|
+
const years = directionYears(arc, key);
|
|
112
|
+
if (years <= maxYears) {
|
|
113
|
+
out.push({ body: b, angle: angle.toUpperCase(), arc, years, jd: natalJd + years * yearLength });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
out.sort((a, b) => a.years - b.years);
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine firdaria -- the Persian/medieval system of planetary time-lord
|
|
3
|
+
* periods (firdariyyat).
|
|
4
|
+
*
|
|
5
|
+
* Life divides into nine periods totalling 75 years: the seven planets in the
|
|
6
|
+
* firdaria order, then the two lunar nodes. A day chart begins with the Sun, a
|
|
7
|
+
* night chart with the Moon; both follow the same cycle (Sun, Venus, Mercury,
|
|
8
|
+
* Moon, Saturn, Jupiter, Mars) and close with the North and South Nodes. Each
|
|
9
|
+
* planetary period splits into seven equal sub-periods led by the seven planets
|
|
10
|
+
* from that period's lord; node periods have no sub-divisions. Pure time
|
|
11
|
+
* arithmetic on the natal moment and the chart's sect. Mirrors the Python
|
|
12
|
+
* reference (astroengine/firdaria.py); the golden fixtures pin the two together.
|
|
13
|
+
*/
|
|
14
|
+
import { Engine } from "./chart.js";
|
|
15
|
+
/** The firdaria cycle of the seven planets. */
|
|
16
|
+
export declare const FIRDARIA_ORDER: readonly ["sun", "venus", "mercury", "moon", "saturn", "jupiter", "mars"];
|
|
17
|
+
/** Period length in years for each of the seven planets. */
|
|
18
|
+
export declare const FIRDARIA_YEARS: Record<(typeof FIRDARIA_ORDER)[number], number>;
|
|
19
|
+
/** The two nodes close the sequence with no sub-periods (70 + 5 = 75 years). */
|
|
20
|
+
export declare const NODE_PERIODS: ReadonlyArray<readonly [string, number]>;
|
|
21
|
+
/** The nine major firdaria periods in order, as `[lord, years]` pairs. */
|
|
22
|
+
export declare function firdariaSequence(day: boolean): Array<[string, number]>;
|
|
23
|
+
export interface FirdariaSub {
|
|
24
|
+
lord: string;
|
|
25
|
+
start: number;
|
|
26
|
+
end: number;
|
|
27
|
+
}
|
|
28
|
+
export interface FirdariaPeriod {
|
|
29
|
+
lord: string;
|
|
30
|
+
years: number;
|
|
31
|
+
start: number;
|
|
32
|
+
end: number;
|
|
33
|
+
sub: FirdariaSub[];
|
|
34
|
+
}
|
|
35
|
+
/** The full firdaria timeline from birth. */
|
|
36
|
+
export declare function firdaria(day: boolean, natalJd: number, yearLength?: number): FirdariaPeriod[];
|
|
37
|
+
/** The major and sub firdar lord active at `targetJd`; both null outside the
|
|
38
|
+
* 75-year span. */
|
|
39
|
+
export declare function firdariaActive(day: boolean, natalJd: number, targetJd: number, yearLength?: number): {
|
|
40
|
+
major: string | null;
|
|
41
|
+
sub: string | null;
|
|
42
|
+
};
|
|
43
|
+
/** The active firdar at `targetJd`, taking the chart's sect from the natal
|
|
44
|
+
* moment and place. */
|
|
45
|
+
export declare function firdariaAt(engine: Engine, natalJd: number, targetJd: number, lat: number, lonEast: number, yearLength?: number): {
|
|
46
|
+
day: boolean;
|
|
47
|
+
major: string | null;
|
|
48
|
+
sub: string | null;
|
|
49
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { TROPICAL_YEAR, isDayChart } from "./derived.js";
|
|
2
|
+
/** The firdaria cycle of the seven planets. */
|
|
3
|
+
export const FIRDARIA_ORDER = [
|
|
4
|
+
"sun", "venus", "mercury", "moon", "saturn", "jupiter", "mars",
|
|
5
|
+
];
|
|
6
|
+
/** Period length in years for each of the seven planets. */
|
|
7
|
+
export const FIRDARIA_YEARS = {
|
|
8
|
+
sun: 10, venus: 8, mercury: 13, moon: 9, saturn: 11, jupiter: 12, mars: 7,
|
|
9
|
+
};
|
|
10
|
+
/** The two nodes close the sequence with no sub-periods (70 + 5 = 75 years). */
|
|
11
|
+
export const NODE_PERIODS = [
|
|
12
|
+
["north_node", 3], ["south_node", 2],
|
|
13
|
+
];
|
|
14
|
+
/** The nine major firdaria periods in order, as `[lord, years]` pairs. */
|
|
15
|
+
export function firdariaSequence(day) {
|
|
16
|
+
const start = day ? 0 : FIRDARIA_ORDER.indexOf("moon");
|
|
17
|
+
const planets = [];
|
|
18
|
+
for (let i = 0; i < 7; i++) {
|
|
19
|
+
const lord = FIRDARIA_ORDER[(start + i) % 7];
|
|
20
|
+
planets.push([lord, FIRDARIA_YEARS[lord]]);
|
|
21
|
+
}
|
|
22
|
+
return [...planets, ...NODE_PERIODS.map((p) => [p[0], p[1]])];
|
|
23
|
+
}
|
|
24
|
+
/** The full firdaria timeline from birth. */
|
|
25
|
+
export function firdaria(day, natalJd, yearLength = TROPICAL_YEAR) {
|
|
26
|
+
const out = [];
|
|
27
|
+
let t = natalJd;
|
|
28
|
+
for (const [lord, years] of firdariaSequence(day)) {
|
|
29
|
+
const span = years * yearLength;
|
|
30
|
+
const major = { lord, years, start: t, end: t + span, sub: [] };
|
|
31
|
+
const li = FIRDARIA_ORDER.indexOf(lord);
|
|
32
|
+
if (li >= 0) {
|
|
33
|
+
const subSpan = span / 7;
|
|
34
|
+
let st = t;
|
|
35
|
+
for (let k = 0; k < 7; k++) {
|
|
36
|
+
const sl = FIRDARIA_ORDER[(li + k) % 7];
|
|
37
|
+
major.sub.push({ lord: sl, start: st, end: st + subSpan });
|
|
38
|
+
st += subSpan;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
out.push(major);
|
|
42
|
+
t += span;
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/** The major and sub firdar lord active at `targetJd`; both null outside the
|
|
47
|
+
* 75-year span. */
|
|
48
|
+
export function firdariaActive(day, natalJd, targetJd, yearLength = TROPICAL_YEAR) {
|
|
49
|
+
for (const major of firdaria(day, natalJd, yearLength)) {
|
|
50
|
+
if (major.start <= targetJd && targetJd < major.end) {
|
|
51
|
+
const sub = major.sub.find((s) => s.start <= targetJd && targetJd < s.end);
|
|
52
|
+
return { major: major.lord, sub: sub ? sub.lord : null };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { major: null, sub: null };
|
|
56
|
+
}
|
|
57
|
+
/** The active firdar at `targetJd`, taking the chart's sect from the natal
|
|
58
|
+
* moment and place. */
|
|
59
|
+
export function firdariaAt(engine, natalJd, targetJd, lat, lonEast, yearLength = TROPICAL_YEAR) {
|
|
60
|
+
const day = isDayChart(engine, natalJd, lat, lonEast);
|
|
61
|
+
return { day, ...firdariaActive(day, natalJd, targetJd, yearLength) };
|
|
62
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -15,3 +15,14 @@ export * from "./astrocartography.js";
|
|
|
15
15
|
export * from "./ephemeris.js";
|
|
16
16
|
export * from "./features.js";
|
|
17
17
|
export * from "./compiler.js";
|
|
18
|
+
export * from "./lots.js";
|
|
19
|
+
export * from "./profections.js";
|
|
20
|
+
export * from "./firdaria.js";
|
|
21
|
+
export * from "./releasing.js";
|
|
22
|
+
export * from "./vedic.js";
|
|
23
|
+
export * from "./directions.js";
|
|
24
|
+
export * from "./vargas.js";
|
|
25
|
+
export * from "./yogini.js";
|
|
26
|
+
export * from "./yogas.js";
|
|
27
|
+
export * from "./ashtottari.js";
|
|
28
|
+
export * from "./rajayoga.js";
|
package/dist/src/index.js
CHANGED
|
@@ -15,3 +15,14 @@ export * from "./astrocartography.js";
|
|
|
15
15
|
export * from "./ephemeris.js";
|
|
16
16
|
export * from "./features.js";
|
|
17
17
|
export * from "./compiler.js";
|
|
18
|
+
export * from "./lots.js";
|
|
19
|
+
export * from "./profections.js";
|
|
20
|
+
export * from "./firdaria.js";
|
|
21
|
+
export * from "./releasing.js";
|
|
22
|
+
export * from "./vedic.js";
|
|
23
|
+
export * from "./directions.js";
|
|
24
|
+
export * from "./vargas.js";
|
|
25
|
+
export * from "./yogini.js";
|
|
26
|
+
export * from "./yogas.js";
|
|
27
|
+
export * from "./ashtottari.js";
|
|
28
|
+
export * from "./rajayoga.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Engine, Zodiac } from "./chart.js";
|
|
2
|
+
/** The seven Hermetic lots, in their conventional order. */
|
|
3
|
+
export declare const HERMETIC_LOTS: readonly ["fortune", "spirit", "eros", "necessity", "courage", "victory", "nemesis"];
|
|
4
|
+
export type HermeticLot = (typeof HERMETIC_LOTS)[number];
|
|
5
|
+
/** Lot of Fortune: Asc + Moon - Sun by day, Asc + Sun - Moon by night. */
|
|
6
|
+
export declare function lotFortune(asc: number, sun: number, moon: number, day: boolean): number;
|
|
7
|
+
/** Lot of Spirit (the reverse of Fortune): Asc + Sun - Moon by day. */
|
|
8
|
+
export declare function lotSpirit(asc: number, sun: number, moon: number, day: boolean): number;
|
|
9
|
+
/** The seven Hermetic lots from the Ascendant, sect, and the seven planets'
|
|
10
|
+
* longitudes (degrees). Pure arithmetic. */
|
|
11
|
+
export declare function hermeticLots(asc: number, day: boolean, sun: number, moon: number, mercury: number, venus: number, mars: number, jupiter: number, saturn: number): Record<HermeticLot, number>;
|
|
12
|
+
export interface ChartLots extends Record<HermeticLot, number> {
|
|
13
|
+
/** True when the Sun is above the horizon (a diurnal chart). */
|
|
14
|
+
day: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** The seven Hermetic lots of a chart: compute the Ascendant and sect, then the
|
|
17
|
+
* lots from the seven planets' longitudes. */
|
|
18
|
+
export declare function lots(engine: Engine, jdUt: number, lat: number, lonEast: number, zodiac?: Zodiac): ChartLots;
|
package/dist/src/lots.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine lots -- Hellenistic lots (Arabic parts), sect-aware.
|
|
3
|
+
*
|
|
4
|
+
* A lot is an arc cast from the Ascendant equal to the arc between two chart
|
|
5
|
+
* points, reversing direction between a day and a night chart. Arithmetic on
|
|
6
|
+
* apparent longitudes already checked against Swiss Ephemeris. Mirrors the
|
|
7
|
+
* Python reference (astroengine/lots.py); the golden fixtures pin the two
|
|
8
|
+
* together. Fortune and Spirit are symmetric about the Ascendant, so
|
|
9
|
+
* `(fortune + spirit) === 2 * asc` (mod 360).
|
|
10
|
+
*/
|
|
11
|
+
import { mod } from "./core.js";
|
|
12
|
+
import { isDayChart } from "./derived.js";
|
|
13
|
+
/** The seven Hermetic lots, in their conventional order. */
|
|
14
|
+
export const HERMETIC_LOTS = [
|
|
15
|
+
"fortune", "spirit", "eros", "necessity", "courage", "victory", "nemesis",
|
|
16
|
+
];
|
|
17
|
+
/** Asc + (a - b) by day, Asc + (b - a) by night, wrapped to [0, 360). */
|
|
18
|
+
function lot(asc, a, b, day) {
|
|
19
|
+
return mod(asc + (day ? a - b : b - a), 360);
|
|
20
|
+
}
|
|
21
|
+
/** Lot of Fortune: Asc + Moon - Sun by day, Asc + Sun - Moon by night. */
|
|
22
|
+
export function lotFortune(asc, sun, moon, day) {
|
|
23
|
+
return lot(asc, moon, sun, day);
|
|
24
|
+
}
|
|
25
|
+
/** Lot of Spirit (the reverse of Fortune): Asc + Sun - Moon by day. */
|
|
26
|
+
export function lotSpirit(asc, sun, moon, day) {
|
|
27
|
+
return lot(asc, sun, moon, day);
|
|
28
|
+
}
|
|
29
|
+
/** The seven Hermetic lots from the Ascendant, sect, and the seven planets'
|
|
30
|
+
* longitudes (degrees). Pure arithmetic. */
|
|
31
|
+
export function hermeticLots(asc, day, sun, moon, mercury, venus, mars, jupiter, saturn) {
|
|
32
|
+
const fortune = lotFortune(asc, sun, moon, day);
|
|
33
|
+
const spirit = lotSpirit(asc, sun, moon, day);
|
|
34
|
+
return {
|
|
35
|
+
fortune,
|
|
36
|
+
spirit,
|
|
37
|
+
eros: lot(asc, venus, spirit, day),
|
|
38
|
+
necessity: lot(asc, fortune, mercury, day),
|
|
39
|
+
courage: lot(asc, fortune, mars, day),
|
|
40
|
+
victory: lot(asc, jupiter, spirit, day),
|
|
41
|
+
nemesis: lot(asc, fortune, saturn, day),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** The seven Hermetic lots of a chart: compute the Ascendant and sect, then the
|
|
45
|
+
* lots from the seven planets' longitudes. */
|
|
46
|
+
export function lots(engine, jdUt, lat, lonEast, zodiac = "tropical") {
|
|
47
|
+
const asc = engine.chartAt(jdUt, lat, lonEast, { zodiac }).angles.asc;
|
|
48
|
+
const day = isDayChart(engine, jdUt, lat, lonEast);
|
|
49
|
+
const lon = (b) => engine.longitude(b, jdUt, { zodiac });
|
|
50
|
+
const h = hermeticLots(asc, day, lon("sun"), lon("moon"), lon("mercury"), lon("venus"), lon("mars"), lon("jupiter"), lon("saturn"));
|
|
51
|
+
return { day, ...h };
|
|
52
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Engine, Zodiac } from "./chart.js";
|
|
2
|
+
/** Traditional (domicile) ruler of each sign, Aries..Pisces. */
|
|
3
|
+
export declare const SIGN_RULERS: readonly ["mars", "venus", "mercury", "moon", "sun", "mercury", "venus", "mars", "jupiter", "saturn", "saturn", "jupiter"];
|
|
4
|
+
/** Traditional (domicile) ruler of a sign index (0 = Aries). */
|
|
5
|
+
export declare function signRuler(sign: number): string;
|
|
6
|
+
export interface ProfectedSign {
|
|
7
|
+
sign: string;
|
|
8
|
+
sign_index: number;
|
|
9
|
+
/** 1-based whole-sign house from the natal Ascendant. */
|
|
10
|
+
house: number;
|
|
11
|
+
/** Traditional (domicile) lord of the profected sign. */
|
|
12
|
+
lord: string;
|
|
13
|
+
}
|
|
14
|
+
/** The whole-sign profection `steps` signs after the Ascendant sign. */
|
|
15
|
+
export declare function profectedSign(ascSign: number, steps: number): ProfectedSign;
|
|
16
|
+
export interface Profection {
|
|
17
|
+
age_years: number;
|
|
18
|
+
/** 1-based month within the profection year. */
|
|
19
|
+
month: number;
|
|
20
|
+
annual: ProfectedSign;
|
|
21
|
+
monthly: ProfectedSign;
|
|
22
|
+
}
|
|
23
|
+
/** Annual and monthly profection at `targetJd` for a natal Ascendant sign. */
|
|
24
|
+
export declare function profection(ascSign: number, natalJd: number, targetJd: number, yearLength?: number): Profection;
|
|
25
|
+
/** Profection from a natal chart: take the Ascendant sign from the natal chart,
|
|
26
|
+
* then profect to `targetJd`. */
|
|
27
|
+
export declare function profectionAt(engine: Engine, natalJd: number, targetJd: number, lat: number, lonEast: number, zodiac?: Zodiac, yearLength?: number): Profection;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine profections -- annual and monthly profections, a Hellenistic
|
|
3
|
+
* time-lord technique.
|
|
4
|
+
*
|
|
5
|
+
* The Ascendant advances one whole sign per year of life; the profected sign's
|
|
6
|
+
* traditional (domicile) ruler is the lord of the year. Within the year the
|
|
7
|
+
* monthly profection advances one further sign per 1/12 of the year. Pure
|
|
8
|
+
* arithmetic on a date difference and the natal Ascendant sign. Mirrors the
|
|
9
|
+
* Python reference (astroengine/profections.py); the golden fixtures pin the
|
|
10
|
+
* two together. Whole-sign frame: the sign N signs after the Ascendant is the
|
|
11
|
+
* (N+1)th house. The profection year is a fixed length (the tropical year by
|
|
12
|
+
* default); birthday-exact profections would key off the solar return.
|
|
13
|
+
*/
|
|
14
|
+
import { mod } from "./core.js";
|
|
15
|
+
import { SIGNS } from "./chart.js";
|
|
16
|
+
import { TROPICAL_YEAR } from "./derived.js";
|
|
17
|
+
/** Traditional (domicile) ruler of each sign, Aries..Pisces. */
|
|
18
|
+
export const SIGN_RULERS = [
|
|
19
|
+
"mars", "venus", "mercury", "moon", "sun", "mercury",
|
|
20
|
+
"venus", "mars", "jupiter", "saturn", "saturn", "jupiter",
|
|
21
|
+
];
|
|
22
|
+
/** Traditional (domicile) ruler of a sign index (0 = Aries). */
|
|
23
|
+
export function signRuler(sign) {
|
|
24
|
+
return SIGN_RULERS[mod(sign, 12)];
|
|
25
|
+
}
|
|
26
|
+
/** The whole-sign profection `steps` signs after the Ascendant sign. */
|
|
27
|
+
export function profectedSign(ascSign, steps) {
|
|
28
|
+
const sign = mod(ascSign + steps, 12);
|
|
29
|
+
return { sign: SIGNS[sign], sign_index: sign, house: mod(steps, 12) + 1, lord: signRuler(sign) };
|
|
30
|
+
}
|
|
31
|
+
/** Annual and monthly profection at `targetJd` for a natal Ascendant sign. */
|
|
32
|
+
export function profection(ascSign, natalJd, targetJd, yearLength = TROPICAL_YEAR) {
|
|
33
|
+
const age = (targetJd - natalJd) / yearLength;
|
|
34
|
+
const years = Math.floor(age);
|
|
35
|
+
const month = Math.floor((age - years) * 12); // 0..11
|
|
36
|
+
return {
|
|
37
|
+
age_years: years,
|
|
38
|
+
month: month + 1,
|
|
39
|
+
annual: profectedSign(ascSign, years),
|
|
40
|
+
monthly: profectedSign(ascSign, years + month),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Profection from a natal chart: take the Ascendant sign from the natal chart,
|
|
44
|
+
* then profect to `targetJd`. */
|
|
45
|
+
export function profectionAt(engine, natalJd, targetJd, lat, lonEast, zodiac = "tropical", yearLength = TROPICAL_YEAR) {
|
|
46
|
+
const asc = engine.chartAt(natalJd, lat, lonEast, { zodiac }).angles.asc;
|
|
47
|
+
const ascSign = mod(Math.floor(asc / 30), 12);
|
|
48
|
+
return profection(ascSign, natalJd, targetJd, yearLength);
|
|
49
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine rajayoga -- the lordship-and-aspect layer for Vedic yogas, and the
|
|
3
|
+
* raja/dhana yogas built on it.
|
|
4
|
+
*
|
|
5
|
+
* Layers: house lordship (traditional ruler of each whole-sign house from the
|
|
6
|
+
* Ascendant); graha drishti (every planet aspects the 7th sign; Mars also 4/8,
|
|
7
|
+
* Jupiter 5/9, Saturn 3/10); association (conjunction, mutual aspect, or
|
|
8
|
+
* parivartana exchange); then raja yoga (a kendra lord 1/4/7/10 associated with
|
|
9
|
+
* a trikona lord 1/5/9), dhana yoga (two wealth-house 2/5/9/11 lords), and the
|
|
10
|
+
* yogakaraka (a planet ruling both a pure kendra 4/7/10 and a pure trikona 5/9).
|
|
11
|
+
* Definitions follow BPHS, validated against the named source in
|
|
12
|
+
* `validate_jyotish`. Mirrors the Python reference (astroengine/rajayoga.py).
|
|
13
|
+
*/
|
|
14
|
+
import { Engine, Zodiac } from "./chart.js";
|
|
15
|
+
/** Graha drishti: the house-distances (1-based) each planet aspects. */
|
|
16
|
+
export declare const DRISHTI: Record<string, number[]>;
|
|
17
|
+
export declare const KENDRAS: number[];
|
|
18
|
+
export declare const TRIKONAS: number[];
|
|
19
|
+
export declare const DHANA_HOUSES: number[];
|
|
20
|
+
/** The traditional ruler of a sign index (0 = Aries). */
|
|
21
|
+
export declare function signLord(sign: number): string;
|
|
22
|
+
/** The sign on the given whole-sign house (1-12) from the Ascendant. */
|
|
23
|
+
export declare function houseSign(ascSign: number, house: number): number;
|
|
24
|
+
/** The lord of the given whole-sign house from the Ascendant. */
|
|
25
|
+
export declare function houseLord(ascSign: number, house: number): string;
|
|
26
|
+
/** The whole-sign house (1-12) a sign falls in from the Ascendant. */
|
|
27
|
+
export declare function houseFromAsc(ascSign: number, sign: number): number;
|
|
28
|
+
/** Whether `planet` at `planetSign` casts a graha drishti onto `targetSign`. */
|
|
29
|
+
export declare function aspectsSign(planet: string, planetSign: number, targetSign: number): boolean;
|
|
30
|
+
/** Sign exchange: a sits in b's sign and b sits in a's sign. */
|
|
31
|
+
export declare function parivartana(planetA: string, signA: number, planetB: string, signB: number): boolean;
|
|
32
|
+
/** How two planets associate: "conjunction" | "exchange" | "aspect" | null. */
|
|
33
|
+
export declare function associationType(planetA: string, signA: number, planetB: string, signB: number): string | null;
|
|
34
|
+
/** Planets ruling both a pure kendra (4/7/10) and a pure trikona (5/9), sorted. */
|
|
35
|
+
export declare function yogakarakas(ascSign: number): string[];
|
|
36
|
+
export interface LordPairYoga {
|
|
37
|
+
lords: string[];
|
|
38
|
+
via: string;
|
|
39
|
+
}
|
|
40
|
+
/** Raja yogas: associations between a kendra lord and a trikona lord. */
|
|
41
|
+
export declare function rajaYogas(signs: Record<string, number>, ascSign: number): LordPairYoga[];
|
|
42
|
+
/** Dhana yogas: associations between two wealth-house (2/5/9/11) lords. */
|
|
43
|
+
export declare function dhanaYogas(signs: Record<string, number>, ascSign: number): LordPairYoga[];
|
|
44
|
+
/** Raja yogas of a natal chart, with the chart's yogakarakas. */
|
|
45
|
+
export declare function rajaYogasAt(engine: Engine, natalJd: number, lat: number, lonEast: number, zodiac?: Zodiac): {
|
|
46
|
+
raja: LordPairYoga[];
|
|
47
|
+
yogakarakas: string[];
|
|
48
|
+
};
|
|
49
|
+
/** Dhana yogas of a natal chart. */
|
|
50
|
+
export declare function dhanaYogasAt(engine: Engine, natalJd: number, lat: number, lonEast: number, zodiac?: Zodiac): LordPairYoga[];
|