import { describe, expect, it } from 'vitest'; import { DAWN_STEPS, dawnStep, END_OF_SHIFT_SUBLINE } from '@/journey/dawn'; import { blendDaybreak, CHAPTER_PALETTES, createMutableChapterPalette, DAYBREAK_PALETTE, engineOffStarScale, } from '@/scene/world/palette'; describe('dawn step mapping (html[data-dawn])', () => { it('steps night -> first-light -> sunrise -> day at 0.3 / 0.6 / 0.95', () => { expect(DAWN_STEPS).toEqual({ 'first-light': 0.3, sunrise: 0.6, day: 0.95 }); const cases: Array<[number, string]> = [ [0, 'night'], [0.29, 'night'], [0.3, 'first-light'], [0.59, 'first-light'], [0.6, 'sunrise'], [0.949, 'sunrise'], [0.95, 'day'], [1, 'day'], [-1, 'night'], [Number.NaN, 'night'], ]; for (const [dawn, step] of cases) expect(dawnStep(dawn)).toBe(step); }); it('reads the end-of-shift sub-line', () => { expect(END_OF_SHIFT_SUBLINE).toBe('END OF SHIFT ยท 05:48'); }); }); describe('daybreak palette', () => { it('is not a journey chapter', () => { expect(Object.keys(CHAPTER_PALETTES)).not.toContain('daybreak'); }); it('leaves the destination untouched at 0 and becomes daybreak at 1', () => { const untouched = createMutableChapterPalette('destination'); blendDaybreak(untouched, 0); expect(untouched.sky.getHex()).toBe(CHAPTER_PALETTES.destination.sky); expect(untouched.starVisibility).toBe(CHAPTER_PALETTES.destination.starVisibility); const full = createMutableChapterPalette('destination'); blendDaybreak(full, 1); for (const key of ['sky', 'fog', 'terrainLow', 'terrainHigh', 'sun', 'haze'] as const) { expect(full[key].getHex()).toBe(DAYBREAK_PALETTE[key]); } expect(full.warmth).toBe(1.25); expect(full.terrainEnergy).toBe(0.4); expect(full.starVisibility).toBe(0); expect(full.streakEnergy).toBe(0); }); it('blends partway and clamps out-of-range amounts', () => { const half = createMutableChapterPalette('destination'); blendDaybreak(half, 0.5); expect(half.warmth).toBeCloseTo((1 + 1.25) / 2); expect(half.starVisibility).toBeCloseTo(0.08); const over = createMutableChapterPalette('destination'); blendDaybreak(over, 3); expect(over.sky.getHex()).toBe(DAYBREAK_PALETTE.sky); const nan = createMutableChapterPalette('destination'); blendDaybreak(nan, Number.NaN); expect(nan.sky.getHex()).toBe(CHAPTER_PALETTES.destination.sky); }); it('boosts the stars as the engine cuts, then drains them as the dawn rises', () => { expect(engineOffStarScale(0, 0)).toBe(1); expect(engineOffStarScale(1, 0)).toBeCloseTo(1.8); expect(engineOffStarScale(1, 0.5)).toBeCloseTo(1.4); expect(engineOffStarScale(1, 1)).toBe(1); // Combined with the daybreak blend, the stars are gone by full dawn. const palette = createMutableChapterPalette('destination'); blendDaybreak(palette, 1); expect(palette.starVisibility * engineOffStarScale(1, 1)).toBe(0); }); });