{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "flickering-grid",
	"title": "Flickering Grid",
	"type": "registry:block",
	"description": "An animated flickering grid pattern component that creates a dynamic canvas-based background with randomly flickering squares.",
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { onMount } from \"svelte\";\n\timport { cn } from \"$UTILS$\";\n\n\tinterface FlickeringGridProps {\n\t\tsquareSize?: number;\n\t\tgridGap?: number;\n\t\tflickerChance?: number;\n\t\tcolor?: string;\n\t\twidth?: number;\n\t\theight?: number;\n\t\tclass?: string;\n\t\tmaxOpacity?: number;\n\t}\n\n\tlet {\n\t\tsquareSize = 4,\n\t\tgridGap = 6,\n\t\tflickerChance = 0.3,\n\t\tcolor = \"rgb(0, 0, 0)\",\n\t\twidth,\n\t\theight,\n\t\tclass: className,\n\t\tmaxOpacity = 0.3,\n\t\t...props\n\t}: FlickeringGridProps = $props();\n\n\tlet canvasRef: HTMLCanvasElement | null = $state(null);\n\tlet containerRef: HTMLDivElement | null = $state(null);\n\tlet isInView = $state(false);\n\tlet canvasSize = $state({ width: 0, height: 0 });\n\n\tconst memoizedColor = $derived.by(() => {\n\t\tconst toRGBA = (color: string) => {\n\t\t\tif (typeof window === \"undefined\") {\n\t\t\t\treturn `rgba(0, 0, 0,`;\n\t\t\t}\n\t\t\tconst canvas = document.createElement(\"canvas\");\n\t\t\tcanvas.width = canvas.height = 1;\n\t\t\tconst ctx = canvas.getContext(\"2d\");\n\t\t\tif (!ctx) return \"rgba(255, 0, 0,\";\n\t\t\tctx.fillStyle = color;\n\t\t\tctx.fillRect(0, 0, 1, 1);\n\t\t\tconst [r, g, b] = Array.from(ctx.getImageData(0, 0, 1, 1).data);\n\t\t\treturn `rgba(${r}, ${g}, ${b},`;\n\t\t};\n\t\treturn toRGBA(color);\n\t});\n\n\tconst setupCanvas = (canvas: HTMLCanvasElement, width: number, height: number) => {\n\t\tconst dpr = window.devicePixelRatio || 1;\n\t\tcanvas.width = width * dpr;\n\t\tcanvas.height = height * dpr;\n\t\tcanvas.style.width = `${width}px`;\n\t\tcanvas.style.height = `${height}px`;\n\t\tconst cols = Math.floor(width / (squareSize + gridGap));\n\t\tconst rows = Math.floor(height / (squareSize + gridGap));\n\n\t\tconst squares = new Float32Array(cols * rows);\n\t\tfor (let i = 0; i < squares.length; i++) {\n\t\t\tsquares[i] = Math.random() * maxOpacity;\n\t\t}\n\n\t\treturn { cols, rows, squares, dpr };\n\t};\n\n\tconst updateSquares = (squares: Float32Array, deltaTime: number) => {\n\t\tfor (let i = 0; i < squares.length; i++) {\n\t\t\tif (Math.random() < flickerChance * deltaTime) {\n\t\t\t\tsquares[i] = Math.random() * maxOpacity;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst drawGrid = (\n\t\tctx: CanvasRenderingContext2D,\n\t\twidth: number,\n\t\theight: number,\n\t\tcols: number,\n\t\trows: number,\n\t\tsquares: Float32Array,\n\t\tdpr: number\n\t) => {\n\t\tctx.clearRect(0, 0, width, height);\n\t\tctx.fillStyle = \"transparent\";\n\t\tctx.fillRect(0, 0, width, height);\n\n\t\tfor (let i = 0; i < cols; i++) {\n\t\t\tfor (let j = 0; j < rows; j++) {\n\t\t\t\tconst opacity = squares[i * rows + j];\n\t\t\t\tctx.fillStyle = `${memoizedColor}${opacity})`;\n\t\t\t\tctx.fillRect(\n\t\t\t\t\ti * (squareSize + gridGap) * dpr,\n\t\t\t\t\tj * (squareSize + gridGap) * dpr,\n\t\t\t\t\tsquareSize * dpr,\n\t\t\t\t\tsquareSize * dpr\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n\n\tonMount(() => {\n\t\tconst canvas = canvasRef;\n\t\tconst container = containerRef;\n\t\tif (!canvas || !container) return;\n\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\n\t\tlet animationFrameId: number;\n\t\tlet gridParams: ReturnType<typeof setupCanvas>;\n\n\t\tconst updateCanvasSize = () => {\n\t\t\tconst newWidth = width || container.clientWidth;\n\t\t\tconst newHeight = height || container.clientHeight;\n\t\t\tcanvasSize = { width: newWidth, height: newHeight };\n\t\t\tgridParams = setupCanvas(canvas, newWidth, newHeight);\n\t\t};\n\n\t\tupdateCanvasSize();\n\n\t\tlet lastTime = 0;\n\t\tconst animate = (time: number) => {\n\t\t\tif (!isInView) return;\n\n\t\t\tconst deltaTime = (time - lastTime) / 1000;\n\t\t\tlastTime = time;\n\n\t\t\tupdateSquares(gridParams.squares, deltaTime);\n\t\t\tdrawGrid(\n\t\t\t\tctx,\n\t\t\t\tcanvas.width,\n\t\t\t\tcanvas.height,\n\t\t\t\tgridParams.cols,\n\t\t\t\tgridParams.rows,\n\t\t\t\tgridParams.squares,\n\t\t\t\tgridParams.dpr\n\t\t\t);\n\t\t\tanimationFrameId = requestAnimationFrame(animate);\n\t\t};\n\n\t\tconst resizeObserver = new ResizeObserver(() => {\n\t\t\tupdateCanvasSize();\n\t\t});\n\n\t\tresizeObserver.observe(container);\n\n\t\tconst intersectionObserver = new IntersectionObserver(\n\t\t\t([entry]) => {\n\t\t\t\tisInView = entry.isIntersecting;\n\t\t\t},\n\t\t\t{ threshold: 0 }\n\t\t);\n\n\t\tintersectionObserver.observe(canvas);\n\n\t\t$effect(() => {\n\t\t\tif (isInView) {\n\t\t\t\tanimationFrameId = requestAnimationFrame(animate);\n\t\t\t}\n\t\t});\n\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(animationFrameId);\n\t\t\tresizeObserver.disconnect();\n\t\t\tintersectionObserver.disconnect();\n\t\t};\n\t});\n</script>\n\n<div bind:this={containerRef} class={cn(\"h-full w-full\", className)} {...props}>\n\t<canvas\n\t\tbind:this={canvasRef}\n\t\tclass=\"pointer-events-none\"\n\t\tstyle:width=\"{canvasSize.width}px\"\n\t\tstyle:height=\"{canvasSize.height}px\"\n\t></canvas>\n</div>\n",
			"type": "registry:component",
			"target": "magic/flickering-grid/flickering-grid.svelte"
		},
		{
			"content": "import FlickeringGrid from \"./flickering-grid.svelte\";\nexport { FlickeringGrid };\n",
			"type": "registry:file",
			"target": "magic/flickering-grid/index.ts"
		}
	]
}