# Universe laboratory models

These small, dependency-free JavaScript ES modules are the exact scientific implementations used by the website. They can be imported in Node.js or a modern browser. They contain original code, licensed with the website’s MIT license. Kepler measurements have their own source credit and data-use terms.

## Moon geometry — `moon-model.mjs`

Version: `distant-sun-1`. Units: degrees; illuminated fractions are dimensionless.

Let θ be orbital progress counterclockwise from new Moon, viewed from above orbital north. The Sun is effectively infinitely far to the right; the Earth-based observer is at the orbit’s center. The cosine of the Sun–Moon–observer phase angle α is −cos θ. Hence the projected illuminated fraction is (1 + cos α)/2 = (1 − cos θ)/2. The bright region is bounded by a circular limb and the projected elliptical terminator. Reflection for waning and rotation of the displayed disk are view operations; neither changes the illuminated fraction.

UI range: 0–360° in 1° steps. The function accepts any finite angle and wraps it modulo 360°. Reference cases: 0° → 0; 90° → 0.5; 180° → 1; 270° → 0.5; 360° → 0. The SVG path uses exact ellipse arcs. Model tests independently integrate projected disk widths rather than only comparing formula copies.

The model is not an ephemeris and predicts no dates, local sky orientation, or eclipses. Sizes and distances in the orbit view are exaggerated. The real orbit is tilted by about 5° relative to Earth’s orbital plane; the drawing flattens that tilt, so alignment in the drawing is not an eclipse prediction.

Source for geometry and phase sequence: NASA Science, [Moon Phases](https://science.nasa.gov/moon/moon-phases/), accessed 27 September 2026. The fraction is also derived above. The site’s diagrams are original and do not trace a source image.

## Transit geometry — `transit-model.mjs`

Version: `uniform-circle-overlap-1`. Length unit: stellar radius. A uniformly bright circular star is occulted by an opaque circular planet. The planet follows a straight projected track at constant speed. With radius ratio k, closest approach b and track position x, the center separation is √(b² + x²). Flux is one minus the overlap area divided by π.

UI bounds: 0.02 ≤ k ≤ 0.5, 0 ≤ b ≤ 1.5, −1.7 ≤ x ≤ 1.7. The general overlap function accepts 0 < k ≤ 1 and nonnegative finite separation. Invalid values throw RangeError. Inverse-trigonometric inputs and small negative roundoff terms are clamped at the geometric boundaries.

Reference cases: k = 0.1, b = x = 0 gives flux 0.99; k = 0.2 gives 0.96. No overlap gives 1. A grazing transit (k = 0.1, b = 1) has a nonzero depth below 0.01. The equal-circle overlap at separation 1 is (2π/3 − √3/2)/π. Tests include contact continuity and independent numerical integration of overlapping vertical chords.

The drawn curve joins 481 exact model samples. A separate test compares interpolation against the analytic curve between those samples across central and grazing examples, with a 0.6 SVG-pixel tolerance. This is a drawing check, not a physical uncertainty or a proof over every possible parameter.

The A/B challenge fixes both plots to the same brightness bounds, 0.95–1.002, and the same track bounds, −1.7–1.7 stellar radii. Thus its 1% and 4% dips appear with a fourfold difference in depth. Independent exploration offers an adjustable scale or fixed brightness bounds 0.68–1.002, which contain every permitted planet size. `transitPlot(k, b, fixedMinimum)` rejects a fixed lower bound that would clip the deepest dip; omitting the third argument retains the adjustable scale. This plotting option changes no overlap geometry.

Horizontal position is proportional to time but is not a measured duration. No stellar radius or projected velocity is fitted. The model omits limb darkening, blending, stellar variability, planetary emission and finite exposure time. It does not measure mass or prove that an observed dip is a planet.

Source: Mandel, K., and Agol, E. (2002), “Analytic Light Curves for Planetary Transit Searches,” *Astrophysical Journal Letters* **580**, L171–L175, § 2, Eq. (1), [doi:10.1086/345520](https://doi.org/10.1086/345520); [author’s open PDF](https://faculty.washington.edu/agol/MandelAgol2002.pdf). Our implementation uses the equivalent circular-segment area expression.

## H–R comparison — `hr-model.mjs`

Version: `stefan-boltzmann-ratios-1`. Inputs: effective temperature in kelvin and radius in solar radii. Output: luminosity in solar luminosities, using the teaching ratio L/L☉ = (R/R☉)² (T/5772 K)⁴. Effective temperature describes total surface emission, not the core temperature.

Bounds: 2500 ≤ T ≤ 30000 K; 0.01 ≤ R/R☉ ≤ 100. The radius slider is logarithmic. The conventional H–R horizontal axis increases in temperature to the left; both axes are logarithmic. Reference cases: (5772 K, 1) → 1; double temperature → 16; double radius → 4; double both → 64.

The Sun is the reference. The four other dots are constructed teaching examples, not estimates for named individual stars. Independently chosen temperature and radius need not correspond to a stable star. Moving a point is not stellar evolution. The 5772 K reference is adopted from [IAU 2015 Resolution B3](https://arxiv.org/abs/1510.07674). The independently rounded IAU nominal constants need not satisfy the Stefan–Boltzmann equation exactly; this lab defines its normalized comparison by the quoted temperature ratio.

## Circular binary — `binary-model.mjs`

Version: `circular-two-body-1`. This original Newtonian model uses masses in
nominal solar units, relative separation in AU, inclination in degrees from
face-on (0) to edge-on (90), and phase in orbital cycles. Bounds: each mass
0.2–20, separation 0.5–20 AU, inclination 0–90 degrees. Phase wraps modulo
one; nonfinite phase and invalid physical inputs throw `RangeError`.

Constants: nominal solar GM = 1.3271244e20 m³/s², exactly, from IAU 2015 B3
([Mamajek et al. 2015, p. 3](https://arxiv.org/pdf/1510.07674)); AU =
149597870700 m exactly ([IAU 2012 B2, recommendation 1](https://iauarchive.eso.org/static/resolutions/IAU2012_English.pdf));
one Julian year = 31557600 seconds. A solar input scales the nominal GM;
the implementation does not multiply separately rounded values of G and mass.

For total mass M and separation a, angular speed is √(GM/a³), period is
2π/angular speed, and radii about the barycentre are a M_B/M and a M_A/M.
For phase angle θ, the first star has coordinates
(a_A cos θ, a_A sin θ cos i, a_A sin θ sin i). The second lies oppositely
with its own radius. The first two coordinates are on the sky; positive z
points away from the observer. Differentiation gives opposite cosine radial
velocities with amplitudes K_A,B = (2π a_A,B/P) sin i. The systemic velocity
is zero. This is the e=0 limit of [Tatum, Celestial Mechanics §18.2,
pp. 2–5](https://www.astro.uvic.ca/~tatum/celmechs/celm18.pdf).

Adding amplitudes and substituting Kepler's relation gives the observable
combination M sin³i = P(K_A+K_B)³/(2πG). The mass ratio M_B/M_A=K_A/K_B
requires a nonzero signal; it is deliberately undefined at exactly face-on.
The lab's comparison presets are (M_A, M_B, a, i) = (0.6, 0.2, 1, 90°)
and (4.8, 1.6, 2, 30°). Multiplying mass by 8 and separation by 2 leaves
a³/M and the period unchanged. Orbital speeds double, while sin i halves,
so both radial-velocity amplitudes remain unchanged. The true total masses
are 0.8 and 6.4 solar masses, with the same projected total mass of 0.8.
Independent inclination or sky-orbit measurements can break this ambiguity.
No eccentricity, stellar radii, eclipses, spectra, tides, noise, interactions,
or relativistic corrections are modeled. Selected points need not represent
a physically stable stellar system over an evolutionary timescale.

The original SVG curves join 241 model points over one orbit. Their velocity
scale is fixed under inclination changes, so projection is not hidden by
rescaling. `node scripts/test-universe-binary.mjs` checks 240 parameter sets
against numerical orbital derivatives and gravitational acceleration,
barycentric momentum, period scaling, input rejection and a pair of different
systems with identical observable curves. The checked curve-interpolation
error is less than 0.01 SVG pixel; that is a drawing tolerance, not a physical
uncertainty. The lab exposes an equivalent semantic table and static example.

## Reproduction commands

Run `node scripts/test-universe-labs.mjs` for the Moon, transit and H–R models, the shared-axis and mass-comparison challenges, and observed-data transformation; run `node scripts/test-universe-binary.mjs` for the binary model. These are scientific model checks; browser accessibility, layout and keyboard behavior are checked separately.

The observed transit excerpt is separately documented in [`../data/README.md`](../data/README.md). The sliders never modify those observations.
