Slunce is a Progressive Web App that visualises sunrise, sunset, twilight, and related solar metrics for any location on Earth. The app combines precise astronomical calculations with a lightweight UI layer and optional offline/PWA support.
The codebase is intentionally small and is organised around three concerns:
- Presentation (
index.html,style.css) – Static markup and CSS define the dashboard layout, data slots, and tooltip affordances that will be filled at runtime. 【F:index.html†L1-L211】【F:style.css†L1-L120】 - Behaviour (
src/main.js) – Bootstraps the UI controller, handles optional?action=URL shortcuts, and defers loading of the PWA helpers. 【F:src/main.js†L1-L45】 - Domain logic (
src/core) – A small collection of modules that encapsulate solar calculations, time-zone heuristics, and higher level aggregates used by the UI. 【F:src/core/solarCalc.js†L1-L108】【F:src/core/solarMath.js†L1-L70】【F:src/core/solarExtras.js†L1-L200】【F:src/core/timezone.js†L1-L37】
The runtime flow is:
src/main.jswaits forDOMContentLoaded, initialises the UI layer, handles URL shortcuts, and registers the service worker/PWA helpers.src/ui/controller.jsbinds DOM listeners, loads translations, and orchestrates renders. On each render it reads the user inputs, calls intocalculatefromsrc/core/solarCalc.js, then derives secondary metrics withsrc/core/solarExtras.jsbefore writing the translated results back into the DOM. 【F:src/ui/controller.js†L1-L208】【F:src/ui/controller.js†L208-L322】- Optional PWA helpers (
src/pwa/install.jsandsrc/pwa/update.js) expose install prompts and update banners once the service worker (sw.js) is registered. 【F:src/pwa/install.js†L1-L83】【F:src/pwa/update.js†L1-L40】【F:sw.js†L1-L104】
Slunce/
├── index.html # Markup for the dashboard and modal shells
├── style.css # Dark themed layout + responsive tweaks
├── src/
│ ├── main.js # Entry point (DOMContentLoaded bootstrap)
│ ├── core/
│ │ ├── solarMath.js # Low-level astronomy formulas
│ │ ├── solarCalc.js # Public calculate() API for sun events
│ │ ├── solarExtras.js # Secondary metrics & heuristics
│ │ └── timezone.js # Crude tz/DST estimation by lat/lng
│ ├── ui/
│ │ └── controller.js # DOM bindings, rendering, i18n glue
│ ├── i18n/
│ │ ├── en.js # English strings + tooltip copy
│ │ └── cs.js # Czech translation
│ └── pwa/
│ ├── install.js # Install prompt / manual instructions
│ └── update.js # Update notification workflow
├── sw.js # Service worker (cache-first app shell)
├── manifest.json # PWA metadata
└── icons/, favicon # App icons referenced by the manifest
solarMath.jsholds pure mathematical helpers: Julian date conversion, solar declination, equation of time, and hour-angle computation. These are the foundation for every other module and are kept side-effect free for easy unit testing. 【F:src/core/solarMath.js†L1-L70】solarCalc.jsexposescalculate(date, lat, lng)which derives sunrise/sunset, twilight boundaries, golden/blue hour, and formats them for the UI. It gracefully handles polar day/night by returning sentinel strings such as"All day"or"No event". 【F:src/core/solarCalc.js†L1-L108】solarExtras.jslayers on top ofcalculateto compute day-to-day deltas, seasonal progress, solar geometry, photography heuristics, and physical quantities like sun distance and irradiance. Many helpers accept pre-formatted strings and convert them back to seconds when needed. 【F:src/core/solarExtras.js†L1-L200】timezone.jsis a pragmatic approximation that returns an offset based on coarse rectangular zones and hemisphere-specific DST heuristics. It is not exhaustive—be wary of edge cases near zone borders. 【F:src/core/timezone.js†L1-L37】
src/ui/controller.jsmanages most of the interactivity: language detection, tooltip behaviour, input validation, geolocation, and scheduled refreshes for true solar time. Rendering is done by writing translated strings into elements addressed by IDs inindex.html. The helpertranslateValueensures dynamic strings (e.g., light quality labels) respect the active locale. 【F:src/ui/controller.js†L1-L322】- Translations live under
src/i18n. English (en.js) is the source of truth; Czech (cs.js) mirrors the same keys. When adding UI copy, update both files to maintain parity. 【F:src/i18n/en.js†L1-L144】
sw.jsprovides an app-shell cache so the experience works offline. When you change cached assets, bumpCACHE_NAMEto invalidate older caches. The service worker uses a cache-first strategy with network fallback and servesindex.htmlas an offline fallback for navigation requests. 【F:sw.js†L1-L104】src/pwa/install.jsintercepts the browser install prompt, exposes a manual modal for unsupported platforms, and shows toast feedback on success. It relies on the globally exportedgetTextto keep strings localised. 【F:src/pwa/install.js†L1-L83】src/pwa/update.jswatches for waiting service workers and surfaces an update banner that reloads the app after callingSKIP_WAITING. 【F:src/pwa/update.js†L1-L40】
- Rendering loop –
calculateAndRender()in the UI controller is the single render pass. If you add new metrics, compute them near the existing sections (deltas, seasonal metrics, physical quantities, photography) so they stay organised. 【F:src/ui/controller.js†L110-L208】 - Input validation – Latitude/longitude are clamped and validated before calculations run. Reuse this logic if you add additional entry points (e.g., URL parameters). 【F:src/ui/controller.js†L118-L148】
- Translations – All user-visible strings should be defined in the i18n files and referenced with
data-i18nattributes orgetText()to keep language toggling consistent. 【F:index.html†L25-L210】【F:src/ui/controller.js†L19-L75】 - Time zones – The current estimation is intentionally lightweight. For more accuracy, consider integrating a real tz lookup service or library. Study
getTimezoneFromCoordinatesbefore making changes so you understand its fallback behaviour. 【F:src/core/timezone.js†L1-L24】 - Testing ideas – Although there is no automated test harness yet, the deterministic core modules (
solarMath.js,solarCalc.js,solarExtras.js) are prime candidates for unit tests. They have no DOM dependencies and accept plain numbers/dates.
To guard against timezone regressions when parsing the calendar input, run the following manual check after changes that touch date handling:
- Change your operating system or browser timezone to a negative UTC offset (for example, UTC−7).
- Load the app, pick a date such as
2024-06-21, and note the rendered events. - Refresh the page or re-open it, re-select the same date, and confirm the results continue to reference that exact calendar day (no off-by-one shifts).
This ensures that local-midnight parsing remains stable for users west of the prime meridian.
- Read through
solarMath.jsandsolarCalc.jsto understand the astronomical formulas and ensure future changes preserve their invariants. - Inspect
calculateAndRender()and the DOM structure inindex.htmlto see how data flows from inputs to outputs. - Experiment with the app in a browser, toggle languages, and trigger the PWA install/update flows to get a feel for the UX.
- Consider adding automated tests or linting to guard the critical calculation modules.
- If you plan to ship on the web, review the service worker cache list whenever you add new assets so offline support remains complete.
This overview should give you the mental map needed to dive deeper into specific features or extend the calculator. Happy hacking!