## ADDED Requirements ### Requirement: GamingUniverse construction The system SHALL export `GamingUniverse` accepting `startTime`, `timeScale`, `UniverseClient`, and optional `clock`. #### Scenario: Construction - **WHEN** `new GamingUniverse({ startTime, timeScale: 3600, universe })` is called - **THEN** the instance is created with `getGameTime()` returning `startTime` ### Requirement: Time scale control The system SHALL provide `setTimeScale`, `pause`, `resume`, and `isPaused`. #### Scenario: Pause and resume - **WHEN** `pause()` is called - **THEN** `isPaused()` returns `true` - **AND** `getGameTime()` stops advancing - **AND** after `resume()`, `isPaused()` returns `false` ### Requirement: Set game time directly The system SHALL provide `setGameTime` to override the clock to a specific date. #### Scenario: Direct time set - **WHEN** `setGameTime(futureDate)` is called - **THEN** `getGameTime()` returns `futureDate` ### Requirement: Scene queries at game time The system SHALL delegate `getScene` to `UniverseClient.getScene` using the current game time. #### Scenario: Scene query - **WHEN** `getScene(observer)` is called while paused - **THEN** the query uses the paused game time, not real time ### Requirement: AsyncScheduler integration The system SHALL wrap `@suaveplan/timing`'s `AsyncScheduler` to drive game time ticks. #### Scenario: Scheduler usage - **WHEN** `GamingUniverse` is constructed - **THEN** it creates or references an `AsyncScheduler` from `@suaveplan/timing` - **AND** `dispose()` stops the scheduler ### Requirement: Event emission The system SHALL emit events via `@suaveplan/events` for `hourChanged`, `dayChanged`, `seasonChanged`, `sunriseStarted`, `sunsetStarted`, `moonriseStarted`, `moonsetStarted`, and `eclipseStarted`. #### Scenario: Day change event - **WHEN** game time advances across a midnight boundary - **THEN** a `dayChanged` event is emitted with the new `gameTime` and `dayNumber` ### Requirement: Signal cancellation The system SHALL pass `AbortSignal` through to `UniverseClient.getScene` and cancel in-flight queries. #### Scenario: Abort in-flight - **WHEN** `getScene` is called and the signal is aborted - **THEN** the promise rejects with an abort error ### Requirement: Dispose idempotency The system SHALL provide `dispose()` that stops the clock and cancels all in-flight queries, callable multiple times safely. #### Scenario: Double dispose - **WHEN** `dispose()` is called twice - **THEN** no error is thrown - **AND** the instance is fully shut down after the first call ### Requirement: UniverseClient exposure The system SHALL expose the underlying `UniverseClient` via a readonly `universe` property. #### Scenario: Access underlying client - **WHEN** `gamingUniverse.universe` is accessed - **THEN** it returns the `UniverseClient` passed at construction