- Enable SSR for home sections and gate GSAP entrance animations on fast desktop hydration so mobile no longer waits ~10s on JS to show content. - Conditionally mount desktop-only video + AutumnConfig behind an isXl viewport check so mobile never downloads them. - Replace the 625KB mobile hero webm with a 63KB static webp frame. - SSR-safe gsap.registerPlugin and hover-only video mounting in features and testimonials. Made-with: Cursor
70 lines
1.6 KiB
TypeScript
70 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import gsap from "gsap";
|
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
import lottie, { type AnimationItem } from "lottie-web";
|
|
import { useEffect, useRef } from "react";
|
|
|
|
if (typeof window !== "undefined") {
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
}
|
|
|
|
export default function SolutionAnimation() {
|
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
const animRef = useRef<AnimationItem | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!containerRef.current) return;
|
|
let cancelled = false;
|
|
|
|
const isMobile = window.innerWidth < 768;
|
|
const url = isMobile
|
|
? "/animation/solution-mobile.json"
|
|
: "/animation/solution-desktop.json";
|
|
|
|
fetch(url)
|
|
.then((res) => res.json())
|
|
.then((animationData) => {
|
|
if (cancelled || !containerRef.current) return;
|
|
|
|
const anim = lottie.loadAnimation({
|
|
container: containerRef.current,
|
|
renderer: "svg",
|
|
loop: false,
|
|
autoplay: false,
|
|
animationData,
|
|
});
|
|
|
|
animRef.current = anim;
|
|
|
|
const totalFrames = anim.totalFrames;
|
|
const loopStart = Math.floor(totalFrames * 0.2);
|
|
|
|
anim.addEventListener("complete", () => {
|
|
anim.loop = true;
|
|
anim.playSegments([loopStart, totalFrames], true);
|
|
});
|
|
|
|
const st = ScrollTrigger.create({
|
|
trigger: containerRef.current,
|
|
start: "top 75%",
|
|
onEnter: () => anim.play(),
|
|
});
|
|
|
|
cleanupRef.current = () => {
|
|
st.kill();
|
|
anim.destroy();
|
|
};
|
|
});
|
|
|
|
const cleanupRef = { current: () => {} };
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
cleanupRef.current();
|
|
};
|
|
}, []);
|
|
|
|
return <div ref={containerRef} style={{ width: "100%" }} />;
|
|
}
|