# Artemis II · USA Live Tracker — v1.0.0

**Real-time Orion spacecraft telemetry from NASA/JPL Horizons. Three.js WebGL trajectory visualization. Cloudflare Pages. No middleman.**

America is back at the Moon. Artemis II is the first crewed Orion flight beyond low-Earth orbit since Apollo 17 in 1972. Orion doesn't orbit or land — it flies a free-return trajectory: Earth → trans-lunar injection → lunar closest approach (~7,400 km / 4,600 mi from the Moon's center) → free-return arc → splashdown. This tracker shows that arc live — planned trajectory vs. actual JPL position — with a 3D WebGL scene and plain-English telemetry.

**Live**: [artemis-tracker.pages.dev](https://artemis-tracker.pages.dev)

---

## Mission at a Glance

| Parameter | Value |
|---|---|
| **Launch** | April 2, 2026 · 01:58 UTC · LC-39B, Kennedy Space Center |
| **Vehicle** | SLS Block 1 + Orion Crew Module + European Service Module |
| **Trajectory** | Hybrid free-return — no lunar orbit insertion |
| **Lunar closest approach** | ~7,400 km (~4,600 mi) from Moon center · ~5,660 km (~3,500 mi) above surface |
| **Earth distance at flyby** | ~412,000 km (~256,000 mi) — farthest crewed mission since Apollo 13 |
| **Splashdown** | April 11, 2026 · 00:17 UTC · Pacific Ocean |
| **Duration** | ~9 days |
| **JPL Horizons object ID** | `-1024` (Orion / Artemis II) |

---

## Crew

| Name | Role | Agency | Bio |
|---|---|---|---|
| Reid Wiseman | Commander | NASA 🇺🇸 | [nasa.gov/people/reid-wiseman](https://www.nasa.gov/people/reid-wiseman/) · [@astro_reid](https://twitter.com/astro_reid) |
| Victor Glover | Pilot | NASA 🇺🇸 | [nasa.gov/people/victor-j-glover-jr](https://www.nasa.gov/people/victor-j-glover-jr/) · [@AstroVicGlover](https://twitter.com/AstroVicGlover) |
| Christina Koch | Mission Specialist | NASA 🇺🇸 | [nasa.gov/people/christina-koch](https://www.nasa.gov/people/christina-koch/) · [@Astro_Christina](https://twitter.com/Astro_Christina) |
| Jeremy Hansen | Mission Specialist | CSA 🇨🇦 | [asc-csa.gc.ca bio](https://www.asc-csa.gc.ca/eng/astronauts/canadian/active/bio-jeremy-hansen.asp) · [@Astro_Jeremy](https://twitter.com/Astro_Jeremy) |

---

## Mission Timeline

| Event | UTC | Notes |
|---|---|---|
| Launch | Apr 2 · 01:58 | SLS from LC-39B |
| Trans-Lunar Injection | Apr 3 · 02:00 | Perigee burn → ~24,500 mph escape velocity |
| Enter Lunar SOI | Apr 6 · 04:43 | ~38,000 miles from Moon · lunar gravity dominant |
| Lunar Flyby | Apr 6 · 23:06 | Closest approach — ~7,400 km from Moon center |
| Exit Lunar SOI | Apr 7 · 17:27 | Earth gravity resumes control |
| Entry Interface | Apr 11 · 00:04 | 400,000 ft altitude · ~25,000 mph · heatshield active |
| Splashdown | Apr 11 · 00:17 | Pacific Ocean · USS San Diego recovery |

---

## Official Resources

| Resource | URL |
|---|---|
| Artemis II Mission Page | https://www.nasa.gov/mission/artemis-ii/ |
| NASA Live Stream | https://www.nasa.gov/nasatv/ |
| NASA YouTube | https://www.youtube.com/@NASA |
| Artemis Program | https://www.nasa.gov/artemis/ |
| Orion Spacecraft | https://www.nasa.gov/humans-in-space/orion-spacecraft/ |
| Space Launch System | https://www.nasa.gov/humans-in-space/space-launch-system/ |
| JPL Horizons | https://ssd.jpl.nasa.gov/horizons/ |
| Kennedy Space Center | https://www.nasa.gov/kennedy/ |
| Artemis Mission Blog | https://blogs.nasa.gov/artemis/ |

---

## For Users

No installation. Visit the live URL or run locally with `npm run dev`.

### What you're seeing

| Element | What it shows |
|---|---|
| **MET counter** | Mission Elapsed Time since launch (Apr 2 01:58 UTC), ticking every minute |
| **Telemetry panel** | Distance from Earth · total speed (mph or km/s) + relatable context ("8× faster than a rifle bullet") · Moon-relative speed · distance from Moon · radial velocity (closing/receding) for both bodies |
| **ECI state vector** | Raw J2000 VX/VY/VZ velocity components from JPL Horizons — collapsible expert disclosure |
| **Mission Progress strip** | 0–100% bar with milestone ticks, countdown to next event, On Track / deviation badge |
| **Playback scrubber** | Replay any moment of the mission — drag to scrub, Play at 60× speed, Live to return to real-time |
| **3D trajectory** | WebGL: full free-return arc from real JPL ephemeris, flown portion in red·white·blue, unflown dim. Milestone hover-tooltips. Photorealistic Earth (texture + normal + specular + cloud layer + Fresnel atmosphere). Realistic Moon (crater texture). Orion capsule composite model. Orange actual-position dot. |
| **View from buttons** | Earth · Moon · Cockpit (over-the-shoulder: Orion in foreground, destination ahead) · Overview (full horseshoe + Sun indicator) · Follow Orion · Live Track |
| **Mission Timeline** | Key events with UTC timestamps, rich descriptions, links to NASA |
| **Crew cards** | Role, agency, spaceflight count, career highlight, bio link, X/Twitter |
| **Mission Resources** | 9 official NASA/JPL links |

Units default to **American (mi, mph)**. Hit the **MI** button to toggle metric.

Drag the 3D scene to orbit. Scroll to zoom. Hover milestone dots for event info.

### The free-return trajectory

Orion does not orbit or land. The free-return arc is set up so that if every engine cut out after TLI, Orion would still loop around the Moon and return to Earth on its own. At closest approach, Orion is ~7,400 km (~4,600 mi) from the Moon's center — ~5,660 km (~3,500 mi) above the surface. At that moment, Orion is approximately 412,000 km (~256,000 miles) from Earth, making this the farthest humans have traveled from Earth since Apollo 13 in 1970.

The 3D visualization uses **actual trajectory vectors from JPL Horizons** fetched at startup — not a hand-drawn approximation. The Moon is placed at its real orbital position at closest approach. The orange dot is Orion's true ECI position from live telemetry.

### What is JPL Horizons?

NASA Jet Propulsion Laboratory's Horizons system computes precise ephemeris data for solar system bodies and spacecraft. This tracker queries it live every 2 minutes — no API key, no cost. Object `-1024` is Orion; object `301` is the Moon.

---

## For Developers

### Architecture

Deployed on **Cloudflare Pages** (free tier). Static files served directly; JPL API calls route through Cloudflare Pages Functions to handle CORS.

```
artemistracker/
├── index.html          — Layout, Three.js importmap, Tailwind CDN, Font Awesome, all UI HTML
├── script.js           — ES module: Three.js scene, GSAP animations, JPL fetch, all app logic
├── style.css           — Custom CSS: navy gradients, starfield, patriot stripes, telem panel
├── about.md            — This file
├── src/
│   └── utils.js        — Pure utilities: MISSION_TIMELINE, unit converters, JPL URL builder,
│                         Horizons response parser. Used by tests and dev-server.mjs.
├── functions/
│   ├── jpl.js          — Cloudflare Pages Function at /jpl — general-purpose CORS proxy;
│                         re-encodes params with encodeURIComponent (never + for spaces)
│   └── proxy.js        — Cloudflare Pages Function at /proxy — structured telemetry proxy;
│                         accepts ?t=<ISO>, calls buildJplUrl(), returns parsed JSON
├── tests/
│   ├── dev-server.mjs  — Node.js static server + proxy used by Playwright E2E tests
│   │                     (wrangler workerd blocks outbound TLS; this replaces it for tests)
│   ├── unit/           — Vitest unit tests (converters, timeline, parser, JPL URL builder)
│   └── e2e/            — Playwright E2E tests (fake clock, JPL fixture interception)
├── wrangler.toml       — Cloudflare Pages config
└── package.json        — v1.0.0 · devDeps: vitest, @playwright/test, wrangler
```

### Library stack

| Library | Version | How loaded | Role |
|---|---|---|---|
| **Three.js** | r175 | importmap → `import` | 3D WebGL: Earth, Moon, Orion, starfield, trajectory tubes, sprites |
| **OrbitControls** | r175 addons | importmap → `import` | Mouse/touch orbit, zoom, view-mode camera transitions |
| **GSAP** | 3.12.7 | `+esm` CDN | Telemetry count-up, entrance animations, Orion drift tween |
| **@chenglou/pretext** | 0.0.4 | CDN | Canvas text layout for 3D label sprites |
| **Tailwind CSS** | CDN play | `<script>` | Utility classes for layout, color, responsive spacing |
| **Font Awesome** | 6.5.1 | `<link>` | Icons throughout the UI |
| **Oxanium** | Google Fonts | `<link>` | Display typeface for headings and labels |

### Texture sources

Earth and Moon textures are loaded from the Three.js GitHub repo via jsDelivr CDN (CORS-enabled):

```
https://cdn.jsdelivr.net/gh/mrdoob/three.js@r175/examples/textures/planets/
  earth_atmos_2048.jpg   — color/diffuse (Blue Marble composite)
  earth_normal_2048.jpg  — surface normal map (terrain relief)
  earth_specular_2048.jpg — specular mask (oceans shiny, land matte)
  earth_clouds_1024.png  — semi-transparent cloud layer
  moon_1024.jpg          — cratered gray surface
```

Earth uses `MeshPhongMaterial` with all four maps. The atmosphere is a custom `ShaderMaterial` with Fresnel (rim) lighting — bright at the limb, transparent toward the viewer — rendered with `AdditiveBlending`. The cloud layer is a separate child sphere rotating slightly faster than the surface.

### Key constants in `script.js`

```
LAUNCH_TIME       = new Date('2026-04-02T01:58:00Z')
MISSION_START_MS  = LAUNCH_TIME.getTime()
MISSION_END_MS    = new Date('2026-04-11T00:17:00Z').getTime()   // splashdown
FLYBY_MS          = new Date('2026-04-06T23:06:00Z').getTime()   // lunar closest approach
ORION_ID          = '-1024'
HORIZONS_API      = '/jpl'   // routes through functions/jpl.js CORS proxy
EARTH_SCENE       = THREE.Vector3(-240, 0, 0)
SCENE_UNITS_PER_KM = 534 / 384400  ≈ 0.001389
TRAJ_CACHE_KEY    = 'artemis2-fulltraj-v2'   // localStorage key
```

### Key functions in `script.js`

```
── COORDINATES ──
jplToScene(x, y, z)          ECI J2000 km → THREE.Vector3 (J2000 Z→Y, J2000 Y→-Z)

── TRAJECTORY CACHE ──
fetchFullTrajectory()         parallel: Orion + Moon hourly ECI pts → cache → applyRealTrajectory()
applyRealTrajectory(entries)  rebuild ghost line, tube, milestone dots, Moon position

── SCENE ──
buildTrajTube(curve)          vertex-colored TubeGeometry: RWB for flown, dim for future
initThreeScene()              full Three.js scene construction; calls fetchFullTrajectory()

── LIVE TELEMETRY ──
fetchTelemetry()              parallel fetchVectors(Earth + Moon) → DOM + 3D, every 2 min
fetchVectors(center)          query /jpl for Orion VECTORS relative to center body
parseVectors(text)            extract pos/vel/LT/RG/RR from 4-line-per-epoch VEC_TABLE=3 format
radialKmps(data)              prefer RR (range-rate from JPL); fall back to dot-product
speedContextStr(mph)          plain-English comparisons ("8× faster than a rifle bullet")

── SCENE UPDATE ──
updateOrionPosition()         getMissionProgress() → curve.getPoint(t) + tangent → orionMesh
setViewMode(mode)             earth | moon | cockpit | wide camera transitions
                               cockpit = over-the-shoulder: 90 units aft, 32 up, 8 left, lerped

── PLAYBACK ──
scrubPlayback(value)          slider 0–1000 → display time → Orion position + MET + progress
togglePlaybackPlay()          animate at 60× real time
exitPlaybackToLive()          return to wall-clock

── UI ──
animateNumber(id, val, fmt)   GSAP tween from data-rawVal to new value
renderTimeline()              TIMELINE_EVENTS → DOM with UTC timestamps + NASA links
renderCrew()                  CREW[] → DOM with bio links, X/Twitter, flight counts
```

### CORS proxy architecture

**`/jpl` (`functions/jpl.js`)** — General-purpose pass-through. Re-encodes all query params with `encodeURIComponent` (never `+`) because JPL rejects `+`-encoded spaces ("Too many constants" error). Returns raw JPL response with `Access-Control-Allow-Origin: *`. Used by `script.js` for all fetches.

**`/proxy` (`functions/proxy.js`)** — Structured. Accepts `?t=<ISO>`, builds the Horizons URL via `buildJplUrl()` from `src/utils.js`, and returns parsed JSON. Used by the unit/E2E test infrastructure.

### JPL Horizons quirks

- Spacecraft ID for Orion / Artemis II: **`-1024`**; Moon: **`301`**
- `VECT_TABLE` and `VECT_CORR` are **invalid** on the REST endpoint — omit them
- Spaces in param values must be **`%20`**, not `+` — build URLs with `encodeURIComponent` manually
- With a 1-minute START→STOP window, use `STEP_SIZE=1` (one step), not `STEP_SIZE=1h` (zero records)
- `RG` (range) from `VEC_TABLE=3` is more accurate than `sqrt(x²+y²+z²)` for displayed distance
- `RR` (range-rate) is direct radial velocity; positive = receding, negative = closing

### VEC_TABLE=3 response format

```
Line 0:  JDTDB = 2461931.xxx = A.D. 2026-Apr-02 ...   (timestamp)
Line 1:   X = <km>  Y = <km>  Z = <km>                (ECI J2000 position)
Line 2:   VX= <km/s>  VY= <km/s>  VZ= <km/s>          (ECI J2000 velocity)
Line 3:   LT= <s>  RG= <km>  RR= <km/s>               (light-time · range · range-rate)
```

### Three.js scene layout

| Object | Notes |
|---|---|
| Earth | `EARTH_SCENE = (-240, 0, 0)` · radius 62 · texture + normal + specular + clouds + Fresnel atmosphere |
| Moon | Real JPL position at flyby · radius 30 · crater texture · fallback `(276, 22, -45)` |
| Trajectory (ghost) | Dim steel-blue `Line` · 280 pts · rebuilt when JPL data arrives |
| Trajectory (tube) | Vertex-colored `TubeGeometry` · RWB flown, dim future · rebuilt on JPL load |
| Milestone dots | Blue (past) / gray (future) · raycaster hover targets |
| Orion group | Composite: crew module (cone) + service module (cylinder, thermal roll) + heat shield + solar panels |
| Actual position dot | Orange sphere · `jplToScene(eci)` from live telemetry · opacity 0 until first fetch |
| History line | Orange `LineBasicMaterial` · `positionHistory[]` · persisted in localStorage |
| Sun | Sphere + glow sprite · artistic position indicator |

### Running locally

```bash
npm install
npm run dev           # wrangler pages dev — localhost:8788 with functions/ proxied
npm test              # vitest unit tests (src/utils.js)
npm run test:e2e      # playwright E2E (uses tests/dev-server.mjs)
npm run test:all      # both
```

> Playwright E2E uses `tests/dev-server.mjs` (plain Node.js) rather than `wrangler pages dev`, because wrangler's workerd sandbox blocks outbound TLS to `ssd.jpl.nasa.gov`. For local development with live JPL data, use `npm run dev`.

### Deploying

**No API keys or secrets required.** JPL Horizons is open and free. All CDN libraries are public.

```bash
wrangler pages deploy . --project-name your-project-name
```

Cloudflare routes `*.pages.dev` automatically. Functions in `functions/` deploy alongside static files. No CI configuration needed. Change `name` in `wrangler.toml` to your own project name — that's the only edit required.

> **Running without Cloudflare:** The `functions/jpl.js` CORS proxy is required because JPL Horizons doesn't send `Access-Control-Allow-Origin` headers. If you're self-hosting on another platform, replace the `/jpl` endpoint in `script.js` with your own CORS proxy. Any platform that can run a small server-side function (Vercel Edge Functions, Netlify Functions, a plain Express server) can serve the same purpose using the same ~30 lines in `functions/jpl.js`.

---

## What's in v1.0.0

- Real-time telemetry from JPL Horizons (object `-1024`) every 2 minutes
- Full mission trajectory from real JPL ephemeris (216 hourly ECI vectors, localStorage-cached)
- Three.js WebGL scene: photorealistic Earth (Blue Marble texture, cloud layer, Fresnel atmosphere glow), Moon (crater texture), Orion capsule composite model
- Reference-frame camera views: Earth · Moon · Cockpit (over-the-shoulder hybrid) · Overview
- Mission playback scrubber — replay any moment of the mission
- Telemetry panel: distance + speed + radial velocity for Earth and Moon, ECI state vector
- Mission resources section with 9 official NASA/JPL links
- Crew cards with NASA/CSA bio links, X/Twitter, spaceflight counts
- Mission timeline with accurate UTC timestamps and rich descriptions
- Cloudflare Pages deployment, free tier, zero configuration

---

## License

MIT — do whatever you want with it. See `LICENSE`.

---

**Real data. Real Moon mission. American hardware.**

Data: NASA/JPL Horizons · Visualization: Three.js WebGL · Hosted: Cloudflare Pages  
Not an official NASA site.
