{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "BlobCursor-TS-TW", "type": "registry:block", "title": "BlobCursor", "description": "Organic blob cursor that smoothly follows the pointer with inertia and elastic morphing.", "dependencies": [ "gsap" ], "files": [ { "path": "public/ts/tailwind/src/ts-tailwind/Animations/BlobCursor/BlobCursor.tsx", "content": "'use client';\r\n\r\nimport React, { useRef, useEffect, useCallback } from 'react';\r\nimport gsap from 'gsap';\r\n\r\nexport interface BlobCursorProps {\r\n blobType?: 'circle' | 'square';\r\n fillColor?: string;\r\n trailCount?: number;\r\n sizes?: number[];\r\n innerSizes?: number[];\r\n innerColor?: string;\r\n opacities?: number[];\r\n shadowColor?: string;\r\n shadowBlur?: number;\r\n shadowOffsetX?: number;\r\n shadowOffsetY?: number;\r\n filterId?: string;\r\n filterStdDeviation?: number;\r\n filterColorMatrixValues?: string;\r\n useFilter?: boolean;\r\n fastDuration?: number;\r\n slowDuration?: number;\r\n fastEase?: string;\r\n slowEase?: string;\r\n zIndex?: number;\r\n}\r\n\r\nexport default function BlobCursor({\r\n blobType = 'circle',\r\n fillColor = '#5227FF',\r\n trailCount = 3,\r\n sizes = [60, 125, 75],\r\n innerSizes = [20, 35, 25],\r\n innerColor = 'rgba(255,255,255,0.8)',\r\n opacities = [0.6, 0.6, 0.6],\r\n shadowColor = 'rgba(0,0,0,0.75)',\r\n shadowBlur = 5,\r\n shadowOffsetX = 10,\r\n shadowOffsetY = 10,\r\n filterId = 'blob',\r\n filterStdDeviation = 30,\r\n filterColorMatrixValues = '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 35 -10',\r\n useFilter = true,\r\n fastDuration = 0.1,\r\n slowDuration = 0.5,\r\n fastEase = 'power3.out',\r\n slowEase = 'power1.out',\r\n zIndex = 100\r\n}: BlobCursorProps) {\r\n const containerRef = useRef(null);\r\n const blobsRef = useRef<(HTMLDivElement | null)[]>([]);\r\n\r\n const updateOffset = useCallback(() => {\r\n if (!containerRef.current) return { left: 0, top: 0 };\r\n const rect = containerRef.current.getBoundingClientRect();\r\n return { left: rect.left, top: rect.top };\r\n }, []);\r\n\r\n const handleMove = useCallback(\r\n (e: React.MouseEvent | React.TouchEvent) => {\r\n const { left, top } = updateOffset();\r\n const x = 'clientX' in e ? e.clientX : e.touches[0].clientX;\r\n const y = 'clientY' in e ? e.clientY : e.touches[0].clientY;\r\n\r\n blobsRef.current.forEach((el, i) => {\r\n if (!el) return;\r\n const isLead = i === 0;\r\n gsap.to(el, {\r\n x: x - left,\r\n y: y - top,\r\n duration: isLead ? fastDuration : slowDuration,\r\n ease: isLead ? fastEase : slowEase\r\n });\r\n });\r\n },\r\n [updateOffset, fastDuration, slowDuration, fastEase, slowEase]\r\n );\r\n\r\n useEffect(() => {\r\n const onResize = () => updateOffset();\r\n window.addEventListener('resize', onResize);\r\n return () => window.removeEventListener('resize', onResize);\r\n }, [updateOffset]);\r\n\r\n return (\r\n \r\n {useFilter && (\r\n \r\n \r\n \r\n \r\n \r\n \r\n )}\r\n\r\n \r\n {Array.from({ length: trailCount }).map((_, i) => (\r\n {\r\n blobsRef.current[i] = el;\r\n }}\r\n className=\"absolute will-change-transform transform -translate-x-1/2 -translate-y-1/2\"\r\n style={{\r\n width: sizes[i],\r\n height: sizes[i],\r\n borderRadius: blobType === 'circle' ? '50%' : '0',\r\n backgroundColor: fillColor,\r\n opacity: opacities[i],\r\n boxShadow: `${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px 0 ${shadowColor}`\r\n }}\r\n >\r\n \r\n \r\n ))}\r\n \r\n \r\n );\r\n}\r\n", "type": "registry:component" } ] }