shaderz 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +208 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/package.json +51 -0
- package/shaders/CosmicNebulaShader.tsx +265 -0
- package/shaders/GlassTwistShader.tsx +169 -0
- package/shaders/GlossyRibbonShader.tsx +164 -0
- package/shaders/GradientWavesShader.tsx +277 -0
- package/shaders/LiquidOrangeShader.tsx +246 -0
- package/shaders/NeonFluidShader.tsx +259 -0
- package/shaders/OceanWavesShader.tsx +229 -0
- package/shaders/PlasmaShader.tsx +174 -0
- package/shaders/SilkFlowShader.tsx +281 -0
- package/shaders/VideoBackground.tsx +37 -0
- package/videos/glossy-film.mp4 +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const GlassTwistShader: React.FC = () => {
|
|
5
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
6
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
7
|
+
const animationRef = useRef<number | null>(null);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const canvas = canvasRef.current;
|
|
11
|
+
const container = containerRef.current;
|
|
12
|
+
if (!canvas || !container) return;
|
|
13
|
+
|
|
14
|
+
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
15
|
+
if (!gl) return;
|
|
16
|
+
|
|
17
|
+
const resizeCanvas = () => {
|
|
18
|
+
const rect = container.getBoundingClientRect();
|
|
19
|
+
canvas.width = rect.width;
|
|
20
|
+
canvas.height = rect.height;
|
|
21
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
resizeCanvas();
|
|
25
|
+
window.addEventListener('resize', resizeCanvas);
|
|
26
|
+
|
|
27
|
+
const vertexShaderSource = `
|
|
28
|
+
attribute vec2 position;
|
|
29
|
+
void main() {
|
|
30
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const fragmentShaderSource = `
|
|
35
|
+
precision highp float;
|
|
36
|
+
uniform vec2 resolution;
|
|
37
|
+
uniform float time;
|
|
38
|
+
|
|
39
|
+
void main(){
|
|
40
|
+
vec2 uv=gl_FragCoord.xy/resolution.xy;
|
|
41
|
+
vec2 p=(uv-0.5)*2.0;
|
|
42
|
+
p.x*=resolution.x/resolution.y;
|
|
43
|
+
vec3 bg=mix(vec3(0.85,0.88,0.92),vec3(0.92,0.94,0.96),uv.y);
|
|
44
|
+
vec3 col=bg;
|
|
45
|
+
|
|
46
|
+
for(float i=0.0;i<4.0;i++){
|
|
47
|
+
float offset=(i-1.5)*0.35;
|
|
48
|
+
float twist=sin(p.x*1.5+time*0.5+i*0.5)*0.5;
|
|
49
|
+
float ribbonY=twist+offset;
|
|
50
|
+
float dist=abs(p.y-ribbonY);
|
|
51
|
+
float ribbon=smoothstep(0.2,0.08,dist);
|
|
52
|
+
float depth=1.0-smoothstep(0.0,0.15,dist);
|
|
53
|
+
|
|
54
|
+
vec3 glass=vec3(0.0,0.75,0.85);
|
|
55
|
+
vec3 light=vec3(0.5,0.95,1.0);
|
|
56
|
+
vec3 c=mix(glass*0.4,light,pow(depth,1.5));
|
|
57
|
+
|
|
58
|
+
float fresnel=pow(1.0-depth,2.0);
|
|
59
|
+
c=mix(c,vec3(0.9,0.98,1.0),fresnel*0.7);
|
|
60
|
+
|
|
61
|
+
float caustic=sin(p.x*15.0+time+i)*sin(p.y*15.0-time)*0.5+0.5;
|
|
62
|
+
caustic=pow(caustic,4.0)*ribbon*0.3;
|
|
63
|
+
c+=glass*caustic;
|
|
64
|
+
|
|
65
|
+
float alpha=ribbon*0.7;
|
|
66
|
+
col=mix(col,c,alpha);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
gl_FragColor=vec4(col,1.0);
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
|
|
74
|
+
const shader = gl.createShader(type);
|
|
75
|
+
if (!shader) return null;
|
|
76
|
+
|
|
77
|
+
gl.shaderSource(shader, source);
|
|
78
|
+
gl.compileShader(shader);
|
|
79
|
+
|
|
80
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
81
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
82
|
+
gl.deleteShader(shader);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return shader;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
90
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
91
|
+
|
|
92
|
+
if (!vertexShader || !fragmentShader) return;
|
|
93
|
+
|
|
94
|
+
const program = gl.createProgram();
|
|
95
|
+
if (!program) return;
|
|
96
|
+
|
|
97
|
+
gl.attachShader(program, vertexShader);
|
|
98
|
+
gl.attachShader(program, fragmentShader);
|
|
99
|
+
gl.linkProgram(program);
|
|
100
|
+
|
|
101
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
102
|
+
console.error('Program link error:', gl.getProgramInfoLog(program));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const positionBuffer = gl.createBuffer();
|
|
107
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
108
|
+
gl.bufferData(
|
|
109
|
+
gl.ARRAY_BUFFER,
|
|
110
|
+
new Float32Array([
|
|
111
|
+
-1, -1,
|
|
112
|
+
1, -1,
|
|
113
|
+
-1, 1,
|
|
114
|
+
1, 1,
|
|
115
|
+
]),
|
|
116
|
+
gl.STATIC_DRAW
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const positionLocation = gl.getAttribLocation(program, 'position');
|
|
120
|
+
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
|
|
121
|
+
const timeLocation = gl.getUniformLocation(program, 'time');
|
|
122
|
+
|
|
123
|
+
let startTime = Date.now();
|
|
124
|
+
|
|
125
|
+
const render = () => {
|
|
126
|
+
if (!gl || !canvas) return;
|
|
127
|
+
|
|
128
|
+
gl.clearColor(0.85, 0.88, 0.92, 1);
|
|
129
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
130
|
+
|
|
131
|
+
gl.useProgram(program);
|
|
132
|
+
|
|
133
|
+
gl.enableVertexAttribArray(positionLocation);
|
|
134
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
135
|
+
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
136
|
+
|
|
137
|
+
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
|
138
|
+
gl.uniform1f(timeLocation, (Date.now() - startTime) / 1000);
|
|
139
|
+
|
|
140
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
141
|
+
|
|
142
|
+
animationRef.current = requestAnimationFrame(render);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
render();
|
|
146
|
+
|
|
147
|
+
return () => {
|
|
148
|
+
window.removeEventListener('resize', resizeCanvas);
|
|
149
|
+
if (animationRef.current) {
|
|
150
|
+
cancelAnimationFrame(animationRef.current);
|
|
151
|
+
}
|
|
152
|
+
gl.deleteProgram(program);
|
|
153
|
+
gl.deleteShader(vertexShader);
|
|
154
|
+
gl.deleteShader(fragmentShader);
|
|
155
|
+
gl.deleteBuffer(positionBuffer);
|
|
156
|
+
};
|
|
157
|
+
}, []);
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div ref={containerRef} className="absolute inset-0 w-full h-full bg-gray-200 overflow-hidden">
|
|
161
|
+
<canvas
|
|
162
|
+
ref={canvasRef}
|
|
163
|
+
className="absolute top-0 left-0 w-full h-full"
|
|
164
|
+
/>
|
|
165
|
+
</div>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export default GlassTwistShader;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const GlossyRibbonShader: React.FC = () => {
|
|
5
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
6
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
7
|
+
const animationRef = useRef<number | null>(null);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const canvas = canvasRef.current;
|
|
11
|
+
const container = containerRef.current;
|
|
12
|
+
if (!canvas || !container) return;
|
|
13
|
+
|
|
14
|
+
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
15
|
+
if (!gl) return;
|
|
16
|
+
|
|
17
|
+
const resizeCanvas = () => {
|
|
18
|
+
const rect = container.getBoundingClientRect();
|
|
19
|
+
canvas.width = rect.width;
|
|
20
|
+
canvas.height = rect.height;
|
|
21
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
resizeCanvas();
|
|
25
|
+
window.addEventListener('resize', resizeCanvas);
|
|
26
|
+
|
|
27
|
+
const vertexShaderSource = `
|
|
28
|
+
attribute vec2 position;
|
|
29
|
+
void main() {
|
|
30
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const fragmentShaderSource = `
|
|
35
|
+
precision highp float;
|
|
36
|
+
uniform vec2 resolution;
|
|
37
|
+
uniform float time;
|
|
38
|
+
|
|
39
|
+
void main(){
|
|
40
|
+
vec2 uv=gl_FragCoord.xy/resolution.xy;
|
|
41
|
+
vec2 p=(uv-0.5)*2.0;
|
|
42
|
+
p.x*=resolution.x/resolution.y;
|
|
43
|
+
vec3 col=vec3(0.0);
|
|
44
|
+
|
|
45
|
+
for(float i=0.0;i<3.0;i++){
|
|
46
|
+
float offset=(i-1.0)*0.4;
|
|
47
|
+
float twist=sin(p.x*1.8+time*0.6+i)*0.6;
|
|
48
|
+
float ribbonY=twist+offset;
|
|
49
|
+
float dist=abs(p.y-ribbonY);
|
|
50
|
+
float ribbon=smoothstep(0.25,0.05,dist);
|
|
51
|
+
|
|
52
|
+
float depth=sin(p.x*2.5+time+i)*0.5+0.5;
|
|
53
|
+
vec3 c1=vec3(1.0,0.1,0.7);
|
|
54
|
+
vec3 c2=vec3(0.7,0.2,1.0);
|
|
55
|
+
vec3 c3=vec3(0.4,0.3,0.9);
|
|
56
|
+
vec3 c=mix(c1,c2,depth);
|
|
57
|
+
c=mix(c,c3,smoothstep(0.3,0.7,sin(p.x*3.0)*0.5+0.5));
|
|
58
|
+
|
|
59
|
+
float spec=pow(1.0-smoothstep(0.0,0.2,dist),3.0)*0.6;
|
|
60
|
+
float edge=smoothstep(0.2,0.25,dist)*smoothstep(0.3,0.25,dist);
|
|
61
|
+
col+=(c*ribbon+vec3(spec)+c*edge*0.4)*(1.0-i*0.15);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
gl_FragColor=vec4(col,1.0);
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
|
|
69
|
+
const shader = gl.createShader(type);
|
|
70
|
+
if (!shader) return null;
|
|
71
|
+
|
|
72
|
+
gl.shaderSource(shader, source);
|
|
73
|
+
gl.compileShader(shader);
|
|
74
|
+
|
|
75
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
76
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
77
|
+
gl.deleteShader(shader);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return shader;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
85
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
86
|
+
|
|
87
|
+
if (!vertexShader || !fragmentShader) return;
|
|
88
|
+
|
|
89
|
+
const program = gl.createProgram();
|
|
90
|
+
if (!program) return;
|
|
91
|
+
|
|
92
|
+
gl.attachShader(program, vertexShader);
|
|
93
|
+
gl.attachShader(program, fragmentShader);
|
|
94
|
+
gl.linkProgram(program);
|
|
95
|
+
|
|
96
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
97
|
+
console.error('Program link error:', gl.getProgramInfoLog(program));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const positionBuffer = gl.createBuffer();
|
|
102
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
103
|
+
gl.bufferData(
|
|
104
|
+
gl.ARRAY_BUFFER,
|
|
105
|
+
new Float32Array([
|
|
106
|
+
-1, -1,
|
|
107
|
+
1, -1,
|
|
108
|
+
-1, 1,
|
|
109
|
+
1, 1,
|
|
110
|
+
]),
|
|
111
|
+
gl.STATIC_DRAW
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const positionLocation = gl.getAttribLocation(program, 'position');
|
|
115
|
+
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
|
|
116
|
+
const timeLocation = gl.getUniformLocation(program, 'time');
|
|
117
|
+
|
|
118
|
+
let startTime = Date.now();
|
|
119
|
+
|
|
120
|
+
const render = () => {
|
|
121
|
+
if (!gl || !canvas) return;
|
|
122
|
+
|
|
123
|
+
gl.clearColor(0, 0, 0, 1);
|
|
124
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
125
|
+
|
|
126
|
+
gl.useProgram(program);
|
|
127
|
+
|
|
128
|
+
gl.enableVertexAttribArray(positionLocation);
|
|
129
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
130
|
+
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
131
|
+
|
|
132
|
+
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
|
133
|
+
gl.uniform1f(timeLocation, (Date.now() - startTime) / 1000);
|
|
134
|
+
|
|
135
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
136
|
+
|
|
137
|
+
animationRef.current = requestAnimationFrame(render);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
render();
|
|
141
|
+
|
|
142
|
+
return () => {
|
|
143
|
+
window.removeEventListener('resize', resizeCanvas);
|
|
144
|
+
if (animationRef.current) {
|
|
145
|
+
cancelAnimationFrame(animationRef.current);
|
|
146
|
+
}
|
|
147
|
+
gl.deleteProgram(program);
|
|
148
|
+
gl.deleteShader(vertexShader);
|
|
149
|
+
gl.deleteShader(fragmentShader);
|
|
150
|
+
gl.deleteBuffer(positionBuffer);
|
|
151
|
+
};
|
|
152
|
+
}, []);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<div ref={containerRef} className="absolute inset-0 w-full h-full bg-black overflow-hidden">
|
|
156
|
+
<canvas
|
|
157
|
+
ref={canvasRef}
|
|
158
|
+
className="absolute top-0 left-0 w-full h-full"
|
|
159
|
+
/>
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export default GlossyRibbonShader;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const GradientWavesShader: React.FC = () => {
|
|
5
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
6
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
7
|
+
const animationRef = useRef<number | null>(null);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const canvas = canvasRef.current;
|
|
11
|
+
const container = containerRef.current;
|
|
12
|
+
if (!canvas || !container) return;
|
|
13
|
+
|
|
14
|
+
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
|
|
15
|
+
if (!gl) return;
|
|
16
|
+
|
|
17
|
+
const resizeCanvas = () => {
|
|
18
|
+
const rect = container.getBoundingClientRect();
|
|
19
|
+
canvas.width = rect.width;
|
|
20
|
+
canvas.height = rect.height;
|
|
21
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
resizeCanvas();
|
|
25
|
+
window.addEventListener('resize', resizeCanvas);
|
|
26
|
+
|
|
27
|
+
const vertexShaderSource = `
|
|
28
|
+
attribute vec2 position;
|
|
29
|
+
void main() {
|
|
30
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const fragmentShaderSource = `
|
|
35
|
+
precision highp float;
|
|
36
|
+
uniform vec2 resolution;
|
|
37
|
+
uniform float time;
|
|
38
|
+
|
|
39
|
+
// Improved hash
|
|
40
|
+
float hash(float n) {
|
|
41
|
+
return fract(sin(n) * 43758.5453123);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 2D rotation matrix
|
|
45
|
+
mat2 rot(float a) {
|
|
46
|
+
float c = cos(a), s = sin(a);
|
|
47
|
+
return mat2(c, -s, s, c);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Smooth value noise
|
|
51
|
+
float noise(vec2 p) {
|
|
52
|
+
vec2 i = floor(p);
|
|
53
|
+
vec2 f = fract(p);
|
|
54
|
+
f = f * f * (3.0 - 2.0 * f);
|
|
55
|
+
|
|
56
|
+
float a = hash(i.x + i.y * 57.0);
|
|
57
|
+
float b = hash(i.x + 1.0 + i.y * 57.0);
|
|
58
|
+
float c = hash(i.x + (i.y + 1.0) * 57.0);
|
|
59
|
+
float d = hash(i.x + 1.0 + (i.y + 1.0) * 57.0);
|
|
60
|
+
|
|
61
|
+
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Layered fbm
|
|
65
|
+
float fbm(vec2 p) {
|
|
66
|
+
float v = 0.0;
|
|
67
|
+
float a = 0.5;
|
|
68
|
+
vec2 shift = vec2(100.0);
|
|
69
|
+
|
|
70
|
+
for(int i = 0; i < 5; i++) {
|
|
71
|
+
v += a * noise(p);
|
|
72
|
+
p = rot(0.5) * p * 2.0 + shift;
|
|
73
|
+
a *= 0.5;
|
|
74
|
+
}
|
|
75
|
+
return v;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Ribbon-like wave pattern
|
|
79
|
+
float ribbonWave(vec2 p, float time, float index) {
|
|
80
|
+
float freq = 2.0 + index * 0.5;
|
|
81
|
+
float phase = time * (0.3 + index * 0.1);
|
|
82
|
+
|
|
83
|
+
// Sinusoidal waves with offset
|
|
84
|
+
float wave = sin(p.x * freq + phase) * 0.5 + 0.5;
|
|
85
|
+
wave *= sin(p.x * freq * 1.5 - phase * 0.8) * 0.5 + 0.5;
|
|
86
|
+
|
|
87
|
+
// Add vertical component
|
|
88
|
+
float yWave = sin(p.y * (freq * 0.5) + phase * 0.5) * 0.3;
|
|
89
|
+
|
|
90
|
+
return wave + yWave;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Distance to ribbon
|
|
94
|
+
float ribbonDist(vec2 p, float time, float index) {
|
|
95
|
+
float offset = index * 0.3 - 0.6;
|
|
96
|
+
float wave = ribbonWave(p, time, index);
|
|
97
|
+
|
|
98
|
+
float centerY = sin(p.x * (1.5 + index * 0.3) + time * (0.4 + index * 0.1)) * 0.4 + offset;
|
|
99
|
+
float width = 0.15 + sin(time * 0.5 + index) * 0.05;
|
|
100
|
+
|
|
101
|
+
float dist = abs(p.y - centerY - wave * 0.2);
|
|
102
|
+
return smoothstep(width, 0.0, dist);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
void main() {
|
|
106
|
+
vec2 uv = gl_FragCoord.xy / resolution.xy;
|
|
107
|
+
vec2 p = (uv - 0.5) * 2.0;
|
|
108
|
+
p.x *= resolution.x / resolution.y;
|
|
109
|
+
|
|
110
|
+
float t = time * 0.4;
|
|
111
|
+
|
|
112
|
+
// Add subtle flow distortion
|
|
113
|
+
vec2 flow = vec2(
|
|
114
|
+
fbm(p * 1.5 + t * 0.2) - 0.5,
|
|
115
|
+
fbm(p * 1.5 - t * 0.15) - 0.5
|
|
116
|
+
) * 0.3;
|
|
117
|
+
|
|
118
|
+
vec2 distorted = p + flow;
|
|
119
|
+
|
|
120
|
+
// Multiple ribbon waves with depth
|
|
121
|
+
float ribbons = 0.0;
|
|
122
|
+
vec3 color = vec3(0.0);
|
|
123
|
+
|
|
124
|
+
for(int i = 0; i < 5; i++) {
|
|
125
|
+
float fi = float(i);
|
|
126
|
+
float ribbon = ribbonDist(distorted, t, fi);
|
|
127
|
+
|
|
128
|
+
// Depth-based coloring
|
|
129
|
+
float depth = fi / 5.0;
|
|
130
|
+
|
|
131
|
+
// Gradient colors - deep blue to violet to pink
|
|
132
|
+
vec3 c1 = vec3(0.1, 0.15, 0.4); // Deep blue
|
|
133
|
+
vec3 c2 = vec3(0.3, 0.2, 0.6); // Violet
|
|
134
|
+
vec3 c3 = vec3(0.5, 0.25, 0.7); // Purple
|
|
135
|
+
vec3 c4 = vec3(0.7, 0.3, 0.8); // Light purple
|
|
136
|
+
|
|
137
|
+
vec3 ribbonColor = mix(c1, c2, depth);
|
|
138
|
+
ribbonColor = mix(ribbonColor, c3, smoothstep(0.3, 0.7, depth));
|
|
139
|
+
ribbonColor = mix(ribbonColor, c4, smoothstep(0.7, 1.0, depth));
|
|
140
|
+
|
|
141
|
+
// Add gradient variation based on position
|
|
142
|
+
float gradientShift = sin(distorted.x * 2.0 + t + fi) * 0.5 + 0.5;
|
|
143
|
+
ribbonColor = mix(ribbonColor, ribbonColor * 1.3, gradientShift * 0.4);
|
|
144
|
+
|
|
145
|
+
// Brightness based on wave position
|
|
146
|
+
float brightness = ribbonWave(distorted, t, fi);
|
|
147
|
+
ribbonColor *= 0.7 + brightness * 0.3;
|
|
148
|
+
|
|
149
|
+
// Accumulate with depth sorting
|
|
150
|
+
color = mix(color, ribbonColor, ribbon * (0.9 - depth * 0.2));
|
|
151
|
+
ribbons += ribbon;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Edge highlighting
|
|
155
|
+
for(int i = 0; i < 5; i++) {
|
|
156
|
+
float fi = float(i);
|
|
157
|
+
float ribbon = ribbonDist(distorted, t, fi);
|
|
158
|
+
float edge = ribbon * (1.0 - ribbon) * 4.0;
|
|
159
|
+
|
|
160
|
+
// Bright edge glow
|
|
161
|
+
vec3 edgeColor = vec3(0.4, 0.5, 1.0);
|
|
162
|
+
color += edgeColor * edge * 0.3;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Subtle shimmer overlay
|
|
166
|
+
float shimmer = fbm(distorted * 8.0 + vec2(t * 2.0, t));
|
|
167
|
+
shimmer = pow(shimmer, 4.0);
|
|
168
|
+
color += vec3(0.6, 0.7, 1.0) * shimmer * ribbons * 0.15;
|
|
169
|
+
|
|
170
|
+
// Vignette for depth
|
|
171
|
+
float vignette = 1.0 - length(uv - 0.5) * 0.5;
|
|
172
|
+
color *= vignette;
|
|
173
|
+
|
|
174
|
+
// Brightness adjustment for minimalism
|
|
175
|
+
color *= 0.85;
|
|
176
|
+
|
|
177
|
+
gl_FragColor = vec4(color, 1.0);
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
|
|
181
|
+
const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
|
|
182
|
+
const shader = gl.createShader(type);
|
|
183
|
+
if (!shader) return null;
|
|
184
|
+
|
|
185
|
+
gl.shaderSource(shader, source);
|
|
186
|
+
gl.compileShader(shader);
|
|
187
|
+
|
|
188
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
189
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
190
|
+
gl.deleteShader(shader);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return shader;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
198
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
199
|
+
|
|
200
|
+
if (!vertexShader || !fragmentShader) return;
|
|
201
|
+
|
|
202
|
+
const program = gl.createProgram();
|
|
203
|
+
if (!program) return;
|
|
204
|
+
|
|
205
|
+
gl.attachShader(program, vertexShader);
|
|
206
|
+
gl.attachShader(program, fragmentShader);
|
|
207
|
+
gl.linkProgram(program);
|
|
208
|
+
|
|
209
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
210
|
+
console.error('Program link error:', gl.getProgramInfoLog(program));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const positionBuffer = gl.createBuffer();
|
|
215
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
216
|
+
gl.bufferData(
|
|
217
|
+
gl.ARRAY_BUFFER,
|
|
218
|
+
new Float32Array([
|
|
219
|
+
-1, -1,
|
|
220
|
+
1, -1,
|
|
221
|
+
-1, 1,
|
|
222
|
+
1, 1,
|
|
223
|
+
]),
|
|
224
|
+
gl.STATIC_DRAW
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const positionLocation = gl.getAttribLocation(program, 'position');
|
|
228
|
+
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
|
|
229
|
+
const timeLocation = gl.getUniformLocation(program, 'time');
|
|
230
|
+
|
|
231
|
+
let startTime = Date.now();
|
|
232
|
+
|
|
233
|
+
const render = () => {
|
|
234
|
+
if (!gl || !canvas) return;
|
|
235
|
+
|
|
236
|
+
gl.clearColor(0, 0, 0, 1);
|
|
237
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
238
|
+
|
|
239
|
+
gl.useProgram(program);
|
|
240
|
+
|
|
241
|
+
gl.enableVertexAttribArray(positionLocation);
|
|
242
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
243
|
+
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
244
|
+
|
|
245
|
+
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
|
246
|
+
gl.uniform1f(timeLocation, (Date.now() - startTime) / 1000);
|
|
247
|
+
|
|
248
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
249
|
+
|
|
250
|
+
animationRef.current = requestAnimationFrame(render);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
render();
|
|
254
|
+
|
|
255
|
+
return () => {
|
|
256
|
+
window.removeEventListener('resize', resizeCanvas);
|
|
257
|
+
if (animationRef.current) {
|
|
258
|
+
cancelAnimationFrame(animationRef.current);
|
|
259
|
+
}
|
|
260
|
+
gl.deleteProgram(program);
|
|
261
|
+
gl.deleteShader(vertexShader);
|
|
262
|
+
gl.deleteShader(fragmentShader);
|
|
263
|
+
gl.deleteBuffer(positionBuffer);
|
|
264
|
+
};
|
|
265
|
+
}, []);
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<div ref={containerRef} className="absolute inset-0 w-full h-full bg-black overflow-hidden">
|
|
269
|
+
<canvas
|
|
270
|
+
ref={canvasRef}
|
|
271
|
+
className="absolute top-0 left-0 w-full h-full"
|
|
272
|
+
/>
|
|
273
|
+
</div>
|
|
274
|
+
);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export default GradientWavesShader;
|