Gradient Moving Background
A dynamic 3D background that blends two colors together with a smooth gradient effect.
tsx
1import BackgroundGradient from '@/components/ui/gradient-background';
2
3export function ComponentPreview() {
4 return (
5 <div className="relative w-full h-screen overflow-hidden z-10">
6 <BackgroundGradient />
7 </div>
8 );
9}Installation
Start by installing the required dependencies:
tsx
1npm install three @react-three/fiberThen, copy the following component code into your project:
components/ui/gradient-background.tsx
1'use client';
2
3import React, { useRef, useMemo, JSX } from 'react';
4import { Canvas, useFrame, RootState } from '@react-three/fiber';
5import * as THREE from 'three';
6
7type ShaderUniforms = {
8 uTime: { value: number };
9 uColor1: { value: THREE.Color };
10 uColor2: { value: THREE.Color };
11};
12
13interface CustomShaderMaterial extends THREE.ShaderMaterial {
14 uniforms: ShaderUniforms;
15
16}
17
18
19function BackgroundShader(): JSX.Element {
20 const material = useRef<CustomShaderMaterial | null>(null);
21
22 const shaderArgs = useMemo(() => ({
23 uniforms: {
24 uTime: { value: 0 },
25 uColor1: { value: new THREE.Color('#191970') },
26 uColor2: { value: new THREE.Color('#468FEA') },
27 },
28 vertexShader: `
29 varying vec2 vUv;
30 void main() {
31 vUv = uv;
32 gl_Position = vec4(position.xy, 0.0, 1.0);
33 }
34 `,
35 fragmentShader: `
36 uniform float uTime;
37 uniform vec3 uColor1;
38 uniform vec3 uColor2;
39 varying vec2 vUv;
40
41 float random(vec2 st) {
42 return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
43 }
44
45 float noise(vec2 st) {
46 vec2 i = floor(st);
47 vec2 f = fract(st);
48 float a = random(i);
49 float b = random(i + vec2(1.0, 0.0));
50 float c = random(i + vec2(0.0, 1.0));
51 float d = random(i + vec2(1.0, 1.0));
52 vec2 u = f * f * (3.0 - 2.0 * f);
53 return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.y * u.x;
54 }
55
56 float fbm(vec2 st) {
57 float value = 0.0;
58 float amplitude = 0.5;
59
60 for (int i = 0; i < 4; i++) {
61 value += amplitude * noise(st);
62 st *= 2.0;
63 amplitude *= 0.5;
64 }
65 return value;
66 }
67
68 void main() {
69 vec2 st = vUv * 1.0;
70 float slowTime = uTime * 0.02;
71 float noisePattern = fbm(st + slowTime);
72 float mixFactor = smoothstep(0.3, 0.7, noisePattern);
73 vec3 color = mix(uColor1, uColor2, mixFactor);
74
75 gl_FragColor = vec4(color, 1.0);
76 }
77 `
78 }), []);
79
80
81 useFrame((state: RootState) => {
82
83 if (material.current) {
84 material.current.uniforms.uTime.value = state.clock.getElapsedTime();
85 }
86 });
87
88 return (
89 <mesh>
90 <planeGeometry args={[2, 2]} />
91
92 <shaderMaterial ref={material} args={[shaderArgs]} />
93 </mesh>
94 );
95}
96
97
98
99const Background: React.FC = () => {
100 return (
101 <div className="absloute top-0 left-0 w-full h-full -z-20 ">
102 <Canvas>
103 <BackgroundShader />
104 </Canvas>
105 </div>
106 );
107}
108
109export default Background;