# Coordinate Frames _(no submodules)_ ## Purpose Defines the `CoordinateFrame` discriminator (`"heliocentric" | "galactic" | "custom"`) and the conversion entry points used across the universe-family packages. The module is the single seam through which any astronomical coordinate transformation is requested, so consumers do not need to know which rotation matrix or epoch correction is in play — they hand off a `SphericalCoord`, name the source and target frames, and receive a `SphericalCoord` in the new frame. The current implementation is a placeholder identity transform: `convertFrame`, `toHeliocentric`, and `toGalactic` return the input unchanged. The public surface and discriminator are stable; consumers can wire to it now and pick up real conversions when this package adds the rotation pipeline without touching any call site. ## Features - `CoordinateFrame` string-literal union — exhaustively switchable. - `convertFrame(coord, from, to, observer?)` — generic frame-to-frame conversion entry point. - `toHeliocentric(coord, observer)` — convenience wrapper for the most common conversion (observer-relative to heliocentric). - `toGalactic(coord)` — observer-independent rotation into galactic coordinates. - Identity short-circuit when `from === to`. - Observer parameter accepts the full `ObserverPosition` discriminated union (surface / atmospheric / space). ## Usage: Basic Example ```ts import { convertFrame } from "@suaveplan/universe"; const coord = { latitude: 10, longitude: 20 }; const same = convertFrame(coord, "heliocentric", "heliocentric"); // same === coord (identity short-circuit) ``` ## Usage: Advanced Example ```ts import { convertFrame, toGalactic, toHeliocentric, type CoordinateFrame, } from "@suaveplan/universe"; const target: CoordinateFrame = "galactic"; const observer = { kind: "surface" as const, planet: { name: "Earth", mass: 1, radius: 1, polarRadius: 1, surfaceGravity: 1, rotationPeriod: 1, axialTilt: 23.4, atmosphere: null, satellites: [], }, coord: { latitude: 51.5, longitude: -0.12 }, }; const skyDirection = { latitude: 45, longitude: 270 }; const heliocentric = toHeliocentric(skyDirection, observer); const galactic = toGalactic(heliocentric); const fromHelio = convertFrame(skyDirection, "heliocentric", target, observer); ``` ## API Reference ### `type CoordinateFrame` `"heliocentric" | "galactic" | "custom"` — string-literal union safe to switch on with exhaustiveness checking. ### `convertFrame(coord, from, to, observer?)` | Param | Type | Description | |---|---|---| | `coord` | `SphericalCoord` | Latitude/longitude pair in source frame. | | `from` | `CoordinateFrame` | Source frame. | | `to` | `CoordinateFrame` | Target frame. | | `observer` | `ObserverPosition?` | Required for any observer-dependent conversion (e.g. topocentric → heliocentric). | Returns a `SphericalCoord` in the target frame. Returns `coord` unchanged when `from === to`. ### `toHeliocentric(coord, observer)` Convenience wrapper that conceptually corresponds to `convertFrame(coord, observer-frame, "heliocentric", observer)`. ### `toGalactic(coord)` Observer-independent rotation from equatorial / heliocentric into galactic coordinates. ## Implementation Notes The body of every function is currently the identity, which keeps the API contract stable while the rotation matrices (J2000 → galactic, ICRS → heliocentric ecliptic, axial-tilt / sidereal-time corrections) are implemented in follow-up changes. Consumers should treat `"custom"` as an extension point — any future conversion that requires caller-supplied basis vectors is expected to flow through `convertFrame(..., "custom", ...)`. Do not bake the identity behaviour into call sites: the contract is "returns the coordinate in the target frame," not "returns the coordinate unchanged."