An open API service indexing awesome lists of open source software.

https://github.com/amardev07/911-ui-

Porsche 911 Animated UI
https://github.com/amardev07/911-ui-

360-view countup gsap npm parallax reactjs scrolltrigger skipper

Last synced: 4 months ago
JSON representation

Porsche 911 Animated UI

Awesome Lists containing this project

README

          

# 🎯 Image Cursor Trail Component - Complete Guide

## 📋 Table of Contents
- [Overview](#overview)
- [How It Works](#how-it-works)
- [Component Architecture](#component-architecture)
- [State Management](#state-management)
- [Event Handling](#event-handling)
- [CSS Architecture](#css-architecture)
- [Performance Optimizations](#performance-optimizations)
- [Customization Options](#customization-options)
- [Troubleshooting](#troubleshooting)

## 🔍 Overview

**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.

### ✨ Key Features:
- **Smooth cursor tracking** - 60fps smooth movement
- **Random image selection** - Array se random images pick karta hai
- **Boundary detection** - Effect sirf container ke andar
- **Performance optimized** - GPU acceleration aur efficient rendering
- **Mobile responsive** - Touch devices pe bhi works
- **Customizable** - Easy to modify aur extend

---

## ⚙️ How It Works

### 🎮 Basic Flow:
```
1. Mouse Move → Track Position
2. Inside Container? → Check Boundaries
3. Add New Image → Random selection + positioning
4. Animate Trail → Fade out + drift effect
5. Cleanup → Remove old images
```

### 🧠 Core Logic:
```javascript
// 1. Mouse position tracking (document level)
document.addEventListener('mousemove', handleMouseMove);

// 2. Boundary detection
const isInside = (mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom);

// 3. Image creation (throttled)
if (now - lastImageTime > 150ms) {
createNewImage();
}

// 4. Animation loop (60fps)
setInterval(() => {
updateTrailImages();
}, 60ms);
```

---

## 🏗️ Component Architecture

### 📁 File Structure:
```
components/
├── ImageCursorTrail.jsx # Main component logic
├── ImageCursorTrail.css # Styling + animations
└── CarsImagesCollection.jsx # Usage example
```

### 🧩 Component Breakdown:

#### **1. ImageCursorTrail.jsx (Main Component)**
```javascript
const ImageCursorTrail = ({ items, maxNumberOfImages, distance, imgClass, children }) => {
// State management
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const [isInsideContainer, setIsInsideContainer] = useState(false);
const [imageTrail, setImageTrail] = useState([]);

// Refs for performance
const containerRef = useRef(null);
const lastImageTime = useRef(0);
const imageCounter = useRef(0);

// Event handlers + lifecycle
useEffect(() => { /* Mouse tracking */ }, []);
useEffect(() => { /* Trail animation */ }, []);
useEffect(() => { /* Cleanup */ }, []);

return (


{/* Trail Images */}
{/* Custom Cursor */}
{/* Content */}

);
};
```

#### **2. Props Interface:**
```javascript
interface Props {
items: string[]; // Array of image URLs
maxNumberOfImages?: number; // Max trail length (default: 5)
distance?: number; // Distance from cursor (default: 25px)
imgClass?: string; // CSS class for image size
children: ReactNode; // Content to display
}
```

---

## 📊 State Management

### 🎯 State Variables:

#### **1. mousePosition**
```javascript
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
```
- **Purpose**: Real-time cursor coordinates
- **Update**: Document-level mousemove event
- **Usage**: Custom cursor positioning

#### **2. isInsideContainer**
```javascript
const [isInsideContainer, setIsInsideContainer] = useState(false);
```
- **Purpose**: Track if mouse is inside component boundary
- **Update**: Boundary detection calculation
- **Usage**: Conditional cursor visibility + trail creation

#### **3. imageTrail**
```javascript
const [imageTrail, setImageTrail] = useState([]);
```
- **Structure**:
```javascript
[
{
id: 1,
x: 500,
y: 300,
src: "image-url",
opacity: 1,
scale: 0.9,
rotation: 15
}
]
```
- **Purpose**: Trail images data aur positioning
- **Update**: Add new + animate existing + remove old

### 🔧 Refs (Performance):

#### **1. containerRef**
```javascript
const containerRef = useRef(null);
```
- **Purpose**: DOM reference for boundary calculations
- **Usage**: `getBoundingClientRect()` for position detection

#### **2. lastImageTime**
```javascript
const lastImageTime = useRef(0);
```
- **Purpose**: Throttling image creation
- **Usage**: Prevent too many images spawning rapidly

#### **3. imageCounter**
```javascript
const imageCounter = useRef(0);
```
- **Purpose**: Unique IDs for images
- **Usage**: React key prop + z-index management

---

## 🎪 Event Handling

### 🖱️ Mouse Events:

#### **1. Document MouseMove**
```javascript
const handleMouseMove = (e) => {
// Always update position (smooth cursor)
setMousePosition({ x: e.clientX, y: e.clientY });

// Boundary detection
const rect = containerRef.current.getBoundingClientRect();
const isInside = (
e.clientX >= rect.left && e.clientX <= rect.right &&
e.clientY >= rect.top && e.clientY <= rect.bottom
);

setIsInsideContainer(isInside);

// Create trail images (only when inside)
if (isInside && shouldCreateImage()) {
createNewImage(e.clientX, e.clientY);
}
};
```

#### **2. Image Creation Logic**
```javascript
const createNewImage = (x, y) => {
const newImage = {
id: imageCounter.current++,
x: x,
y: y,
src: items[Math.floor(Math.random() * items.length)], // Random selection
opacity: 1,
scale: 0.8 + Math.random() * 0.4, // Random size (0.8-1.2)
rotation: (Math.random() - 0.5) * 30 // Random rotation (-15° to +15°)
};

setImageTrail(prev => [newImage, ...prev].slice(0, maxNumberOfImages));
};
```

#### **3. Throttling Mechanism**
```javascript
const shouldCreateImage = () => {
const now = Date.now();
if (now - lastImageTime.current > 150) { // 150ms throttle
lastImageTime.current = now;
return true;
}
return false;
};
```

---

## 🎨 CSS Architecture

### 🏗️ CSS Structure:

#### **1. Container Setup**
```css
.cursor-trail-container {
position: relative; /* Positioning context */
min-height: 100vh; /* Full viewport */
overflow: hidden; /* Prevent scrollbars */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.cursor-trail-container:hover {
cursor: none; /* Hide default cursor on hover */
}
```

#### **2. Trail Images**
```css
.trail-image {
position: fixed; /* Fixed positioning for smooth movement */
pointer-events: none; /* Don't interfere with mouse events */
object-fit: cover; /* Maintain aspect ratio */
border-radius: 12px; /* Rounded corners */
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); /* Depth */
transition: opacity 0.2s ease-out, transform 0.1s ease-out;
z-index: 40; /* Layer management */
will-change: transform; /* GPU acceleration hint */
}
```

#### **3. Custom Cursor**
```css
.custom-cursor {
position: fixed;
width: 20px;
height: 20px;
background: radial-gradient(circle, #ffffff 0%, #f0f0f0 70%, #e0e0e0 100%);
border: 2px solid rgba(255, 255, 255, 0.8);
border-radius: 50%;
pointer-events: none;
z-index: 9999; /* Always on top */
transform: translate(-50%, -50%); /* Center on cursor */
transition: all 0.1s ease-out;
will-change: transform; /* Smooth movement */
}
```

### 🎭 Animation System:

#### **1. Image Lifecycle Animation**
```javascript
// Creation
.trail-image {
animation: imageAppear 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes imageAppear {
0% { opacity: 0; transform: scale(0.5) rotate(-10deg); }
50% { opacity: 0.8; transform: scale(1.1) rotate(5deg); }
100% { opacity: 1; transform: scale(1) rotate(0deg); }
}

// Fade out (JavaScript)
setInterval(() => {
setImageTrail(prev =>
prev.map((img, index) => ({
...img,
opacity: Math.max(0, img.opacity - 0.025), // Gradual fade
scale: img.scale * 0.985, // Slight shrink
y: img.y + (index * 1.5) // Drift down
})).filter(img => img.opacity > 0.1) // Remove faded
);
}, 60);
```

---

## ⚡ Performance Optimizations

### 🚀 Key Optimizations:

#### **1. GPU Acceleration**
```css
.trail-image,
.custom-cursor {
will-change: transform; /* Hint browser for GPU layer */
transform: translateZ(0); /* Force hardware acceleration */
}
```

#### **2. Efficient Event Handling**
```javascript
// Document-level listener (not container-level)
document.addEventListener('mousemove', handleMouseMove);

// Throttling to prevent too many images
if (now - lastImageTime.current > 150) {
createNewImage();
}
```

#### **3. Memory Management**
```javascript
// Automatic cleanup
.filter(img => img.opacity > 0.1) // Remove faded images

// Limit trail length
.slice(0, maxNumberOfImages) // Cap array size

// Cleanup on unmount
return () => {
document.removeEventListener('mousemove', handleMouseMove);
};
```

#### **4. React Optimizations**
```javascript
// useRef for non-reactive values
const lastImageTime = useRef(0); // No re-renders
const imageCounter = useRef(0); // Persistent counter

// Conditional rendering
{isInsideContainer && }
```

---

## 🎛️ Customization Options

### 📝 Props Customization:

#### **1. Image Settings**
```javascript

```

#### **2. CSS Classes**
```css
/* Custom size classes */
.large-size { width: 200px; height: 250px; }
.small-size { width: 80px; height: 100px; }
.square-size { width: 150px; height: 150px; }
```

#### **3. Animation Timing**
```javascript
// In component
const THROTTLE_TIME = 100; // Faster image creation
const FADE_SPEED = 0.05; // Faster fade out
const ANIMATION_INTERVAL = 30; // Smoother animation (120fps)
```

#### **4. Visual Effects**
```css
/* Different cursor styles */
.glow-cursor {
box-shadow: 0 0 50px rgba(255, 255, 255, 0.8);
background: radial-gradient(circle, #ff6b6b, #4ecdc4);
}

/* Different image effects */
.neon-images {
box-shadow: 0 0 30px rgba(0, 255, 255, 0.5);
border: 2px solid rgba(0, 255, 255, 0.3);
}
```

---

## 🔧 Troubleshooting

### ❌ Common Issues & Solutions:

#### **1. Cursor Not Smooth**
**Problem**: Laggy cursor movement
**Solution**:
```javascript
// Use document-level listener
document.addEventListener('mousemove', handler);

// Add GPU acceleration
.custom-cursor { will-change: transform; }
```

#### **2. Images Not Appearing**
**Problem**: No trail images
**Solution**:
```javascript
// Check image URLs
console.log('Images loaded:', items);

// Check boundary detection
console.log('Inside container:', isInsideContainer);
```

#### **3. Effect Outside Container**
**Problem**: Trail appears on other pages
**Solution**:
```javascript
// Proper cleanup
useEffect(() => {
return () => {
document.removeEventListener('mousemove', handleMouseMove);
setImageTrail([]); // Clear trail
};
}, []);
```

#### **4. Performance Issues**
**Problem**: Slow rendering, frame drops
**Solution**:
```javascript
// Reduce max images
maxNumberOfImages={3}

// Increase throttle time
if (now - lastImageTime.current > 200) { ... }

// Optimize CSS
.trail-image { will-change: transform; }
```

---

## 🎯 Advanced Usage Examples

### 🌟 Custom Implementations:

#### **1. Different Image Categories**
```javascript
const carImages = ['car1.jpg', 'car2.jpg'];
const animalImages = ['cat.jpg', 'dog.jpg'];

```

#### **2. Dynamic Configuration**
```javascript
const [trailConfig, setTrailConfig] = useState({
maxImages: 5,
distance: 25,
size: 'medium'
});

```

#### **3. Multiple Trail Areas**
```javascript
function MultiTrailPage() {
return (












);
}
```

---

## 📚 Learning Path

### 🎓 Skills Needed:
1. **React Hooks** - useState, useEffect, useRef
2. **JavaScript Events** - Mouse events, event delegation
3. **CSS Animations** - Transitions, keyframes
4. **Performance** - GPU acceleration, throttling
5. **Math** - Coordinate calculations, boundary detection

### 🛠️ Build Your Own:
1. Start with basic mouse tracking
2. Add image rendering
3. Implement boundary detection
4. Add animations and effects
5. Optimize performance
6. Add customization options

### 🔗 Useful Resources:
- [React Hooks Documentation](https://reactjs.org/docs/hooks-intro.html)
- [CSS will-change Property](https://developer.mozilla.org/en-US/docs/Web/CSS/will-change)
- [Mouse Events API](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent)
- [Performance Optimization](https://web.dev/performance/)

---

## 📄 Component Summary

**ImageCursorTrail** ek advanced interactive component hai jo:

✅ **Smooth cursor tracking** provide karta hai
✅ **Boundary-aware** effect sirf designated area main
✅ **Performance optimized** GPU acceleration ke saath
✅ **Highly customizable** props aur CSS se
✅ **Mobile responsive** touch devices ke liye
✅ **Production ready** proper cleanup aur error handling

Is guide ko follow kar ke aap similar advanced components bana sakte hain! 🚀

# 360° Product Viewer - Complete Step-by-Step Explanation

## Step 1: Basic Setup and Imports

```javascript
import React, { useState, useRef, useEffect } from 'react';
```

**Explanation:**
- `useState` - For state management (like current image index, dragging status)
- `useRef` - To access DOM elements directly
- `useEffect` - To handle side effects (like autoplay, event listeners)

## Step 2: State Variables Setup

```javascript
const [currentIndex, setCurrentIndex] = useState(0);
const [isDragging, setIsDragging] = useState(false);
const [isAutoplay, setIsAutoplay] = useState(true);
const [lastMouseX, setLastMouseX] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const containerRef = useRef(null);
const autoplayRef = useRef(null);
```

**Purpose of Each State:**
- `currentIndex` - Which image is currently showing (0 to 35)
- `isDragging` - Whether user is dragging or not
- `isAutoplay` - Whether automatic rotation is running
- `lastMouseX` - Previous mouse position (to calculate drag distance)
- `isLoading` - Whether image is loading
- `containerRef` - Reference to the image container
- `autoplayRef` - Reference to control the autoplay interval

## Step 3: Configuration Variables

```javascript
const totalImages = 36; // Total number of images
const autoplaySpeed = 400; // Speed in milliseconds
```

**Explanation:**
- These variables can be easily modified
- If you have 50 images, just change `totalImages = 50`

## Step 4: Image URL Generator Function

```javascript
const getImageUrl = (index) => {
return `/Car/img_0_0_${index + 1}.jpg`;
};
```

**Explanation:**
- This function returns the correct image path for any index
- `index + 1` because images start from 1, not 0
- Example: for index 0, it returns `/Car/img_0_0_1.jpg`

## Step 5: Autoplay Functionality

```javascript
useEffect(() => {
if (isAutoplay && !isDragging) {
autoplayRef.current = setInterval(() => {
setCurrentIndex((prev) => (prev + 1) % totalImages);
}, autoplaySpeed);
} else {
clearInterval(autoplayRef.current);
}

return () => clearInterval(autoplayRef.current);
}, [isAutoplay, isDragging, autoplaySpeed, totalImages]);
```

**Step-by-step breakdown:**
1. If autoplay is ON and user is not dragging
2. Start a timer that runs every `autoplaySpeed` milliseconds
3. In the timer, increment the `currentIndex`
4. `% totalImages` ensures that after the last image, it goes back to the first
5. If autoplay is OFF or user is dragging, stop the timer
6. Clean up the timer when component unmounts

## Step 6: Mouse Drag Handlers

### Mouse Down Handler:
```javascript
const handleMouseDown = (e) => {
setIsDragging(true);
setIsAutoplay(false);
setLastMouseX(e.clientX);
};
```

**Explanation:**
- When user presses mouse, start dragging
- Pause autoplay
- Store current mouse X position

### Mouse Move Handler:
```javascript
const handleMouseMove = (e) => {
if (!isDragging) return;

const deltaX = e.clientX - lastMouseX;
const sensitivity = 5;

if (Math.abs(deltaX) > sensitivity) {
const direction = deltaX > 0 ? 1 : -1;
setCurrentIndex((prev) => {
let newIndex = prev + direction;
if (newIndex < 0) newIndex = totalImages - 1;
if (newIndex >= totalImages) newIndex = 0;
return newIndex;
});
setLastMouseX(e.clientX);
}
};
```

**Step-by-step:**
1. If not dragging, do nothing
2. Calculate mouse movement distance (`deltaX`)
3. Only change image if movement is greater than sensitivity
4. Right movement = next image, Left movement = previous image
5. Handle edge cases (wrap around for first/last image)

### Mouse Up Handler:
```javascript
const handleMouseUp = () => {
setIsDragging(false);
};
```

**Explanation:**
- When mouse is released, stop dragging

## Step 7: Touch Handlers (Mobile Support)

```javascript
const handleTouchStart = (e) => {
setIsDragging(true);
setIsAutoplay(false);
setLastMouseX(e.touches[0].clientX);
};

const handleTouchMove = (e) => {
// Similar logic as handleMouseMove but uses touches[0].clientX
};

const handleTouchEnd = () => {
setIsDragging(false);
};
```

**Explanation:**
- Touch events are for mobile devices
- Logic is same as mouse events, but uses `touches[0].clientX` instead of `clientX`

## Step 8: Global Event Listeners

```javascript
useEffect(() => {
if (isDragging) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('touchmove', handleTouchMove);
document.addEventListener('touchend', handleTouchEnd);
}

return () => {
// Remove all event listeners
};
}, [isDragging, lastMouseX]);
```

**Explanation:**
- Add event listeners to the document level
- This allows dragging to work even when mouse moves outside the image container
- Cleanup function removes all listeners to prevent memory leaks

## Step 9: Main JSX Structure

### Image Container:
```javascript


{`360° setIsLoading(false)}
onError={() => setIsLoading(false)}
/>

{isLoading && (

Loading...


)}

```

**Key Points:**
- `getImageUrl(currentIndex)` gets the current image path
- `draggable={false}` disables browser's default drag behavior
- Loading overlay only shows when `isLoading` is true
- `onLoad` and `onError` both set loading to false

### Control Buttons:
```javascript



setCurrentIndex(prev => prev === 0 ? totalImages - 1 : prev - 1)}>
← Prev

setCurrentIndex(prev => (prev + 1) % totalImages)}>
Next →


setIsAutoplay(!isAutoplay)}>
{isAutoplay ? 'Pause' : 'Play'}



```

**Explanation:**
- Prev button: If index is 0, jump to last image, otherwise subtract 1
- Next button: Use modulo operator to wrap around
- Autoplay button: Toggle the current autoplay state

### Progress Indicator:
```javascript



Frame {currentIndex + 1} of {totalImages}
{Math.round((currentIndex / (totalImages - 1)) * 100)}%





```

**Explanation:**
- Calculate progress percentage based on current index
- Progress bar width changes dynamically using inline styles
- Shows both frame number and percentage

## Step 10: How to Build This Yourself

### 1. Start with Basic Structure:
```javascript
const Viewer360 = () => {
const [currentIndex, setCurrentIndex] = useState(0);
const totalImages = 36;

return (




);
};
```

### 2. Add Navigation:
```javascript
setCurrentIndex(prev => (prev + 1) % totalImages)}>
Next

```

### 3. Add Dragging:
```javascript
const [isDragging, setIsDragging] = useState(false);
const [lastMouseX, setLastMouseX] = useState(0);

const handleMouseDown = (e) => {
setIsDragging(true);
setLastMouseX(e.clientX);
};
```

### 4. Add Autoplay:
```javascript
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex(prev => (prev + 1) % totalImages);
}, 400);

return () => clearInterval(interval);
}, []);
```

### 5. Add Styling with CSS

## Key Concepts to Understand:

1. **State Management**: How React tracks changing data
2. **Event Handling**: Responding to user interactions
3. **useEffect**: Managing side effects and cleanup
4. **Modulo Operator (%)**: For wrapping around arrays
5. **Event Listeners**: Document-level event handling
6. **Conditional Rendering**: Showing/hiding elements based on state

This structure allows you to create any 360° viewer by just changing the image paths and total count!