---
path: /domains/nyx/telescope
surface: customer
domain: nyx
auth: signed-in
source: apps/oshun/web/src/app/domains/nyx/telescope/page.tsx
status: walked
last_walked:
  - 2026-07-02 equipment-boundary addendum — Playwright now opens the
    Telescope Control Equipment tab, verifies seeded telescope-only profiles,
    creates a new profile through the Add Profile flow, and proves that profile
    does not leak into `/domains/nyx/observation-log` equipment fixtures. Spec:
    `apps/oshun/web/e2e/nyx-tonight-observation.spec.ts`.
  - '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
    (2xx), console/page-errors, expected content, screenshot verified; live
    screen-reader, touch, offline, and telemetry-delivery checks pending a
    manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md'
---

# Nyx · Telescope Control

## Purpose

Telescope-control surface for hardware integration (ASCOM / Alpaca) — connection
profile, current scope status, GoTo target selection, tracking / guiding
configuration, and equipment library. Wired via
`apps/oshun/web/src/app/domains/nyx/telescope/page.tsx` ('use client') which
mounts `<NyxTelescopeControl onClose={() => router.back()} />`.

## Entry points

- **Direct URL / bookmark** — yes (signed-in)
- **In-app navigation** — verify Nyx hub link, and any "Slew to here" link from
  catalog or star-chart popups
- **Browser back affordance** — in-component back button calls `router.back()`

## Layout regions

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

- **Header**: back button (`aria-label="Back"`), `Telescope` icon, title
  `<h1>Telescope Control</h1>`, connection-status badge (status text + pulsing
  indicator when `connecting`)
- **Tab bar** (`TABS`): five tabs — `Connection`, `Status`, `GoTo`, `Tracking`,
  `Equipment`
- **Per-tab content**:
  - `connection` — protocol (`ASCOM`), host (`localhost`), port (`11111`),
    device name (`Telescope Simulator`) inputs; Connect / Disconnect actions
  - `status` — current state: tracking mode, isTracking, isSlewing, isParked,
    current RA / Dec / altitude / azimuth, sidereal time, pier side, guide
    rates, settling time
  - `goto` — RA H/M/S + Dec D/M/S inputs (defaults `05:35:17 / -05:23:28`),
    search box with object suggestions filtered from `COMMON_OBJECTS`
  - `tracking` — slew speed slider, pulse RA / pulse Dec duration inputs
  - `equipment` — equipment profile list (default `eq-sct-11`), eyepiece
    selector (`25mm`), computed magnification + true FOV; "Add profile" flow

## States

- [ ] **Loading** — bundled fixture; client-only
- [ ] **Disconnected** — initial state; status badge "disconnected"
- [ ] **Connecting** — status "connecting" with pulsing indicator
- [ ] **Connected** — status "connected"; telescope state controls become usable
- [ ] **Connection failed** — verify error state copy and recovery
- [ ] **GoTo search empty** — no suggestions visible
- [ ] **GoTo search with results** — `filteredObjects` populated from
      `COMMON_OBJECTS` filter
- [ ] **Slewing** — verify visual indication when `isSlewing`
- [ ] **Parked** — verify visual indication when `isParked`
- [x] **Add profile open** — `showAddProfile` true; new-profile name input
      appears after clicking "Add Profile"
- [ ] **Offline** — bundle is local; an actual ASCOM connection requires LAN
      reachability

## Interactions

### Header

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

### Tab bar (five tabs)

- [ ] **Connection tab** — sets `activeTab='connection'`
- [ ] **Status tab** — sets `activeTab='status'`
- [ ] **GoTo tab** — sets `activeTab='goto'`
- [ ] **Tracking tab** — sets `activeTab='tracking'`
- [ ] **Equipment tab** — sets `activeTab='equipment'`

### Connection tab

- [ ] **Protocol selector** — verify exact options (ASCOM is the default)
- [ ] **Host input**
- [ ] **Port input**
- [ ] **Device name input**
- [ ] **Connect button** — calls `handleConnect` → sets status to `connecting`
- [ ] **Disconnect button** — verify

### Status tab

- [ ] **Tracking mode selector** — values include `sidereal`
- [ ] **Pier side indicator** — read-only
- [ ] **Guide rate fields** — RA / Dec rates

### GoTo tab

- [ ] **RA H / M / S inputs** — three numeric fields
- [ ] **Dec D / M / S inputs** — three numeric fields (allows negative degrees)
- [ ] **Search input** — `gotoSearch`; opens suggestion list with
      `showObjectSuggestions`
- [ ] **Object suggestion item** (button) — selects target

### Tracking tab

- [ ] **Slew speed slider** (`slewSpeed`)
- [ ] **Pulse RA duration input**
- [ ] **Pulse Dec duration input**

### Equipment tab

- [x] **Equipment profile card** (each in `equipmentProfiles`) — selecting sets
      `activeProfileId`
- [ ] **Eyepiece selector** — sets `selectedEyepiece`
- [ ] **Magnification readout** —
      `Math.round(focalLengthMm /     selectedEyepiece)`
- [ ] **True FOV readout** — `52 / magnification`
- [x] **"Add profile" button** — toggles `showAddProfile`
- [x] **New profile name input** — `newProfileName`
- [x] **Save profile button** — "Add" appends a profile to the in-component
      `equipmentProfiles` array for this mounted telescope-control session

## Data & contracts

- **Reads**: `INITIAL_EQUIPMENT_PROFILES` + `COMMON_OBJECTS` bundled inside the
  component
- **Writes**: telescope state held in component (no real network in code; ASCOM
  connection is mocked locally per the connection handlers). Added equipment
  profiles are component-local and are not shared with
  `/domains/nyx/observation-log`.
- **Realtime**: none in code
- **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-catalogs.md`](./domains-nyx-catalogs.md) (catalog
  GoTo handoff), [`domains-nyx-coordinates.md`](./domains-nyx-coordinates.md),
  [`domains-nyx-observation-log.md`](./domains-nyx-observation-log.md)
- Component source:
  `apps/oshun/web/src/components/domains/nyx/NyxTelescopeControl.tsx`

## Automated coverage

- `apps/oshun/web/e2e/nyx-tonight-observation.spec.ts` — opens Equipment,
  verifies the seeded telescope profiles, creates a browser-visible profile via
  Add Profile, and proves the profile remains separate from the Observation Log
  equipment fixture list.

## Open questions / known gaps

- [ ] Confirm whether the ASCOM / Alpaca client actually reaches a local server
      or is fully mocked
- [ ] Document the catalog → telescope GoTo handoff (no entry-point query param
      is consumed by `page.tsx`)
- [ ] Confirm whether `Add to telescope GoTo` is an action surfaced on catalog
      or star-chart popups
- [ ] Verify keyboard semantics on RA / Dec multi-field inputs (single tab stop
      vs six)
