{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "math-curve-loader",
  "title": "Math Curve Loader",
  "description": "Animated mathematical curve loader with neubrutalism aesthetics — 8 curve variants including rose, lissajous, butterfly, and more",
  "dependencies": [
    "class-variance-authority"
  ],
  "registryDependencies": [
    "@boldkit/utils",
    "@boldkit/math-curves",
    "@boldkit/error-boundary"
  ],
  "files": [
    {
      "path": "registry/default/ui/math-curve-loader.tsx",
      "content": "/* eslint-disable react-refresh/only-export-components */\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { ErrorBoundary } from '@/components/ErrorBoundary'\nimport {\n  buildPath,\n  getPoint,\n  getAngle,\n  getDetailScale,\n  getCurvePulseDuration,\n  type LoaderCurveKey,\n} from '@/lib/math-curves'\n\nconst mathCurveLoaderVariants = cva('', {\n  variants: {\n    size: {\n      xs: 'w-6 h-6',\n      sm: 'w-8 h-8',\n      md: 'w-12 h-12',\n      lg: 'w-16 h-16',\n      xl: 'w-24 h-24',\n    },\n  },\n  defaultVariants: {\n    size: 'md',\n  },\n})\n\nconst SPEED_DURATION: Record<string, number> = {\n  slow: 9000,\n  normal: 5500,\n  fast: 3000,\n}\n\nexport interface MathCurveLoaderProps\n  extends React.SVGAttributes<SVGSVGElement>,\n    VariantProps<typeof mathCurveLoaderVariants> {\n  curve?: LoaderCurveKey\n  speed?: 'slow' | 'normal' | 'fast'\n  trackColor?: string\n  headColor?: string\n  strokeWidth?: number\n  headSize?: number\n}\n\nconst MathCurveLoader = React.forwardRef<SVGSVGElement, MathCurveLoaderProps>(\n  (\n    {\n      className,\n      size,\n      curve = 'rose',\n      speed = 'normal',\n      trackColor,\n      headColor,\n      strokeWidth = 4,\n      headSize = 8,\n      'aria-label': ariaLabel = 'Loading',\n      ...props\n    },\n    ref\n  ) => {\n    const pathRef = React.useRef<SVGPathElement>(null)\n    const rectRef = React.useRef<SVGRectElement>(null)\n    const rafRef = React.useRef<number>(0)\n    const startTimeRef = React.useRef<number>(performance.now())\n\n    const durationMs = SPEED_DURATION[speed] ?? SPEED_DURATION.normal\n\n    // Rebuild static track path when curve changes\n    const trackPath = React.useMemo(() => buildPath(curve, 1.0), [curve])\n\n    React.useEffect(() => {\n      startTimeRef.current = performance.now()\n\n      const tick = () => {\n        const now = performance.now()\n        const elapsed = (now - startTimeRef.current) % durationMs\n        const progress = elapsed / durationMs\n        const detailScale = getDetailScale(now, getCurvePulseDuration(curve))\n\n        const { x, y } = getPoint(curve, progress, detailScale)\n        const angle = getAngle(curve, progress, detailScale)\n\n        // Update track path with breathing detail scale\n        if (pathRef.current) {\n          pathRef.current.setAttribute('d', buildPath(curve, detailScale))\n        }\n\n        // Update head rect position and rotation\n        if (rectRef.current) {\n          const cx = x\n          const cy = y\n          rectRef.current.setAttribute('x', String(cx - headSize / 2))\n          rectRef.current.setAttribute('y', String(cy - headSize / 2))\n          rectRef.current.setAttribute('transform', `rotate(${angle} ${cx} ${cy})`)\n        }\n\n        rafRef.current = requestAnimationFrame(tick)\n      }\n\n      rafRef.current = requestAnimationFrame(tick)\n\n      return () => {\n        cancelAnimationFrame(rafRef.current)\n      }\n    }, [curve, speed, durationMs, headSize])\n\n    const resolvedTrackStroke = trackColor ?? 'currentColor'\n    const resolvedHeadFill = headColor ?? 'hsl(var(--primary))'\n\n    return (\n      <ErrorBoundary>\n        <svg\n          ref={ref}\n          viewBox=\"0 0 100 100\"\n          xmlns=\"http://www.w3.org/2000/svg\"\n          role=\"status\"\n          aria-label={ariaLabel}\n          className={cn(\n            mathCurveLoaderVariants({ size }),\n            'group',\n            className\n          )}\n          {...props}\n        >\n          {/* Track layer */}\n          <path\n            ref={pathRef}\n            d={trackPath}\n            fill=\"none\"\n            stroke={resolvedTrackStroke}\n            strokeWidth={strokeWidth}\n            strokeOpacity={0.2}\n            strokeLinecap=\"square\"\n            strokeLinejoin=\"miter\"\n            className=\"group-hover:[stroke-opacity:0.4] transition-[stroke-opacity] duration-200\"\n          />\n          {/* Head square */}\n          <rect\n            ref={rectRef}\n            width={headSize}\n            height={headSize}\n            x={50 - headSize / 2}\n            y={50 - headSize / 2}\n            fill={resolvedHeadFill}\n            stroke=\"currentColor\"\n            strokeWidth={1.5}\n          />\n        </svg>\n      </ErrorBoundary>\n    )\n  }\n)\nMathCurveLoader.displayName = 'MathCurveLoader'\n\nexport { MathCurveLoader, mathCurveLoaderVariants }\n",
      "type": "registry:ui",
      "target": "components/ui/math-curve-loader.tsx"
    }
  ],
  "type": "registry:ui"
}