{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "faulty-terminal",
  "type": "registry:block",
  "title": "Faulty terminal",
  "description": "Faulty terminal",
  "files": [
    {
      "path": "components/usages/faultyterminalusage.tsx",
      "content": "import FaultyTerminal from \"@/registry/open-source/faulty-terminal\";\n\nexport default function Usage() {\n\treturn (\n\t\t<div style={{ width: \"100%\", height: \"600px\", position: \"relative\" }}>\n\t\t\t<FaultyTerminal\n\t\t\t\tscale={1.5}\n\t\t\t\tgridMul={[2, 1]}\n\t\t\t\tdigitSize={1.2}\n\t\t\t\ttimeScale={1}\n\t\t\t\tpause={false}\n\t\t\t\tscanlineIntensity={1}\n\t\t\t\tglitchAmount={1}\n\t\t\t\tflickerAmount={1}\n\t\t\t\tnoiseAmp={1}\n\t\t\t\tchromaticAberration={0}\n\t\t\t\tdither={0}\n\t\t\t\tcurvature={0}\n\t\t\t\ttint=\"#ffffff\"\n\t\t\t\tmouseReact={true}\n\t\t\t\tmouseStrength={0.5}\n\t\t\t\tpageLoadAnimation={false}\n\t\t\t\tbrightness={1}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/faultyterminalusage.tsx",
      "content": "import FaultyTerminal from \"@/registry/open-source/faulty-terminal\";\n\nexport default function Usage() {\n\treturn (\n\t\t<div style={{ width: \"100%\", height: \"600px\", position: \"relative\" }}>\n\t\t\t<FaultyTerminal\n\t\t\t\tscale={1.5}\n\t\t\t\tgridMul={[2, 1]}\n\t\t\t\tdigitSize={1.2}\n\t\t\t\ttimeScale={1}\n\t\t\t\tpause={false}\n\t\t\t\tscanlineIntensity={1}\n\t\t\t\tglitchAmount={1}\n\t\t\t\tflickerAmount={1}\n\t\t\t\tnoiseAmp={1}\n\t\t\t\tchromaticAberration={0}\n\t\t\t\tdither={0}\n\t\t\t\tcurvature={0}\n\t\t\t\ttint=\"#ffffff\"\n\t\t\t\tmouseReact={true}\n\t\t\t\tmouseStrength={0.5}\n\t\t\t\tpageLoadAnimation={false}\n\t\t\t\tbrightness={1}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/faulty-terminal.tsx",
      "content": "import React, { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport { Color, Mesh, Program, Renderer, Triangle } from \"ogl\";\n\ntype Vec2 = [number, number];\n\nexport interface FaultyTerminalProps\n\textends React.HTMLAttributes<HTMLDivElement> {\n\tscale?: number;\n\tgridMul?: Vec2;\n\tdigitSize?: number;\n\ttimeScale?: number;\n\tpause?: boolean;\n\tscanlineIntensity?: number;\n\tglitchAmount?: number;\n\tflickerAmount?: number;\n\tnoiseAmp?: number;\n\tchromaticAberration?: number;\n\tdither?: number | boolean;\n\tcurvature?: number;\n\ttint?: string;\n\tmouseReact?: boolean;\n\tmouseStrength?: number;\n\tdpr?: number;\n\tpageLoadAnimation?: boolean;\n\tbrightness?: number;\n}\n\nconst vertexShader = `\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst fragmentShader = `\nprecision mediump float;\n\nvarying vec2 vUv;\n\nuniform float iTime;\nuniform vec3  iResolution;\nuniform float uScale;\n\nuniform vec2  uGridMul;\nuniform float uDigitSize;\nuniform float uScanlineIntensity;\nuniform float uGlitchAmount;\nuniform float uFlickerAmount;\nuniform float uNoiseAmp;\nuniform float uChromaticAberration;\nuniform float uDither;\nuniform float uCurvature;\nuniform vec3  uTint;\nuniform vec2  uMouse;\nuniform float uMouseStrength;\nuniform float uUseMouse;\nuniform float uPageLoadProgress;\nuniform float uUsePageLoadAnimation;\nuniform float uBrightness;\n\nfloat time;\n\nfloat hash21(vec2 p){\n  p = fract(p * 234.56);\n  p += dot(p, p + 34.56);\n  return fract(p.x * p.y);\n}\n\nfloat noise(vec2 p)\n{\n  return sin(p.x * 10.0) * sin(p.y * (3.0 + sin(time * 0.090909))) + 0.2; \n}\n\nmat2 rotate(float angle)\n{\n  float c = cos(angle);\n  float s = sin(angle);\n  return mat2(c, -s, s, c);\n}\n\nfloat fbm(vec2 p)\n{\n  p *= 1.1;\n  float f = 0.0;\n  float amp = 0.5 * uNoiseAmp;\n  \n  mat2 modify0 = rotate(time * 0.02);\n  f += amp * noise(p);\n  p = modify0 * p * 2.0;\n  amp *= 0.454545; // 1/2.2\n  \n  mat2 modify1 = rotate(time * 0.02);\n  f += amp * noise(p);\n  p = modify1 * p * 2.0;\n  amp *= 0.454545;\n  \n  mat2 modify2 = rotate(time * 0.08);\n  f += amp * noise(p);\n  \n  return f;\n}\n\nfloat pattern(vec2 p, out vec2 q, out vec2 r) {\n  vec2 offset1 = vec2(1.0);\n  vec2 offset0 = vec2(0.0);\n  mat2 rot01 = rotate(0.1 * time);\n  mat2 rot1 = rotate(0.1);\n  \n  q = vec2(fbm(p + offset1), fbm(rot01 * p + offset1));\n  r = vec2(fbm(rot1 * q + offset0), fbm(q + offset0));\n  return fbm(p + r);\n}\n\nfloat digit(vec2 p){\n    vec2 grid = uGridMul * 15.0;\n    vec2 s = floor(p * grid) / grid;\n    p = p * grid;\n    vec2 q, r;\n    float intensity = pattern(s * 0.1, q, r) * 1.3 - 0.03;\n    \n    if(uUseMouse > 0.5){\n        vec2 mouseWorld = uMouse * uScale;\n        float distToMouse = distance(s, mouseWorld);\n        float mouseInfluence = exp(-distToMouse * 8.0) * uMouseStrength * 10.0;\n        intensity += mouseInfluence;\n        \n        float ripple = sin(distToMouse * 20.0 - iTime * 5.0) * 0.1 * mouseInfluence;\n        intensity += ripple;\n    }\n    \n    if(uUsePageLoadAnimation > 0.5){\n        float cellRandom = fract(sin(dot(s, vec2(12.9898, 78.233))) * 43758.5453);\n        float cellDelay = cellRandom * 0.8;\n        float cellProgress = clamp((uPageLoadProgress - cellDelay) / 0.2, 0.0, 1.0);\n        \n        float fadeAlpha = smoothstep(0.0, 1.0, cellProgress);\n        intensity *= fadeAlpha;\n    }\n    \n    p = fract(p);\n    p *= uDigitSize;\n    \n    float px5 = p.x * 5.0;\n    float py5 = (1.0 - p.y) * 5.0;\n    float x = fract(px5);\n    float y = fract(py5);\n    \n    float i = floor(py5) - 2.0;\n    float j = floor(px5) - 2.0;\n    float n = i * i + j * j;\n    float f = n * 0.0625;\n    \n    float isOn = step(0.1, intensity - f);\n    float brightness = isOn * (0.2 + y * 0.8) * (0.75 + x * 0.25);\n    \n    return step(0.0, p.x) * step(p.x, 1.0) * step(0.0, p.y) * step(p.y, 1.0) * brightness;\n}\n\nfloat onOff(float a, float b, float c)\n{\n  return step(c, sin(iTime + a * cos(iTime * b))) * uFlickerAmount;\n}\n\nfloat displace(vec2 look)\n{\n    float y = look.y - mod(iTime * 0.25, 1.0);\n    float window = 1.0 / (1.0 + 50.0 * y * y);\n    return sin(look.y * 20.0 + iTime) * 0.0125 * onOff(4.0, 2.0, 0.8) * (1.0 + cos(iTime * 60.0)) * window;\n}\n\nvec3 getColor(vec2 p){\n    \n    float bar = step(mod(p.y + time * 20.0, 1.0), 0.2) * 0.4 + 1.0; // more efficient than ternary\n    bar *= uScanlineIntensity;\n    \n    float displacement = displace(p);\n    p.x += displacement;\n\n    if (uGlitchAmount != 1.0) {\n      float extra = displacement * (uGlitchAmount - 1.0);\n      p.x += extra;\n    }\n\n    float middle = digit(p);\n    \n    const float off = 0.002;\n    float sum = digit(p + vec2(-off, -off)) + digit(p + vec2(0.0, -off)) + digit(p + vec2(off, -off)) +\n                digit(p + vec2(-off, 0.0)) + digit(p + vec2(0.0, 0.0)) + digit(p + vec2(off, 0.0)) +\n                digit(p + vec2(-off, off)) + digit(p + vec2(0.0, off)) + digit(p + vec2(off, off));\n    \n    vec3 baseColor = vec3(0.9) * middle + sum * 0.1 * vec3(1.0) * bar;\n    return baseColor;\n}\n\nvec2 barrel(vec2 uv){\n  vec2 c = uv * 2.0 - 1.0;\n  float r2 = dot(c, c);\n  c *= 1.0 + uCurvature * r2;\n  return c * 0.5 + 0.5;\n}\n\nvoid main() {\n    time = iTime * 0.333333;\n    vec2 uv = vUv;\n\n    if(uCurvature != 0.0){\n      uv = barrel(uv);\n    }\n    \n    vec2 p = uv * uScale;\n    vec3 col = getColor(p);\n\n    if(uChromaticAberration != 0.0){\n      vec2 ca = vec2(uChromaticAberration) / iResolution.xy;\n      col.r = getColor(p + ca).r;\n      col.b = getColor(p - ca).b;\n    }\n\n    col *= uTint;\n    col *= uBrightness;\n\n    if(uDither > 0.0){\n      float rnd = hash21(gl_FragCoord.xy);\n      col += (rnd - 0.5) * (uDither * 0.003922);\n    }\n\n    gl_FragColor = vec4(col, 1.0);\n}\n`;\n\nfunction hexToRgb(hex: string): [number, number, number] {\n\tlet h = hex.replace(\"#\", \"\").trim();\n\tif (h.length === 3)\n\t\th = h\n\t\t\t.split(\"\")\n\t\t\t.map((c) => c + c)\n\t\t\t.join(\"\");\n\tconst num = parseInt(h, 16);\n\treturn [\n\t\t((num >> 16) & 255) / 255,\n\t\t((num >> 8) & 255) / 255,\n\t\t(num & 255) / 255,\n\t];\n}\n\nexport default function FaultyTerminal({\n\tscale = 1,\n\tgridMul = [2, 1],\n\tdigitSize = 1.5,\n\ttimeScale = 0.3,\n\tpause = false,\n\tscanlineIntensity = 0.3,\n\tglitchAmount = 1,\n\tflickerAmount = 1,\n\tnoiseAmp = 1,\n\tchromaticAberration = 0,\n\tdither = 0,\n\tcurvature = 0.2,\n\ttint = \"#ffffff\",\n\tmouseReact = true,\n\tmouseStrength = 0.2,\n\tdpr = Math.min(window.devicePixelRatio || 1, 2),\n\tpageLoadAnimation = true,\n\tbrightness = 1,\n\tclassName,\n\tstyle,\n\t...rest\n}: FaultyTerminalProps) {\n\tconst containerRef = useRef<HTMLDivElement>(null);\n\tconst programRef = useRef<Program>(null);\n\tconst rendererRef = useRef<Renderer>(null);\n\tconst mouseRef = useRef({ x: 0.5, y: 0.5 });\n\tconst smoothMouseRef = useRef({ x: 0.5, y: 0.5 });\n\tconst frozenTimeRef = useRef(0);\n\tconst rafRef = useRef<number>(0);\n\tconst loadAnimationStartRef = useRef<number>(0);\n\tconst timeOffsetRef = useRef<number>(Math.random() * 100);\n\n\tconst tintVec = useMemo(() => hexToRgb(tint), [tint]);\n\n\tconst ditherValue = useMemo(\n\t\t() => (typeof dither === \"boolean\" ? (dither ? 1 : 0) : dither),\n\t\t[dither]\n\t);\n\n\tconst handleMouseMove = useCallback((e: MouseEvent) => {\n\t\tconst ctn = containerRef.current;\n\t\tif (!ctn) return;\n\t\tconst rect = ctn.getBoundingClientRect();\n\t\tconst x = (e.clientX - rect.left) / rect.width;\n\t\tconst y = 1 - (e.clientY - rect.top) / rect.height;\n\t\tmouseRef.current = { x, y };\n\t}, []);\n\n\tuseEffect(() => {\n\t\tconst ctn = containerRef.current;\n\t\tif (!ctn) return;\n\n\t\tconst renderer = new Renderer({ dpr });\n\t\trendererRef.current = renderer;\n\t\tconst gl = renderer.gl;\n\t\tgl.clearColor(0, 0, 0, 1);\n\n\t\tconst geometry = new Triangle(gl);\n\n\t\tconst program = new Program(gl, {\n\t\t\tvertex: vertexShader,\n\t\t\tfragment: fragmentShader,\n\t\t\tuniforms: {\n\t\t\t\tiTime: { value: 0 },\n\t\t\t\tiResolution: {\n\t\t\t\t\tvalue: new Color(\n\t\t\t\t\t\tgl.canvas.width,\n\t\t\t\t\t\tgl.canvas.height,\n\t\t\t\t\t\tgl.canvas.width / gl.canvas.height\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\tuScale: { value: scale },\n\n\t\t\t\tuGridMul: { value: new Float32Array(gridMul) },\n\t\t\t\tuDigitSize: { value: digitSize },\n\t\t\t\tuScanlineIntensity: { value: scanlineIntensity },\n\t\t\t\tuGlitchAmount: { value: glitchAmount },\n\t\t\t\tuFlickerAmount: { value: flickerAmount },\n\t\t\t\tuNoiseAmp: { value: noiseAmp },\n\t\t\t\tuChromaticAberration: { value: chromaticAberration },\n\t\t\t\tuDither: { value: ditherValue },\n\t\t\t\tuCurvature: { value: curvature },\n\t\t\t\tuTint: { value: new Color(tintVec[0], tintVec[1], tintVec[2]) },\n\t\t\t\tuMouse: {\n\t\t\t\t\tvalue: new Float32Array([\n\t\t\t\t\t\tsmoothMouseRef.current.x,\n\t\t\t\t\t\tsmoothMouseRef.current.y,\n\t\t\t\t\t]),\n\t\t\t\t},\n\t\t\t\tuMouseStrength: { value: mouseStrength },\n\t\t\t\tuUseMouse: { value: mouseReact ? 1 : 0 },\n\t\t\t\tuPageLoadProgress: { value: pageLoadAnimation ? 0 : 1 },\n\t\t\t\tuUsePageLoadAnimation: { value: pageLoadAnimation ? 1 : 0 },\n\t\t\t\tuBrightness: { value: brightness },\n\t\t\t},\n\t\t});\n\t\tprogramRef.current = program;\n\n\t\tconst mesh = new Mesh(gl, { geometry, program });\n\n\t\tfunction resize() {\n\t\t\tif (!ctn || !renderer) return;\n\t\t\trenderer.setSize(ctn.offsetWidth, ctn.offsetHeight);\n\t\t\tprogram.uniforms.iResolution.value = new Color(\n\t\t\t\tgl.canvas.width,\n\t\t\t\tgl.canvas.height,\n\t\t\t\tgl.canvas.width / gl.canvas.height\n\t\t\t);\n\t\t}\n\n\t\tconst resizeObserver = new ResizeObserver(() => resize());\n\t\tresizeObserver.observe(ctn);\n\t\tresize();\n\n\t\tconst update = (t: number) => {\n\t\t\trafRef.current = requestAnimationFrame(update);\n\n\t\t\tif (pageLoadAnimation && loadAnimationStartRef.current === 0) {\n\t\t\t\tloadAnimationStartRef.current = t;\n\t\t\t}\n\n\t\t\tif (!pause) {\n\t\t\t\tconst elapsed = (t * 0.001 + timeOffsetRef.current) * timeScale;\n\t\t\t\tprogram.uniforms.iTime.value = elapsed;\n\t\t\t\tfrozenTimeRef.current = elapsed;\n\t\t\t} else {\n\t\t\t\tprogram.uniforms.iTime.value = frozenTimeRef.current;\n\t\t\t}\n\n\t\t\tif (pageLoadAnimation && loadAnimationStartRef.current > 0) {\n\t\t\t\tconst animationDuration = 2000;\n\t\t\t\tconst animationElapsed = t - loadAnimationStartRef.current;\n\t\t\t\tconst progress = Math.min(animationElapsed / animationDuration, 1);\n\t\t\t\tprogram.uniforms.uPageLoadProgress.value = progress;\n\t\t\t}\n\n\t\t\tif (mouseReact) {\n\t\t\t\tconst dampingFactor = 0.08;\n\t\t\t\tconst smoothMouse = smoothMouseRef.current;\n\t\t\t\tconst mouse = mouseRef.current;\n\t\t\t\tsmoothMouse.x += (mouse.x - smoothMouse.x) * dampingFactor;\n\t\t\t\tsmoothMouse.y += (mouse.y - smoothMouse.y) * dampingFactor;\n\n\t\t\t\tconst mouseUniform = program.uniforms.uMouse.value as Float32Array;\n\t\t\t\tmouseUniform[0] = smoothMouse.x;\n\t\t\t\tmouseUniform[1] = smoothMouse.y;\n\t\t\t}\n\n\t\t\trenderer.render({ scene: mesh });\n\t\t};\n\t\trafRef.current = requestAnimationFrame(update);\n\t\tctn.appendChild(gl.canvas);\n\n\t\tif (mouseReact) ctn.addEventListener(\"mousemove\", handleMouseMove);\n\n\t\treturn () => {\n\t\t\tcancelAnimationFrame(rafRef.current);\n\t\t\tresizeObserver.disconnect();\n\t\t\tif (mouseReact) ctn.removeEventListener(\"mousemove\", handleMouseMove);\n\t\t\tif (gl.canvas.parentElement === ctn) ctn.removeChild(gl.canvas);\n\t\t\tgl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n\t\t\tloadAnimationStartRef.current = 0;\n\t\t\ttimeOffsetRef.current = Math.random() * 100;\n\t\t};\n\t}, [\n\t\tdpr,\n\t\tpause,\n\t\ttimeScale,\n\t\tscale,\n\t\tgridMul,\n\t\tdigitSize,\n\t\tscanlineIntensity,\n\t\tglitchAmount,\n\t\tflickerAmount,\n\t\tnoiseAmp,\n\t\tchromaticAberration,\n\t\tditherValue,\n\t\tcurvature,\n\t\ttintVec,\n\t\tmouseReact,\n\t\tmouseStrength,\n\t\tpageLoadAnimation,\n\t\tbrightness,\n\t\thandleMouseMove,\n\t]);\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tclassName={`w-full h-full relative overflow-hidden ${className}`}\n\t\t\tstyle={style}\n\t\t\t{...rest}\n\t\t/>\n\t);\n}\n",
      "type": "registry:ui"
    }
  ]
}