{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "string-art-background",
  "type": "registry:block",
  "title": "String art background",
  "description": "String art background",
  "files": [
    {
      "path": "components/usages/stringartbackgroundusage.tsx",
      "content": "import React from 'react';\nimport { IoChevronForward } from \"react-icons/io5\";\nimport StringArt from '@/registry/open-source/string-art-background';\nconst App = () => {\n    return (\n        <StringArt>\n            <div\n                className=\"relative z-10 flex flex-col items-center justify-center w-full h-full text-center max-w-[700px] mx-auto px-5 py-10 md:py-0 lg:lg:px-0 text-white\">\n                <button\n                    className=\"py-1.5 pl-5 backdrop-blur-md pr-6 border-gray-600 rounded-full text-[0.9rem] border mb-4\">\n                    ✨ Introducing ZenUI v2.3\n                </button>\n\n                <h1\n                    className=\"text-[2rem] lg:text-[3rem] font-bold leading-[40px] lg:leading-[50px]\">\n                    Open-Source UI Components & Templates Library\n                </h1>\n\n                <p\n                    className=\"text-white/80 max-w-[700px] mt-3\">\n                    ZenUI Library is an Tailwind CSS components library for any needs. Comes with UI examples &\n                    blocks,\n                    templates, Icons, Color Palette and more.\n                </p>\n\n                <div\n                    className=\"flex items-center flex-col md:flex-row gap-3 justify-center 425px:gap-6 mt-10 md:mt-12\">\n                    <button\n                        className=\"bg-[#0FABCA] pl-5 pr-4 border border-[#0FABCA] rounded-lg py-3 flex items-center gap-2 text-[1rem] group\"\n                    >\n                        Browse Components\n                        <IoChevronForward className=\"group-hover:ml-1 transition-all duration-200\" />\n                    </button>\n                    <button\n                        className=\"border-2 border-[#0FABCA] pl-5 pr-4 rounded-lg py-3 flex items-center gap-2 text-[1rem] group\">\n                        Browse Templates\n                        <IoChevronForward className=\"group-hover:ml-1 transition-all duration-200\" />\n                    </button>\n                </div>\n            </div>\n        </StringArt>\n    );\n};\n\nexport default App;\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/stringartbackgroundusage.tsx",
      "content": "import React from 'react';\nimport { IoChevronForward } from \"react-icons/io5\";\nimport StringArt from '@/registry/open-source/string-art-background';\nconst App = () => {\n    return (\n        <StringArt>\n            <div\n                className=\"relative z-10 flex flex-col items-center justify-center w-full h-full text-center max-w-[700px] mx-auto px-5 py-10 md:py-0 lg:lg:px-0 text-white\">\n                <button\n                    className=\"py-1.5 pl-5 backdrop-blur-md pr-6 border-gray-600 rounded-full text-[0.9rem] border mb-4\">\n                    ✨ Introducing ZenUI v2.3\n                </button>\n\n                <h1\n                    className=\"text-[2rem] lg:text-[3rem] font-bold leading-[40px] lg:leading-[50px]\">\n                    Open-Source UI Components & Templates Library\n                </h1>\n\n                <p\n                    className=\"text-white/80 max-w-[700px] mt-3\">\n                    ZenUI Library is an Tailwind CSS components library for any needs. Comes with UI examples &\n                    blocks,\n                    templates, Icons, Color Palette and more.\n                </p>\n\n                <div\n                    className=\"flex items-center flex-col md:flex-row gap-3 justify-center 425px:gap-6 mt-10 md:mt-12\">\n                    <button\n                        className=\"bg-[#0FABCA] pl-5 pr-4 border border-[#0FABCA] rounded-lg py-3 flex items-center gap-2 text-[1rem] group\"\n                    >\n                        Browse Components\n                        <IoChevronForward className=\"group-hover:ml-1 transition-all duration-200\" />\n                    </button>\n                    <button\n                        className=\"border-2 border-[#0FABCA] pl-5 pr-4 rounded-lg py-3 flex items-center gap-2 text-[1rem] group\">\n                        Browse Templates\n                        <IoChevronForward className=\"group-hover:ml-1 transition-all duration-200\" />\n                    </button>\n                </div>\n            </div>\n        </StringArt>\n    );\n};\n\nexport default App;\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/string-art-background.tsx",
      "content": "import { useRef, useEffect, useState } from \"react\"\n\n// Credit:\n// https://zenui.net/animations/background-animations\n\nconst StringArt = ({ children }) => {\n    const canvasRef = useRef(null)\n    const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })\n    const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n    const anchorPointsRef = useRef([])\n    const animationRef = useRef(null)\n\n    useEffect(() => {\n        const canvas = canvasRef.current\n        const ctx = canvas.getContext(\"2d\")\n\n        const handleResize = () => {\n            const dpr = window.devicePixelRatio || 1\n            const width = window.innerWidth\n            const height = window.innerHeight\n\n            canvas.width = width * dpr\n            canvas.height = height * dpr\n            canvas.style.width = `${width}px`\n            canvas.style.height = `${height}px`\n\n            ctx.setTransform(1, 0, 0, 1, 0, 0)\n            ctx.scale(dpr, dpr)\n\n            setDimensions({ width, height })\n            generateAnchorPoints(width, height)\n        }\n\n        const generateAnchorPoints = (width, height) => {\n            const points = []\n            const pointCount = width < 768 ? 40 : 60\n            const radius = Math.min(width, height) * 0.3\n            const centerX = width / 2\n            const centerY = height / 2\n\n            for (let i = 0; i < pointCount; i++) {\n                const angle = (i / pointCount) * Math.PI * 2\n                const x = centerX + Math.cos(angle) * radius\n                const y = centerY + Math.sin(angle) * radius\n                points.push({ x, y })\n            }\n\n            anchorPointsRef.current = points\n        }\n\n        handleResize()\n        window.addEventListener(\"resize\", handleResize)\n        return () => {\n            window.removeEventListener(\"resize\", handleResize)\n            if (animationRef.current) cancelAnimationFrame(animationRef.current)\n        }\n    }, [])\n\n    useEffect(() => {\n        const handleMouseMove = (e) => {\n            const rect = canvasRef.current.getBoundingClientRect()\n            setMousePosition({\n                x: e.clientX - rect.left,\n                y: e.clientY - rect.top,\n            })\n        }\n\n        window.addEventListener(\"mousemove\", handleMouseMove)\n        return () => window.removeEventListener(\"mousemove\", handleMouseMove)\n    }, [])\n\n    useEffect(() => {\n        if (!dimensions.width) return\n        const canvas = canvasRef.current\n        const ctx = canvas.getContext(\"2d\")\n\n        const animate = () => {\n            ctx.clearRect(0, 0, dimensions.width, dimensions.height)\n\n            const anchorPoints = anchorPointsRef.current\n\n            ctx.fillStyle = \"rgba(255, 255, 255, 0.5)\"\n            for (const point of anchorPoints) {\n                ctx.beginPath()\n                ctx.arc(point.x, point.y, 2.5, 0, Math.PI * 2)\n                ctx.fill()\n            }\n\n            for (const point of anchorPoints) {\n                const dx = point.x - mousePosition.x\n                const dy = point.y - mousePosition.y\n                const distance = Math.sqrt(dx * dx + dy * dy)\n                const angle = Math.atan2(dy, dx)\n                const skipFactor = Math.abs(Math.sin(angle * 5)) < 0.3\n                if (skipFactor) continue\n\n                const maxDistance = Math.max(dimensions.width, dimensions.height) * 0.7\n                const opacity = 0.1 + 0.4 * (1 - Math.min(1, distance / maxDistance))\n                const hue = ((angle * 180) / Math.PI + 180) % 360\n\n                ctx.beginPath()\n                ctx.moveTo(point.x, point.y)\n                ctx.lineTo(mousePosition.x, mousePosition.y)\n                ctx.strokeStyle = `hsla(${hue}, 70%, 60%, ${opacity})`\n                ctx.lineWidth = 0.6\n                ctx.stroke()\n            }\n\n            const gradient = ctx.createRadialGradient(\n                mousePosition.x,\n                mousePosition.y,\n                0,\n                mousePosition.x,\n                mousePosition.y,\n                30\n            )\n            gradient.addColorStop(0, \"rgba(33,33,33,0.2)\")\n            gradient.addColorStop(1, \"rgba(0, 0, 0, 0.1)\")\n\n            ctx.fillStyle = gradient\n            ctx.beginPath()\n            ctx.arc(mousePosition.x, mousePosition.y, 30, 0, Math.PI * 2)\n            ctx.fill()\n\n            animationRef.current = requestAnimationFrame(animate)\n        }\n\n        animate()\n        return () => {\n            if (animationRef.current) cancelAnimationFrame(animationRef.current)\n        }\n    }, [dimensions, mousePosition])\n\n    return (\n        <div\n            className=\"relative w-full min-h-[500px] flex items-center justify-center flex-col overflow-hidden rounded-high bg-gray-900\">\n\n            <canvas ref={canvasRef}\n                className=\"absolute left-[50%] translate-x-[-50%] top-[50%] translate-y-[-50%] w-[50%] h-[50%]\" />\n\n            {children}\n        </div>\n    )\n}\n\nexport default StringArt;\n",
      "type": "registry:ui"
    }
  ]
}