← Back to the visualiser

The maths behind the Sunset Visualiser

Every formula the page uses, the function that implements it, and the numbers it produces. Each figure quoted here comes from running that code, not from a textbook or an estimate.

  1. Conventions
  2. The Sun’s angular diameter
  3. Where the Sun is
  4. Where the Sun appears from the ground
  5. Globe model: why the Sun doesn’t shrink
  6. Flat model: why it would
  7. Refraction
  8. The camera
  9. What is decorative
  10. Known simplifications
  11. Headline results
  12. Sources

All the physics lives in js/physics/ as small pure functions with no dependencies. Nothing in js/render/ or js/main.js computes a physical quantity; those files only draw numbers they are handed. The verification suite checks the physics against published values, closed-form identities, and independent derivations of the same quantity that would disagree if either were wrong.

1Conventions

QuantityValueWhere
Astronomical unit149,597,870.700 km (exact)constants.js AU_KM
Solar radius695,700 km (IAU nominal)constants.js R_SUN_KM
Earth radius6,378.137 km (WGS-84 equatorial)solar.js R_EARTH_KM
Mean solar day86,400 sconstants.js SOLAR_DAY_S

2The Sun’s angular diameter

solar.js → angularDiameterDeg(distanceKm)

A sphere of radius r seen from distance d to its centre subtends

θ = 2 · arcsin( r / d )

Note that this is arcsin, not arctan. The sight lines graze the limb, so they are tangent to the sphere and do not pass through its centre plane. The test suite pins this down with a sphere at d = 2r, which must subtend exactly 60°.

At 1 AU: θ = 0.53291° = 31.97′.

3Where the Sun is

solar.js → solarPosition(date)

This uses the U.S. Naval Observatory / Astronomical Almanac low-precision formulae, accurate to about 0.01° in ecliptic longitude between 1950 and 2050. With n = days since J2000.0 (2000 January 1, 12:00 TT):

L = 280.460° + 0.9856474° n mean longitude g = 357.528° + 0.9856003° n mean anomaly λ = L + 1.915° sin g + 0.020° sin 2g ecliptic longitude ε = 23.439° − 0.0000004° n obliquity of the ecliptic δ = arcsin( sin ε · sin λ ) declination D = 1.00014 − 0.01671 cos g − 0.00014 cos 2g AU Earth–Sun distance
CheckThis codePublished
Declination at J2000.0−23.03°−23.03°
Earth–Sun distance at J2000.00.98331 AU0.98330 AU
September 2026 equinox (δ = 0)00:17 UTC, 23 Sep00:05 UTC, 23 Sep
Perihelion / aphelion 20260.9833 / 1.0167 AU0.9833 / 1.0167 AU

The equinox lands 12 minutes off, which is within the formula’s stated accuracy.

4Where the Sun appears from the ground

4.1 Altitude

solar.js → altitudeGeocentricDeg(lat, dec, H)
sin a = sin φ · sin δ + cos φ · cos δ · cos H

For an observer on the equator (φ = 0) at an equinox (δ = 0), this reduces to a = 90° − H. The Sun is at exactly 45° at 15:00 and 0° at 18:00, descending at exactly 15° per hour. That is why the default scenario uses this case: the arithmetic is checkable by hand.

altitudeTopocentricDeg then subtracts diurnal parallax, at most 8.79″ for the Sun. That is negligible, but it is included.

4.2 The central angle

solar.js → centralAngleDeg, groundDistanceToSubsolarKm

The subsolar point is where the Sun is directly overhead. The angle at Earth’s centre between the observer and that point is

ψ = 90° − a

The great-circle ground distance to it is (with ψ in radians). At 15:00 in the default scenario that is 5,009.4 km. This is a measurable distance on the real Earth, and it matters in §6.

4.3 Sunset

solar.js → hourAngleAtAltitude(lat, dec, h0)
cos H0 = ( sin h0 − sin φ · sin δ ) / ( cos φ · cos δ )

With h0 = 0 (geometric sunset, the Sun’s centre on the horizon) this gives H0 = 90°, so sunset is at 18:00. The function returns null when |cos H0| > 1, which is polar day or night; the app then refuses to build a scenario rather than inventing one.

4.4 The sea horizon

solar.js → horizonDipDeg, horizonDistanceKm

For an eye at height h above a spherical sea:

dip = arccos( R / (R + h) )     distance = √( h (2R + h) )

At 1.7 m the dip is 2.51′ and the horizon is 4.66 km away.

5Globe model: why the Sun doesn’t shrink

5.1 Observer–Sun distance

globe.js → observerSunDistanceKm(D, a)

The observer stands at distance R from Earth’s centre and the Sun is at distance D. The angle between those directions, at Earth’s centre, is ψ. By the law of cosines:

d² = D² + R² − 2DR · cos ψ = D² + R² − 2DR · sin a

since cos ψ = sin a. The test suite checks two exact cases: with the Sun overhead, d = DR; with the Sun on the horizon, d = √(D² + R²).

5.2 Two effects change the distance, and both are included

Effect15:00 → 18:00
Rotation. The observer is carried from 45° to 0° altitude, moving them about R cos 45° further from the Sun.+4,510 km
Orbit. In September Earth is heading towards perihelion, so the Earth–Sun distance D itself shrinks.−5,244 km
Net−734 km

The observer–Sun distances the code produces are 150,107,466 km at 15:00 and 150,106,732 km at 18:00. The net change is 734 km out of 150 million, or 0.0005%.

The distance goes down, so on this date the Sun is very slightly larger at sunset than three hours earlier. Most treatments quote only the rotational term, which would overstate the change, so the code computes both.

5.3 The resulting angular size

Angular diameter
15:000.531097°
18:000.531100°
Change+0.0094″ (+0.0005%)

The unaided eye resolves about 60″, which is more than 6,000 times this change.

5.4 Rate of change

globe.js → angularRateBreakdown(t), angularRateDegPerHour(t)

Differentiating θ = 2 arcsin(r/d):

dθ/dt = −2 (r/d²) / √(1 − (r/d)²) · dd/dt

Differentiating d² = D² + R² − 2DR sin a splits the distance rate into exactly the two effects above:

d · dd/dt = (DR sin a) dD/dtRD cos a · da/dt first term orbital, second term rotational

dD/dt and dδ/dt come from differentiating the ephemeris series in §3, and da/dt from differentiating §4.1 with dH/dt = 15° per hour. The ephemeris series run in hours of UTC while the app’s clock is apparent solar time; the two drift apart by about 2 parts in 10,000 through the equation of time, and the analytic form corrects for it. That correction matters here only because the two terms nearly cancel.

AtRotationalOrbitalTotal
15:00−0.01504″/h+0.02226″/h+0.00722″/h
18:00−0.02127″/h+0.02227″/h+0.00100″/h

How this is verified. The numerical rate (a central difference on the sampled curve) and the analytic rate above are written independently and share no algebra. The suite requires them to agree to 1 part in 100,000 of the terms’ magnitude, at five points across the window.

6Flat model: why it would

flat.js → makeFlatModel

6.1 The model

The ground is a plane. The Sun is a small sphere at constant height h above it, travelling horizontally away from the observer in a straight line. This is the most charitable version of the flat model, and its speed is the measured speed of the subsolar point over the real ground:

v = 2πR cos δ / 24 h = 1,669.8 km/h at the equator

At the equator this agrees exactly with the arc length in §4.2: 5,009.4 km = v × 3 h. The suite checks the two routes agree to one part in 1012.

6.2 Where the flat Sun starts

A flat model has to put the Sun somewhere at 15:00, and there are two defensible ways to do it. The app offers both.

Match the real elevation (the default). Start the Sun at the elevation the real Sun actually has:

x0 = h / tan a0

Both camera views then begin identical, so every later difference comes from the model alone. The cost is an inconsistency, which the app reports on screen rather than hiding: at h = 1,000 mi the Sun must start 1,609 km away horizontally, but the real subsolar point is 5,009 km away.

Above the real subsolar point. Set x(t) = (t), the measured ground distance. This has no free parameters, but the Sun then starts at the wrong elevation: 17.81° at 1,000 mi instead of 45°.

The two agree at exactly one height, h ≈ 5,009 km, which is offered as a preset.

6.3 The Sun’s size is derived, not assumed

The flat Sun’s physical radius is set so that it has the real angular diameter at the start of the window:

d0 = √(x0² + h²)     r = d0 · sin( θ0 / 2 )

At 1,000 mi that gives a Sun 21.10 km across. The model is handed the correct starting appearance for free and only has to get the next three hours right.

6.4 What happens next

x(t) = x0 + v (tt0) d(t) = √(x² + h²) θ(t) = 2 arcsin( r / d ) a(t) = arctan( h / x )
15:0018:00 (real sunset)
Horizontal distance1,609 km6,619 km
Line of sight2,276 km6,812 km
Angular diameter0.5311°0.1775° (33.4% of start)
Elevation45.00°13.67°

The Sun shrinks by 21.22′, which is 136,140× the globe model’s change. And since a = arctan(h/x) is positive for any finite x, the flat Sun can never set. It only approaches the horizon asymptotically.

6.5 Rate of change

With the elevation anchor x is linear in t, so dd/dt = xv/d and

dθ/dt = −2 (r/d²) / √(1 − (r/d)²) · xv/d

Where the shrink is fastest. Since θ ≈ 2r/d, the rate goes as x/(x²+h²)3/2, which peaks at x = h/√2, where the elevation is arctan√2 = 54.7°. The window starts at 45°, already past that peak, so the flat Sun shrinks fastest at the start and slows down: −16.53″ per minute at 15:00, −2.54″ per minute at 18:00. That is the shape of the curve in the rate chart.

How this is verified. The suite compares this closed form with a central difference, then halves the differentiation step four times and requires the gap to fall by 4× each time. That is second-order convergence, which shows the remaining gap is truncation error in the numerical derivative and not an algebra error in either form.

6.6 How high would the flat Sun need to be?

flat.js → minimumHeightForImperceptibleShrink

Bisection on h for the lowest height at which the shrink across the window stays under 1′, the naked-eye limit:

Start positionMinimum heightElevation at real sunset
Match the real elevation78,504 km (6.2 Earth diameters)43.2°
Above the real subsolar point33,439 km73.3°

At those heights the flat model hides the shrink only by failing to set at all.

6.7 The other flat model: the Gleason map

flat.js → makeFlatModel({ path: 'gleason' })

The local-plane version above is a steelman: it is handed the measured speed of the subsolar point and asked only to move in a straight line. The maps flat-Earth arguments actually use are azimuthal-equidistant discs — the Gleason map and its relatives — with the north pole at the centre and distance from the pole preserved:

r(φ) = R (π/2 − φ)so the north pole is 0, the equator 10,019 km out, and the south pole is smeared round the rim

Choose that map and nothing is left to fit. The Sun circles above the latitude of its own declination, and the observer sits on his own circle, so the distance between them is the cosine rule about the pole, with the hour angle as the included angle:

x(t) = √( robs² + rsun² − 2 robs rsun cos H )

Three consequences follow, none of them chosen:

This map saysMeasured
Length of the equator62,950 km40,075 km
Sun's speed over the ground2,628 km/h1,670 km/h
Bearing of the Sun at sunset, equator, equinox315° (north-west)270° (due west)

The equator comes out longer by exactly π/2, which is 57%, and everything else follows from that. It is not a subtle discrepancy: it is checkable by flying between two points on the equator and timing it, or by watching where the Sun actually sets with a compass. A 45° error in bearing is the width of half the sky.

An honest surprise: on angular size this map does better than the steelman, not worse. The obvious guess is that a Sun moving half as fast again must shrink faster. It does not, because the map also starts it 7,676 km away rather than 1,609 km, and the extra starting distance more than cancels the extra speed. Its Sun ends at 54.9% of its width, against 33.4% for the elevation-matched local plane.

That is still a 45% loss of width where the real Sun changes by 0.0094″, and it is still about 92,000 times the globe model's change. The map buys a slightly better answer on this one question by being flatly wrong about where the Sun is in the sky.

The plan-view inset in the flat side panel shows the map itself: the pole, the observer's circle, the Sun's circle, and the line between them, because the elevation view alone cannot show a Sun that swings round rather than receding in a straight line.

Which way round it goes. The Sun's longitude east of the observer is −H: it is overhead at solar noon and falls away westward all afternoon. Viewed from above the north pole, eastward runs counter-clockwise, so westward travel is clockwise, and that is how the inset draws it, with an arrow on the leading edge. The sign matters more than it looks: get it wrong and the picture is a view of the disc from underneath, which would disagree with the bearing the model reports for the same instant. The test suite pins the longitude falling through the whole window and the Sun staying in the western half of the sky.

6.8 What latitude changes

The equator is where the flat model fares worst: the Sun starts highest, and so nearest, and then recedes furthest in relative terms. Moving away from it softens the contrast without coming close to rescuing the model.

ObserverSun at 15:00Globe changeFlat Sun ends atRatio
Equator45.0°+0.0094″33.4% of its width136,150×
Melbourne, 37.8°S34.0°+0.0214″38.0%55,374×
London, 51.5°N26.0°+0.0311″43.4%34,876×
80°N6.9°+0.0568″72.7%9,169×

Even at 80°, where the Sun only creeps down a shallow slope, the flat model still loses more than a quarter of the Sun’s width while the real one changes by six hundredths of an arcsecond. The globe figures grow with latitude because the Sun spends the window nearer the horizon, where the observer’s rotation carries them away from it most directly. They stay thousands of times too small to see.

7Refraction

refraction.js

Standard air by default, and applied equally to both models. Real sunsets happen in an atmosphere, and the comparison does not depend on refraction either way, because it acts on the vertical axis only (§7.2). “Off (pure geometry)” is one of the presets if you want the bare geometry.

Sæmundsson (1986), from true altitude h — the direction the app uses, since geometry is computed first:

R = 1.02′ / tan( h + 10.3 / (h + 5.11) )

Bennett (1982), from apparent altitude ha, used to cross-check that the two are mutual inverses:

R = 1′ / tan( ha + 7.31 / (ha + 4.4) )

7.1 How much refraction: the settings

Both formulae are written for 1010 hPa and 10 °C, and scale for other conditions as

factor = (P / 1010) · (283 / (273 + T)) · scale

Denser air bends light more, so refraction rises with pressure and falls with temperature. Each preset’s label is generated at runtime from the functions themselves, so a label can never advertise a figure the code does not produce.

PresetConditionsRefraction at the horizon
Offpure geometry0
Standard air (default)1010 hPa, 10 °C29.0′
Hot day1005 hPa, 40 °C26.1′
Cold day1020 hPa, −20 °C32.7′
Cold, high pressure1040 hPa, −30 °C34.8′

That is the whole range, and it is narrow: across all ordinary weather the scaling spans only about ±10%.

Why there is no “mirage” preset. Real horizon refraction varies far more than weather scaling suggests, because it is governed by the temperature profile of the lowest few hundred metres of air. A strong inversion over cold water can multiply it several times over, produce mirages, stack and invert images, and in the Novaya Zemlya effect lift a Sun that set days ago.

Neither formula here models any of that. Doing it properly means ray tracing through a temperature profile, including ducting and the multiple images it produces — a different piece of work. Rather than offer a multiplier dressed up as a setting, this page offers only conditions the formulae are actually valid for, and answers the mirage question with the argument in §7.2 instead, which does not depend on modelling it.

7.2 What refraction does, and what it cannot do

refraction.js → apparentDiscDeg

It lifts the Sun, so at geometric sunset the Sun appears about half a degree above the horizon and real sunset comes a few minutes later. And because it lifts the lower limb more than the upper limb, it squashes the disc vertically: to 85.5% of its width in standard air, and to 42% under the ×4 preset.

The key property, and it is a theorem rather than a result of these formulae. Refraction is a function of altitude alone. Two points at the same altitude are therefore displaced identically, so the horizontal diameter of the disc cannot change — at any strength, under any profile, including ones nobody can compute. All refraction can do is move the limbs vertically relative to each other, squashing the disc, or in the extreme turning the image over.

That is what settles the mirage question without modelling a mirage. The flat model needs the Sun to lose 67% of its width. Refraction cannot take away any of it.

The suite checks the width is untouched to the last bit for every preset at eleven altitudes from 45° down to 4° below the horizon, and separately at 2, 4 and 8 times standard refraction — strengths no preset offers — to show the property does not depend on the setting. At 8 times, the lower limb overtakes the upper one and the image inverts, which the code reports as a flag rather than as a negative height.

Horizon dip. With refraction on, the sea-horizon dip uses the navigational value 1.76′√h[m], which is 2.29′ at 1.7 m against a geometric 2.51′ (Bowditch). On the flat model the horizon is the vanishing line of the plane, at exactly 0°.

7.3 Where the formulae stop working

Both formulae contain an inner term of the form h + k/(h + c), which has a minimum at h = √kc. Below that altitude the term turns and refraction starts falling with depth, which is not what real air does. Applied to a disc it is worse than wrong: the upper limb would get more refraction than the lower, stretching the Sun vertically instead of squashing it.

FormulaValid down toMaximum modelled refraction
Sæmundsson (true altitude)−1.901°44.65′ in standard air
Bennett (apparent altitude)−1.696°

Nothing you can see depends on the clamp. Under every preset the Sun’s upper limb is already below the horizon before its altitude reaches the limit — between 0.76° and 0.98° below it, depending on the preset, which the test suite checks. Past that the Sun is hidden by the sea, and the readouts say “not modelled this low” instead of quoting a number.

Below those altitudes the code holds refraction at its maximum modelled value rather than following the formula down. The test suite walks both formulae from 60° down to −6° and requires that refraction never decreases, and checks the disc is never widened at any altitude down to 4° below the horizon under every preset.

What the clamp is. A guard against nonsense, not a description of the air. Down there real refraction keeps growing and keeps squashing the disc — that is what produces the flattened, stacked and omega-shaped Suns in mirage photographs — so a held value is wrong. It is wrong in the safe direction, understating refraction rather than inventing a stretched Sun, and it governs nothing that is on screen.

This matters in practice because the timeline runs to 4° below the horizon, so that the disc can be seen to set even under the ×4 preset, which lifts it by nearly 3°.

8The camera

optics.js

8.1 Lens

A pinhole (rectilinear) lens on a full-frame 36 × 24 mm sensor. Focal length refers to the 24 mm height, because vertical framing is what this scene is about; the horizontal field extends to fill the pane.

vertical field of view = 2 · arctan( 12 mm / f )

At 24 mm that is 53.13°.

8.2 Projection

optics.js → project, projectVector, discOutline

A direction in local east–north–up coordinates, seen by a camera with basis (forward , right , up ), lands at

x = fpx ( · ) / ( · )     y = fpx ( · ) / ( · )     fpx = Hpx · f / 24 mm

The Sun’s outline is built on the sphere and then projected, so the lens distorts it exactly as a real lens would rather than being drawn as a circle and hoped for.

8.3 Framing

optics.js → pitchForHorizonFractionDeg, defaultFraming

To put the horizon a fraction k of the frame height above the bottom edge:

tan(pitch) = (1 − 2k) · tan( vfov / 2 )

The default lens is the longest common focal length that fits everything from the horizon to the top of the Sun at 15:00 (45° + θ/2 = 45.27°) with 2% margins:

f ≤ 12 mm (1 − 2 × 0.02) / tan(45.27° / 2) = 27.63 mm

The longest common lens that fits is therefore 24 mm. The horizon then sits 8.31% of the frame height above the bottom, and that fraction is held fixed as the lens is changed.

Away from the equator the Sun sets at a slant, so it tracks sideways as it goes: about 32° of bearing across the window at Melbourne, 38° at London. The frame has to hold that too, so the lens is the shorter of the two limits, measured against a 3:2 frame (real panes are wider, so this is the conservative test), and the camera faces the Sun’s mean bearing rather than its bearing at sunset.

That leaves vertical slack, because a low Sun needs little height. Centring the content would then float the horizon up the middle of the frame and fill the bottom half with sea, so the horizon is capped at 12% of the frame height and the slack goes to the sky instead. The suite checks that the Sun and the horizon are both still inside the frame across the range of latitudes the picker allows.

8.4 Why the loupe is a separate camera

A rectilinear lens stretches objects off-axis. At 24 mm the Sun at 45° is 22.6° off-axis, where a disc is drawn 16.9% taller than on-axis.

That is correct lens behaviour, and the main view reproduces it. But magnifying that frame would make the Sun appear to change size as it crossed it — exactly the effect under test. So the loupe is a second camera aimed straight at the Sun, where the disc is undistorted. The suite verifies that a disc viewed head-on spans exactly 2f tan r in both axes, at any altitude.

It defaults to 1600 mm, a 0.86° field, in which the Sun fills about 62% of the height. Where the pane is wide enough, the loupe is a full-height panel beside the frame rather than an inset on top of it.

8.5 Glow brightness

Two things change how much light arrives. One is the Sun’s angular area, since surface brightness does not change with distance, so flux follows the solid angle. The other is the air.

8.6 Extinction, and why people think the Sun shrinks

extinction.js

Light from a low Sun crosses far more atmosphere than light from a high one. The standard fit for how much more is Kasten & Young (1989):

X = 1 / ( sin h + 0.50572 (h + 6.07995)−1.6364 )airmass: 1.00 overhead, 1.41 at 45°, 37.92 at the horizon

and the loss is the usual magnitude law, transmittance = 10−0.4kX. With k = 0.15 magnitudes per airmass the total dimming from overhead to the horizon comes to about 5.5 magnitudes, a factor of roughly 165 — consistent with the drop from ~100,000 lux at midday to ~500 lux at a clear sunset. A single coefficient is an approximation: real extinction is Rayleigh scattering plus aerosol plus ozone, and the aerosol part varies by a factor of several with haze. It is the right trend and the right order of magnitude, not photometry.

Put the two together and the globe model predicts this:

Angular diameterLight reaching you
15:000.5311°100%
Sunset0.5311°1.6%

This is the honest version of “the Sun looks smaller at sunset”. Something really does shrink, by a factor of sixty: the glare. At midday the Sun is so far past what an eye or a sensor can hold that it blooms into a patch many times the disc; by sunset it is faint enough to look at, and the bloom collapses onto the disc.

The disc inside it never moved. That is what the loupe on this page is for: the wide view shows the glare shrinking, and the magnified view beside it shows the disc against a dashed ring at its starting size, unchanged. If you have ever watched a sunset and felt the Sun get smaller, this is almost certainly what you were watching.

Where the physics stops and the drawing starts. The flux is computed. Turning it into a radius is not. Veiling glare in an eye or a lens falls off roughly as the inverse square of angle — the Stiles–Holladay form — so the radius at which it drops below a fixed visibility threshold goes as the square root of the flux, and that is the rule the renderer uses. Opacity is held constant, because both eye and camera re-expose as the scene darkens; anything else would make the glare fade rather than contract, and an altitude term would make it appear to grow towards sunset as the sky went dark behind it. It is a plausible rule, not a scattering model, and both panes use the identical one.

The progression is not linear, and should not be: from 45° down to about 18° the glare barely changes, because the air in the way has barely changed. Almost all of the collapse happens in the last few degrees, which is exactly when people say the Sun looks like it is shrinking.

9What is decorative

These carry no part of the argument, and both models use the same functions for them:

10Known simplifications

SimplificationSize of effectWhy it cannot change the conclusion
Spherical Earth; oblateness 0.34% ignoredChanges R by at most 21 km, so the 4,510 km rotational term by at most ~15 kmMoves the globe result by at most ~0.0003″
Low-precision ephemeris~0.01° in solar longitudeThe globe result depends on distance changes of thousands of km; the ephemeris is far better than that
Flat Sun moves in a straight line (now optional)The azimuthal-equidistant map is offered too, and circles the Sun at 2,628 km/h (§6.7)Neither is the flat model’s best case on every count: the map shrinks the Sun less but puts it 45° wrong in bearing
Declination held fixed for the flat Sun’s speedδ changes ~0.05° across the windowChanges v by about 3 parts in a million near the equinox
Refraction formulae, and the scale knobUnreliable below about −1°; inversions are not modelled, only approximated by a multiplierRefraction cannot alter the disc’s width at any strength (§7.2)
Naked-eye resolution taken as 1′A rule of thumbThe globe change is 6,000× smaller; the threshold could be wrong by 1,000× without mattering

11Headline results

Default scenario: equator, 23 September 2026, 15:00 → 18:00 apparent solar time, flat Sun at 1,000 mi starting at the real elevation.

GlobeFlat
Angular diameter at 15:000.531097°0.531097° (calibrated)
Angular diameter at 18:000.531100°0.1775°
Change+0.0094″−1,273″ (−21.22′)
Size at 18:00 vs 15:00100.0005%33.4%
Altitude at 18:000.00°13.67°
Distance to Sun, change−734 km+4,536 km
Light received at 18:00 vs 15:00100.001%11.2%

The flat model’s change is 136,140× the globe model’s.

12Sources

Every constant and formula in js/physics/ traces to one of these.

Constants

ValueSource
Astronomical unit, 149,597,870,700 m (exact)IAU 2012 Resolution B2, Re-definition of the astronomical unit of length
Nominal solar radius, 6.957 × 108 mIAU 2015 Resolution B3, Recommended nominal conversion constants for selected solar and planetary properties
Earth equatorial radius, 6,378,137 mWorld Geodetic System 1984 (WGS-84), NIMA Technical Report TR8350.2
Earth mean radius, 6,371,008.8 mMoritz, H. (2000), Geodetic Reference System 1980, Journal of Geodesy 74, 128–133
Mean sidereal day, 86,164.0905 sIERS Conventions (2010), IERS Technical Note 36
International mile 1,609.344 m; foot 0.3048 m (exact)International Yard and Pound Agreement (1959)

Solar position

Extinction

Refraction and horizon dip

Values used to check the code

CheckValueSource
Solar declination and distance at J2000.0−23.03°, 0.98330 AUThe Astronomical Almanac for 2000
September 2026 equinox2026-09-23 00:05 UTCUSNO Earth’s Seasons; also EarthSky and Star Walk
Perihelion and aphelion distances0.9833 AU, 1.0167 AUThe Astronomical Almanac
Refraction at the horizonabout 34′Bennett (1982); standard navigational tables
Equation of time, early Novemberabout +16.4 minThe Astronomical Almanac

Rules of thumb, flagged as such where used