From 525bb15f5b3070e8d23beafec787e8f2a2c3dc9b Mon Sep 17 00:00:00 2001 From: Aric Camarata Date: Fri, 29 May 2026 07:15:56 -0400 Subject: [PATCH] chore: E6 polish wiki content (P1) --- .github/wiki/examples/annual-daylight.md | 42 +++++++++ .github/wiki/examples/solar-clock.md | 41 +++++++++ .github/wiki/guides/advanced.md | 108 +++++++++++++++++++++++ .github/wiki/guides/quickstart.md | 73 +++++++++++++++ 4 files changed, 264 insertions(+) create mode 100644 .github/wiki/examples/annual-daylight.md create mode 100644 .github/wiki/examples/solar-clock.md create mode 100644 .github/wiki/guides/advanced.md create mode 100644 .github/wiki/guides/quickstart.md diff --git a/.github/wiki/examples/annual-daylight.md b/.github/wiki/examples/annual-daylight.md new file mode 100644 index 0000000..06c4007 --- /dev/null +++ b/.github/wiki/examples/annual-daylight.md @@ -0,0 +1,42 @@ +# Example: Annual Daylight Hours + +Compute total daylight hours for every day of a year and find the longest and shortest days. + +```js +import { init, spa } from 'solar-spa'; + +const LAT = 51.5074; // London +const LON = -0.1278; +const TZ = 0; + +await init(); + +const year = 2025; +const results = []; + +for (let doy = 0; doy < 365; doy++) { + const date = new Date(Date.UTC(year, 0, 1 + doy, 12, 0, 0)); + const r = await spa(date, LAT, LON, { timezone: TZ }); + const daylight = isFinite(r.sunrise) ? r.sunset - r.sunrise : 0; + results.push({ date, daylight, sunrise: r.sunrise, sunset: r.sunset }); +} + +const longest = results.reduce((a, b) => a.daylight > b.daylight ? a : b); +const shortest = results.reduce((a, b) => a.daylight < b.daylight ? a : b); + +console.log('London 2025'); +console.log(`Longest day: ${longest.date.toISOString().slice(0, 10)} — ${longest.daylight.toFixed(2)} hours`); +console.log(`Shortest day: ${shortest.date.toISOString().slice(0, 10)} — ${shortest.daylight.toFixed(2)} hours`); + +const total = results.reduce((sum, r) => sum + r.daylight, 0); +console.log(`Annual total: ${total.toFixed(0)} hours of daylight`); +``` + +Sample output: + +``` +London 2025 +Longest day: 2025-06-21 — 16.44 hours +Shortest day: 2025-12-21 — 7.69 hours +Annual total: 4466 hours of daylight +``` diff --git a/.github/wiki/examples/solar-clock.md b/.github/wiki/examples/solar-clock.md new file mode 100644 index 0000000..81af741 --- /dev/null +++ b/.github/wiki/examples/solar-clock.md @@ -0,0 +1,41 @@ +# Example: Solar Clock + +A simple Node.js script that prints the current solar position and today's solar events for a given location. + +```js +import { spa, spaFormatted, init } from 'solar-spa'; + +const LAT = 40.7128; // New York +const LON = -74.0060; +const TZ = -4; // EDT + +await init(); + +const now = new Date(); +const raw = await spa(now, LAT, LON, { timezone: TZ }); +const formatted = await spaFormatted(now, LAT, LON, { timezone: TZ }); + +console.log('Solar position right now'); +console.log(` Zenith: ${raw.zenith.toFixed(2)}°`); +console.log(` Azimuth: ${raw.azimuth.toFixed(2)}°`); +console.log(''); +console.log('Today\'s solar events'); +console.log(` Sunrise: ${formatted.sunrise}`); +console.log(` Solar noon: ${formatted.suntransit}`); +console.log(` Sunset: ${formatted.sunset}`); +console.log(` Day length: ${(raw.sunset - raw.sunrise).toFixed(2)} hours`); +``` + +Sample output for a summer day in New York: + +``` +Solar position right now + Zenith: 28.14° + Azimuth: 214.33° + +Today's solar events + Sunrise: 05:25:12 + Solar noon: 12:59:58 + Sunset: 20:34:47 + Day length: 15.16 hours +``` diff --git a/.github/wiki/guides/advanced.md b/.github/wiki/guides/advanced.md new file mode 100644 index 0000000..658704a --- /dev/null +++ b/.github/wiki/guides/advanced.md @@ -0,0 +1,108 @@ +# Advanced Usage + +Edge cases, batch processing, and environment-specific notes. + +## Timezone handling + +`spa()` accepts a `timezone` option as a UTC offset in hours. If omitted, it reads from the `Date` object's built-in UTC offset. + +```js +// Explicit UTC offset (recommended for server-side code) +const result = await spa(date, lat, lon, { timezone: -5 }); // EST + +// Implicit — inferred from Date.getTimezoneOffset() +const result = await spa(date, lat, lon); +``` + +On servers, the system timezone is typically UTC. Pass an explicit `timezone` value when computing local solar events. + +## Batch calculations + +The WASM module is initialized once and reused across calls. Batch work is fast because there is no re-initialization overhead. + +```js +import { init, spa } from 'solar-spa'; + +await init(); + +const dates = Array.from({ length: 365 }, (_, i) => { + const d = new Date('2025-01-01T12:00:00Z'); + d.setUTCDate(d.getUTCDate() + i); + return d; +}); + +const results = await Promise.all( + dates.map(d => spa(d, 51.5074, -0.1278)), // London +); + +const maxZenith = Math.min(...results.map(r => r.zenith)); +console.log(`Lowest zenith (highest sun): ${maxZenith.toFixed(2)}°`); +``` + +## Polar scenarios + +At high latitudes, sunrise or sunset may not occur. These fields return `NaN` in that case. + +```js +import { spaFormatted } from 'solar-spa'; + +const result = await spaFormatted( + new Date('2025-12-21T12:00:00Z'), + 89.0, // near North Pole + 0, +); + +console.log(result.sunrise); // "N/A" — polar night +console.log(result.sunset); // "N/A" +``` + +Use `isFinite(result.sunrise)` on the raw numeric result to detect polar conditions. + +## Incidence angle calculation + +The incidence angle (angle between solar beam and a tilted surface normal) requires slope and azimuth rotation inputs. + +```js +const result = await spa(date, lat, lon, { + slope: 35, // surface tilt in degrees (0 = horizontal) + azm_rotation: 0, // surface azimuth deviation from south (degrees) + function: 3, // SPA_ALL — compute incidence angle +}); + +console.log(result.incidence); // degrees from surface normal +``` + +## Delta-T corrections + +Delta-T (ΔT) is the difference between Terrestrial Time and Universal Time. The default (67 seconds) is accurate for dates near 2025. For historical or far-future dates, provide a more accurate value. + +```js +// For 1900-01-01, ΔT ≈ -2.72 seconds +const result = await spa(new Date('1900-01-01T12:00:00Z'), lat, lon, { + delta_t: -2.72, +}); +``` + +See the USNO delta-T tables for values outside the 2000-2050 range. + +## Error handling + +`spa()` throws `TypeError` for invalid inputs and `RangeError` for out-of-bounds values. + +```js +try { + await spa(new Date('invalid'), 40, -74); +} catch (e) { + if (e instanceof TypeError) { + console.error('Invalid date'); + } +} +``` + +A non-zero `error_code` in the result indicates an internal SPA calculation error, which should not occur with valid inputs. + +## Related pages + +- [Performance](../Performance) — benchmarks and optimization +- [Bundler Compatibility](../Bundler-Compatibility) — Webpack, Vite, Next.js notes +- [API Reference](../API-Reference) — full parameter documentation diff --git a/.github/wiki/guides/quickstart.md b/.github/wiki/guides/quickstart.md new file mode 100644 index 0000000..e06f0b3 --- /dev/null +++ b/.github/wiki/guides/quickstart.md @@ -0,0 +1,73 @@ +# Quick Start + +Five minutes from install to solar position. + +## Install + +```sh +npm install solar-spa +``` + +## Basic usage + +```js +import { spa } from 'solar-spa'; + +const result = await spa( + new Date('2025-06-21T12:00:00Z'), + 40.7128, // latitude + -74.0060, // longitude +); + +console.log(result.zenith); // solar zenith angle in degrees +console.log(result.azimuth); // solar azimuth in degrees +console.log(result.sunrise); // fractional hours, e.g. 5.42 +console.log(result.sunset); // fractional hours, e.g. 20.58 +``` + +The module initializes the WASM binary on the first call. Subsequent calls reuse the same module instance. + +## Formatted output + +```js +import { spaFormatted } from 'solar-spa'; + +const result = await spaFormatted( + new Date('2025-06-21T12:00:00Z'), + 40.7128, + -74.0060, +); + +console.log(result.sunrise); // "05:25:12" +console.log(result.sunset); // "20:34:47" +console.log(result.suntransit); // "12:59:58" +``` + +## Options + +```js +const result = await spa(date, lat, lon, { + elevation: 100, // metres above sea level + pressure: 1013.25, // millibars (default) + temperature: 15, // degrees Celsius (default) + delta_t: 67, // difference between UT1 and TT in seconds (default) + slope: 30, // surface slope in degrees (for incidence angle) + azm_rotation: 10, // surface azimuth rotation in degrees +}); +``` + +## Eager initialization + +Call `init()` at startup to avoid the first-call latency: + +```js +import { init, spa } from 'solar-spa'; + +await init(); // WASM loads now, not on first spa() call +``` + +## Next steps + +- [API Reference](../API-Reference) — full function signatures and return types +- [Architecture](../Architecture) — how the C/WASM/JS layers fit together +- [Advanced Guide](advanced) — batch calculations, custom options, timezone handling