{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "pixel-image",
	"title": "Pixel Image",
	"type": "registry:block",
	"description": "An image component that reveals itself through a pixelated grid animation with optional grayscale to color transition.",
	"dependencies": [
		"motion-sv",
		"runed"
	],
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { cn } from \"$UTILS$.js\";\n\timport { useInView } from \"motion-sv\";\n\timport { watch } from \"runed\";\n\n\ttype Grid = {\n\t\trows: number;\n\t\tcols: number;\n\t};\n\n\tconst DEFAULT_GRIDS: Record<string, Grid> = {\n\t\t\"6x4\": { rows: 4, cols: 6 },\n\t\t\"8x8\": { rows: 8, cols: 8 },\n\t\t\"8x3\": { rows: 3, cols: 8 },\n\t\t\"4x6\": { rows: 6, cols: 4 },\n\t\t\"3x8\": { rows: 8, cols: 3 },\n\t};\n\n\ttype PredefinedGridKey = keyof typeof DEFAULT_GRIDS;\n\n\tinterface Props {\n\t\tsrc: string;\n\t\tgrid?: PredefinedGridKey;\n\t\tcustomGrid?: Grid;\n\t\tgrayscaleAnimation?: boolean;\n\t\tpixelFadeInDuration?: number;\n\t\tmaxAnimationDelay?: number;\n\t\tcolorRevealDelay?: number;\n\t\tonce?: boolean;\n\t}\n\n\tlet {\n\t\tsrc,\n\t\tgrid = \"6x4\",\n\t\tgrayscaleAnimation = true,\n\t\tpixelFadeInDuration = 1000,\n\t\tmaxAnimationDelay = 1200,\n\t\tcolorRevealDelay = 1300,\n\t\tcustomGrid,\n\t\tonce = false,\n\t}: Props = $props();\n\n\tlet showColor = $state(false);\n\n\tconst MIN_GRID = 1;\n\tconst MAX_GRID = 16;\n\n\tlet dimensions = $derived.by(() => {\n\t\tconst isValidGrid = (grid?: Grid) => {\n\t\t\tif (!grid) return false;\n\t\t\tconst { rows, cols } = grid;\n\t\t\treturn (\n\t\t\t\tNumber.isInteger(rows) &&\n\t\t\t\tNumber.isInteger(cols) &&\n\t\t\t\trows >= MIN_GRID &&\n\t\t\t\tcols >= MIN_GRID &&\n\t\t\t\trows <= MAX_GRID &&\n\t\t\t\tcols <= MAX_GRID\n\t\t\t);\n\t\t};\n\n\t\treturn isValidGrid(customGrid) ? customGrid! : DEFAULT_GRIDS[grid];\n\t});\n\n\tlet pieces = $derived.by(() => {\n\t\tconst total = dimensions.rows * dimensions.cols;\n\t\treturn Array.from({ length: total }, (_, index) => {\n\t\t\tconst row = Math.floor(index / dimensions.cols);\n\t\t\tconst col = index % dimensions.cols;\n\n\t\t\tconst clipPath = `polygon(\n        ${col * (100 / dimensions.cols)}% ${row * (100 / dimensions.rows)}%,\n        ${(col + 1) * (100 / dimensions.cols)}% ${row * (100 / dimensions.rows)}%,\n        ${(col + 1) * (100 / dimensions.cols)}% ${(row + 1) * (100 / dimensions.rows)}%,\n        ${col * (100 / dimensions.cols)}% ${(row + 1) * (100 / dimensions.rows)}%\n      )`;\n\n\t\t\tconst delay = Math.random() * maxAnimationDelay;\n\t\t\treturn {\n\t\t\t\tclipPath,\n\t\t\t\tdelay,\n\t\t\t};\n\t\t});\n\t});\n\n\tlet element: HTMLDivElement | null = $state(null);\n\tlet view = useInView(\n\t\t() => element!,\n\t\t() => ({ once }) as any // type definition bug\n\t);\n\n\twatch(\n\t\t() => view.current,\n\t\t(isInView) => {\n\t\t\tif (isInView) {\n\t\t\t\t// Element entered view - start color reveal after delay\n\t\t\t\tconst colorTimeout = setTimeout(() => {\n\t\t\t\t\tshowColor = true;\n\t\t\t\t}, colorRevealDelay);\n\t\t\t\treturn () => clearTimeout(colorTimeout);\n\t\t\t} else if (!once) {\n\t\t\t\t// Element left view and once is false - reset animation\n\t\t\t\tshowColor = false;\n\t\t\t}\n\t\t}\n\t);\n\n\t// $inspect(view.current, \"In View\");\n</script>\n\n<div class=\"relative h-72 w-72 select-none md:h-96 md:w-96\" bind:this={element}>\n\t{#each pieces as piece, index}\n\t\t<div\n\t\t\tclass={cn(\n\t\t\t\t\"absolute inset-0 transition-all ease-out\",\n\t\t\t\tview.current ? \"opacity-100\" : \"opacity-0\"\n\t\t\t)}\n\t\t\tstyle=\"clip-path: {piece.clipPath}; transition-delay: {piece.delay}ms; transition-duration: {pixelFadeInDuration}ms;\"\n\t\t>\n\t\t\t<img\n\t\t\t\t{src}\n\t\t\t\talt=\"Pixel image piece {index + 1}\"\n\t\t\t\tclass={cn(\n\t\t\t\t\t\"z-1 rounded-[2.5rem] object-cover\",\n\t\t\t\t\tgrayscaleAnimation && (showColor ? \"grayscale-0\" : \"grayscale\")\n\t\t\t\t)}\n\t\t\t\tstyle={grayscaleAnimation\n\t\t\t\t\t? `filter: ${showColor ? \"grayscale(0)\" : \"grayscale(1)\"}; transition: filter ${pixelFadeInDuration}ms cubic-bezier(0.4, 0, 0.2, 1)`\n\t\t\t\t\t: \"\"}\n\t\t\t\tdraggable=\"false\"\n\t\t\t/>\n\t\t</div>\n\t{/each}\n</div>\n",
			"type": "registry:component",
			"target": "magic/pixel-image/pixel-image.svelte"
		},
		{
			"content": "import PixelImage from \"./pixel-image.svelte\";\nexport { PixelImage };\n",
			"type": "registry:file",
			"target": "magic/pixel-image/index.ts"
		}
	]
}