Gradient Moving Background

A dynamic 3D background that blends two colors together with a smooth gradient effect.

Installation

Start by installing the required dependencies:

tsx
1npm install three @react-three/fiber

Then, 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;
Popular Components