Components
Loading preview...
import React, { useRef, useMemo } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
const PrismaticShaderMaterial = {
uniforms: {
uTime: { value: 0 },
uMouse: { value: new THREE.Vector2(0.5, 0.5) },
uResolution: { value: new THREE.Vector2() },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float uTime;
uniform vec2 uMouse;
uniform vec2 uResolution;
varying vec2 vUv;
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);
}
float fbm(vec2 p) {
float v = 0.0;
float a = 0.5;
for (int i = 0; i < 5; i++) {
v += a * noise(p);
p *= 2.0;
a *= 0.5;
}
return v;
}
void main() {
vec2 uv = (vUv - 0.5) * 2.0;
uv.x *= uResolution.x / uResolution.y;
float d = length(uv - (uMouse - 0.5) * 2.0);
float flow = fbm(uv * 0.8 + uTime * 0.1);
float r = smoothstep(0.95, 1.0, sin(uv.x * 15.1 + flow * 12.1 + uTime * 0.51));
float g = smoothstep(0.95, 1.0, sin(uv.x * 15.0 + flow * 12.0 + uTime * 0.5));
float b = smoothstep(0.95, 1.0, sin(uv.x * 14.9 + flow * 11.9 + uTime * 0.49));
vec3 rainbow = 0.5 + 0.5 * cos(uTime + uv.xyx + vec3(0.0, 2.0, 4.0));
vec3 lines = vec3(r, g, b) * rainbow;
float mask = smoothstep(1.5, 0.0, length(vUv - 0.5));
float interaction = smoothstep(0.6, 0.0, d);
vec3 finalColor = lines * 0.4 + interaction * rainbow * 0.1;
finalColor *= mask;
gl_FragColor = vec4(finalColor + vec3(0.01, 0.01, 0.03), 1.0);
}
`,
};
const BackgroundMesh: React.FC = () => {
const meshRef = useRef<THREE.Mesh>(null!);
const { size } = useThree();
const uniforms = useMemo(
() => ({
uTime: { value: 0 },
uMouse: { value: new THREE.Vector2(0.5, 0.5) },
uResolution: { value: new THREE.Vector2(size.width, size.height) },
}),
[]
);
useFrame((state) => {
const { clock, mouse } = state;
if (meshRef.current) {
const material = meshRef.current.material as THREE.ShaderMaterial;
material.uniforms.uTime.value = clock.getElapsedTime();
const targetX = (mouse.x + 1) / 2;
const targetY = (mouse.y + 1) / 2;
material.uniforms.uMouse.value.x += (targetX - material.uniforms.uMouse.value.x) * 0.05;
material.uniforms.uMouse.value.y += (targetY - material.uniforms.uMouse.value.y) * 0.05;
material.uniforms.uResolution.value.set(size.width, size.height);
}
});
return (
<mesh ref={meshRef}>
<planeGeometry args={[2, 2]} />
<shaderMaterial
fragmentShader={PrismaticShaderMaterial.fragmentShader}
vertexShader={PrismaticShaderMaterial.vertexShader}
uniforms={uniforms}
transparent
/>
</mesh>
);
};
export default function Scene() {
return (
<div className="absolute inset-0 w-full h-full">
<Canvas camera={{ position: [0, 0, 1] }} dpr={[1, 2]}>
<BackgroundMesh />
</Canvas>
</div>
);
}