@typescriptify/sweph 1.0.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.
Files changed (211) hide show
  1. package/README.md +422 -0
  2. package/ephe/semo_18.se1 +0 -0
  3. package/ephe/sepl_18.se1 +0 -0
  4. package/originalCode/.eslintrc.json +124 -0
  5. package/originalCode/.gitattributes +2 -0
  6. package/originalCode/.github/FUNDING.yml +5 -0
  7. package/originalCode/.github/workflows/test.yml +35 -0
  8. package/originalCode/LICENSE +840 -0
  9. package/originalCode/README.md +91 -0
  10. package/originalCode/binding.gyp +41 -0
  11. package/originalCode/constants.js +366 -0
  12. package/originalCode/docs.gif +0 -0
  13. package/originalCode/index.d.ts +5115 -0
  14. package/originalCode/index.js +7 -0
  15. package/originalCode/index.mjs +109 -0
  16. package/originalCode/package.json +55 -0
  17. package/originalCode/src/functions/azalt.cpp +39 -0
  18. package/originalCode/src/functions/azalt_rev.cpp +35 -0
  19. package/originalCode/src/functions/calc.cpp +29 -0
  20. package/originalCode/src/functions/calc_pctr.cpp +31 -0
  21. package/originalCode/src/functions/calc_ut.cpp +29 -0
  22. package/originalCode/src/functions/close.cpp +6 -0
  23. package/originalCode/src/functions/cotrans.cpp +26 -0
  24. package/originalCode/src/functions/cotrans_sp.cpp +26 -0
  25. package/originalCode/src/functions/cs2degstr.cpp +19 -0
  26. package/originalCode/src/functions/cs2lonlatstr.cpp +23 -0
  27. package/originalCode/src/functions/cs2timestr.cpp +23 -0
  28. package/originalCode/src/functions/csnorm.cpp +15 -0
  29. package/originalCode/src/functions/csroundsec.cpp +15 -0
  30. package/originalCode/src/functions/d2l.cpp +15 -0
  31. package/originalCode/src/functions/date_conversion.cpp +30 -0
  32. package/originalCode/src/functions/day_of_week.cpp +15 -0
  33. package/originalCode/src/functions/degnorm.cpp +15 -0
  34. package/originalCode/src/functions/deltat.cpp +15 -0
  35. package/originalCode/src/functions/deltat_ex.cpp +24 -0
  36. package/originalCode/src/functions/difcs2n.cpp +19 -0
  37. package/originalCode/src/functions/difcsn.cpp +19 -0
  38. package/originalCode/src/functions/difdeg2n.cpp +19 -0
  39. package/originalCode/src/functions/difdegn.cpp +19 -0
  40. package/originalCode/src/functions/fixstar.cpp +32 -0
  41. package/originalCode/src/functions/fixstar2.cpp +32 -0
  42. package/originalCode/src/functions/fixstar2_mag.cpp +28 -0
  43. package/originalCode/src/functions/fixstar2_ut.cpp +32 -0
  44. package/originalCode/src/functions/fixstar_mag.cpp +28 -0
  45. package/originalCode/src/functions/fixstar_ut.cpp +32 -0
  46. package/originalCode/src/functions/gauquelin_sector.cpp +44 -0
  47. package/originalCode/src/functions/get_ayanamsa.cpp +15 -0
  48. package/originalCode/src/functions/get_ayanamsa_ex.cpp +27 -0
  49. package/originalCode/src/functions/get_ayanamsa_ex_ut.cpp +27 -0
  50. package/originalCode/src/functions/get_ayanamsa_name.cpp +19 -0
  51. package/originalCode/src/functions/get_ayanamsa_ut.cpp +15 -0
  52. package/originalCode/src/functions/get_current_file_data.cpp +28 -0
  53. package/originalCode/src/functions/get_library_path.cpp +8 -0
  54. package/originalCode/src/functions/get_orbital_elements.cpp +29 -0
  55. package/originalCode/src/functions/get_planet_name.cpp +19 -0
  56. package/originalCode/src/functions/get_tid_acc.cpp +7 -0
  57. package/originalCode/src/functions/heliacal_pheno_ut.cpp +52 -0
  58. package/originalCode/src/functions/heliacal_ut.cpp +52 -0
  59. package/originalCode/src/functions/helio_cross.cpp +33 -0
  60. package/originalCode/src/functions/helio_cross_ut.cpp +33 -0
  61. package/originalCode/src/functions/house_name.cpp +20 -0
  62. package/originalCode/src/functions/house_pos.cpp +36 -0
  63. package/originalCode/src/functions/houses.cpp +35 -0
  64. package/originalCode/src/functions/houses_armc.cpp +38 -0
  65. package/originalCode/src/functions/houses_armc_ex2.cpp +47 -0
  66. package/originalCode/src/functions/houses_ex.cpp +37 -0
  67. package/originalCode/src/functions/houses_ex2.cpp +46 -0
  68. package/originalCode/src/functions/jdet_to_utc.cpp +38 -0
  69. package/originalCode/src/functions/jdut1_to_utc.cpp +38 -0
  70. package/originalCode/src/functions/julday.cpp +25 -0
  71. package/originalCode/src/functions/lat_to_lmt.cpp +27 -0
  72. package/originalCode/src/functions/lmt_to_lat.cpp +27 -0
  73. package/originalCode/src/functions/lun_eclipse_how.cpp +34 -0
  74. package/originalCode/src/functions/lun_eclipse_when.cpp +31 -0
  75. package/originalCode/src/functions/lun_eclipse_when_loc.cpp +39 -0
  76. package/originalCode/src/functions/lun_occult_when_glob.cpp +35 -0
  77. package/originalCode/src/functions/lun_occult_when_loc.cpp +43 -0
  78. package/originalCode/src/functions/lun_occult_where.cpp +34 -0
  79. package/originalCode/src/functions/mooncross.cpp +26 -0
  80. package/originalCode/src/functions/mooncross_node.cpp +30 -0
  81. package/originalCode/src/functions/mooncross_node_ut.cpp +30 -0
  82. package/originalCode/src/functions/mooncross_ut.cpp +26 -0
  83. package/originalCode/src/functions/nod_aps.cpp +42 -0
  84. package/originalCode/src/functions/nod_aps_ut.cpp +42 -0
  85. package/originalCode/src/functions/orbit_max_min_true_distance.cpp +37 -0
  86. package/originalCode/src/functions/pheno.cpp +29 -0
  87. package/originalCode/src/functions/pheno_ut.cpp +29 -0
  88. package/originalCode/src/functions/radnorm.cpp +15 -0
  89. package/originalCode/src/functions/refrac.cpp +23 -0
  90. package/originalCode/src/functions/refrac_extended.cpp +32 -0
  91. package/originalCode/src/functions/revjul.cpp +33 -0
  92. package/originalCode/src/functions/rise_trans.cpp +44 -0
  93. package/originalCode/src/functions/rise_trans_true_hor.cpp +46 -0
  94. package/originalCode/src/functions/set_delta_t_userdef.cpp +14 -0
  95. package/originalCode/src/functions/set_ephe_path.cpp +14 -0
  96. package/originalCode/src/functions/set_jpl_file.cpp +14 -0
  97. package/originalCode/src/functions/set_sid_mode.cpp +20 -0
  98. package/originalCode/src/functions/set_tid_acc.cpp +14 -0
  99. package/originalCode/src/functions/set_topo.cpp +20 -0
  100. package/originalCode/src/functions/sidtime.cpp +15 -0
  101. package/originalCode/src/functions/sidtime0.cpp +21 -0
  102. package/originalCode/src/functions/sol_eclipse_how.cpp +34 -0
  103. package/originalCode/src/functions/sol_eclipse_when_glob.cpp +31 -0
  104. package/originalCode/src/functions/sol_eclipse_when_loc.cpp +39 -0
  105. package/originalCode/src/functions/sol_eclipse_where.cpp +30 -0
  106. package/originalCode/src/functions/solcross.cpp +26 -0
  107. package/originalCode/src/functions/solcross_ut.cpp +26 -0
  108. package/originalCode/src/functions/split_deg.cpp +35 -0
  109. package/originalCode/src/functions/time_equ.cpp +25 -0
  110. package/originalCode/src/functions/utc_time_zone.cpp +48 -0
  111. package/originalCode/src/functions/utc_to_jd.cpp +37 -0
  112. package/originalCode/src/functions/version.cpp +8 -0
  113. package/originalCode/src/functions/vis_limit_mag.cpp +50 -0
  114. package/originalCode/src/sweph.cpp +150 -0
  115. package/originalCode/src/sweph.h +119 -0
  116. package/originalCode/swisseph/swecl.c +6428 -0
  117. package/originalCode/swisseph/swedate.c +588 -0
  118. package/originalCode/swisseph/swedate.h +81 -0
  119. package/originalCode/swisseph/swehel.c +3511 -0
  120. package/originalCode/swisseph/swehouse.c +3143 -0
  121. package/originalCode/swisseph/swehouse.h +98 -0
  122. package/originalCode/swisseph/swejpl.c +958 -0
  123. package/originalCode/swisseph/swejpl.h +103 -0
  124. package/originalCode/swisseph/swemmoon.c +1930 -0
  125. package/originalCode/swisseph/swemplan.c +967 -0
  126. package/originalCode/swisseph/swemptab.h +10640 -0
  127. package/originalCode/swisseph/swenut2000a.h +2819 -0
  128. package/originalCode/swisseph/sweodef.h +326 -0
  129. package/originalCode/swisseph/sweph.c +8614 -0
  130. package/originalCode/swisseph/sweph.h +849 -0
  131. package/originalCode/swisseph/swephexp.h +1020 -0
  132. package/originalCode/swisseph/swephlib.c +4634 -0
  133. package/originalCode/swisseph/swephlib.h +189 -0
  134. package/package.json +28 -0
  135. package/scripts/gen-swemptab.js +177 -0
  136. package/scripts/gen-swenut2000a.js +106 -0
  137. package/src/SwissEph/README.md +268 -0
  138. package/src/SwissEph/UseCases/Ayanamsa.md +363 -0
  139. package/src/SwissEph/UseCases/AzimuthAltitude.md +408 -0
  140. package/src/SwissEph/UseCases/CoordinateSystems.md +337 -0
  141. package/src/SwissEph/UseCases/DateAndTime.md +368 -0
  142. package/src/SwissEph/UseCases/DeltaT.md +258 -0
  143. package/src/SwissEph/UseCases/EphemerisFiles.md +338 -0
  144. package/src/SwissEph/UseCases/FixedStars.md +300 -0
  145. package/src/SwissEph/UseCases/GauquelinSectors.md +304 -0
  146. package/src/SwissEph/UseCases/HeliacalEvents.md +396 -0
  147. package/src/SwissEph/UseCases/HelioCrossings.md +325 -0
  148. package/src/SwissEph/UseCases/HousePosition.md +254 -0
  149. package/src/SwissEph/UseCases/HouseSystems.md +279 -0
  150. package/src/SwissEph/UseCases/LunarEclipse.md +326 -0
  151. package/src/SwissEph/UseCases/MeridianTransit.md +279 -0
  152. package/src/SwissEph/UseCases/MoonCrossings.md +373 -0
  153. package/src/SwissEph/UseCases/NodesAndApsides.md +307 -0
  154. package/src/SwissEph/UseCases/Occultation.md +352 -0
  155. package/src/SwissEph/UseCases/OrbitalElements.md +469 -0
  156. package/src/SwissEph/UseCases/Phenomena.md +328 -0
  157. package/src/SwissEph/UseCases/PlanetPositions.md +366 -0
  158. package/src/SwissEph/UseCases/Planetocentric.md +278 -0
  159. package/src/SwissEph/UseCases/Refraction.md +314 -0
  160. package/src/SwissEph/UseCases/RiseAndSet.md +433 -0
  161. package/src/SwissEph/UseCases/SiderealTime.md +302 -0
  162. package/src/SwissEph/UseCases/SolarEclipse.md +379 -0
  163. package/src/SwissEph/UseCases/SunCrossings.md +275 -0
  164. package/src/SwissEph/UseCases/TopocentricCorrection.md +335 -0
  165. package/src/SwissEph/errors.ts +10 -0
  166. package/src/SwissEph/index.ts +823 -0
  167. package/src/SwissEph/types.ts +291 -0
  168. package/src/constants.ts +762 -0
  169. package/src/file-reader.ts +147 -0
  170. package/src/index.ts +10 -0
  171. package/src/swecl.ts +4526 -0
  172. package/src/swedate.ts +376 -0
  173. package/src/swehel.ts +1939 -0
  174. package/src/swehouse.ts +2167 -0
  175. package/src/swejpl.ts +470 -0
  176. package/src/swemmoon.ts +1318 -0
  177. package/src/swemplan.ts +585 -0
  178. package/src/swemptab.ts +4448 -0
  179. package/src/swenut2000a.ts +2763 -0
  180. package/src/sweph.ts +3993 -0
  181. package/src/swephlib.ts +2720 -0
  182. package/src/types.ts +490 -0
  183. package/tests/c-style/ayanamsa.test.ts +63 -0
  184. package/tests/c-style/config.test.ts +96 -0
  185. package/tests/c-style/crossings.test.ts +81 -0
  186. package/tests/c-style/date-time.test.ts +114 -0
  187. package/tests/c-style/eclipses.test.ts +84 -0
  188. package/tests/c-style/fixed-stars.test.ts +66 -0
  189. package/tests/c-style/heliacal.test.ts +34 -0
  190. package/tests/c-style/houses.test.ts +135 -0
  191. package/tests/c-style/math-utils.test.ts +160 -0
  192. package/tests/c-style/orbital.test.ts +78 -0
  193. package/tests/c-style/phenomena.test.ts +42 -0
  194. package/tests/c-style/planetocentric.test.ts +26 -0
  195. package/tests/c-style/planets.test.ts +117 -0
  196. package/tests/c-style/rise-set.test.ts +71 -0
  197. package/tests/helpers.ts +21 -0
  198. package/tests/modern/ayanamsa.test.ts +47 -0
  199. package/tests/modern/calc.test.ts +113 -0
  200. package/tests/modern/config.test.ts +46 -0
  201. package/tests/modern/crossings.test.ts +45 -0
  202. package/tests/modern/eclipses.test.ts +81 -0
  203. package/tests/modern/errors.test.ts +71 -0
  204. package/tests/modern/heliacal.test.ts +30 -0
  205. package/tests/modern/houses.test.ts +87 -0
  206. package/tests/modern/orbital.test.ts +79 -0
  207. package/tests/modern/phenomena.test.ts +41 -0
  208. package/tests/modern/rise-set.test.ts +60 -0
  209. package/tests/modern/statics.test.ts +99 -0
  210. package/tests/modern/utilities.test.ts +70 -0
  211. package/tsconfig.json +20 -0
@@ -0,0 +1,328 @@
1
+ # Planetary Phenomena
2
+
3
+ Planetary phenomena are the observable characteristics of a planet as seen from Earth at a given moment. When you look at a planet in the night sky, you might wonder: How bright is it? How far from the Sun does it appear? How much of its surface is illuminated? The `phenomena()` method answers all these questions at once, returning five key measurements:
4
+
5
+ - **Phase angle**: the angle Sun-Planet-Earth, which determines how much of the planet's illuminated side faces us
6
+ - **Phase (illuminated fraction)**: a number from 0.0 to 1.0 representing what proportion of the visible disk is lit
7
+ - **Elongation**: the angular separation between the planet and the Sun as seen from Earth
8
+ - **Apparent diameter**: how large the planet appears, measured in arcseconds
9
+ - **Apparent magnitude**: how bright the planet appears on the astronomical magnitude scale
10
+
11
+ These quantities are useful for observation planning (can I see this planet tonight?), astrophotography, and understanding the geometric relationship between the Sun, a planet, and the Earth.
12
+
13
+ ---
14
+
15
+ ## Quick Example
16
+
17
+ ```typescript
18
+ import { SwissEph } from '../index';
19
+ import { SE_VENUS } from '../../constants';
20
+
21
+ const swe = new SwissEph();
22
+ const jd = SwissEph.julianDay(2025, 3, 15, 20); // 2025 Mar 15, 20:00 UT
23
+
24
+ const p = swe.phenomena(jd, SE_VENUS);
25
+
26
+ console.log(`Phase angle: ${p.phaseAngle.toFixed(2)} deg`);
27
+ console.log(`Phase (illuminated): ${(p.phase * 100).toFixed(1)}%`);
28
+ console.log(`Elongation from Sun: ${p.elongation.toFixed(2)} deg`);
29
+ console.log(`Apparent diameter: ${p.apparentDiameter.toFixed(2)} arcsec`);
30
+ console.log(`Apparent magnitude: ${p.apparentMagnitude.toFixed(2)}`);
31
+
32
+ swe.close();
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Detailed Examples
38
+
39
+ ### Phenomena for all visible planets
40
+
41
+ ```typescript
42
+ import { SwissEph } from '../index';
43
+ import {
44
+ SE_MERCURY, SE_VENUS, SE_MARS,
45
+ SE_JUPITER, SE_SATURN,
46
+ } from '../../constants';
47
+
48
+ const swe = new SwissEph();
49
+ const jd = SwissEph.julianDay(2025, 6, 1, 0);
50
+
51
+ const planets = [
52
+ { id: SE_MERCURY, name: 'Mercury' },
53
+ { id: SE_VENUS, name: 'Venus' },
54
+ { id: SE_MARS, name: 'Mars' },
55
+ { id: SE_JUPITER, name: 'Jupiter' },
56
+ { id: SE_SATURN, name: 'Saturn' },
57
+ ];
58
+
59
+ console.log('Planet Elong Phase% Mag Diam"');
60
+ console.log('---------- ------ ------ ----- -----');
61
+
62
+ for (const pl of planets) {
63
+ const p = swe.phenomena(jd, pl.id);
64
+ console.log(
65
+ `${pl.name.padEnd(10)} ` +
66
+ `${p.elongation.toFixed(1).padStart(5)}° ` +
67
+ `${(p.phase * 100).toFixed(1).padStart(5)}% ` +
68
+ `${p.apparentMagnitude.toFixed(1).padStart(5)} ` +
69
+ `${p.apparentDiameter.toFixed(2).padStart(5)}`
70
+ );
71
+ }
72
+
73
+ swe.close();
74
+ ```
75
+
76
+ ### Checking if a planet is visible
77
+
78
+ A planet is generally visible to the naked eye when:
79
+ 1. Its elongation from the Sun is greater than about 15 degrees (so the sky is dark enough where it appears)
80
+ 2. Its apparent magnitude is less than about 6.0 (the naked-eye limit)
81
+
82
+ ```typescript
83
+ import { SwissEph } from '../index';
84
+ import {
85
+ SE_MERCURY, SE_VENUS, SE_MARS,
86
+ SE_JUPITER, SE_SATURN,
87
+ } from '../../constants';
88
+
89
+ const swe = new SwissEph();
90
+ const jd = SwissEph.julianDay(2025, 4, 10, 20);
91
+
92
+ const planets = [
93
+ { id: SE_MERCURY, name: 'Mercury' },
94
+ { id: SE_VENUS, name: 'Venus' },
95
+ { id: SE_MARS, name: 'Mars' },
96
+ { id: SE_JUPITER, name: 'Jupiter' },
97
+ { id: SE_SATURN, name: 'Saturn' },
98
+ ];
99
+
100
+ for (const pl of planets) {
101
+ const p = swe.phenomena(jd, pl.id);
102
+
103
+ const farEnoughFromSun = p.elongation > 15;
104
+ const brightEnough = p.apparentMagnitude < 6.0;
105
+ const visible = farEnoughFromSun && brightEnough;
106
+
107
+ console.log(
108
+ `${pl.name.padEnd(10)} elong=${p.elongation.toFixed(1).padStart(5)}° ` +
109
+ `mag=${p.apparentMagnitude.toFixed(1).padStart(5)} ` +
110
+ `→ ${visible ? 'VISIBLE' : 'not visible'}`
111
+ );
112
+ }
113
+
114
+ swe.close();
115
+ ```
116
+
117
+ Note: This is a simplified check. True visibility also depends on whether the planet is above the horizon at your location and the time of night. For a complete analysis, combine with `swe.riseSet()` and `swe.azalt()`.
118
+
119
+ ### Tracking Venus phases over a synodic cycle
120
+
121
+ Venus goes through phases like the Moon. As an inferior planet (orbiting closer to the Sun than Earth), Venus shows a full range of phases depending on its position relative to the Sun and Earth.
122
+
123
+ ```typescript
124
+ import { SwissEph } from '../index';
125
+ import { SE_VENUS } from '../../constants';
126
+
127
+ const swe = new SwissEph();
128
+
129
+ // Track Venus phenomena monthly over ~19 months (Venus synodic period ≈ 584 days)
130
+ const startJd = SwissEph.julianDay(2025, 1, 1, 0);
131
+
132
+ console.log('Date Phase% Elong PhaseAngle Mag Diam"');
133
+
134
+ for (let month = 0; month < 20; month++) {
135
+ const jd = startJd + month * 30.44; // ~1 month intervals
136
+ const p = swe.phenomena(jd, SE_VENUS);
137
+ const d = SwissEph.fromJulianDay(jd);
138
+
139
+ console.log(
140
+ `${d.year}-${String(d.month).padStart(2,'0')}-${String(Math.floor(d.day)).padStart(2,'0')} ` +
141
+ `${(p.phase * 100).toFixed(1).padStart(5)}% ` +
142
+ `${p.elongation.toFixed(1).padStart(5)}° ` +
143
+ `${p.phaseAngle.toFixed(1).padStart(9)}° ` +
144
+ `${p.apparentMagnitude.toFixed(1).padStart(5)} ` +
145
+ `${p.apparentDiameter.toFixed(1).padStart(5)}`
146
+ );
147
+ }
148
+
149
+ swe.close();
150
+ ```
151
+
152
+ When Venus is on the far side of the Sun (superior conjunction), it appears nearly full but small and faint. When it is closest to Earth (inferior conjunction), it appears as a thin crescent but very large and actually at its brightest just before/after, when the combination of size and illumination peaks.
153
+
154
+ ### Moon phase as illuminated fraction
155
+
156
+ The `phenomena()` method works for the Moon too, giving you the illuminated fraction directly.
157
+
158
+ ```typescript
159
+ import { SwissEph } from '../index';
160
+ import { SE_MOON } from '../../constants';
161
+
162
+ const swe = new SwissEph();
163
+
164
+ // Check Moon phase nightly for a month
165
+ const startJd = SwissEph.julianDay(2025, 3, 1, 0);
166
+
167
+ for (let day = 0; day < 30; day++) {
168
+ const jd = startJd + day;
169
+ const p = swe.phenomena(jd, SE_MOON);
170
+ const d = SwissEph.fromJulianDay(jd);
171
+
172
+ // Simple phase name based on illuminated fraction and phase angle
173
+ const pct = p.phase * 100;
174
+ let phaseName: string;
175
+ if (pct < 2) phaseName = 'New Moon';
176
+ else if (pct < 40) phaseName = p.elongation < 180 ? 'Waxing Crescent' : 'Waning Crescent';
177
+ else if (pct < 60) phaseName = p.elongation < 180 ? 'First Quarter' : 'Last Quarter';
178
+ else if (pct < 98) phaseName = p.elongation < 180 ? 'Waxing Gibbous' : 'Waning Gibbous';
179
+ else phaseName = 'Full Moon';
180
+
181
+ const bar = '#'.repeat(Math.round(pct / 5)).padEnd(20);
182
+ console.log(
183
+ `Mar ${String(day + 1).padStart(2)} ${pct.toFixed(1).padStart(5)}% [${bar}] ${phaseName}`
184
+ );
185
+ }
186
+
187
+ swe.close();
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Deep Explanation
193
+
194
+ ### Phase Angle
195
+
196
+ The phase angle is the angle formed at the planet between the directions to the Sun and to the Earth. Imagine standing on the planet's surface: the phase angle is the angle between the Sun and Earth in your sky.
197
+
198
+ ```
199
+ Sun
200
+ /
201
+ / phase angle
202
+ Planet ---------- Earth
203
+ ```
204
+
205
+ - **0 degrees**: The Sun is directly behind Earth (from the planet's perspective). This is **opposition** for superior planets -- the planet's fully lit face points toward Earth. For the Moon, this is a Full Moon.
206
+ - **90 degrees**: Half the visible disk is illuminated (like a quarter Moon, or Mercury/Venus at greatest elongation).
207
+ - **180 degrees**: The planet is between Earth and the Sun (**conjunction**). The lit side faces away from Earth. For the Moon, this is a New Moon.
208
+
209
+ ### Phase (Illuminated Fraction)
210
+
211
+ The phase is a value from 0.0 to 1.0 representing the fraction of the planet's visible disk that is illuminated by the Sun. It is related to the phase angle by:
212
+
213
+ ```
214
+ phase = (1 + cos(phaseAngle)) / 2
215
+ ```
216
+
217
+ - 1.0 = fully illuminated (opposition/full)
218
+ - 0.5 = half illuminated (quarter)
219
+ - 0.0 = unilluminated (conjunction/new)
220
+
221
+ For the Moon, this is the familiar "percent illumination" often shown in weather apps and calendars.
222
+
223
+ ### Elongation
224
+
225
+ Elongation is the angular distance between the planet and the Sun as seen from Earth. It determines whether and when you can observe the planet:
226
+
227
+ - **0 degrees**: conjunction -- the planet is in the same direction as the Sun and invisible in the glare
228
+ - **~15 degrees**: the minimum elongation for a planet to be glimpsed in twilight
229
+ - **90 degrees**: quadrature -- the planet is a quarter of the sky away from the Sun
230
+ - **180 degrees**: opposition -- the planet is opposite the Sun, rising at sunset and visible all night
231
+
232
+ For **inferior planets** (Mercury and Venus, which orbit closer to the Sun than Earth), elongation has a maximum value:
233
+ - Mercury: ~18-28 degrees (varies due to orbital eccentricity)
234
+ - Venus: ~45-47 degrees
235
+
236
+ This is why Mercury and Venus are always seen near the Sun, as "morning stars" or "evening stars." They can never appear at opposition.
237
+
238
+ For **superior planets** (Mars through Pluto), elongation can range from 0 to 180 degrees.
239
+
240
+ ### Apparent Diameter
241
+
242
+ The apparent diameter is how large the planet appears in the sky, measured in **arcseconds** (1/3600 of a degree). For reference:
243
+ - The Sun and Moon are each about 1800 arcseconds (30 arcminutes, or half a degree)
244
+ - Jupiter at opposition: ~45 arcseconds
245
+ - Saturn (disk only): ~18 arcseconds
246
+ - Mars at opposition: ~14-25 arcseconds (varies greatly)
247
+ - Venus at closest approach: ~60 arcseconds (larger than Jupiter!)
248
+
249
+ The apparent diameter changes as the planet's distance from Earth changes. It is inversely proportional to distance.
250
+
251
+ ### Apparent Magnitude
252
+
253
+ The **magnitude scale** is the astronomer's measure of brightness. It was invented by the ancient Greek astronomer **Hipparchus** (~150 BC), who classified stars into six groups: the brightest stars were "first magnitude" and the faintest visible stars were "sixth magnitude."
254
+
255
+ The modern scale is logarithmic and extends in both directions:
256
+ - **Lower numbers = brighter**. Negative magnitudes are very bright.
257
+ - Each step of 1 magnitude corresponds to a brightness factor of about 2.512
258
+ - A difference of 5 magnitudes = exactly 100x brightness difference
259
+
260
+ Typical planet magnitudes:
261
+ | Object | Typical Magnitude |
262
+ |--------|------------------|
263
+ | Sun | -26.7 |
264
+ | Full Moon | -12.7 |
265
+ | Venus (brightest) | -4.6 |
266
+ | Jupiter (opposition) | -2.5 |
267
+ | Mars (opposition) | -2.0 to -2.9 |
268
+ | Saturn | +0.5 to +1.5 |
269
+ | Mercury | -0.5 to +3 |
270
+ | Uranus | +5.7 |
271
+ | Neptune | +7.8 (invisible to naked eye) |
272
+ | Naked eye limit | ~+6.0 |
273
+
274
+ ### Geometry of Opposition and Conjunction
275
+
276
+ For a **superior planet** (orbiting farther from the Sun than Earth):
277
+
278
+ ```
279
+ Sun
280
+ |
281
+ Earth-+--------Planet ← Opposition (phase angle ≈ 0°, elongation = 180°)
282
+ ```
283
+
284
+ At opposition, the planet is closest to Earth, appears brightest, shows its full disk, and is visible all night. This is the best time to observe it.
285
+
286
+ ```
287
+ Sun
288
+ |
289
+ Planet-+-Earth ← Conjunction (phase angle ≈ 180°, elongation ≈ 0°)
290
+ ```
291
+
292
+ At conjunction, the planet is behind the Sun and invisible.
293
+
294
+ For an **inferior planet** (Mercury or Venus):
295
+
296
+ ```
297
+ Sun
298
+ |
299
+ Earth-+ Venus ← Greatest Eastern Elongation (evening star)
300
+ seen after sunset in the west
301
+ ```
302
+
303
+ ```
304
+ Sun
305
+ |
306
+ Venus +-Earth ← Greatest Western Elongation (morning star)
307
+ seen before sunrise in the east
308
+ ```
309
+
310
+ ### Return Type
311
+
312
+ ```typescript
313
+ interface PhenoResult {
314
+ phaseAngle: number; // degrees, 0-180
315
+ phase: number; // illuminated fraction, 0.0-1.0
316
+ elongation: number; // degrees from Sun, 0-180
317
+ apparentDiameter: number; // arcseconds
318
+ apparentMagnitude: number; // magnitude (lower = brighter)
319
+ }
320
+ ```
321
+
322
+ ### Applicable Bodies
323
+
324
+ The `phenomena()` method works for all planets (Mercury through Pluto), the Moon, asteroids, and fixed stars. For the Sun itself, most values are not meaningful (the Sun's elongation from itself is always 0).
325
+
326
+ ### Flags
327
+
328
+ The optional `flags` parameter controls the calculation method. Normally you can omit it and accept the defaults. Possible flags include sidereal mode flags, but for phenomena calculations the default tropical geocentric computation is standard.
@@ -0,0 +1,366 @@
1
+ # Planet Positions
2
+
3
+ Calculating the position of a planet is the most fundamental operation in astrology and astronomical computing. Given a moment in time (expressed as a Julian Day number), the Swiss Ephemeris computes where each planet appears in the sky. The result includes the planet's **longitude** (its position along the ecliptic, 0-360 degrees), **latitude** (how far above or below the ecliptic plane), and **distance** (how far away it is, in AU). You also get the **speed** of each value -- how fast the planet is moving per day.
4
+
5
+ This is the building block for natal charts, transits, progressions, synastry, and virtually every astrological technique.
6
+
7
+ ---
8
+
9
+ ## Quick Example
10
+
11
+ ```typescript
12
+ import { SwissEph } from '../index';
13
+ import { SE_SUN, SE_MOON, SE_MARS } from '../../constants';
14
+
15
+ const swe = new SwissEph();
16
+
17
+ // J2000.0 epoch (January 1, 2000 at 12:00 UT)
18
+ const jd = SwissEph.julianDay(2000, 1, 1, 12);
19
+
20
+ const sun = swe.calc(jd, SE_SUN);
21
+ console.log(`Sun longitude: ${sun.longitude.toFixed(4)}deg`);
22
+ // Sun longitude: 280.3706deg
23
+
24
+ const moon = swe.calc(jd, SE_MOON);
25
+ console.log(`Moon longitude: ${moon.longitude.toFixed(4)}deg`);
26
+
27
+ const mars = swe.calc(jd, SE_MARS);
28
+ console.log(`Mars longitude: ${mars.longitude.toFixed(4)}deg`);
29
+ console.log(`Mars speed: ${mars.longitudeSpeed.toFixed(4)} deg/day`);
30
+
31
+ swe.close();
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Detailed Examples
37
+
38
+ ### All classical planets at a given date
39
+
40
+ ```typescript
41
+ import { SwissEph } from '../index';
42
+ import {
43
+ SE_SUN, SE_MOON, SE_MERCURY, SE_VENUS, SE_MARS,
44
+ SE_JUPITER, SE_SATURN, SE_URANUS, SE_NEPTUNE, SE_PLUTO,
45
+ } from '../../constants';
46
+
47
+ const swe = new SwissEph();
48
+ const jd = SwissEph.julianDay(2024, 4, 8, 18.28); // 2024 Apr 8, ~18:17 UT
49
+
50
+ const planets = [
51
+ { id: SE_SUN, name: 'Sun' },
52
+ { id: SE_MOON, name: 'Moon' },
53
+ { id: SE_MERCURY, name: 'Mercury' },
54
+ { id: SE_VENUS, name: 'Venus' },
55
+ { id: SE_MARS, name: 'Mars' },
56
+ { id: SE_JUPITER, name: 'Jupiter' },
57
+ { id: SE_SATURN, name: 'Saturn' },
58
+ { id: SE_URANUS, name: 'Uranus' },
59
+ { id: SE_NEPTUNE, name: 'Neptune' },
60
+ { id: SE_PLUTO, name: 'Pluto' },
61
+ ];
62
+
63
+ for (const p of planets) {
64
+ const pos = swe.calc(jd, p.id);
65
+
66
+ // Convert longitude to zodiac sign
67
+ const signs = ['Ari','Tau','Gem','Can','Leo','Vir','Lib','Sco','Sag','Cap','Aqu','Pis'];
68
+ const signIndex = Math.floor(pos.longitude / 30);
69
+ const degInSign = pos.longitude - signIndex * 30;
70
+
71
+ console.log(
72
+ `${p.name.padEnd(9)} ${degInSign.toFixed(2).padStart(6)}deg ${signs[signIndex]}` +
73
+ ` speed: ${pos.longitudeSpeed.toFixed(4)} deg/day`
74
+ );
75
+ }
76
+
77
+ swe.close();
78
+ ```
79
+
80
+ ### Equatorial coordinates (Right Ascension and Declination)
81
+
82
+ Astronomers typically use equatorial coordinates rather than ecliptic. Pass `SEFLG_EQUATORIAL` to get Right Ascension (in degrees, 0-360) and Declination (in degrees, -90 to +90) instead of ecliptic longitude and latitude.
83
+
84
+ ```typescript
85
+ import { SwissEph } from '../index';
86
+ import { SE_SUN, SEFLG_EQUATORIAL } from '../../constants';
87
+
88
+ const swe = new SwissEph();
89
+ const jd = SwissEph.julianDay(2024, 6, 21, 12);
90
+
91
+ const sun = swe.calc(jd, SE_SUN, SEFLG_EQUATORIAL);
92
+
93
+ // When SEFLG_EQUATORIAL is set:
94
+ // longitude -> Right Ascension (degrees, 0-360)
95
+ // latitude -> Declination (degrees, -90 to +90)
96
+ // distance -> distance in AU (same as ecliptic)
97
+ console.log(`Sun RA: ${sun.longitude.toFixed(4)} deg`);
98
+ console.log(`Sun Dec: ${sun.latitude.toFixed(4)} deg`);
99
+
100
+ // Convert RA from degrees to hours/minutes/seconds
101
+ const raHours = sun.longitude / 15;
102
+ const h = Math.floor(raHours);
103
+ const m = Math.floor((raHours - h) * 60);
104
+ const s = ((raHours - h) * 60 - m) * 60;
105
+ console.log(`Sun RA: ${h}h ${m}m ${s.toFixed(1)}s`);
106
+
107
+ swe.close();
108
+ ```
109
+
110
+ ### Heliocentric positions
111
+
112
+ View planets from the Sun's perspective instead of from Earth. Useful for heliocentric astrology and astronomical research.
113
+
114
+ ```typescript
115
+ import { SwissEph } from '../index';
116
+ import { SE_MARS, SE_EARTH, SEFLG_HELCTR } from '../../constants';
117
+
118
+ const swe = new SwissEph();
119
+ const jd = SwissEph.julianDay(2024, 1, 1, 12);
120
+
121
+ // Heliocentric Mars (as seen from the Sun)
122
+ const mars = swe.calc(jd, SE_MARS, SEFLG_HELCTR);
123
+ console.log(`Mars heliocentric longitude: ${mars.longitude.toFixed(4)} deg`);
124
+ console.log(`Mars distance from Sun: ${mars.distance.toFixed(6)} AU`);
125
+
126
+ // Heliocentric Earth
127
+ const earth = swe.calc(jd, SE_EARTH, SEFLG_HELCTR);
128
+ console.log(`Earth heliocentric longitude: ${earth.longitude.toFixed(4)} deg`);
129
+
130
+ swe.close();
131
+ ```
132
+
133
+ ### Lunar nodes and Lilith
134
+
135
+ ```typescript
136
+ import { SwissEph } from '../index';
137
+ import { SE_MEAN_NODE, SE_TRUE_NODE, SE_MEAN_APOG, SE_OSCU_APOG } from '../../constants';
138
+
139
+ const swe = new SwissEph();
140
+ const jd = SwissEph.julianDay(2024, 1, 1, 12);
141
+
142
+ const meanNode = swe.calc(jd, SE_MEAN_NODE);
143
+ const trueNode = swe.calc(jd, SE_TRUE_NODE);
144
+ console.log(`Mean North Node: ${meanNode.longitude.toFixed(4)} deg`);
145
+ console.log(`True North Node: ${trueNode.longitude.toFixed(4)} deg`);
146
+ // The South Node is always 180 degrees opposite the North Node.
147
+
148
+ const meanLilith = swe.calc(jd, SE_MEAN_APOG);
149
+ const oscuLilith = swe.calc(jd, SE_OSCU_APOG);
150
+ console.log(`Mean Lilith (Black Moon): ${meanLilith.longitude.toFixed(4)} deg`);
151
+ console.log(`Osculating Lilith: ${oscuLilith.longitude.toFixed(4)} deg`);
152
+
153
+ swe.close();
154
+ ```
155
+
156
+ ### Chiron and the main asteroids
157
+
158
+ ```typescript
159
+ import { SwissEph } from '../index';
160
+ import { SE_CHIRON, SE_CERES, SE_PALLAS, SE_JUNO, SE_VESTA } from '../../constants';
161
+
162
+ const swe = new SwissEph();
163
+ const jd = SwissEph.julianDay(2024, 1, 1, 12);
164
+
165
+ const bodies = [
166
+ { id: SE_CHIRON, name: 'Chiron' },
167
+ { id: SE_CERES, name: 'Ceres' },
168
+ { id: SE_PALLAS, name: 'Pallas' },
169
+ { id: SE_JUNO, name: 'Juno' },
170
+ { id: SE_VESTA, name: 'Vesta' },
171
+ ];
172
+
173
+ for (const b of bodies) {
174
+ const pos = swe.calc(jd, b.id);
175
+ console.log(`${b.name.padEnd(8)} ${pos.longitude.toFixed(4)} deg`);
176
+ }
177
+
178
+ swe.close();
179
+ ```
180
+
181
+ ### Detecting retrograde motion
182
+
183
+ A planet is retrograde when its longitudinal speed is negative.
184
+
185
+ ```typescript
186
+ import { SwissEph } from '../index';
187
+ import { SE_MERCURY } from '../../constants';
188
+
189
+ const swe = new SwissEph();
190
+
191
+ // Check Mercury's direction over several months
192
+ for (let month = 1; month <= 12; month++) {
193
+ const jd = SwissEph.julianDay(2024, month, 15, 12);
194
+ const pos = swe.calc(jd, SE_MERCURY);
195
+ const direction = pos.longitudeSpeed < 0 ? 'RETROGRADE' : 'direct';
196
+ console.log(`2024-${String(month).padStart(2,'0')}-15 Mercury speed: ${pos.longitudeSpeed.toFixed(4)} deg/day ${direction}`);
197
+ }
198
+
199
+ swe.close();
200
+ ```
201
+
202
+ ### Topocentric positions (observer on Earth's surface)
203
+
204
+ Geocentric positions are calculated from Earth's center. For the Moon especially, the difference from a specific location on Earth's surface (topocentric) can be up to about 1 degree.
205
+
206
+ ```typescript
207
+ import { SwissEph } from '../index';
208
+ import { SE_MOON, SEFLG_TOPOCTR } from '../../constants';
209
+
210
+ // Set up the observer's location in the constructor
211
+ const swe = new SwissEph({
212
+ topo: { longitude: -73.9857, latitude: 40.7484, altitude: 10 }, // New York
213
+ });
214
+
215
+ const jd = SwissEph.julianDay(2024, 1, 1, 12);
216
+
217
+ // Topocentric Moon
218
+ const moonTopo = swe.calc(jd, SE_MOON, SEFLG_TOPOCTR);
219
+ console.log(`Moon (topocentric): ${moonTopo.longitude.toFixed(4)} deg`);
220
+
221
+ // Compare with geocentric (no SEFLG_TOPOCTR)
222
+ const swe2 = new SwissEph();
223
+ const moonGeo = swe2.calc(jd, SE_MOON);
224
+ console.log(`Moon (geocentric): ${moonGeo.longitude.toFixed(4)} deg`);
225
+ console.log(`Difference: ${(moonTopo.longitude - moonGeo.longitude).toFixed(4)} deg`);
226
+
227
+ swe.close();
228
+ swe2.close();
229
+ ```
230
+
231
+ ### Sidereal positions
232
+
233
+ ```typescript
234
+ import { SwissEph } from '../index';
235
+ import { SE_SUN, SE_SIDM_LAHIRI, SEFLG_SIDEREAL } from '../../constants';
236
+
237
+ const swe = new SwissEph({ siderealMode: SE_SIDM_LAHIRI });
238
+ const jd = SwissEph.julianDay(2024, 1, 15, 12);
239
+
240
+ // IMPORTANT: you must pass SEFLG_SIDEREAL in the flags to calc()
241
+ // Setting siderealMode in the constructor only configures which ayanamsa to use;
242
+ // it does NOT automatically add SEFLG_SIDEREAL to calc() calls.
243
+ const sun = swe.calc(jd, SE_SUN, SEFLG_SIDEREAL);
244
+ console.log(`Sun sidereal longitude (Lahiri): ${sun.longitude.toFixed(4)} deg`);
245
+
246
+ swe.close();
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Deep Explanation
252
+
253
+ ### What the return values mean
254
+
255
+ | Field | Description |
256
+ |-------------------|-----------------------------------------------------------------------------------------------|
257
+ | `longitude` | Position along the ecliptic (or RA if `SEFLG_EQUATORIAL`), in degrees 0-360 |
258
+ | `latitude` | Angular distance above/below the ecliptic (or Declination if `SEFLG_EQUATORIAL`), in degrees |
259
+ | `distance` | Distance in AU (astronomical units; 1 AU = ~149.6 million km). For the Moon, also in AU. |
260
+ | `longitudeSpeed` | Daily motion in longitude (degrees per day). Negative = retrograde. |
261
+ | `latitudeSpeed` | Daily motion in latitude (degrees per day). |
262
+ | `distanceSpeed` | Daily change in distance (AU per day). Negative = approaching. |
263
+ | `flags` | Flags actually used by the engine (may differ from your input if the engine fell back). |
264
+
265
+ ### Available planets and bodies
266
+
267
+ | Constant | Value | Description |
268
+ |------------------|-------|---------------------------------------------------------------------|
269
+ | `SE_SUN` | 0 | The Sun |
270
+ | `SE_MOON` | 1 | The Moon |
271
+ | `SE_MERCURY` | 2 | Mercury |
272
+ | `SE_VENUS` | 3 | Venus |
273
+ | `SE_MARS` | 4 | Mars |
274
+ | `SE_JUPITER` | 5 | Jupiter |
275
+ | `SE_SATURN` | 6 | Saturn |
276
+ | `SE_URANUS` | 7 | Uranus |
277
+ | `SE_NEPTUNE` | 8 | Neptune |
278
+ | `SE_PLUTO` | 9 | Pluto |
279
+ | `SE_MEAN_NODE` | 10 | Mean Lunar Node (North Node / Rahu). Moves smoothly. |
280
+ | `SE_TRUE_NODE` | 11 | True (osculating) Lunar Node. Wobbles with lunar perturbations. |
281
+ | `SE_MEAN_APOG` | 12 | Mean Lunar Apogee (Black Moon Lilith). Smooth mean motion. |
282
+ | `SE_OSCU_APOG` | 13 | Osculating Lunar Apogee. True instantaneous value, wobbles. |
283
+ | `SE_EARTH` | 14 | Earth (only meaningful for heliocentric/barycentric calculations). |
284
+ | `SE_CHIRON` | 15 | Chiron (minor planet / centaur orbiting between Saturn and Uranus). |
285
+ | `SE_CERES` | 17 | Ceres (dwarf planet, largest body in the asteroid belt). |
286
+ | `SE_PALLAS` | 18 | Pallas (second-largest asteroid). |
287
+ | `SE_JUNO` | 19 | Juno (asteroid). |
288
+ | `SE_VESTA` | 20 | Vesta (second-most-massive asteroid). |
289
+
290
+ **Note on the South Node**: The Swiss Ephemeris only calculates the North Node. The South Node is always exactly 180 degrees opposite: `southNode = (northNode + 180) % 360`.
291
+
292
+ **Note on SE_EARTH**: Requesting SE_EARTH in normal geocentric mode is meaningless (you would be asking for Earth's position as seen from Earth). Use it with `SEFLG_HELCTR` (heliocentric) or `SEFLG_BARYCTR` (barycentric).
293
+
294
+ ### Flag constants
295
+
296
+ Flags modify the calculation. They are combined with the bitwise OR operator (`|`). The wrapper automatically adds `SEFLG_SPEED` so you always get speed values.
297
+
298
+ | Constant | Value | Effect |
299
+ |--------------------|--------|----------------------------------------------------------------------------|
300
+ | `SEFLG_SPEED` | 256 | Compute speed (added automatically by wrapper). |
301
+ | `SEFLG_EQUATORIAL` | 2048 | Return Right Ascension / Declination instead of ecliptic longitude/lat. |
302
+ | `SEFLG_XYZ` | 4096 | Return Cartesian (X, Y, Z) instead of polar (lon, lat, dist). |
303
+ | `SEFLG_RADIANS` | 8192 | Return angles in radians instead of degrees. |
304
+ | `SEFLG_HELCTR` | 8 | Heliocentric position (as seen from the Sun). |
305
+ | `SEFLG_BARYCTR` | 16384 | Barycentric position (relative to solar system barycenter). |
306
+ | `SEFLG_TOPOCTR` | 32768 | Topocentric (from observer's location). Requires `topo` to be set. |
307
+ | `SEFLG_SIDEREAL` | 65536 | Sidereal zodiac. Requires `siderealMode` to be configured. |
308
+ | `SEFLG_TRUEPOS` | 16 | True/geometric position (no light-time correction). |
309
+ | `SEFLG_NOABERR` | 1024 | No aberration of light correction. |
310
+ | `SEFLG_NOGDEFL` | 512 | No gravitational deflection of light. |
311
+ | `SEFLG_J2000` | 32 | Refer positions to the J2000 equinox (not the equinox of date). |
312
+ | `SEFLG_NONUT` | 64 | No nutation (use mean equinox of date, not true equinox). |
313
+
314
+ You can combine flags:
315
+
316
+ ```typescript
317
+ import { SEFLG_EQUATORIAL, SEFLG_TOPOCTR, SEFLG_SIDEREAL } from '../../constants';
318
+
319
+ // Sidereal equatorial topocentric position
320
+ const pos = swe.calc(jd, SE_SUN, SEFLG_EQUATORIAL | SEFLG_SIDEREAL | SEFLG_TOPOCTR);
321
+ ```
322
+
323
+ ### Understanding ecliptic longitude
324
+
325
+ Ecliptic longitude is measured along the ecliptic (the Sun's apparent path through the sky over a year). It starts at the **vernal equinox point** (0 degrees Aries in the tropical zodiac) and increases eastward through the zodiac signs:
326
+
327
+ | Degrees | Sign |
328
+ |-----------|-------------|
329
+ | 0 - 30 | Aries |
330
+ | 30 - 60 | Taurus |
331
+ | 60 - 90 | Gemini |
332
+ | 90 - 120 | Cancer |
333
+ | 120 - 150 | Leo |
334
+ | 150 - 180 | Virgo |
335
+ | 180 - 210 | Libra |
336
+ | 210 - 240 | Scorpio |
337
+ | 240 - 270 | Sagittarius |
338
+ | 270 - 300 | Capricorn |
339
+ | 300 - 330 | Aquarius |
340
+ | 330 - 360 | Pisces |
341
+
342
+ To convert absolute longitude to sign + degree within sign:
343
+ ```typescript
344
+ const signIndex = Math.floor(longitude / 30); // 0 = Aries, 11 = Pisces
345
+ const degreeInSign = longitude - signIndex * 30; // 0.0 to 29.999...
346
+ ```
347
+
348
+ ### Understanding ecliptic latitude
349
+
350
+ Most planets stay very close to the ecliptic (latitude near 0). The Moon can reach about +/-5 degrees. Pluto can reach about +/-17 degrees. The Sun's ecliptic latitude is always essentially 0 (by definition, since the ecliptic is the Sun's apparent path).
351
+
352
+ ### Time input: UT vs ET
353
+
354
+ The Julian Day number you pass to `calc()` is interpreted according to the `timeMode` set in the constructor:
355
+
356
+ - **`'ut'`** (default): Universal Time. This is clock time corrected for time zones. Use this for most astrological work.
357
+ - **`'et'`**: Ephemeris Time (also called Terrestrial Time / TT). This is the uniform time scale used internally by the ephemeris. It differs from UT by "delta-T", which is about 69 seconds in 2024.
358
+
359
+ For dates within a few centuries of the present, the difference between UT and ET is small and the library handles the conversion internally. For ancient or far-future dates, the distinction becomes significant.
360
+
361
+ ### Edge cases
362
+
363
+ - **Speed is always included**: The wrapper adds `SEFLG_SPEED` automatically. You do not need to pass it.
364
+ - **Ephemeris fallback**: If you request `'swisseph'` or `'jpl'` but the ephemeris files are not loaded, the engine silently falls back to the Moshier analytical ephemeris. You can check the returned `flags` field to see which ephemeris was actually used.
365
+ - **Retrograde planets**: When `longitudeSpeed < 0`, the planet is retrograde (appearing to move backward through the zodiac from Earth's perspective). This is a normal geometric effect of orbital mechanics.
366
+ - **Mean vs True Node**: The mean node moves smoothly backward through the zodiac (~19.3 degrees/year). The true node oscillates around the mean with a period of about 173 days. Most astrologers use the mean node; Vedic astrology traditionally uses the true node (Rahu/Ketu).