Initial Commit
This commit is contained in:
151
openspec/changes/enterprise-gaming-day-night/proposal.md
Normal file
151
openspec/changes/enterprise-gaming-day-night/proposal.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# OpenSpec Change: enterprise-gaming-day-night
|
||||
|
||||
- **Change ID**: enterprise-gaming-day-night
|
||||
- **Package**: `@suaveplan/day-night`
|
||||
- **Category**: gaming/world
|
||||
- **Target path**: `gaming/world/day-night`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-24
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/day-night.md`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver `@suaveplan/day-night` on the genesis branch from scratch at enterprise quality. The package provides a day/night cycle with configurable time scale, sun/moon position math, light schedule interpolation, and gameplay effect modifiers. `DayNightClock` advances in-game time at a configurable multiple of real time; `SkyPositionCalculator` computes sun and moon azimuth/elevation from in-game time using a simplified celestial model; `LightSchedule` keyframes ambient light color and intensity across the day; `GameplayModifiers` maps time-of-day segments to gameplay effect multipliers (spawn rate, visibility, economy). Genesis adds Zod schemas, structured errors, OTel time counter, injectable clock, and 100% coverage.
|
||||
|
||||
---
|
||||
|
||||
## Current-state audit (genesis)
|
||||
|
||||
Package does not exist on genesis yet — fresh build.
|
||||
|
||||
---
|
||||
|
||||
## Available workspace deps on genesis
|
||||
|
||||
| Package | Role |
|
||||
|---|---|
|
||||
| `@suaveplan/error` (`workspace:^`) | `DayNightError`; `DAY_NIGHT.*` codes |
|
||||
| `@suaveplan/types` (`workspace:^`) | `Clock` |
|
||||
| `@suaveplan/events` (`workspace:^`) | `time:dawn`, `time:noon`, `time:dusk`, `time:midnight` events |
|
||||
| `zod` (`catalog:forms`) | `LightSchedule`, `GameplayModifiers` schemas |
|
||||
| `@opentelemetry/api` (`catalog:observability`) | In-game time gauge |
|
||||
|
||||
---
|
||||
|
||||
## Public API surface
|
||||
|
||||
```ts
|
||||
function createDayNightClock(options: DayNightClockOptions): DayNightClock
|
||||
|
||||
interface DayNightClockOptions {
|
||||
timeScale?: number // real seconds per in-game minute, default 1 min = 1 sec
|
||||
initialHour?: number // 0–24
|
||||
clock?: Clock
|
||||
}
|
||||
|
||||
interface DayNightClock {
|
||||
tick(dt: number): void
|
||||
readonly hour: number // 0–24 fractional
|
||||
readonly dayCount: number
|
||||
setHour(hour: number): void
|
||||
pause(): void
|
||||
resume(): void
|
||||
readonly isPaused: boolean
|
||||
}
|
||||
|
||||
interface SkyPosition {
|
||||
azimuth: number // degrees
|
||||
elevation: number // degrees (-90 to 90)
|
||||
intensity: number // 0–1
|
||||
}
|
||||
|
||||
function computeSunPosition(hour: number): SkyPosition
|
||||
function computeMoonPosition(hour: number): SkyPosition
|
||||
|
||||
// Light schedule
|
||||
interface LightKeyframe {
|
||||
hour: number
|
||||
ambientColor: [r: number, g: number, b: number]
|
||||
ambientIntensity: number
|
||||
fogDensity?: number
|
||||
}
|
||||
|
||||
function createLightSchedule(keyframes: LightKeyframe[]): LightSchedule
|
||||
interface LightSchedule {
|
||||
evaluate(hour: number): LightKeyframe
|
||||
}
|
||||
|
||||
// Gameplay modifiers
|
||||
interface TimeModifier {
|
||||
fromHour: number
|
||||
toHour: number
|
||||
spawnRateMultiplier?: number
|
||||
visibilityMultiplier?: number
|
||||
economyMultiplier?: number
|
||||
label?: string
|
||||
}
|
||||
|
||||
function createGameplayModifiers(modifiers: TimeModifier[]): GameplayModifiers
|
||||
interface GameplayModifiers {
|
||||
evaluate(hour: number): TimeModifier & Required<Omit<TimeModifier, 'label' | 'fromHour' | 'toHour'>>
|
||||
}
|
||||
```
|
||||
|
||||
### Error codes
|
||||
|
||||
```ts
|
||||
type DayNightErrorCode =
|
||||
| 'DAY_NIGHT_INVALID_HOUR'
|
||||
| 'DAY_NIGHT_SCHEDULE_EMPTY'
|
||||
| 'DAY_NIGHT_KEYFRAME_GAP'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File layout
|
||||
|
||||
```text
|
||||
gaming/world/day-night/
|
||||
package.json
|
||||
tsconfig.json
|
||||
vitest.config.ts
|
||||
src/
|
||||
index.ts
|
||||
error-codes.ts
|
||||
constants/index.ts
|
||||
types/common.ts
|
||||
types/common.md
|
||||
core/
|
||||
day-night-clock/
|
||||
day-night-clock.ts
|
||||
day-night-clock.md
|
||||
day-night-clock.types.ts
|
||||
day-night-clock.test.ts
|
||||
index.ts
|
||||
light-schedule/
|
||||
light-schedule.ts
|
||||
light-schedule.md
|
||||
light-schedule.types.ts
|
||||
light-schedule.test.ts
|
||||
index.ts
|
||||
gameplay-modifiers/
|
||||
gameplay-modifiers.ts
|
||||
gameplay-modifiers.md
|
||||
gameplay-modifiers.types.ts
|
||||
gameplay-modifiers.test.ts
|
||||
index.ts
|
||||
utils/
|
||||
sky-position.ts
|
||||
sky-position.md
|
||||
sky-position.test.ts
|
||||
tests/
|
||||
integration.test.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Impact
|
||||
|
||||
**Downstream**: `@suaveplan/r3f-environment` uses sun/moon positions for directional light; `@suaveplan/weather` reads time for weather transitions. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`.
|
||||
Reference in New Issue
Block a user