UNPKG

xlibs-components

Version:

Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications

222 lines (211 loc) 9.13 kB
"use client"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { cn } from '../../lib/utils.js'; import { Canvas, useFrame, useThree } from "@react-three/fiber"; import React, { useMemo, useRef, useState, useEffect } from "react"; import * as THREE from "three"; // WebGL detection utility const isWebGLAvailable = () => { try { const canvas = document.createElement('canvas'); return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))); } catch (e) { return false; } }; export const CanvasRevealEffect = ({ animationSpeed = 0.4, opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1], colors = [[0, 255, 255]], containerClassName, dotSize, showGradient = true, }) => { const [webGLAvailable, setWebGLAvailable] = useState(true); useEffect(() => { setWebGLAvailable(isWebGLAvailable()); }, []); // Fallback component when WebGL is not available if (!webGLAvailable) { return (_jsxs("div", { className: cn("h-full relative bg-white w-full", containerClassName), children: [_jsx("div", { className: "h-full w-full bg-gradient-to-br from-cyan-400 to-blue-500 opacity-20" }), showGradient && (_jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-gray-950 to-[84%]" }))] })); } return (_jsxs("div", { className: cn("h-full relative bg-white w-full", containerClassName), children: [_jsx("div", { className: "h-full w-full", children: _jsx(DotMatrix, { colors: colors ?? [[0, 255, 255]], dotSize: dotSize ?? 3, opacities: opacities ?? [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1], shader: ` float animation_speed_factor = ${animationSpeed.toFixed(1)}; float intro_offset = distance(u_resolution / 2.0 / u_total_size, st2) * 0.01 + (random(st2) * 0.15); opacity *= step(intro_offset, u_time * animation_speed_factor); opacity *= clamp((1.0 - step(intro_offset + 0.1, u_time * animation_speed_factor)) * 1.25, 1.0, 1.25); `, center: ["x", "y"] }) }), showGradient && (_jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-gray-950 to-[84%]" }))] })); }; const DotMatrix = ({ colors = [[0, 0, 0]], opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14], totalSize = 4, dotSize = 2, shader = "", center = ["x", "y"], }) => { const uniforms = React.useMemo(() => { let colorsArray = [ colors[0], colors[0], colors[0], colors[0], colors[0], colors[0], ]; if (colors.length === 2) { colorsArray = [ colors[0], colors[0], colors[0], colors[1], colors[1], colors[1], ]; } else if (colors.length === 3) { colorsArray = [ colors[0], colors[0], colors[1], colors[1], colors[2], colors[2], ]; } return { u_colors: { value: colorsArray.map((color) => [ color[0] / 255, color[1] / 255, color[2] / 255, ]), type: "uniform3fv", }, u_opacities: { value: opacities, type: "uniform1fv", }, u_total_size: { value: totalSize, type: "uniform1f", }, u_dot_size: { value: dotSize, type: "uniform1f", }, }; }, [colors, opacities, totalSize, dotSize]); return (_jsx(Shader, { source: ` precision mediump float; varying vec2 vUv; uniform float u_time; uniform float u_opacities[10]; uniform vec3 u_colors[6]; uniform float u_total_size; uniform float u_dot_size; uniform vec2 u_resolution; const float PHI = 1.61803398874989484820459; float random(vec2 xy) { return fract(tan(distance(xy * PHI, xy) * 0.5) * xy.x); } void main() { vec2 st = vUv * u_resolution; ${center.includes("x") ? "st.x -= abs(floor((mod(u_resolution.x, u_total_size) - u_dot_size) * 0.5));" : ""} ${center.includes("y") ? "st.y -= abs(floor((mod(u_resolution.y, u_total_size) - u_dot_size) * 0.5));" : ""} float opacity = step(0.0, st.x); opacity *= step(0.0, st.y); vec2 st2 = vec2(int(st.x / u_total_size), int(st.y / u_total_size)); float frequency = 5.0; float show_offset = random(st2); float rand = random(st2 * floor((u_time / frequency) + show_offset + frequency) + 1.0); opacity *= u_opacities[int(rand * 10.0)]; opacity *= 1.0 - step(u_dot_size / u_total_size, fract(st.x / u_total_size)); opacity *= 1.0 - step(u_dot_size / u_total_size, fract(st.y / u_total_size)); vec3 color = u_colors[int(show_offset * 6.0)]; ${shader} gl_FragColor = vec4(color, opacity); gl_FragColor.rgb *= gl_FragColor.a; }`, uniforms: uniforms, maxFps: 60 })); }; const ShaderMaterial = ({ source, uniforms, maxFps = 60, }) => { const { size } = useThree(); const ref = useRef(null); let lastFrameTime = 0; useFrame(({ clock }) => { if (!ref.current) return; const timestamp = clock.getElapsedTime(); if (timestamp - lastFrameTime < 1 / maxFps) { return; } lastFrameTime = timestamp; const material = ref.current.material; if (material && material.uniforms && material.uniforms.u_time) { material.uniforms.u_time.value = timestamp; } }); const getUniforms = () => { const preparedUniforms = {}; for (const uniformName in uniforms) { const uniform = uniforms[uniformName]; switch (uniform.type) { case "uniform1f": preparedUniforms[uniformName] = { value: uniform.value, type: "1f" }; break; case "uniform3f": preparedUniforms[uniformName] = { value: new THREE.Vector3().fromArray(uniform.value), type: "3f", }; break; case "uniform1fv": preparedUniforms[uniformName] = { value: uniform.value, type: "1fv" }; break; case "uniform3fv": preparedUniforms[uniformName] = { value: uniform.value.map((v) => new THREE.Vector3().fromArray(v)), type: "3fv", }; break; case "uniform2f": preparedUniforms[uniformName] = { value: new THREE.Vector2().fromArray(uniform.value), type: "2f", }; break; default: console.error(`Invalid uniform type for '${uniformName}'.`); break; } } return preparedUniforms; }; const material = useMemo(() => { try { return new THREE.ShaderMaterial({ vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: source, uniforms: { u_time: { value: 0 }, u_resolution: { value: new THREE.Vector2(size.width, size.height) }, ...getUniforms(), }, transparent: true, blending: THREE.AdditiveBlending, }); } catch (error) { console.error("Shader compilation error:", error); // Fallback to a simple material if shader fails return new THREE.MeshBasicMaterial({ color: 0x00ffff, transparent: true, opacity: 0.5 }); } }, [source, uniforms, size]); return (_jsx("mesh", { ref: ref, material: material, children: _jsx("planeGeometry", { args: [2, 2] }) })); }; const Shader = ({ source, uniforms, maxFps = 60 }) => { return (_jsx(Canvas, { style: { width: "100%", height: "100%", }, camera: { position: [0, 0, 1] }, onError: (error) => { console.error("Canvas error:", error); }, children: _jsx(ShaderMaterial, { source: source, uniforms: uniforms, maxFps: maxFps }) })); };