/* global React, gsap */
/* eslint-disable */
// Watercolor pink butterflies + flowers + atmosphere
// Animations driven entirely by GSAP (ScrollTrigger + timelines)
const { useEffect, useMemo, useRef } = React;
/* ============================================================
Watercolor butterfly SVG
============================================================ */
function ButterflySVG({ variant = 1, size = 90 }) {
const id = useMemo(() => "bf" + Math.random().toString(36).slice(2, 8), []);
const palettes = [
{ a: "#ffd2e0", b: "#ff9bbf", c: "#e25b8a", d: "#7a2d4a" },
{ a: "#ffe1ec", b: "#f8a7c4", c: "#d65a85", d: "#4a1d33" },
{ a: "#fbc6da", b: "#e88aae", c: "#b53d6a", d: "#3a1326" },
{ a: "#ffeaf2", b: "#f4b0cb", c: "#cf6f95", d: "#5a223c" },
{ a: "#f7b8d2", b: "#e87aad", c: "#a93668", d: "#2c0f1d" },
];
const p = palettes[(variant - 1) % palettes.length];
return (
);
}
/* ============================================================
Watercolor flower SVG
============================================================ */
function FlowerSVG({ variant = 1 }) {
const id = useMemo(() => "fl" + Math.random().toString(36).slice(2, 8), []);
const configs = [
{ petals: 6, outerR: 42, innerR: 22, pColor: "#ffd2e0", cColor: "#ff9bbf", stemColor: "#c87890" },
{ petals: 5, outerR: 38, innerR: 20, pColor: "#ffe0ec", cColor: "#f8b4cc", stemColor: "#d4809a" },
{ petals: 8, outerR: 35, innerR: 18, pColor: "#ffcad8", cColor: "#f09ab8", stemColor: "#b8607a" },
];
const c = configs[(variant - 1) % configs.length];
const petals = Array.from({ length: c.petals }, (_, i) => {
const angle = (i / c.petals) * Math.PI * 2;
const cx = Math.cos(angle) * c.innerR * 1.6;
const cy = Math.sin(angle) * c.innerR * 1.6;
return { cx, cy, angle };
});
return (
);
}
/* ============================================================
Static butterflies — entrance with GSAP, gentle float loop
============================================================ */
function StaticButterflies({ items }) {
const refs = useRef([]);
useEffect(() => {
if (typeof gsap === "undefined") return;
refs.current.forEach((el, i) => {
if (!el) return;
const item = items[i];
const delay = item.delay || 0;
// Entrance
gsap.fromTo(el,
{ opacity: 0, scale: 0.4, y: 30 },
{ opacity: item.opacity ?? 0.92, scale: 1, y: 0,
duration: 1.4, delay: delay + 0.3,
ease: "back.out(1.4)" }
);
// Continuous gentle float
gsap.to(el, {
y: "random(-14, 14)",
x: "random(-8, 8)",
rotation: `random(-6, 6)`,
duration: "random(3.5, 5.5)",
repeat: -1,
yoyo: true,
ease: "sine.inOut",
delay: delay,
});
// Wing flutter: animate scaleX of `.wings` children
const wings = el.querySelectorAll(".wings");
if (wings.length) {
gsap.to(wings, {
scaleX: 0.55,
duration: 0.32,
repeat: -1,
yoyo: true,
ease: "sine.inOut",
stagger: 0.05,
transformOrigin: "center center",
});
}
});
}, [items]);
return (
<>
{items.map((item, i) => (
(refs.current[i] = el)}
style={{
top: item.top,
left: item.left,
right: item.right,
bottom: item.bottom,
width: item.size,
height: item.size,
opacity: 0,
transform: `rotate(${item.rot || 0}deg)`,
}}
>
))}
>
);
}
/* ============================================================
Flying butterflies — GSAP-driven sinusoidal flight path
============================================================ */
function FlyingButterflies({ count = 2 }) {
const containerRef = useRef(null);
useEffect(() => {
if (typeof gsap === "undefined") return;
const container = containerRef.current;
if (!container) return;
const elements = container.querySelectorAll(".fly-x");
elements.forEach((el, i) => {
const delay = i * 8 + Math.random() * 4;
const dur = 22 + Math.random() * 12;
const yBase = 5 + Math.random() * 55; // % from top
// Reset to start position
gsap.set(el, { x: "-12vw", y: `${yBase}vh`, opacity: 0 });
// Flight timeline — cross-screen with sinusoidal vertical drift
const tl = gsap.timeline({ repeat: -1, delay });
tl.to(el, {
x: "112vw",
duration: dur,
ease: "none",
});
tl.to(el, { opacity: 0.9, duration: 1.2 }, 0);
tl.to(el, { opacity: 0, duration: 1.5 }, dur - 1.5);
// Sinusoidal vertical wobble layered on top
gsap.to(el, {
y: `+=${15 + Math.random() * 20}`,
duration: dur / 4,
repeat: -1,
yoyo: true,
ease: "sine.inOut",
delay,
});
// Wing flutter
const wings = el.querySelectorAll(".wings");
if (wings.length) {
gsap.to(wings, {
scaleX: 0.5,
duration: 0.28,
repeat: -1,
yoyo: true,
ease: "sine.inOut",
stagger: 0.06,
transformOrigin: "center center",
});
}
});
}, [count]);
return (
{Array.from({ length: count }, (_, i) => (
))}
);
}
/* ============================================================
Particles — GSAP stagger float-up
============================================================ */
function Particles({ count = 28 }) {
const containerRef = useRef(null);
const particles = useMemo(() => {
return Array.from({ length: count }, (_, i) => ({
id: i,
left: `${Math.random() * 98}%`,
size: 3 + Math.random() * 5,
delay: Math.random() * 12,
dur: 8 + Math.random() * 14,
drift: (Math.random() - 0.5) * 60,
}));
}, [count]);
useEffect(() => {
if (typeof gsap === "undefined") return;
const container = containerRef.current;
if (!container) return;
const els = container.querySelectorAll(".particle");
els.forEach((el, i) => {
const p = particles[i];
if (!p) return;
gsap.set(el, { y: 20, opacity: 0 });
gsap.to(el, {
y: -(window.innerHeight * 1.1),
x: p.drift,
opacity: keyframeOpacity,
duration: p.dur,
delay: p.delay,
repeat: -1,
ease: "none",
onStart() {
gsap.set(el, { opacity: 0, y: 20 });
},
onRepeat() {
gsap.set(el, { opacity: 0, y: 20, x: (Math.random() - 0.5) * 60 });
},
});
// Fade in and out within the travel
gsap.to(el, {
keyframes: [
{ opacity: 0, duration: 0 },
{ opacity: 0.9, duration: p.dur * 0.18 },
{ opacity: 0.7, duration: p.dur * 0.64 },
{ opacity: 0, duration: p.dur * 0.18 },
],
delay: p.delay,
repeat: -1,
duration: p.dur,
ease: "none",
});
});
}, [particles]);
return (
{particles.map((p) => (
))}
);
}
// Dummy ref for opacity — GSAP keyframes object handles it inline
const keyframeOpacity = undefined;
/* ============================================================
Flowers — GSAP sway
============================================================ */
function Flowers({ items }) {
const refs = useRef([]);
useEffect(() => {
if (typeof gsap === "undefined") return;
refs.current.forEach((el, i) => {
if (!el) return;
const item = items[i];
// Entrance
gsap.fromTo(el,
{ opacity: 0, scale: 0.5, y: 20 },
{ opacity: item.opacity ?? 0.85, scale: 1, y: 0,
duration: 1.6, delay: (item.delay || 0) + 0.2,
ease: "back.out(1.6)" }
);
// Gentle sway with GSAP (smoother than CSS keyframe)
gsap.to(el, {
rotation: 4,
duration: 3 + Math.random() * 3,
repeat: -1,
yoyo: true,
ease: "sine.inOut",
transformOrigin: "bottom center",
delay: item.delay || 0,
startAt: { rotation: -4 },
});
});
}, [items]);
return (
<>
{items.map((item, i) => (
(refs.current[i] = el)}
style={{
top: item.top,
left: item.left,
right: item.right,
bottom: item.bottom,
width: item.size,
height: item.size,
opacity: 0,
}}
>
))}
>
);
}