Skip to content

Repository files navigation

@ddevkim/carousel-circular-3d

A luxury 3D circular carousel component for React with smooth animations, drag interactions, and premium visual effects.

npm version npm downloads license GitHub issues GitHub stars PRs Welcome

✨ Features

  • 🎨 Luxury 3D Effects - Smooth perspective transforms, depth perception, and premium visual effects
  • 🖱️ Interactive - Drag, touch, and momentum physics for natural interactions
  • High Performance - GPU-accelerated animations, 60fps on desktop, 55fps+ on mobile
  • 🖼️ Built-in Lightbox - Full-screen image viewer with smooth transitions
  • 🎯 LQIP Support - Progressive image loading with blur placeholders
  • ⌨️ Keyboard Navigation - Enhanced keyboard support for carousel and lightbox (Arrow keys, ESC) with configurable options
  • 📱 Fully Responsive - Touch-optimized for mobile devices
  • 🔧 Highly Customizable - Extensive API for fine-tuning every aspect
  • 💪 TypeScript - Full type safety and IntelliSense support
  • 🌟 Zero Dependencies - Only React as peer dependency

🎯 Why Choose This?

Unlike traditional flat carousels, this component provides:

  • ✨ Premium Feel: 3D transforms and smooth physics-based interactions
  • 🚀 Production Ready: Used in real projects, battle-tested
  • 📦 Zero Config: Works out of the box with sensible defaults
  • 🎨 Fully Customizable: 30+ props to fine-tune every aspect
  • 📱 Mobile First: Touch-optimized with momentum scrolling
  • ♿ Accessible: ARIA labels, keyboard navigation, screen reader friendly
  • ⚡ Performant: GPU-accelerated, 60fps on desktop

📚 Table of Contents

🚀 Demo

Live Demo - See it in action!

Interactive 3D carousel with smooth animations and lightbox

📦 Installation

# npm
npm install @ddevkim/carousel-circular-3d

# yarn
yarn add @ddevkim/carousel-circular-3d

# pnpm
pnpm add @ddevkim/carousel-circular-3d

🎯 Quick Start

1️⃣ Import Component + CSS

Important: You must import the CSS file for styles to work properly!

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css"; // Required for styles

2️⃣ Minimal Example (30 seconds)

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

const items = [
  { id: 1, image: "/image1.jpg", alt: "Image 1" },
  { id: 2, image: "/image2.jpg", alt: "Image 2" },
  { id: 3, image: "/image3.jpg", alt: "Image 3" },
];

function App() {
  return <CarouselCircular items={items} />;
}

That's it! 🎉 The carousel will render with sensible defaults.

3️⃣ Luxury Example (Recommended)

For a premium look with 3D depth and smooth interactions:

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

function App() {
  return (
    <CarouselCircular
      items={items}
      containerHeight={600}
      geometry={{
        radius: 900,
        cameraAngle: 12,
      }}
      visualEffect={{
        minScale: 0.5,
        enableReflection: true,
      }}
    />
  );
}

📖 API Reference

Props

Required Props

Prop Type Description
items CarouselItem[] Array of items to display (max 30 recommended)

3D Geometry (geometry)

Prop Type Default Description
radius number 600 Circle radius in pixels
perspective number radius * 3.33 Perspective depth (min: radius * 2)
cameraAngle number 0 Camera vertical angle (-30 to 30 degrees)
depthIntensity number 0 Individual item Z-depth variation (0-3, recommended: 1.0-2.0)

Interaction (interaction)

Prop Type Default Description
dragSensitivity number 1.0 Drag responsiveness multiplier
enableMomentum boolean true Enable physics-based momentum
momentumFriction number 0.95 Friction coefficient (0-1)
enableKeyboardNavigation boolean true Enable keyboard navigation (Arrow keys). Auto-disabled when lightbox is open

Auto-Rotation (autoRotateConfig)

Prop Type Default Description
enabled boolean false Enable auto-rotation
speed number 0.1 Rotation speed (degrees/frame)
resumeDelay number 3000 Delay before resuming after interaction (ms)

Visual Effects (visualEffect)

Prop Type Default Description
opacityRange [number, number] [0.3, 1.0] Opacity range [min, max]
minScale number 0.7 Minimum scale for back items (0.0~1.0, front items are always 1.0)
enableReflection boolean false Enable bottom reflection effect

Styling (style)

Prop Type Description
className string CSS class for container
itemClassName string CSS class for each item

Container

Prop Type Default Description
containerHeight number 600 Container height in pixels

Lightbox

Prop Type Default Description
enableLightboxWhenClick boolean false Enable lightbox on click
lightboxOptions LightboxOptions - Lightbox configuration

LightboxOptions:

Prop Type Default Description
enableKeyboardNavigation boolean true Enable keyboard navigation (ArrowLeft/ArrowRight) in lightbox
closeOnEsc boolean true Enable ESC key to close lightbox
backgroundBlur number 8 Background blur intensity in pixels
animationDuration number 500 Animation duration in milliseconds
onOpen function - Callback when lightbox opens (receives index)
onClose function - Callback when lightbox closes

Callbacks & Accessibility

Prop Type Description
onItemClick (item, index) => void Callback when item is clicked
ariaLabel string ARIA label for screen readers

CarouselItem Type

// Image-based item
type CarouselItemWithImage = {
  id: string | number;
  image: string;
  lqip?: {
    base64: string;
    width: number;
    height: number;
  };
  alt?: string;
  title?: string;
};

// Custom content item
type CarouselItemWithContent = {
  id: string | number;
  content: ReactNode;
  alt?: string;
  title?: string;
};

type CarouselItem = CarouselItemWithImage | CarouselItemWithContent;

🎨 Use Cases & Examples

📸 Product Gallery with Lightbox

Perfect for e-commerce sites, portfolios, or any image-heavy application:

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

const products = [
  { id: 1, image: "/products/watch.jpg", alt: "Luxury Watch" },
  { id: 2, image: "/products/phone.jpg", alt: "Smartphone" },
  { id: 3, image: "/products/laptop.jpg", alt: "Laptop" },
];

export function ProductGallery() {
  return (
    <CarouselCircular
      items={products}
      enableLightboxWhenClick={true}
      lightboxOptions={{
        enableKeyboardNavigation: true,
        closeOnEsc: true,
        backgroundBlur: 10,
      }}
      geometry={{
        radius: 900,
        cameraAngle: 12,
      }}
    />
  );
}

Features:

  • Click any product to view full-screen
  • Navigate with arrow keys or swipe
  • Press ESC to close
  • Smooth fade transitions

🚀 Progressive Loading with LQIP

Show blurred placeholders instantly while high-res images load:

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

const items = [
  {
    id: 1,
    image: "/gallery/hero.jpg",
    lqip: {
      base64: "data:image/webp;base64,UklGRiQAAABXRUJQ...", // tiny base64 image
      width: 800,
      height: 600,
    },
    alt: "Mountain landscape",
  },
];

<CarouselCircular items={items} />;

Benefits:

  • Instant visual feedback (no blank space)
  • Smooth transition from blur to sharp
  • Better perceived performance
  • Works offline (base64 inline)

🎡 Auto-Rotating Hero Carousel

Great for landing pages or showcases:

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

export function HeroCarousel() {
  return (
    <CarouselCircular
      items={items}
      autoRotateConfig={{
        enabled: true,
        speed: 0.1, // Slow, elegant rotation
        resumeDelay: 3000, // Resume 3s after user interaction
      }}
      geometry={{
        radius: 1200,
        cameraAngle: 15,
      }}
    />
  );
}

Pro Tips:

  • Use slower speed (0.05-0.15) for luxury feel
  • Longer resumeDelay gives users control
  • Rotation pauses on hover/drag automatically

🎨 Custom Content Cards

Not just images! Render any React component:

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

const teamMembers = [
  {
    id: 1,
    content: (
      <div className="team-card">
        <img src="/avatar1.jpg" alt="John Doe" />
        <h3>John Doe</h3>
        <p>CEO & Founder</p>
        <div className="social-links">{/* Your custom content */}</div>
      </div>
    ),
  },
];

export function TeamCarousel() {
  return (
    <CarouselCircular
      items={teamMembers}
      containerHeight={500}
      itemClassName="custom-team-card"
    />
  );
}

Use Cases:

  • Team members
  • Testimonials
  • Feature cards
  • Pricing tiers
  • Anything you can imagine!

🎯 Full Example: Complete Product Showcase

import { useState } from "react";
import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

export function ProductShowcase() {
  const [selectedProduct, setSelectedProduct] = useState(null);

  const products = [
    {
      id: 1,
      image: "/products/watch.jpg",
      lqip: { base64: "...", width: 800, height: 600 },
      alt: "Premium Watch",
      title: "Swiss Automatic Watch",
    },
    // ... more products
  ];

  return (
    <div className="showcase">
      <CarouselCircular
        items={products}
        containerHeight={700}
        geometry={{
          radius: 1000,
          cameraAngle: 12,
          depthIntensity: 1.5,
        }}
        visualEffect={{
          minScale: 0.6,
          opacityRange: [0.4, 1],
          enableReflection: true,
        }}
        enableLightboxWhenClick={true}
        lightboxOptions={{
          onOpen: (index) => setSelectedProduct(products[index]),
          onClose: () => setSelectedProduct(null),
        }}
        autoRotateConfig={{
          enabled: true,
          speed: 0.08,
          resumeDelay: 4000,
        }}
        onItemClick={(item, index) => {
          console.log("Clicked:", item.title);
        }}
        ariaLabel="Product showcase carousel"
      />

      {selectedProduct && (
        <div className="product-info">
          <h2>{selectedProduct.title}</h2>
          {/* Additional product details */}
        </div>
      )}
    </div>
  );
}

🎯 Best Practices

Performance Tips

  1. Image Optimization: Use optimized images (WebP, compressed JPEG)
  2. LQIP: Include LQIP data for smooth loading experience
  3. Item Count: Keep items under 30 for optimal performance
  4. Container Height: Match your content size to avoid unnecessary scaling

Visual Design Tips

  1. Radius: Larger radius (900-1200px) creates more luxurious spacing
  2. Camera Angle: 8-15 degrees provides subtle depth without distortion
  3. Depth Intensity: 1.0-2.0 adds subtle Z-axis variation
  4. Scale Range: [0.5, 1] creates dramatic focus effect

Accessibility

  1. Always provide alt text for images
  2. Set meaningful ariaLabel for container
  3. Test keyboard navigation:
    • Carousel: Arrow keys (Left/Right) for navigation
    • Lightbox: Arrow keys (Left/Right) for navigation, ESC to close
    • Keyboard navigation is automatically disabled for carousel when lightbox is open to prevent conflicts
  4. Ensure sufficient color contrast for text overlays
  5. Configure keyboard options via interaction.enableKeyboardNavigation and lightboxOptions.enableKeyboardNavigation if needed

🔧 Framework Integration

Next.js (App Router)

// app/components/ProductCarousel.tsx
"use client"; // Required for client-side interactivity

import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

export function ProductCarousel({ items }) {
  return <CarouselCircular items={items} />;
}

Next.js (Pages Router)

// pages/index.tsx
import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

export default function Home() {
  return <CarouselCircular items={items} />;
}

Vite + React

// src/App.tsx
import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

export default function App() {
  return <CarouselCircular items={items} />;
}

Create React App

// src/App.js
import { CarouselCircular } from "@ddevkim/carousel-circular-3d";
import "@ddevkim/carousel-circular-3d/dist/index.css";

function App() {
  return <CarouselCircular items={items} />;
}

❓ Troubleshooting

Styles Not Showing

Problem: Carousel renders but has no styles (buttons missing, layout broken)

Solution: Make sure you import the CSS file:

import "@ddevkim/carousel-circular-3d/dist/index.css"; // ← Don't forget this!

Alternative imports that work:

// Option 1: Direct path (recommended)
import "@ddevkim/carousel-circular-3d/dist/index.css";

// Option 2: Using styles export
import "@ddevkim/carousel-circular-3d/styles";

TypeScript Errors

Problem: Type errors when using the component

Solution: The package includes TypeScript definitions. Make sure your tsconfig.json includes:

{
  "compilerOptions": {
    "moduleResolution": "bundler", // or "node"
    "esModuleInterop": true
  }
}

Images Not Loading

Problem: Images show broken icon or don't load

Solution:

  1. Check image paths: Ensure paths are correct relative to your public folder
  2. Use absolute URLs: Try using full URLs: https://example.com/image.jpg
  3. Verify CORS: If using external images, ensure CORS headers are set
// ✅ Good - relative to public folder
{ id: 1, image: "/images/product.jpg" }

// ✅ Good - absolute URL
{ id: 1, image: "https://cdn.example.com/product.jpg" }

// ❌ Bad - relative to component file
{ id: 1, image: "../assets/product.jpg" }

Performance Issues

Problem: Carousel feels laggy or slow

Solutions:

  1. Reduce item count: Keep items under 30
  2. Optimize images: Use WebP format and compress
  3. Add LQIP: Use progressive loading
  4. Check radius: Very large radius (>2000px) may impact performance
// ✅ Optimized
<CarouselCircular
  items={items.slice(0, 20)} // Limit items
  geometry={{ radius: 900 }} // Reasonable radius
/>

Lightbox Not Opening

Problem: Click on image but lightbox doesn't open

Solution: Make sure enableLightboxWhenClick is set to true:

<CarouselCircular
  items={items}
  enableLightboxWhenClick={true} // ← Required for lightbox
/>

Auto-Rotation Not Working

Problem: Carousel doesn't auto-rotate

Solution: Check your config:

<CarouselCircular
  items={items}
  autoRotateConfig={{
    enabled: true, // ← Must be true
    speed: 0.1,
  }}
/>

Keyboard Navigation Issues

Problem: Arrow keys don't work

Solutions:

  1. Carousel navigation: Ensure interaction.enableKeyboardNavigation is true (default)
  2. Lightbox navigation: Check lightboxOptions.enableKeyboardNavigation is true (default)
  3. Focus state: Carousel container must be focused (click on it first)
<CarouselCircular
  items={items}
  interaction={{
    enableKeyboardNavigation: true, // Carousel arrow keys
  }}
  lightboxOptions={{
    enableKeyboardNavigation: true, // Lightbox arrow keys
    closeOnEsc: true, // ESC to close
  }}
/>

🏗️ Architecture

Key Features

  • GPU-Accelerated: Uses CSS transform and will-change for 60fps animations
  • Physics-Based: Realistic momentum with configurable friction
  • Orientation Detection: Automatically calculates item sizes based on image dimensions
  • Smart Angle Distribution: Even spacing regardless of portrait/landscape mix
  • RAF-Based: All animations use requestAnimationFrame for smooth performance

💡 FAQ

Can I use this with TypeScript?

Yes! The package includes full TypeScript definitions with IntelliSense support.

Does it work with Server-Side Rendering (SSR)?

Yes! It works with Next.js (both App Router and Pages Router), including SSR and SSG.

For Next.js App Router, use the "use client" directive in your component file.

How do I generate LQIP data?

You can use any LQIP generation tool. Here are popular options:

  • sqip - SVG-based LQIP generator
  • lqip-modern - Modern LQIP with multiple algorithms
  • plaiceholder - Next.js-friendly LQIP generator
  • ImageMagick - Create base64 thumbnails with blur

Example with ImageMagick:

convert input.jpg -resize 20x -quality 30 -blur 0x1 output.webp
base64 output.webp

Can I customize the lightbox appearance?

The lightbox uses minimal inline styles. You can customize it by overriding CSS classes or using className props.

What's the browser support?

Modern browsers (Chrome, Firefox, Safari, Edge) with CSS3 transforms support. IE11 is not supported.

How many items can I display?

We recommend keeping items under 30 for optimal performance. The component can handle more, but performance may degrade on lower-end devices.

Can I use videos instead of images?

Currently, the component is optimized for images. For videos, use the content prop with a custom video player component.

🤝 Contributing

We welcome contributions from the community! Whether it's bug reports, feature requests, or code contributions, we appreciate your help in making this library better.

Ways to Contribute

Quick Start for Contributors

# Fork and clone the repository
git clone https://github.com/YOUR_USERNAME/carousel-circular-3d.git
cd carousel-circular-3d

# Install dependencies
pnpm install

# Start development
pnpm dev

# Run tests
pnpm lint && pnpm type-check && pnpm build

For detailed guidelines, please read our Contributing Guide and Code of Conduct.

Community Guidelines

  • Be respectful and inclusive
  • Provide constructive feedback
  • Help others when you can
  • Follow our Code of Conduct

📄 License

MIT © ddevkim

🙏 Acknowledgments

Built with:

  • React 18+ for modern UI
  • TypeScript for type safety
  • tsup for blazing-fast builds
  • Turbo for monorepo management

📬 Contact

Have questions or need support?


Made with ❤️ by ddevkim

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages