import React, { useMemo } from 'react'; import { SeasonalOverlayProps } from '../types'; import { animSnowFall, animSnowSway, animBulbBreathe, animAurora, animFrostPulse, } from './Christmas.css'; // Deterministic pseudo-random so the scene is identical every mount (no React // state per frame). Large primes keep the distribution well spread. const rand = (seed: number) => { const x = Math.sin(seed * 127.1 + 311.7) * 43758.5453; return x - Math.floor(x); }; // Warm incandescent string-light hues in oklch — gold, soft red, cool white, // pine green, icy blue. Kept luminous and gentle so they read as bokeh glow. const BULB_COLORS = [ 'oklch(0.85 0.12 85)', // warm gold 'oklch(0.72 0.15 28)', // soft red 'oklch(0.95 0.03 230)', // icy white 'oklch(0.78 0.13 150)', // pine green 'oklch(0.8 0.1 235)', // cool blue ]; type Flake = { left: number; size: number; duration: number; delay: number; swayDuration: number; opacity: number; blur: number; }; type Bulb = { left: number; top: number; size: number; color: string; duration: number; delay: number; }; export function ChristmasOverlay({ reduced }: SeasonalOverlayProps) { // Three parallax bands of snow: far (small/slow/dim) -> near (large/fast). const flakes = useMemo(() => { const bands = [ { count: 12, size: [1.5, 2.5], dur: [16, 22], op: [0.35, 0.55], blur: 0.6 }, { count: 10, size: [2.5, 4], dur: [11, 15], op: [0.55, 0.8], blur: 0.3 }, { count: 8, size: [4, 6.5], dur: [8, 11], op: [0.7, 0.95], blur: 0 }, ]; const out: Flake[] = []; let s = 1; bands.forEach((b) => { for (let i = 0; i < b.count; i += 1) { const r1 = rand(s); const r2 = rand(s + 0.37); const r3 = rand(s + 0.71); const r4 = rand(s + 0.91); out.push({ left: r1 * 100, size: b.size[0] + r2 * (b.size[1] - b.size[0]), duration: b.dur[0] + r3 * (b.dur[1] - b.dur[0]), delay: -r4 * (b.dur[1] + 4), swayDuration: 4 + r2 * 5, opacity: b.op[0] + r3 * (b.op[1] - b.op[0]), blur: b.blur, }); s += 1; } }); return out; }, []); // Bokeh string lights strung along the very top edge, gently sagging. const bulbs = useMemo(() => { const count = 9; const out: Bulb[] = []; for (let i = 0; i < count; i += 1) { const t = i / (count - 1); // Two-segment garland sag so the lights drape rather than sit in a line. const sag = Math.sin(t * Math.PI * 2) * 3.2; out.push({ left: 4 + t * 92, top: 2.5 + Math.abs(Math.sin(t * Math.PI)) * 2 + sag, size: 12 + rand(i + 5) * 8, color: BULB_COLORS[i % BULB_COLORS.length], duration: 3.4 + rand(i + 2) * 2.6, delay: -rand(i + 9) * 3, }); } return out; }, []); return ( <> {/* Deep night-blue ambient wash — layered radial + linear oklch gradients for depth. Kept low-opacity so chat text stays legible (WCAG-AA). */}