{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "cool-mode",
	"title": "Cool Mode",
	"type": "registry:block",
	"description": "Add a fun particle effect that follows mouse interactions, with support for emojis, images, and custom shapes.",
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { onMount, onDestroy } from \"svelte\";\n\timport type { Snippet } from \"svelte\";\n\n\texport interface BaseParticle {\n\t\telement: HTMLElement | SVGSVGElement;\n\t\tleft: number;\n\t\tsize: number;\n\t\ttop: number;\n\t}\n\n\texport interface BaseParticleOptions {\n\t\tparticle?: string;\n\t\tsize?: number;\n\t}\n\n\texport interface CoolParticle extends BaseParticle {\n\t\tdirection: number;\n\t\tspeedHorz: number;\n\t\tspeedUp: number;\n\t\tspinSpeed: number;\n\t\tspinVal: number;\n\t}\n\n\texport interface CoolParticleOptions extends BaseParticleOptions {\n\t\tparticleCount?: number;\n\t\tspeedHorz?: number;\n\t\tspeedUp?: number;\n\t}\n\n\tinterface CoolModeProps {\n\t\tchildren: Snippet;\n\t\toptions?: CoolParticleOptions;\n\t}\n\n\tlet { children, options }: CoolModeProps = $props();\n\n\tlet ref: HTMLSpanElement;\n\tlet cleanup: (() => void) | undefined;\n\n\tconst getContainer = () => {\n\t\tconst id = \"_coolMode_effect\";\n\t\tconst existingContainer = document.getElementById(id);\n\n\t\tif (existingContainer) {\n\t\t\treturn existingContainer;\n\t\t}\n\n\t\tconst container = document.createElement(\"div\");\n\t\tcontainer.setAttribute(\"id\", id);\n\t\tcontainer.setAttribute(\n\t\t\t\"style\",\n\t\t\t\"overflow:hidden; position:fixed; height:100%; top:0; left:0; right:0; bottom:0; pointer-events:none; z-index:2147483647\"\n\t\t);\n\n\t\tdocument.body.appendChild(container);\n\n\t\treturn container;\n\t};\n\n\tlet instanceCounter = 0;\n\n\tconst applyParticleEffect = (\n\t\telement: HTMLElement,\n\t\toptions?: CoolParticleOptions\n\t): (() => void) => {\n\t\tinstanceCounter++;\n\n\t\tconst defaultParticle = \"circle\";\n\t\tconst particleType = options?.particle || defaultParticle;\n\t\tconst sizes = [15, 20, 25, 35, 45];\n\t\tconst limit = 45;\n\n\t\tlet particles: CoolParticle[] = [];\n\t\tlet autoAddParticle = false;\n\t\tlet mouseX = 0;\n\t\tlet mouseY = 0;\n\n\t\tconst container = getContainer();\n\n\t\tfunction generateParticle() {\n\t\t\tconst size = options?.size || sizes[Math.floor(Math.random() * sizes.length)];\n\t\t\tconst speedHorz = options?.speedHorz || Math.random() * 10;\n\t\t\tconst speedUp = options?.speedUp || Math.random() * 25;\n\t\t\tconst spinVal = Math.random() * 360;\n\t\t\tconst spinSpeed = Math.random() * 35 * (Math.random() <= 0.5 ? -1 : 1);\n\t\t\tconst top = mouseY - size / 2;\n\t\t\tconst left = mouseX - size / 2;\n\t\t\tconst direction = Math.random() <= 0.5 ? -1 : 1;\n\n\t\t\tconst particle = document.createElement(\"div\");\n\n\t\t\tif (particleType === \"circle\") {\n\t\t\t\tconst svgNS = \"http://www.w3.org/2000/svg\";\n\t\t\t\tconst circleSVG = document.createElementNS(svgNS, \"svg\");\n\t\t\t\tconst circle = document.createElementNS(svgNS, \"circle\");\n\t\t\t\tcircle.setAttributeNS(null, \"cx\", (size / 2).toString());\n\t\t\t\tcircle.setAttributeNS(null, \"cy\", (size / 2).toString());\n\t\t\t\tcircle.setAttributeNS(null, \"r\", (size / 2).toString());\n\t\t\t\tcircle.setAttributeNS(null, \"fill\", `hsl(${Math.random() * 360}, 70%, 50%)`);\n\n\t\t\t\tcircleSVG.appendChild(circle);\n\t\t\t\tcircleSVG.setAttribute(\"width\", size.toString());\n\t\t\t\tcircleSVG.setAttribute(\"height\", size.toString());\n\n\t\t\t\tparticle.appendChild(circleSVG);\n\t\t\t} else if (particleType.startsWith(\"http\") || particleType.startsWith(\"/\")) {\n\t\t\t\t// Handle URL-based images\n\t\t\t\tparticle.innerHTML = `<img src=\"${particleType}\" width=\"${size}\" height=\"${size}\" style=\"border-radius: 50%\">`;\n\t\t\t} else {\n\t\t\t\t// Handle emoji or text characters\n\t\t\t\tconst fontSizeMultiplier = 3; // Make emojis 3x bigger\n\t\t\t\tconst emojiSize = size * fontSizeMultiplier;\n\t\t\t\tparticle.innerHTML = `<div style=\"font-size: ${emojiSize}px; line-height: 1; text-align: center; width: ${size}px; height: ${size}px; display: flex; align-items: center; justify-content: center; transform: scale(${fontSizeMultiplier}); transform-origin: center;\">${particleType}</div>`;\n\t\t\t}\n\n\t\t\tparticle.style.position = \"absolute\";\n\t\t\tparticle.style.transform = `translate3d(${left}px, ${top}px, 0px) rotate(${spinVal}deg)`;\n\n\t\t\tcontainer.appendChild(particle);\n\n\t\t\tparticles.push({\n\t\t\t\tdirection,\n\t\t\t\telement: particle,\n\t\t\t\tleft,\n\t\t\t\tsize,\n\t\t\t\tspeedHorz,\n\t\t\t\tspeedUp,\n\t\t\t\tspinSpeed,\n\t\t\t\tspinVal,\n\t\t\t\ttop,\n\t\t\t});\n\t\t}\n\n\t\tfunction refreshParticles() {\n\t\t\tparticles.forEach((p) => {\n\t\t\t\tp.left = p.left - p.speedHorz * p.direction;\n\t\t\t\tp.top = p.top - p.speedUp;\n\t\t\t\tp.speedUp = Math.min(p.size, p.speedUp - 1);\n\t\t\t\tp.spinVal = p.spinVal + p.spinSpeed;\n\n\t\t\t\tif (p.top >= Math.max(window.innerHeight, document.body.clientHeight) + p.size) {\n\t\t\t\t\tparticles = particles.filter((o) => o !== p);\n\t\t\t\t\tp.element.remove();\n\t\t\t\t}\n\n\t\t\t\tp.element.setAttribute(\n\t\t\t\t\t\"style\",\n\t\t\t\t\t[\n\t\t\t\t\t\t\"position:absolute\",\n\t\t\t\t\t\t\"will-change:transform\",\n\t\t\t\t\t\t`top:${p.top}px`,\n\t\t\t\t\t\t`left:${p.left}px`,\n\t\t\t\t\t\t`transform:rotate(${p.spinVal}deg)`,\n\t\t\t\t\t].join(\";\")\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\n\t\tlet animationFrame: number | undefined;\n\n\t\tlet lastParticleTimestamp = 0;\n\t\tconst particleGenerationDelay = 30;\n\n\t\tfunction loop() {\n\t\t\tconst currentTime = performance.now();\n\t\t\tif (\n\t\t\t\tautoAddParticle &&\n\t\t\t\tparticles.length < limit &&\n\t\t\t\tcurrentTime - lastParticleTimestamp > particleGenerationDelay\n\t\t\t) {\n\t\t\t\tgenerateParticle();\n\t\t\t\tlastParticleTimestamp = currentTime;\n\t\t\t}\n\n\t\t\trefreshParticles();\n\t\t\tanimationFrame = requestAnimationFrame(loop);\n\t\t}\n\n\t\tloop();\n\n\t\tconst isTouchInteraction = \"ontouchstart\" in window;\n\n\t\tconst tap = isTouchInteraction ? \"touchstart\" : \"mousedown\";\n\t\tconst tapEnd = isTouchInteraction ? \"touchend\" : \"mouseup\";\n\t\tconst move = isTouchInteraction ? \"touchmove\" : \"mousemove\";\n\n\t\tconst updateMousePosition = (e: MouseEvent | TouchEvent) => {\n\t\t\tif (\"touches\" in e) {\n\t\t\t\tmouseX = e.touches?.[0].clientX;\n\t\t\t\tmouseY = e.touches?.[0].clientY;\n\t\t\t} else {\n\t\t\t\tmouseX = e.clientX;\n\t\t\t\tmouseY = e.clientY;\n\t\t\t}\n\t\t};\n\n\t\tconst tapHandler = (e: MouseEvent | TouchEvent) => {\n\t\t\tupdateMousePosition(e);\n\t\t\tautoAddParticle = true;\n\t\t};\n\n\t\tconst disableAutoAddParticle = () => {\n\t\t\tautoAddParticle = false;\n\t\t};\n\n\t\telement.addEventListener(move, updateMousePosition, { passive: true });\n\t\telement.addEventListener(tap, tapHandler, { passive: true });\n\t\telement.addEventListener(tapEnd, disableAutoAddParticle, { passive: true });\n\t\telement.addEventListener(\"mouseleave\", disableAutoAddParticle, {\n\t\t\tpassive: true,\n\t\t});\n\n\t\treturn () => {\n\t\t\telement.removeEventListener(move, updateMousePosition);\n\t\t\telement.removeEventListener(tap, tapHandler);\n\t\t\telement.removeEventListener(tapEnd, disableAutoAddParticle);\n\t\t\telement.removeEventListener(\"mouseleave\", disableAutoAddParticle);\n\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (animationFrame && particles.length === 0) {\n\t\t\t\t\tcancelAnimationFrame(animationFrame);\n\t\t\t\t\tclearInterval(interval);\n\n\t\t\t\t\tif (--instanceCounter === 0) {\n\t\t\t\t\t\tcontainer.remove();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 500);\n\t\t};\n\t};\n\n\tonMount(() => {\n\t\tif (ref) {\n\t\t\tcleanup = applyParticleEffect(ref, options);\n\t\t}\n\t});\n\n\tonDestroy(() => {\n\t\tif (cleanup) {\n\t\t\tcleanup();\n\t\t}\n\t});\n</script>\n\n<span bind:this={ref}>\n\t{@render children()}\n</span>\n",
			"type": "registry:component",
			"target": "magic/cool-mode/cool-mode.svelte"
		},
		{
			"content": "export { default as CoolMode } from \"./cool-mode.svelte\";\nexport type {\n\tCoolParticleOptions,\n\tBaseParticle,\n\tCoolParticle,\n\tBaseParticleOptions,\n} from \"./cool-mode.svelte\";\n",
			"type": "registry:file",
			"target": "magic/cool-mode/index.ts"
		}
	]
}