"use client"
import { cn } from "@/lib/utils"
import { Canvas, useFrame, useThree } from "@react-three/fiber"
import React, { useMemo, useRef } from "react"
import * as THREE from "three"
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,
}: {
animationSpeed?: number
opacities?: number[]
colors?: number[][]
containerClassName?: string
dotSize?: number
showGradient?: boolean
}) => {
return (
)
}
interface DotMatrixProps {
colors?: number[][]
opacities?: number[]
totalSize?: number
dotSize?: number
shader?: string
center?: ("x" | "y")[]
}
const DotMatrix: React.FC = ({
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 (
)
}
type Uniforms = {
[key: string]: {
value: number[] | number[][] | number
type: string
}
}
const ShaderMaterial = ({
source,
uniforms,
maxFps = 60,
}: {
source: string
hovered?: boolean
maxFps?: number
uniforms: Uniforms
}) => {
const { size } = useThree()
const ref = useRef()
let lastFrameTime = 0
useFrame(({ clock }) => {
if (!ref.current) return
const timestamp = clock.getElapsedTime()
if (timestamp - lastFrameTime < 1 / maxFps) {
return
}
lastFrameTime = timestamp
const material: any = ref.current.material
const timeLocation = material.uniforms.u_time
timeLocation.value = timestamp
})
const getUniforms = () => {
const preparedUniforms: any = {}
for (const uniformName in uniforms) {
const uniform: any = 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: number[]) =>
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
}
}
preparedUniforms["u_time"] = { value: 0, type: "1f" }
preparedUniforms["u_resolution"] = {
value: new THREE.Vector2(size.width * 2, size.height * 2),
} // Initialize u_resolution
return preparedUniforms
}
// Shader material
const material = useMemo(() => {
const materialObject = new THREE.ShaderMaterial({
vertexShader: `
precision mediump float;
in vec2 coordinates;
uniform vec2 u_resolution;
out vec2 fragCoord;
void main(){
float x = position.x;
float y = position.y;
gl_Position = vec4(x, y, 0.0, 1.0);
fragCoord = (position.xy + vec2(1.0)) * 0.5 * u_resolution;
fragCoord.y = u_resolution.y - fragCoord.y;
}
`,
fragmentShader: source,
uniforms: getUniforms(),
glslVersion: THREE.GLSL3,
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneFactor,
})
return materialObject
}, [size.width, size.height, source])
return (
)
}
const Shader: React.FC = ({ source, uniforms, maxFps = 60 }) => {
return (
)
}
interface ShaderProps {
source: string
uniforms: {
[key: string]: {
value: number[] | number[][] | number
type: string
}
}
maxFps?: number
}