{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dither",
  "type": "registry:block",
  "title": "Dither",
  "description": "Dither",
  "files": [
    {
      "path": "components/usages/ditherusage.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\n\nimport Dither from \"@/registry/open-source/dither\";\n\nexport default function Usage() {\n\treturn (\n\t\t<div className=\"h-screen w-full flex items-center justify-center relative overflow-hidden bg-background\">\n\t\t\t<section>\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\theight: \"600px\",\n\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Dither\n\t\t\t\t\t\twaveColor={[0.5, 0.5, 0.5]}\n\t\t\t\t\t\tdisableAnimation={false}\n\t\t\t\t\t\tenableMouseInteraction={true}\n\t\t\t\t\t\tmouseRadius={0.3}\n\t\t\t\t\t\tcolorNum={4}\n\t\t\t\t\t\twaveAmplitude={0.3}\n\t\t\t\t\t\twaveFrequency={3}\n\t\t\t\t\t\twaveSpeed={0.05}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</section>{\" \"}\n\t\t</div>\n\t);\n}\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/ditherusage.tsx",
      "content": "\"use client\";\n\nimport React from \"react\";\n\nimport Dither from \"@/registry/open-source/dither\";\n\nexport default function Usage() {\n\treturn (\n\t\t<div className=\"h-screen w-full flex items-center justify-center relative overflow-hidden bg-background\">\n\t\t\t<section>\n\t\t\t\t<div\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\theight: \"600px\",\n\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Dither\n\t\t\t\t\t\twaveColor={[0.5, 0.5, 0.5]}\n\t\t\t\t\t\tdisableAnimation={false}\n\t\t\t\t\t\tenableMouseInteraction={true}\n\t\t\t\t\t\tmouseRadius={0.3}\n\t\t\t\t\t\tcolorNum={4}\n\t\t\t\t\t\twaveAmplitude={0.3}\n\t\t\t\t\t\twaveFrequency={3}\n\t\t\t\t\t\twaveSpeed={0.05}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</section>{\" \"}\n\t\t</div>\n\t);\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/dither.tsx",
      "content": "/* eslint-disable react/no-unknown-property */\nimport { forwardRef, useEffect, useRef } from \"react\";\n\nimport { Canvas, ThreeEvent, useFrame, useThree } from \"@react-three/fiber\";\nimport { EffectComposer, wrapEffect } from \"@react-three/postprocessing\";\nimport { Effect } from \"postprocessing\";\nimport * as THREE from \"three\";\n\n// Credit:\n// https://www.reactbits.dev/backgrounds/dither\n\nconst waveVertexShader = `\nprecision highp float;\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  vec4 modelPosition = modelMatrix * vec4(position, 1.0);\n  vec4 viewPosition = viewMatrix * modelPosition;\n  gl_Position = projectionMatrix * viewPosition;\n}\n`;\n\nconst waveFragmentShader = `\nprecision highp float;\nuniform vec2 resolution;\nuniform float time;\nuniform float waveSpeed;\nuniform float waveFrequency;\nuniform float waveAmplitude;\nuniform vec3 waveColor;\nuniform vec2 mousePos;\nuniform int enableMouseInteraction;\nuniform float mouseRadius;\n\nvec4 mod289(vec4 x) { return x - floor(x * (1.0/289.0)) * 289.0; }\nvec4 permute(vec4 x) { return mod289(((x * 34.0) + 1.0) * x); }\nvec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\nvec2 fade(vec2 t) { return t*t*t*(t*(t*6.0-15.0)+10.0); }\n\nfloat cnoise(vec2 P) {\n  vec4 Pi = floor(P.xyxy) + vec4(0.0,0.0,1.0,1.0);\n  vec4 Pf = fract(P.xyxy) - vec4(0.0,0.0,1.0,1.0);\n  Pi = mod289(Pi);\n  vec4 ix = Pi.xzxz;\n  vec4 iy = Pi.yyww;\n  vec4 fx = Pf.xzxz;\n  vec4 fy = Pf.yyww;\n  vec4 i = permute(permute(ix) + iy);\n  vec4 gx = fract(i * (1.0/41.0)) * 2.0 - 1.0;\n  vec4 gy = abs(gx) - 0.5;\n  vec4 tx = floor(gx + 0.5);\n  gx = gx - tx;\n  vec2 g00 = vec2(gx.x, gy.x);\n  vec2 g10 = vec2(gx.y, gy.y);\n  vec2 g01 = vec2(gx.z, gy.z);\n  vec2 g11 = vec2(gx.w, gy.w);\n  vec4 norm = taylorInvSqrt(vec4(dot(g00,g00), dot(g01,g01), dot(g10,g10), dot(g11,g11)));\n  g00 *= norm.x; g01 *= norm.y; g10 *= norm.z; g11 *= norm.w;\n  float n00 = dot(g00, vec2(fx.x, fy.x));\n  float n10 = dot(g10, vec2(fx.y, fy.y));\n  float n01 = dot(g01, vec2(fx.z, fy.z));\n  float n11 = dot(g11, vec2(fx.w, fy.w));\n  vec2 fade_xy = fade(Pf.xy);\n  vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);\n  return 2.3 * mix(n_x.x, n_x.y, fade_xy.y);\n}\n\nconst int OCTAVES = 4;\nfloat fbm(vec2 p) {\n  float value = 0.0;\n  float amp = 1.0;\n  float freq = waveFrequency;\n  for (int i = 0; i < OCTAVES; i++) {\n    value += amp * abs(cnoise(p));\n    p *= freq;\n    amp *= waveAmplitude;\n  }\n  return value;\n}\n\nfloat pattern(vec2 p) {\n  vec2 p2 = p - time * waveSpeed;\n  return fbm(p + fbm(p2)); \n}\n\nvoid main() {\n  vec2 uv = gl_FragCoord.xy / resolution.xy;\n  uv -= 0.5;\n  uv.x *= resolution.x / resolution.y;\n  float f = pattern(uv);\n  if (enableMouseInteraction == 1) {\n    vec2 mouseNDC = (mousePos / resolution - 0.5) * vec2(1.0, -1.0);\n    mouseNDC.x *= resolution.x / resolution.y;\n    float dist = length(uv - mouseNDC);\n    float effect = 1.0 - smoothstep(0.0, mouseRadius, dist);\n    f -= 0.5 * effect;\n  }\n  vec3 col = mix(vec3(0.0), waveColor, f);\n  gl_FragColor = vec4(col, 1.0);\n}\n`;\n\nconst ditherFragmentShader = `\nprecision highp float;\nuniform float colorNum;\nuniform float pixelSize;\nconst float bayerMatrix8x8[64] = float[64](\n  0.0/64.0, 48.0/64.0, 12.0/64.0, 60.0/64.0,  3.0/64.0, 51.0/64.0, 15.0/64.0, 63.0/64.0,\n  32.0/64.0,16.0/64.0, 44.0/64.0, 28.0/64.0, 35.0/64.0,19.0/64.0, 47.0/64.0, 31.0/64.0,\n  8.0/64.0, 56.0/64.0,  4.0/64.0, 52.0/64.0, 11.0/64.0,59.0/64.0,  7.0/64.0, 55.0/64.0,\n  40.0/64.0,24.0/64.0, 36.0/64.0, 20.0/64.0, 43.0/64.0,27.0/64.0, 39.0/64.0, 23.0/64.0,\n  2.0/64.0, 50.0/64.0, 14.0/64.0, 62.0/64.0,  1.0/64.0,49.0/64.0, 13.0/64.0, 61.0/64.0,\n  34.0/64.0,18.0/64.0, 46.0/64.0, 30.0/64.0, 33.0/64.0,17.0/64.0, 45.0/64.0, 29.0/64.0,\n  10.0/64.0,58.0/64.0,  6.0/64.0, 54.0/64.0,  9.0/64.0,57.0/64.0,  5.0/64.0, 53.0/64.0,\n  42.0/64.0,26.0/64.0, 38.0/64.0, 22.0/64.0, 41.0/64.0,25.0/64.0, 37.0/64.0, 21.0/64.0\n);\n\nvec3 dither(vec2 uv, vec3 color) {\n  vec2 scaledCoord = floor(uv * resolution / pixelSize);\n  int x = int(mod(scaledCoord.x, 8.0));\n  int y = int(mod(scaledCoord.y, 8.0));\n  float threshold = bayerMatrix8x8[y * 8 + x] - 0.25;\n  float step = 1.0 / (colorNum - 1.0);\n  color += threshold * step;\n  float bias = 0.2;\n  color = clamp(color - bias, 0.0, 1.0);\n  return floor(color * (colorNum - 1.0) + 0.5) / (colorNum - 1.0);\n}\n\nvoid mainImage(in vec4 inputColor, in vec2 uv, out vec4 outputColor) {\n  vec2 normalizedPixelSize = pixelSize / resolution;\n  vec2 uvPixel = normalizedPixelSize * floor(uv / normalizedPixelSize);\n  vec4 color = texture2D(inputBuffer, uvPixel);\n  color.rgb = dither(uv, color.rgb);\n  outputColor = color;\n}\n`;\n\nclass RetroEffectImpl extends Effect {\n\tpublic uniforms: Map<string, THREE.Uniform<any>>;\n\tconstructor() {\n\t\tconst uniforms = new Map<string, THREE.Uniform<any>>([\n\t\t\t[\"colorNum\", new THREE.Uniform(4.0)],\n\t\t\t[\"pixelSize\", new THREE.Uniform(2.0)],\n\t\t]);\n\t\tsuper(\"RetroEffect\", ditherFragmentShader, { uniforms });\n\t\tthis.uniforms = uniforms;\n\t}\n\tset colorNum(value: number) {\n\t\tthis.uniforms.get(\"colorNum\")!.value = value;\n\t}\n\tget colorNum(): number {\n\t\treturn this.uniforms.get(\"colorNum\")!.value;\n\t}\n\tset pixelSize(value: number) {\n\t\tthis.uniforms.get(\"pixelSize\")!.value = value;\n\t}\n\tget pixelSize(): number {\n\t\treturn this.uniforms.get(\"pixelSize\")!.value;\n\t}\n}\n\nconst RetroEffect = forwardRef<\n\tRetroEffectImpl,\n\t{ colorNum: number; pixelSize: number }\n>((props, ref) => {\n\tconst { colorNum, pixelSize } = props;\n\tconst WrappedRetroEffect = wrapEffect(RetroEffectImpl);\n\treturn (\n\t\t<WrappedRetroEffect ref={ref} colorNum={colorNum} pixelSize={pixelSize} />\n\t);\n});\n\nRetroEffect.displayName = \"RetroEffect\";\n\ninterface WaveUniforms {\n\t[key: string]: THREE.Uniform<any>;\n\ttime: THREE.Uniform<number>;\n\tresolution: THREE.Uniform<THREE.Vector2>;\n\twaveSpeed: THREE.Uniform<number>;\n\twaveFrequency: THREE.Uniform<number>;\n\twaveAmplitude: THREE.Uniform<number>;\n\twaveColor: THREE.Uniform<THREE.Color>;\n\tmousePos: THREE.Uniform<THREE.Vector2>;\n\tenableMouseInteraction: THREE.Uniform<number>;\n\tmouseRadius: THREE.Uniform<number>;\n}\n\ninterface DitheredWavesProps {\n\twaveSpeed: number;\n\twaveFrequency: number;\n\twaveAmplitude: number;\n\twaveColor: [number, number, number];\n\tcolorNum: number;\n\tpixelSize: number;\n\tdisableAnimation: boolean;\n\tenableMouseInteraction: boolean;\n\tmouseRadius: number;\n}\n\nfunction DitheredWaves({\n\twaveSpeed,\n\twaveFrequency,\n\twaveAmplitude,\n\twaveColor,\n\tcolorNum,\n\tpixelSize,\n\tdisableAnimation,\n\tenableMouseInteraction,\n\tmouseRadius,\n}: DitheredWavesProps) {\n\tconst mesh = useRef<THREE.Mesh>(null);\n\tconst mouseRef = useRef(new THREE.Vector2());\n\tconst { viewport, size, gl } = useThree();\n\n\tconst waveUniformsRef = useRef<WaveUniforms>({\n\t\ttime: new THREE.Uniform(0),\n\t\tresolution: new THREE.Uniform(new THREE.Vector2(0, 0)),\n\t\twaveSpeed: new THREE.Uniform(waveSpeed),\n\t\twaveFrequency: new THREE.Uniform(waveFrequency),\n\t\twaveAmplitude: new THREE.Uniform(waveAmplitude),\n\t\twaveColor: new THREE.Uniform(new THREE.Color(...waveColor)),\n\t\tmousePos: new THREE.Uniform(new THREE.Vector2(0, 0)),\n\t\tenableMouseInteraction: new THREE.Uniform(enableMouseInteraction ? 1 : 0),\n\t\tmouseRadius: new THREE.Uniform(mouseRadius),\n\t});\n\n\tuseEffect(() => {\n\t\tconst dpr = gl.getPixelRatio();\n\t\tconst newWidth = Math.floor(size.width * dpr);\n\t\tconst newHeight = Math.floor(size.height * dpr);\n\t\tconst currentRes = waveUniformsRef.current.resolution.value;\n\t\tif (currentRes.x !== newWidth || currentRes.y !== newHeight) {\n\t\t\tcurrentRes.set(newWidth, newHeight);\n\t\t}\n\t}, [size, gl]);\n\n\tconst prevColor = useRef([...waveColor]);\n\tuseFrame(({ clock }) => {\n\t\tconst u = waveUniformsRef.current;\n\n\t\tif (!disableAnimation) {\n\t\t\tu.time.value = clock.getElapsedTime();\n\t\t}\n\n\t\tif (u.waveSpeed.value !== waveSpeed) u.waveSpeed.value = waveSpeed;\n\t\tif (u.waveFrequency.value !== waveFrequency)\n\t\t\tu.waveFrequency.value = waveFrequency;\n\t\tif (u.waveAmplitude.value !== waveAmplitude)\n\t\t\tu.waveAmplitude.value = waveAmplitude;\n\n\t\tif (!prevColor.current.every((v, i) => v === waveColor[i])) {\n\t\t\tu.waveColor.value.set(...waveColor);\n\t\t\tprevColor.current = [...waveColor];\n\t\t}\n\n\t\tu.enableMouseInteraction.value = enableMouseInteraction ? 1 : 0;\n\t\tu.mouseRadius.value = mouseRadius;\n\n\t\tif (enableMouseInteraction) {\n\t\t\tu.mousePos.value.copy(mouseRef.current);\n\t\t}\n\t});\n\n\tconst handlePointerMove = (e: ThreeEvent<PointerEvent>) => {\n\t\tif (!enableMouseInteraction) return;\n\t\tconst rect = gl.domElement.getBoundingClientRect();\n\t\tconst dpr = gl.getPixelRatio();\n\t\tmouseRef.current.set(\n\t\t\t(e.clientX - rect.left) * dpr,\n\t\t\t(e.clientY - rect.top) * dpr\n\t\t);\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<mesh ref={mesh} scale={[viewport.width, viewport.height, 1]}>\n\t\t\t\t<planeGeometry args={[1, 1]} />\n\t\t\t\t<shaderMaterial\n\t\t\t\t\tvertexShader={waveVertexShader}\n\t\t\t\t\tfragmentShader={waveFragmentShader}\n\t\t\t\t\tuniforms={waveUniformsRef.current}\n\t\t\t\t/>\n\t\t\t</mesh>\n\n\t\t\t<EffectComposer>\n\t\t\t\t<RetroEffect colorNum={colorNum} pixelSize={pixelSize} />\n\t\t\t</EffectComposer>\n\n\t\t\t<mesh\n\t\t\t\tonPointerMove={handlePointerMove}\n\t\t\t\tposition={[0, 0, 0.01]}\n\t\t\t\tscale={[viewport.width, viewport.height, 1]}\n\t\t\t\tvisible={false}\n\t\t\t>\n\t\t\t\t<planeGeometry args={[1, 1]} />\n\t\t\t\t<meshBasicMaterial transparent opacity={0} />\n\t\t\t</mesh>\n\t\t</>\n\t);\n}\n\ninterface DitherProps {\n\twaveSpeed?: number;\n\twaveFrequency?: number;\n\twaveAmplitude?: number;\n\twaveColor?: [number, number, number];\n\tcolorNum?: number;\n\tpixelSize?: number;\n\tdisableAnimation?: boolean;\n\tenableMouseInteraction?: boolean;\n\tmouseRadius?: number;\n}\n\nexport default function Dither({\n\twaveSpeed = 0.05,\n\twaveFrequency = 3,\n\twaveAmplitude = 0.3,\n\twaveColor = [0.5, 0.5, 0.5],\n\tcolorNum = 4,\n\tpixelSize = 2,\n\tdisableAnimation = false,\n\tenableMouseInteraction = true,\n\tmouseRadius = 1,\n}: DitherProps) {\n\treturn (\n\t\t<Canvas\n\t\t\tclassName=\"w-full h-full relative\"\n\t\t\tcamera={{ position: [0, 0, 6] }}\n\t\t\tdpr={window.devicePixelRatio}\n\t\t\tgl={{ antialias: true, preserveDrawingBuffer: true }}\n\t\t>\n\t\t\t<DitheredWaves\n\t\t\t\twaveSpeed={waveSpeed}\n\t\t\t\twaveFrequency={waveFrequency}\n\t\t\t\twaveAmplitude={waveAmplitude}\n\t\t\t\twaveColor={waveColor}\n\t\t\t\tcolorNum={colorNum}\n\t\t\t\tpixelSize={pixelSize}\n\t\t\t\tdisableAnimation={disableAnimation}\n\t\t\t\tenableMouseInteraction={enableMouseInteraction}\n\t\t\t\tmouseRadius={mouseRadius}\n\t\t\t/>\n\t\t</Canvas>\n\t);\n}\n",
      "type": "registry:ui"
    }
  ]
}