# Celestial geometry

Kepler's equation solved to machine precision, ellipses about a focus, the terminator great circle, illumination and limb darkening, body frames, and a deterministic irregular radius field.

> For the complete index, see [llms.txt](https://robocn.dev/llms.txt). A Markdown version of any page is available by appending `.md` to its URL or by sending an `Accept: text/markdown` header.

## Install

```bash
bunx --bun shadcn@latest add https://robocn.dev/r/celestial-geometry.json
```

Registry item: `celestial-geometry` · [`https://robocn.dev/r/celestial-geometry.json`](https://robocn.dev/r/celestial-geometry.json)

## Notes

- Pure functions over plain `{x, y, z}` in the set's world axes. No React, no camera, no dependencies.
- Kepler is safeguarded rather than plain Newton: the root is always within `e` of the mean anomaly, so that bracket is exact and any step leaving it is replaced by a bisection. Newton alone wanders near periapsis on a very eccentric orbit.
- No gravity, no perturbation theory, no radiative transfer and no ephemeris. The elements are the caller's, bodies do not pull on each other, and nothing here is a position for a date.

## Usage

```tsx
import { orbitalState, terminator, limbDarkening } from "@/lib/robocn/celestial"

const state = orbitalState({ semiMajor: 100, eccentricity: 0.5, period: 4 }, time)
state.radius                       // a(1 − e·cos E): the hub is at a focus
terminator(44, { x: 0.4, y: 0.7, z: -0.6 })
```

## API

| name | type | default | description |
| --- | --- | --- | --- |
| `solveKepler(meanAnomaly, eccentricity?)` | `number` | — | The eccentric anomaly, by safeguarded Newton. Inverts itself to 1e-9 at every mean anomaly for eccentricities up to 0.97. |
| `orbitalState(elements, time?)` | `OrbitalState` | — | Position, radius and true anomaly, with the focus at the origin. One period returns the body to where it started, and equal areas are swept in equal times. |
| `orbitPath(elements, steps?)` | `Vec3[]` | — | The ellipse, stepped in eccentric anomaly so the curve is evenly drawn rather than bunched where the body runs. |
| `terminator(radius, sun, steps?)` | `Vec3[]` | — | The great circle where the light grazes the sphere. Projected, it is the crescent — which is why nothing has to draw one. |
| `phaseFraction(sun, viewer)` | `number` | — | The lit fraction of the disc a viewer sees: 1 at opposition, 0 at conjunction, a half at quadrature. |
| `illumination(point, sun)` | `number` | — | How lit one surface point is, −1 to 1, and exactly 0 on the terminator. |
| `limbDarkening(mu, coefficient?)` | `number` | — | `1 − u(1 − μ)`: the real law, monotone from the centre of the disc to the limb. |
| `bodyFrame(options?)` | `CelestialFrame` | — | A body's own axes: tilt the pole, then turn about it. Advance the spin and the precession at different rates and you have a tumble. |
| `surfacePoint(frame, radius, latitude, longitude)` | `Vec3` | — | A point on the turning body. Always at `radius`; a 360° spin is the identity. |
| `latitudeBand / meridian` | `Vec3[]` | — | A parallel and a longitude line on that same body. |
| `sphereLattice(count)` | `Vec3[]` | — | Points spread evenly over a sphere by equal area — craters, granules, spots — with no seam and no pole cluster. |
| `lumpyRadius(direction, options?)` | `number` | — | An irregular body's radius as a fraction of the mean. Deterministic for a seed, bounded in 1 ± depth, and smooth across every lobe axis. |
| `spinAxis / lumpyPoint / discMu` | `—` | — | The pole for a tilt and a bearing, that radius field applied, and the cosine of the view angle at a fraction of the way out of a disc. |

## Source

- `src/lib/robocn/celestial.ts`
