---
path: /domains/nyx/coordinates
surface: customer
domain: nyx
auth: signed-in
source: apps/oshun/web/src/app/domains/nyx/coordinates/page.tsx
status: walked
last_walked:
  '2026-05-29 automated runtime walk (Playwright) — hydration fix verified: 0
  page/console errors, render+data OK; live SR/touch/offline/telemetry pending
  manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md'
---

# Nyx · Coordinate Tools

## Purpose

Astronomical coordinate-system conversion and timing tools — equatorial ↔
horizontal, galactic conversions, airmass calculation, sidereal time, rise/set
times, and coordinate format conversion. Wired via
`apps/oshun/web/src/app/domains/nyx/coordinates/page.tsx` ('use client') which
mounts `<NyxCoordinateTools onClose={() => router.back()} />`.

## Entry points

- **Direct URL / bookmark** — yes (signed-in)
- **In-app navigation** — verify Nyx domain hub deep-link presence
- **Browser back affordance** — in-component back button calls `router.back()`

## Layout regions

`NyxCoordinateTools`
(`apps/oshun/web/src/components/domains/nyx/NyxCoordinateTools.tsx`):

- **Header**: back button (`aria-label="Go back"`), title
  `<h1>Coordinate Tools</h1>`
- **Tab bar**: six tabs from `TABS` — `RA/Dec ↔ Alt/Az` (`converter`),
  `Galactic` (`galactic`), `Airmass` (`airmass`), `Sidereal Time` (`sidereal`),
  `Rise/Set` (`riseset`), `Format` (`format`)
- **Content**: per-tab calculator with inputs and computed outputs
- **Direction toggle** (within `converter`/`galactic`): switches conversion
  direction (`eq2hz` ↔ `hz2eq`, `eq2gal` ↔ `gal2eq`)

## States

- [ ] **Loading** — no async data
- [ ] **Default tab** — `converter` is initial active tab
- [ ] **Computed result** — converter shows transformed coordinates with the
      observer location and time
- [ ] **Invalid input** — verify behaviour on out-of-range RA / Dec / lat / lng
- [ ] **Offline** — static client bundle; works offline

## Interactions

### Header

- [ ] **"Go back" button** (icon button, `ArrowLeft`)
  - Function: `onClose` → `router.back()`
  - Screen reader: "Go back"

### Tab bar

- [ ] **RA/Dec ↔ Alt/Az tab** — sets `direction='converter'`
- [ ] **Galactic tab** — sets `direction='galactic'`
- [ ] **Airmass tab**
- [ ] **Sidereal Time tab**
- [ ] **Rise/Set tab**
- [ ] **Format tab**

### Converter direction toggle (within converter tab)

- [ ] **eq2hz button** (`Equatorial → Horizontal`) — sets `direction='eq2hz'`
- [ ] **hz2eq button** (`Horizontal → Equatorial`) — sets `direction='hz2eq'`

### Galactic direction toggle (within galactic tab)

- [ ] **eq2gal button** (`Equatorial → Galactic`) — sets `direction='eq2gal'`
- [ ] **gal2eq button** (`Galactic → Equatorial`) — sets `direction='gal2eq'`

### Per-tab input fields

- [ ] **RA / Dec inputs** — numeric inputs feeding conversion functions
- [ ] **Lat / Lng / time inputs** (where applicable) — observer context
- [ ] **Computed output rows** — read-only display of the transformed
      coordinates

## Data & contracts

- **Reads**: pure client computation — no network reads
- **Writes**: none
- **Realtime**: none
- **Caching**: static client bundle
- **Auth/role check**: middleware enforces signed-in for `/domains/*`

## Cross-references

- Domain hub: [`nyx.md`](./nyx.md)
- Sibling tools: [`domains-nyx-star-chart.md`](./domains-nyx-star-chart.md),
  [`domains-nyx-time-travel.md`](./domains-nyx-time-travel.md),
  [`domains-nyx-telescope.md`](./domains-nyx-telescope.md)
- Component source:
  `apps/oshun/web/src/components/domains/nyx/NyxCoordinateTools.tsx`

## Open questions / known gaps

- [x] **Runtime walk (2026-05-29) — defect FIXED & verified:** React 418
      hydration mismatch resolved (time-derived values now deferred to a
      post-mount effect via `useClientNow`/`useIsMounted` from
      `@/hooks/useClientTime`; for `/coordinates` the missed `RiseSetCalculator`
      site was gated). Re-walked against a fresh build: 0 page errors, 0 console
      errors, HTTP 200. React error #418; visit https://react.dev/errors/418?a.
      React error 418 is a hydration mismatch — server-rendered HTML differs
      from the client (this view renders time/position-dependent content, e.g.
      `new Date()`/`toLocale*`, without `suppressHydrationWarning`). Fix:
      compute time-dependent values in an effect or gate with
      `suppressHydrationWarning`. Status kept `drafted` until fixed.
- [ ] Document exact per-tab input field labels (lat/lng/RA/Dec format expected)
- [ ] Confirm whether numeric inputs surface ARIA labels and validation messages
- [ ] Verify whether observer location defaults to `DEFAULT_OBSERVER` or
      requests user lat/lng
