{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "Balatro-TS-CSS",
	"title": "Balatro",
	"description": "The balatro shader, fully customizalbe and interactive.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "Balatro/Balatro.css",
			"content": ".balatro-container {\n  width: 100%;\n  height: 100%;\n}\n"
		},
		{
			"type": "registry:component",
			"path": "Balatro/Balatro.tsx",
			"content": "import { Renderer, Program, Mesh, Triangle } from 'ogl';\nimport { useEffect, useRef } from 'react';\n\nimport './Balatro.css';\n\ninterface BalatroProps {\n  spinRotation?: number;\n  spinSpeed?: number;\n  offset?: [number, number];\n  color1?: string;\n  color2?: string;\n  color3?: string;\n  contrast?: number;\n  lighting?: number;\n  spinAmount?: number;\n  pixelFilter?: number;\n  spinEase?: number;\n  isRotate?: boolean;\n  mouseInteraction?: boolean;\n}\n\nfunction hexToVec4(hex: string): [number, number, number, number] {\n  let hexStr = hex.replace('#', '');\n  let r = 0,\n    g = 0,\n    b = 0,\n    a = 1;\n  if (hexStr.length === 6) {\n    r = parseInt(hexStr.slice(0, 2), 16) / 255;\n    g = parseInt(hexStr.slice(2, 4), 16) / 255;\n    b = parseInt(hexStr.slice(4, 6), 16) / 255;\n  } else if (hexStr.length === 8) {\n    r = parseInt(hexStr.slice(0, 2), 16) / 255;\n    g = parseInt(hexStr.slice(2, 4), 16) / 255;\n    b = parseInt(hexStr.slice(4, 6), 16) / 255;\n    a = parseInt(hexStr.slice(6, 8), 16) / 255;\n  }\n  return [r, g, b, a];\n}\n\nconst vertexShader = `\nattribute vec2 uv;\nattribute vec2 position;\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  gl_Position = vec4(position, 0, 1);\n}\n`;\n\nconst fragmentShader = `\nprecision highp float;\n\n#define PI 3.14159265359\n\nuniform float iTime;\nuniform vec3 iResolution;\nuniform float uSpinRotation;\nuniform float uSpinSpeed;\nuniform vec2 uOffset;\nuniform vec4 uColor1;\nuniform vec4 uColor2;\nuniform vec4 uColor3;\nuniform float uContrast;\nuniform float uLighting;\nuniform float uSpinAmount;\nuniform float uPixelFilter;\nuniform float uSpinEase;\nuniform bool uIsRotate;\nuniform vec2 uMouse;\n\nvarying vec2 vUv;\n\nvec4 effect(vec2 screenSize, vec2 screen_coords) {\n    float pixel_size = length(screenSize.xy) / uPixelFilter;\n    vec2 uv = (floor(screen_coords.xy * (1.0 / pixel_size)) * pixel_size - 0.5 * screenSize.xy) / length(screenSize.xy) - uOffset;\n    float uv_len = length(uv);\n    \n    float speed = (uSpinRotation * uSpinEase * 0.2);\n    if(uIsRotate){\n       speed = iTime * speed;\n    }\n    speed += 302.2;\n    \n    float mouseInfluence = (uMouse.x * 2.0 - 1.0);\n    speed += mouseInfluence * 0.1;\n    \n    float new_pixel_angle = atan(uv.y, uv.x) + speed - uSpinEase * 20.0 * (uSpinAmount * uv_len + (1.0 - uSpinAmount));\n    vec2 mid = (screenSize.xy / length(screenSize.xy)) / 2.0;\n    uv = (vec2(uv_len * cos(new_pixel_angle) + mid.x, uv_len * sin(new_pixel_angle) + mid.y) - mid);\n    \n    uv *= 30.0;\n    float baseSpeed = iTime * uSpinSpeed;\n    speed = baseSpeed + mouseInfluence * 2.0;\n    \n    vec2 uv2 = vec2(uv.x + uv.y);\n    \n    for(int i = 0; i < 5; i++) {\n        uv2 += sin(max(uv.x, uv.y)) + uv;\n        uv += 0.5 * vec2(\n            cos(5.1123314 + 0.353 * uv2.y + speed * 0.131121),\n            sin(uv2.x - 0.113 * speed)\n        );\n        uv -= cos(uv.x + uv.y) - sin(uv.x * 0.711 - uv.y);\n    }\n    \n    float contrast_mod = (0.25 * uContrast + 0.5 * uSpinAmount + 1.2);\n    float paint_res = min(2.0, max(0.0, length(uv) * 0.035 * contrast_mod));\n    float c1p = max(0.0, 1.0 - contrast_mod * abs(1.0 - paint_res));\n    float c2p = max(0.0, 1.0 - contrast_mod * abs(paint_res));\n    float c3p = 1.0 - min(1.0, c1p + c2p);\n    float light = (uLighting - 0.2) * max(c1p * 5.0 - 4.0, 0.0) + uLighting * max(c2p * 5.0 - 4.0, 0.0);\n    \n    return (0.3 / uContrast) * uColor1 + (1.0 - 0.3 / uContrast) * (uColor1 * c1p + uColor2 * c2p + vec4(c3p * uColor3.rgb, c3p * uColor1.a)) + light;\n}\n\nvoid main() {\n    vec2 uv = vUv * iResolution.xy;\n    gl_FragColor = effect(iResolution.xy, uv);\n}\n`;\n\nexport default function Balatro({\n  spinRotation = -2.0,\n  spinSpeed = 7.0,\n  offset = [0.0, 0.0],\n  color1 = '#DE443B',\n  color2 = '#006BB4',\n  color3 = '#162325',\n  contrast = 3.5,\n  lighting = 0.4,\n  spinAmount = 0.25,\n  pixelFilter = 745.0,\n  spinEase = 1.0,\n  isRotate = false,\n  mouseInteraction = true\n}: BalatroProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    if (!containerRef.current) return;\n    const container = containerRef.current;\n    const renderer = new Renderer();\n    const gl = renderer.gl;\n    gl.clearColor(0, 0, 0, 1);\n\n    let program: Program;\n\n    function resize() {\n      renderer.setSize(container.offsetWidth, container.offsetHeight);\n      if (program) {\n        program.uniforms.iResolution.value = [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height];\n      }\n    }\n    window.addEventListener('resize', resize);\n    resize();\n\n    const geometry = new Triangle(gl);\n    program = new Program(gl, {\n      vertex: vertexShader,\n      fragment: fragmentShader,\n      uniforms: {\n        iTime: { value: 0 },\n        iResolution: {\n          value: [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height]\n        },\n        uSpinRotation: { value: spinRotation },\n        uSpinSpeed: { value: spinSpeed },\n        uOffset: { value: offset },\n        uColor1: { value: hexToVec4(color1) },\n        uColor2: { value: hexToVec4(color2) },\n        uColor3: { value: hexToVec4(color3) },\n        uContrast: { value: contrast },\n        uLighting: { value: lighting },\n        uSpinAmount: { value: spinAmount },\n        uPixelFilter: { value: pixelFilter },\n        uSpinEase: { value: spinEase },\n        uIsRotate: { value: isRotate },\n        uMouse: { value: [0.5, 0.5] }\n      }\n    });\n\n    const mesh = new Mesh(gl, { geometry, program });\n    let animationFrameId: number;\n\n    function update(time: number) {\n      animationFrameId = requestAnimationFrame(update);\n      program.uniforms.iTime.value = time * 0.001;\n      renderer.render({ scene: mesh });\n    }\n    animationFrameId = requestAnimationFrame(update);\n    container.appendChild(gl.canvas);\n\n    function handleMouseMove(e: MouseEvent) {\n      if (!mouseInteraction) return;\n      const rect = container.getBoundingClientRect();\n      const x = (e.clientX - rect.left) / rect.width;\n      const y = 1.0 - (e.clientY - rect.top) / rect.height;\n      program.uniforms.uMouse.value = [x, y];\n    }\n    container.addEventListener('mousemove', handleMouseMove);\n\n    return () => {\n      cancelAnimationFrame(animationFrameId);\n      window.removeEventListener('resize', resize);\n      container.removeEventListener('mousemove', handleMouseMove);\n      container.removeChild(gl.canvas);\n      gl.getExtension('WEBGL_lose_context')?.loseContext();\n    };\n  }, [\n    spinRotation,\n    spinSpeed,\n    offset,\n    color1,\n    color2,\n    color3,\n    contrast,\n    lighting,\n    spinAmount,\n    pixelFilter,\n    spinEase,\n    isRotate,\n    mouseInteraction\n  ]);\n\n  return <div ref={containerRef} className=\"balatro-container\" />;\n}\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"ogl@^1.0.11"
	]
}