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

caelus-birth

v0.8.0

Published

Local birth time + place -> UT, correctly. IANA timezone resolution for caelus charts: DST, half-hour zones, ambiguous and nonexistent times.

Readme

caelus-birth

Local birth time + place → UT, correctly. The timezone layer for caelus charts.

The trap this package exists for

caelus takes UT. Users state local wall-clock time. The naive conversion uses the runtime's timezone and is the single most common cause of wrong charts in amateur astrology software:

// WRONG — interprets "14:30" in whatever zone the server/browser runs in
const d = new Date("1990-06-10T14:30:00");
engine.chart(d.getUTCFullYear(), /* ... */);
// Tampa birth computed on a UTC server: Asc 10°54' Leo  ← wrong by ~2 signs

// RIGHT — resolve the zone from the birthplace, apply historical tzdb rules
import { toUT } from "caelus-birth";
const t = toUT({ year: 1990, month: 6, day: 10, hour: 14, minute: 30,
                 lat: 27.95, lon: -82.46 });
// zone "America/New_York", EDT, 18:30 UT → Asc 3°26' Libra  ← correct

Four hours of error moves the Ascendant ~60°, every house cusp with it, and (here) the Moon by 2°.

Usage

npm install caelus-birth
import { toUT, localToChart } from "caelus-birth";

const t = toUT({
  year: 1955, month: 6, day: 10, hour: 12, minute: 0,
  lat: 51.5, lon: -0.12,          // east-positive longitude
  // zone: "Europe/London"        // optional IANA override
});
t.utc;            // { year: 1955, month: 6, day: 10, hour: 11, ... } (BST +1)
t.jdUt;           // ready for engine.chart() / engine.position()
t.zone;           // "Europe/London" — resolved offline from coordinates
t.offsetMinutes;  // 60
t.dst;            // true
t.status;         // "ok" | "ambiguous" | "nonexistent"

// or in one call:
const { chart, status } = localToChart(input, engine, "placidus");

DST edge cases are reported, never guessed silently

  • "ambiguous" — the fall-back hour happens twice (e.g. 01:30 on the night US DST ends). Both readings are returned in candidates (earliest first) and the earlier instant is chosen by default. Surface this to the user: "clocks changed that night — we used the earlier 01:30; switch?"
  • "nonexistent" — the spring-forward gap (e.g. 02:30 the night US DST starts never existed). Shifted forward per tzdb convention (02:30 EST → 03:30 EDT) and flagged.

Historical rules come from the runtime's IANA database (via Luxon / Intl): half-hour and 45-minute zones, southern-hemisphere DST, pre-1970 rules, and wartime offsets (British Double Summer Time, US War Time) all resolve correctly — see the golden tests.

Geocoding (optional, separate entry point)

Place-name search needs a network service, so the core stays offline-pure and adapters live behind caelus-birth/geocode:

import { openMeteoGeocoder } from "caelus-birth/geocode";
const places = await openMeteoGeocoder.search("Tampa");
// [{ name: "Tampa, Florida, United States", lat: 27.95, lon: -82.46, ... }]

The shipped adapter uses the free, keyless Open-Meteo Geocoding API (data: GeoNames, CC-BY 4.0 — attribution required). Implement the one-method Geocoder interface to use any other service.

Scope

Coordinates → zone is offline (tz-lookup, ~70 KB embedded map, CC0). Zone → offset uses the runtime's Intl tzdb (Luxon, MIT). This package has runtime dependencies by design; caelus core stays at zero.

The caelus packages

  • caelus — the engine
  • caelus-birth — this package
  • caelus-wheel — React SVG chart wheel
  • caelus-mcp — MCP server, seven chart tools over stdio