## ADDED Requirements ### Requirement: Sky colour via Rayleigh/Mie scattering The system SHALL compute sky colour from sun altitude, `AtmosphereConfig.rayleighCoefficient`, and `mieCoefficient`. #### Scenario: Earth noon sky - **WHEN** the sun is at zenith on an Earth-like planet - **THEN** the computed `skyColour` is deep blue (high B, moderate G, low R) #### Scenario: Earth sunset sky - **WHEN** the sun is near the horizon on an Earth-like planet - **THEN** the computed `skyColour` is orange/red (high R, moderate G, low B) #### Scenario: Mars noon sky - **WHEN** the sun is at zenith on a Mars-like planet with CO₂ atmosphere - **THEN** the computed `skyColour` is butterscotch (high R, moderate G, low B) #### Scenario: Vacuum world - **WHEN** the observer's planet has no `AtmosphereConfig` - **THEN** `skyColour` is black always ### Requirement: Twilight star visibility thresholds The system SHALL apply magnitude limits based on sun altitude and twilight phase. #### Scenario: Civil twilight limit - **WHEN** sun altitude is between `0` and `-6` degrees - **THEN** only stars with `apparentMagnitude <= 1` are visible #### Scenario: Astronomical twilight limit - **WHEN** sun altitude is between `-12` and `-18` degrees - **THEN** stars with `apparentMagnitude <= 6` are visible #### Scenario: Full dark - **WHEN** sun altitude is below `-18` degrees - **THEN** all naked-eye stars are visible #### Scenario: Vacuum collapse - **WHEN** the planet has no atmosphere - **THEN** all stars are visible regardless of sun altitude ### Requirement: Multi-satellite moonlight The system SHALL compute per-satellite moonlight proportional to phase illumination, angular diameter squared, and albedo, summing across all satellites. #### Scenario: Single moon night - **WHEN** a planet with one satellite has a full-moon phase - **THEN** `moonContributions` contains one entry with significant light value #### Scenario: Multiple moons - **WHEN** a planet with two satellites both above the horizon is evaluated - **THEN** `totalAmbientLight` includes the sum of both contributions ### Requirement: Gameplay modifiers The system SHALL export `EnvironmentModifiers` with `totalAmbientLight`, `stealthBonus`, `visibilityRangeMetres`, and `npcSleepProbability` as continuous functions of ambient light. #### Scenario: Stealth at midnight - **WHEN** `totalAmbientLight` is near `0` - **THEN** `stealthBonus` is near `1` #### Scenario: Visibility at noon - **WHEN** `totalAmbientLight` is near `1` - **THEN** `visibilityRangeMetres` is at its maximum ### Requirement: Plain ECS component interfaces The system SHALL export `DayNightClock`, `LightState`, and `DayNightAffected` as plain TypeScript interfaces with no `@suaveplan/ecs` dependency. #### Scenario: Interface shapes - **WHEN** the exports are inspected - **THEN** they are `interface` declarations, not class constructors or archetype registrations ### Requirement: RenderPayload shape The system SHALL export `RenderPayload` as the canonical per-tick output for downstream render integrations. #### Scenario: Payload completeness - **WHEN** a render payload is generated at a tick - **THEN** it contains `skyColour`, `sunAltitude`, `sunAzimuth`, `horizonColour`, `totalAmbientLight`, `moonContributions`, `fogDensity`, `rayleighTint`, `textures`, and optional `weather` ### Requirement: Texture manifest pass-through The system SHALL pass `PlanetTextureManifest` identifiers through verbatim without loading or storing assets. #### Scenario: Texture identifiers - **WHEN** a `PlanetConfig` with `textures: { diffuse: "earth-diffuse", night: "earth-night" }` is used - **THEN** the `RenderPayload.textures` contains the same identifiers - **AND** no file loading occurs ### Requirement: Weather state pass-through The system SHALL include `WeatherState` in `RenderPayload` and `LightState` when a `WeatherProvider` is registered, without breaking when absent. #### Scenario: No weather provider - **WHEN** no `WeatherProvider` is registered in the underlying `UniverseClient` - **THEN** `RenderPayload.weather` is undefined - **AND** lighting computation continues without weather modulation