caelus 0.11.0 → 0.12.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.
@@ -59,9 +59,40 @@ export interface EngineData {
59
59
  /** Fixed-star catalog (HYG-derived; ICRS J2000 + proper motions). */
60
60
  fixedStars?: import("./stars.js").StarPack;
61
61
  }
62
+ /**
63
+ * Convert a UT calendar date and time to a Julian Day (UT) — the time
64
+ * coordinate the engine consumes. Pass the result to {@link Engine.position},
65
+ * {@link Engine.longitude}, {@link Engine.chartAt}, and the event/derived
66
+ * functions; {@link Engine.chart} takes the calendar fields directly instead.
67
+ *
68
+ * Arguments are **UT**, not local civil time — convert a local time to UT
69
+ * first (see the `caelus-birth` package). Uses the proleptic Gregorian
70
+ * calendar.
71
+ *
72
+ * @param y Year in UT, e.g. `1990`.
73
+ * @param mo Month, `1`–`12`.
74
+ * @param d Day of month, `1`–`31`.
75
+ * @param h Hour, `0`–`23`. Defaults to `0`.
76
+ * @param mi Minute, `0`–`59`. Defaults to `0`.
77
+ * @param s Second, `0`–`59`. Defaults to `0`.
78
+ * @returns The Julian Day in UT (a fractional day count).
79
+ * @example
80
+ * ```ts
81
+ * const jd = julianDay(2025, 6, 1, 12, 0, 0); // 2025-06-01 12:00 UT
82
+ * engine.longitude("sun", jd);
83
+ * ```
84
+ */
62
85
  export declare function julianDay(y: number, mo: number, d: number, h?: number, mi?: number, s?: number): number;
63
- /** TT - UT1 in seconds. Observed IERS 1955-2025, E&M polynomials before,
64
- * gentle extrapolation after (Earth's rotation sped up post-2016). */
86
+ /**
87
+ * ΔT (TT UT1) in seconds at a given instant — the gap between Terrestrial
88
+ * Time and universal time. Observed IERS values 1955–2025, Espenak–Meeus
89
+ * polynomials before, and a gentle extrapolation after (Earth's rotation sped
90
+ * up post-2016). The engine applies this for you; call it directly only for
91
+ * timescale work.
92
+ *
93
+ * @param jdUt Julian Day (UT).
94
+ * @returns ΔT in seconds.
95
+ */
65
96
  export declare function deltaT(jdUt: number): number;
66
97
  export declare function jdTT(jdUt: number): number;
67
98
  export declare function vsopHeliocentric(series: VsopSeries, jde: number): [number, number, number];
package/dist/src/core.js CHANGED
@@ -17,6 +17,29 @@ export function mod(a, b) {
17
17
  return r !== 0 && (r < 0) !== (b < 0) ? r + b : r;
18
18
  }
19
19
  // ---------------------------------------------------------------- timescale
20
+ /**
21
+ * Convert a UT calendar date and time to a Julian Day (UT) — the time
22
+ * coordinate the engine consumes. Pass the result to {@link Engine.position},
23
+ * {@link Engine.longitude}, {@link Engine.chartAt}, and the event/derived
24
+ * functions; {@link Engine.chart} takes the calendar fields directly instead.
25
+ *
26
+ * Arguments are **UT**, not local civil time — convert a local time to UT
27
+ * first (see the `caelus-birth` package). Uses the proleptic Gregorian
28
+ * calendar.
29
+ *
30
+ * @param y Year in UT, e.g. `1990`.
31
+ * @param mo Month, `1`–`12`.
32
+ * @param d Day of month, `1`–`31`.
33
+ * @param h Hour, `0`–`23`. Defaults to `0`.
34
+ * @param mi Minute, `0`–`59`. Defaults to `0`.
35
+ * @param s Second, `0`–`59`. Defaults to `0`.
36
+ * @returns The Julian Day in UT (a fractional day count).
37
+ * @example
38
+ * ```ts
39
+ * const jd = julianDay(2025, 6, 1, 12, 0, 0); // 2025-06-01 12:00 UT
40
+ * engine.longitude("sun", jd);
41
+ * ```
42
+ */
20
43
  export function julianDay(y, mo, d, h = 0, mi = 0, s = 0) {
21
44
  const frac = (h + mi / 60.0 + s / 3600.0) / 24.0;
22
45
  if (mo <= 2) {
@@ -33,8 +56,16 @@ const DT_OBS = [
33
56
  [1980, 50.5], [1985, 54.3], [1990, 56.9], [1995, 60.8], [2000, 63.8],
34
57
  [2005, 64.7], [2010, 66.1], [2015, 67.6], [2020, 69.4], [2025, 69.2],
35
58
  ];
36
- /** TT - UT1 in seconds. Observed IERS 1955-2025, E&M polynomials before,
37
- * gentle extrapolation after (Earth's rotation sped up post-2016). */
59
+ /**
60
+ * ΔT (TT UT1) in seconds at a given instant — the gap between Terrestrial
61
+ * Time and universal time. Observed IERS values 1955–2025, Espenak–Meeus
62
+ * polynomials before, and a gentle extrapolation after (Earth's rotation sped
63
+ * up post-2016). The engine applies this for you; call it directly only for
64
+ * timescale work.
65
+ *
66
+ * @param jdUt Julian Day (UT).
67
+ * @returns ΔT in seconds.
68
+ */
38
69
  export function deltaT(jdUt) {
39
70
  const y = 2000.0 + (jdUt - J2000) / 365.25;
40
71
  if (y >= 1955 && y <= 2025) {
@@ -5,11 +5,50 @@ export declare function midpointLon(a: number, b: number): number;
5
5
  /** UT JDs in [jdStart, jdEnd] when `body` returns to its natal longitude.
6
6
  * Outer-planet returns can show three crossings around a retrograde loop. */
7
7
  export declare function returns(engine: Engine, body: BodyId, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac, maxHits?: number): number[];
8
+ /**
9
+ * Solar-return instants in `[jdStart, jdEnd]`: the times the Sun returns to its
10
+ * natal longitude (about once a year). Build a chart at each with
11
+ * {@link Engine.chartAt} for the solar-return chart.
12
+ *
13
+ * @param engine The engine used to evaluate positions.
14
+ * @param natalJd Natal Julian Day (UT) — defines the target Sun longitude.
15
+ * @param jdStart Start of the search window, Julian Day (UT).
16
+ * @param jdEnd End of the search window, Julian Day (UT).
17
+ * @param zodiac Zodiac for the longitude match. Defaults to tropical.
18
+ * @returns Return instants as Julian Days (UT), sorted.
19
+ * @example
20
+ * ```ts
21
+ * const natal = julianDay(1990, 6, 10, 14, 30);
22
+ * const [thisYear] = solarReturn(engine, natal, julianDay(2025, 1, 1), julianDay(2026, 1, 1));
23
+ * const returnChart = engine.chartAt(thisYear, 27.95, -82.46);
24
+ * ```
25
+ * @see {@link lunarReturn} for the monthly Moon return.
26
+ */
8
27
  export declare function solarReturn(engine: Engine, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac): number[];
9
28
  export declare function lunarReturn(engine: Engine, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac): number[];
10
29
  /** The JD whose real positions are the secondary-progressed positions for the
11
30
  * age (targetJd - natalJd): one day of motion per year of life. */
12
31
  export declare function progressedJd(natalJd: number, targetJd: number, yearLength?: number): number;
32
+ /**
33
+ * Secondary-progressed longitude of a body for a given target date: the
34
+ * "day-for-a-year" method, where one day of real motion after birth maps to one
35
+ * year of life. Equivalent to taking the body's longitude at
36
+ * {@link progressedJd}.
37
+ *
38
+ * @param engine The engine used to evaluate positions.
39
+ * @param body A body id from {@link Engine.bodies}.
40
+ * @param natalJd Natal Julian Day (UT).
41
+ * @param targetJd The date to progress to, Julian Day (UT).
42
+ * @param yearLength Days per year of life. Defaults to the tropical year.
43
+ * @param zodiac Zodiac for the result. Defaults to tropical.
44
+ * @returns The progressed ecliptic longitude in degrees, `[0, 360)`.
45
+ * @example
46
+ * ```ts
47
+ * const natal = julianDay(1990, 6, 10, 14, 30);
48
+ * progressedLongitude(engine, "moon", natal, julianDay(2025, 6, 10));
49
+ * ```
50
+ * @see {@link solarArc} and {@link directedLongitude} for solar-arc directions.
51
+ */
13
52
  export declare function progressedLongitude(engine: Engine, body: BodyId, natalJd: number, targetJd: number, yearLength?: number, zodiac?: Zodiac): number;
14
53
  /** Solar-arc direction angle (degrees, forward): how far the secondary-
15
54
  * progressed Sun has moved from the natal Sun. Add it to any natal longitude. */
@@ -24,6 +63,22 @@ export declare function compositeLongitudes(engine: Engine, jdA: number, jdB: nu
24
63
  export declare function davisonParams(jdA: number, jdB: number, latA: number, lonEastA: number, latB: number, lonEastB: number): [number, number, number];
25
64
  /** The nth-harmonic longitude of a point: lon * n, wrapped to 360. */
26
65
  export declare function harmonicLongitude(lon: number, n: number): number;
66
+ /**
67
+ * The nth-harmonic chart: each body's longitude multiplied by `n` and wrapped
68
+ * to `[0, 360)`. The 5th harmonic surfaces quintiles, the 9th the navamsa, and
69
+ * so on.
70
+ *
71
+ * @param engine The engine used to evaluate positions.
72
+ * @param jd Julian Day (UT).
73
+ * @param bodies The bodies to include.
74
+ * @param n The harmonic number, e.g. `5` or `9`.
75
+ * @param zodiac Zodiac for the base longitudes. Defaults to tropical.
76
+ * @returns Harmonic longitudes in degrees, keyed by body id.
77
+ * @example
78
+ * ```ts
79
+ * harmonicChart(engine, jd, ["sun", "moon", "venus"], 5); // quintile harmonic
80
+ * ```
81
+ */
27
82
  export declare function harmonicChart(engine: Engine, jd: number, bodies: BodyId[], n: number, zodiac?: Zodiac): Record<string, number>;
28
83
  /** Reflection across the solstice (Cancer-Capricorn) axis. */
29
84
  export declare function antiscion(lon: number): number;
@@ -37,15 +92,49 @@ export interface DeclinationPair {
37
92
  b: string;
38
93
  kind: DeclinationKind;
39
94
  }
95
+ /**
96
+ * Parallels and contraparallels among a set of bodies at an instant: pairs
97
+ * whose declinations are equal (parallel) or equal and opposite
98
+ * (contraparallel) within `orb` — the declination analogue of conjunction and
99
+ * opposition.
100
+ *
101
+ * @param engine The engine used to evaluate positions.
102
+ * @param bodies The bodies to compare.
103
+ * @param jd Julian Day (UT).
104
+ * @param orb Declination orb in degrees. Defaults to `1.0`.
105
+ * @returns {@link DeclinationPair}s `{ a, b, kind }`, where `kind` is
106
+ * `"parallel"` or `"contraparallel"`.
107
+ */
40
108
  export declare function declinationAspects(engine: Engine, bodies: BodyId[], jd: number, orb?: number): DeclinationPair[];
41
109
  /** |declination| minus the mean obliquity, degrees. Positive = out of bounds. */
42
110
  export declare function outOfBoundsMargin(engine: Engine, body: BodyId, jd: number): number;
43
111
  export declare function outOfBounds(engine: Engine, body: BodyId, jd: number): boolean;
44
- /** Essential dignities of `body` in `sign`: domicile, exaltation, detriment,
45
- * fall (the last two are the signs opposite domicile and exaltation). */
112
+ /**
113
+ * Essential dignities a body holds in a sign: any of `"domicile"`,
114
+ * `"exaltation"`, `"detriment"`, `"fall"` (the last two are the signs opposite
115
+ * domicile and exaltation). Empty when the body is peregrine there.
116
+ *
117
+ * @param body Body id, e.g. `"mars"`.
118
+ * @param sign A sign index `0`–`11` (Aries = 0) or its name, e.g. `"Aries"`.
119
+ * @returns The dignities held, in the order above; empty if none.
120
+ * @example
121
+ * ```ts
122
+ * dignities("mars", "Aries"); // ["domicile"]
123
+ * dignities("sun", "Libra"); // ["fall"]
124
+ * ```
125
+ */
46
126
  export declare function dignities(body: string, sign: number | string): string[];
47
127
  export declare function dignityOf(engine: Engine, body: BodyId, jd: number, zodiac?: Zodiac): string[];
48
128
  /** Diurnal when the Sun is above the horizon at the given place. */
49
129
  export declare function isDayChart(engine: Engine, jd: number, lat: number, lonEast: number): boolean;
130
+ /**
131
+ * The sect a body belongs to: `"diurnal"` (Sun, Jupiter, Saturn),
132
+ * `"nocturnal"` (Moon, Venus, Mars), or `null` for Mercury and bodies without a
133
+ * fixed sect. Whether a chart is itself day or night — the Sun above or below
134
+ * the horizon — is a separate question.
135
+ *
136
+ * @param body Body id.
137
+ * @returns `"diurnal"`, `"nocturnal"`, or `null`.
138
+ */
50
139
  export declare function planetarySect(body: string): "diurnal" | "nocturnal" | null;
51
140
  export declare function inSect(body: string, dayChart: boolean): boolean | null;
@@ -25,6 +25,25 @@ export function returns(engine, body, natalJd, jdStart, jdEnd, zodiac = "tropica
25
25
  const natalLon = engine.longitude(body, natalJd, { zodiac });
26
26
  return crossings(engine, body, natalLon, jdStart, jdEnd, zodiac, maxHits);
27
27
  }
28
+ /**
29
+ * Solar-return instants in `[jdStart, jdEnd]`: the times the Sun returns to its
30
+ * natal longitude (about once a year). Build a chart at each with
31
+ * {@link Engine.chartAt} for the solar-return chart.
32
+ *
33
+ * @param engine The engine used to evaluate positions.
34
+ * @param natalJd Natal Julian Day (UT) — defines the target Sun longitude.
35
+ * @param jdStart Start of the search window, Julian Day (UT).
36
+ * @param jdEnd End of the search window, Julian Day (UT).
37
+ * @param zodiac Zodiac for the longitude match. Defaults to tropical.
38
+ * @returns Return instants as Julian Days (UT), sorted.
39
+ * @example
40
+ * ```ts
41
+ * const natal = julianDay(1990, 6, 10, 14, 30);
42
+ * const [thisYear] = solarReturn(engine, natal, julianDay(2025, 1, 1), julianDay(2026, 1, 1));
43
+ * const returnChart = engine.chartAt(thisYear, 27.95, -82.46);
44
+ * ```
45
+ * @see {@link lunarReturn} for the monthly Moon return.
46
+ */
28
47
  export function solarReturn(engine, natalJd, jdStart, jdEnd, zodiac = "tropical") {
29
48
  return returns(engine, "sun", natalJd, jdStart, jdEnd, zodiac);
30
49
  }
@@ -37,6 +56,26 @@ export function lunarReturn(engine, natalJd, jdStart, jdEnd, zodiac = "tropical"
37
56
  export function progressedJd(natalJd, targetJd, yearLength = TROPICAL_YEAR) {
38
57
  return natalJd + (targetJd - natalJd) / yearLength;
39
58
  }
59
+ /**
60
+ * Secondary-progressed longitude of a body for a given target date: the
61
+ * "day-for-a-year" method, where one day of real motion after birth maps to one
62
+ * year of life. Equivalent to taking the body's longitude at
63
+ * {@link progressedJd}.
64
+ *
65
+ * @param engine The engine used to evaluate positions.
66
+ * @param body A body id from {@link Engine.bodies}.
67
+ * @param natalJd Natal Julian Day (UT).
68
+ * @param targetJd The date to progress to, Julian Day (UT).
69
+ * @param yearLength Days per year of life. Defaults to the tropical year.
70
+ * @param zodiac Zodiac for the result. Defaults to tropical.
71
+ * @returns The progressed ecliptic longitude in degrees, `[0, 360)`.
72
+ * @example
73
+ * ```ts
74
+ * const natal = julianDay(1990, 6, 10, 14, 30);
75
+ * progressedLongitude(engine, "moon", natal, julianDay(2025, 6, 10));
76
+ * ```
77
+ * @see {@link solarArc} and {@link directedLongitude} for solar-arc directions.
78
+ */
40
79
  export function progressedLongitude(engine, body, natalJd, targetJd, yearLength = TROPICAL_YEAR, zodiac = "tropical") {
41
80
  return engine.longitude(body, progressedJd(natalJd, targetJd, yearLength), { zodiac });
42
81
  }
@@ -82,6 +121,22 @@ export function davisonParams(jdA, jdB, latA, lonEastA, latB, lonEastB) {
82
121
  export function harmonicLongitude(lon, n) {
83
122
  return mod(lon * n, 360);
84
123
  }
124
+ /**
125
+ * The nth-harmonic chart: each body's longitude multiplied by `n` and wrapped
126
+ * to `[0, 360)`. The 5th harmonic surfaces quintiles, the 9th the navamsa, and
127
+ * so on.
128
+ *
129
+ * @param engine The engine used to evaluate positions.
130
+ * @param jd Julian Day (UT).
131
+ * @param bodies The bodies to include.
132
+ * @param n The harmonic number, e.g. `5` or `9`.
133
+ * @param zodiac Zodiac for the base longitudes. Defaults to tropical.
134
+ * @returns Harmonic longitudes in degrees, keyed by body id.
135
+ * @example
136
+ * ```ts
137
+ * harmonicChart(engine, jd, ["sun", "moon", "venus"], 5); // quintile harmonic
138
+ * ```
139
+ */
85
140
  export function harmonicChart(engine, jd, bodies, n, zodiac = "tropical") {
86
141
  const out = {};
87
142
  for (const b of bodies)
@@ -105,6 +160,19 @@ export function declinationAspect(decA, decB, orb = 1.0) {
105
160
  return "contraparallel";
106
161
  return null;
107
162
  }
163
+ /**
164
+ * Parallels and contraparallels among a set of bodies at an instant: pairs
165
+ * whose declinations are equal (parallel) or equal and opposite
166
+ * (contraparallel) within `orb` — the declination analogue of conjunction and
167
+ * opposition.
168
+ *
169
+ * @param engine The engine used to evaluate positions.
170
+ * @param bodies The bodies to compare.
171
+ * @param jd Julian Day (UT).
172
+ * @param orb Declination orb in degrees. Defaults to `1.0`.
173
+ * @returns {@link DeclinationPair}s `{ a, b, kind }`, where `kind` is
174
+ * `"parallel"` or `"contraparallel"`.
175
+ */
108
176
  export function declinationAspects(engine, bodies, jd, orb = 1.0) {
109
177
  const decs = {};
110
178
  for (const b of bodies)
@@ -140,8 +208,20 @@ const EXALTATION = {
140
208
  function signIndex(sign) {
141
209
  return typeof sign === "number" ? sign : SIGNS.indexOf(sign);
142
210
  }
143
- /** Essential dignities of `body` in `sign`: domicile, exaltation, detriment,
144
- * fall (the last two are the signs opposite domicile and exaltation). */
211
+ /**
212
+ * Essential dignities a body holds in a sign: any of `"domicile"`,
213
+ * `"exaltation"`, `"detriment"`, `"fall"` (the last two are the signs opposite
214
+ * domicile and exaltation). Empty when the body is peregrine there.
215
+ *
216
+ * @param body Body id, e.g. `"mars"`.
217
+ * @param sign A sign index `0`–`11` (Aries = 0) or its name, e.g. `"Aries"`.
218
+ * @returns The dignities held, in the order above; empty if none.
219
+ * @example
220
+ * ```ts
221
+ * dignities("mars", "Aries"); // ["domicile"]
222
+ * dignities("sun", "Libra"); // ["fall"]
223
+ * ```
224
+ */
145
225
  export function dignities(body, sign) {
146
226
  const idx = signIndex(sign);
147
227
  const dom = DOMICILE[body] ?? [];
@@ -169,6 +249,15 @@ export function isDayChart(engine, jd, lat, lonEast) {
169
249
  const [, alt] = azAlt(engine.data, sun.lon, sun.lat, jd, lat, lonEast);
170
250
  return alt > 0;
171
251
  }
252
+ /**
253
+ * The sect a body belongs to: `"diurnal"` (Sun, Jupiter, Saturn),
254
+ * `"nocturnal"` (Moon, Venus, Mars), or `null` for Mercury and bodies without a
255
+ * fixed sect. Whether a chart is itself day or night — the Sun above or below
256
+ * the horizon — is a separate question.
257
+ *
258
+ * @param body Body id.
259
+ * @returns `"diurnal"`, `"nocturnal"`, or `null`.
260
+ */
172
261
  export function planetarySect(body) {
173
262
  if (DIURNAL.has(body))
174
263
  return "diurnal";
@@ -20,5 +20,21 @@ export interface SolarEclipse {
20
20
  }
21
21
  /** Lunar eclipses in [jdStart, jdEnd] (UT JDs). */
22
22
  export declare function lunarEclipses(engine: Engine, jdStart: number, jdEnd: number): LunarEclipse[];
23
- /** Solar eclipses (global circumstances) in [jdStart, jdEnd] (UT JDs). */
23
+ /**
24
+ * Solar eclipses in `[jdStart, jdEnd]`, with global circumstances (not
25
+ * local visibility). Each new Moon in the window is tested for an eclipse and,
26
+ * when found, classified by the Moon's shadow geometry.
27
+ *
28
+ * @param engine The engine used to evaluate positions.
29
+ * @param jdStart Start of the window, Julian Day (UT).
30
+ * @param jdEnd End of the window, Julian Day (UT).
31
+ * @returns {@link SolarEclipse} records: `tMax` (greatest eclipse, JD UT),
32
+ * `type` (`"total"`/`"annular"`/`"hybrid"`/`"partial"`), `gamma` (minimum
33
+ * shadow-axis distance in Earth radii), and the `begin`/`end` JDs.
34
+ * @example
35
+ * ```ts
36
+ * const eclipses = solarEclipses(engine, julianDay(2025, 1, 1), julianDay(2030, 1, 1));
37
+ * eclipses[0].type; // e.g. "partial"
38
+ * ```
39
+ */
24
40
  export declare function solarEclipses(engine: Engine, jdStart: number, jdEnd: number): SolarEclipse[];
@@ -131,7 +131,23 @@ export function lunarEclipses(engine, jdStart, jdEnd) {
131
131
  }
132
132
  return out;
133
133
  }
134
- /** Solar eclipses (global circumstances) in [jdStart, jdEnd] (UT JDs). */
134
+ /**
135
+ * Solar eclipses in `[jdStart, jdEnd]`, with global circumstances (not
136
+ * local visibility). Each new Moon in the window is tested for an eclipse and,
137
+ * when found, classified by the Moon's shadow geometry.
138
+ *
139
+ * @param engine The engine used to evaluate positions.
140
+ * @param jdStart Start of the window, Julian Day (UT).
141
+ * @param jdEnd End of the window, Julian Day (UT).
142
+ * @returns {@link SolarEclipse} records: `tMax` (greatest eclipse, JD UT),
143
+ * `type` (`"total"`/`"annular"`/`"hybrid"`/`"partial"`), `gamma` (minimum
144
+ * shadow-axis distance in Earth radii), and the `begin`/`end` JDs.
145
+ * @example
146
+ * ```ts
147
+ * const eclipses = solarEclipses(engine, julianDay(2025, 1, 1), julianDay(2030, 1, 1));
148
+ * eclipses[0].type; // e.g. "partial"
149
+ * ```
150
+ */
135
151
  export function solarEclipses(engine, jdStart, jdEnd) {
136
152
  const out = [];
137
153
  for (const tNew of syzygies(engine, jdStart - 1, jdEnd + 1, 0.0)) {
@@ -8,22 +8,68 @@ export interface RiseSetOptions {
8
8
  /** Rise/set of the disc center instead of the upper limb. */
9
9
  discCenter?: boolean;
10
10
  }
11
- /** Next rise/set/meridian transit (UT JD) after jdStart, or null when the
12
- * event does not occur in the window (polar day/night). */
11
+ /**
12
+ * The next rise, set, or meridian transit of a body after `jdStart`, as a
13
+ * Julian Day (UT). Accounts for the body's apparent radius, atmospheric
14
+ * refraction, and observer altitude.
15
+ *
16
+ * @param engine The engine used to evaluate positions.
17
+ * @param body A body id from {@link Engine.bodies}.
18
+ * @param jdStart Search start, Julian Day (UT). The result is the first event
19
+ * strictly after this instant.
20
+ * @param latDeg Observer latitude in degrees, north positive.
21
+ * @param lonDeg Observer longitude in degrees, east positive.
22
+ * @param kind `"rise"`, `"set"`, `"mtransit"` (upper/meridian transit), or
23
+ * `"itransit"` (lower transit). Defaults to `"rise"`.
24
+ * @param opts `altM` (observer altitude, m), `pressure` (hPa), `tempC`, and
25
+ * `searchDays` (how far ahead to look; defaults to 2).
26
+ * @returns The event time as a Julian Day (UT), or `null` when it does not
27
+ * occur in the window (e.g. polar day or night).
28
+ * @example
29
+ * ```ts
30
+ * // Next sunrise over London after 2025-06-01
31
+ * const jd = riseSet(engine, "sun", julianDay(2025, 6, 1), 51.5, -0.13, "rise");
32
+ * ```
33
+ */
13
34
  export declare function riseSet(engine: Engine, body: BodyId, jdStart: number, latDeg: number, lonDeg: number, kind?: RiseKind, opts?: RiseSetOptions): number | null;
14
35
  /** UT JDs where the body's apparent longitude crosses targetLon (degrees)
15
36
  * in [jdStart, jdEnd]. Retrograde bodies can cross a degree three times;
16
37
  * every crossing is returned in time order. */
17
38
  export declare function crossings(engine: Engine, body: BodyId, targetLon: number, jdStart: number, jdEnd: number, zodiac?: Zodiac, maxHits?: number): number[];
18
39
  export type PhaseName = "new" | "first_quarter" | "full" | "last_quarter";
19
- /** New/first-quarter/full/last-quarter times in [jdStart, jdEnd], sorted. */
40
+ /**
41
+ * Every principal lunar phase (new, first quarter, full, last quarter) within
42
+ * `[jdStart, jdEnd]`, sorted by time. Found from the Sun–Moon elongation
43
+ * crossing 0°/90°/180°/270°.
44
+ *
45
+ * @param engine The engine used to evaluate positions.
46
+ * @param jdStart Start of the window, Julian Day (UT).
47
+ * @param jdEnd End of the window, Julian Day (UT).
48
+ * @param maxHits Cap on the number of phases returned. Defaults to 60.
49
+ * @returns Sorted `[jdUt, phase]` pairs, where `phase` is one of
50
+ * {@link PhaseName}.
51
+ * @example
52
+ * ```ts
53
+ * const phases = lunarPhases(engine, julianDay(2025, 1, 1), julianDay(2025, 2, 1));
54
+ * // [[jd, "new"], [jd, "first_quarter"], ...]
55
+ * ```
56
+ */
20
57
  export declare function lunarPhases(engine: Engine, jdStart: number, jdEnd: number, maxHits?: number): Array<[number, PhaseName]>;
21
58
  /** Times the body stations (speed crosses zero): [jdUt, direction the body
22
59
  * turns]. Sun and Moon never station. Station timing is ill-conditioned:
23
60
  * expect minute-level differences between ephemerides. */
24
61
  export declare function stations(engine: Engine, body: BodyId, jdStart: number, jdEnd: number, maxHits?: number): Array<[number, "retrograde" | "direct"]>;
25
- /** Gauquelin sector (1..36, float) from rise/set times of the disc center
26
- * with refraction (Swiss Ephemeris method 3). Sectors run from rise: 1-18
27
- * above the horizon, 19-36 below. Null in polar no-rise/no-set
28
- * conditions. */
62
+ /**
63
+ * The Gauquelin sector of a body (1–36, fractional) from the rise/set times of
64
+ * the disc centre with refraction (Swiss Ephemeris method 3). Sectors run from
65
+ * rise: 1–18 above the horizon, 19–36 below.
66
+ *
67
+ * @param engine The engine used to evaluate positions.
68
+ * @param body A body id from {@link Engine.bodies}.
69
+ * @param jdUt Julian Day (UT).
70
+ * @param latDeg Observer latitude in degrees, north positive.
71
+ * @param lonDeg Observer longitude in degrees, east positive.
72
+ * @returns The sector in `[1, 37)`, or `null` in polar no-rise/no-set
73
+ * conditions.
74
+ */
29
75
  export declare function gauquelinSector(engine: Engine, body: BodyId, jdUt: number, latDeg: number, lonDeg: number): number | null;
@@ -44,8 +44,29 @@ function bisect(f, a, b, iters = 45) {
44
44
  }
45
45
  return (a + b) / 2;
46
46
  }
47
- /** Next rise/set/meridian transit (UT JD) after jdStart, or null when the
48
- * event does not occur in the window (polar day/night). */
47
+ /**
48
+ * The next rise, set, or meridian transit of a body after `jdStart`, as a
49
+ * Julian Day (UT). Accounts for the body's apparent radius, atmospheric
50
+ * refraction, and observer altitude.
51
+ *
52
+ * @param engine The engine used to evaluate positions.
53
+ * @param body A body id from {@link Engine.bodies}.
54
+ * @param jdStart Search start, Julian Day (UT). The result is the first event
55
+ * strictly after this instant.
56
+ * @param latDeg Observer latitude in degrees, north positive.
57
+ * @param lonDeg Observer longitude in degrees, east positive.
58
+ * @param kind `"rise"`, `"set"`, `"mtransit"` (upper/meridian transit), or
59
+ * `"itransit"` (lower transit). Defaults to `"rise"`.
60
+ * @param opts `altM` (observer altitude, m), `pressure` (hPa), `tempC`, and
61
+ * `searchDays` (how far ahead to look; defaults to 2).
62
+ * @returns The event time as a Julian Day (UT), or `null` when it does not
63
+ * occur in the window (e.g. polar day or night).
64
+ * @example
65
+ * ```ts
66
+ * // Next sunrise over London after 2025-06-01
67
+ * const jd = riseSet(engine, "sun", julianDay(2025, 6, 1), 51.5, -0.13, "rise");
68
+ * ```
69
+ */
49
70
  export function riseSet(engine, body, jdStart, latDeg, lonDeg, kind = "rise", opts = {}) {
50
71
  const altM = opts.altM ?? 0.0;
51
72
  const pressure = opts.pressure ?? 1013.25;
@@ -110,7 +131,23 @@ export function crossings(engine, body, targetLon, jdStart, jdEnd, zodiac = "tro
110
131
  }
111
132
  return out;
112
133
  }
113
- /** New/first-quarter/full/last-quarter times in [jdStart, jdEnd], sorted. */
134
+ /**
135
+ * Every principal lunar phase (new, first quarter, full, last quarter) within
136
+ * `[jdStart, jdEnd]`, sorted by time. Found from the Sun–Moon elongation
137
+ * crossing 0°/90°/180°/270°.
138
+ *
139
+ * @param engine The engine used to evaluate positions.
140
+ * @param jdStart Start of the window, Julian Day (UT).
141
+ * @param jdEnd End of the window, Julian Day (UT).
142
+ * @param maxHits Cap on the number of phases returned. Defaults to 60.
143
+ * @returns Sorted `[jdUt, phase]` pairs, where `phase` is one of
144
+ * {@link PhaseName}.
145
+ * @example
146
+ * ```ts
147
+ * const phases = lunarPhases(engine, julianDay(2025, 1, 1), julianDay(2025, 2, 1));
148
+ * // [[jd, "new"], [jd, "first_quarter"], ...]
149
+ * ```
150
+ */
114
151
  export function lunarPhases(engine, jdStart, jdEnd, maxHits = 60) {
115
152
  const elong = (t) => mod(engine.longitude("moon", t) - engine.longitude("sun", t), 360);
116
153
  const names = [
@@ -154,10 +191,19 @@ export function stations(engine, body, jdStart, jdEnd, maxHits = 30) {
154
191
  }
155
192
  return out;
156
193
  }
157
- /** Gauquelin sector (1..36, float) from rise/set times of the disc center
158
- * with refraction (Swiss Ephemeris method 3). Sectors run from rise: 1-18
159
- * above the horizon, 19-36 below. Null in polar no-rise/no-set
160
- * conditions. */
194
+ /**
195
+ * The Gauquelin sector of a body (1–36, fractional) from the rise/set times of
196
+ * the disc centre with refraction (Swiss Ephemeris method 3). Sectors run from
197
+ * rise: 1–18 above the horizon, 19–36 below.
198
+ *
199
+ * @param engine The engine used to evaluate positions.
200
+ * @param body A body id from {@link Engine.bodies}.
201
+ * @param jdUt Julian Day (UT).
202
+ * @param latDeg Observer latitude in degrees, north positive.
203
+ * @param lonDeg Observer longitude in degrees, east positive.
204
+ * @returns The sector in `[1, 37)`, or `null` in polar no-rise/no-set
205
+ * conditions.
206
+ */
161
207
  export function gauquelinSector(engine, body, jdUt, latDeg, lonDeg) {
162
208
  const surrounding = (kind) => {
163
209
  let t = riseSet(engine, body, jdUt - 1.3, latDeg, lonDeg, kind, { discCenter: true });
@@ -1,19 +1,63 @@
1
1
  import { Engine, BodyId, Zodiac } from "./chart.js";
2
2
  import { RankedMoment } from "./scan.js";
3
3
  export declare const DEFAULT_BODIES: string[];
4
- /** Flat vector [w*cos(lon), w*sin(lon), ...] for the given (longitude, weight)
5
- * pairs, in order. */
4
+ /**
5
+ * Build a feature vector from explicit `(longitude, weight)` pairs: each pair
6
+ * contributes a weighted unit-circle point `[w·cos(lon), w·sin(lon)]`. The
7
+ * low-level primitive behind {@link chartFeatures}; most callers want that.
8
+ *
9
+ * @param weightedLons `[longitudeDeg, weight]` pairs, in the order they should
10
+ * appear in the vector.
11
+ * @returns A flat vector, two entries per pair.
12
+ */
6
13
  export declare function featureVector(weightedLons: [number, number][]): number[];
7
- /** Cosine similarity of two feature vectors, in [-1, 1]. */
14
+ /**
15
+ * Cosine similarity of two feature vectors, in `[-1, 1]`. For vectors from
16
+ * {@link chartFeatures} this is a weighted mean of `cos(Δlongitude)` per body:
17
+ * `1` when the configurations coincide, falling off as bodies diverge.
18
+ *
19
+ * @param a First feature vector.
20
+ * @param b Second feature vector (compared over the shorter length).
21
+ * @returns Similarity in `[-1, 1]`; `0` if either vector is all zeros.
22
+ */
8
23
  export declare function cosineSimilarity(a: number[], b: number[]): number;
9
24
  export interface FeatureOptions {
10
25
  bodies?: BodyId[];
11
26
  weights?: Record<string, number>;
12
27
  zodiac?: Zodiac;
13
28
  }
14
- /** Feature vector for the sky at jdUt over an ordered set of bodies. */
29
+ /**
30
+ * Encode the sky at an instant as a feature vector: each body's ecliptic
31
+ * longitude becomes a weighted unit-circle point. The deterministic substrate
32
+ * for matching and searching chart configurations — compare two with
33
+ * {@link cosineSimilarity}, or rank a time range against one with
34
+ * {@link searchConfigurations}.
35
+ *
36
+ * @param engine The engine used to evaluate positions.
37
+ * @param jdUt Julian Day in UT.
38
+ * @param opts `bodies` (ordered; defaults to the ten major bodies), per-body
39
+ * `weights`, and `zodiac` (tropical by default).
40
+ * @returns A flat vector `[w·cos(lon), w·sin(lon), ...]`, two entries per body
41
+ * in `bodies` order.
42
+ * @example
43
+ * ```ts
44
+ * const target = chartFeatures(engine, julianDay(2000, 1, 1));
45
+ * const now = chartFeatures(engine, julianDay(2025, 6, 1));
46
+ * cosineSimilarity(now, target); // 1 = identical configuration
47
+ * ```
48
+ */
15
49
  export declare function chartFeatures(engine: Engine, jdUt: number, opts?: FeatureOptions): number[];
16
- /** Similarity between the sky at jdUt and a target feature vector. */
50
+ /**
51
+ * Similarity between the sky at `jdUt` and a target feature vector — shorthand
52
+ * for `cosineSimilarity(chartFeatures(engine, jdUt, opts), target)`. The scoring
53
+ * function {@link searchConfigurations} maximizes.
54
+ *
55
+ * @param engine The engine used to evaluate positions.
56
+ * @param jdUt Julian Day in UT.
57
+ * @param target A target feature vector from {@link chartFeatures}.
58
+ * @param opts {@link FeatureOptions} — must match those used to build `target`.
59
+ * @returns Cosine similarity in `[-1, 1]`.
60
+ */
17
61
  export declare function configurationFit(engine: Engine, jdUt: number, target: number[], opts?: FeatureOptions): number;
18
62
  export interface SearchConfigOptions extends FeatureOptions {
19
63
  start: number;
@@ -21,6 +65,24 @@ export interface SearchConfigOptions extends FeatureOptions {
21
65
  step: number;
22
66
  limit?: number;
23
67
  }
24
- /** Rank the instants in [start, end] by how closely the sky resembles `target`
25
- * (a feature vector), best first. Realization search over the feature space. */
68
+ /**
69
+ * Rank the instants in `[start, end]` by how closely the sky resembles a
70
+ * `target` feature vector, best first — a realization search over the feature
71
+ * space. Build `target` with {@link chartFeatures} (e.g. from a natal chart).
72
+ *
73
+ * @param engine The engine used to evaluate positions.
74
+ * @param target A target feature vector from {@link chartFeatures}.
75
+ * @param opts `start`/`end` (Julian Days, UT) and `step` (days) define the
76
+ * scan, `limit` caps the results, plus the {@link FeatureOptions} (`bodies`,
77
+ * `weights`, `zodiac`) — which must match those used to build `target`.
78
+ * @returns Ranked `{ jd, score }` moments, highest similarity first.
79
+ * @example
80
+ * ```ts
81
+ * const natal = chartFeatures(engine, julianDay(1990, 6, 10, 14, 30));
82
+ * const matches = searchConfigurations(engine, natal, {
83
+ * start: julianDay(2025, 1, 1), end: julianDay(2026, 1, 1), step: 1, limit: 5,
84
+ * });
85
+ * matches[0].jd; // best-matching instant
86
+ * ```
87
+ */
26
88
  export declare function searchConfigurations(engine: Engine, target: number[], opts: SearchConfigOptions): RankedMoment[];