No description
Find a file
2026-03-28 18:19:03 -04:00
.github Add GitHub Sponsors funding config 2026-03-28 18:19:03 -04:00
.wiki style: fix prettier table formatting in wiki 2026-03-08 17:30:56 -04:00
src refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
wasm v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
.editorconfig v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
.gitignore refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
.npmrc Remove pnpm-specific .npmrc setting that causes npm warning 2026-02-25 11:17:19 -05:00
.nvmrc v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
.prettierrc refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
CHANGELOG.md v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
eslint.config.mjs refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
LICENSE v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
package.json refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
pnpm-lock.yaml refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
pnpm-workspace.yaml v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
README.md v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
test-cjs.cjs refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
test.mjs refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
tsconfig.json refactor: code quality improvements across the board 2026-03-08 11:33:21 -04:00
tsup.config.ts v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00
validate.mjs v2.0.0: TypeScript rewrite with WASM recompilation 2026-02-25 10:35:24 -05:00

solar-spa

npm version CI license

NREL Solar Position Algorithm compiled to WebAssembly. Calculates solar zenith, azimuth, incidence angle, sunrise, sunset, solar noon, and equation of time for any location and date.

The algorithm is the NREL SPA by Ibrahim Reda and Afshin Andreas, originally written in C. This package compiles the original C source to WASM via Emscripten and provides a TypeScript/JavaScript interface on top.

Installation

npm install solar-spa

Quick Start

import { spa } from 'solar-spa';

const result = await spa(
  new Date(2025, 5, 21, 12, 0, 0),   // June 21, 2025 at noon
  40.7128,                             // latitude (NYC)
  -74.0060,                            // longitude
  { timezone: -4, elevation: 10 }      // EDT (UTC-4), 10m elevation
);

console.log(result.zenith);       // ~27   (degrees from vertical)
console.log(result.azimuth);      // ~179  (degrees from north)
console.log(result.sunrise);      // ~5.4  (fractional hours)
console.log(result.sunset);       // ~20.5 (fractional hours)

CommonJS works too:

const { spa } = require('solar-spa');

API

spa(date, latitude, longitude, options?)

Returns a Promise<SpaResult> with raw numeric values.

Parameters:

Name Type Description
date Date Date and time for the calculation
latitude number Observer latitude, -90 to 90 (negative = south)
longitude number Observer longitude, -180 to 180 (negative = west)
options object Optional. See below

Options:

Option Type Default Description
timezone number auto Hours from UTC. Auto-detected from the Date object if omitted
elevation number 0 Meters above sea level
pressure number 1013.25 Atmospheric pressure in millibars
temperature number 15 Temperature in Celsius
delta_ut1 number 0 UT1-UTC correction in seconds
delta_t number 67 TT-UTC difference in seconds
slope number 0 Surface slope in degrees
azm_rotation number 0 Surface azimuth rotation in degrees
atmos_refract number 0.5667 Atmospheric refraction in degrees
function number 3 SPA function code (see below)

Result fields:

Field Unit Description
zenith degrees Topocentric zenith angle
azimuth degrees Topocentric azimuth, eastward from north
azimuth_astro degrees Topocentric azimuth, westward from south
incidence degrees Surface incidence angle
sunrise fractional hours Local sunrise time
sunset fractional hours Local sunset time
suntransit fractional hours Solar noon
sun_transit_alt degrees Sun transit altitude
eot minutes Equation of time
error_code integer 0 on success

spaFormatted(date, latitude, longitude, options?)

Same as spa(), but sunrise, sunset, and suntransit are returned as HH:MM:SS strings. Returns "N/A" for these fields during polar day or polar night.

formatTime(hours)

Converts fractional hours to an HH:MM:SS string. Returns "N/A" for non-finite or negative values (polar night/day scenarios).

init()

Pre-initializes the WASM module. Optional. The module initializes automatically on the first spa() call. Useful if you want to pay the initialization cost at application startup rather than on the first calculation.

Function Codes

Constant Value Computes
SPA_ZA 0 Zenith and azimuth
SPA_ZA_INC 1 Zenith, azimuth, and incidence
SPA_ZA_RTS 2 Zenith, azimuth, and rise/transit/set
SPA_ALL 3 All output values

Architecture

The package has three layers:

  1. C layer (src/spa.c, src/spa_wrapper.c): The original NREL SPA algorithm with a thin wrapper that exposes a flat function signature suitable for WASM.

  2. WASM layer (wasm/spa-module.js): Compiled with Emscripten using -sSINGLE_FILE=1, which inlines the WASM binary as base64. No external .wasm file to resolve. This eliminates the bundler path-resolution issues that plague most WASM packages.

  3. TypeScript layer (src/index.ts, src/types.ts): Written in TypeScript and compiled by tsup to both CJS and native ESM with generated declaration files. Singleton WASM initialization, cached cwrap bindings, input validation, and named struct offset constants.

Build Flags

The WASM binary is compiled with:

  • -O3 -flto: Maximum optimization with link-time optimization
  • -sSINGLE_FILE=1: WASM inlined as base64 (no file path resolution)
  • -sMODULARIZE=1: No global Module pollution
  • -sNO_FILESYSTEM=1: No filesystem API bundled (saves ~15KB)
  • -sINITIAL_MEMORY=1048576: 1MB fixed memory (SPA needs very little)
  • -sASSERTIONS=0: No debug assertions in production
  • -sENVIRONMENT='node,web,worker': Works in Node.js, browsers, and web workers

Compatibility

Tested in:

  • Node.js 20+
  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • Webpack 5
  • Vite
  • Next.js (both Pages and App Router)
  • Web Workers

The SINGLE_FILE approach eliminates the .wasm file resolution problem that breaks most WASM packages in bundlers. There is no external binary to locate at runtime.

TypeScript

Full type definitions are generated from the TypeScript source and included with the package. Import types directly:

import { spa, SPA_ALL } from 'solar-spa';
import type { SpaResult, SpaOptions } from 'solar-spa';

Documentation

See the Wiki for detailed documentation: API reference, architecture, performance, bundler compatibility, validation benchmarks, and more.

  • nrel-spa: Pure JavaScript port of the same algorithm. No WASM dependency, synchronous API. Better choice if you do not need WASM-level performance.
  • NREL SPA: The original algorithm specification and C source.
  • pray-calc: Islamic prayer time calculator built on nrel-spa.

Acknowledgments

This package includes the Solar Position Algorithm (SPA) developed at the National Renewable Energy Laboratory (NREL) by Ibrahim Reda and Afshin Andreas. The C source files spa.c and spa.h are copyright Alliance for Sustainable Energy, LLC (2008-2011) and are distributed under the terms included in those files.

Reda, I., Andreas, A. (2004). "Solar Position Algorithm for Solar Radiation Applications." Solar Energy, 76(5), 577-589. doi:10.1016/j.solener.2003.12.003

The original C source and an online calculator are available at midcdmz.nrel.gov/spa.

License

MIT (wrapper, TypeScript source, and build tooling). The NREL SPA C source (src/spa.c, src/spa.h) is subject to its own terms; see the notice in those files.