{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "EvilEye-JS-CSS", "title": "EvilEye", "description": "Procedural evil eye shader with animated iris, slit pupil, and fiery outer glow.", "type": "registry:component", "files": [ { "type": "registry:component", "path": "EvilEye/EvilEye.css", "content": ".evil-eye-container {\n width: 100%;\n height: 100%;\n}\n" }, { "type": "registry:component", "path": "EvilEye/EvilEye.jsx", "content": "import { Renderer, Program, Mesh, Triangle, Texture } from 'ogl';\nimport { useEffect, useRef } from 'react';\nimport './EvilEye.css';\n\nfunction hexToVec3(hex) {\n const h = hex.replace('#', '');\n return [\n parseInt(h.slice(0, 2), 16) / 255,\n parseInt(h.slice(2, 4), 16) / 255,\n parseInt(h.slice(4, 6), 16) / 255\n ];\n}\n\nfunction generateNoiseTexture(size = 256) {\n const data = new Uint8Array(size * size * 4);\n\n function hash(x, y, s) {\n let n = x * 374761393 + y * 668265263 + s * 1274126177;\n n = Math.imul(n ^ (n >>> 13), 1274126177);\n return ((n ^ (n >>> 16)) >>> 0) / 4294967296;\n }\n\n function noise(px, py, freq, seed) {\n const fx = (px / size) * freq;\n const fy = (py / size) * freq;\n const ix = Math.floor(fx);\n const iy = Math.floor(fy);\n const tx = fx - ix;\n const ty = fy - iy;\n const w = freq | 0;\n const v00 = hash(((ix % w) + w) % w, ((iy % w) + w) % w, seed);\n const v10 = hash((((ix + 1) % w) + w) % w, ((iy % w) + w) % w, seed);\n const v01 = hash(((ix % w) + w) % w, (((iy + 1) % w) + w) % w, seed);\n const v11 = hash((((ix + 1) % w) + w) % w, (((iy + 1) % w) + w) % w, seed);\n return v00 * (1 - tx) * (1 - ty) + v10 * tx * (1 - ty) + v01 * (1 - tx) * ty + v11 * tx * ty;\n }\n\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n let v = 0;\n let amp = 0.4;\n let totalAmp = 0;\n for (let o = 0; o < 8; o++) {\n const f = 32 * (1 << o);\n v += amp * noise(x, y, f, o * 31);\n totalAmp += amp;\n amp *= 0.65;\n }\n v /= totalAmp;\n v = (v - 0.5) * 2.2 + 0.5;\n v = Math.max(0, Math.min(1, v));\n const val = Math.round(v * 255);\n const i = (y * size + x) * 4;\n data[i] = val;\n data[i + 1] = val;\n data[i + 2] = val;\n data[i + 3] = 255;\n }\n }\n\n return data;\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\nuniform float uTime;\nuniform vec3 uResolution;\nuniform sampler2D uNoiseTexture;\nuniform float uPupilSize;\nuniform float uIrisWidth;\nuniform float uGlowIntensity;\nuniform float uIntensity;\nuniform float uScale;\nuniform float uNoiseScale;\nuniform vec2 uMouse;\nuniform float uPupilFollow;\nuniform float uFlameSpeed;\nuniform vec3 uEyeColor;\nuniform vec3 uBgColor;\n\nvoid main() {\n vec2 uv = (gl_FragCoord.xy * 2.0 - uResolution.xy) / uResolution.y;\n uv /= uScale;\n float ft = uTime * uFlameSpeed;\n\n float polarRadius = length(uv) * 2.0;\n float polarAngle = (2.0 * atan(uv.x, uv.y)) / 6.28 * 0.3;\n vec2 polarUv = vec2(polarRadius, polarAngle);\n\n vec4 noiseA = texture2D(uNoiseTexture, polarUv * vec2(0.2, 7.0) * uNoiseScale + vec2(-ft * 0.1, 0.0));\n vec4 noiseB = texture2D(uNoiseTexture, polarUv * vec2(0.3, 4.0) * uNoiseScale + vec2(-ft * 0.2, 0.0));\n vec4 noiseC = texture2D(uNoiseTexture, polarUv * vec2(0.1, 5.0) * uNoiseScale + vec2(-ft * 0.1, 0.0));\n\n float distanceMask = 1.0 - length(uv);\n\n // Inner ring\n float innerRing = clamp(-1.0 * ((distanceMask - 0.7) / uIrisWidth), 0.0, 1.0);\n innerRing = (innerRing * distanceMask - 0.2) / 0.28;\n innerRing += noiseA.r - 0.5;\n innerRing *= 1.3;\n innerRing = clamp(innerRing, 0.0, 1.0);\n\n float outerRing = clamp(-1.0 * ((distanceMask - 0.5) / 0.2), 0.0, 1.0);\n outerRing = (outerRing * distanceMask - 0.1) / 0.38;\n outerRing += noiseC.r - 0.5;\n outerRing *= 1.3;\n outerRing = clamp(outerRing, 0.0, 1.0);\n\n innerRing += outerRing;\n\n // Inner eye\n float innerEye = distanceMask - 0.1 * 2.0;\n innerEye *= noiseB.r * 2.0;\n\n // Pupil with cursor tracking\n vec2 pupilOffset = uMouse * uPupilFollow * 0.12;\n vec2 pupilUv = uv - pupilOffset;\n float pupil = 1.0 - length(pupilUv * vec2(9.0, 2.3));\n pupil *= uPupilSize;\n pupil = clamp(pupil, 0.0, 1.0);\n pupil /= 0.35;\n\n // Outer eye\n float outerEyeGlow = 1.0 - length(uv * vec2(0.5, 1.5));\n outerEyeGlow = clamp(outerEyeGlow + 0.5, 0.0, 1.0);\n outerEyeGlow += noiseC.r - 0.5;\n float outerBgGlow = outerEyeGlow;\n outerEyeGlow = pow(outerEyeGlow, 2.0);\n outerEyeGlow += distanceMask;\n outerEyeGlow *= uGlowIntensity;\n outerEyeGlow = clamp(outerEyeGlow, 0.0, 1.0);\n outerEyeGlow *= pow(1.0 - distanceMask, 2.0) * 2.5;\n\n // Outer eye bg glow\n outerBgGlow += distanceMask;\n outerBgGlow = pow(outerBgGlow, 0.5);\n outerBgGlow *= 0.15;\n\n vec3 color = uEyeColor * uIntensity * clamp(max(innerRing + innerEye, outerEyeGlow + outerBgGlow) - pupil, 0.0, 3.0);\n color += uBgColor;\n\n gl_FragColor = vec4(color, 1.0);\n}\n`;\n\nexport default function EvilEye({\n eyeColor = '#FF6F37',\n intensity = 1.5,\n pupilSize = 0.6,\n irisWidth = 0.25,\n glowIntensity = 0.35,\n scale = 0.8,\n noiseScale = 1.0,\n pupilFollow = 1.0,\n flameSpeed = 1.0,\n backgroundColor = '#000000'\n}) {\n const containerRef = useRef(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n const container = containerRef.current;\n const renderer = new Renderer({ alpha: true, premultipliedAlpha: false });\n const gl = renderer.gl;\n gl.clearColor(0, 0, 0, 0);\n\n const noiseData = generateNoiseTexture(256);\n const noiseTexture = new Texture(gl, {\n image: noiseData,\n width: 256,\n height: 256,\n generateMipmaps: false,\n flipY: false,\n });\n noiseTexture.minFilter = gl.LINEAR;\n noiseTexture.magFilter = gl.LINEAR;\n noiseTexture.wrapS = gl.REPEAT;\n noiseTexture.wrapT = gl.REPEAT;\n\n const mouse = { x: 0, y: 0, tx: 0, ty: 0 };\n\n function onMouseMove(e) {\n const rect = container.getBoundingClientRect();\n mouse.tx = ((e.clientX - rect.left) / rect.width) * 2 - 1;\n mouse.ty = -(((e.clientY - rect.top) / rect.height) * 2 - 1);\n }\n\n function onMouseLeave() {\n mouse.tx = 0;\n mouse.ty = 0;\n }\n\n container.addEventListener('mousemove', onMouseMove);\n container.addEventListener('mouseleave', onMouseLeave);\n\n let program;\n\n function resize() {\n renderer.setSize(container.offsetWidth, container.offsetHeight);\n if (program) {\n program.uniforms.uResolution.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 uTime: { value: 0 },\n uResolution: { value: [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height] },\n uNoiseTexture: { value: noiseTexture },\n uPupilSize: { value: pupilSize },\n uIrisWidth: { value: irisWidth },\n uGlowIntensity: { value: glowIntensity },\n uIntensity: { value: intensity },\n uScale: { value: scale },\n uNoiseScale: { value: noiseScale },\n uMouse: { value: [0, 0] },\n uPupilFollow: { value: pupilFollow },\n uFlameSpeed: { value: flameSpeed },\n uEyeColor: { value: hexToVec3(eyeColor) },\n uBgColor: { value: hexToVec3(backgroundColor) }\n }\n });\n\n const mesh = new Mesh(gl, { geometry, program });\n container.appendChild(gl.canvas);\n\n let animationFrameId;\n\n function update(time) {\n animationFrameId = requestAnimationFrame(update);\n mouse.x += (mouse.tx - mouse.x) * 0.05;\n mouse.y += (mouse.ty - mouse.y) * 0.05;\n program.uniforms.uMouse.value = [mouse.x, mouse.y];\n program.uniforms.uTime.value = time * 0.001;\n renderer.render({ scene: mesh });\n }\n animationFrameId = requestAnimationFrame(update);\n\n return () => {\n cancelAnimationFrame(animationFrameId);\n window.removeEventListener('resize', resize);\n container.removeEventListener('mousemove', onMouseMove);\n container.removeEventListener('mouseleave', onMouseLeave);\n container.removeChild(gl.canvas);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n };\n }, [eyeColor, intensity, pupilSize, irisWidth, glowIntensity, scale, noiseScale, pupilFollow, flameSpeed, backgroundColor]);\n\n return
;\n}\n" } ], "registryDependencies": [], "dependencies": [ "ogl@^1.0.11" ] }