The application calculates sunlight and moon data for 37 places. It handles midnight sun and polar night by sampling altitude once per minute instead of assuming the sun crosses the horizon.
No external API, no database, no API key. The same question returns the same answer.
sindrg.com/sky, served from a GKE cluster that builds this repository at a pinned commit. The cluster and its delivery pipeline live in k8-lab; this repository is the application alone.
- Sunrise, sunset, golden hour, blue hour, and maximum solar altitude
- Moon phase, illumination, moonrise, and moonset
- Solar and lunar eclipse occurrence
- Browser observatory with four views: the solar system, the night sky, a globe of the places above, and the scale of the universe
- Internal JSON API, health endpoint, and version endpoint
python3 -m venv .venv
.venv/bin/pip install -r app/requirements-dev.txt
.venv/bin/uvicorn app.src.main:app --reload --port 8123
Open http://localhost:8123.
docker compose up --build --wait
The default address is http://localhost:8123. To use another host port or set a version:
GOLDEN_HOUR_PORT=9123 SERVICE_VERSION=0.1.0-local \
docker compose up --build --wait
Stop the local stack with docker compose down.
curl 'localhost:8123/api/light?place=lofoten&on=2026-06-21'
curl 'localhost:8123/api/moon?place=tromso'
curl 'localhost:8123/api/eclipses?days=900'
curl 'localhost:8123/health'
.venv/bin/python -m pytest app/tests -q
.venv/bin/ruff check app
.venv/bin/ruff format --check app
node --test app/tests/observatory.test.mjs app/tests/frontend/astronomy.test.js
scripts/container-smoke.sh
Solar coordinates follow the US Naval Observatory's approximate solar model. Lunar coordinates follow Paul Schlyter's low-precision model.
Five geocentric lunar positions in 2026 are checked against NASA JPL Horizons DE441 output. Those samples are within 3 arcminutes in ecliptic longitude and latitude. This bounded check is not a general accuracy guarantee. Rise and set times also use one-minute sampling and simplified horizon corrections.
The arithmetic is permanent. The delivery is not, and the distinction is worth stating: daylight saving rules are political rather than astronomical, so IANA timezone data genuinely needs updating, and the runtime dependencies and base image need security patches. All three are pinned, and Dependabot watches all three so a pin cannot go quietly stale.
Eclipse results report occurrence and kind. Path, magnitude, and local visibility require full ephemerides and are outside the current scope.
Pull requests preserve a reviewable history and CI enforces the automated contracts. This is an owner-maintained project, so those pull requests are not independent peer review unless another reviewer participates. Green CI demonstrates that the checked contracts pass. It is not external validation of the architecture or astronomy.