Guides

Architecture

The packages are layers, not alternatives. A real app threads a birth event through all of them; each does one job and hands a plain object to the next.

place + local time
    → caelus-birth    resolve IANA zone from coordinates, local → UT (DST-safe)
    → caelus          positions, houses, aspects from the UT instant
    → caelus-wheel    SSR-safe SVG wheel from the chart object
    → caelus-mcp      (optional) the same engine, exposed as AI tools

Only caelus-birth carries runtime dependencies (timezone data); the core engine stays zero-dependency and I/O-free, and the wheel renders to a string. That split is why the same chart code runs in the browser, on edge, in Node, and behind MCP.

One component, end to end

This is the whole pipeline in a single server component — birth input to rendered wheel, with the timezone resolved for you:

NatalWheel.tsx
import { Engine } from "caelus";
import { embeddedData } from "caelus/data-embedded";
import { localToChart } from "caelus-birth";
import { ChartWheel } from "caelus-wheel";

// Build the engine once and reuse it (module scope, not per render).
const engine = new Engine(embeddedData);

export function NatalWheel() {
// Local wall-clock time and place, exactly as a person would enter them:
const { chart, zone, status } = localToChart(
  { year: 1990, month: 6, day: 10, hour: 14, minute: 30, lat: 27.95, lon: -82.46 },
  engine,
);

return (
  <figure>
    <ChartWheel chart={chart} size={520} showAspects />
    <figcaption>
      {zone}
      {status !== "ok" && ` · ${status} local timecheck the offset`}
    </figcaption>
  </figure>
);
}

localToChart resolves the IANA zone from the coordinates, converts the local time to UT, and runs engine.chart — returning the chart plus a status (ok, ambiguous, or nonexistent) so DST edge cases surface instead of silently producing a wrong chart. See Edge Cases & Stability for those cases.

Where each package fits

LayerPackageInput → outputRuntime deps
Time & placecaelus-birthlocal time + coords → UT + zone + statustz data
EnginecaelusUT instant + location → chart objectnone
Rendercaelus-wheelchart object → SVG stringnone
Agentscaelus-mcpMCP tool call → chart payloadMCP SDK

Start from the template

caelus-starter is this exact pipeline as a deployable Next.js app: a birth form, caelus-birth timezone handling, a server-rendered caelus-wheel, and an optional reading route. Clone it rather than wiring the layers from scratch.

See the Quickstart for the engine alone, the MCP Setup for the agent layer, and Recipes for queries and event search. Electional Search threads this same pipeline through a richer use case: scanning a window for the best moment, not just rendering one fixed instant.