style: fix prettier table formatting in wiki

This commit is contained in:
Aric Camarata 2026-03-08 17:30:56 -04:00
parent f21be803fe
commit a57b4502b2
7 changed files with 256 additions and 258 deletions

View file

@ -7,7 +7,7 @@ Returns a `Promise<SpaResult>` with raw numeric values.
### Parameters ### Parameters
| Name | Type | Description | | Name | Type | Description |
| --- | --- | --- | | ----------- | -------- | ------------------------------------------------- |
| `date` | `Date` | Date and time for the calculation | | `date` | `Date` | Date and time for the calculation |
| `latitude` | `number` | Observer latitude, -90 to 90 (negative = south) | | `latitude` | `number` | Observer latitude, -90 to 90 (negative = south) |
| `longitude` | `number` | Observer longitude, -180 to 180 (negative = west) | | `longitude` | `number` | Observer longitude, -180 to 180 (negative = west) |
@ -16,7 +16,7 @@ Returns a `Promise<SpaResult>` with raw numeric values.
### Options ### Options
| Option | Type | Default | Description | | Option | Type | Default | Description |
| --- | --- | --- | --- | | --------------- | -------- | --------- | ------------------------------------------------------------- |
| `timezone` | `number` | auto | Hours from UTC. Auto-detected from the Date object if omitted | | `timezone` | `number` | auto | Hours from UTC. Auto-detected from the Date object if omitted |
| `elevation` | `number` | `0` | Meters above sea level | | `elevation` | `number` | `0` | Meters above sea level |
| `pressure` | `number` | `1013.25` | Atmospheric pressure in millibars | | `pressure` | `number` | `1013.25` | Atmospheric pressure in millibars |
@ -31,7 +31,7 @@ Returns a `Promise<SpaResult>` with raw numeric values.
### Result Fields ### Result Fields
| Field | Type | Unit | Description | | Field | Type | Unit | Description |
| --- | --- | --- | --- | | ----------------- | -------- | ---------------- | ------------------------------------------------------------------ |
| `zenith` | `number` | degrees | Topocentric zenith angle (0 = directly overhead) | | `zenith` | `number` | degrees | Topocentric zenith angle (0 = directly overhead) |
| `azimuth` | `number` | degrees | Topocentric azimuth, eastward from north (navigational convention) | | `azimuth` | `number` | degrees | Topocentric azimuth, eastward from north (navigational convention) |
| `azimuth_astro` | `number` | degrees | Topocentric azimuth, westward from south (astronomical convention) | | `azimuth_astro` | `number` | degrees | Topocentric azimuth, westward from south (astronomical convention) |
@ -48,7 +48,7 @@ Returns a `Promise<SpaResult>` with raw numeric values.
When `timezone` is omitted, the value is derived from the `Date` object's local timezone offset: When `timezone` is omitted, the value is derived from the `Date` object's local timezone offset:
```js ```js
timezone = -(date.getTimezoneOffset() / 60) timezone = -(date.getTimezoneOffset() / 60);
``` ```
This works correctly in most cases. Provide an explicit value when computing for a location whose timezone differs from the machine's local timezone. This works correctly in most cases. Provide an explicit value when computing for a location whose timezone differs from the machine's local timezone.
@ -72,11 +72,9 @@ A null result pointer (WASM memory allocation failure) also throws.
Same parameters and behavior as `spa()`. Returns a result object with the same fields, but `sunrise`, `sunset`, and `suntransit` are `HH:MM:SS` strings instead of fractional hours. During polar day or polar night, these strings are `"N/A"`: Same parameters and behavior as `spa()`. Returns a result object with the same fields, but `sunrise`, `sunset`, and `suntransit` are `HH:MM:SS` strings instead of fractional hours. During polar day or polar night, these strings are `"N/A"`:
```js ```js
const result = await spaFormatted( const result = await spaFormatted(new Date(2025, 5, 21, 12, 0, 0), 40.7128, -74.006, {
new Date(2025, 5, 21, 12, 0, 0), timezone: -4,
40.7128, -74.006, });
{ timezone: -4 }
);
console.log(result.sunrise); // "05:25:12" console.log(result.sunrise); // "05:25:12"
console.log(result.sunset); // "20:30:42" console.log(result.sunset); // "20:30:42"
@ -117,7 +115,7 @@ Calling `init()` multiple times is safe. The second and subsequent calls return
The `function` option controls which outputs the SPA computes. Lower codes skip the rise/transit/set and incidence calculations, which are the most expensive part. The `function` option controls which outputs the SPA computes. Lower codes skip the rise/transit/set and incidence calculations, which are the most expensive part.
| Constant | Value | Computes | | Constant | Value | Computes |
| --- | --- | --- | | ------------ | ----- | ------------------------------------------- |
| `SPA_ZA` | `0` | Zenith and azimuth only | | `SPA_ZA` | `0` | Zenith and azimuth only |
| `SPA_ZA_INC` | `1` | Zenith, azimuth, and incidence angle | | `SPA_ZA_INC` | `1` | Zenith, azimuth, and incidence angle |
| `SPA_ZA_RTS` | `2` | Zenith, azimuth, and rise/transit/set times | | `SPA_ZA_RTS` | `2` | Zenith, azimuth, and rise/transit/set times |

View file

@ -23,7 +23,7 @@ The C source is compiled with Emscripten to produce a single JavaScript file tha
### Build flags ### Build flags
| Flag | Purpose | | Flag | Purpose |
| --- | --- | | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `-O3 -flto` | Maximum optimization with link-time optimization. The compiler inlines across translation units and eliminates dead code | | `-O3 -flto` | Maximum optimization with link-time optimization. The compiler inlines across translation units and eliminates dead code |
| `--no-entry` | No `main()` function exists. The module exposes only the exported wrapper functions | | `--no-entry` | No `main()` function exists. The module exposes only the exported wrapper functions |
| `-sSINGLE_FILE=1` | Inlines the WASM binary as a base64 string inside the JavaScript file. Eliminates the `.wasm` file entirely | | `-sSINGLE_FILE=1` | Inlines the WASM binary as a base64 string inside the JavaScript file. Eliminates the `.wasm` file entirely |

View file

@ -30,8 +30,8 @@ import { spa } from 'solar-spa';
const result = await spa( const result = await spa(
new Date(2025, 5, 21, 12, 0, 0), // June 21, 2025 at noon new Date(2025, 5, 21, 12, 0, 0), // June 21, 2025 at noon
40.7128, // latitude (NYC) 40.7128, // latitude (NYC)
-74.0060, // longitude -74.006, // longitude
{ timezone: -4, elevation: 10 } // EDT (UTC-4), 10m elevation { timezone: -4, elevation: 10 }, // EDT (UTC-4), 10m elevation
); );
console.log(result.zenith); // ~27 (degrees from vertical) console.log(result.zenith); // ~27 (degrees from vertical)

View file

@ -81,7 +81,7 @@ The SPA's accuracy far exceeds the precision of any practical measurement system
The SPA validates all inputs and returns a non-zero error code if any are out of range: The SPA validates all inputs and returns a non-zero error code if any are out of range:
| Parameter | Valid range | | Parameter | Valid range |
| --- | --- | | ---------------------- | --------------------------- |
| Year | -2000 to 6000 | | Year | -2000 to 6000 |
| Month | 1 to 12 | | Month | 1 to 12 |
| Day | 1 to 31 | | Day | 1 to 31 |

View file

@ -46,7 +46,7 @@ Memory growth is disabled (`ALLOW_MEMORY_GROWTH=0`). This means the ArrayBuffer
Not all callers need every output. The `function` option controls how much work the SPA does: Not all callers need every output. The `function` option controls how much work the SPA does:
| Code | Computation | Relative cost | | Code | Computation | Relative cost |
| --- | --- | --- | | ---------------- | ------------------ | -------------------------------- |
| `SPA_ZA` (0) | Zenith and azimuth | ~1x | | `SPA_ZA` (0) | Zenith and azimuth | ~1x |
| `SPA_ZA_INC` (1) | + incidence angle | ~1x (incidence is cheap) | | `SPA_ZA_INC` (1) | + incidence angle | ~1x (incidence is cheap) |
| `SPA_ZA_RTS` (2) | + rise/transit/set | ~3x (three position evaluations) | | `SPA_ZA_RTS` (2) | + rise/transit/set | ~3x (three position evaluations) |
@ -70,7 +70,7 @@ These flags together produce a ~60KB output file, down from the ~150KB that a de
## When to use solar-spa vs nrel-spa ## When to use solar-spa vs nrel-spa
| Scenario | Recommended | | Scenario | Recommended |
| --- | --- | | ------------------------------------------------------ | -------------------------------------------------------------------- |
| Single position lookup (e.g., sunrise for today) | Either. Both are fast enough | | Single position lookup (e.g., sunrise for today) | Either. Both are fast enough |
| Batch computation (hundreds or thousands of positions) | solar-spa (WASM) | | Batch computation (hundreds or thousands of positions) | solar-spa (WASM) |
| Animation or real-time tracking | solar-spa (WASM) | | Animation or real-time tracking | solar-spa (WASM) |

View file

@ -7,7 +7,7 @@ Pre-release validation of the solar-spa v2.0.0 WASM implementation. All results
100 scenarios covering seven categories: 100 scenarios covering seven categories:
| Category | Scenarios | Description | | Category | Scenarios | Description |
| --- | --- | --- | | ------------------------- | --------- | --------------------------------------------------------------- |
| Cities worldwide | 1-40 | 20 cities across every continent, summer and winter solstice | | Cities worldwide | 1-40 | 20 cities across every continent, summer and winter solstice |
| Boundary conditions | 41-55 | Poles, equator, date line, extreme elevation, date range limits | | Boundary conditions | 41-55 | Poles, equator, date line, extreme elevation, date range limits |
| Polar regions | 56-65 | Polar day, polar night, midnight sun, Antarctic stations | | Polar regions | 56-65 | Polar day, polar night, midnight sun, Antarctic stations |
@ -23,7 +23,7 @@ Pre-release validation of the solar-spa v2.0.0 WASM implementation. All results
20 major cities tested at both the June 21 and December 21 solstices, 2025, local noon. Each scenario validates that the zenith angle falls within a physically reasonable range for the latitude and season. 20 major cities tested at both the June 21 and December 21 solstices, 2025, local noon. Each scenario validates that the zenith angle falls within a physically reasonable range for the latitude and season.
| # | City | Season | Zenith | Azimuth | Time | | # | City | Season | Zenith | Azimuth | Time |
| --- | --- | --- | --- | --- | --- | | --- | ------------ | ------ | ------ | ------- | ----- |
| 1 | New York | Summer | 21.12 | 140.47 | 242us | | 1 | New York | Summer | 21.12 | 140.47 | 242us |
| 2 | New York | Winter | 65.35 | 166.30 | 168us | | 2 | New York | Winter | 65.35 | 166.30 | 168us |
| 3 | London | Summer | 30.52 | 150.96 | 110us | | 3 | London | Summer | 30.52 | 150.96 | 110us |
@ -72,7 +72,7 @@ Note: "Summer" and "Winter" refer to Northern Hemisphere seasons. For Southern H
Tests at the mathematical limits of the algorithm's input domain. Tests at the mathematical limits of the algorithm's input domain.
| # | Scenario | Zenith | Note | | # | Scenario | Zenith | Note |
| --- | --- | --- | --- | | --- | ------------------------- | ------ | ----------------------------------- |
| 41 | North Pole, June solstice | 66.53 | Midnight sun: zenith < 90 | | 41 | North Pole, June solstice | 66.53 | Midnight sun: zenith < 90 |
| 42 | North Pole, Dec solstice | 113.44 | Polar night: zenith > 90 | | 42 | North Pole, Dec solstice | 113.44 | Polar night: zenith > 90 |
| 43 | South Pole, Dec solstice | 66.53 | Midnight sun (southern summer) | | 43 | South Pole, Dec solstice | 66.53 | Midnight sun (southern summer) |
@ -96,7 +96,7 @@ The equinox results confirm the algorithm's accuracy: a zenith of 1.84 degrees a
Polar day/night conditions test the algorithm's handling of non-standard sunrise/sunset scenarios. Polar day/night conditions test the algorithm's handling of non-standard sunrise/sunset scenarios.
| # | Location | Condition | Zenith | | # | Location | Condition | Zenith |
| --- | --- | --- | --- | | --- | ------------------------- | -------------------------- | ------ |
| 56 | Tromso, Norway (69.6N) | Polar day (June) | 46.70 | | 56 | Tromso, Norway (69.6N) | Polar day (June) | 46.70 |
| 57 | Tromso, Norway | Polar night (Dec) | 93.14 | | 57 | Tromso, Norway | Polar night (Dec) | 93.14 |
| 58 | Murmansk, Russia (69.0N) | Polar day (June) | 46.12 | | 58 | Murmansk, Russia (69.0N) | Polar day (June) | 46.12 |
@ -113,7 +113,7 @@ Scenario 64 is notable: at Svalbard at midnight on the June solstice, the sun is
## Category 4: Time Edge Cases (66-75) ## Category 4: Time Edge Cases (66-75)
| # | Scenario | Zenith | Note | | # | Scenario | Zenith | Note |
| --- | --- | --- | --- | | --- | --------------------------------- | ------ | -------------------------------- |
| 66 | Exact midnight UTC (London, June) | 105.05 | Sun well below horizon | | 66 | Exact midnight UTC (London, June) | 105.05 | Sun well below horizon |
| 67 | Dawn, 5 AM summer London | 88.47 | Near horizon | | 67 | Dawn, 5 AM summer London | 88.47 | Near horizon |
| 68 | Dusk, 9 PM summer London | 87.93 | Near horizon | | 68 | Dusk, 9 PM summer London | 87.93 | Near horizon |
@ -130,7 +130,7 @@ Scenario 64 is notable: at Svalbard at midnight on the June solstice, the sun is
All four function codes (`SPA_ZA`, `SPA_ZA_INC`, `SPA_ZA_RTS`, `SPA_ALL`) produce identical zenith and azimuth values within 0.01 degree tolerance. This confirms that the function code parameter only affects which outputs are computed, not the core position algorithm. All four function codes (`SPA_ZA`, `SPA_ZA_INC`, `SPA_ZA_RTS`, `SPA_ALL`) produce identical zenith and azimuth values within 0.01 degree tolerance. This confirms that the function code parameter only affects which outputs are computed, not the core position algorithm.
| # | Test | Result | | # | Test | Result |
| --- | --- | --- | | --- | ------------------------------------- | ------------------------------------- |
| 76 | SPA_ZA matches SPA_ALL | zenith identical | | 76 | SPA_ZA matches SPA_ALL | zenith identical |
| 77 | SPA_ZA_INC matches SPA_ALL | zenith, azimuth, incidence identical | | 77 | SPA_ZA_INC matches SPA_ALL | zenith, azimuth, incidence identical |
| 78 | SPA_ZA_RTS matches SPA_ALL | zenith, azimuth identical | | 78 | SPA_ZA_RTS matches SPA_ALL | zenith, azimuth identical |
@ -140,7 +140,7 @@ All four function codes (`SPA_ZA`, `SPA_ZA_INC`, `SPA_ZA_RTS`, `SPA_ALL`) produc
## Category 6: Atmospheric Conditions (81-90) ## Category 6: Atmospheric Conditions (81-90)
| # | Condition | Zenith | Note | | # | Condition | Zenith | Note |
| --- | --- | --- | --- | | --- | --------------------------------------- | ------ | ------------------------------ |
| 81 | Standard atmosphere (1013.25 mbar, 15C) | 21.12 | Reference baseline | | 81 | Standard atmosphere (1013.25 mbar, 15C) | 21.12 | Reference baseline |
| 82 | Low pressure (300 mbar, -30C, 9000m) | 21.12 | High altitude conditions | | 82 | Low pressure (300 mbar, -30C, 9000m) | 21.12 | High altitude conditions |
| 83 | High pressure (1100 mbar) | 21.12 | Dense atmosphere | | 83 | High pressure (1100 mbar) | 21.12 | Dense atmosphere |
@ -159,7 +159,7 @@ Scenario 89 confirms that different atmospheric pressures produce measurably dif
The SPA is valid for years -2000 to 6000. These scenarios confirm correct behavior across the full range, with era-appropriate delta_t values. The SPA is valid for years -2000 to 6000. These scenarios confirm correct behavior across the full range, with era-appropriate delta_t values.
| # | Year | Context | Zenith | delta_t | | # | Year | Context | Zenith | delta_t |
| --- | --- | --- | --- | --- | | --- | ---------------------- | ------------------------------ | ------ | ------- |
| 91 | 1000 CE | Medieval era | 17.25 | 1574s | | 91 | 1000 CE | Medieval era | 17.25 | 1574s |
| 92 | 1582 | Gregorian calendar switch | 50.37 | 120s | | 92 | 1582 | Gregorian calendar switch | 50.37 | 120s |
| 93 | 1900 | Turn of century | 25.45 | -3s | | 93 | 1900 | Turn of century | 25.45 | -3s |
@ -182,7 +182,7 @@ Measured on Apple Silicon (Node.js), single-threaded.
From the 100 validation scenarios: From the 100 validation scenarios:
| Metric | Value | | Metric | Value |
| --- | --- | | ------ | ----- |
| Min | 7us | | Min | 7us |
| Max | 242us | | Max | 242us |
| Mean | 46us | | Mean | 46us |
@ -197,7 +197,7 @@ The first call is slowest (242us) because it includes WASM module initialization
10,000 consecutive calls to the same location and date: 10,000 consecutive calls to the same location and date:
| Function Code | Time | Throughput | | Function Code | Time | Throughput |
| --- | --- | --- | | ------------- | ----- | ------------------ |
| SPA_ALL | 201ms | ~50,000 calls/sec | | SPA_ALL | 201ms | ~50,000 calls/sec |
| SPA_ZA | 46ms | ~219,000 calls/sec | | SPA_ZA | 46ms | ~219,000 calls/sec |

View file

@ -40,7 +40,7 @@ Emscripten supports a `locateFile` callback that lets the consumer specify where
```js ```js
const Module = await createModule({ const Module = await createModule({
locateFile: (path) => '/static/wasm/' + path locateFile: (path) => '/static/wasm/' + path,
}); });
``` ```
@ -54,10 +54,8 @@ Webpack can be configured to copy `.wasm` files to the output directory and rewr
// webpack.config.js // webpack.config.js
module.exports = { module.exports = {
module: { module: {
rules: [ rules: [{ test: /\.wasm$/, type: 'asset/resource' }],
{ test: /\.wasm$/, type: 'asset/resource' } },
]
}
}; };
``` ```
@ -90,10 +88,12 @@ let _pending: Promise<void> | null = null;
export function init(): Promise<void> { export function init(): Promise<void> {
if (_module) return Promise.resolve(); if (_module) return Promise.resolve();
if (_pending) return _pending; if (_pending) return _pending;
_pending = createSpaModule().then((mod) => { _pending = createSpaModule()
.then((mod) => {
_module = mod; _module = mod;
_pending = null; _pending = null;
}).catch((err) => { })
.catch((err) => {
_pending = null; // Allow retry on next call _pending = null; // Allow retry on next call
throw err; throw err;
}); });
@ -118,9 +118,9 @@ For small to medium WASM binaries (under a few hundred KB), inlining as base64 i
## Summary ## Summary
| Approach | Universal? | Consumer config? | Size overhead | | Approach | Universal? | Consumer config? | Size overhead |
| --- | --- | --- | --- | | ------------------------------------- | ----------- | ----------------- | ------------- |
| Separate `.wasm` + default resolution | No | No | None | | Separate `.wasm` + default resolution | No | No | None |
| `locateFile` callback | Yes* | Yes (per-bundler) | None | | `locateFile` callback | Yes\* | Yes (per-bundler) | None |
| Bundler-specific config | Per-bundler | Yes | None | | Bundler-specific config | Per-bundler | Yes | None |
| `import.meta.url` | Partial | No | None | | `import.meta.url` | Partial | No | None |
| **SINGLE_FILE (base64 inline)** | **Yes** | **No** | **~33%** | | **SINGLE_FILE (base64 inline)** | **Yes** | **No** | **~33%** |