UNPKG

@jurneyx2/react-lottie-hooks

Version:

🎯 Simple and powerful React hooks for DotLottie animations with GSAP ScrollTrigger integration and automatic SSR/CSR detection

653 lines (522 loc) β€’ 16.9 kB
# 🎯 React Lottie Hooks v1.2.7 (DotLottie) **Simple and powerful React hooks for DotLottie animations with GSAP ScrollTrigger** > ✨ Easily implement scroll-based animations with React hooks optimized exclusively for DotLottie! > > **v1.2.7 is the latest stable release** - Enhanced with full internationalization, ES Module compatibility, and security improvements πŸš€ **[View Live Examples](https://github.com/Imjurney/react-dotLottie-hooks/tree/main/examples)** | πŸ“¦ **[NPM Package](https://www.npmjs.com/package/@jurneyx2/react-lottie-hooks)** | πŸ“š **[Documentation](https://github.com/Imjurney/react-dotLottie-hooks)** ## πŸš€ Features - 🎨 **DotLottie Exclusive**: Perfect support for `@lottiefiles/dotlottie-react` - πŸ“± **SSR/CSR Safe**: Full compatibility with SSR frameworks like Next.js, Remix, React Router - 🎯 **GSAP ScrollTrigger**: Scroll-based animations and effects - πŸ”§ **TypeScript**: Complete type safety - πŸŽͺ **Simple API**: Ready to use without complex configuration - ⚑ **Optimized**: Performance and memory efficiency optimized - 🎨 **4 Complete Examples**: Next.js, Vite, Remix, and React Router implementations with full source code - 🌍 **Internationalization**: Debug messages in Korean and English - πŸ“¦ **ES Module Compatible**: Works with all modern bundlers (Vite, Webpack, esbuild) ## πŸ†• What's New in v1.2.7 ### πŸ”’ Security & Performance Improvements Enhanced library security and bundle optimization: ```tsx // No source maps in production builds for better security // Reduced bundle size and protected source code ``` ### πŸ“¦ Enhanced ES Module Compatibility Improved GSAP ScrollTrigger integration for React Router v7: ```tsx // Automatic handling of .js extensions in ESM environments // Perfect compatibility with React Router v7 framework mode const hook = useLottieScrollTrigger({ start: "top center", end: "bottom center", }); ``` ### πŸ› οΈ Build Optimizations - **Security**: Removed source maps from production builds - **Bundle Size**: Optimized output size for better performance - **ESM Support**: Enhanced compatibility with strict ESM environments ## πŸ“¦ Installation ```bash # npm (recommended) npm install @jurneyx2/react-lottie-hooks @lottiefiles/dotlottie-react gsap # pnpm pnpm add @jurneyx2/react-lottie-hooks @lottiefiles/dotlottie-react gsap # yarn yarn add @jurneyx2/react-lottie-hooks @lottiefiles/dotlottie-react gsap ``` ## 🎯 Basic Usage ```tsx import React from "react"; import { DotLottieReact } from "@lottiefiles/dotlottie-react"; import { useLottieScrollTrigger } from "@jurneyx2/react-lottie-hooks"; export default function ScrollAnimation() { const { triggerRef, handleDotLottieRef, isLoaded } = useLottieScrollTrigger({ start: "top center", end: "bottom 20%", debug: process.env.NODE_ENV === "development", }); return ( <div> {/* Scroll trigger area */} <div ref={triggerRef} style={{ height: "100vh" }}> <h2>Animation starts when you scroll!</h2> {/* DotLottie animation */} <DotLottieReact src="/animations/my-animation.lottie" loop={false} autoplay={false} dotLottieRefCallback={handleDotLottieRef} className="w-full h-full" /> </div> {isLoaded && <p>Animation has been loaded! ✨</p>} </div> ); } ``` ## 🎨 Advanced Usage ### Using with GSAP Animations ````tsx const { triggerRef, handleDotLottieRef, play, pause, currentFrame, } = useLottieScrollTrigger({ start: "top bottom", end: "bottom top", // GSAP animation effects gsapAnimations: { scale: 1.2, rotation: 360, opacity: 0.8, duration: 2, ease: "power2.out", trigger: "enter", scrub: true, // Sync with scroll }, // Custom event handlers onEnter: (dotLottie) => { console.log("Entered animation area!"); dotLottie.setSpeed(1.5); }, ``` ### Performance Optimized Usage ```tsx function PerformanceOptimizedLottie() { const { triggerRef, handleDotLottieRef, getCurrentFrame, // ref-based getter (no re-renders) getIsPlaying, // ref-based getter (no re-renders) play, pause, } = useLottieScrollTrigger({ // Disable React state tracking (default: false) enableStateTracking: false, // Monitor state through callbacks onPlayStateChange: (isPlaying) => { console.log('Play state changed:', isPlaying); }, onFrameChange: (frame) => { console.log('Frame changed:', frame); // Update external state or UI (only when needed) }, // Adjust frame update throttle (ms) frameUpdateThrottle: 50, // default: 100ms }); const handlePlayToggle = () => { // Check current state via ref (no re-renders) if (getIsPlaying()) { pause(); } else { play(); } }; return ( <div ref={triggerRef}> <DotLottieReact src="/animation.lottie" loop={false} autoplay={false} dotLottieRefCallback={handleDotLottieRef} /> <button onClick={handlePlayToggle}> Play/Pause </button> <div> {/* Get current frame via ref (no re-renders) */} Current frame: {getCurrentFrame()} </div> </div> ); } ```` ### Scroll Progress Tracking ```tsx function ScrollProgress() { const { triggerRef, handleDotLottieRef } = useLottieScrollTrigger({ start: "top center", end: "bottom center", // onScrollUpdate has been removed in v1.2.0 // Use callbacks like onEnter, onLeave instead }); return ( <div ref={triggerRef} className="h-screen"> <DotLottieReact src="/scroll-animation.lottie" loop={false} autoplay={false} dotLottieRefCallback={handleDotLottieRef} className="w-full h-full" /> </div> ); } ``` ### Safe Usage in SSR Environment ```tsx // Next.js App Router export default function MyPage() { const { triggerRef, handleDotLottieRef, isClient, isDOMReady, isLoaded } = useLottieScrollTrigger({ strictMode: true, // Auto-enabled in SSR frameworks waitForDOMReady: true, // Wait for complete DOM load debug: true, }); // Render only on client if (!isClient || !isDOMReady) { return <div>Loading...</div>; } return ( <div ref={triggerRef} className="h-screen"> <DotLottieReact src="/animations/hero.lottie" loop={false} autoplay={false} dotLottieRefCallback={handleDotLottieRef} className="w-full h-full" /> </div> ); } ``` ## 🎨 Framework Examples This package includes complete example implementations for major React frameworks: ### πŸ“± Next.js Example Perfect for server-side rendering with App Router: ```bash cd examples/nextjs-example pnpm install pnpm dev ``` **Features:** - βœ… App Router with SSR/CSR safety - βœ… Tailwind CSS styling - βœ… TypeScript configuration - βœ… Production-ready build **Key Implementation:** ```tsx // app/page.tsx import LottieScrollExample from "@/components/LottieScrollExample"; export default function Home() { return <LottieScrollExample />; } ``` ### ⚑ Vite Example Lightning-fast development with modern tooling: ```bash cd examples/vite-example pnpm install pnpm dev ``` **Features:** - βœ… Lightning-fast HMR - βœ… Optimized production build - βœ… TypeScript support - βœ… Modern bundling ### πŸƒ Remix Example Full-stack framework with SSR capabilities: ```bash cd examples/remix-example pnpm install pnpm dev ``` **Features:** - βœ… Server-side rendering - βœ… Progressive enhancement - βœ… TypeScript configuration - βœ… Tailwind CSS integration ### 🚦 React Router Example Client-side routing with React Router 7: ```bash cd examples/react-router-example pnpm install pnpm dev ``` **Features:** - βœ… React Router v7 - βœ… File-based routing - βœ… Tailwind CSS 4.0 - βœ… Vite build system ### 🎯 Common Example Features All examples include: - **Scroll Trigger Animation**: Smooth DotLottie animations triggered by scroll - **Play/Pause Controls**: Manual animation control - **Debug Information**: Real-time animation state display - **Responsive Design**: Mobile-friendly layouts - **Performance Monitoring**: Frame rate and state tracking - **Manual Control Mode**: Toggle between scroll and manual control ### πŸ“‹ Example Code Structure Each example follows this pattern: ```tsx export default function LottieScrollExample() { const [externalPlayState, setExternalPlayState] = useState(false); const [isManualControl, setIsManualControl] = useState(false); const { triggerRef, handleDotLottieRef, play, pause, isPlaying, currentFrame, isLoaded, } = useLottieScrollTrigger({ start: "top 80%", end: "bottom 20%", debug: process.env.NODE_ENV === "development", enableStateTracking: true, onPlayStateChange: (isPlaying) => { setExternalPlayState(isPlaying); }, }); return ( <div className="min-h-screen bg-gradient-to-br from-purple-50 to-blue-50"> {/* Control Panel */} <div className="fixed top-4 right-4 bg-white rounded-lg shadow-lg p-4"> <button onClick={() => setIsManualControl(!isManualControl)} className="mb-2 px-4 py-2 bg-blue-500 text-white rounded" > {isManualControl ? "Auto Mode" : "Manual Mode"} </button> {isManualControl && ( <div className="space-x-2"> <button onClick={play} className="px-3 py-1 bg-green-500 text-white rounded" > Play </button> <button onClick={pause} className="px-3 py-1 bg-red-500 text-white rounded" > Pause </button> </div> )} </div> {/* Scroll Trigger Section */} <div ref={triggerRef} className="h-screen flex items-center justify-center" > <div className="max-w-md w-full"> <DotLottieReact src="/animations/sample.lottie" loop={false} autoplay={false} dotLottieRefCallback={handleDotLottieRef} className="w-full h-auto" /> </div> </div> {/* Status Display */} <div className="p-8 text-center"> <p>Animation Status: {isLoaded ? "βœ… Loaded" : "⏳ Loading..."}</p> <p>Playing: {isPlaying ? "▢️ Yes" : "⏸️ No"}</p> <p>Current Frame: {currentFrame}</p> </div> </div> ); } ``` ## πŸ“‹ API Reference ### `useLottieScrollTrigger(options)` #### Options ```typescript interface UseLottieScrollTriggerOptions { // ScrollTrigger basic settings start?: string; // default: "top center" end?: string; // default: "bottom 20%" markers?: boolean; // default: true only in development pauseOnLoad?: boolean; // default: true // Debugging debug?: boolean; // default: false debugLanguage?: "ko" | "en"; // default: "ko" // SSR/CSR safety strictMode?: boolean; // default: auto true in SSR frameworks waitForDOMReady?: boolean; // default: auto true in SSR frameworks // Performance optimization options (re-render control) enableStateTracking?: boolean; // default: false (disable React state tracking) frameUpdateThrottle?: number; // default: 100 (ms) onPlayStateChange?: (isPlaying: boolean) => void; // Play state change callback onFrameChange?: (currentFrame: number) => void; // Frame change callback // DotLottie event callbacks onEnter?: (dotLottie: DotLottie) => void; onLeave?: (dotLottie: DotLottie) => void; onEnterBack?: (dotLottie: DotLottie) => void; onLeaveBack?: (dotLottie: DotLottie) => void; // GSAP animations gsapAnimations?: { rotation?: number; // Rotation angle scale?: number; // Scale factor x?: number; // X-axis movement y?: number; // Y-axis movement opacity?: number; // Opacity duration?: number; // Animation duration ease?: string; // Easing function trigger?: "enter" | "enterBack" | "leave" | "leaveBack" | "scroll"; scrub?: boolean | number; // Sync with scroll }; // Additional ScrollTrigger options scrollTriggerOptions?: Partial<ScrollTrigger.StaticVars>; } ``` #### Return Value ```typescript interface UseLottieScrollTriggerReturn { // Required refs triggerRef: React.RefObject<HTMLDivElement>; handleDotLottieRef: (dotLottie: DotLottie | null) => void; // DotLottie instance and state dotLottie: DotLottie | null; isDotLottieLoaded: boolean; // Control functions play: () => void; pause: () => void; stop: () => void; setFrame: (frame: number) => void; // Performance optimized state access getCurrentFrame: () => number; // ref-based getter (no re-renders) getIsPlaying: () => boolean; // ref-based getter (no re-renders) // React state (updates only when enableStateTracking is true) isPlaying: boolean; // always false if enableStateTracking is false currentFrame: number; // always 0 if enableStateTracking is false // Environment and loading state isMounted: boolean; isDOMReady: boolean; isClient: boolean; isLoaded: boolean; isSSRFramework: boolean; isNextJS: boolean; isNuxt: boolean; } ``` ## ⚑ Performance Optimization ### Minimize Re-renders By default, `useLottieScrollTrigger` disables React state tracking for performance: ```typescript // πŸš€ High performance mode (default) const { getCurrentFrame, getIsPlaying } = useLottieScrollTrigger({ enableStateTracking: false, // default }); // Check state via ref (no re-renders) console.log(getCurrentFrame()); // Current frame console.log(getIsPlaying()); // Play state ``` ### Selective State Tracking Enable only when you need to display animation state in UI: ```typescript // 🎯 Track state only when needed const { isPlaying, currentFrame } = useLottieScrollTrigger({ enableStateTracking: true, // Enable React state updates frameUpdateThrottle: 200, // Limit frame updates to 200ms onFrameChange: (frame) => { // External state management or UI updates setExternalState(frame); }, }); ``` ### Callback-based State Monitoring ```typescript // πŸ“Š Performance optimization with callbacks const { play, pause } = useLottieScrollTrigger({ enableStateTracking: false, // Prevent re-renders onPlayStateChange: (isPlaying) => { // Update external state only when needed updateExternalPlayState(isPlaying); }, onFrameChange: (frame) => { // Update progress bar etc. updateProgressBar(frame); }, }); ``` ### Frame Update Throttling ```typescript const hook = useLottieScrollTrigger({ frameUpdateThrottle: 100, // default: 100ms (10fps) // frameUpdateThrottle: 16, // For 60fps when needed // frameUpdateThrottle: 50, // 20fps compromise }); ``` ### Performance Monitoring ```typescript const hook = useLottieScrollTrigger({ debug: true, // Check performance logs in console onFrameChange: (frame) => { console.log(`Frame update: ${frame}`); }, }); ``` ## πŸ› οΈ Troubleshooting ### Common Issues **Q: Animation won't play** ```typescript // 1. Check DotLottie load status const { isLoaded, isDotLottieLoaded } = useLottieScrollTrigger({ debug: true }); // 2. Make sure autoplay is set to false <DotLottieReact autoplay={false} />; // 3. Check pauseOnLoad option useLottieScrollTrigger({ pauseOnLoad: true }); // Pause after load ``` **Q: Getting errors in SSR environment** ```typescript // Enable strictMode and waitForDOMReady const hook = useLottieScrollTrigger({ strictMode: true, waitForDOMReady: true, }); // Render only on client if (!hook.isClient || !hook.isDOMReady) { return <div>Loading...</div>; } ``` **Q: ScrollTrigger not working** ```typescript // 1. Check if triggerRef is properly set <div ref={triggerRef}> <DotLottieReact dotLottieRefCallback={handleDotLottieRef} /> </div> // 2. Verify GSAP is correctly installed npm list gsap // 3. Debug the issue with debug mode useLottieScrollTrigger({ debug: true, markers: true }) ``` ## 🀝 Contributing 1. Fork this repository 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'feat: add amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ## πŸ“„ License MIT License - see the [LICENSE](LICENSE) file for details. ## πŸ™ Acknowledgments - [@lottiefiles/dotlottie-react](https://github.com/LottieFiles/dotlottie-react) - Excellent DotLottie React component - [GSAP](https://greensock.com/gsap/) - Powerful animation library - All contributors in the React community --- **πŸ’‘ For more examples and documentation, visit the [GitHub Repository](https://github.com/Imjurney/react-dotLottie-hooks)!**