{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "GridMotion-JS-CSS",
	"title": "GridMotion",
	"description": "Perspective moving grid lines based on cusror position.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "GridMotion.css",
			"target": "@components/GridMotion.css",
			"content": ".noscroll {\n  height: 100%;\n  width: 100%;\n  overflow: hidden;\n}\n\n.intro {\n  width: 100%;\n  height: 100vh;\n  overflow: hidden;\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.intro::after {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background-size: 250px;\n  pointer-events: none;\n  z-index: 4;\n}\n\n.gridMotion-container {\n  gap: 1rem;\n  flex: none;\n  position: relative;\n  width: 150vw;\n  height: 150vh;\n  display: grid;\n  grid-template-rows: repeat(4, 1fr);\n  grid-template-columns: 100%;\n  transform: rotate(-15deg);\n  transform-origin: center center;\n  z-index: 2;\n}\n\n.row {\n  display: grid;\n  gap: 1rem;\n  grid-template-columns: repeat(7, 1fr);\n  will-change: transform, filter;\n}\n\n.row__item {\n  position: relative;\n}\n\n.row__item-inner {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  border-radius: 10px;\n  background-color: #111;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: white;\n  font-size: 1.5rem;\n}\n\n.row__item-img {\n  width: 100%;\n  height: 100%;\n  background-size: cover;\n  background-position: 50% 50%;\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n\n.row__item-content {\n  padding: 1rem;\n  text-align: center;\n  z-index: 1;\n}\n\n.fullview {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  top: 0;\n  left: 0;\n  pointer-events: none;\n}\n\n.fullview .row__item-inner {\n  border-radius: 0px;\n}\n"
		},
		{
			"type": "registry:component",
			"path": "GridMotion.jsx",
			"content": "import { useEffect, useRef } from 'react';\nimport { gsap } from 'gsap';\nimport './GridMotion.css';\n\nconst GridMotion = ({ items = [], gradientColor = 'black' }) => {\n  const gridRef = useRef(null);\n  const rowRefs = useRef([]);\n  const mouseXRef = useRef(window.innerWidth / 2);\n\n  const totalItems = 28;\n  const defaultItems = Array.from({ length: totalItems }, (_, index) => `Item ${index + 1}`);\n  const combinedItems = items.length > 0 ? items.slice(0, totalItems) : defaultItems;\n\n  useEffect(() => {\n    gsap.ticker.lagSmoothing(0);\n\n    const handleMouseMove = e => {\n      mouseXRef.current = e.clientX;\n    };\n\n    const updateMotion = () => {\n      const maxMoveAmount = 300;\n      const baseDuration = 0.8;\n      const inertiaFactors = [0.6, 0.4, 0.3, 0.2];\n\n      rowRefs.current.forEach((row, index) => {\n        if (row) {\n          const direction = index % 2 === 0 ? 1 : -1;\n          const moveAmount = ((mouseXRef.current / window.innerWidth) * maxMoveAmount - maxMoveAmount / 2) * direction;\n\n          gsap.to(row, {\n            x: moveAmount,\n            duration: baseDuration + inertiaFactors[index % inertiaFactors.length],\n            ease: 'power3.out',\n            overwrite: 'auto'\n          });\n        }\n      });\n    };\n\n    const removeAnimationLoop = gsap.ticker.add(updateMotion);\n\n    window.addEventListener('mousemove', handleMouseMove);\n\n    return () => {\n      window.removeEventListener('mousemove', handleMouseMove);\n      removeAnimationLoop();\n    };\n  }, []);\n\n  return (\n    <div className=\"noscroll loading\" ref={gridRef}>\n      <section\n        className=\"intro\"\n        style={{\n          background: `radial-gradient(circle, ${gradientColor} 0%, transparent 100%)`\n        }}\n      >\n        <div className=\"gridMotion-container\">\n          {[...Array(4)].map((_, rowIndex) => (\n            <div key={rowIndex} className=\"row\" ref={el => {\n                rowRefs.current[rowIndex] = el;\n              }}>\n              {[...Array(7)].map((_, itemIndex) => {\n                const content = combinedItems[rowIndex * 7 + itemIndex];\n                return (\n                  <div key={itemIndex} className=\"row__item\">\n                    <div className=\"row__item-inner\" style={{ backgroundColor: '#111' }}>\n                      {typeof content === 'string' && content.startsWith('http') ? (\n                        <div\n                          className=\"row__item-img\"\n                          style={{\n                            backgroundImage: `url(${content})`\n                          }}\n                        ></div>\n                      ) : (\n                        <div className=\"row__item-content\">{content}</div>\n                      )}\n                    </div>\n                  </div>\n                );\n              })}\n            </div>\n          ))}\n        </div>\n        <div className=\"fullview\"></div>\n      </section>\n    </div>\n  );\n};\n\nexport default GridMotion;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"gsap@^3.13.0"
	]
}