wavyjs
Version:
Reusable React + TypeScript component and hooks library with Tailwind, Framer Motion, and GSAP.
1 lines • 212 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/hooks/Cursor.tsx","../src/hooks/Fetch.tsx","../src/hooks/Hover.tsx","../src/hooks/SessionTimeout.tsx","../src/hooks/SpeechSynthesis.tsx","../src/hooks/Toggle.tsx","../src/components/Button/Button.tsx","../src/components/Fading Patterns/FadingBG.tsx","../src/components/Fading Patterns/GithubBG.tsx","../src/components/Scrolling Patterns/NameScroller.tsx","../src/components/Moving Patterns/AnimatedBG.tsx","../src/components/Moving Patterns/MaskedBG.tsx","../src/components/Icons/ReactIcon.tsx","../src/components/Icons/JavaScriptIcon.tsx","../src/components/Icons/JavaIcon.tsx","../src/components/Icons/TailwindIcon.tsx","../src/components/Icons/HtmlIcon.tsx","../src/components/Icons/CSSIcon.tsx","../src/components/Icons/FlutterIcon.tsx","../src/components/Icons/PythonIcon.tsx","../src/components/Icons/GithubIcon.tsx","../src/components/Icons/DartIcon.tsx","../src/components/Card-Icons/ReactCardIcon.tsx","../src/components/Card-Icons/JavascriptCardIcon.tsx","../src/components/Card-Icons/JavaCardIcon.tsx","../src/components/Card-Icons/TailwindCardIcon.tsx","../src/components/Card-Icons/HtmlCardIcon.tsx","../src/components/Card-Icons/CSSCardIcon.tsx","../src/components/Card-Icons/FlutterCardIcon.tsx","../src/components/Card-Icons/PythonCardIcon.tsx","../src/components/Card-Icons/GithubCardIcon.tsx","../src/components/Card-Icons/DartCardIcon.tsx","../src/components/interactive Backgrounds/DotInteraction.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\r\n\r\nconst useCursor = () => {\r\n const [position, setPosition] = useState({ x: 0, y: 0 });\r\n\r\n useEffect(() => {\r\n const updatePosition = (e: MouseEvent) => {\r\n setPosition({ x: e.clientX, y: e.clientY });\r\n };\r\n\r\n window.addEventListener(\"mousemove\", updatePosition);\r\n return () => {\r\n window.removeEventListener(\"mousemove\", updatePosition);\r\n };\r\n }, []);\r\n\r\n return position;\r\n}\r\n\r\nexport { useCursor };\r\n","import { useEffect, useState } from \"react\";\r\n\r\nconst useFetch = (url: string) => {\r\n const [data, setData] = useState(null);\r\n const [loading, setLoading] = useState<boolean>(true);\r\n const [error, setError] = useState<unknown>(null);\r\n\r\n useEffect(() => {\r\n let isCancelled = false;\r\n\r\n async function fetchData() {\r\n try {\r\n setLoading(true);\r\n const response = await fetch(url);\r\n if (!response.ok) throw new Error(\"Failed to fetch\");\r\n const result = await response.json();\r\n if (!isCancelled) setData(result);\r\n } catch (err) {\r\n if (!isCancelled) setError(err);\r\n } finally {\r\n if (!isCancelled) setLoading(false);\r\n }\r\n }\r\n\r\n fetchData();\r\n\r\n return () => {\r\n isCancelled = true;\r\n };\r\n }, [url]);\r\n\r\n return { data, loading, error };\r\n}\r\n\r\nexport { useFetch };\r\n","import { useState } from \"react\";\r\n\r\nconst useHover = () => {\r\n const [isHovered, setIsHovered] = useState(false);\r\n\r\n const eventHandlers = {\r\n onMouseEnter: () => setIsHovered(true),\r\n onMouseLeave: () => setIsHovered(false),\r\n };\r\n\r\n return [isHovered, eventHandlers] as const;\r\n}\r\n\r\nexport { useHover };","import { useEffect, useRef } from \"react\";\r\n\r\ntype UseSessionTimeoutProps = {\r\n timeout: number; // In milliseconds\r\n onTimeout: () => void;\r\n warningTime?: number; // Optional warning before logout\r\n onWarning?: () => void;\r\n};\r\n\r\nexport function useSessionTimeout({\r\n timeout,\r\n onTimeout,\r\n warningTime = 0,\r\n onWarning,\r\n}: UseSessionTimeoutProps) {\r\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n const warningRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n\r\n const resetTimers = () => {\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n if (warningRef.current) clearTimeout(warningRef.current);\r\n\r\n if (warningTime > 0 && onWarning) {\r\n warningRef.current = setTimeout(onWarning, timeout - warningTime);\r\n }\r\n\r\n timeoutRef.current = setTimeout(onTimeout, timeout);\r\n };\r\n\r\n useEffect(() => {\r\n const events = [\"mousemove\", \"keydown\", \"click\", \"touchstart\"];\r\n\r\n const handleActivity = () => resetTimers();\r\n\r\n for (const event of events) {\r\n window.addEventListener(event, handleActivity);\r\n }\r\n\r\n resetTimers(); // Set initial timeout\r\n\r\n return () => {\r\n for (const event of events) {\r\n window.removeEventListener(event, handleActivity);\r\n }\r\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\r\n if (warningRef.current) clearTimeout(warningRef.current);\r\n };\r\n }, [timeout, onTimeout, warningTime, onWarning]);\r\n}\r\n","import { useCallback, useRef } from \"react\";\r\n\r\nconst useSpeechSynthesis = () => {\r\n const synth = window.speechSynthesis;\r\n const utteranceRef = useRef<SpeechSynthesisUtterance | null>(null);\r\n\r\n const speak = useCallback((text: string, options: Partial<SpeechSynthesisUtterance> = {}) => {\r\n if (!synth) return;\r\n\r\n // Cancel any ongoing speech\r\n synth.cancel();\r\n\r\n const utterance = new SpeechSynthesisUtterance(text);\r\n Object.assign(utterance, options); // pitch, rate, voice, etc.\r\n synth.speak(utterance);\r\n utteranceRef.current = utterance;\r\n }, [synth]);\r\n\r\n const stop = useCallback(() => {\r\n synth?.cancel();\r\n }, [synth]);\r\n\r\n return { speak, stop };\r\n}\r\n\r\nexport { useSpeechSynthesis };\r\n\r\n\r\n\r\n","import { useState, useCallback } from \"react\";\r\n\r\nfunction useToggle(initialValue = false) {\r\n const [value, setValue] = useState(initialValue);\r\n\r\n const toggle = useCallback(() => {\r\n setValue((prev) => !prev);\r\n }, []);\r\n\r\n return [value, toggle];\r\n}\r\n\r\nexport { useToggle };","import React from 'react';\r\nimport { motion, type HTMLMotionProps } from 'framer-motion';\r\n\r\ntype Variant = 'primary' | 'secondary' | 'ghost';\r\n\r\ntype BaseButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {\r\n variant?: Variant;\r\n asMotion?: false | undefined;\r\n};\r\n\r\ntype MotionButtonProps = Omit<HTMLMotionProps<'button'>, 'className' | 'ref'> & {\r\n className?: string;\r\n variant?: Variant;\r\n asMotion: true;\r\n};\r\n\r\nexport type ButtonProps = BaseButtonProps | MotionButtonProps;\r\n\r\nconst baseClass =\r\n 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background';\r\n\r\nconst variants: Record<NonNullable<ButtonProps['variant']>, string> = {\r\n primary:\r\n 'bg-blue-600 text-white hover:bg-blue-700 focus-visible:ring-blue-400 px-4 py-2',\r\n secondary:\r\n 'bg-slate-200 text-slate-900 hover:bg-slate-300 focus-visible:ring-slate-400 px-4 py-2',\r\n ghost:\r\n 'bg-transparent text-slate-900 hover:bg-slate-100 focus-visible:ring-slate-300 px-3 py-2',\r\n};\r\n\r\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {\r\n if (props.asMotion) {\r\n const { asMotion: _a, className = '', variant = 'primary', children, ...rest } = props;\r\n const classNames = `${baseClass} ${variants[variant]} ${className}`.trim();\r\n return (\r\n <motion.button\r\n ref={ref}\r\n className={classNames}\r\n whileTap={{ scale: 0.98 }}\r\n whileHover={{ y: -1 }}\r\n {...(rest as MotionButtonProps)}\r\n >\r\n {children}\r\n </motion.button>\r\n );\r\n }\r\n\r\n const { asMotion: _a2, className = '', variant = 'primary', children, ...rest } = props as BaseButtonProps;\r\n const classNames = `${baseClass} ${variants[variant]} ${className}`.trim();\r\n return (\r\n <button ref={ref} className={classNames} {...(rest as BaseButtonProps)}>\r\n {children}\r\n </button>\r\n );\r\n});\r\n\r\nButton.displayName = 'Button';\r\n\r\n\r\n","import gsap from 'gsap';\r\nimport React, { useEffect, useRef } from 'react';\r\n\r\nexport const FadingBG: React.FC = () => {\r\n const containerRef = useRef<HTMLDivElement | null>(null);\r\n\r\n // Grid configuration (kept internal for now)\r\n const numColumns = 18;\r\n const numRows = 16;\r\n const totalDots = numColumns * numRows;\r\n\r\n useEffect(() => {\r\n if (!containerRef.current) return;\r\n\r\n const context = gsap.context(() => {\r\n const timeline = gsap.timeline({ repeat: -1, repeatDelay: 0.6 });\r\n\r\n timeline.from('.box', {\r\n scale: 0,\r\n yoyo: true,\r\n repeat: 1,\r\n ease: 'power1.inOut',\r\n stagger: {\r\n amount: 1.5,\r\n grid: [numColumns, numRows],\r\n axis: 'x',\r\n ease: 'back.out(1.7)',\r\n from: 'center',\r\n },\r\n });\r\n\r\n timeline.to('.box', {\r\n yoyo: true,\r\n scale: 1,\r\n repeat: 1,\r\n ease: 'power1.inOut',\r\n stagger: {\r\n amount: 1.5,\r\n grid: [numColumns, numRows],\r\n axis: 'y',\r\n ease: 'back.out(1.7)',\r\n from: 'center',\r\n },\r\n });\r\n }, containerRef);\r\n\r\n return () => context.revert();\r\n }, [numColumns, numRows]);\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n \r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n zIndex: 0, // keep visible by default\r\n backgroundColor: 'black',\r\n overflow: 'hidden',\r\n pointerEvents: 'none',\r\n userSelect: 'none',\r\n }}\r\n >\r\n {/* <div\r\n style={{\r\n position: 'absolute',\r\n inset: 0,\r\n background: 'radial-gradient(circle at center, transparent 5%, black 100%)',\r\n }}\r\n /> */}\r\n <div\r\n style={{\r\n position: 'relative',\r\n width: '100%',\r\n height: '100%',\r\n display: 'grid',\r\n gridTemplateColumns: `repeat(${numColumns}, minmax(0, 1fr))`,\r\n gridTemplateRows: `repeat(${numRows}, minmax(0, 1fr))`,\r\n }}\r\n >\r\n {Array.from({ length: totalDots }).map((_, i) => (\r\n <div\r\n key={i}\r\n className=\"box\"\r\n style={{\r\n width: 2,\r\n height: 2,\r\n backgroundColor: 'rgba(255,255,255,0.5)',\r\n borderRadius: 9999,\r\n justifySelf: 'center',\r\n alignSelf: 'center',\r\n }}\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nFadingBG.displayName = 'FadingBG';\r\n\r\nexport default FadingBG;\r\n","import gsap from 'gsap';\r\nimport React, { useEffect, useRef, useState } from 'react';\r\n\r\nconst GithubBG: React.FC = () => {\r\n const [boxCount, setBoxCount] = useState(0);\r\n const boxRefs = useRef<Array<HTMLDivElement | null>>([]);\r\n\r\n useEffect(() => {\r\n function calculateBoxes() {\r\n if (!containerRef.current) return;\r\n\r\n const { clientWidth: width, clientHeight: height } = containerRef.current;\r\n const boxSize = 16;\r\n const cols = Math.floor(width / boxSize);\r\n const rows = Math.floor(height / boxSize);\r\n setBoxCount(cols * rows);\r\n }\r\n\r\n calculateBoxes();\r\n window.addEventListener('resize', calculateBoxes);\r\n return () => window.removeEventListener('resize', calculateBoxes);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (boxCount > 0) {\r\n const interval = setInterval(() => {\r\n const randomIndex = Math.floor(Math.random() * boxCount);\r\n const box = boxRefs.current[randomIndex];\r\n if (box) {\r\n gsap.fromTo(\r\n box,\r\n { opacity: 0.2 },\r\n { opacity: 1, duration: 0.3, yoyo: true, repeat: 1, ease: 'power1.inOut' }\r\n );\r\n }\r\n }, 100);\r\n return () => clearInterval(interval);\r\n }\r\n }, [boxCount]);\r\n\r\n const getRandomColor = () => {\r\n const colors = [\r\n 'rgba(0, 0, 0, 0.5)',\r\n 'rgba(155, 233, 168, 0.5)',\r\n 'rgba(64, 196, 99, 0.5)',\r\n 'rgba(48, 161, 78, 0.5)',\r\n 'rgba(33, 110, 57, 0.5)',\r\n ];\r\n return colors[Math.floor(Math.random() * colors.length)];\r\n };\r\n\r\n const containerRef = useRef<HTMLDivElement | null>(null);\r\n\r\n return (\r\n <div\r\n ref={containerRef}\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n backgroundColor: 'black',\r\n overflow: 'hidden',\r\n position: 'relative', // important so inner grid is relative to parent\r\n }}\r\n >\r\n <div\r\n style={{\r\n position: 'absolute',\r\n inset: 0,\r\n background: 'radial-gradient(circle at center, transparent 80%, black 100%)',\r\n pointerEvents: 'none',\r\n }}\r\n />\r\n <div\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(auto-fill, 16px)',\r\n gridAutoRows: '16px',\r\n gap: 8,\r\n padding: 24,\r\n alignContent: 'end',\r\n }}\r\n >\r\n {Array.from({ length: boxCount }).map((_, i) => (\r\n <div\r\n key={i}\r\n ref={(el) => (boxRefs.current[i] = el)}\r\n style={{\r\n width: 16,\r\n height: 16,\r\n backgroundColor: getRandomColor(),\r\n borderRadius: 6,\r\n }}\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nGithubBG.displayName = 'GithubBG';\r\nexport default GithubBG;\r\n","import React, { useEffect, useRef } from \"react\";\r\nimport gsap from \"gsap\";\r\n\r\nexport interface NameScrollerProps {\r\n title?: string;\r\n shadowSize?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\";\r\n shadowColor?: string;\r\n textColor?: string;\r\n numberOfRows?: number;\r\n baseDuration?: number;\r\n className?: string;\r\n}\r\n\r\nconst NameScroller: React.FC<NameScrollerProps> = ({\r\n title = \"WAVY JS\",\r\n shadowSize = \"lg\",\r\n shadowColor = \"white/80\",\r\n textColor = \"black/30\",\r\n numberOfRows = 6,\r\n baseDuration = 12,\r\n className = \"\"\r\n}) => {\r\n const rowRefs = useRef<HTMLDivElement[]>([]);\r\n\r\n // Helper function to parse color and opacity\r\n const parseColor = (colorString: string) => {\r\n if (colorString.includes('/')) {\r\n const [color, opacity] = colorString.split('/');\r\n return { color, opacity: parseFloat(opacity) / 100 };\r\n }\r\n return { color: colorString, opacity: 1 };\r\n };\r\n\r\n // Helper function to get shadow styles\r\n const getShadowStyles = (size: string, color: string) => {\r\n const { color: shadowColor, opacity } = parseColor(color);\r\n \r\n // Base shadow templates without opacity\r\n const shadowTemplates = {\r\n sm: '0 1px 2px 0',\r\n md: '0 4px 6px -1px',\r\n lg: '0 10px 15px -3px',\r\n xl: '0 20px 25px -5px',\r\n \"2xl\": '0 25px 50px -12px'\r\n };\r\n\r\n // Convert common color names to RGB values\r\n const colorMap: Record<string, string> = {\r\n 'black': '0, 0, 0',\r\n 'white': '255, 255, 255',\r\n 'red': '239, 68, 68',\r\n 'blue': '59, 130, 246',\r\n 'green': '34, 197, 94',\r\n 'yellow': '234, 179, 8',\r\n 'purple': '147, 51, 234',\r\n 'pink': '236, 72, 153',\r\n 'gray': '107, 114, 128',\r\n 'indigo': '99, 102, 241',\r\n 'teal': '20, 184, 166',\r\n 'orange': '249, 115, 22',\r\n 'cyan': '6, 182, 212',\r\n 'lime': '132, 204, 22',\r\n 'emerald': '16, 185, 129',\r\n 'amber': '245, 158, 11',\r\n 'rose': '244, 63, 94',\r\n 'violet': '139, 92, 246',\r\n 'fuchsia': '217, 70, 239',\r\n 'sky': '14, 165, 233',\r\n 'slate': '100, 116, 139',\r\n 'zinc': '113, 113, 122',\r\n 'neutral': '115, 115, 115',\r\n 'stone': '120, 113, 108'\r\n };\r\n\r\n // Get the base shadow template\r\n const shadowTemplate = shadowTemplates[size as keyof typeof shadowTemplates];\r\n \r\n let finalColor = '0, 0, 0'; // Default to black\r\n \r\n // Handle Tailwind color scale (e.g., blue-600)\r\n if (shadowColor.includes('-')) {\r\n const [colorName, scale] = shadowColor.split('-');\r\n const baseColor = colorMap[colorName];\r\n if (baseColor) {\r\n finalColor = baseColor;\r\n }\r\n }\r\n // Handle basic color names\r\n else if (colorMap[shadowColor]) {\r\n finalColor = colorMap[shadowColor];\r\n }\r\n // If it's a hex color, convert to RGB\r\n else if (shadowColor.startsWith('#')) {\r\n const hex = shadowColor.replace('#', '');\r\n const r = parseInt(hex.substr(0, 2), 16);\r\n const g = parseInt(hex.substr(2, 2), 16);\r\n const b = parseInt(hex.substr(4, 2), 16);\r\n finalColor = `${r}, ${g}, ${b}`;\r\n }\r\n // If it's already an RGB format, extract the values\r\n else if (shadowColor.startsWith('rgb')) {\r\n finalColor = shadowColor.replace('rgb', '').replace('rgba', '').replace('(', '').replace(')', '');\r\n }\r\n\r\n // Return the final shadow with the correct color and opacity\r\n return `${shadowTemplate} rgba(${finalColor}, ${opacity})`;\r\n };\r\n\r\n // Helper function to get text color with opacity support\r\n const getTextColor = (colorString: string) => {\r\n const { color, opacity } = parseColor(colorString);\r\n \r\n const colorMap: Record<string, string> = {\r\n 'black': '0, 0, 0',\r\n 'white': '255, 255, 255',\r\n 'red': '239, 68, 68',\r\n 'blue': '59, 130, 246',\r\n 'green': '34, 197, 94',\r\n 'yellow': '234, 179, 8',\r\n 'purple': '147, 51, 234',\r\n 'pink': '236, 72, 153',\r\n 'gray': '107, 114, 128',\r\n 'indigo': '99, 102, 241',\r\n 'teal': '20, 184, 166',\r\n 'orange': '249, 115, 22',\r\n 'cyan': '6, 182, 212',\r\n 'lime': '132, 204, 22',\r\n 'emerald': '16, 185, 129',\r\n 'amber': '245, 158, 11',\r\n 'rose': '244, 63, 94',\r\n 'violet': '139, 92, 246',\r\n 'fuchsia': '217, 70, 239',\r\n 'sky': '14, 165, 233',\r\n 'slate': '100, 116, 139',\r\n 'zinc': '113, 113, 122',\r\n 'neutral': '115, 115, 115',\r\n 'stone': '120, 113, 108'\r\n };\r\n\r\n // Handle Tailwind color scale (e.g., blue-600)\r\n if (color.includes('-')) {\r\n const [colorName, scale] = color.split('-');\r\n const baseColor = colorMap[colorName];\r\n if (baseColor) {\r\n // For now, return the base color. You can expand this for more accurate scaling\r\n return `rgba(${baseColor}, ${opacity})`;\r\n }\r\n }\r\n\r\n // Handle basic color names\r\n if (colorMap[color]) {\r\n return `rgba(${colorMap[color]}, ${opacity})`;\r\n }\r\n\r\n // If it's a hex color, convert to RGBA\r\n if (color.startsWith('#')) {\r\n const hex = color.replace('#', '');\r\n const r = parseInt(hex.substr(0, 2), 16);\r\n const g = parseInt(hex.substr(2, 2), 16);\r\n const b = parseInt(hex.substr(4, 2), 16);\r\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\r\n }\r\n\r\n // If it's already an RGB/RGBA format, return as is\r\n if (color.startsWith('rgb')) {\r\n return color;\r\n }\r\n\r\n // Default fallback\r\n return color;\r\n };\r\n\r\n useEffect(() => {\r\n rowRefs.current.forEach((row, index) => {\r\n if (!row) return;\r\n\r\n const totalWidth = row.scrollWidth / 2;\r\n const isEvenRow = index % 2 === 0;\r\n \r\n // Alternate speeds: even rows are faster, odd rows are slower\r\n const duration = isEvenRow ? baseDuration : baseDuration * 1.8;\r\n\r\n // All rows move to the left (right to left)\r\n gsap.fromTo(row,\r\n { x: 0 },\r\n {\r\n x: -totalWidth,\r\n duration: duration,\r\n ease: \"linear\",\r\n repeat: -1,\r\n modifiers: {\r\n x: (x) => {\r\n const num = parseFloat(x);\r\n return `${((num % -totalWidth) - totalWidth) % -totalWidth}px`;\r\n },\r\n },\r\n }\r\n );\r\n });\r\n }, [baseDuration]);\r\n\r\n const textSet = Array.from({ length: 8 }).map((_, idx) => (\r\n <h1 \r\n key={idx} \r\n className=\"text-8xl md:text-9xl font-bold mx-6 md:mx-8 whitespace-nowrap\"\r\n style={{\r\n color: getTextColor(textColor),\r\n textShadow: getShadowStyles(shadowSize, shadowColor)\r\n }}\r\n >\r\n {title}\r\n </h1>\r\n ));\r\n\r\n const rows = Array.from({ length: numberOfRows }).map((_, rowIndex) => (\r\n <div\r\n key={rowIndex}\r\n ref={(el) => {\r\n if (el) rowRefs.current[rowIndex] = el;\r\n }}\r\n className=\"flex whitespace-nowrap\"\r\n style={{ willChange: \"transform\" }}\r\n >\r\n {textSet}\r\n {textSet} {/* Duplicate for seamless loop */}\r\n </div>\r\n ));\r\n\r\n return (\r\n <div\r\n className={className}\r\n aria-hidden\r\n style={{\r\n position: 'fixed',\r\n inset: 0,\r\n zIndex: 0,\r\n backgroundColor: 'black',\r\n overflow: 'hidden',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n justifyContent: 'center',\r\n gap: 24,\r\n pointerEvents: 'none',\r\n userSelect: 'none',\r\n }}\r\n >\r\n {rows}\r\n </div>\r\n );\r\n};\r\n\r\nNameScroller.displayName = 'NameScroller';\r\n\r\nexport default NameScroller;\r\n","\r\nimport gsap from 'gsap'\r\nimport React, { useEffect } from 'react'\r\n\r\nexport const AnimatedBG: React.FC = () => {\r\n useEffect(() => {\r\n const randomX = gsap.utils.random(100, 100)\r\n const randomY = gsap.utils.random(100, 100)\r\n gsap.to('.green', {\r\n x: randomX,\r\n y: randomY,\r\n scale: 1,\r\n opacity: 1,\r\n duration: gsap.utils.random(2, 10), // slow speed\r\n repeat: -1,\r\n yoyo: true,\r\n ease: 'power1.inOut'\r\n });\r\n gsap.to('.red', {\r\n x: randomX,\r\n y: randomY,\r\n scale: 1,\r\n opacity: 1,\r\n duration: gsap.utils.random(2, 8), // slow speed\r\n repeat: -1,\r\n yoyo: true,\r\n ease: 'power1.inOut'\r\n });\r\n gsap.to('.pink', {\r\n x: randomX,\r\n y: randomY,\r\n scale: 1,\r\n opacity: 1,\r\n duration: gsap.utils.random(2, 4), // slow speed\r\n repeat: -1,\r\n yoyo: true,\r\n ease: 'power1.inOut'\r\n });\r\n }, [])\r\n \r\n return (\r\n <div\r\n aria-hidden\r\n style={{\r\n height: '100%',\r\n width:'100%',\r\n zIndex: 0,\r\n backgroundColor: 'black',\r\n overflow: 'hidden',\r\n pointerEvents: 'none',\r\n userSelect: 'none',\r\n }}\r\n >\r\n <div style={{ position: 'relative', width: '100%', height: '100%' }}>\r\n <div\r\n className=\"green\"\r\n style={{\r\n position: 'absolute',\r\n backgroundColor: 'rgba(34, 197, 94, 0.4)',\r\n borderRadius: 9999,\r\n width: 128,\r\n height: 128,\r\n left: '10%',\r\n top: '2%'\r\n }}\r\n />\r\n <div\r\n className=\"green\"\r\n style={{\r\n position: 'absolute',\r\n backgroundColor: 'rgba(59, 130, 246, 0.4)',\r\n borderRadius: 9999,\r\n width: 128,\r\n height: 128,\r\n left: '10%',\r\n top: '60%'\r\n }}\r\n />\r\n\r\n <div\r\n className=\"red\"\r\n style={{\r\n position: 'absolute',\r\n backgroundColor: 'rgba(239, 68, 68, 0.4)',\r\n borderRadius: 9999,\r\n width: 128,\r\n height: 128,\r\n left: '60%',\r\n top: '2%'\r\n }}\r\n />\r\n\r\n <div\r\n className=\"pink\"\r\n style={{\r\n position: 'absolute',\r\n backgroundColor: 'rgba(236, 72, 153, 0.4)',\r\n borderRadius: 9999,\r\n width: 128,\r\n height: 128,\r\n left: '40%',\r\n top: '50%'\r\n }}\r\n />\r\n <div\r\n className=\"pink\"\r\n style={{\r\n position: 'absolute',\r\n backgroundColor: 'rgba(234, 179, 8, 0.4)',\r\n borderRadius: 9999,\r\n width: 128,\r\n height: 128,\r\n left: '80%',\r\n top: '40%'\r\n }}\r\n />\r\n\r\n <div\r\n style={{\r\n position: 'absolute',\r\n inset: 0,\r\n backgroundColor: 'rgba(0,0,0,0.3)',\r\n backdropFilter: 'blur(24px)'\r\n }}\r\n />\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\nAnimatedBG.displayName = 'AnimatedBG'","import gsap from 'gsap'\r\nimport React, { useEffect } from 'react'\r\n// Remove CSS import to prevent global style conflicts\r\n// import './MaskedBG.css'\r\n\r\nconst MaskedBG: React.FC = () => {\r\n useEffect(() => {\r\n const container = document.querySelector('#masked-bg-container');\r\n if (!container) return;\r\n\r\n // Animate first circle\r\n gsap.fromTo('#circle1', \r\n { \r\n y: 50,\r\n x: 0,\r\n }, \r\n { \r\n y: 200,\r\n x: 100,\r\n duration: 5,\r\n ease: 'power2.inOut',\r\n repeat: -1,\r\n yoyo: true,\r\n onUpdate: function() {\r\n const circle = document.querySelector('#circle1');\r\n if (!circle) return;\r\n const rect = circle.getBoundingClientRect();\r\n const x = (rect.left + rect.width/2) / window.innerWidth * 100;\r\n const y = (rect.top + rect.height/2) / window.innerHeight * 100;\r\n (container as HTMLElement).style.setProperty('--circle1-x', `${x}%`);\r\n (container as HTMLElement).style.setProperty('--circle1-y', `${y}%`);\r\n }\r\n }\r\n );\r\n\r\n // Animate second circle\r\n gsap.fromTo('#circle2', \r\n { \r\n x: 0,\r\n y: -50,\r\n }, \r\n { \r\n x: 50,\r\n y: 50,\r\n duration: 3,\r\n ease: 'power1.inOut',\r\n repeat: -1,\r\n yoyo: true,\r\n onUpdate: function() {\r\n const circle = document.querySelector('#circle2');\r\n if (!circle) return;\r\n const rect = circle.getBoundingClientRect();\r\n const x = (rect.left + rect.width/2) / window.innerWidth * 100;\r\n const y = (rect.top + rect.height/2) / window.innerHeight * 100;\r\n (container as HTMLElement).style.setProperty('--circle2-x', `${x}%`);\r\n (container as HTMLElement).style.setProperty('--circle2-y', `${y}%`);\r\n }\r\n }\r\n );\r\n gsap.fromTo('#circle3', \r\n { \r\n x: 0,\r\n y: -50,\r\n \r\n }, \r\n { \r\n x: 60,\r\n y: 50,\r\n duration: 3,\r\n ease: 'power1.inOut',\r\n repeat: -1,\r\n yoyo: true,\r\n onUpdate: function() {\r\n const circle = document.querySelector('#circle3');\r\n if (!circle) return;\r\n const rect = circle.getBoundingClientRect();\r\n const x = (rect.left + rect.width/2) / window.innerWidth * 100;\r\n const y = (rect.top + rect.height/2) / window.innerHeight * 100;\r\n (container as HTMLElement).style.setProperty('--circle3-x', `${x}%`);\r\n (container as HTMLElement).style.setProperty('--circle3-y', `${y}%`);\r\n }\r\n }\r\n );\r\n gsap.fromTo('#circle4', \r\n { \r\n x: 0,\r\n y: -50,\r\n \r\n }, \r\n { \r\n x: 50,\r\n y: 50,\r\n duration: 3,\r\n ease: 'power1.inOut',\r\n repeat: -1,\r\n yoyo: true,\r\n onUpdate: function() {\r\n const circle = document.querySelector('#circle4');\r\n if (!circle) return;\r\n const rect = circle.getBoundingClientRect();\r\n const x = (rect.left + rect.width/2) / window.innerWidth * 100;\r\n const y = (rect.top + rect.height/2) / window.innerHeight * 100;\r\n (container as HTMLElement).style.setProperty('--circle4-x', `${x}%`);\r\n (container as HTMLElement).style.setProperty('--circle4-y', `${y}%`);\r\n }\r\n }\r\n );\r\n }, []);\r\n\r\n return (\r\n <div\r\n id=\"masked-bg-container\"\r\n aria-hidden\r\n style={{\r\n height: '100%',\r\n width: '100%',\r\n zIndex: 0,\r\n overflow: 'hidden',\r\n pointerEvents: 'none',\r\n userSelect: 'none',\r\n }}\r\n >\r\n <style dangerouslySetInnerHTML={{\r\n __html: `\r\n .background {\r\n position: absolute;\r\n inset: 0;\r\n background: black;\r\n }\r\n .background::before {\r\n content: \"\";\r\n position: absolute;\r\n inset: 0;\r\n background: repeating-linear-gradient(\r\n to right,\r\n rgba(255, 255, 255, 0.1) 0 2px,\r\n transparent 2px 50px\r\n );\r\n -webkit-mask-image:\r\n radial-gradient(circle 400px at 10% 80%, black 40%, transparent 100%),\r\n radial-gradient(circle 250px at 80% 90%, black 40%, transparent 100%),\r\n radial-gradient(circle 400px at 40% 95%, black 40%, transparent 100%),\r\n radial-gradient(circle 250px at 60% 80%, black 40%, transparent 100%);\r\n -webkit-mask-repeat: no-repeat;\r\n -webkit-mask-composite: destination-out;\r\n mask-composite: exclude;\r\n }\r\n .background::after {\r\n content: \"\";\r\n position: absolute;\r\n inset: 0;\r\n background:\r\n radial-gradient(circle 400px at 40% 95%, rgba(152, 8, 255, 0.6) 0%, transparent 100%),\r\n radial-gradient(circle 250px at 60% 80%, rgba(255, 0, 255, 0.6) 0%, transparent 100%);\r\n pointer-events: none;\r\n }\r\n `\r\n }} />\r\n <div style={{ position: 'relative', width: '100%', height: '100%', overflow: 'hidden', zIndex: 0 }}>\r\n {/* Black background */}\r\n <div className=\"background\" />\r\n\r\n {/* Circle masks */}\r\n <div id=\"circle1\" className=\"absolute\"\r\n style={{\r\n width: 300,\r\n height: 300,\r\n borderRadius: 9999,\r\n left: '10%',\r\n top: '80%',\r\n transform: 'translate(-50%, -50%)',\r\n filter: 'blur(20px)',\r\n }}\r\n />\r\n <div id=\"circle2\" className=\"absolute\"\r\n style={{\r\n width: 300,\r\n height: 300,\r\n borderRadius: 9999,\r\n left: '80%',\r\n top: '90%',\r\n transform: 'translate(-50%, -50%)',\r\n filter: 'blur(20px)',\r\n }}\r\n />\r\n <div id=\"circle3\" className=\"absolute\"\r\n style={{\r\n width: 300,\r\n height: 300,\r\n borderRadius: 9999,\r\n left: '40%',\r\n top: '95%',\r\n transform: 'translate(-50%, -50%)',\r\n filter: 'blur(20px)',\r\n }}\r\n />\r\n <div id=\"circle4\" className=\"absolute\"\r\n style={{\r\n width: 300,\r\n height: 300,\r\n borderRadius: 9999,\r\n left: '60%',\r\n top: '80%',\r\n transform: 'translate(-50%, -50%)',\r\n filter: 'blur(20px)',\r\n }}\r\n />\r\n\r\n {/* Masked grid layer */}\r\n <div style={{ position: 'absolute', inset: 0 }}>\r\n {/* Grid columns */}\r\n <div\r\n style={{\r\n position: 'absolute',\r\n inset: 0,\r\n display: 'flex',\r\n WebkitMaskImage: `\r\n radial-gradient(\r\n circle 400px at var(--circle1-x, 20%) var(--circle1-y, 40%),\r\n rgba(75, 0, 130, 0.6) 0%, /* Dark Indigo inside */\r\n rgba(75, 0, 130, 0) 100%\r\n ),\r\n radial-gradient(\r\n circle 250px at var(--circle3-x, 40%) var(--circle3-y, 95%),\r\n rgba(128, 0, 128, 0.6) 0%, /* Dark Purple inside */\r\n rgba(128, 0, 128, 0) 100%\r\n ),\r\n radial-gradient(\r\n circle 400px at var(--circle2-x, 70%) var(--circle2-y, 50%),\r\n rgba(75, 0, 130, 0.6) 0%, /* Dark Indigo inside */\r\n rgba(75, 0, 130, 0) 100%\r\n ),\r\n radial-gradient(\r\n circle 250px at var(--circle4-x, 60%) var(--circle4-y, 80%),\r\n rgba(128, 0, 128, 0.6) 0%, /* Dark Purple inside */\r\n rgba(128, 0, 128, 0) 100%\r\n )\r\n `,\r\n WebkitMaskRepeat: 'no-repeat',\r\n maskComposite: 'destination-out',\r\n }}\r\n >\r\n {Array.from({ length: 24 }).map((_, i) => (\r\n <div\r\n key={i}\r\n style={{ flex: 1, backgroundColor: '#3b82f6' }}\r\n />\r\n ))}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\nMaskedBG.displayName = 'MaskedBG';\r\n\r\nexport default MaskedBG;\r\n\r\n","\r\nimport { motion } from \"framer-motion\";\r\nimport React, { useEffect, useRef } from \"react\";\r\nimport gsap from \"gsap\";\r\n\r\ninterface ReactIconProps {\r\n size?: number;\r\n color?: string;\r\n className?: string;\r\n}\r\n\r\nconst ReactIcon: React.FC<ReactIconProps> = ({ \r\n size = 200, \r\n color = \"cyan\",\r\n className\r\n}) => {\r\n const svgRef = useRef<SVGSVGElement>(null);\r\n\r\n useEffect(() => {\r\n if (svgRef.current) {\r\n gsap.to(svgRef.current, {\r\n rotate: 360,\r\n repeat: -1,\r\n duration: 6\r\n });\r\n }\r\n }, []);\r\n\r\n return (\r\n <svg\r\n ref={svgRef}\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 841.9 595.3\"\r\n width={size}\r\n height={size}\r\n fill=\"none\"\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n className={[\"svg\", className].filter(Boolean).join(\" \")}\r\n style={{ width: \"100%\", height: \"auto\", maxWidth: size }}\r\n >\r\n {/* Base React logo (3 ellipses) with softer glow */}\r\n <g\r\n stroke={color}\r\n strokeWidth=\"20\"\r\n opacity=\"0.5\"\r\n filter=\"url(#glowSoft)\"\r\n >\r\n <ellipse cx=\"420.9\" cy=\"296.5\" rx=\"300\" ry=\"120\" />\r\n <ellipse\r\n cx=\"420.9\"\r\n cy=\"296.5\"\r\n rx=\"300\"\r\n ry=\"120\"\r\n transform=\"rotate(60 420.9 296.5)\"\r\n />\r\n <ellipse\r\n cx=\"420.9\"\r\n cy=\"296.5\"\r\n rx=\"300\"\r\n ry=\"120\"\r\n transform=\"rotate(120 420.9 296.5)\"\r\n />\r\n </g>\r\n\r\n {/* Glowing moving circle (kept strong) */}\r\n <motion.circle\r\n r=\"14\"\r\n fill={color}\r\n filter=\"url(#circleGlow)\"\r\n animate={{ scale: [1, 1.2, 1] }}\r\n transition={{\r\n duration: 1.2,\r\n repeat: Infinity,\r\n ease: \"easeInOut\",\r\n }}\r\n >\r\n <animateMotion\r\n dur=\"5s\"\r\n repeatCount=\"indefinite\"\r\n rotate=\"auto\"\r\n path=\"M 120,296.5 A 300,120 0 1,1 721,296.5 A 300,120 0 1,1 120,296.5 Z\"\r\n />\r\n </motion.circle>\r\n\r\n {/* Glow filters */}\r\n <defs>\r\n {/* Softer glow for ellipses */}\r\n <filter id=\"glowSoft\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\r\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4\" result=\"blur\" />\r\n <feColorMatrix\r\n in=\"blur\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0\r\n 0 0 0 0 1\r\n 0 0 0 0 1\r\n 0 0 0 0.7 0\"\r\n result=\"glowColor\"\r\n />\r\n <feMerge>\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"SourceGraphic\" />\r\n </feMerge>\r\n </filter>\r\n\r\n {/* Strong glow for circle */}\r\n <filter id=\"circleGlow\" x=\"-50%\" y=\"-50%\" width=\"300%\" height=\"300%\">\r\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"12\" result=\"blur\" />\r\n <feColorMatrix\r\n in=\"blur\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0\r\n 0 0 0 0 1\r\n 0 0 0 0 1\r\n 0 0 0 1 0\"\r\n result=\"glowColor\"\r\n />\r\n <feMerge>\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"SourceGraphic\" />\r\n </feMerge>\r\n </filter>\r\n </defs>\r\n </svg>\r\n );\r\n};\r\n\r\nexport default ReactIcon;\r\n","\r\nimport { motion } from \"framer-motion\";\r\nimport React, { useEffect, useRef } from \"react\";\r\n\r\n\r\ninterface JavaScriptIconProps {\r\n size?: number;\r\n color?: string;\r\n className?: string;\r\n}\r\n\r\nconst JavaScriptIcon: React.FC<JavaScriptIconProps> = ({ \r\n size = 200, \r\n color = \"#f7df1e\",\r\n className\r\n}) => {\r\n const svgRef = useRef<SVGSVGElement>(null);\r\n\r\n return (\r\n <svg\r\n ref={svgRef}\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 630 630\"\r\n width={size}\r\n height={size}\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n className={[\"js-svg\", className].filter(Boolean).join(\" \")}\r\n style={{ width: \"100%\", height: \"auto\", maxWidth: size }}\r\n overflow=\"visible\"\r\n >\r\n {/* Base JS square with soft glow */}\r\n <rect\r\n width=\"630\"\r\n height=\"630\"\r\n fill={color}\r\n filter=\"url(#glowSoft)\"\r\n rx=\"30\"\r\n />\r\n\r\n {/* Letters JS */}\r\n <text\r\n x=\"50%\"\r\n y=\"60%\"\r\n textAnchor=\"middle\"\r\n fontSize=\"280\"\r\n fontWeight=\"bold\"\r\n fill=\"black\"\r\n fontFamily=\"Arial, sans-serif\"\r\n >\r\n JS\r\n </text>\r\n\r\n {/* Glowing moving circle (now on the border) */}\r\n <motion.circle\r\n r=\"18\"\r\n fill={color}\r\n filter=\"url(#circleGlow)\"\r\n animate={{ scale: [1, 1.2, 1] }}\r\n transition={{\r\n duration: 1.2,\r\n repeat: Infinity,\r\n ease: \"easeInOut\",\r\n }}\r\n >\r\n {/* Path hugs the outer border */}\r\n <animateMotion\r\n dur=\"6s\"\r\n repeatCount=\"indefinite\"\r\n rotate=\"auto\"\r\n path=\"M 0,0 H 630 V 630 H 0 Z\"\r\n />\r\n </motion.circle>\r\n\r\n {/* Glow filters */}\r\n <defs>\r\n {/* Softer glow for square */}\r\n <filter id=\"glowSoft\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\r\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"6\" result=\"blur\" />\r\n <feColorMatrix\r\n in=\"blur\"\r\n type=\"matrix\"\r\n values=\"1 1 0 0 0\r\n 1 1 0 0 0\r\n 0 0 0 0 0\r\n 0 0 0 0.6 0\"\r\n result=\"glowColor\"\r\n />\r\n <feMerge>\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"SourceGraphic\" />\r\n </feMerge>\r\n </filter>\r\n\r\n {/* Strong glow for circle */}\r\n <filter id=\"circleGlow\" x=\"-50%\" y=\"-50%\" width=\"300%\" height=\"300%\">\r\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"12\" result=\"blur\" />\r\n <feColorMatrix\r\n in=\"blur\"\r\n type=\"matrix\"\r\n values=\"1 1 0 0 0\r\n 1 1 0 0 0\r\n 0 0 0 0 0\r\n 0 0 0 1 0\"\r\n result=\"glowColor\"\r\n />\r\n <feMerge>\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"SourceGraphic\" />\r\n </feMerge>\r\n </filter>\r\n </defs>\r\n </svg>\r\n );\r\n};\r\n\r\nexport default JavaScriptIcon;\r\n","import { motion } from \"framer-motion\";\r\nimport React, { useRef } from \"react\";\r\n\r\ninterface JavaIconProps {\r\n size?: number;\r\n color?: string;\r\n className?: string;\r\n}\r\n\r\nconst JavaIcon: React.FC<JavaIconProps> = ({\r\n size = 200,\r\n color = \"#0074BD\", // default blue shade\r\n className,\r\n}) => {\r\n const svgRef = useRef<SVGSVGElement>(null);\r\n\r\n return (\r\n <svg\r\n ref={svgRef}\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 128 128\"\r\n width={size}\r\n height={size}\r\n preserveAspectRatio=\"xMidYMid meet\"\r\n className={[\"java-svg\", className].filter(Boolean).join(\" \")}\r\n style={{ width: \"100%\", height: \"auto\", maxWidth: size }}\r\n overflow=\"visible\"\r\n >\r\n {/* White square with glow (like JS icon) */}\r\n <rect\r\n width=\"128\"\r\n height=\"128\"\r\n fill=\"white\"\r\n filter=\"url(#glowSoft)\"\r\n rx=\"16\"\r\n />\r\n\r\n {/* Original Java logo paths */}\r\n <g transform=\"scale(1) translate(0,0)\">\r\n <path\r\n fill=\"#0074BD\"\r\n d=\"M47.617 98.12s-4.767 2.774 3.397 3.71c9.892 1.13 14.947.968 25.845-1.092 0 0 2.871 1.795 6.873 3.351-24.439 10.47-55.308-.607-36.115-5.969zm-2.988-13.665s-5.348 3.959 2.823 4.805c10.567 1.091 18.91 1.18 33.354-1.6 0 0 1.993 2.025 5.132 3.131-29.542 8.64-62.446.68-41.309-6.336z\"\r\n />\r\n <path\r\n fill=\"#EA2D2E\"\r\n d=\"M69.802 61.271c6.025 6.935-1.58 13.17-1.58 13.17s15.289-7.891 8.269-17.777c-6.559-9.215-11.587-13.792 15.635-29.58 0 .001-42.731 10.67-22.324 34.187z\"\r\n />\r\n <path\r\n fill=\"#0074BD\"\r\n d=\"M102.123 108.229s3.529 2.91-3.888 5.159c-14.102 4.272-58.706 5.56-71.094.171-4.451-1.938 3.899-4.625 6.526-5.192 2.739-.593 4.303-.485 4.303-.485-4.953-3.487-32.013 6.85-13.743 9.815 49.821 8.076 90.817-3.637 77.896-9.468zM49.912 70.294s-22.686 5.389-8.033 7.348c6.188.828 18.518.638 30.011-.326 9.39-.789 18.813-2.474 18.813-2.474s-3.308 1.419-5.704 3.053c-23.042 6.061-67.544 3.238-54.731-2.958 10.832-5.239 19.644-4.643 19.644-4.643zm40.697 22.747c23.421-12.167 12.591-23.86 5.032-22.285-1.848.385-2.677.72-2.677.72s.688-1.079 2-1.543c14.953-5.255 26.451 15.503-4.823 23.725 0-.002.359-.327.468-.617z\"\r\n />\r\n <path\r\n fill=\"#EA2D2E\"\r\n d=\"M76.491 1.587S89.459 14.563 64.188 34.51c-20.266 16.006-4.621 25.13-.007 35.559-11.831-10.673-20.509-20.07-14.688-28.815C58.041 28.42 81.722 22.195 76.491 1.587z\"\r\n />\r\n <path\r\n fill=\"#0074BD\"\r\n d=\"M52.214 126.021c22.476 1.437 57-.8 57.817-11.436 0 0-1.571 4.032-18.577 7.231-19.186 3.612-42.854 3.191-56.887.874 0 .001 2.875 2.381 17.647 3.331z\"\r\n />\r\n </g>\r\n\r\n {/* Glowing moving circle around border */}\r\n <motion.circle\r\n r=\"6\"\r\n fill={color}\r\n filter=\"url(#circleGlow)\"\r\n animate={{ scale: [1, 1.2, 1] }}\r\n transition={{\r\n duration: 1.2,\r\n repeat: Infinity,\r\n ease: \"easeInOut\",\r\n }}\r\n >\r\n {/* Path hugs the outer border of 128x128 square */}\r\n <animateMotion\r\n dur=\"6s\"\r\n repeatCount=\"indefinite\"\r\n rotate=\"auto\"\r\n path=\"M 0,0 H 128 V 128 H 0 Z\"\r\n />\r\n </motion.circle>\r\n\r\n {/* Glow filters */}\r\n <defs>\r\n {/* Soft glow for square */}\r\n <filter id=\"glowSoft\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\r\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"4\" result=\"blur\" />\r\n <feColorMatrix\r\n in=\"blur\"\r\n type=\"matrix\"\r\n values=\"0 0 1 0 0\r\n 0 0 1 0 0\r\n 0 0 1 0 0\r\n 0 0 0 0.6 0\"\r\n result=\"glowColor\"\r\n />\r\n <feMerge>\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"SourceGraphic\" />\r\n </feMerge>\r\n </filter>\r\n\r\n {/* Strong glow for circle */}\r\n <filter id=\"circleGlow\" x=\"-50%\" y=\"-50%\" width=\"300%\" height=\"300%\">\r\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"6\" result=\"blur\" />\r\n <feColorMatrix\r\n in=\"blur\"\r\n type=\"matrix\"\r\n values=\"1 0 0 0 0\r\n 0 0 1 0 0\r\n 0 0 1 0 0\r\n 0 0 0 1 0\"\r\n result=\"glowColor\"\r\n />\r\n <feMerge>\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"glowColor\" />\r\n <feMergeNode in=\"SourceGraphic\" />\r\n </feMerge>\