Cursor ImageTrail
scrollxui/cursorimagetrailFreeComponent
The CursorImageTrail component creates an interactive mouse trail effect with animated images.
Live preview
live · rendered by the registry
Rendered by scrollxui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://scrollxui.dev/registry/cursorimagetrail.jsonSource
1'use client';23import React, { useRef, ReactNode, MouseEventHandler } from 'react';4import { motion, useAnimate } from 'motion/react';56interface CursorImageTrailProps {7 children: ReactNode;8 images: string[];9 renderImageBuffer: number;10 rotationRange: number;11 animationStyle?: 'dynamic' | 'minimal';12}1314const CursorImageTrail = ({15 children,16 images,17 renderImageBuffer,18 rotationRange,19 animationStyle = 'dynamic',20}: CursorImageTrailProps) => {21 const [scope, animate] = useAnimate();22 const lastRenderPosition = useRef({ x: 0, y: 0 });23 const imageRenderCount = useRef(0);2425 const calculateDistance = (26 x1: number,27 y1: number,28 x2: number,29 y2: number,30 ) => {31 const deltaX = x2 - x1;32 const deltaY = y2 - y1;33 return Math.sqrt(deltaX * deltaX + deltaY * deltaY);34 };3536 const renderNextImage = () => {37 const index = imageRenderCount.current % images.length;38 const selector = `[data-mouse-move-index="${index}"]`;39 const el = document.querySelector(selector) as HTMLElement;40 if (!el || !scope.current) return;4142 const containerRect = scope.current.getBoundingClientRect();43 const relativeX = lastRenderPosition.current.x - containerRect.left;44 const relativeY = lastRenderPosition.current.y - containerRect.top;4546 el.style.left = `${relativeX}px`;47 el.style.top = `${relativeY}px`;48 el.style.zIndex = `${imageRenderCount.current}`;4950 const rotation = Math.random() * rotationRange;5152 if (animationStyle === 'dynamic') {53 const scale = 0.8 + Math.random() * 0.4;54 const skewX = Math.random() * 10;55 const skewY = Math.random() * 10;5657 animate(58 selector,59 {60 opacity: [0, 1],61 transform: [62 `translate(-50%, -30%) scale(${scale}) rotate(${63 index % 2 === 0 ? rotation : -rotation64 }deg) skew(${skewX}deg, ${skewY}deg)`,65 `translate(-50%, -50%) scale(1.1) rotate(${66 index % 2 === 0 ? -rotation : rotation67 }deg) skew(0deg, 0deg)`,68 ],69 },70 { type: 'spring', stiffness: 150, damping: 20 },71 );7273 animate(74 selector,75 {76 opacity: [1, 0],77 y: ['0%', '-40%'],78 },79 {80 duration: 0.8,81 ease: 'easeOut',82 delay: 2,83 },84 );85 } else {86 animate(87 selector,88 {89 opacity: [0, 1],90 transform: [91// … truncated
What it pulls in
npm packages
Files it writes
More from scrollxui
All 180 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | scrollxui | Components | Free | 4 deps | |
| Alert Dialogalert-dialog | scrollxui | Components | Free | 7 deps | |
| Animated Buttonanimated-button | scrollxui | Components | Free | 4 deps | |
| Animated Tabsanimated-tabs | scrollxui | Components | Free | 1 dep | |
| Animated Testimonialsanimated-testimonials | scrollxui | Components | Free | 2 deps | |
| Animated TextGenerateanimated-textgenerate | scrollxui | Components | Free | 3 deps | |
| Announcementannouncement | scrollxui | Components | Free | 5 deps | |
| Aspect Ratioaspect-ratio | scrollxui | Components | Free | 1 dep |
