{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "modern-loader",
  "type": "registry:ui",
  "title": "Modern Loader",
  "description": "A modern, dynamic code loader designed for AI-powered coding environments.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": ["@scrollxui/typeanimation"],
  "dependencies": ["motion", "react-type-animation", "clsx", "tailwind-merge"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/modern-loader.tsx",
      "content": "'use client';\nimport React, {\n  useState,\n  useEffect,\n  useRef,\n  useCallback,\n  useMemo,\n} from 'react';\nimport { motion, AnimatePresence } from 'motion/react';\nimport { cn } from '@/lib/utils';\nimport TypeAnimation from '@/components/ui/typeanimation';\n\ninterface ModernLoaderProps {\n  words?: string[];\n}\n\nconst ModernLoader: React.FC<ModernLoaderProps> = ({\n  words = [\n    'Setting things up...',\n    'Initializing modules...',\n    'Almost ready...',\n  ],\n}) => {\n  const [currentLine, setCurrentLine] = useState(0);\n  const [cursorVisible, setCursorVisible] = useState(true);\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  const colors = useMemo(\n    () => [\n      'bg-gray-500',\n      'bg-teal-500',\n      'bg-blue-500',\n      'bg-gray-600',\n      'bg-pink-500',\n    ],\n    [],\n  );\n  const BUFFER = 20;\n  const MAX_LINES = 100;\n\n  const generateLines = useCallback(\n    (count = 20) =>\n      Array.from({ length: count }, (_, idx) => ({\n        id: Date.now() + idx,\n        segments: Array.from(\n          { length: Math.floor(Math.random() * 4) + 1 },\n          () => ({\n            width: `${Math.floor(Math.random() * 80) + 50}px`,\n            color: colors[Math.floor(Math.random() * colors.length)],\n            isCircle: Math.random() > 0.93,\n            indent: Math.random() > 0.7 ? 1 : 0,\n          }),\n        ),\n      })),\n    [colors],\n  );\n\n  const [lines, setLines] = useState(() => generateLines());\n\n  const getVisibleRange = () => {\n    const start = Math.max(0, currentLine - BUFFER);\n    const end = Math.min(lines.length, currentLine + BUFFER);\n    return { start, end };\n  };\n\n  const { start: visibleStart, end: visibleEnd } = getVisibleRange();\n\n  useEffect(() => {\n    if (containerRef.current) {\n      containerRef.current.scrollTop = containerRef.current.scrollHeight;\n    }\n  }, [currentLine]);\n\n  useEffect(() => {\n    const timer = setTimeout(() => {\n      setCurrentLine((prev) => {\n        const nextLine = prev + 1;\n        if (nextLine >= lines.length - 10)\n          setLines((old) => [...old, ...generateLines(50)]);\n        return nextLine;\n      });\n    }, 200);\n    return () => clearTimeout(timer);\n  }, [currentLine, lines.length, generateLines]);\n\n  useEffect(() => {\n    const interval = setInterval(() => setCursorVisible((prev) => !prev), 530);\n    return () => clearInterval(interval);\n  }, []);\n\n  useEffect(() => {\n    const cleanup = () => {\n      if (lines.length > MAX_LINES && currentLine > BUFFER * 2) {\n        setLines((oldLines) => {\n          const safeIndex = currentLine - BUFFER * 2;\n          if (safeIndex > 0) {\n            setCurrentLine((prev) => prev - safeIndex);\n            return oldLines.slice(safeIndex);\n          }\n          return oldLines;\n        });\n      }\n    };\n    const interval = setInterval(cleanup, 5000);\n    return () => clearInterval(interval);\n  }, [currentLine, lines.length]);\n\n  const visibleLines = lines.slice(visibleStart, visibleEnd);\n\n  return (\n    <div className='w-full max-w-md mx-auto p-8'>\n      <motion.div\n        initial={{ opacity: 0, scale: 0.95 }}\n        animate={{ opacity: 1, scale: 1 }}\n        transition={{ duration: 0.3 }}\n        className='relative bg-background h-75 rounded-2xl shadow-2xl overflow-hidden border border-border'\n      >\n        <div className='px-4 py-3 flex items-center z-10 relative'>\n          <div className='flex items-center gap-1.5'>\n            <motion.div className='w-2 xs:w-2.5 sm:w-3 h-2 xs:h-2.5 sm:h-3 rounded-full bg-red-500' />\n            <motion.div className='w-2 xs:w-2.5 sm:w-3 h-2 xs:h-2.5 sm:h-3 rounded-full bg-yellow-500' />\n            <motion.div className='w-2 xs:w-2.5 sm:w-3 h-2 xs:h-2.5 sm:h-3 rounded-full bg-green-500' />\n          </div>\n\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            transition={{ delay: 0.2 }}\n            className='flex-1 text-center'\n          >\n            <TypeAnimation\n              words={words}\n              typingSpeed='slow'\n              deletingSpeed='slow'\n              pauseDuration={2000}\n              className='text-muted-foreground text-xs font-mono'\n            />\n          </motion.div>\n        </div>\n\n        <div\n          ref={containerRef}\n          className='relative px-5 py-4 font-mono text-sm overflow-y-hidden h-[calc(100%-48px)]'\n        >\n          <div className='space-y-2 relative z-10'>\n            <AnimatePresence mode='sync'>\n              {visibleLines.map((line, idx) => {\n                const actualIndex = visibleStart + idx;\n                if (actualIndex >= currentLine) return null;\n                const extraMargin = (idx + 1) % 4 === 0 ? 'mt-2' : '';\n                const paddingClass = line.segments[0]?.indent ? 'pl-4' : '';\n                return (\n                  <React.Fragment key={line.id}>\n                    <motion.div\n                      className={cn(\n                        'flex items-center gap-2 h-5',\n                        extraMargin,\n                        paddingClass,\n                      )}\n                      initial={{ opacity: 0, x: -5 }}\n                      animate={{ opacity: 1, x: 0 }}\n                      exit={{ opacity: 0 }}\n                      transition={{ duration: 0.2, ease: 'easeOut' }}\n                    >\n                      {line.segments.map((seg, i) =>\n                        seg.isCircle ? (\n                          <motion.div\n                            key={i}\n                            initial={{ scale: 0 }}\n                            animate={{ scale: 1 }}\n                            transition={{ duration: 0.2, delay: 0.05 }}\n                            className={cn(\n                              'w-4 h-4 rounded-full opacity-50',\n                              seg.color,\n                            )}\n                          />\n                        ) : (\n                          <motion.div\n                            key={i}\n                            initial={{ width: 0 }}\n                            animate={{ width: seg.width }}\n                            transition={{ duration: 0.25, ease: 'easeOut' }}\n                            className={cn(\n                              'h-3 rounded-sm opacity-50',\n                              seg.color,\n                            )}\n                            style={{ width: seg.width }}\n                          />\n                        ),\n                      )}\n                    </motion.div>\n\n                    {(actualIndex + 1) % 6 === 0 && (\n                      <motion.div\n                        className='w-full h-1 bg-background rounded-sm opacity-30'\n                        initial={{ opacity: 0 }}\n                        animate={{ opacity: 1 }}\n                        exit={{ opacity: 0 }}\n                        transition={{ duration: 0.3 }}\n                      />\n                    )}\n                  </React.Fragment>\n                );\n              })}\n            </AnimatePresence>\n\n            {currentLine < lines.length && (\n              <motion.div\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                className='flex items-center h-5'\n                style={{\n                  paddingLeft: `${\n                    lines[currentLine]?.segments[0]?.indent ? 16 : 0\n                  }px`,\n                }}\n              >\n                <motion.div\n                  animate={{ opacity: cursorVisible ? 1 : 0 }}\n                  transition={{ duration: 0.1 }}\n                  className='w-0.5 h-3.5 bg-blue-500'\n                />\n              </motion.div>\n            )}\n          </div>\n        </div>\n      </motion.div>\n    </div>\n  );\n};\n\nexport default ModernLoader;\n"
    },
    {
      "type": "registry:ui",
      "path": "components/ui/typeanimation.tsx",
      "content": "'use client';\n\nimport { motion } from 'motion/react';\nimport { TypeAnimation } from 'react-type-animation';\nimport { cn } from '@/lib/utils';\nimport { ComponentProps } from 'react';\n\ntype LibrarySpeedType = ComponentProps<typeof TypeAnimation>['speed'];\n\ntype SpeedType = number | 'slow' | 'normal' | 'fast';\n\ninterface TypeanimationProps {\n  words?: string[];\n  className?: string;\n  typingSpeed?: SpeedType;\n  deletingSpeed?: SpeedType;\n  pauseDuration?: number;\n  gradientFrom?: string;\n  gradientTo?: string;\n}\n\nconst Typeanimation = ({\n  words = [' existence', ' reality', ' the Internet'],\n  className,\n  typingSpeed = 50,\n  deletingSpeed = 50,\n  pauseDuration = 1000,\n  gradientFrom = 'blue-500',\n  gradientTo = 'purple-600',\n}: TypeanimationProps) => {\n  const sequence = words.flatMap((word) => [word, pauseDuration]);\n\n  return (\n    <motion.span\n      className={cn(\n        `bg-clip-text text-transparent bg-linear-to-r from-${gradientFrom} to-${gradientTo}`,\n        className,\n      )}\n      initial={{ opacity: 0 }}\n      animate={{ opacity: 1 }}\n      transition={{ duration: 1 }}\n    >\n      <TypeAnimation\n        sequence={sequence}\n        wrapper='span'\n        repeat={Infinity}\n        className=''\n        speed={typingSpeed as LibrarySpeedType}\n        deletionSpeed={deletingSpeed as LibrarySpeedType}\n      />\n    </motion.span>\n  );\n};\n\nexport default Typeanimation;\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
