BlobCursor
react-bits/BlobCursor-TS-TWFreeComponent
Organic blob cursor that smoothly follows the pointer with inertia and elastic morphing.
Live preview
live · rendered by the registry
Rendered by @react-bits on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://www.reactbits.dev/r/BlobCursor-TS-TW.jsonSource
1'use client';23import React, { useRef, useEffect, useCallback } from 'react';4import gsap from 'gsap';56export interface BlobCursorProps {7 blobType?: 'circle' | 'square';8 fillColor?: string;9 trailCount?: number;10 sizes?: number[];11 innerSizes?: number[];12 innerColor?: string;13 opacities?: number[];14 shadowColor?: string;15 shadowBlur?: number;16 shadowOffsetX?: number;17 shadowOffsetY?: number;18 filterId?: string;19 filterStdDeviation?: number;20 filterColorMatrixValues?: string;21 useFilter?: boolean;22 fastDuration?: number;23 slowDuration?: number;24 fastEase?: string;25 slowEase?: string;26 zIndex?: number;27}2829export default function BlobCursor({30 blobType = 'circle',31 fillColor = '#5227FF',32 trailCount = 3,33 sizes = [60, 125, 75],34 innerSizes = [20, 35, 25],35 innerColor = 'rgba(255,255,255,0.8)',36 opacities = [0.6, 0.6, 0.6],37 shadowColor = 'rgba(0,0,0,0.75)',38 shadowBlur = 5,39 shadowOffsetX = 10,40 shadowOffsetY = 10,41 filterId = 'blob',42 filterStdDeviation = 30,43 filterColorMatrixValues = '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 35 -10',44 useFilter = true,45 fastDuration = 0.1,46 slowDuration = 0.5,47 fastEase = 'power3.out',48 slowEase = 'power1.out',49 zIndex = 10050}: BlobCursorProps) {51 const containerRef = useRef<HTMLDivElement>(null);52 const blobsRef = useRef<(HTMLDivElement | null)[]>([]);5354 const updateOffset = useCallback(() => {55 if (!containerRef.current) return { left: 0, top: 0 };56 const rect = containerRef.current.getBoundingClientRect();57 return { left: rect.left, top: rect.top };58 }, []);5960 const handleMove = useCallback(61 (e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>) => {62 const { left, top } = updateOffset();63 const x = 'clientX' in e ? e.clientX : e.touches[0].clientX;64 const y = 'clientY' in e ? e.clientY : e.touches[0].clientY;6566 blobsRef.current.forEach((el, i) => {67 if (!el) return;68 const isLead = i === 0;69 gsap.to(el, {70 x: x - left,71 y: y - top,72 duration: isLead ? fastDuration : slowDuration,73 ease: isLead ? fastEase : slowEase74 });75 });76 },77 [updateOffset, fastDuration, slowDuration, fastEase, slowEase]78 );7980 useEffect(() => {81 const onResize = () => updateOffset();82 window.addEventListener('resize', onResize);83 return () => window.removeEventListener('resize', onResize);84 }, [updateOffset]);8586 return (87 <div88 ref={containerRef}89// … truncated
What it pulls in
npm packages
Files it writes
More from @react-bits
All 556 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| AnimatedContentAnimatedContent-JS-CSS | @react-bits | Components | Free | 1 dep | |
| AnimatedContentAnimatedContent-JS-TW | @react-bits | Components | Free | 1 dep | |
| AnimatedContentAnimatedContent-TS-CSS | @react-bits | Components | Free | 1 dep | |
| AnimatedContentAnimatedContent-TS-TW | @react-bits | Components | Free | 1 dep | |
| AnimatedListAnimatedList-JS-CSS | @react-bits | Components | Free | 1 dep · 2 files | |
| AnimatedListAnimatedList-JS-TW | @react-bits | Components | Free | 1 dep | |
| AnimatedListAnimatedList-TS-CSS | @react-bits | Components | Free | 1 dep · 2 files | |
| AnimatedListAnimatedList-TS-TW | @react-bits | Components | Free | 1 dep |
