Claude Code Plugins

Community-maintained marketplace

Feedback

Use when implementing coverflow carousels with 3D rotation. Applies Swiper configuration patterns with rotation limits to prevent flipping.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name coverflow
description Use when implementing coverflow carousels with 3D rotation. Applies Swiper configuration patterns with rotation limits to prevent flipping.
version 2.0.0

Coverflow Effect (Swiper)

Swiper-based coverflow carousel with 3D rotation, click-to-center, and info overlays.

References:

Installation

npm install swiper
import Swiper from 'swiper';
import { EffectCoverflow, FreeMode, Keyboard, Mousewheel } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/effect-coverflow';

The Rotation Formula (CRITICAL)

Swiper calculates rotation as: rotate × distance_from_center

Problem: With rotate: 50 and a slide 4 positions away, rotation = 200°, causing the slide to flip backwards.

Solution: Limit slidesPerView and calculate safe rotation:

max_rotation = rotate × (slidesPerView - 1) / 2
slidesPerView rotate Max Rotation Safe?
5 20 40°
7 15 45°
5 45 90° ⚠️ Edge
'auto' 50 ✗ FLIPS

Rule: Keep max_rotation < 90° to prevent flipping.

Configuration

Core Options

new Swiper('.coverflow-swiper', {
  modules: [EffectCoverflow, FreeMode, Keyboard, Mousewheel],
  effect: 'coverflow',
  grabCursor: true,
  centeredSlides: true,
  slidesPerView: 5,  // Limit to control rotation
  slideToClickedSlide: true,

  coverflowEffect: {
    rotate: 20,      // Keep low with slidesPerView limit
    stretch: 0,      // px offset between slides
    depth: 100,      // z-axis depth
    modifier: 1,     // effect multiplier
    slideShadows: false,
  },
});

Official Swiper Defaults (Reference)

coverflowEffect: {
  rotate: 50,      // degrees per slide position
  stretch: 0,      // px offset between slides
  depth: 100,      // z-axis depth
  modifier: 1,     // effect multiplier
  slideShadows: true,
}

Scroll Handling

Smooth Scrolling with Snapping

freeMode: {
  enabled: true,
  sticky: true,  // Snap to slides after momentum
  momentumRatio: 0.5,
  momentumVelocityRatio: 0.5,
}

Detect Horizontal vs Vertical Intent

touchAngle: 30,  // Stricter than default 45
touchReleaseOnEdges: true,
passiveListeners: false,  // Allow preventDefault
mousewheel: {
  forceToAxis: true,
  releaseOnEdges: true,
}

Prevent Page Scroll While in Coverflow

The mousewheel/trackpad can trigger both coverflow scroll AND page scroll simultaneously. Add a custom handler:

let wheelHandler: ((e: WheelEvent) => void) | null = null;

function initCoverflow() {
  const container = document.querySelector<HTMLElement>('.coverflow-swiper');
  if (!container) return;

  const swiper = new Swiper('.coverflow-swiper', { /* config */ });

  // Prevent page scroll when scrolling within coverflow
  wheelHandler = (e: WheelEvent) => {
    const scrollingRight = e.deltaY > 0 || e.deltaX > 0;
    const scrollingLeft = e.deltaY < 0 || e.deltaX < 0;

    // Allow page scroll only at edges
    const allowPageScroll =
      (swiper.isBeginning && scrollingLeft) ||
      (swiper.isEnd && scrollingRight);

    if (!allowPageScroll) {
      e.preventDefault();
      e.stopPropagation();
    }
  };

  container.addEventListener('wheel', wheelHandler, { passive: false });
}

function destroyCoverflow() {
  if (wheelHandler) {
    const container = document.querySelector<HTMLElement>('.coverflow-swiper');
    container?.removeEventListener('wheel', wheelHandler);
    wheelHandler = null;
  }
  // ... destroy swiper
}

Complete Example

import Swiper from 'swiper';
import { EffectCoverflow, FreeMode, Keyboard, Mousewheel } from 'swiper/modules';
import 'swiper/css';
import 'swiper/css/effect-coverflow';

let swiperInstance: Swiper | null = null;
let wheelHandler: ((e: WheelEvent) => void) | null = null;

export function initCoverflow(): void {
  const container = document.querySelector<HTMLElement>('.coverflow-swiper');
  if (!container || swiperInstance) return;

  swiperInstance = new Swiper('.coverflow-swiper', {
    modules: [EffectCoverflow, FreeMode, Keyboard, Mousewheel],
    effect: 'coverflow',
    grabCursor: true,
    centeredSlides: true,
    slidesPerView: 5,
    slideToClickedSlide: true,
    touchAngle: 30,
    touchReleaseOnEdges: true,
    passiveListeners: false,
    keyboard: { enabled: true },
    mousewheel: {
      forceToAxis: true,
      releaseOnEdges: true,
    },
    freeMode: {
      enabled: true,
      sticky: true,
      momentumRatio: 0.5,
      momentumVelocityRatio: 0.5,
    },
    coverflowEffect: {
      rotate: 20,
      stretch: 0,
      depth: 100,
      modifier: 1,
      slideShadows: false,
    },
  });

  // Prevent page scroll
  wheelHandler = (e: WheelEvent) => {
    if (!swiperInstance) return;
    const scrollingRight = e.deltaY > 0 || e.deltaX > 0;
    const scrollingLeft = e.deltaY < 0 || e.deltaX < 0;
    const allowPageScroll =
      (swiperInstance.isBeginning && scrollingLeft) ||
      (swiperInstance.isEnd && scrollingRight);
    if (!allowPageScroll) {
      e.preventDefault();
      e.stopPropagation();
    }
  };
  container.addEventListener('wheel', wheelHandler, { passive: false });
}

export function destroyCoverflow(): void {
  if (wheelHandler) {
    const container = document.querySelector<HTMLElement>('.coverflow-swiper');
    container?.removeEventListener('wheel', wheelHandler);
    wheelHandler = null;
  }
  if (swiperInstance) {
    swiperInstance.destroy(true, true);
    swiperInstance = null;
  }
}

CSS: Contain 3D Overflow

The coverflow effect rotates slides in 3D space, which extends them beyond their container bounds. Without overflow containment, this creates page-level horizontal scrollbars.

.coverflow-wrapper {
  overflow-x: hidden;  /* Clip 3D rotated slides */
}

.coverflow-swiper {
  overflow: visible;   /* Allow slides to render outside for 3D effect */
}

Key insight: The inner .coverflow-swiper needs overflow: visible for the 3D transforms to render correctly, but the outer wrapper must clip them to prevent page scroll.

CSS: Active Slide Styling

Use .swiper-slide-active to style only the centered slide:

/* Info overlay - hidden by default */
.coverflow-item__info {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/* Only show on active/centered slide */
.swiper-slide-active .coverflow-item__info {
  opacity: 1;
  pointer-events: auto;
}

CSS: Reflection Effect

.coverflow-item img {
  -webkit-box-reflect: below 0.5em linear-gradient(
    transparent 60%,
    rgba(0, 0, 0, 0.3)
  );
}

Accessibility

Reduced Motion

@media (prefers-reduced-motion: reduce) {
  .swiper-slide {
    transition: none !important;
  }
}

Keyboard Navigation

Enabled via keyboard: { enabled: true } - arrow keys navigate slides.

Avoid

  • slidesPerView: 'auto' with high rotate - causes flipping on edge slides
  • rotate > 45 without limiting slidesPerView - same flipping issue
  • Forgetting wheel handler cleanup - causes memory leaks
  • Missing passiveListeners: false - prevents preventDefault() from working
  • Using scale in coverflowEffect - can cause weird sizing on distant slides
  • Missing overflow-x: hidden on wrapper - 3D rotated slides create page-level horizontal scrollbars