116 lines
7.0 KiB
Markdown
116 lines
7.0 KiB
Markdown
## Context
|
||
|
||
The existing `@suaveplan/day-night` package conflates gaming concerns (ECS components, gameplay modifiers, in-game clock) with pseudo-astronomy (hardcoded sinusoidal sun arc, 30-day moon cycle, no lat/lon). It is not extensible to other planets, not observatory-accurate, and not enterprise-grade. The existing `@suaveplan/geo` covers Earth-surface geometry only and mixes abstract math with Earth-specific constants.
|
||
|
||
This design defines a seven-package family split across three layers: abstract geometry (Layer 0), concrete planet surfaces (Layer 1), and astronomical observer core (Layer 2).
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
|
||
- Provide real, observatory-accurate astronomical calculations via a pluggable provider architecture.
|
||
- Generalise Earth-surface geometry to any planet via configurable ellipsoid and physical parameters.
|
||
- Support an observer-centric model: stars, planets, tides, and lighting computed from a single observer position on any planet surface, in atmosphere, or in space.
|
||
- Lock in a binary wire protocol (BitSchemas via `@suaveplan/bitpacker`) for efficient server→client star delivery.
|
||
- Preserve the public API of existing `@suaveplan/geo` consumers while restructuring internals.
|
||
- Achieve 100% test coverage, Zod schemas for all public options, OTel instrumentation, and `AbortSignal` on every async method.
|
||
|
||
**Non-Goals:**
|
||
|
||
- Gaming-layer integration — deferred to `enterprise-gaming-universe`.
|
||
- SurrealDB star storage schema and SurrealQL JS function bodies (deferred).
|
||
- Hipparcos, Tycho-2, Gaia catalog source implementations (interfaces locked, implementations deferred).
|
||
- R3F / Three.js rendering integration for sky, terrain, planet textures.
|
||
- Multiplayer synchronisation of game time across clients.
|
||
- `@suaveplan/weather` integration (locked interface but no implementation).
|
||
- Bundling texture assets — only identifiers pass through.
|
||
|
||
## Decisions
|
||
|
||
### 1. Layered architecture with explicit dependency graph
|
||
|
||
Layers prevent circular dependencies and make testing tractable:
|
||
|
||
- `geo` → `geo-planet` → `geo-earth`
|
||
- `geo` + `geo-planet` → `universe`
|
||
- `universe` → (`solar-system`, `stars`, `tides`)
|
||
|
||
**Rationale**: Each layer adds semantic meaning. `geo` has no astronomical meaning. `universe` is gaming-agnostic and can be consumed directly by game engines or simulation tools without pulling in timing or event dependencies.
|
||
|
||
### 2. `PlanetConfig` as the single source of truth for any planet
|
||
|
||
All planet-specific data (mass, radius, rotation, axial tilt, atmosphere, satellites, orbit, textures) lives in one serialisable struct. `PlanetSurface` wraps it with geometry operations.
|
||
|
||
**Rationale**: Prevents scattered constants and makes multi-planet games trivial — swap the config, reuse the same code paths.
|
||
|
||
### 3. ObserverPosition carries `PlanetConfig` inline
|
||
|
||
For surface and atmospheric observers, the `PlanetConfig` is embedded in the position value rather than referenced by ID.
|
||
|
||
**Rationale**: Eliminates lookup at query time. Providers receive everything they need in one argument. No global registry, no async lookup, no cache invalidation complexity.
|
||
|
||
### 4. Provider registry pattern in `UniverseClient`
|
||
|
||
`UniverseClient.register(domain, provider)` allows consumers to mix and match: astronomy.js for solar, BSC5 for stars, TICON for Earth tides, physics model for Mars tides.
|
||
|
||
**Rationale**: Composition over inheritance. Each provider is independently testable. Consumers can inject mocks or custom game-defined providers.
|
||
|
||
### 5. Two-engine model in `solar-system`
|
||
|
||
Real bodies use astronomy.js (observatory-accurate). Game-defined planets with `OrbitalConfig` use a Keplerian propagator (physically plausible, not observatory-grade).
|
||
|
||
**Rationale**: astronomy.js is battle-tested and correct to arcsecond precision. Rewriting it would be error-prone. Custom planets need only plausible orbits, not ephemeris data.
|
||
|
||
### 6. BitSchema wire protocol for stars and bodies
|
||
|
||
`StarPacket` (~11 bytes/star) and `CelestialBodyPacket` quantise data for compact transmission. Rendering does not need float64.
|
||
|
||
**Rationale**: ~18× compression vs JSON. Essential for server→client star streaming. The schema is locked now so downstream render integrations can depend on it.
|
||
|
||
### 7. Feature-module directory layout — Pattern B
|
||
|
||
Every feature module uses a dedicated folder containing a main implementation file, a barrel `index.ts` with explicit named re-exports, sibling `.md` docs, and co-located tests.
|
||
|
||
Example:
|
||
|
||
```text
|
||
src/distance/
|
||
├── index.ts
|
||
├── distance.ts
|
||
├── distance.test.ts
|
||
└── distance.md
|
||
```
|
||
|
||
The `package.json` exports map uses the repeated-name form (`./distance/distance`) pointing to the main implementation file, not to `index.ts`.
|
||
|
||
**Rationale**: The barrel is reviewable and explicit. The main file name makes stack traces and import paths self-describing. Tests and docs are co-located so they stay in sync.
|
||
|
||
### 8. TICON and ADMIRALTY providers preserved verbatim
|
||
|
||
The Earth harmonic engine and station data are kept intact; enterprise additions wrap them with Zod, OTel, and `AbortSignal`.
|
||
|
||
**Rationale**: The harmonic engine is correct and tested. Rewriting it risks regressions. The enterprise layer adds cross-cutting concerns without changing physics.
|
||
|
||
## Risks / Trade-offs
|
||
|
||
| Risk | Mitigation |
|
||
|---|---|
|
||
| astronomy.js bundle size | Evaluate at build time; tree-shaking removes unused bodies. Document size impact in README. |
|
||
| BSC5 catalog (~100 KB bitpacked) may bloat browser bundles | Subpath export `stars/catalogs/bsc5` is optional; consumers importing only `StarProviderImpl` do not pull the catalog. |
|
||
| Keplerian propagator for custom planets is not observatory-accurate | Documented as "physically plausible" in API docs. Games needing precision must supply real ephemeris. |
|
||
| Multi-satellite tidal physics model is simplified (no ocean basin resonance) | Documented limitation. Earth consumers use TICON/ADMIRALTY for accuracy. |
|
||
| `PlanetConfig` embeds full config on every `ObserverPosition` | Config objects are small (~1 KB). Copying avoids lookup complexity and shared mutable state. |
|
||
| 7 packages increase monorepo maintenance surface | Each package has a single responsibility and narrow public API. Dependency graph is a DAG with no cycles. |
|
||
| Deferred SurrealDB / weather / Gaia integrations may drift from locked interfaces | Interfaces are versioned in `stars` and `universe` specs. Future implementations must satisfy the structural contract. |
|
||
|
||
## Migration Plan
|
||
|
||
1. Land packages in dependency order: `geo` → `geo-planet` → `geo-earth` → `universe` → `solar-system` → `stars` → `tides`.
|
||
2. Update `STATUS.md` and `SUMMARY.md` as each package completes.
|
||
3. Run dependent sweep on `@suaveplan/geo-earth` (successor to `@suaveplan/geo`) to verify downstream consumers compile and test.
|
||
4. After this change archives, `enterprise-gaming-universe` can begin implementing `gaming-universe` and `gaming-environment-lighting`.
|
||
|
||
## Open Questions
|
||
|
||
- None — all deferred items are explicitly scoped out in §13 of the design spec with locked interfaces.
|