Files
2026-05-27 23:29:53 +01:00

116 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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.