npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aulunarcana/ephemeris

v0.2.3

Published

AuLun Ephemeris: NASA-grade astronomical ephemeris and chart engine (WASM). Free for non-commercial use; commercial licenses available.

Readme

@aulunarcana/ephemeris

Build professional astrology software without relying on external APIs or GPL-licensed ephemerides.

AuLun Ephemeris is a production-grade astronomical engine for Node.js, with a Rust core and WebAssembly bindings. One call computes a complete natal chart — bodies, eleven house systems, tropical and sidereal zodiacs, aspects, and pattern detection — plus standalone transit, equatorial, and heliocentric position APIs. Validated against JPL Horizons to sub-arcsecond accuracy across 1900–2100, with a Moon median error of 0.06″. Free for non-commercial use; commercial licenses available (see License below).

Install

npm install @aulunarcana/ephemeris

Node 18+. Self-contained — all ephemeris data (~13 MB) is embedded.

Quick start — tropical zodiac, Placidus houses

import { Ephemeris, degreesToRadians, radiansToDegrees } from "@aulunarcana/ephemeris";

const engine = new Ephemeris(); // parses embedded data once — construct once, reuse

const chart = engine.computeChart(
  { year: 1990, month: 6, day: 15, hour: 21, minute: 30 }, // local civil time
  "America/Los_Angeles",                                   // IANA timezone
  { latitudeRad: degreesToRadians(34.05), longitudeRad: degreesToRadians(-118.24) },
  { houseSystem: "placidus" },                             // tropical is the default zodiac
);

radiansToDegrees(chart.ascendantRad);      // Ascendant
chart.bodies.sun.longitudeRad;             // apparent ecliptic longitude
chart.bodies.moon.longitudeRateRadPerDay;  // negative = retrograde
chart.houses.cuspsRad;                     // the 12 Placidus cusps
chart.aspects;                             // aspects with applying/separating
chart.patterns;                            // grand trines, T-squares, …

All angles are radians; convert with radiansToDegrees / degreesToRadians. The full result shape is in index.d.ts (Chart).

Deploying — Next.js, React, bundlers

The published build targets Node (wasm-pack --target nodejs) and loads its WASM binary at import time through createRequire("./pkg/ephemeris_wasm.js") — a dynamic require that bundlers and file tracers cannot follow statically. Plain node scripts and servers need nothing special. Anything that bundles or traces your server code does:

Next.js / Vercel

Mark the package as a server external:

// next.config.ts
const config: NextConfig = {
  serverExternalPackages: ["@aulunarcana/ephemeris"],
};

Without it, next build succeeds but production functions crash at module load with MODULE_NOT_FOUND: the bundler inlines index.mjs while the pkg/ WASM files it requires are left behind, and output file tracing cannot see the dynamic require either. serverExternalPackages keeps the package un-bundled, so the require resolves against the real node_modules directory and the tracer copies the whole package into the deployed function.

Two notes from a real production incident with this package:

  • outputFileTracingIncludes alone is not a reliable substitute — it can verify clean locally and on a preview deployment and still fail in production functions. Use serverExternalPackages.
  • The failure is at module load, after a green build. When you first deploy, request one route that actually computes a chart before calling it done.

Import the package only in server code — route handlers, Server Components, server actions, crons — on the Node runtime. It cannot run under export const runtime = "edge".

React

The package does not run in the browser: browser bundlers (webpack, Vite, esbuild) cannot bundle its Node-target WASM loading. Compute on the server and hand React plain data — chart output is JSON-serializable and crosses the server→client boundary as-is:

// app/chart/page.tsx — Server Component
import { Ephemeris, degreesToRadians } from "@aulunarcana/ephemeris";

export default async function ChartPage() {
  const eph = new Ephemeris();
  const chart = eph.computeChart(
    { year: 1990, month: 6, day: 15, hour: 21, minute: 30 },
    "America/Los_Angeles",
    { latitudeRad: degreesToRadians(34.05), longitudeRad: degreesToRadians(-118.24) },
    { houseSystem: "placidus" },
  );
  return <ChartView chart={chart} />; // client component receives plain data
}

The same shape applies to any SPA: put the ephemeris behind an API route and fetch the JSON. An in-browser build (--target web) is not currently published — open an issue if your use case needs one.

Other Node-side bundlers

Same rule, same reason — keep the package external:

  • Vite SSR: ssr: { external: ["@aulunarcana/ephemeris"] }
  • esbuild: external: ["@aulunarcana/ephemeris"]
  • webpack (server): externals: { "@aulunarcana/ephemeris": "commonjs @aulunarcana/ephemeris" }

What a chart contains

  • Bodies (chart.bodies): sun, moon, mercury, venus, mars, jupiter, saturn, uranus, neptune, pluto, chiron — each with apparent ecliptic longitude, latitude, distance, and daily motion (negative = retrograde).
  • Angles and houses: Ascendant, Midheaven, 12 house cusps, plus vertexRad and eastPointRad (the prime-vertical angles — see below).
  • Lunar points: mean and true North/South Node and Lilith.
  • Hermetic lots: Fortune, Spirit, Eros, Necessity, Courage, Victory, Nemesis (day/night sect handled via isDayChart).
  • Aspects: major and minor aspects with orb, exact angle, and applying/separating; plus detected patterns (grand trine, T-square, …). Orbs are configurable — see Orb policy below.

Vertex and East Point

Beside the Ascendant and Midheaven, every timed chart carries the two prime-vertical angles:

  • chart.vertexRad — the Vertex (western prime-vertical/ecliptic intersection). null at the equator, where the prime vertical degenerates.
  • chart.eastPointRad — the East Point (Equatorial Ascendant). Singularity-free, always present.

Both are radians, tropical true-ecliptic-of-date, like ascendantRad.

House systems

Pass one of these as houseSystem (default: "placidus"):

| Value | System | |---|---| | "placidus" | Placidus | | "koch" | Koch | | "whole_sign" | Whole Sign | | "equal" | Equal | | "porphyry" | Porphyry | | "regiomontanus" | Regiomontanus | | "campanus" | Campanus | | "alcabitius" | Alcabitius | | "topocentric" | Topocentric (Polich–Page) | | "morinus" | Morinus | | "meridian" | Meridian (Axial) |

Zodiac: tropical and sidereal (Vedic)

Every chart is computed in the tropical zodiac. To also get sidereal values, pass an ayanamsa:

| Value | Tradition | |---|---| | "lahiri" | Vedic / Jyotish standard (Chitrapaksha) | | "fagan_bradley" | Western sidereal | | "krishnamurti" | Krishnamurti Paddhati (KP) | | "raman" | B. V. Raman | | "true_chitrapaksha" | True Spica pinned at 0° Libra exactly |

true_chitrapaksha and lahiri are both true-Spica-anchored in this engine and return identical values — this crate's lahiri is the true/Chitrapaksha variant, not the mean-precession construction some reference software uses under that name.

const vedic = engine.computeChart(civil, zone, observer, {
  houseSystem: "whole_sign",
  ayanamsa: "lahiri",
});
vedic.bodies.moon.siderealLongitudeRad; // sidereal position
vedic.siderealHouses.cuspsRad;          // sidereal cusps
vedic.ayanamsaRad;                      // the ayanamsa applied

Sidereal output is additive — the tropical fields are always present.

Custom ayanamsa

For a sidereal zero point not in the table, pass ayanamsaCustom instead of ayanamsa — a linear model in degrees: valueAtT0Deg at Julian date t0JdTt (TT), advancing at ratePerCenturyDeg per Julian century. It takes precedence over ayanamsa and reports ayanamsaName === "custom".

const custom = engine.computeChart(civil, zone, observer, {
  ayanamsaCustom: {
    t0JdTt: 2451545.0,      // J2000.0 (TT)
    valueAtT0Deg: 23.85,    // ayanamsa at t0
    ratePerCenturyDeg: 1.4, // ≈ precession rate
  },
});

Orb policy

By default, aspects use fixed per-aspect orbs (conjunction 8°, sextile 6°, square/trine 7°, opposition 8°, minors 3°). Pass an orbPolicy to choose a different scheme. Every field is optional and in degrees; omitting orbPolicy keeps the defaults exactly.

| Field | Meaning | |---|---| | resolution | "perAspect" (default, fixed per-aspect orbs), "moietySum" (moiety(a)+moiety(b), + luminary bonus, on majors; flat orb on minors), or "moietyMax" (wider of the two body moieties on majors; per-aspect orb on minors) | | moietiesDeg | Per-body moiety (half-orb), e.g. { sun: 4.5, moon: 4.5 } | | defaultMoietyDeg | Moiety for bodies not in moietiesDeg | | luminaries | Bodies earning the luminary bonus (moietySum) | | luminaryBonusDeg | Extra orb on a major leg touching a luminary | | minorFlatOrbDeg | Flat orb for minor aspects under moietySum | | majorAspects | Which aspect names count as "major" | | basesDeg | Per-aspect base-orb overrides, e.g. { conjunction: 10 } |

const chart = engine.computeChart(civil, zone, observer, {
  orbPolicy: {
    resolution: "moietySum",
    moietiesDeg: { sun: 4.5, moon: 4.5, mercury: 3.5 },
    defaultMoietyDeg: 3.5,
    luminaries: ["sun", "moon"],
    luminaryBonusDeg: 1.0,
    minorFlatOrbDeg: 1.5,
  },
});

The policy governs both chart.aspects and the patterns built from them. AspectHit.orbRad reports the resolved allowance actually used.

Extended patterns

Pass extendedPatterns: true to also populate chart.patternsExtended with the full seven-figure set — the four default figures plus kite, stellium, and minor grand trine — computed over the bodies, the angles, and the true node. This is additive: chart.patterns (the default four figures) is unchanged.

const chart = engine.computeChart(civil, zone, observer, {
  extendedPatterns: true,
});
for (const p of chart.patternsExtended) {
  p.pattern;   // "kite" | "stellium" | "minor_grand_trine" | …
  p.bodies;    // members, apex-first where a figure has an apex
  p.apex;      // focal point (t_square/yod/minor_grand_trine) or null
  p.sign;      // zodiac sign for a stellium, else null
  p.maxOrbRad; // loosest leg / widest spread, radians
}

Extended minor bodies (optional)

Sixteen additional bodies are supported but not embedded: ceres, pallas, juno, vesta, eris, sedna, haumea, makemake, quaoar, orcus, varuna, ixion, gonggong, pholus, nessus, chariklo. Load a body's data table first, then request it:

engine.loadMinorBodyTable("ceres", ceresTableText);
const chart = engine.computeChart(civil, zone, observer, {
  includeMinorBodies: ["ceres"],
});

A requested body whose table isn't loaded (or whose date is outside table coverage) is listed in chart.outOfRange instead of failing the chart.

Fast path: positions only

For transit scans and anything else that samples a few bodies across many instants, computeBodies returns just the requested bodies' apparent positions and daily rates — identical numbers to the full chart, at a fraction of the cost (a full chart computes houses, nodes, lots, aspects, and patterns you may not need):

const { bodies } = engine.computeBodies(
  { year: 2026, month: 1, day: 1, hour: 12, minute: 0 }, // UTC fields
  ["jupiter", "saturn", "mars"],
);
bodies.jupiter.longitudeRad;            // apparent ecliptic longitude
bodies.jupiter.longitudeRateRadPerDay;  // analytic rate (negative = retrograde)

Equatorial and heliocentric positions

Two more position surfaces re-express the same apparent pipeline in other frames. Both take resolved UTC fields plus a body list, and route uranus/neptune/pluto through the DE441 tables just like the chart.

Equatorial — apparent RA/Dec of date plus astrometric ICRF/J2000:

const eq = engine.computeEquatorial(
  { year: 2026, month: 1, day: 1, hour: 12, minute: 0 },
  ["mars", "uranus"],
);
eq.bodies.mars.ofDate.rightAscensionRad; // apparent RA, equinox of date
eq.bodies.mars.ofDate.declinationRad;    // apparent Dec of date
eq.bodies.mars.j2000.rightAscensionRad;  // astrometric ICRF/J2000 RA

Heliocentric — geometric ecliptic-of-date longitude, latitude, and radius. Defined only for Sun-orbiting bodies: requesting the Sun, Moon, or a lunar node/Lilith throws.

const helio = engine.computeHeliocentric(
  { year: 2026, month: 1, day: 1, hour: 12, minute: 0 },
  ["jupiter", "uranus"],
);
helio.bodies.jupiter.longitudeRad; // heliocentric ecliptic longitude
helio.bodies.jupiter.radiusAu;     // heliocentric distance

For both, a body outside its table coverage (or an unloaded minor) is listed in outOfRange rather than failing the call.

Time handling

computeChart takes naive civil time plus an IANA zone and resolves DST correctly:

  • Ambiguous local times (DST fall-back) throw AmbiguousLocalTimeError unless you pass fold (0 = earlier instant, 1 = later).
  • Nonexistent local times (spring-forward gap) always throw NonexistentLocalTimeError.

If you already have UTC, use engine.computeChartUtc(utc, observer, options) and skip timezone resolution entirely.

Accuracy

Apparent positions are computed from VSOP87E, ELP/MPP02, and JPL-derived state vectors with full IAU 2000A/2006 precession- nutation, light-time, and relativistic aberration.

vs JPL Horizons, 1900–2100 (median error, arcseconds):

| Body | Median error | vs. the previous Moshier-derived engine AuLun ran on | |---|---|---| | Moon | 0.06″ | 67× more accurate | | Sun | 0.13″ | 5× more accurate | | Mercury / Venus | 0.13″ | 5× more accurate | | Mars | 0.12″ | 3× more accurate | | Jupiter / Saturn | 0.24–0.28″ | at parity (both already sub-arcsecond) | | Uranus / Neptune / Pluto | 0.02–0.13″ | at parity to 1.2× |

Every body ships sub-arcsecond median accuracy. Independently cross-checked against a second, widely-used commercial ephemeris implementation on identical ground truth: this engine lands within 1.0–1.3× of it for the Moon, the outer planets, Chiron, and Vesta — effectively at parity for the bodies that matter most in natal and transit work, with the largest remaining gap (2–4×, still sub-arcsecond in absolute terms) on the inner planets and main-belt asteroids.

Numbers above are generated by a committed benchmark harness against cached JPL Horizons reference data (41 epochs, 1900–2100, no hand-typed values) — full per-body breakdown across all 25 supported bodies available on request.

License

Proprietary. Free for non-commercial use — personal, educational, and research use is free of charge under the LICENSE shipped with this package. Use in or for anything sold, monetized, or operated for commercial advantage requires a commercial license: contact the copyright holder via https://github.com/AuLunArcana.

Changelog

See CHANGELOG.md, included in this package.

© 2026 AuLun Arcana LLC. All rights reserved.