{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "BlobCursor-JS-CSS", "type": "registry:block", "title": "BlobCursor", "description": "Organic blob cursor that smoothly follows the pointer with inertia and elastic morphing.", "dependencies": [ "gsap" ], "files": [ { "path": "public/default/src/content/Animations/BlobCursor/BlobCursor.jsx", "content": "'use client';\r\n\r\nimport { useRef, useEffect, useCallback } from 'react';\r\nimport gsap from 'gsap';\r\nimport './BlobCursor.css';\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}) {\r\n const containerRef = useRef(null);\r\n const blobsRef = useRef([]);\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 => {\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 (blobsRef.current[i] = el)}\r\n className=\"blob\"\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" }, { "path": "public/default/src/content/Animations/BlobCursor/BlobCursor.css", "content": ".blob-container {\r\n position: relative;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n}\r\n\r\n.blob-main {\r\n pointer-events: none;\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n overflow: hidden;\r\n background: transparent;\r\n user-select: none;\r\n cursor: default;\r\n}\r\n\r\n.blob {\r\n position: absolute;\r\n will-change: transform;\r\n transform: translate(-50%, -50%);\r\n}\r\n\r\n.inner-dot {\r\n position: absolute;\r\n}\r\n", "type": "registry:item" } ] }