Floating Card
refinery/floating-cardFreeComponent
Card with 3D tilt, text-reveal and image focus effects on hover.
Live preview
live · rendered by the registry
Rendered by refinery on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://refinery.abhii.me/r/floating-card.jsonSource
1"use client";23import { motion, useMotionValue, useSpring, useTransform } from "motion/react";4import { cn } from "@/lib/utils";5import { useRef, useState } from "react";67const DEFAULT_CARD = {8 image:9 "https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=400&q=80",10 name: "Priya Nair",11 description: "Design Lead",12};1314const EASE: [number, number, number, number] = [0.22, 1, 0.36, 1];15const SPRING = { stiffness: 180, damping: 22, mass: 0.5 };1617type FloatingCardProps = {18 image?: string;19 name?: string;20 description?: string;21 index?: number;22 className?: string;23};2425export function FloatingCard({26 image = DEFAULT_CARD.image,27 name = DEFAULT_CARD.name,28 description = DEFAULT_CARD.description,29 index = 0,30 className,31}: FloatingCardProps) {32 const [hovered, setHovered] = useState(false);33 const cardRef = useRef<HTMLDivElement>(null);3435 const rawX = useMotionValue(0);36 const rawY = useMotionValue(0);37 const rotateX = useSpring(useTransform(rawY, [-0.5, 0.5], [6, -6]), SPRING);38 const rotateY = useSpring(useTransform(rawX, [-0.5, 0.5], [-6, 6]), SPRING);3940 const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {41 const rect = cardRef.current?.getBoundingClientRect();42 if (!rect) return;43 rawX.set((e.clientX - rect.left) / rect.width - 0.5);44 rawY.set((e.clientY - rect.top) / rect.height - 0.5);45 };4647 const handleMouseLeave = () => {48 rawX.set(0);49 rawY.set(0);50 setHovered(false);51 };5253 return (54 <motion.div55 ref={cardRef}56 onMouseMove={handleMouseMove}57 onMouseEnter={() => setHovered(true)}58 onMouseLeave={handleMouseLeave}59 style={{ rotateX, rotateY, transformPerspective: 900 }}60 initial={{ opacity: 0, y: 24 }}61 animate={{ opacity: 1, y: 0 }}62 transition={{ duration: 0.55, delay: index * 0.1, ease: EASE }}63 className={cn(64 "group relative h-88 w-72 overflow-hidden rounded-2xl border border-black/10 bg-neutral-100 font-sans shadow-[0_2px_12px_rgba(0,0,0,0.08)] select-none dark:border-white/10 dark:bg-neutral-900 dark:shadow-[0_2px_20px_rgba(0,0,0,0.45)]",65 className66 )}67 >68 <motion.img69 src={image}70 alt={name}71 animate={{ scale: hovered ? 1.06 : 1 }}72 transition={{ duration: 0.5, ease: EASE }}73 className="block h-full w-full object-cover md:grayscale-100 md:group-hover:grayscale-0"74 />7576 {/* Vignette (always visible, deepens on hover) */}77 <motion.div78// … truncated
What it pulls in
npm packages
Files it writes
More from refinery
All 16 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Analog Clock Screensaveranalog-clock-screensaver | refinery | Components | Free | 1 dep | |
| Avatar Circleavatar-circle | refinery | Components | Free | 1 dep | |
| DVD Screensaverdvd-screensaver | refinery | Components | Free | 1 dep | |
| Floating Navfloating-nav | refinery | Components | Free | 1 dep | |
| Glowy Buttonglowy-button | refinery | Components | Free | 1 dep | |
| Move To Topmove-to-top-button | refinery | Components | Free | 1 dep | |
| Notification Badgenotification-badge | refinery | Components | Free | 1 dep | |
| Sleeping Cat Screensaversleeping-cat-screensaver | refinery | Components | Free | 2 deps |
