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
JavaScript
"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 }) }));
};