@essrt/physics 17.0.0 → 18.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,7 +5,8 @@ as implemented by the [ESSRT simulator](https://3d.holisticuniverse.com)
5
5
  ([source, AGPL-3.0](https://github.com/dvansonsbeek/3d)). Pure computation:
6
6
  no I/O, no globals, no DOM, constants injected. The package ships the
7
7
  **complete model**, including the fitted coefficients, so an installed copy
8
- reproduces the hosted simulator bit-for-bit on the shared golden masters.
8
+ reproduces the simulator's engine on the shared golden masters (bit-exact in
9
+ Node; the browser build is held to a measured cross-runtime tolerance).
9
10
 
10
11
  ## Versioning — two axes, deliberately
11
12
 
@@ -39,10 +40,13 @@ subpath export) generated from the sources' JSDoc — `import` from
39
40
  `@essrt/physics` or any subpath is fully typed; no ambient shim needed.
40
41
 
41
42
  See the `exports` map in `package.json` for the full surface: moon
42
- (arguments/series/apparent/ecc-channel/month-chain), planets (geometry,
43
- corrections, predict, model, fibonacci-laws, …), deltat (cycles, deep-time,
44
- historical), cardinal points, phase, chain-cycles, sun, climate, eclipse
45
- finders, and the published reference curves.
43
+ (arguments, series, series-extension, apparent, ecc-channel,
44
+ deep-ecc-channel, month-chain), earth (year-lengths, precession-composed,
45
+ frame-of-date, sidereal-year-channel, deep-orbital-history), planets
46
+ (keplerian-chain, orbit-chain, secular-shape, secular-series,
47
+ inv-plane-frame, spin-channel, ecc-channel, geometry, model), deltat
48
+ (cycles, deep-time, recession-history, historical), cardinal points, phase,
49
+ chain-cycles, sun, climate and eclipse finders.
46
50
 
47
51
  For rendered display values (day/year lengths, precession rates, orbital
48
52
  elements as preformatted strings), see
@@ -57,10 +61,11 @@ The canonical assembly, wired once inside the package:
57
61
  import { createModel, DEFAULT_CONSTANTS } from '@essrt/physics';
58
62
 
59
63
  const model = createModel();
60
- model.identity.modelVersion; // the shipped model identity (e.g. 'v11.0') + both content hashes
61
- model.epoch.hAtYear(2000 - 380e6); // 306189 — Devonian H (the Wells 1963 match)
64
+ model.identity.modelVersion; // the shipped model identity (e.g. 'v21.0') + both content hashes
65
+ model.lunisolar.meanPeriodYearsAtYear(2000 - 380e6); // 21699 — the Devonian precession period
66
+ model.epoch.lodSecondsAtYear(2000 - 380e6); // 78895 — the Devonian day (Wells 1963's coral count)
62
67
  model.earth.obliquityDeg(2000); // 23.4393
63
- model.cardinal.jd(2000, 'SS'); // 2451716.5736 — June solstice 2000, the apparent Sun's crossing (USNO 2451716.575: the 2-min gap is the mean-longitude anchor convention, labelled)
68
+ model.cardinal.jd(2000, 'SS'); // 2451716.5751 — June solstice 2000, the apparent Sun's crossing (USNO 2451716.575)
64
69
  model.lengths.tropicalYearDays(2000); // 365.24219
65
70
 
66
71
  // Counterfactual (§2d): inject different constants, get a different solar
@@ -69,22 +74,27 @@ const cf = createModel({
69
74
  ...DEFAULT_CONSTANTS,
70
75
  foundational: { ...DEFAULT_CONSTANTS.foundational, holisticyearLength: 400000 },
71
76
  });
72
- cf.epoch.hAtYear(2000); // 400000
77
+ cf.epoch.hAtYear(2000); // 400000 — the anchor unit (a fit constant, not a period)
73
78
  cf.identity.counterfactual; // true
74
79
  ```
75
80
 
76
81
  The surface groups: `time` (exact JD ↔ model-year conversion on the SI
77
82
  axis the fits were anchored on — callers holding a JD convert here, never
78
83
  with their own formula), `identity` (version + hashes + citation DOI), `epoch`
79
- (H, LOD, α, ΔT, deep-time quantities at any year ±500 Myr), `earth`
84
+ (the internal unit, LOD, α, ΔT, the precession period and the deep-time
85
+ quantities at any year ±500 Myr), `lunisolar` (the mean lunisolar precession
86
+ period and rate at any year, its solar/lunar torque split, the nodal mode
87
+ and the obliquity beat, the apsidal and perihelion-of-date periods and their
88
+ ratios over the published window), `earth`
80
89
  (obliquity, eccentricity, inclination, perihelion), `lengths` (year and
81
90
  day lengths), `cardinal` (solstice/equinox JD, RA, year length), `moon`
82
91
  (distance and months at epoch, plus the apparent-position chain on the
83
92
  JD(UT) axis — ecliptic longitude, latitude and distance from the shared
84
93
  Meeus series over framework-native arguments), `eclipse` (geocentric
85
94
  solar/lunar eclipse search over a JD window, greatest-eclipse convention),
86
- `climate` (the L1 orbital-forcing formula) and `planets` (the retired integer-law
87
- records and orientation at epoch). Validation targets are refused as
95
+ `climate` (the L1 orbital-forcing formula) and `planets` (the N-body chain's
96
+ elements of date — perihelion longitude, node and inclination on the
97
+ invariable plane, eccentricity — and spin). Validation targets are refused as
88
98
  inputs — a counterfactual cannot move the goalposts it is judged by.
89
99
 
90
100
  ### The series artifact
@@ -105,7 +115,7 @@ createModel().earth.eccentricity(2000 - 100000); // 0.03374 — the mode table
105
115
  Without the artifact `createModel()` evaluates the embedded 18-term mode
106
116
  table at every epoch: exact at J2000, a compact approximation away from it
107
117
  (RMS 3.6·10⁻³ in e against La2010a over the last 500 kyr, where the series
108
- reads 2.5·10⁻⁵). The hosted API, the MCP server and the simulator always
118
+ reads 2.5·10⁻⁵). The API handler, the MCP server and the simulator always
109
119
  pass the artifact.
110
120
 
111
121
  ## Underneath: a parts library
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@essrt/physics",
3
- "version": "17.0.0",
3
+ "version": "18.0.1",
4
4
  "description": "ESSRT (Expanding Solar System Resonance Theory) physics core — pure, injectable-constants, no I/O, no globals, no DOM. The complete model incl. fitted coefficients; every published version immutably ships one recorded model identity.",
5
5
  "essrt": {
6
6
  "modelVersion": "v21.0",
package/src/index.js CHANGED
@@ -126,7 +126,7 @@ export { computeEarthFrameOfDate, solveWheelAngleForLongitude } from './earth/fr
126
126
  // (planets/fibonacci-laws), the record-based orientation forms
127
127
  // (planets/orientation) and the ascending-node integrator
128
128
  // (planets/asc-node-integrator) are DELETED at plan 07 R5/R6: the planets'
129
- // elements of date have one home, the N-body chain; docs/retired-record.md.
129
+ // elements of date have one home, the N-body chain.
130
130
  export { derivePlanetGeometry } from './planets/geometry.cjs';
131
131
  export { eccentricityFromCycles, computeEccentricityIntegrated } from './planets/ecc-channel.cjs';
132
132
  export * as planetOrbitChain from './planets/orbit-chain.cjs';
@@ -156,7 +156,7 @@ export { createYearLengths, ONE_FAMILY_WINDOW_YEARS } from './earth/year-lengths
156
156
  // leg-1's physical rate; the structural H(t)/13 clock is its named diagnostic.
157
157
  export { computeSolarTorqueShare, createComposedPrecession } from './earth/precession-composed.cjs';
158
158
  // (planets/predict.cjs — the planet predictive-precession feature basis — was
159
- // retired at plan 06 R8 with PREDICT_COEFFS_PHYSICAL; docs/retired-record.md.)
159
+ // retired at plan 06 R8 with PREDICT_COEFFS_PHYSICAL.)
160
160
  // L10 — the composition front door: one law set, N body records. Thin by
161
161
  // design; engines keep their direct call sites (see planets/model.cjs).
162
162
  export { createPlanetModel } from './planets/model.cjs';
package/src/model.js CHANGED
@@ -646,11 +646,30 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
646
646
  /** @param {number} year @returns {number} */
647
647
  const tropicalYearDirectDays = (year) => evalYearFourier(year, tropicalYearDaysBase(year), F.TROPICAL_YEAR_HARMONICS);
648
648
 
649
- /** @param {number} year @returns {number} */
650
- const solarYearSeconds = (year) => tropicalYearDays(year) * dayLengthSeconds(year);
651
- /** @param {number} year @returns {number} */
652
- const siderealDaySeconds = (year) => solarYearSeconds(year) / (tropicalYearDays(year) + 1);
653
- /** @param {number} year @returns {number} */
649
+ /** Layer-4 solar day of date in SI seconds — LOD_real, the shipped
650
+ * observable (the tweakpane Solar Day row, the registry's lodRealPhysical,
651
+ * the Framework Verification panel's day): the kinematic day of date + the
652
+ * ecliptic missing-motion term on the nodal period + the calibrated ΔT
653
+ * cycle stack incl. the core-mantle swing. Twin of tools/lib
654
+ * computeLodRealSecondsAtEpoch and the browser's _vfpSolarDaySecondsOfDate
655
+ * (86,400.001780 s at 2000). @param {number} year @returns {number} */
656
+ const lodRealSeconds = (year) =>
657
+ dayLengthSeconds(year)
658
+ + (deepLod.eclipticLodCorrectionSecondsAtAge(yearToTMa(year)) ?? 0)
659
+ + dtCycleLodCorrectionSum(year);
660
+ /** Mean sidereal day of date in SI seconds — on LOD_real (plan 08 storyline
661
+ * sweep, 2026-10-09: the published day bases are the SI day of exactly
662
+ * 86,400 s, the IAU constants, and LOD_real; this rode the KINEMATIC day
663
+ * before, 1.7 ms below the simulator's readout at J2000). One rotation
664
+ * more against the equinox than there are solar days in a year.
665
+ * @param {number} year @returns {number} */
666
+ const siderealDaySeconds = (year) => {
667
+ const Y = tropicalYearDays(year);
668
+ return (lodRealSeconds(year) * Y) / (Y + 1);
669
+ };
670
+ /** Mean stellar day of date in SI seconds — the sidereal day plus the
671
+ * equinox's daily regression projected onto the equator (on LOD_real, like
672
+ * the sidereal day). @param {number} year @returns {number} */
654
673
  const stellarDaySeconds = (year) => {
655
674
  const tMa = yearToTMa(year);
656
675
  // S5 (plan 06): one equinox turn per T_p(t) — the composed lunisolar
@@ -658,13 +677,12 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
658
677
  // unit's counter H(t)/13 (0.086 % slow; 7 µs on the 8.37 ms offset).
659
678
  const TpRaw = deepLod.lunisolarPrecessionPeriodYearsAtAge(tMa);
660
679
  const Tp = TpRaw === null ? certifiedAxialPrecessionJ2000Years() : TpRaw;
661
- const syS = solarYearSeconds(year);
662
680
  const syD = tropicalYearDays(year);
663
681
  const sidDay = siderealDaySeconds(year);
664
682
  // Layer A (plan 06): the RA projection reads the published ε (the one-source
665
683
  // hybrid), not the K comb — the browser's _sceneEpsTargetDeg twin; 1e-8 s.
666
684
  const raProjection = Math.cos((oneSourceM.epsAt(year) * Math.PI) / 180);
667
- return (syS / (syD + 1) / Tp / (syD + 1)) * raProjection + sidDay;
685
+ return (sidDay / Tp / (syD + 1)) * raProjection + sidDay;
668
686
  };
669
687
  /** @param {number} year @returns {number} */
670
688
  const measuredSolarDaySeconds = (year) => dayLengthSeconds(year) + raDayOffsetMs(year) / 1000;
@@ -1488,7 +1506,15 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
1488
1506
  epoch: Object.freeze({
1489
1507
  yearToTMa,
1490
1508
  hAtYear: /** @param {number} year @returns {number|null} */ (year) => deepLod.hAtAge(yearToTMa(year)),
1509
+ // The Layer-2 mean day of date — the tidal + GIA base the deep-time law
1510
+ // gives at any age (86,399.9997 s at J2000): the day the paleo anchors
1511
+ // and the ΔT integrand ride. NOT the observable solar day of date —
1512
+ // that is lodRealSecondsAtYear below (plan 08 storyline sweep).
1491
1513
  lodSecondsAtYear: /** @param {number} year @returns {number|null} */ (year) => deepLod.lodSecondsAtAge(yearToTMa(year)),
1514
+ // LOD_real of date — the Layer-4 observable (the simulator's Solar Day,
1515
+ // the registry's lodRealPhysical): the kinematic day + the ecliptic term
1516
+ // + the calibrated ΔT cycle stack. 86,400.001780 s at J2000.
1517
+ lodRealSecondsAtYear: /** @param {number} year @returns {number} */ (year) => lodRealSeconds(year),
1492
1518
  alphaAtYear: /** @param {number} year @returns {number} */ (year) => earthMoiFactorAtAge(yearToTMa(year)),
1493
1519
  moonDistanceKmAtYear: /** @param {number} year @returns {number} */ (year) => moonDistanceMetresAtAge(yearToTMa(year)) / 1000,
1494
1520
  // D6: OF-DATE — mass-loss law / the banked planetary λ̇ ratio
@@ -1600,6 +1626,7 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
1600
1626
  siderealYearDays,
1601
1627
  anomalisticYearDays,
1602
1628
  dayLengthSeconds,
1629
+ lodRealSeconds,
1603
1630
  siderealDaySeconds,
1604
1631
  stellarDaySeconds,
1605
1632
  measuredSolarDaySeconds,
@@ -14,7 +14,7 @@
14
14
  * inclination amplitude/mean; K constant → eccentricity amplitude/base/
15
15
  * phase) are DELETED — K at plan 07 R6, ψ at plan 07 R5. A planet's
16
16
  * inclination and eccentricity of date have one home, the N-body chain
17
- * (model.js planetChainElementsAt); docs/retired-record.md is the record.
17
+ * (model.js planetChainElementsAt).
18
18
  *
19
19
  * THIN BY DESIGN. This is the composition surface, not a rewiring: both
20
20
  * engines keep their existing direct call sites, and the runtime channels
package/types/model.d.ts CHANGED
@@ -28,6 +28,7 @@ export function assembleModel(C: Readonly<Record<string, any>>, F: Readonly<Reco
28
28
  yearToTMa: (year: number) => number;
29
29
  hAtYear: (year: number) => number | null;
30
30
  lodSecondsAtYear: (year: number) => number | null;
31
+ lodRealSecondsAtYear: (year: number) => number;
31
32
  alphaAtYear: (year: number) => number;
32
33
  moonDistanceKmAtYear: (year: number) => number;
33
34
  siderealYearSecondsAtYear: (year: number) => number;
@@ -86,6 +87,7 @@ export function assembleModel(C: Readonly<Record<string, any>>, F: Readonly<Reco
86
87
  siderealYearDays: (year: number) => number;
87
88
  anomalisticYearDays: (year: number) => number;
88
89
  dayLengthSeconds: (year: number) => number;
90
+ lodRealSeconds: (year: number) => number;
89
91
  siderealDaySeconds: (year: number) => number;
90
92
  stellarDaySeconds: (year: number) => number;
91
93
  measuredSolarDaySeconds: (year: number) => number;