Add the deep-sky backdrop, the last unbuilt piece of the plan
The design doc scopes deep-sky objects as a galaxy-view backdrop and lists fetchDeepSky.ts, deepsky.json and deepsky.model.ts, but none of it existed — it was the only part of the plan with no implementation behind it. ETL: fetchDeepSky.ts pulls the OpenNGC catalog, classifies each object as a galaxy/nebula/cluster, and keeps the ~460 worth drawing (everything Messier, everything with a common name, and anything brighter than magnitude 9) out of ~12,000 mostly-anonymous rows. build.ts runs it and validates the output. Distances are the hard part: OpenNGC has no distance column, and both fallbacks fail for the best-known objects. M31, M33 and M42 are Local Group members whose redshift is negative or absent, and a galaxy's catalog parallax comes from a cross-matched foreground star — 6 mas for M31 would put a 780 kpc galaxy at 167 pc. So records store a unit direction on the celestial sphere rather than a position (the line of sight is always known precisely, and the objects are drawn on a fixed backdrop shell where true distance is unusable anyway), and distance is optional metadata carrying its own provenance. Parallax is trusted only for galactic objects, redshift only above z=0.003 where expansion outweighs peculiar velocity. 330 of 463 get a distance; the rest honestly report none. Rendering: DeepSkyRenderer paints the objects as soft additive billboards on a 2500 pc shell — clear of the 50 pc star field, beyond the camera's 2000 pc orbit limit, and inside its 5000 pc far plane. Size comes from real angular extent, so Andromeda is six times wider than the full Moon, clamped at both ends. Sprites rather than points because the WebGPU backend caps point primitives at one pixel; materials are shared per kind and brightness band, so 460 objects cost nine of them. The brightest dozen get permanent labels, which needed the label overlay to accept string ids alongside numeric star ids. The backdrop is decorative, so a failure to load its dataset is logged and the star field comes up regardless. Also documents the app in the README, which until now covered only the plugin marketplace. Tests: 112 passing, up from 54. Build, both typechecks and the Playwright suite are green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G
This commit is contained in:
@@ -1,20 +1,124 @@
|
||||
# star-map
|
||||
|
||||
Personal marketplace of `cs:*` Claude Code commands, agents, and skills.
|
||||
An interactive 3D star map in the spirit of Star Citizen's in-game starmap, but populated with
|
||||
real astronomical data instead of fictional systems. Browse the solar neighbourhood, fly into a
|
||||
star's system to see its planets on their real orbits, and drill into a single body for the
|
||||
NASA figures behind it.
|
||||
|
||||
## Install (global — works in every project)
|
||||
This repo also hosts a small Claude Code plugin marketplace — see [Plugins](#plugins) below.
|
||||
|
||||
This repo is a Claude Code plugin marketplace. Adding it and installing a
|
||||
plugin defaults to **user scope**, meaning the plugin becomes available in
|
||||
*every* project on your machine, not just the one you happen to be in:
|
||||
## Running it
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm start # dev server on http://localhost:4200
|
||||
npm run build # production bundle into dist/
|
||||
```
|
||||
|
||||
Requires the Node version in `package.json`'s Angular toolchain range (Node 22.22.3+ or 24.15+).
|
||||
|
||||
```bash
|
||||
npm test # unit/component tests (Vitest, jsdom)
|
||||
npm run e2e # end-to-end tests (Playwright + Chromium) — see e2e/README.md
|
||||
npm run etl # refresh the astronomical datasets — see below
|
||||
npm run etl:typecheck # type-check the ETL scripts (they build separately from the app)
|
||||
npm run e2e:typecheck
|
||||
```
|
||||
|
||||
## What's in it
|
||||
|
||||
**Galaxy view** — every HYG-catalogue star within 50 parsecs as a point field, positioned from
|
||||
real RA/Dec/parallax, coloured by spectral index and sized by magnitude. Names label the stars
|
||||
nearest the camera. Behind them sits a backdrop of notable deep-sky objects and a Milky Way
|
||||
panorama.
|
||||
|
||||
**System view** — selecting a star flies the camera continuously into its system rather than
|
||||
cutting to a new scene. The Sun gets the real solar-system bodies from JPL Horizons; other
|
||||
stars get their confirmed exoplanets. Orbits are drawn as ellipses and bodies are propagated
|
||||
along them by a Kepler solver against the current epoch.
|
||||
|
||||
**Body detail** — a dedicated close-up scene and info panel for one planet, moon or exoplanet,
|
||||
with real photography where NASA/ESA/USGS imagery exists.
|
||||
|
||||
**Search** — name search across stars, solar-system bodies and exoplanets, navigating to the
|
||||
same place an in-scene click would.
|
||||
|
||||
### Architecture notes
|
||||
|
||||
- **Rendering** runs on Three.js `WebGPURenderer`, which falls back to a WebGL2 backend
|
||||
automatically. The render loop runs outside Angular's change detection.
|
||||
- **Two coordinate scales.** The galaxy view works in parsecs and the system view in AU —
|
||||
about eight orders of magnitude apart, which wrecks float precision if rendered in one unit
|
||||
space. The camera rig recentres the active star to the origin ("floating origin") and swaps
|
||||
the unit scale and near/far planes at the transition point.
|
||||
- **No backend.** Every dataset is baked at build time into `src/assets/data/` and served as a
|
||||
static asset. Nothing queries an astronomy API at runtime.
|
||||
|
||||
## Data pipeline
|
||||
|
||||
`npm run etl` runs `tools/etl/build.ts`, which fetches each source, writes the static assets,
|
||||
then validates the combined output. Raw responses are cached under `tools/etl/.cache/`, so
|
||||
re-runs are cheap and offline-friendly; set `ETL_FORCE_REFRESH=1` to bypass the cache.
|
||||
|
||||
| Script | Source | Output |
|
||||
| --- | --- | --- |
|
||||
| `fetchStars.ts` | HYG database (Hipparcos/Yale/Gliese) | `stars.bin`, `stars-index.json` |
|
||||
| `fetchSolarSystem.ts` | JPL Horizons / SSD | `bodies.json` |
|
||||
| `fetchExoplanets.ts` | NASA Exoplanet Archive (TAP) | `exoplanets.json` |
|
||||
| `fetchDeepSky.ts` | OpenNGC | `deepsky.json` |
|
||||
|
||||
Star positions ship as a packed `Float32Array` (`stars.bin`) rather than JSON to keep the
|
||||
initial payload and parse cost down; `stars-index.json` carries everything else in the same
|
||||
order.
|
||||
|
||||
`ETL_STAR_DISTANCE_PC` (default `50`) sets the star-field distance cutoff.
|
||||
|
||||
### On deep-sky distances
|
||||
|
||||
OpenNGC publishes no distance column, so distance has to be inferred — and the inference fails
|
||||
for precisely the best-known objects. M31, M33 and M42 are Local Group members whose redshift
|
||||
is negative or absent, and the catalogue's parallax for a galaxy comes from a cross-matched
|
||||
foreground star (it lists 6 mas for M31, implying 167 pc for something 780,000 pc away).
|
||||
|
||||
So deep-sky records store a **unit direction** on the celestial sphere rather than a position:
|
||||
the line of sight is always known precisely, and the objects are drawn as a fixed-radius
|
||||
backdrop shell where true distance would be unusable anyway. `distancePc` is optional metadata,
|
||||
derived from parallax for galactic objects or the Hubble law for genuinely distant galaxies,
|
||||
and left `null` — with its `distanceMethod` — whenever neither is trustworthy. Roughly 330 of
|
||||
the 463 cataloged objects get a distance; the rest honestly report none.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
src/app/
|
||||
core/engine/ Three.js renderer, render loop, resize
|
||||
core/data/ static-asset loading and caching
|
||||
features/galaxy-system/ shared galaxy+system scene, camera rig, star field,
|
||||
deep-sky backdrop, orbits, labels
|
||||
features/body-detail/ close-up scene and info panel
|
||||
features/search/ name search across every dataset
|
||||
shared/astro/ coordinates, Kepler propagator, deep-sky classification
|
||||
shared/models/ record contracts shared by the app and the ETL
|
||||
shared/rendering/ skybox, glow sprites, texture catalog
|
||||
shared/state/ navigation store (Angular signals)
|
||||
tools/etl/ build-time data pipeline
|
||||
e2e/ Playwright end-to-end tests
|
||||
```
|
||||
|
||||
The design document behind all of this is `.junie/plans/nasa-star-map.md`.
|
||||
|
||||
## Plugins
|
||||
|
||||
This repo doubles as a Claude Code plugin marketplace. Adding it and installing a plugin
|
||||
defaults to **user scope**, meaning the plugin becomes available in *every* project on your
|
||||
machine, not just the one you happen to be in:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add avalon-vanguard/star-map
|
||||
/plugin install caveman@star-map
|
||||
```
|
||||
|
||||
Scope can be overridden at install time if you want it tied to a single
|
||||
repo instead:
|
||||
Scope can be overridden at install time if you want it tied to a single repo instead:
|
||||
|
||||
```bash
|
||||
# Shared with collaborators via that repo's .claude/settings.json
|
||||
@@ -27,9 +131,15 @@ repo instead:
|
||||
See [Claude Code plugin installation scopes](https://code.claude.com/docs/en/plugins-reference)
|
||||
for details on `user` / `project` / `local` scope.
|
||||
|
||||
## Plugins
|
||||
|
||||
- **caveman** — `/cs:caveman` ultra-compressed communication mode.
|
||||
- Command: [`commands/cs/caveman.md`](commands/cs/caveman.md)
|
||||
- Agent: [`agents/cs-caveman-mode.md`](agents/cs-caveman-mode.md)
|
||||
- Skill: [`skills/caveman/SKILL.md`](skills/caveman/SKILL.md)
|
||||
- Skill: [`skills/caveman/SKILL.md`](skills/caveman/SKILL.md)
|
||||
|
||||
## Data credits
|
||||
|
||||
Star catalogue: [HYG database](https://github.com/astronexus/HYG-Database) (Hipparcos, Yale
|
||||
Bright Star, Gliese). Solar-system ephemerides: NASA/JPL Horizons. Exoplanets: NASA Exoplanet
|
||||
Archive. Deep-sky objects: [OpenNGC](https://github.com/mattiaverga/OpenNGC). Body and skybox
|
||||
imagery: NASA/JPL/USGS public domain and Solar System Scope (CC BY 4.0) — per-file provenance
|
||||
is recorded in `src/app/shared/rendering/texture-catalog.ts`.
|
||||
|
||||
Reference in New Issue
Block a user