{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "BlobCursor-JS-CSS", "title": "BlobCursor", "description": "Organic blob cursor that smoothly follows the pointer with inertia and elastic morphing.", "type": "registry:component", "files": [ { "type": "registry:component", "path": "BlobCursor/BlobCursor.css", "content": ".blob-container {\n position: relative;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.blob-main {\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: transparent;\n user-select: none;\n cursor: default;\n}\n\n.blob {\n position: absolute;\n will-change: transform;\n transform: translate(-50%, -50%);\n}\n\n.inner-dot {\n position: absolute;\n}\n" }, { "type": "registry:component", "path": "BlobCursor/BlobCursor.jsx", "content": "'use client';\n\nimport { useRef, useEffect, useCallback } from 'react';\nimport gsap from 'gsap';\nimport './BlobCursor.css';\n\nexport default function BlobCursor({\n blobType = 'circle',\n fillColor = '#5227FF',\n trailCount = 3,\n sizes = [60, 125, 75],\n innerSizes = [20, 35, 25],\n innerColor = 'rgba(255,255,255,0.8)',\n opacities = [0.6, 0.6, 0.6],\n shadowColor = 'rgba(0,0,0,0.75)',\n shadowBlur = 5,\n shadowOffsetX = 10,\n shadowOffsetY = 10,\n filterId = 'blob',\n filterStdDeviation = 30,\n filterColorMatrixValues = '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 35 -10',\n useFilter = true,\n fastDuration = 0.1,\n slowDuration = 0.5,\n fastEase = 'power3.out',\n slowEase = 'power1.out',\n zIndex = 100\n}) {\n const containerRef = useRef(null);\n const blobsRef = useRef([]);\n\n const updateOffset = useCallback(() => {\n if (!containerRef.current) return { left: 0, top: 0 };\n const rect = containerRef.current.getBoundingClientRect();\n return { left: rect.left, top: rect.top };\n }, []);\n\n const handleMove = useCallback(\n e => {\n const { left, top } = updateOffset();\n const x = 'clientX' in e ? e.clientX : e.touches[0].clientX;\n const y = 'clientY' in e ? e.clientY : e.touches[0].clientY;\n\n blobsRef.current.forEach((el, i) => {\n if (!el) return;\n const isLead = i === 0;\n gsap.to(el, {\n x: x - left,\n y: y - top,\n duration: isLead ? fastDuration : slowDuration,\n ease: isLead ? fastEase : slowEase\n });\n });\n },\n [updateOffset, fastDuration, slowDuration, fastEase, slowEase]\n );\n\n useEffect(() => {\n const onResize = () => updateOffset();\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, [updateOffset]);\n\n return (\n \n {useFilter && (\n \n \n \n \n \n \n )}\n\n
\n {Array.from({ length: trailCount }).map((_, i) => (\n (blobsRef.current[i] = el)}\n className=\"blob\"\n style={{\n width: sizes[i],\n height: sizes[i],\n borderRadius: blobType === 'circle' ? '50%' : '0%',\n backgroundColor: fillColor,\n opacity: opacities[i],\n boxShadow: `${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px 0 ${shadowColor}`\n }}\n >\n \n
\n ))}\n \n \n );\n}\n" } ], "registryDependencies": [], "dependencies": [ "gsap@^3.13.0" ] }