import React, { useMemo } from 'react'; import { SeasonalOverlayProps } from '../types'; import { animCloverTumble, animCloverSway, animVerdantBreathe, animRainbowShimmer, animCoinGlint, animMoteTwinkle, } from './StPatricks.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); }; // Shamrock (three-leaf) and lucky four-leaf clover silhouettes as inline SVG // data-URIs — pure CSS, no external assets, Tauri/CSP-safe. The `fill` color is // baked per-variant in oklch-adjacent sRGB (data-URIs can't carry oklch), kept // luminous green so the glyphs read as foliage even at low opacity. const cloverSvg = (leaves: 3 | 4, fill: string) => { // Each leaf is a heart-ish lobe; petals arranged radially around the stem. const heart = 'M0,-2 C5,-12 18,-9 14,2 C12,8 4,9 0,3 C-4,9 -12,8 -14,2 C-18,-9 -5,-12 0,-2 Z'; // Rotations for the lobes; 3-leaf = 120° spread, 4-leaf = 90° spread. const rots = leaves === 4 ? [0, 90, 180, 270] : [-90, 30, 150]; const lobes = rots .map((r) => ``) .join(''); const stem = ``; const svg = `` + `${lobes}${stem}`; return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`; }; // Three foliage greens for parallax depth — far/dim through near/bright. These // are the sRGB siblings of the brief's oklch emerald / shamrock-green targets. const CLOVER_FILLS = [ '#1f9e54', // deep shamrock (far) '#2db866', // emerald (mid) '#48d97f', // bright clover (near) ]; type Clover = { left: number; size: number; duration: number; delay: number; swayDuration: number; opacity: number; blur: number; fill: string; leaves: 3 | 4; // Resting position + tilt for the static (reduced) settled scene. restTop: number; restRot: number; }; type Coin = { left: number; top: number; size: number; duration: number; delay: number; }; type Mote = { left: number; top: number; size: number; duration: number; delay: number; }; export function StPatricksOverlay({ reduced }: SeasonalOverlayProps) { // Three parallax bands of clovers: far (small/slow/dim) -> near (large/fast). // ~22 clovers total; one lucky four-leaf seeded in for charm. const clovers = useMemo(() => { const bands = [ { count: 8, size: [12, 18], dur: [20, 26], op: [0.22, 0.34], blur: 0.8, fill: 0 }, { count: 8, size: [18, 26], dur: [15, 20], op: [0.34, 0.5], blur: 0.4, fill: 1 }, { count: 6, size: [26, 38], dur: [11, 15], op: [0.46, 0.62], blur: 0, fill: 2 }, ]; const out: Clover[] = []; 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); const r5 = rand(s + 1.13); 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] + 5), swayDuration: 5 + r2 * 6, opacity: b.op[0] + r3 * (b.op[1] - b.op[0]), blur: b.blur, // The single lucky four-leaf: one mid-band clover. leaves: s === 10 ? 4 : 3, fill: CLOVER_FILLS[b.fill], restTop: 6 + r5 * 88, restRot: (r4 - 0.5) * 80, }); s += 1; } }); return out; }, []); // Gold-coin glints scattered low — a faint pot-of-gold sparkle. ~5 discs. const coins = useMemo(() => { const count = 5; const out: Coin[] = []; for (let i = 0; i < count; i += 1) { out.push({ left: 8 + rand(i + 40) * 84, top: 58 + rand(i + 47) * 36, size: 8 + rand(i + 51) * 9, duration: 4 + rand(i + 55) * 3, delay: -rand(i + 61) * 6, }); } return out; }, []); // Golden sparkle motes drifting through the scene. ~7 points. const motes = useMemo(() => { const count = 7; const out: Mote[] = []; for (let i = 0; i < count; i += 1) { out.push({ left: rand(i + 70) * 100, top: 8 + rand(i + 77) * 82, size: 2 + rand(i + 83) * 3, duration: 3 + rand(i + 89) * 3.5, delay: -rand(i + 97) * 6, }); } return out; }, []); return ( <> {/* Emerald ambient wash — layered radial + linear oklch gradients for depth. Kept low-opacity so chat text stays legible (WCAG-AA). */}