---
path: /domains/nyx/satellites
surface: customer
domain: nyx
auth: signed-in
source: apps/oshun/web/src/app/domains/nyx/satellites/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 · Satellite Tracker

## Purpose

Satellite tracking surface — live map of currently overhead satellites, pass
prediction lookups, Iridium flare events, and Starlink-specific feeds. Wired via
`apps/oshun/web/src/app/domains/nyx/satellites/page.tsx` ('use client') which
mounts `<NyxSatelliteTracker onBack={() => router.back()} />`.

## Entry points

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

## Layout regions

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

- **Header**: back button (`aria-label="Back"`), title
  `<h1>Satellite Tracker</h1>` (1.125rem)
- **Tab bar**: four tabs from local `tabs` — `Live Map` (`map`, `Globe`),
  `Pass Predictions` (`passes`, `Eye`), `Iridium Flares` (`flares`, `Zap`),
  `Starlink` (`starlink`, `Wifi`)
- **Per-tab content**:
  - `map` — live map with satellite positions
  - `passes` — predicted pass list for the observer
  - `flares` — Iridium flare event list
  - `starlink` — Starlink-specific filters and trains

## States

- [ ] **Loading** — bundled fixture; client-only
- [ ] **Default tab** — `Live Map` (verify initial `tab`)
- [ ] **Map populated** — satellite markers visible
- [ ] **Pass predictions populated** — upcoming passes listed
- [ ] **Pass predictions empty** — verify empty-state copy
- [ ] **Flares populated** / **empty**
- [ ] **Starlink train listed** — verify whether a specific train is shown
- [ ] **Offline** — static bundle; map tiles may fail offline

## Interactions

### Header

- [ ] **"Back" button** (icon, `ArrowLeft`) — `onBack` → `router.back()`

### Tab bar (four tabs)

- [ ] **Live Map tab** — sets `tab='map'`
- [ ] **Pass Predictions tab** — sets `tab='passes'`
- [ ] **Iridium Flares tab** — sets `tab='flares'`
- [ ] **Starlink tab** — sets `tab='starlink'`

### Live Map tab

- [ ] **Map provider** — verify (Leaflet / Mapbox / SVG)
- [ ] **Satellite marker tap** — verify behaviour
- [ ] **Filter / search** — verify any filtering of the visible satellites

### Pass Predictions tab

- [ ] **Each pass row** — verify whether row is interactive (detail) or
      read-only
- [ ] **Sort / filter** — verify sort affordances

### Iridium Flares / Starlink tabs

- [ ] **Event row** — read-only metadata

## Data & contracts

- **Reads**: bundled fixture inside the component
- **Writes**: none
- **Realtime**: none in code; verify whether the live-map updates positions on a
  timer
- **Caching**: static client bundle; map tiles depend on provider
- **Auth/role check**: middleware enforces signed-in for `/domains/*`

## Cross-references

- Domain hub: [`nyx.md`](./nyx.md)
- Sibling tools: [`domains-nyx-neo.md`](./domains-nyx-neo.md),
  [`domains-nyx-solar.md`](./domains-nyx-solar.md)
- Dashboard widget: [`domains-nyx-widgets.md`](./domains-nyx-widgets.md)
  (`ISS Tracker` widget mirrors a subset of this view)
- Component source:
  `apps/oshun/web/src/components/domains/nyx/NyxSatelliteTracker.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.
- [ ] Confirm whether the live map is animated (positions advance on a timer) or
      static
- [ ] Document the map tile provider and offline behaviour
- [ ] Verify whether pass predictions use the user's actual lat/lng or
      `DEFAULT_OBSERVER`
