{"id":30196321,"url":"https://github.com/amardev07/911-ui-","last_synced_at":"2026-05-06T10:32:50.546Z","repository":{"id":307717267,"uuid":"1030449944","full_name":"AMARDEV07/911-UI-","owner":"AMARDEV07","description":"Porsche 911 Animated UI","archived":false,"fork":false,"pushed_at":"2025-08-09T18:56:29.000Z","size":53355,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-06T03:32:52.754Z","etag":null,"topics":["360-view","countup","gsap","npm","parallax","reactjs","scrolltrigger","skipper"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AMARDEV07.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-01T16:56:08.000Z","updated_at":"2025-08-09T18:56:32.000Z","dependencies_parsed_at":"2025-08-07T12:41:01.981Z","dependency_job_id":null,"html_url":"https://github.com/AMARDEV07/911-UI-","commit_stats":null,"previous_names":["amardev07/f1-ui-","amardev07/911-ui-"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AMARDEV07/911-UI-","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AMARDEV07%2F911-UI-","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AMARDEV07%2F911-UI-/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AMARDEV07%2F911-UI-/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AMARDEV07%2F911-UI-/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AMARDEV07","download_url":"https://codeload.github.com/AMARDEV07/911-UI-/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AMARDEV07%2F911-UI-/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281862786,"owners_count":26574703,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["360-view","countup","gsap","npm","parallax","reactjs","scrolltrigger","skipper"],"created_at":"2025-08-13T05:17:56.858Z","updated_at":"2025-10-30T18:44:24.702Z","avatar_url":"https://github.com/AMARDEV07.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎯 Image Cursor Trail Component - Complete Guide\n\n## 📋 Table of Contents\n- [Overview](#overview)\n- [How It Works](#how-it-works)\n- [Component Architecture](#component-architecture)\n- [State Management](#state-management)\n- [Event Handling](#event-handling)\n- [CSS Architecture](#css-architecture)\n- [Performance Optimizations](#performance-optimizations)\n- [Customization Options](#customization-options)\n- [Troubleshooting](#troubleshooting)\n\n## 🔍 Overview\n\n**Image Cursor Trail** ek interactive React component hai jo mouse cursor ke behind images ka trail create karta hai. Ye effect sirf designated container ke andar hi active hota hai.\n\n### ✨ Key Features:\n- **Smooth cursor tracking** - 60fps smooth movement\n- **Random image selection** - Array se random images pick karta hai\n- **Boundary detection** - Effect sirf container ke andar\n- **Performance optimized** - GPU acceleration aur efficient rendering\n- **Mobile responsive** - Touch devices pe bhi works\n- **Customizable** - Easy to modify aur extend\n\n---\n\n## ⚙️ How It Works\n\n### 🎮 Basic Flow:\n```\n1. Mouse Move → Track Position\n2. Inside Container? → Check Boundaries  \n3. Add New Image → Random selection + positioning\n4. Animate Trail → Fade out + drift effect\n5. Cleanup → Remove old images\n```\n\n### 🧠 Core Logic:\n```javascript\n// 1. Mouse position tracking (document level)\ndocument.addEventListener('mousemove', handleMouseMove);\n\n// 2. Boundary detection\nconst isInside = (mouseX \u003e= left \u0026\u0026 mouseX \u003c= right \u0026\u0026 mouseY \u003e= top \u0026\u0026 mouseY \u003c= bottom);\n\n// 3. Image creation (throttled)\nif (now - lastImageTime \u003e 150ms) {\n  createNewImage();\n}\n\n// 4. Animation loop (60fps)\nsetInterval(() =\u003e {\n  updateTrailImages();\n}, 60ms);\n```\n\n---\n\n## 🏗️ Component Architecture\n\n### 📁 File Structure:\n```\ncomponents/\n├── ImageCursorTrail.jsx     # Main component logic\n├── ImageCursorTrail.css     # Styling + animations\n└── CarsImagesCollection.jsx # Usage example\n```\n\n### 🧩 Component Breakdown:\n\n#### **1. ImageCursorTrail.jsx (Main Component)**\n```javascript\nconst ImageCursorTrail = ({ items, maxNumberOfImages, distance, imgClass, children }) =\u003e {\n  // State management\n  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });\n  const [isInsideContainer, setIsInsideContainer] = useState(false);\n  const [imageTrail, setImageTrail] = useState([]);\n  \n  // Refs for performance\n  const containerRef = useRef(null);\n  const lastImageTime = useRef(0);\n  const imageCounter = useRef(0);\n  \n  // Event handlers + lifecycle\n  useEffect(() =\u003e { /* Mouse tracking */ }, []);\n  useEffect(() =\u003e { /* Trail animation */ }, []);\n  useEffect(() =\u003e { /* Cleanup */ }, []);\n  \n  return (\n    \u003cdiv ref={containerRef}\u003e\n      {/* Trail Images */}\n      {/* Custom Cursor */}\n      {/* Content */}\n    \u003c/div\u003e\n  );\n};\n```\n\n#### **2. Props Interface:**\n```javascript\ninterface Props {\n  items: string[];           // Array of image URLs\n  maxNumberOfImages?: number; // Max trail length (default: 5)\n  distance?: number;         // Distance from cursor (default: 25px)\n  imgClass?: string;         // CSS class for image size\n  children: ReactNode;       // Content to display\n}\n```\n\n---\n\n## 📊 State Management\n\n### 🎯 State Variables:\n\n#### **1. mousePosition**\n```javascript\nconst [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });\n```\n- **Purpose**: Real-time cursor coordinates\n- **Update**: Document-level mousemove event\n- **Usage**: Custom cursor positioning\n\n#### **2. isInsideContainer** \n```javascript\nconst [isInsideContainer, setIsInsideContainer] = useState(false);\n```\n- **Purpose**: Track if mouse is inside component boundary\n- **Update**: Boundary detection calculation\n- **Usage**: Conditional cursor visibility + trail creation\n\n#### **3. imageTrail**\n```javascript\nconst [imageTrail, setImageTrail] = useState([]);\n```\n- **Structure**: \n```javascript\n[\n  {\n    id: 1,\n    x: 500,\n    y: 300,\n    src: \"image-url\",\n    opacity: 1,\n    scale: 0.9,\n    rotation: 15\n  }\n]\n```\n- **Purpose**: Trail images data aur positioning\n- **Update**: Add new + animate existing + remove old\n\n### 🔧 Refs (Performance):\n\n#### **1. containerRef**\n```javascript\nconst containerRef = useRef(null);\n```\n- **Purpose**: DOM reference for boundary calculations\n- **Usage**: `getBoundingClientRect()` for position detection\n\n#### **2. lastImageTime** \n```javascript\nconst lastImageTime = useRef(0);\n```\n- **Purpose**: Throttling image creation\n- **Usage**: Prevent too many images spawning rapidly\n\n#### **3. imageCounter**\n```javascript\nconst imageCounter = useRef(0);\n```\n- **Purpose**: Unique IDs for images\n- **Usage**: React key prop + z-index management\n\n---\n\n## 🎪 Event Handling\n\n### 🖱️ Mouse Events:\n\n#### **1. Document MouseMove**\n```javascript\nconst handleMouseMove = (e) =\u003e {\n  // Always update position (smooth cursor)\n  setMousePosition({ x: e.clientX, y: e.clientY });\n  \n  // Boundary detection\n  const rect = containerRef.current.getBoundingClientRect();\n  const isInside = (\n    e.clientX \u003e= rect.left \u0026\u0026 e.clientX \u003c= rect.right \u0026\u0026\n    e.clientY \u003e= rect.top \u0026\u0026 e.clientY \u003c= rect.bottom\n  );\n  \n  setIsInsideContainer(isInside);\n  \n  // Create trail images (only when inside)\n  if (isInside \u0026\u0026 shouldCreateImage()) {\n    createNewImage(e.clientX, e.clientY);\n  }\n};\n```\n\n#### **2. Image Creation Logic**\n```javascript\nconst createNewImage = (x, y) =\u003e {\n  const newImage = {\n    id: imageCounter.current++,\n    x: x,\n    y: y,\n    src: items[Math.floor(Math.random() * items.length)], // Random selection\n    opacity: 1,\n    scale: 0.8 + Math.random() * 0.4,  // Random size (0.8-1.2)\n    rotation: (Math.random() - 0.5) * 30 // Random rotation (-15° to +15°)\n  };\n  \n  setImageTrail(prev =\u003e [newImage, ...prev].slice(0, maxNumberOfImages));\n};\n```\n\n#### **3. Throttling Mechanism**\n```javascript\nconst shouldCreateImage = () =\u003e {\n  const now = Date.now();\n  if (now - lastImageTime.current \u003e 150) { // 150ms throttle\n    lastImageTime.current = now;\n    return true;\n  }\n  return false;\n};\n```\n\n---\n\n## 🎨 CSS Architecture\n\n### 🏗️ CSS Structure:\n\n#### **1. Container Setup**\n```css\n.cursor-trail-container {\n  position: relative;        /* Positioning context */\n  min-height: 100vh;        /* Full viewport */\n  overflow: hidden;         /* Prevent scrollbars */\n  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n}\n\n.cursor-trail-container:hover {\n  cursor: none;             /* Hide default cursor on hover */\n}\n```\n\n#### **2. Trail Images**\n```css\n.trail-image {\n  position: fixed;          /* Fixed positioning for smooth movement */\n  pointer-events: none;     /* Don't interfere with mouse events */\n  object-fit: cover;        /* Maintain aspect ratio */\n  border-radius: 12px;      /* Rounded corners */\n  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); /* Depth */\n  transition: opacity 0.2s ease-out, transform 0.1s ease-out;\n  z-index: 40;              /* Layer management */\n  will-change: transform;   /* GPU acceleration hint */\n}\n```\n\n#### **3. Custom Cursor**\n```css\n.custom-cursor {\n  position: fixed;\n  width: 20px;\n  height: 20px;\n  background: radial-gradient(circle, #ffffff 0%, #f0f0f0 70%, #e0e0e0 100%);\n  border: 2px solid rgba(255, 255, 255, 0.8);\n  border-radius: 50%;\n  pointer-events: none;\n  z-index: 9999;           /* Always on top */\n  transform: translate(-50%, -50%); /* Center on cursor */\n  transition: all 0.1s ease-out;\n  will-change: transform;  /* Smooth movement */\n}\n```\n\n### 🎭 Animation System:\n\n#### **1. Image Lifecycle Animation**\n```javascript\n// Creation\n.trail-image {\n  animation: imageAppear 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n@keyframes imageAppear {\n  0% { opacity: 0; transform: scale(0.5) rotate(-10deg); }\n  50% { opacity: 0.8; transform: scale(1.1) rotate(5deg); }\n  100% { opacity: 1; transform: scale(1) rotate(0deg); }\n}\n\n// Fade out (JavaScript)\nsetInterval(() =\u003e {\n  setImageTrail(prev =\u003e \n    prev.map((img, index) =\u003e ({\n      ...img,\n      opacity: Math.max(0, img.opacity - 0.025), // Gradual fade\n      scale: img.scale * 0.985,                  // Slight shrink\n      y: img.y + (index * 1.5)                  // Drift down\n    })).filter(img =\u003e img.opacity \u003e 0.1)        // Remove faded\n  );\n}, 60);\n```\n\n---\n\n## ⚡ Performance Optimizations\n\n### 🚀 Key Optimizations:\n\n#### **1. GPU Acceleration**\n```css\n.trail-image,\n.custom-cursor {\n  will-change: transform;  /* Hint browser for GPU layer */\n  transform: translateZ(0); /* Force hardware acceleration */\n}\n```\n\n#### **2. Efficient Event Handling**\n```javascript\n// Document-level listener (not container-level)\ndocument.addEventListener('mousemove', handleMouseMove);\n\n// Throttling to prevent too many images\nif (now - lastImageTime.current \u003e 150) {\n  createNewImage();\n}\n```\n\n#### **3. Memory Management**\n```javascript\n// Automatic cleanup\n.filter(img =\u003e img.opacity \u003e 0.1)  // Remove faded images\n\n// Limit trail length\n.slice(0, maxNumberOfImages)       // Cap array size\n\n// Cleanup on unmount\nreturn () =\u003e {\n  document.removeEventListener('mousemove', handleMouseMove);\n};\n```\n\n#### **4. React Optimizations**\n```javascript\n// useRef for non-reactive values\nconst lastImageTime = useRef(0);    // No re-renders\nconst imageCounter = useRef(0);     // Persistent counter\n\n// Conditional rendering\n{isInsideContainer \u0026\u0026 \u003cCustomCursor /\u003e}\n```\n\n---\n\n## 🎛️ Customization Options\n\n### 📝 Props Customization:\n\n#### **1. Image Settings**\n```javascript\n\u003cImageCursorTrail\n  items={imageUrls}           // Array of image URLs\n  maxNumberOfImages={8}       // More/less trail length\n  distance={40}               // Further from cursor\n  imgClass=\"large-size\"       // Custom size class\n/\u003e\n```\n\n#### **2. CSS Classes**\n```css\n/* Custom size classes */\n.large-size { width: 200px; height: 250px; }\n.small-size { width: 80px; height: 100px; }\n.square-size { width: 150px; height: 150px; }\n```\n\n#### **3. Animation Timing**\n```javascript\n// In component\nconst THROTTLE_TIME = 100;        // Faster image creation\nconst FADE_SPEED = 0.05;          // Faster fade out\nconst ANIMATION_INTERVAL = 30;    // Smoother animation (120fps)\n```\n\n#### **4. Visual Effects**\n```css\n/* Different cursor styles */\n.glow-cursor {\n  box-shadow: 0 0 50px rgba(255, 255, 255, 0.8);\n  background: radial-gradient(circle, #ff6b6b, #4ecdc4);\n}\n\n/* Different image effects */\n.neon-images {\n  box-shadow: 0 0 30px rgba(0, 255, 255, 0.5);\n  border: 2px solid rgba(0, 255, 255, 0.3);\n}\n```\n\n---\n\n## 🔧 Troubleshooting\n\n### ❌ Common Issues \u0026 Solutions:\n\n#### **1. Cursor Not Smooth**\n**Problem**: Laggy cursor movement\n**Solution**: \n```javascript\n// Use document-level listener\ndocument.addEventListener('mousemove', handler);\n\n// Add GPU acceleration\n.custom-cursor { will-change: transform; }\n```\n\n#### **2. Images Not Appearing**\n**Problem**: No trail images\n**Solution**:\n```javascript\n// Check image URLs\nconsole.log('Images loaded:', items);\n\n// Check boundary detection\nconsole.log('Inside container:', isInsideContainer);\n```\n\n#### **3. Effect Outside Container**\n**Problem**: Trail appears on other pages\n**Solution**:\n```javascript\n// Proper cleanup\nuseEffect(() =\u003e {\n  return () =\u003e {\n    document.removeEventListener('mousemove', handleMouseMove);\n    setImageTrail([]); // Clear trail\n  };\n}, []);\n```\n\n#### **4. Performance Issues**\n**Problem**: Slow rendering, frame drops\n**Solution**:\n```javascript\n// Reduce max images\nmaxNumberOfImages={3}\n\n// Increase throttle time\nif (now - lastImageTime.current \u003e 200) { ... }\n\n// Optimize CSS\n.trail-image { will-change: transform; }\n```\n\n---\n\n## 🎯 Advanced Usage Examples\n\n### 🌟 Custom Implementations:\n\n#### **1. Different Image Categories**\n```javascript\nconst carImages = ['car1.jpg', 'car2.jpg'];\nconst animalImages = ['cat.jpg', 'dog.jpg'];\n\n\u003cImageCursorTrail \n  items={hoveredCategory === 'cars' ? carImages : animalImages}\n/\u003e\n```\n\n#### **2. Dynamic Configuration**\n```javascript\nconst [trailConfig, setTrailConfig] = useState({\n  maxImages: 5,\n  distance: 25,\n  size: 'medium'\n});\n\n\u003cImageCursorTrail \n  maxNumberOfImages={trailConfig.maxImages}\n  distance={trailConfig.distance}\n  imgClass={`${trailConfig.size}-size`}\n/\u003e\n```\n\n#### **3. Multiple Trail Areas**\n```javascript\nfunction MultiTrailPage() {\n  return (\n    \u003cdiv\u003e\n      \u003cImageCursorTrail items={galleryImages}\u003e\n        \u003cGallery /\u003e\n      \u003c/ImageCursorTrail\u003e\n      \n      \u003cRegularSection /\u003e\n      \n      \u003cImageCursorTrail items={portfolioImages}\u003e\n        \u003cPortfolio /\u003e\n      \u003c/ImageCursorTrail\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n---\n\n## 📚 Learning Path\n\n### 🎓 Skills Needed:\n1. **React Hooks** - useState, useEffect, useRef\n2. **JavaScript Events** - Mouse events, event delegation\n3. **CSS Animations** - Transitions, keyframes\n4. **Performance** - GPU acceleration, throttling\n5. **Math** - Coordinate calculations, boundary detection\n\n### 🛠️ Build Your Own:\n1. Start with basic mouse tracking\n2. Add image rendering\n3. Implement boundary detection\n4. Add animations and effects\n5. Optimize performance\n6. Add customization options\n\n### 🔗 Useful Resources:\n- [React Hooks Documentation](https://reactjs.org/docs/hooks-intro.html)\n- [CSS will-change Property](https://developer.mozilla.org/en-US/docs/Web/CSS/will-change)\n- [Mouse Events API](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)\n- [Performance Optimization](https://web.dev/performance/)\n\n---\n\n## 📄 Component Summary\n\n**ImageCursorTrail** ek advanced interactive component hai jo:\n\n✅ **Smooth cursor tracking** provide karta hai  \n✅ **Boundary-aware** effect sirf designated area main  \n✅ **Performance optimized** GPU acceleration ke saath  \n✅ **Highly customizable** props aur CSS se  \n✅ **Mobile responsive** touch devices ke liye  \n✅ **Production ready** proper cleanup aur error handling  \n\nIs guide ko follow kar ke aap similar advanced components bana sakte hain! 🚀\n\n\n\n\n# 360° Product Viewer - Complete Step-by-Step Explanation\n\n## Step 1: Basic Setup and Imports\n\n```javascript\nimport React, { useState, useRef, useEffect } from 'react';\n```\n\n**Explanation:**\n- `useState` - For state management (like current image index, dragging status)\n- `useRef` - To access DOM elements directly\n- `useEffect` - To handle side effects (like autoplay, event listeners)\n\n## Step 2: State Variables Setup\n\n```javascript\nconst [currentIndex, setCurrentIndex] = useState(0);\nconst [isDragging, setIsDragging] = useState(false);\nconst [isAutoplay, setIsAutoplay] = useState(true);\nconst [lastMouseX, setLastMouseX] = useState(0);\nconst [isLoading, setIsLoading] = useState(true);\nconst containerRef = useRef(null);\nconst autoplayRef = useRef(null);\n```\n\n**Purpose of Each State:**\n- `currentIndex` - Which image is currently showing (0 to 35)\n- `isDragging` - Whether user is dragging or not\n- `isAutoplay` - Whether automatic rotation is running\n- `lastMouseX` - Previous mouse position (to calculate drag distance)\n- `isLoading` - Whether image is loading\n- `containerRef` - Reference to the image container\n- `autoplayRef` - Reference to control the autoplay interval\n\n## Step 3: Configuration Variables\n\n```javascript\nconst totalImages = 36; // Total number of images\nconst autoplaySpeed = 400; // Speed in milliseconds\n```\n\n**Explanation:**\n- These variables can be easily modified\n- If you have 50 images, just change `totalImages = 50`\n\n## Step 4: Image URL Generator Function\n\n```javascript\nconst getImageUrl = (index) =\u003e {\n  return `/Car/img_0_0_${index + 1}.jpg`;\n};\n```\n\n**Explanation:**\n- This function returns the correct image path for any index\n- `index + 1` because images start from 1, not 0\n- Example: for index 0, it returns `/Car/img_0_0_1.jpg`\n\n## Step 5: Autoplay Functionality\n\n```javascript\nuseEffect(() =\u003e {\n  if (isAutoplay \u0026\u0026 !isDragging) {\n    autoplayRef.current = setInterval(() =\u003e {\n      setCurrentIndex((prev) =\u003e (prev + 1) % totalImages);\n    }, autoplaySpeed);\n  } else {\n    clearInterval(autoplayRef.current);\n  }\n\n  return () =\u003e clearInterval(autoplayRef.current);\n}, [isAutoplay, isDragging, autoplaySpeed, totalImages]);\n```\n\n**Step-by-step breakdown:**\n1. If autoplay is ON and user is not dragging\n2. Start a timer that runs every `autoplaySpeed` milliseconds\n3. In the timer, increment the `currentIndex`\n4. `% totalImages` ensures that after the last image, it goes back to the first\n5. If autoplay is OFF or user is dragging, stop the timer\n6. Clean up the timer when component unmounts\n\n## Step 6: Mouse Drag Handlers\n\n### Mouse Down Handler:\n```javascript\nconst handleMouseDown = (e) =\u003e {\n  setIsDragging(true);\n  setIsAutoplay(false);\n  setLastMouseX(e.clientX);\n};\n```\n\n**Explanation:**\n- When user presses mouse, start dragging\n- Pause autoplay\n- Store current mouse X position\n\n### Mouse Move Handler:\n```javascript\nconst handleMouseMove = (e) =\u003e {\n  if (!isDragging) return;\n\n  const deltaX = e.clientX - lastMouseX;\n  const sensitivity = 5;\n\n  if (Math.abs(deltaX) \u003e sensitivity) {\n    const direction = deltaX \u003e 0 ? 1 : -1;\n    setCurrentIndex((prev) =\u003e {\n      let newIndex = prev + direction;\n      if (newIndex \u003c 0) newIndex = totalImages - 1;\n      if (newIndex \u003e= totalImages) newIndex = 0;\n      return newIndex;\n    });\n    setLastMouseX(e.clientX);\n  }\n};\n```\n\n**Step-by-step:**\n1. If not dragging, do nothing\n2. Calculate mouse movement distance (`deltaX`)\n3. Only change image if movement is greater than sensitivity\n4. Right movement = next image, Left movement = previous image\n5. Handle edge cases (wrap around for first/last image)\n\n### Mouse Up Handler:\n```javascript\nconst handleMouseUp = () =\u003e {\n  setIsDragging(false);\n};\n```\n\n**Explanation:**\n- When mouse is released, stop dragging\n\n## Step 7: Touch Handlers (Mobile Support)\n\n```javascript\nconst handleTouchStart = (e) =\u003e {\n  setIsDragging(true);\n  setIsAutoplay(false);\n  setLastMouseX(e.touches[0].clientX);\n};\n\nconst handleTouchMove = (e) =\u003e {\n  // Similar logic as handleMouseMove but uses touches[0].clientX\n};\n\nconst handleTouchEnd = () =\u003e {\n  setIsDragging(false);\n};\n```\n\n**Explanation:**\n- Touch events are for mobile devices\n- Logic is same as mouse events, but uses `touches[0].clientX` instead of `clientX`\n\n## Step 8: Global Event Listeners\n\n```javascript\nuseEffect(() =\u003e {\n  if (isDragging) {\n    document.addEventListener('mousemove', handleMouseMove);\n    document.addEventListener('mouseup', handleMouseUp);\n    document.addEventListener('touchmove', handleTouchMove);\n    document.addEventListener('touchend', handleTouchEnd);\n  }\n\n  return () =\u003e {\n    // Remove all event listeners\n  };\n}, [isDragging, lastMouseX]);\n```\n\n**Explanation:**\n- Add event listeners to the document level\n- This allows dragging to work even when mouse moves outside the image container\n- Cleanup function removes all listeners to prevent memory leaks\n\n## Step 9: Main JSX Structure\n\n### Image Container:\n```javascript\n\u003cdiv \n  ref={containerRef}\n  className={`viewer-container ${isDragging ? 'dragging' : ''}`}\n  onMouseDown={handleMouseDown}\n  onTouchStart={handleTouchStart}\n\u003e\n  \u003cimg\n    src={getImageUrl(currentIndex)}\n    alt={`360° view frame ${currentIndex + 1}`}\n    className=\"viewer-image\"\n    draggable={false}\n    onLoad={() =\u003e setIsLoading(false)}\n    onError={() =\u003e setIsLoading(false)}\n  /\u003e\n  \n  {isLoading \u0026\u0026 (\n    \u003cdiv className=\"loading-overlay\"\u003e\n      \u003cdiv className=\"loading-text\"\u003eLoading...\u003c/div\u003e\n    \u003c/div\u003e\n  )}\n\u003c/div\u003e\n```\n\n**Key Points:**\n- `getImageUrl(currentIndex)` gets the current image path\n- `draggable={false}` disables browser's default drag behavior\n- Loading overlay only shows when `isLoading` is true\n- `onLoad` and `onError` both set loading to false\n\n### Control Buttons:\n```javascript\n\u003cdiv className=\"controls\"\u003e\n  \u003cdiv className=\"nav-buttons\"\u003e\n    \u003cbutton onClick={() =\u003e setCurrentIndex(prev =\u003e prev === 0 ? totalImages - 1 : prev - 1)}\u003e\n      ← Prev\n    \u003c/button\u003e\n    \u003cbutton onClick={() =\u003e setCurrentIndex(prev =\u003e (prev + 1) % totalImages)}\u003e\n      Next →\n    \u003c/button\u003e\n  \u003c/div\u003e\n\n  \u003cdiv className=\"autoplay-controls\"\u003e\n    \u003cbutton onClick={() =\u003e setIsAutoplay(!isAutoplay)}\u003e\n      {isAutoplay ? 'Pause' : 'Play'}\n    \u003c/button\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n**Explanation:**\n- Prev button: If index is 0, jump to last image, otherwise subtract 1\n- Next button: Use modulo operator to wrap around\n- Autoplay button: Toggle the current autoplay state\n\n### Progress Indicator:\n```javascript\n\u003cdiv className=\"progress-section\"\u003e\n  \u003cdiv className=\"progress-info\"\u003e\n    \u003cspan\u003eFrame {currentIndex + 1} of {totalImages}\u003c/span\u003e\n    \u003cspan\u003e{Math.round((currentIndex / (totalImages - 1)) * 100)}%\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv className=\"progress-bar\"\u003e\n    \u003cdiv \n      className=\"progress-fill\"\n      style={{ width: `${(currentIndex / (totalImages - 1)) * 100}%` }}\n    /\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n**Explanation:**\n- Calculate progress percentage based on current index\n- Progress bar width changes dynamically using inline styles\n- Shows both frame number and percentage\n\n## Step 10: How to Build This Yourself\n\n### 1. Start with Basic Structure:\n```javascript\nconst Viewer360 = () =\u003e {\n  const [currentIndex, setCurrentIndex] = useState(0);\n  const totalImages = 36;\n  \n  return (\n    \u003cdiv\u003e\n      \u003cimg src={`/images/img_${currentIndex + 1}.jpg`} /\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\n### 2. Add Navigation:\n```javascript\n\u003cbutton onClick={() =\u003e setCurrentIndex(prev =\u003e (prev + 1) % totalImages)}\u003e\n  Next\n\u003c/button\u003e\n```\n\n### 3. Add Dragging:\n```javascript\nconst [isDragging, setIsDragging] = useState(false);\nconst [lastMouseX, setLastMouseX] = useState(0);\n\nconst handleMouseDown = (e) =\u003e {\n  setIsDragging(true);\n  setLastMouseX(e.clientX);\n};\n```\n\n### 4. Add Autoplay:\n```javascript\nuseEffect(() =\u003e {\n  const interval = setInterval(() =\u003e {\n    setCurrentIndex(prev =\u003e (prev + 1) % totalImages);\n  }, 400);\n  \n  return () =\u003e clearInterval(interval);\n}, []);\n```\n\n### 5. Add Styling with CSS\n\n## Key Concepts to Understand:\n\n1. **State Management**: How React tracks changing data\n2. **Event Handling**: Responding to user interactions\n3. **useEffect**: Managing side effects and cleanup\n4. **Modulo Operator (%)**: For wrapping around arrays\n5. **Event Listeners**: Document-level event handling\n6. **Conditional Rendering**: Showing/hiding elements based on state\n\nThis structure allows you to create any 360° viewer by just changing the image paths and total count!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famardev07%2F911-ui-","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famardev07%2F911-ui-","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famardev07%2F911-ui-/lists"}