tonus 0.1.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 (141) hide show
  1. package/BIBLIOGRAPHY.md +99 -0
  2. package/LICENSE +29 -0
  3. package/README.md +108 -0
  4. package/dist/data/cal.d.ts +10 -0
  5. package/dist/data/cal.js +3862 -0
  6. package/dist/data/commune.d.ts +17 -0
  7. package/dist/data/commune.js +1333 -0
  8. package/dist/data/gr.d.ts +5 -0
  9. package/dist/data/gr.js +13449 -0
  10. package/dist/data/kyriale.d.ts +11 -0
  11. package/dist/data/kyriale.js +971 -0
  12. package/dist/data/la.d.ts +5 -0
  13. package/dist/data/la.js +14229 -0
  14. package/dist/data/lh.d.ts +5 -0
  15. package/dist/data/lh.js +3619 -0
  16. package/dist/data/lu.d.ts +5 -0
  17. package/dist/data/lu.js +23779 -0
  18. package/dist/data/masses.d.ts +18 -0
  19. package/dist/data/masses.js +297 -0
  20. package/dist/data/office-roman.d.ts +19 -0
  21. package/dist/data/office-roman.js +13792 -0
  22. package/dist/data/office.d.ts +12 -0
  23. package/dist/data/office.js +13052 -0
  24. package/dist/data/propers.d.ts +13 -0
  25. package/dist/data/propers.js +7584 -0
  26. package/dist/data/psalms.d.ts +4 -0
  27. package/dist/data/psalms.js +10 -0
  28. package/dist/data/psalms.json +22918 -0
  29. package/dist/data/tones.d.ts +20 -0
  30. package/dist/data/tones.js +153 -0
  31. package/dist/data/types.d.ts +3 -0
  32. package/dist/data/types.js +2 -0
  33. package/dist/engines/cal/calendar.d.ts +21 -0
  34. package/dist/engines/cal/calendar.js +265 -0
  35. package/dist/engines/cal/date.d.ts +31 -0
  36. package/dist/engines/cal/date.js +141 -0
  37. package/dist/engines/cal/types.d.ts +66 -0
  38. package/dist/engines/cal/types.js +189 -0
  39. package/dist/engines/chant/chant.d.ts +10 -0
  40. package/dist/engines/chant/chant.js +135 -0
  41. package/dist/engines/chant/hour.d.ts +8 -0
  42. package/dist/engines/chant/hour.js +135 -0
  43. package/dist/engines/chant/intone.d.ts +8 -0
  44. package/dist/engines/chant/intone.js +84 -0
  45. package/dist/engines/chant/ordinary.d.ts +7 -0
  46. package/dist/engines/chant/ordinary.js +232 -0
  47. package/dist/engines/chant/propers.d.ts +8 -0
  48. package/dist/engines/chant/propers.js +107 -0
  49. package/dist/engines/chant/psalm.d.ts +7 -0
  50. package/dist/engines/chant/psalm.js +60 -0
  51. package/dist/engines/chant/syllabify.d.ts +20 -0
  52. package/dist/engines/chant/syllabify.js +192 -0
  53. package/dist/engines/chant/types.d.ts +76 -0
  54. package/dist/engines/chant/types.js +34 -0
  55. package/dist/engines/epoch.d.ts +2 -0
  56. package/dist/engines/epoch.js +14 -0
  57. package/dist/engines/harmonia/api.d.ts +35 -0
  58. package/dist/engines/harmonia/api.js +90 -0
  59. package/dist/engines/harmonia/aspects.d.ts +8 -0
  60. package/dist/engines/harmonia/aspects.js +15 -0
  61. package/dist/engines/harmonia/data/doctrines.d.ts +16 -0
  62. package/dist/engines/harmonia/data/doctrines.js +154 -0
  63. package/dist/engines/harmonia/data/vowels.d.ts +10 -0
  64. package/dist/engines/harmonia/data/vowels.js +21 -0
  65. package/dist/engines/harmonia/presence.d.ts +13 -0
  66. package/dist/engines/harmonia/presence.js +48 -0
  67. package/dist/engines/harmonia/tabula.d.ts +28 -0
  68. package/dist/engines/harmonia/tabula.js +32 -0
  69. package/dist/engines/harmonia/voice.d.ts +19 -0
  70. package/dist/engines/harmonia/voice.js +51 -0
  71. package/dist/engines/imprint.d.ts +30 -0
  72. package/dist/engines/imprint.js +152 -0
  73. package/dist/engines/planet/appearance.d.ts +40 -0
  74. package/dist/engines/planet/appearance.js +84 -0
  75. package/dist/engines/planet/aspects.d.ts +5 -0
  76. package/dist/engines/planet/aspects.js +41 -0
  77. package/dist/engines/planet/math.d.ts +13 -0
  78. package/dist/engines/planet/math.js +56 -0
  79. package/dist/engines/planet/orbital.d.ts +25 -0
  80. package/dist/engines/planet/orbital.js +223 -0
  81. package/dist/engines/planet/planet.d.ts +13 -0
  82. package/dist/engines/planet/planet.js +198 -0
  83. package/dist/engines/planet/position.d.ts +62 -0
  84. package/dist/engines/planet/position.js +156 -0
  85. package/dist/engines/planet/types.d.ts +61 -0
  86. package/dist/engines/planet/types.js +14 -0
  87. package/dist/engines/score/api.d.ts +54 -0
  88. package/dist/engines/score/api.js +87 -0
  89. package/dist/engines/score/articulation.d.ts +6 -0
  90. package/dist/engines/score/articulation.js +112 -0
  91. package/dist/engines/score/emitters/midi.d.ts +65 -0
  92. package/dist/engines/score/emitters/midi.js +158 -0
  93. package/dist/engines/score/emitters/musicxml.d.ts +18 -0
  94. package/dist/engines/score/emitters/musicxml.js +166 -0
  95. package/dist/engines/score/infer.d.ts +4 -0
  96. package/dist/engines/score/infer.js +77 -0
  97. package/dist/engines/score/ir.d.ts +4 -0
  98. package/dist/engines/score/ir.js +177 -0
  99. package/dist/engines/score/meta.d.ts +19 -0
  100. package/dist/engines/score/meta.js +34 -0
  101. package/dist/engines/score/neume.d.ts +3 -0
  102. package/dist/engines/score/neume.js +26 -0
  103. package/dist/engines/score/parse.d.ts +3 -0
  104. package/dist/engines/score/parse.js +359 -0
  105. package/dist/engines/score/phrasing.d.ts +24 -0
  106. package/dist/engines/score/phrasing.js +257 -0
  107. package/dist/engines/score/prosody.d.ts +35 -0
  108. package/dist/engines/score/prosody.js +109 -0
  109. package/dist/engines/score/tabula.d.ts +70 -0
  110. package/dist/engines/score/tabula.js +109 -0
  111. package/dist/engines/score/types.d.ts +159 -0
  112. package/dist/engines/score/types.js +2 -0
  113. package/dist/engines/temper/api.d.ts +60 -0
  114. package/dist/engines/temper/api.js +130 -0
  115. package/dist/engines/temper/data/constants.d.ts +27 -0
  116. package/dist/engines/temper/data/constants.js +150 -0
  117. package/dist/engines/temper/data/guido.d.ts +14 -0
  118. package/dist/engines/temper/data/guido.js +29 -0
  119. package/dist/engines/temper/data/modes.d.ts +38 -0
  120. package/dist/engines/temper/data/modes.js +158 -0
  121. package/dist/engines/temper/gabc.d.ts +5 -0
  122. package/dist/engines/temper/gabc.js +53 -0
  123. package/dist/engines/temper/gamut.d.ts +9 -0
  124. package/dist/engines/temper/gamut.js +24 -0
  125. package/dist/engines/temper/guido.d.ts +16 -0
  126. package/dist/engines/temper/guido.js +48 -0
  127. package/dist/engines/temper/interval.d.ts +15 -0
  128. package/dist/engines/temper/interval.js +31 -0
  129. package/dist/engines/temper/modes.d.ts +6 -0
  130. package/dist/engines/temper/modes.js +13 -0
  131. package/dist/engines/temper/neume.d.ts +14 -0
  132. package/dist/engines/temper/neume.js +59 -0
  133. package/dist/engines/temper/pitch.d.ts +40 -0
  134. package/dist/engines/temper/pitch.js +129 -0
  135. package/dist/engines/temper/scale.d.ts +37 -0
  136. package/dist/engines/temper/scale.js +217 -0
  137. package/dist/engines/temper/step.d.ts +23 -0
  138. package/dist/engines/temper/step.js +53 -0
  139. package/dist/index.d.ts +40 -0
  140. package/dist/index.js +27 -0
  141. package/package.json +60 -0
@@ -0,0 +1,223 @@
1
+ export const ORBITAL_ELEMENTS = new Map([
2
+ [
3
+ "Mercury",
4
+ {
5
+ name: "Mercury",
6
+ symbol: "☿",
7
+ datasets: [
8
+ [
9
+ [0.38709927, 0.00000037],
10
+ [0.20563593, 0.00001906],
11
+ [7.00497902, -0.00594749],
12
+ [252.2503235, 149472.67411175],
13
+ [77.45779628, 0.16047689],
14
+ [48.33076593, -0.12534081],
15
+ ],
16
+ [
17
+ [0.38709843, 0],
18
+ [0.20563661, 0.00002123],
19
+ [7.00559432, -0.00590158],
20
+ [252.25166724, 149472.67486623],
21
+ [77.45771895, 0.15940013],
22
+ [48.33961819, -0.12214182],
23
+ ],
24
+ ],
25
+ radius: 2439.4,
26
+ rotation_period: 58.6462,
27
+ },
28
+ ],
29
+ [
30
+ "Venus",
31
+ {
32
+ name: "Venus",
33
+ symbol: "♀",
34
+ datasets: [
35
+ [
36
+ [0.72333566, 0.0000039],
37
+ [0.00676399, -0.00005107],
38
+ [3.39467605, -0.0007889],
39
+ [181.9790995, 58517.81538729],
40
+ [131.60246718, 0.00268329],
41
+ [76.67984255, -0.27769418],
42
+ ],
43
+ [
44
+ [0.72332102, -0.00000026],
45
+ [-0.00005107, 0.01673163],
46
+ [3.39777545, 0.00043494],
47
+ [181.9797085, 58517.8156026],
48
+ [131.76755713, 0.05679648],
49
+ [76.67261496, -0.27274174],
50
+ ],
51
+ ],
52
+ radius: 6051.8,
53
+ rotation_period: -243.018,
54
+ },
55
+ ],
56
+ [
57
+ "Earth",
58
+ {
59
+ name: "Earth",
60
+ symbol: "♁",
61
+ datasets: [
62
+ [
63
+ [1.00000261, 0.00000562],
64
+ [0.01671123, -0.00004392],
65
+ [-0.00001531, -0.01294668],
66
+ [100.46457166, 35999.37244981],
67
+ [102.93768193, 0.32327364],
68
+ [0, 0],
69
+ ],
70
+ [
71
+ [1.00000018, 1.52371243],
72
+ [0.01673163, -0.00003661],
73
+ [-0.00054346, -0.01337178],
74
+ [100.46691572, 35999.37306329],
75
+ [102.93005885, 0.3179526],
76
+ [-5.11260389, -0.24123856],
77
+ ],
78
+ ],
79
+ radius: 6371.0084,
80
+ rotation_period: 0.99726968,
81
+ },
82
+ ],
83
+ [
84
+ "Mars",
85
+ {
86
+ name: "Mars",
87
+ symbol: "♂",
88
+ datasets: [
89
+ [
90
+ [1.52371034, 0.00001847],
91
+ [0.0933941, 0.00007882],
92
+ [1.84969142, -0.00813131],
93
+ [-4.55343205, 19140.30268499],
94
+ [-23.94362959, 0.44441088],
95
+ [49.55953891, -0.29257343],
96
+ ],
97
+ [
98
+ [1.52371243, 0.00000097],
99
+ [0.09336511, 0.00009149],
100
+ [1.85181869, -0.00724757],
101
+ [-4.56813164, 19140.29934243],
102
+ [-23.91744784, 0.45223625],
103
+ [49.71320984, -0.26852431],
104
+ ],
105
+ ],
106
+ radius: 3389.5,
107
+ rotation_period: 1.02595676,
108
+ },
109
+ ],
110
+ [
111
+ "Jupiter",
112
+ {
113
+ name: "Jupiter",
114
+ symbol: "♃",
115
+ datasets: [
116
+ [
117
+ [5.202887, -0.00011607],
118
+ [0.04838624, -0.00013253],
119
+ [1.30439695, -0.00183714],
120
+ [34.39644051, 3034.74612775],
121
+ [14.72847983, 0.21252668],
122
+ [100.47390909, 0.20469106],
123
+ ],
124
+ [
125
+ [5.20248019, -0.00002864],
126
+ [0.0485359, 0.00018026],
127
+ [1.29861416, -0.00322699],
128
+ [34.33479152, 3034.90371757],
129
+ [14.27495244, 0.18199196],
130
+ [100.29282654, 0.13024619],
131
+ ],
132
+ [0.00012452, 0.0606406, -0.35635438, 38.35125],
133
+ ],
134
+ radius: 69911,
135
+ rotation_period: 0.41354,
136
+ },
137
+ ],
138
+ [
139
+ "Saturn",
140
+ {
141
+ name: "Saturn",
142
+ symbol: "♄",
143
+ datasets: [
144
+ [
145
+ [9.53667594, -0.0012506],
146
+ [0.05386179, -0.00050991],
147
+ [2.48599187, 0.00193609],
148
+ [49.95424423, 1222.49362201],
149
+ [92.59887831, -0.41897216],
150
+ [113.66242448, -0.28867794],
151
+ ],
152
+ [
153
+ [9.54149883, -0.00003065],
154
+ [0.05550825, -0.00032044],
155
+ [2.49424102, 0.00451969],
156
+ [50.07571329, 1222.11494724],
157
+ [92.86136063, 0.54179478],
158
+ [113.639987, -0.25015002],
159
+ ],
160
+ [0.00025899, -0.13434469, 0.87320147, 38.35125],
161
+ ],
162
+ radius: 58232,
163
+ rotation_period: 0.44401,
164
+ },
165
+ ],
166
+ [
167
+ "Uranus",
168
+ {
169
+ name: "Uranus",
170
+ symbol: "♅",
171
+ datasets: [
172
+ [
173
+ [19.18916464, -0.00196176],
174
+ [0.04725744, -0.00004397],
175
+ [0.77263783, -0.00242939],
176
+ [313.23810451, 428.48202785],
177
+ [170.9542763, 0.40805281],
178
+ [74.01692503, 0.04240589],
179
+ ],
180
+ [
181
+ [19.18797948, -0.00020455],
182
+ [0.0468574, -0.0000155],
183
+ [0.77298127, -0.00180155],
184
+ [314.20276625, 428.49512595],
185
+ [172.43404441, 0.09266985],
186
+ [73.96250215, 0.05739699],
187
+ ],
188
+ [0.00058331, -0.97731848, 0.17689245, 7.67025],
189
+ ],
190
+ radius: 25362,
191
+ rotation_period: -0.718,
192
+ },
193
+ ],
194
+ [
195
+ "Neptune",
196
+ {
197
+ name: "Neptune",
198
+ symbol: "♆",
199
+ datasets: [
200
+ [
201
+ [30.06992276, 0.00026291],
202
+ [0.00859048, 0.00005105],
203
+ [1.77004347, 0.00035372],
204
+ [-55.12002969, 218.45945325],
205
+ [44.96476227, -0.32241464],
206
+ [131.78422574, -0.00508664],
207
+ ],
208
+ [
209
+ [30.06952752, 0.00006447],
210
+ [0.00895439, 0.00000818],
211
+ [1.7700552, 0.000224],
212
+ [304.22289287, 218.46515314],
213
+ [46.68158724, 0.01009938],
214
+ [131.78635853, -0.00606302],
215
+ ],
216
+ [-0.00041348, 0.68346318, -0.10162547, 7.67025],
217
+ ],
218
+ radius: 24622,
219
+ rotation_period: 0.67125,
220
+ },
221
+ ],
222
+ ]);
223
+ //# sourceMappingURL=orbital.js.map
@@ -0,0 +1,13 @@
1
+ import type { Cosmos, CosmosQuery } from "./types.js";
2
+ /**
3
+ * Ephemeris lookup (`tonus.caelum`). Computes geocentric and heliocentric
4
+ * positions, zodiac signs, retrogradation, and aspects for the classical
5
+ * bodies at an instant (JPL Keplerian elements, 3000 BC – 3000 AD). A
6
+ * `from`/`to` range returns a stepped series.
7
+ */
8
+ export declare function getCosmos(query: CosmosQuery & {
9
+ from: Date;
10
+ to: Date;
11
+ }): Cosmos[];
12
+ export declare function getCosmos(query?: CosmosQuery): Cosmos;
13
+ //# sourceMappingURL=planet.d.ts.map
@@ -0,0 +1,198 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/planet/planet — planetary snapshot builder
3
+ // ---------------------------------------------------------------------------
4
+ import { angleDelta, wrapAngle } from "./math.js";
5
+ import { getState, sunPos, moonPos, planetPos } from "./position.js";
6
+ import { sunAppearance, moonAppearance, planetAppearance } from "./appearance.js";
7
+ import { detectAspects } from "./aspects.js";
8
+ import { ORBITAL_ELEMENTS } from "./orbital.js";
9
+ import { latinName } from "./types.js";
10
+ import { DEFAULT_EPOCH } from "../epoch.js";
11
+ const MS_PER_DAY = 86400000;
12
+ const ALL_BODIES = ["Sun", "Moon", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn"];
13
+ const SIGNS = [
14
+ "Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
15
+ "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces",
16
+ ];
17
+ const zodiac = (lon) => Math.floor(wrapAngle(lon) / 30) % 12;
18
+ const sign = (lon) => SIGNS[zodiac(lon)];
19
+ function computeSpeed(geoLon, name, ts) {
20
+ const nextState = getState(ts + MS_PER_DAY);
21
+ const nextSun = sunPos(nextState);
22
+ let nextLon;
23
+ if (name === "Sun") {
24
+ nextLon = nextSun.geo.lon;
25
+ }
26
+ else if (name === "Moon") {
27
+ nextLon = moonPos(nextState, nextSun).geo.lon;
28
+ }
29
+ else {
30
+ nextLon = planetPos(name, nextState, nextSun).geo.lon;
31
+ }
32
+ return angleDelta(geoLon, nextLon);
33
+ }
34
+ function buildSun(ts) {
35
+ const state = getState(ts);
36
+ const pos = sunPos(state);
37
+ const app = sunAppearance(pos.geo.dist);
38
+ const speed = computeSpeed(pos.geo.lon, "Sun", ts);
39
+ return {
40
+ name: "Sun",
41
+ nomen: latinName("Sun"),
42
+ symbol: "☉",
43
+ helio: { lon: pos.helio.lon, lat: pos.helio.lat, dist: pos.helio.dist },
44
+ geo: pos.geo,
45
+ speed,
46
+ retrograde: speed < 0,
47
+ magnitude: app.magnitude,
48
+ elongation: 0,
49
+ phase: 1,
50
+ apparentDiameter: app.apparentDiameter,
51
+ zodiac: zodiac(pos.geo.lon),
52
+ sign: sign(pos.geo.lon),
53
+ };
54
+ }
55
+ function buildMoon(ts) {
56
+ const state = getState(ts);
57
+ const sun = sunPos(state);
58
+ const pos = moonPos(state, sun);
59
+ const app = moonAppearance({
60
+ sunLongitude: sun.geo.lon,
61
+ moonLongitude: pos.geo.lon,
62
+ moonLatitude: pos.geo.lat,
63
+ distEarthRadii: pos.distEarthRadii,
64
+ });
65
+ const speed = computeSpeed(pos.geo.lon, "Moon", ts);
66
+ return {
67
+ name: "Moon",
68
+ nomen: latinName("Moon"),
69
+ symbol: "☾",
70
+ helio: { lon: 0, lat: 0, dist: 0 },
71
+ geo: {
72
+ lon: pos.geo.lon,
73
+ lat: pos.geo.lat,
74
+ dist: pos.geo.dist,
75
+ equatorial: pos.geo.equatorial,
76
+ },
77
+ speed,
78
+ retrograde: speed < 0,
79
+ magnitude: -12.6,
80
+ elongation: app.elongation,
81
+ phase: app.phase,
82
+ apparentDiameter: app.apparentDiameter,
83
+ zodiac: zodiac(pos.geo.lon),
84
+ sign: sign(pos.geo.lon),
85
+ distEarthRadii: pos.distEarthRadii,
86
+ };
87
+ }
88
+ function buildPlanet(name, ts) {
89
+ const state = getState(ts);
90
+ const sun = sunPos(state);
91
+ const pos = planetPos(name, state, sun);
92
+ const elem = ORBITAL_ELEMENTS.get(name);
93
+ const app = planetAppearance({
94
+ name,
95
+ heliocentricDistance: pos.helio.dist,
96
+ geocentricDistance: pos.geo.dist,
97
+ geocentricLongitude: pos.geo.lon,
98
+ geocentricLatitude: pos.geo.lat,
99
+ sunDistance: sun.geo.dist,
100
+ J: state.J,
101
+ });
102
+ const speed = computeSpeed(pos.geo.lon, name, ts);
103
+ return {
104
+ name,
105
+ nomen: latinName(name),
106
+ symbol: elem.symbol,
107
+ helio: { lon: pos.helio.lon, lat: pos.helio.lat, dist: pos.helio.dist },
108
+ geo: {
109
+ lon: pos.geo.lon, lat: pos.geo.lat, dist: pos.geo.dist,
110
+ equatorial: pos.geo.equatorial,
111
+ },
112
+ speed,
113
+ retrograde: speed < 0,
114
+ magnitude: app.magnitude,
115
+ elongation: app.elongation,
116
+ phase: app.phase,
117
+ apparentDiameter: app.apparentDiameter,
118
+ zodiac: zodiac(pos.helio.lon),
119
+ sign: sign(pos.helio.lon),
120
+ };
121
+ }
122
+ function buildEarth(ts) {
123
+ const state = getState(ts);
124
+ const sun = sunPos(state);
125
+ const pos = planetPos("Earth", state, sun);
126
+ const elem = ORBITAL_ELEMENTS.get("Earth");
127
+ const speed = computeSpeed(pos.geo.lon, "Earth", ts);
128
+ return {
129
+ name: "Earth",
130
+ nomen: latinName("Earth"),
131
+ symbol: elem.symbol,
132
+ helio: { lon: pos.helio.lon, lat: pos.helio.lat, dist: pos.helio.dist },
133
+ geo: {
134
+ lon: pos.geo.lon, lat: pos.geo.lat, dist: pos.geo.dist,
135
+ equatorial: pos.geo.equatorial,
136
+ },
137
+ speed,
138
+ retrograde: speed < 0,
139
+ magnitude: 0,
140
+ elongation: 0,
141
+ phase: 1,
142
+ apparentDiameter: 0,
143
+ zodiac: zodiac(pos.helio.lon),
144
+ sign: sign(pos.helio.lon),
145
+ };
146
+ }
147
+ const BODY_BUILDERS = {
148
+ Sun: buildSun,
149
+ Moon: buildMoon,
150
+ Mercury: (ts) => buildPlanet("Mercury", ts),
151
+ Venus: (ts) => buildPlanet("Venus", ts),
152
+ Earth: buildEarth,
153
+ Mars: (ts) => buildPlanet("Mars", ts),
154
+ Jupiter: (ts) => buildPlanet("Jupiter", ts),
155
+ Saturn: (ts) => buildPlanet("Saturn", ts),
156
+ };
157
+ const MAX_FRAMES = 10000;
158
+ function snapshotAt(date, requested, orbLimit) {
159
+ const ts = date.getTime();
160
+ const bodies = requested.map((name) => BODY_BUILDERS[name](ts));
161
+ const geoLons = {};
162
+ for (const body of bodies) {
163
+ if (body.name !== "Earth")
164
+ geoLons[body.name] = body.geo.lon;
165
+ }
166
+ const aspects = detectAspects(geoLons, { orbLimit });
167
+ return { date, bodies, aspects };
168
+ }
169
+ export function getCosmos(query = {}) {
170
+ const requested = query.bodies ?? ALL_BODIES;
171
+ if (query.from != null || query.to != null) {
172
+ if (query.from == null || query.to == null) {
173
+ throw new RangeError("caelum range requires both from and to");
174
+ }
175
+ if (query.to.getTime() < query.from.getTime()) {
176
+ throw new RangeError("caelum range: to must be >= from");
177
+ }
178
+ const step = query.step ?? 1;
179
+ if (step <= 0) {
180
+ throw new RangeError("caelum range: step must be > 0");
181
+ }
182
+ const stepMs = step * MS_PER_DAY;
183
+ const startTs = query.from.getTime();
184
+ const endTs = query.to.getTime();
185
+ const frameCount = Math.floor((endTs - startTs) / stepMs) + 1;
186
+ if (frameCount > MAX_FRAMES) {
187
+ throw new RangeError(`caelum range would produce ${frameCount} frames (max ${MAX_FRAMES})`);
188
+ }
189
+ const frames = [];
190
+ for (let ts = startTs; ts <= endTs; ts += stepMs) {
191
+ frames.push(snapshotAt(new Date(ts), requested, query.orbLimit));
192
+ }
193
+ return frames;
194
+ }
195
+ const date = query.date ?? query.feast?.date ?? DEFAULT_EPOCH;
196
+ return snapshotAt(date, requested, query.orbLimit);
197
+ }
198
+ //# sourceMappingURL=planet.js.map
@@ -0,0 +1,62 @@
1
+ export declare const EARTH_RADIUS_AU: number;
2
+ export interface AstroState {
3
+ JD: number;
4
+ TT: number;
5
+ TS: number;
6
+ J: number;
7
+ T: number;
8
+ eps: number;
9
+ }
10
+ export declare function getState(ts: number): AstroState;
11
+ export interface ComputedPos {
12
+ geo: {
13
+ x: number;
14
+ y: number;
15
+ z: number;
16
+ lon: number;
17
+ lat: number;
18
+ dist: number;
19
+ equatorial: {
20
+ x: number;
21
+ y: number;
22
+ z: number;
23
+ ra: number;
24
+ dec: number;
25
+ dist: number;
26
+ };
27
+ };
28
+ }
29
+ export interface SunPos extends ComputedPos {
30
+ helio: {
31
+ lon: number;
32
+ lat: number;
33
+ dist: number;
34
+ };
35
+ orbit: {
36
+ L: number;
37
+ M: number;
38
+ omega: number;
39
+ e: number;
40
+ };
41
+ }
42
+ export interface PlanetPos extends ComputedPos {
43
+ helio: {
44
+ x: number;
45
+ y: number;
46
+ z: number;
47
+ lon: number;
48
+ lat: number;
49
+ dist: number;
50
+ };
51
+ }
52
+ export interface MoonPos extends ComputedPos {
53
+ helio: Record<string, never>;
54
+ geo: ComputedPos["geo"] & {
55
+ distEarthRadii: number;
56
+ };
57
+ distEarthRadii: number;
58
+ }
59
+ export declare function sunPos(state: AstroState): SunPos;
60
+ export declare function moonPos(state: AstroState, sun: SunPos): MoonPos;
61
+ export declare function planetPos(name: string, state: AstroState, sun: SunPos): PlanetPos;
62
+ //# sourceMappingURL=position.d.ts.map
@@ -0,0 +1,156 @@
1
+ // ---------------------------------------------------------------------------
2
+ // engines/planet/position — Julian date, astro state, helio/geo position engine
3
+ // ---------------------------------------------------------------------------
4
+ import { sinDeg, cosDeg, atan2Deg, kepler, wrapAngle, toAu, toCartesian, toSpherical, toEquatorial } from "./math.js";
5
+ import { ORBITAL_ELEMENTS } from "./orbital.js";
6
+ const MS_PER_DAY = 86400000;
7
+ // Precomputed Earth radius in AU (used for Moon distance conversion)
8
+ const EARTH_ELEM = ORBITAL_ELEMENTS.get("Earth");
9
+ export const EARTH_RADIUS_AU = toAu(EARTH_ELEM.radius);
10
+ function meanObliquity(T) {
11
+ const eps0 = 23 + 26 / 60 + 21.406 / 3600;
12
+ const sec = -46.836769 * T -
13
+ 0.0001831 * T ** 2 +
14
+ 0.0020034 * T ** 3 -
15
+ 0.000000576 * T ** 4 -
16
+ 0.0000000434 * T ** 5;
17
+ return eps0 + sec / 3600;
18
+ }
19
+ export function getState(ts) {
20
+ const JD = 2440587.5 + ts / MS_PER_DAY;
21
+ const _T = (JD - 2451545) / 36525;
22
+ const dT = 64.7 + 64.7 * _T - 0.6 * _T * _T; // seconds
23
+ const TT = JD + dT / 86400;
24
+ const J = TT - 2451545.0;
25
+ const T = J / 36525;
26
+ const eps = meanObliquity(T);
27
+ return { JD, TT, TS: ts, J, T, eps };
28
+ }
29
+ // ── Sun position ──
30
+ export function sunPos(state) {
31
+ const { J, eps } = state;
32
+ const omega = 282.9404 + 4.70935e-5 * J;
33
+ const e = 0.016709 - 1.151e-9 * J;
34
+ const M = 356.047 + 0.9856002585 * J;
35
+ const E = M + (180 / Math.PI) * e * sinDeg(M) * (1 + e * cosDeg(M));
36
+ const xp = cosDeg(E) - e;
37
+ const yp = Math.sqrt(1 - e * e) * sinDeg(E);
38
+ const dist = Math.sqrt(xp * xp + yp * yp);
39
+ const v = atan2Deg(yp, xp);
40
+ const lambda = v + omega;
41
+ const L = omega + M;
42
+ const x = dist * cosDeg(lambda);
43
+ const y = dist * sinDeg(lambda);
44
+ const z = 0;
45
+ const [xe, ye, ze] = toEquatorial(x, y, z, eps);
46
+ const [ra, dec, rho] = toSpherical(xe, ye, ze);
47
+ return {
48
+ helio: { lon: wrapAngle(lambda), lat: 0, dist },
49
+ orbit: { L: wrapAngle(L), M: wrapAngle(M), omega, e },
50
+ geo: {
51
+ x, y, z,
52
+ lon: wrapAngle(lambda), lat: 0, dist,
53
+ equatorial: { x: xe, y: ye, z: ze, ra: wrapAngle(ra), dec, dist: rho },
54
+ },
55
+ };
56
+ }
57
+ // ── Moon position ──
58
+ export function moonPos(state, sun) {
59
+ const { J, eps } = state;
60
+ const Omega = wrapAngle(125.1228 - 0.0529538083 * J);
61
+ const I = 5.1454;
62
+ const omega = wrapAngle(318.0634 + 0.1643573223 * J);
63
+ const a = 60.2666; // Earth radii
64
+ const e = 0.0549;
65
+ const M = wrapAngle(115.3654 + 13.0649929509 * J);
66
+ const E = M + (180 / Math.PI) * e * sinDeg(M) * (1 + e * cosDeg(M));
67
+ const xh = a * (cosDeg(E) - e);
68
+ const yh = a * Math.sqrt(1 - e * e) * sinDeg(E);
69
+ const cO = cosDeg(Omega), sO = sinDeg(Omega);
70
+ const cw = cosDeg(omega), sw = sinDeg(omega);
71
+ const cI = cosDeg(I), sI = sinDeg(I);
72
+ const x = (cw * cO - sw * sO * cI) * xh + (-sw * cO - cw * sO * cI) * yh;
73
+ const y = (cw * sO + sw * cO * cI) * xh + (-sw * sO + cw * cO * cI) * yh;
74
+ const z = sw * sI * xh + cw * sI * yh;
75
+ const [lonE, latE, distE] = toSpherical(x, y, z);
76
+ const Lm = wrapAngle(Omega + omega + M);
77
+ const Ms = sun.orbit.M;
78
+ const Ls = sun.orbit.L;
79
+ const D = wrapAngle(Lm - Ls);
80
+ const F = wrapAngle(Lm - Omega);
81
+ // Lunar perturbations
82
+ const lonPerturb = -1.274 * sinDeg(M - 2 * D) + 0.658 * sinDeg(2 * D) - 0.186 * sinDeg(Ms) -
83
+ 0.059 * sinDeg(2 * M - 2 * D) - 0.057 * sinDeg(M - 2 * D + Ms) +
84
+ 0.053 * sinDeg(M + 2 * D) + 0.046 * sinDeg(2 * D - Ms) +
85
+ 0.041 * sinDeg(M - Ms) - 0.035 * sinDeg(D) - 0.031 * sinDeg(M + Ms) -
86
+ 0.015 * sinDeg(2 * F - 2 * D) + 0.011 * sinDeg(M - 4 * D);
87
+ const latPerturb = -0.173 * sinDeg(F - 2 * D) - 0.055 * sinDeg(M - F - 2 * D) -
88
+ 0.046 * sinDeg(M + F - 2 * D) + 0.033 * sinDeg(F + 2 * D) +
89
+ 0.017 * sinDeg(2 * M + F);
90
+ const distPerturb = -0.58 * cosDeg(M - 2 * D) - 0.46 * cosDeg(2 * D);
91
+ const lon = wrapAngle(lonE + lonPerturb);
92
+ const lat = latE + latPerturb;
93
+ const rER = distE + distPerturb; // Earth radii
94
+ const [xc, yc, zc] = toCartesian(lon, lat, rER);
95
+ const xAu = xc * EARTH_RADIUS_AU;
96
+ const yAu = yc * EARTH_RADIUS_AU;
97
+ const zAu = zc * EARTH_RADIUS_AU;
98
+ const distAu = rER * EARTH_RADIUS_AU;
99
+ const [xe, ye, ze] = toEquatorial(xAu, yAu, zAu, eps);
100
+ const [ra, dec, rho] = toSpherical(xe, ye, ze);
101
+ return {
102
+ helio: {},
103
+ distEarthRadii: rER,
104
+ geo: {
105
+ x: xAu, y: yAu, z: zAu,
106
+ lon, lat, dist: distAu,
107
+ distEarthRadii: rER,
108
+ equatorial: { x: xe, y: ye, z: ze, ra: wrapAngle(ra), dec, dist: rho },
109
+ },
110
+ };
111
+ }
112
+ // ── Planet position ──
113
+ export function planetPos(name, state, sun) {
114
+ const body = ORBITAL_ELEMENTS.get(name);
115
+ if (!body)
116
+ throw new Error(`Unknown body: ${name}`);
117
+ const { J, T, eps } = state;
118
+ const oe = body.datasets;
119
+ // Use higher-precision dataset (1800–2050) if in range, otherwise long-range dataset
120
+ const dataset = J > -73048.5 && J < 18626.5 ? oe[1] : oe[0];
121
+ const [a, e, I, L, wBar, Omega] = dataset.map(([x0, x1]) => x0 + x1 * T);
122
+ const omega = wBar - Omega; // argument of periapsis
123
+ let M = L - wBar; // mean anomaly
124
+ // Perturbation correction for outer planets
125
+ if (oe[2]) {
126
+ const [b, c, s, f] = oe[2];
127
+ M += b * T * T + c * cosDeg(f * T) + s * sinDeg(f * T);
128
+ }
129
+ const E = kepler(M, e);
130
+ const xh = a * (cosDeg(E) - e);
131
+ const yh = a * Math.sqrt(1 - e * e) * sinDeg(E);
132
+ const cO = cosDeg(Omega), sO = sinDeg(Omega);
133
+ const cw = cosDeg(omega), sw = sinDeg(omega);
134
+ const cI = cosDeg(I), sI = sinDeg(I);
135
+ // Ecliptic heliocentric Cartesian
136
+ const x = (cw * cO - sw * sO * cI) * xh + (-sw * cO - cw * sO * cI) * yh;
137
+ const y = (cw * sO + sw * cO * cI) * xh + (-sw * sO + cw * cO * cI) * yh;
138
+ const z = sw * sI * xh + cw * sI * yh;
139
+ const [helioLon, helioLat, helioR] = toSpherical(x, y, z);
140
+ // Geocentric (add Sun's geocentric position vector to flip to Earth-centered)
141
+ const xg = x + sun.geo.x;
142
+ const yg = y + sun.geo.y;
143
+ const zg = z + sun.geo.z;
144
+ const [geoLon, geoLat, geoDist] = toSpherical(xg, yg, zg);
145
+ const [xe, ye, ze] = toEquatorial(xg, yg, zg, eps);
146
+ const [ra, dec, rho] = toSpherical(xe, ye, ze);
147
+ return {
148
+ helio: { x, y, z, lon: wrapAngle(helioLon), lat: helioLat, dist: helioR },
149
+ geo: {
150
+ x: xg, y: yg, z: zg,
151
+ lon: wrapAngle(geoLon), lat: geoLat, dist: geoDist,
152
+ equatorial: { x: xe, y: ye, z: ze, ra: wrapAngle(ra), dec, dist: rho },
153
+ },
154
+ };
155
+ }
156
+ //# sourceMappingURL=position.js.map