# Observer _(no submodules)_ ## Purpose Re-exports the `ObserverPosition` discriminated union that every universe-family entry point consumes. The union has three branches — `SurfaceObserver`, `AtmosphericObserver`, and `SpaceObserver` — distinguished by a `kind` literal field so call sites can narrow exhaustively without runtime type tags or class hierarchies. Centralising these types in one module gives `@suaveplan/universe/client/client`, providers, and frame-conversion utilities a single shape to consume. Because the source declarations live in `@suaveplan/types` (zero-runtime, types-only), this re-export adds no bundle weight; it exists so consumers can import observer shapes without crossing into the foundational types package directly. ## Features - `ObserverPosition` — full discriminated union, switch on `kind`. - `SurfaceObserver` — planet-bound observer at a `{latitude, longitude}` coordinate. - `AtmosphericObserver` — same as surface but with `altitudeMetres` (planes, balloons, drones). - `SpaceObserver` — heliocentric vector + reference `frame` (e.g. `"icrs"`). - All three branches share the `kind` literal as the discriminator. - Pure types — zero runtime cost, tree-shaken to nothing. ## Usage: Basic Example ```ts import type { ObserverPosition } from "@suaveplan/universe"; const observer: ObserverPosition = { kind: "space", heliocentricVec: { x: 1, y: 0, z: 0 }, frame: "icrs", }; ``` ## Usage: Advanced Example ```ts import type { AtmosphericObserver, ObserverPosition, SpaceObserver, SurfaceObserver, } from "@suaveplan/universe"; function describe(o: ObserverPosition): string { switch (o.kind) { case "surface": return `surface at ${o.coord.latitude},${o.coord.longitude}`; case "atmospheric": return `${o.altitudeMetres} m above ${o.planet.name}`; case "space": return `space, ${o.frame} vector ${JSON.stringify(o.heliocentricVec)}`; } } const earth = { name: "Earth", mass: 1, radius: 1, polarRadius: 1, surfaceGravity: 1, rotationPeriod: 1, axialTilt: 23.4, atmosphere: null, satellites: [], }; const surface: SurfaceObserver = { kind: "surface", planet: earth, coord: { latitude: 51.5, longitude: -0.12 }, }; const balloon: AtmosphericObserver = { kind: "atmospheric", planet: earth, coord: { latitude: 51.5, longitude: -0.12 }, altitudeMetres: 12000, }; const probe: SpaceObserver = { kind: "space", heliocentricVec: { x: 1.0, y: 0.0, z: 0.0 }, frame: "icrs", }; [surface, balloon, probe].forEach((o) => describe(o)); ``` ## API Reference ### `type SurfaceObserver` | Property | Type | Description | |---|---|---| | `kind` | `"surface"` | Discriminator literal. | | `planet` | `PlanetConfig` | Host body (mass, radius, axial tilt, satellites …). | | `coord` | `{ latitude: number; longitude: number }` | Geographic location in degrees. | ### `type AtmosphericObserver` Extends `SurfaceObserver` shape with an additional `altitudeMetres: number` and `kind: "atmospheric"`. ### `type SpaceObserver` | Property | Type | Description | |---|---|---| | `kind` | `"space"` | Discriminator literal. | | `heliocentricVec` | `{ x: number; y: number; z: number }` | Cartesian position in AU. | | `frame` | `string` | Reference frame label, e.g. `"icrs"`. | ### `type ObserverPosition` `SurfaceObserver | AtmosphericObserver | SpaceObserver` — exhaustive switch on `kind`. ## Implementation Notes These types are re-exported from `@suaveplan/types`; this module contains no runtime code and contributes nothing to the emitted bundle. Keeping the canonical declarations in `@suaveplan/types` preserves the universe-family rule that any observer-shaped value flowing through providers, the client, frame conversions, or packet codecs is structurally identical no matter which sibling package produced it.