import React, { useMemo } from 'react'; import { SeasonalOverlayProps } from '../types'; import { animLeafTumble, animSeedDrift, animPollenFloat, animPollenGlow, animRayBreathe, animAuroraSway, animEarthRespire, } from './EarthDay.css'; // ─── Palette (oklch) ────────────────────────────────────────────────────────── // Verdant, hopeful nature: living leaf greens, soft sky + deep ocean blues, // and a warm sun highlight. Kept low-alpha so chat text stays WCAG-AA legible. const LEAF_GREEN = 'oklch(0.65 0.15 145)'; const LEAF_DEEP = 'oklch(0.52 0.14 150)'; const LEAF_LIME = 'oklch(0.78 0.16 130)'; const SKY_BLUE = 'oklch(0.70 0.10 230)'; const OCEAN_BLUE = 'oklch(0.55 0.12 240)'; const SUN_WARM = 'oklch(0.92 0.10 95)'; const POLLEN_GOLD = 'oklch(0.88 0.13 95)'; // Soft, translucent tints for the ambient gradient washes. const LEAF_GREEN_SOFT = 'oklch(0.65 0.15 145 / 0.10)'; const LEAF_LIME_SOFT = 'oklch(0.78 0.16 130 / 0.08)'; const SKY_BLUE_SOFT = 'oklch(0.70 0.10 230 / 0.07)'; const SUN_SOFT = 'oklch(0.92 0.10 95 / 0.10)'; const AURORA_TINT = 'oklch(0.74 0.16 155 / 0.22)'; // ─── Inline SVG leaf, drawn once (CSP-safe data-URI, no external assets) ─────── // A simple veined leaf silhouette. Color is baked per-variant so we can tint // individual falling leaves without a runtime filter. function leafUri(fill: string, vein: string): string { const svg = ``; return `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}")`; } // Three leaf tints, generated once at module load. const LEAF_URIS = [ leafUri('oklch(0.65 0.15 145 / 0.9)', 'oklch(0.40 0.10 150 / 0.7)'), leafUri('oklch(0.78 0.16 130 / 0.9)', 'oklch(0.50 0.12 140 / 0.7)'), leafUri('oklch(0.52 0.14 150 / 0.9)', 'oklch(0.34 0.08 155 / 0.7)'), ]; export function EarthDayOverlay({ reduced }: SeasonalOverlayProps) { // ── Deterministic per-mount generation — never per-frame React state. ── // Tumbling leaves (the heaviest motif → kept modest). const leaves = useMemo( () => Array.from({ length: 10 }, (_, i) => ({ left: (i * 6173 + 137) % 96, size: 16 + (i % 4) * 6, duration: 16 + (i % 5) * 2.5, delay: (i * 1.7) % 16, uri: LEAF_URIS[i % LEAF_URIS.length], opacity: 0.45 + (i % 3) * 0.12, })), [], ); // Tiny drifting seeds / spores — small, faint, slow. const seeds = useMemo( () => Array.from({ length: 8 }, (_, i) => ({ left: (i * 4099 + 53) % 98, size: 2 + (i % 2), duration: 18 + (i % 4) * 3, delay: (i * 2.3) % 18, })), [], ); // Glowing pollen motes rising from below, catching the light. const pollen = useMemo( () => Array.from({ length: 12 }, (_, i) => ({ left: (i * 5279 + 89) % 100, bottom: (i * 2731 + 31) % 32, size: 3 + (i % 3), duration: 13 + (i % 6) * 2, delay: (i * 0.9) % 13, twinkle: 2.6 + (i % 5) * 0.5, })), [], ); // Sun rays fanning down from the top — a few soft angled beams. const rays = useMemo( () => Array.from({ length: 5 }, (_, i) => ({ left: 12 + i * 18, rotate: -14 + i * 7, width: 60 + (i % 3) * 26, duration: 8 + (i % 3) * 2, delay: i * 1.3, opacity: 0.32 + (i % 3) * 0.08, })), [], ); return ( <> {/* ── Base wash: layered green/sky gradients for verdant depth ── */}
{/* ── Green aurora veil drifting near the top ── */} {/* ── Soft sun rays fanning down from above ── */} {/* ── Blue-marble Earth tucked into the bottom-right corner ── */} {/* ── Rising, glowing pollen motes ── */} {pollen.map((p, i) => ( ))} {/* ── Drifting seeds / spores (skip entirely when reduced) ── */} {!reduced && seeds.map((s, i) => ( ))} {/* ── Tumbling leaves ── */} {leaves.map((l, i) => ( ))} > ); }