caelus 0.2.1 → 0.4.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 +14 -6
- package/accuracy.json +234 -25
- package/dist/src/chart.d.ts +59 -11
- package/dist/src/chart.js +238 -46
- package/dist/src/core.d.ts +57 -1
- package/dist/src/core.js +168 -21
- package/dist/src/events.d.ts +22 -0
- package/dist/src/events.js +156 -0
- package/dist/src/houses.d.ts +31 -0
- package/dist/src/houses.js +205 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/node-loader.js +21 -2
- package/dist/src/pheno.d.ts +35 -0
- package/dist/src/pheno.js +152 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,11 +6,12 @@ ephemeris files. 1:1 port of the Python reference, checked by golden fixtures.
|
|
|
6
6
|
## Verification chain
|
|
7
7
|
|
|
8
8
|
1. Python engine checked against Swiss Ephemeris 2.10 across 1900–2099:
|
|
9
|
-
every planet ≤ 1″ (Sun–Saturn), Moon ≤ 2.5″, Chiron ≤ 1″,
|
|
9
|
+
every planet ≤ 1″ (Sun–Saturn), Moon ≤ 2.5″, Chiron ≤ 1″, mean node ≤ 1″,
|
|
10
|
+
true node ≤ 1′ vs SE's built-in ephemeris (≤ 1″ vs JPL DE431)
|
|
10
11
|
(vs full DE431 files, 1850–2149), angles and Placidus cusps ≤ 3.2″ — all
|
|
11
12
|
invisible at the arcminute display precision chart software uses.
|
|
12
|
-
2. TypeScript port verified against Python golden fixtures: **
|
|
13
|
-
0 failures, worst deviation
|
|
13
|
+
2. TypeScript port verified against Python golden fixtures: **3,177 checks,
|
|
14
|
+
0 failures, worst deviation 1.64 nano-arcseconds.** The two implementations
|
|
14
15
|
are numerically identical.
|
|
15
16
|
|
|
16
17
|
Regenerate fixtures any time from the Python side; any future TS change must
|
|
@@ -62,8 +63,15 @@ engine.longitude("chiron", 2451545.0);
|
|
|
62
63
|
engine.position("mars", 2451545.0); // { lon, speed, retrograde, sign, signDeg }
|
|
63
64
|
```
|
|
64
65
|
|
|
65
|
-
Bodies: sun, moon, mercury…pluto, chiron, mean_node, true_node
|
|
66
|
-
|
|
66
|
+
Bodies: sun, moon, mercury…pluto, chiron, mean_node, true_node; on request:
|
|
67
|
+
mean_lilith, true_lilith, ceres, pallas, juno, vesta, pholus, and the eight
|
|
68
|
+
Hamburg-school Uranian bodies (cupido…poseidon) when their data packs are
|
|
69
|
+
loaded.
|
|
70
|
+
House systems: placidus, porphyry, equal, whole_sign, koch, regiomontanus,
|
|
71
|
+
campanus, alcabitius, morinus, meridian, polich_page, vehlow (Placidus and
|
|
72
|
+
Koch fall back to whole_sign above the polar circles).
|
|
73
|
+
Event search: rise/set/meridian transits, zodiac crossings, lunar phases,
|
|
74
|
+
stations (`events.ts`).
|
|
67
75
|
Performance: ~2.4 ms per full chart (13 bodies × 3 evaluations + houses +
|
|
68
76
|
aspects) single-threaded in Node 22 — ~420 charts/sec, faster in hot loops.
|
|
69
77
|
|
|
@@ -92,4 +100,4 @@ test/golden.test.ts conformance suite vs Python fixtures
|
|
|
92
100
|
- caelus — this package
|
|
93
101
|
- [caelus-birth](https://www.npmjs.com/package/caelus-birth) — local birth time + place → UT (charts take UT; use this)
|
|
94
102
|
- [caelus-wheel](https://www.npmjs.com/package/caelus-wheel) — React SVG chart wheel
|
|
95
|
-
- [caelus-mcp](https://www.npmjs.com/package/caelus-mcp) — MCP server,
|
|
103
|
+
- [caelus-mcp](https://www.npmjs.com/package/caelus-mcp) — MCP server, seven chart tools over stdio
|
package/accuracy.json
CHANGED
|
@@ -3,30 +3,239 @@
|
|
|
3
3
|
"range": "1900-2099",
|
|
4
4
|
"unit": "arcsec",
|
|
5
5
|
"bodies": [
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
{
|
|
7
|
+
"name": "Sun",
|
|
8
|
+
"max": "0.4",
|
|
9
|
+
"rms": "0.2",
|
|
10
|
+
"note": ""
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "Moon (precise tier)",
|
|
14
|
+
"max": "2.5",
|
|
15
|
+
"rms": "0.9",
|
|
16
|
+
"note": "JPL DE423 fit (2010); DE423 vs DE440 is <0.1″ over this span"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "Moon (embedded series)",
|
|
20
|
+
"max": "9.6",
|
|
21
|
+
"rms": "2.8",
|
|
22
|
+
"note": "60-term ELP abridged"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "Mercury",
|
|
26
|
+
"max": "0.5",
|
|
27
|
+
"rms": "0.2",
|
|
28
|
+
"note": ""
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "Venus",
|
|
32
|
+
"max": "0.8",
|
|
33
|
+
"rms": "0.2",
|
|
34
|
+
"note": ""
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "Mars",
|
|
38
|
+
"max": "0.7",
|
|
39
|
+
"rms": "0.2",
|
|
40
|
+
"note": ""
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "Jupiter",
|
|
44
|
+
"max": "0.9",
|
|
45
|
+
"rms": "0.3",
|
|
46
|
+
"note": ""
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "Saturn",
|
|
50
|
+
"max": "0.8",
|
|
51
|
+
"rms": "0.4",
|
|
52
|
+
"note": ""
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "Uranus",
|
|
56
|
+
"max": "1.9",
|
|
57
|
+
"rms": "0.7",
|
|
58
|
+
"note": "series truncation; complete VSOP87 holds ≤1″"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "Neptune",
|
|
62
|
+
"max": "4.6",
|
|
63
|
+
"rms": "2.2",
|
|
64
|
+
"note": "series truncation; complete VSOP87 holds ≤1″"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "Pluto",
|
|
68
|
+
"max": "2.5",
|
|
69
|
+
"rms": "1.0",
|
|
70
|
+
"note": "series valid 1885-2099"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "Chiron",
|
|
74
|
+
"max": "1.0",
|
|
75
|
+
"rms": "0.3",
|
|
76
|
+
"note": "JPL Horizons fit, 1850-2150"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "Mean node",
|
|
80
|
+
"max": "0.1",
|
|
81
|
+
"rms": "0.1",
|
|
82
|
+
"note": ""
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "True node",
|
|
86
|
+
"max": "0.8",
|
|
87
|
+
"rms": "0.4",
|
|
88
|
+
"note": "vs full JPL DE431 files; vs Swiss Ephemeris's BUILT-IN (Moshier) ephemeris expect up to ~1′ (measured: 50″ max, 8″ median, 300 epochs) — that is the built-in lunar theory's own node error, not ours"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "Ascendant / MC",
|
|
92
|
+
"max": "3.2",
|
|
93
|
+
"rms": "—",
|
|
94
|
+
"note": ""
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"name": "Placidus cusps (all 12)",
|
|
98
|
+
"max": "3.2",
|
|
99
|
+
"rms": "—",
|
|
100
|
+
"note": ""
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "Mean Lilith",
|
|
104
|
+
"max": "1.3",
|
|
105
|
+
"rms": "0.5",
|
|
106
|
+
"note": "mean lunar apogee on the inclined orbit; latitude ≤0.1″"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "Sidereal longitudes",
|
|
110
|
+
"max": "0.1",
|
|
111
|
+
"rms": "—",
|
|
112
|
+
"note": "ayanamsa model vs SE ≤0.30″ at the 1900/2099 edges (IAU 1976 vs Vondrák precession); Sun worst-case 0.08″ at 120 sampled epochs"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "RA / Dec",
|
|
116
|
+
"max": "2.1",
|
|
117
|
+
"rms": "—",
|
|
118
|
+
"note": "rotation is exact; bound tracks each body's ecliptic accuracy (Moon worst)"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "Topocentric Moon",
|
|
122
|
+
"max": "2.7",
|
|
123
|
+
"rms": "—",
|
|
124
|
+
"note": "parallax model adds ≤0.1″ over the geocentric bound"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "House cusps, 8 new systems",
|
|
128
|
+
"max": "0.0",
|
|
129
|
+
"rms": "0.0",
|
|
130
|
+
"note": "Koch, Regiomontanus, Campanus, Alcabitius, Morinus, Meridian, Polich-Page, Vehlow: exact vs swe_houses_armc (200 polar-inclusive cases each)"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "Vertex / east point",
|
|
134
|
+
"max": "0.0",
|
|
135
|
+
"rms": "0.0",
|
|
136
|
+
"note": "exact vs swe_houses_armc"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "Magnitudes",
|
|
140
|
+
"max": "0.045 mag",
|
|
141
|
+
"rms": "—",
|
|
142
|
+
"note": "Mallama 2018; Moon (Allen law) valid to phase angle 140°"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"name": "Rise/set/meridian transit",
|
|
146
|
+
"max": "0.5 s",
|
|
147
|
+
"rms": "—",
|
|
148
|
+
"note": "vs swe_rise_trans, 48 polar-inclusive cases per body; Moon bound tracks its position accuracy"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "Crossings / lunar phases",
|
|
152
|
+
"max": "4 s",
|
|
153
|
+
"rms": "—",
|
|
154
|
+
"note": "vs swe_solcross/swe_mooncross and elongation root-finds"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "Stations",
|
|
158
|
+
"max": "55 s",
|
|
159
|
+
"rms": "—",
|
|
160
|
+
"note": "ill-conditioned by nature: speed-zero slope ~0.01°/day² turns sub-arcsecond model differences into minutes"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"name": "True Lilith (osc. apogee)",
|
|
164
|
+
"max": "187",
|
|
165
|
+
"rms": "—",
|
|
166
|
+
"note": "hypersensitive to the lunar theory (~1/e amplification); SE's own Moshier-vs-DE difference dominates. 'True Lilith' values disagree across software at this scale"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "Ceres, Pallas, Juno, Vesta, Pholus",
|
|
170
|
+
"max": "1.0",
|
|
171
|
+
"rms": "0.3",
|
|
172
|
+
"note": "JPL Horizons fits 1850-2150 (residual <5e-6 AU); same geocentric pipeline as Chiron. No independent SE oracle here: SE's asteroid files are unavailable in Moshier mode"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"name": "Uranian bodies (Cupido…Poseidon)",
|
|
176
|
+
"max": "2.3",
|
|
177
|
+
"rms": "—",
|
|
178
|
+
"note": "Hamburg-school constant-element Kepler orbits, elements fitted to SE 2.10's built-in definitions (fit_uranian.py prints per-body figures; Zeus is fit-noise-limited at ~3″ heliocentric). Uranian practice works in arcminutes"
|
|
179
|
+
}
|
|
22
180
|
],
|
|
23
181
|
"summary": [
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
182
|
+
{
|
|
183
|
+
"label": "Sun–Saturn",
|
|
184
|
+
"bound": "≤ 1″"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"label": "Uranus / Neptune",
|
|
188
|
+
"bound": "≤ 1.9″ / ≤ 4.6″"
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"label": "Moon (1920–2080 tier)",
|
|
192
|
+
"bound": "≤ 2.5″"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"label": "Moon (series, embedded)",
|
|
196
|
+
"bound": "≤ 10″"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"label": "Pluto / Chiron",
|
|
200
|
+
"bound": "≤ 2.5″ / ≤ 1″"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"label": "Angles & Placidus cusps",
|
|
204
|
+
"bound": "≤ 3.2″"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"label": "True node",
|
|
208
|
+
"bound": "≤ 1′ vs SE built-in (≤ 1″ vs JPL DE431)"
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"label": "Mean Lilith",
|
|
212
|
+
"bound": "≤ 1.3″"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"label": "Sidereal (5 ayanamsas)",
|
|
216
|
+
"bound": "≤ 0.3″ added"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"label": "8 new house systems",
|
|
220
|
+
"bound": "exact (0.0″)"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"label": "Rise/set/transit",
|
|
224
|
+
"bound": "≤ 0.5 s"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"label": "Crossings & phases",
|
|
228
|
+
"bound": "≤ 4 s"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"label": "Asteroids (big 4 + Pholus)",
|
|
232
|
+
"bound": "≤ 1″"
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"label": "Uranian bodies",
|
|
236
|
+
"bound": "≤ 2.3″"
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
"v03_harness": "python/validate_swiss.py regenerates every figure above the line against pyswisseph 2.10 (Moshier mode)",
|
|
240
|
+
"true_node_vs_builtin": "1′"
|
|
241
|
+
}
|
package/dist/src/chart.d.ts
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
1
|
/** astroengine chart -- public API: natal charts, aspects, retrogrades. */
|
|
2
|
-
import { EngineData } from "./core.js";
|
|
2
|
+
import { EngineData, AYANAMSA_J2000 } from "./core.js";
|
|
3
3
|
export declare const BODIES: readonly ["sun", "moon", "mercury", "venus", "mars", "jupiter", "saturn", "uranus", "neptune", "pluto", "chiron", "mean_node", "true_node"];
|
|
4
4
|
export type Body = (typeof BODIES)[number];
|
|
5
|
+
/** Computable on request (not in the default chart set). */
|
|
6
|
+
export declare const EXTRA_BODIES: readonly ["mean_lilith", "true_lilith"];
|
|
7
|
+
/** Core names keep autocomplete; any string id is accepted (data packs). */
|
|
8
|
+
export type BodyId = Body | (typeof EXTRA_BODIES)[number] | (string & {});
|
|
5
9
|
export declare const SIGNS: string[];
|
|
6
10
|
export declare const ASPECTS: Record<string, number>;
|
|
7
11
|
export declare const DEFAULT_ORBS: Record<string, number>;
|
|
8
|
-
export type HouseSystem = "placidus" | "porphyry" | "equal" | "whole_sign";
|
|
12
|
+
export type HouseSystem = "placidus" | "porphyry" | "equal" | "whole_sign" | "koch" | "regiomontanus" | "campanus" | "alcabitius" | "morinus" | "meridian" | "polich_page" | "vehlow";
|
|
13
|
+
export type Ayanamsa = keyof typeof AYANAMSA_J2000 & string;
|
|
14
|
+
export type Zodiac = "tropical" | `sidereal:${string}`;
|
|
15
|
+
export interface Observer {
|
|
16
|
+
lat: number;
|
|
17
|
+
lonEast: number;
|
|
18
|
+
altM?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface CalcOptions {
|
|
21
|
+
zodiac?: Zodiac;
|
|
22
|
+
topocentric?: boolean;
|
|
23
|
+
observer?: Observer;
|
|
24
|
+
}
|
|
25
|
+
export interface ChartOptions extends CalcOptions {
|
|
26
|
+
houseSystem?: HouseSystem;
|
|
27
|
+
bodies?: BodyId[];
|
|
28
|
+
orbs?: Record<string, number>;
|
|
29
|
+
}
|
|
9
30
|
export interface Position {
|
|
10
31
|
lon: number;
|
|
11
32
|
speed: number;
|
|
12
33
|
retrograde: boolean;
|
|
13
34
|
sign: string;
|
|
14
35
|
signDeg: number;
|
|
36
|
+
/** Ecliptic latitude, deg (0 for nodes). */
|
|
37
|
+
lat: number;
|
|
38
|
+
/** Geocentric distance in AU (Moon included); null for nodes and Lilith. */
|
|
39
|
+
dist: number | null;
|
|
40
|
+
/** Equatorial coordinates, true equinox of date, deg. */
|
|
41
|
+
ra: number;
|
|
42
|
+
dec: number;
|
|
15
43
|
}
|
|
16
44
|
export interface Aspect {
|
|
17
45
|
a: string;
|
|
@@ -21,30 +49,50 @@ export interface Aspect {
|
|
|
21
49
|
}
|
|
22
50
|
export interface Chart {
|
|
23
51
|
jdUt: number;
|
|
24
|
-
|
|
25
|
-
|
|
52
|
+
zodiac: Zodiac;
|
|
53
|
+
/** House system actually used. May differ from the request: Placidus and
|
|
54
|
+
* Koch are undefined above the polar circles and fall back to whole_sign. */
|
|
26
55
|
houseSystem: HouseSystem;
|
|
27
56
|
houseSystemRequested: HouseSystem;
|
|
28
57
|
bodies: Record<string, Position>;
|
|
29
58
|
angles: {
|
|
30
59
|
asc: number;
|
|
31
60
|
mc: number;
|
|
61
|
+
vertex: number;
|
|
62
|
+
eastPoint: number;
|
|
32
63
|
};
|
|
33
64
|
cusps: number[];
|
|
34
65
|
aspects: Aspect[];
|
|
35
66
|
}
|
|
36
67
|
export declare class Engine {
|
|
37
|
-
|
|
68
|
+
readonly data: EngineData;
|
|
38
69
|
private moonCheb;
|
|
39
70
|
private chironCheb;
|
|
71
|
+
private packs;
|
|
40
72
|
constructor(data: EngineData);
|
|
73
|
+
private pack;
|
|
41
74
|
private moonInRange;
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
/** Body ids this engine can compute, given the data it was handed. */
|
|
76
|
+
bodies(): BodyId[];
|
|
77
|
+
/** Apparent geocentric [lon rad, lat rad, dist AU | null] at TT jde.
|
|
78
|
+
* Building block for the events module; chart consumers want
|
|
79
|
+
* position() instead. */
|
|
80
|
+
ecliptic(body: BodyId, jde: number): [number, number, number | null];
|
|
81
|
+
private lonOnly;
|
|
82
|
+
/** Apparent geocentric ecliptic longitude (deg). Tropical: true equinox
|
|
83
|
+
* of date. Sidereal: mean equinox minus ayanamsa. */
|
|
84
|
+
longitude(body: BodyId, jdUt: number, opts?: CalcOptions): number;
|
|
85
|
+
/** Geometric heliocentric ecliptic of date (deg, deg, AU). */
|
|
86
|
+
heliocentric(body: BodyId, jdUt: number): {
|
|
87
|
+
lon: number;
|
|
88
|
+
lat: number;
|
|
89
|
+
dist: number;
|
|
90
|
+
};
|
|
91
|
+
/** Full position: lon/speed/retrograde/sign + lat, dist (AU), ra, dec. */
|
|
92
|
+
position(body: BodyId, jdUt: number, opts?: CalcOptions): Position;
|
|
93
|
+
/** Full natal chart. Time is UT. East longitude positive. The ninth
|
|
94
|
+
* argument takes a house system name (0.2.x form) or a ChartOptions bag. */
|
|
95
|
+
chart(y: number, mo: number, d: number, h: number, mi: number, s: number, lat: number, lonEast: number, opts?: HouseSystem | ChartOptions): Chart;
|
|
48
96
|
}
|
|
49
97
|
export declare function findAspects(bodies: Record<string, Position>, orbs?: Record<string, number>): Aspect[];
|
|
50
98
|
export declare function fmtLon(deg: number): string;
|