"use client"; /** * Confetti — a lightweight, dependency-free confetti shower for the reward * celebration. Spawns a fixed set of colored pieces that fall with a little * horizontal drift and spin, then fade. Pointer-events-none so it never * blocks the dialog beneath it. Honors prefers-reduced-motion. */ import { useMemo } from "react"; const COLORS = [ "#f59e0b", "#fb7185", "#34d399", "#60a5fa", "#fbbf24", "#f472b6", "#a78bfa", "#facc15", ]; // Deterministic pseudo-random in [0,1) from a seed. Math.sin is pure, so this // keeps the confetti layout stable across renders (no Math.random impurity). function rand(seed: number): number { const x = Math.sin(seed * 127.1) * 43758.5453; return x - Math.floor(x); } export function Confetti({ pieces = 140 }: { pieces?: number }) { // Computed once per mount; varying by index keeps it deterministic-ish // without Date/Math.random concerns (this is a normal component). const items = useMemo( () => Array.from({ length: pieces }, (_, i) => { const r = (k: number) => rand(i * 9.17 + k * 3.13); return { left: r(1) * 100, delay: r(2) * 0.5, dur: 2.4 + r(3) * 1.8, rot: r(4) * 360, drift: (r(5) * 2 - 1) * 70, size: 6 + r(6) * 7, color: COLORS[i % COLORS.length], round: r(7) < 0.3, }; }), [pieces], ); return (
{items.map((p, i) => ( ))}
); }