What it is
Nightfall renders the night side of the planet in real time. NASA's VIIRS Black Marble city-lights composite sits beneath a live day/night terminator, all three twilight bands (civil, nautical, astronomical), the subsolar and sublunar points, the current moon phase and illumination, a ±24-hour time scrubber, and a time-lapse mode that sweeps the terminator around the globe. There is no Esri basemap in the app at all — the imagery is NASA GIBS WMTS.
The distinctive engineering is the terminator math. Rather than searching latitude-by-longitude for where the sun sets, Nightfall treats each twilight boundary as exactly what it geometrically is: the sun's altitude at any point equals 90° minus the great-circle distance to the subsolar point, so the region where altitude falls below a threshold h is a perfect geodesic circle — a spherical cap of radius (90° + h) centered on the antisolar point. That yields exact boundaries with no iteration, roughly a hundred times cheaper, and — critically — it stays correct near the equinoxes, where the per-meridian search method breaks because the night cap touches neither pole.
It is a portfolio piece and a conversation starter as much as a tool: an elegant, correct, visibly branded demonstration of ATS's cartographic and mathematical craft, suited to science communicators, educators, planetarium and museum contexts, and anyone who wants to see the shape of night on Earth.
The experience
The app opens on the live view: the night hemisphere sits opposite a glowing gold sun disc, city lights blazing across the dark side.
- Twilight bands. Civil, nautical, and astronomical twilight render as stacked translucent navy caps whose per-layer alphas are solved so each band hits its exact design darkness, even when individual bands are toggled off.
- Sun and moon markers. A glowing gold marker sits at the sun's zenith point and a white marker at the moon's, with the moon-phase name and illumination percentage and a live UTC readout.
- The time scrubber. Drag ±24 hours to move a virtual clock; the terminator, bands, and sun/moon markers recompute while the imagery tiles stay put. A LIVE / offset chip shows whether you are on real time.
- Time-lapse. A play mode advances the virtual clock +10 minutes every 200 ms, sweeping the terminator around the planet; only the vector overlays recompute each frame — imagery is never re-fetched.
- Glass controls. A glass panel offers band toggles and an imagery opacity slider; Lucide glass pods handle the rest. No Esri widget chrome appears anywhere.
The data — where it comes from
Nightfall uses one imagery service and computes all geometry client-side; there is no basemap or credentialed service.
| Source | What it provides | Refresh | Cost | Attribution |
|---|---|---|---|---|
| NASA GIBS — VIIRS Black Marble | City-lights night imagery (2016 composite), WMTS tiles to level 8 | Static composite (anonymous WMTS) | Free / public | NASA GIBS / ESDIS |
| suncalc (client library) | Solar & lunar position, moon phase & illumination | Recomputed per minute (or per tick) | Free / open source | V. Agafonkin (suncalc) |
| Terminator & twilight geometry | Geodesic twilight caps computed in-browser | Per refresh / per scrub tick | In-app (no service) | ATS (src/lib/terminator.ts) |
How it was assembled
Nightfall is an ATS-branded React 19 + Tailwind 4 application on the ArcGIS Maps SDK for JavaScript. It carries no Esri UI widgets.
Engineering decisions worth calling out
- Zero-credential by construction. GIBS is anonymous WMTS and there is no Esri basemap or Location Platform service anywhere in the app, so .env stays empty and there is nothing to authenticate.
- Glass-pod controls, no Esri widget chrome. The three branded apps deliberately ship zero Esri UI widgets. ui: { components: [] } clears the default chrome (attribution still renders, restyled to a whisper), and all interaction lives in custom floating glass pods built from Tailwind and Lucide. This is an ATS brand standard: the map should read as a finished product surface, not a developer toolkit.
- Terminator as geodesic circles. Sun altitude at a point P is 90° − dist(P, subsolar), so {altitude < h} is exactly the spherical cap of radius (90° + h) around the antisolar point. Boundary vertices were verified to under 0.0001° altitude error against suncalc ground truth. The per-meridian binary-search approach was rejected because near the equinoxes (|declination| < 18°) the night cap touches neither pole and is not one latitude per longitude.
- Subsolar point without solar-position formulas. One SunCalc.getPosition(date, 0, 0) plus a great-circle destination from (0,0) along the sun's bearing at distance (90° − altitude) yields the subsolar point; suncalc's azimuth is measured from south, positive west, so bearing = azimuth·180/π + 180.
- Nested caps, not annuli. The four "sun below h" polygons are stacked simple rings with per-layer alphas solved so cumulative darkness hits the design targets (0.25 / 0.35 / 0.45 / 0.55) exactly for whichever bands are visible — avoiding hole-ring orientation edge cases.
- Cheap time-lapse. Only the GraphicsLayers are touched per 200 ms tick (about 124 polygon vertices plus four markers). The WebTileLayer is created once; its opacity is the only property ever mutated. Live mode recomputes on the floored minute, not on every clock render.