A single-point solar calculation — “what is the sun doing at the origin right now?” — would give a misleading answer for any trip that lasts more than a few minutes: the vehicle moves, and so does the Earth relative to the sun. Helios solves this by treating the journey as a continuous great-circle arc. It moves an imaginary vehicle along that arc at constant speed and, as the vehicle travels, samples solar events (sunrises and sunsets) at the vehicle’s current interpolated position. The result is a list of timestamped, geo-located solar events that divides the journey into discrete daylight sections.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/V3RNE42/helios/llms.txt
Use this file to discover all available pages before exploring further.
Great-circle interpolation
The geometric foundation isgetNewCoords in trigo.js. Given an origin, a destination, and a fraction between 0 and 1, it returns the coordinates of the point that lies that fraction of the way along the great-circle arc:
- Angular distance — the haversine formula converts the latitude/longitude pairs into an angular distance (in kilometres, using an Earth radius of 6,371 km).
- Bearing —
getBearingcomputes the initial compass heading from origin to destination using the standard spherical-trigonometry bearing formula. - Destination coordinates —
getDestinationCoordsprojects from the start point along the computed bearing forfraction × distancekilometres, returning the interpolated{ lat, lon }object.
fraction value is called RATE inside computeRouteSections and advances from 0 (departure) to 1 (arrival) as the algorithm walks through the journey.
The computeRouteSections loop
computeRouteSections in routeSolar.js is the core of the route model. It accepts the departure and arrival coordinates and timestamps, the getDayInfo solar calculator, and an optional getOffset timezone resolver. It works as follows:
-
Initialise at the origin. Set
RATE = 0(position = origin),datePointer = diasalida(departure time), and callisThereDaylightNowto decide whether to search for the next sunset (if it is already daytime) or the next sunrise (if it is currently night). -
Outer loop — advance through solar events. Repeat until arrival time is reached or the loop budget is exhausted:
- If looking for a sunrise, advance
datePointerby one day so the search window covers the next morning. - Enter the inner convergence loop.
- If looking for a sunrise, advance
-
Inner convergence loop — binary-search-like refinement. Iterate until the difference between two consecutive time estimates is under
MAX_DIFF = 2500milliseconds:- Call
updateTime()to compute the sunset or sunrise time at the current(RATE, coordPoint). - Update
RATEto the fraction corresponding to that time. - Move
coordPointto the newRATEposition. - Check
isThereDaylightNowat the new position. If the vehicle is still on the “wrong” side of the solar event (e.g. still in daylight when searching for a sunset), nudgeRATEforward byincrease; otherwise nudge it backward. This steers the estimate toward the crossing point. - Recalculate
coordPointanddatePointerand measurediff.
MAX_INNER_ITERATIONS = 100000. Exceeding that limit throws an explicit error rather than hanging the browser tab. - Call
-
Record the event. Once converged, push an entry onto the
sectionsarray containing the event type ("sunrise"or"sunset"), the converged timestamp (datePointer), the geographic coordinates (coordPoint), and the UTC offset if local time display is enabled. -
Flip and repeat. Toggle
seekSunsetand return to step 2 to search for the next solar event.
Section formatting
The rawsections array produced by computeRouteSections is a flat list of timestamped solar-event objects bookended by the departure and arrival entries. sectionFormatter in index_def.js transforms this list into paired day-segments:
- The array is sorted chronologically and trimmed so that it always starts with a
sunriseentry and ends with asunsetentry. - Elements are consumed in pairs:
sections[i](sunrise) andsections[i+1](sunset) form one section. - For each pair,
sectionFormattercomputes:noon— the midpoint timestamp between sunrise and sunset:new Date(Math.floor((sunset.getTime() - sunrise.getTime()) / 2) + sunrise.getTime()).noonCoords— the midpoint between the sunrise and sunset geographic coordinates.NaS(North-to-South) —trueif the sunrise latitude is greater than the sunset latitude, meaning the vehicle is moving south through that segment.
Multi-day journeys
The outer loop budget incomputeRouteSections scales with trip duration:
limit = 2, so MAX_LOOPS = 4 — enough for one sunrise and one sunset. A three-day trip gets limit = 6 and MAX_LOOPS = 36. The squaring gives extra headroom for edge cases where more iterations are needed near the poles.
Section structure
AftersectionFormatter runs, the journey looks like this:
NaS direction computed from the interpolated coordinates at that section’s sunrise and sunset events, not from the overall origin-to-destination bearing — so a route that curves significantly mid-journey will have per-section directions that reflect the local bearing at that point in time.