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,229 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const OceanWavesShader: 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
|
+
// Hash function for pseudo-random values
|
|
40
|
+
float hash(vec2 p) {
|
|
41
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
42
|
+
p += dot(p, p + 45.32);
|
|
43
|
+
return fract(p.x * p.y);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 2D noise function
|
|
47
|
+
float noise(vec2 p) {
|
|
48
|
+
vec2 i = floor(p);
|
|
49
|
+
vec2 f = fract(p);
|
|
50
|
+
f = f * f * (3.0 - 2.0 * f);
|
|
51
|
+
|
|
52
|
+
float a = hash(i);
|
|
53
|
+
float b = hash(i + vec2(1.0, 0.0));
|
|
54
|
+
float c = hash(i + vec2(0.0, 1.0));
|
|
55
|
+
float d = hash(i + vec2(1.0, 1.0));
|
|
56
|
+
|
|
57
|
+
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Fractal Brownian Motion
|
|
61
|
+
float fbm(vec2 p) {
|
|
62
|
+
float value = 0.0;
|
|
63
|
+
float amplitude = 0.5;
|
|
64
|
+
float frequency = 1.0;
|
|
65
|
+
|
|
66
|
+
for(int i = 0; i < 6; i++) {
|
|
67
|
+
value += amplitude * noise(p * frequency);
|
|
68
|
+
frequency *= 2.0;
|
|
69
|
+
amplitude *= 0.5;
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Ocean wave function
|
|
75
|
+
float wave(vec2 p, float time) {
|
|
76
|
+
float w = 0.0;
|
|
77
|
+
|
|
78
|
+
// Large rolling waves
|
|
79
|
+
w += sin(p.x * 0.5 + time * 0.3) * 0.3;
|
|
80
|
+
w += sin(p.x * 0.3 - p.y * 0.2 + time * 0.2) * 0.2;
|
|
81
|
+
|
|
82
|
+
// Medium waves
|
|
83
|
+
w += sin(p.x * 1.0 + p.y * 0.5 + time * 0.5) * 0.15;
|
|
84
|
+
w += sin(p.x * 1.5 - p.y * 0.8 + time * 0.4) * 0.1;
|
|
85
|
+
|
|
86
|
+
// Small ripples
|
|
87
|
+
w += fbm(p * 2.0 + vec2(time * 0.1, time * 0.05)) * 0.1;
|
|
88
|
+
|
|
89
|
+
return w;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void main() {
|
|
93
|
+
vec2 uv = gl_FragCoord.xy / resolution.xy;
|
|
94
|
+
vec2 p = (uv - 0.5) * 2.0;
|
|
95
|
+
p.x *= resolution.x / resolution.y;
|
|
96
|
+
|
|
97
|
+
// Create wave motion
|
|
98
|
+
float waves = wave(p * 2.0, time);
|
|
99
|
+
|
|
100
|
+
// Add foam patterns
|
|
101
|
+
float foam = fbm(p * 4.0 + vec2(time * 0.2, waves * 2.0));
|
|
102
|
+
foam = smoothstep(0.5, 0.7, foam);
|
|
103
|
+
|
|
104
|
+
// Ocean colors
|
|
105
|
+
vec3 deepWater = vec3(0.0, 0.2, 0.4); // Deep blue
|
|
106
|
+
vec3 shallowWater = vec3(0.0, 0.4, 0.6); // Lighter blue
|
|
107
|
+
vec3 foamColor = vec3(0.7, 0.9, 1.0); // White-blue foam
|
|
108
|
+
|
|
109
|
+
// Mix colors based on wave height
|
|
110
|
+
float waveHeight = waves * 0.5 + 0.5;
|
|
111
|
+
vec3 color = mix(deepWater, shallowWater, waveHeight);
|
|
112
|
+
|
|
113
|
+
// Add foam highlights
|
|
114
|
+
color = mix(color, foamColor, foam * 0.4);
|
|
115
|
+
|
|
116
|
+
// Add depth gradient
|
|
117
|
+
float depth = smoothstep(0.0, 1.0, 1.0 - uv.y);
|
|
118
|
+
color = mix(color, deepWater, depth * 0.3);
|
|
119
|
+
|
|
120
|
+
// Add shimmer effect
|
|
121
|
+
float shimmer = fbm(p * 8.0 + vec2(time * 0.5, time * 0.3));
|
|
122
|
+
shimmer = pow(shimmer, 3.0) * 0.2;
|
|
123
|
+
color += vec3(shimmer);
|
|
124
|
+
|
|
125
|
+
// Vignette effect
|
|
126
|
+
float vignette = 1.0 - length(uv - 0.5) * 0.5;
|
|
127
|
+
color *= vignette;
|
|
128
|
+
|
|
129
|
+
gl_FragColor = vec4(color, 1.0);
|
|
130
|
+
}
|
|
131
|
+
`;
|
|
132
|
+
|
|
133
|
+
const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
|
|
134
|
+
const shader = gl.createShader(type);
|
|
135
|
+
if (!shader) return null;
|
|
136
|
+
|
|
137
|
+
gl.shaderSource(shader, source);
|
|
138
|
+
gl.compileShader(shader);
|
|
139
|
+
|
|
140
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
141
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
142
|
+
gl.deleteShader(shader);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return shader;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
150
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
151
|
+
|
|
152
|
+
if (!vertexShader || !fragmentShader) return;
|
|
153
|
+
|
|
154
|
+
const program = gl.createProgram();
|
|
155
|
+
if (!program) return;
|
|
156
|
+
|
|
157
|
+
gl.attachShader(program, vertexShader);
|
|
158
|
+
gl.attachShader(program, fragmentShader);
|
|
159
|
+
gl.linkProgram(program);
|
|
160
|
+
|
|
161
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
162
|
+
console.error('Program link error:', gl.getProgramInfoLog(program));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const positionBuffer = gl.createBuffer();
|
|
167
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
168
|
+
gl.bufferData(
|
|
169
|
+
gl.ARRAY_BUFFER,
|
|
170
|
+
new Float32Array([
|
|
171
|
+
-1, -1,
|
|
172
|
+
1, -1,
|
|
173
|
+
-1, 1,
|
|
174
|
+
1, 1,
|
|
175
|
+
]),
|
|
176
|
+
gl.STATIC_DRAW
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const positionLocation = gl.getAttribLocation(program, 'position');
|
|
180
|
+
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
|
|
181
|
+
const timeLocation = gl.getUniformLocation(program, 'time');
|
|
182
|
+
|
|
183
|
+
let startTime = Date.now();
|
|
184
|
+
|
|
185
|
+
const render = () => {
|
|
186
|
+
if (!gl || !canvas) return;
|
|
187
|
+
|
|
188
|
+
gl.clearColor(0, 0, 0, 1);
|
|
189
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
190
|
+
|
|
191
|
+
gl.useProgram(program);
|
|
192
|
+
|
|
193
|
+
gl.enableVertexAttribArray(positionLocation);
|
|
194
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
195
|
+
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
196
|
+
|
|
197
|
+
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
|
198
|
+
gl.uniform1f(timeLocation, (Date.now() - startTime) / 1000);
|
|
199
|
+
|
|
200
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
201
|
+
|
|
202
|
+
animationRef.current = requestAnimationFrame(render);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
render();
|
|
206
|
+
|
|
207
|
+
return () => {
|
|
208
|
+
window.removeEventListener('resize', resizeCanvas);
|
|
209
|
+
if (animationRef.current) {
|
|
210
|
+
cancelAnimationFrame(animationRef.current);
|
|
211
|
+
}
|
|
212
|
+
gl.deleteProgram(program);
|
|
213
|
+
gl.deleteShader(vertexShader);
|
|
214
|
+
gl.deleteShader(fragmentShader);
|
|
215
|
+
gl.deleteBuffer(positionBuffer);
|
|
216
|
+
};
|
|
217
|
+
}, []);
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div ref={containerRef} className="absolute inset-0 w-full h-full bg-black overflow-hidden">
|
|
221
|
+
<canvas
|
|
222
|
+
ref={canvasRef}
|
|
223
|
+
className="absolute top-0 left-0 w-full h-full"
|
|
224
|
+
/>
|
|
225
|
+
</div>
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export default OceanWavesShader;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
|
|
4
|
+
function PlasmaShader() {
|
|
5
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
6
|
+
const glRef = useRef<WebGLRenderingContext | null>(null);
|
|
7
|
+
const programRef = useRef<WebGLProgram | null>(null);
|
|
8
|
+
const animationRef = useRef<number | null>(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const canvas = canvasRef.current;
|
|
12
|
+
if (!canvas) return;
|
|
13
|
+
|
|
14
|
+
const gl = canvas.getContext('webgl');
|
|
15
|
+
glRef.current = gl;
|
|
16
|
+
|
|
17
|
+
if (!gl) {
|
|
18
|
+
console.error('WebGL not supported');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const resizeCanvas = () => {
|
|
23
|
+
canvas.width = window.innerWidth;
|
|
24
|
+
canvas.height = window.innerHeight;
|
|
25
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
resizeCanvas();
|
|
29
|
+
window.addEventListener('resize', resizeCanvas);
|
|
30
|
+
|
|
31
|
+
const vertexShaderSource = `
|
|
32
|
+
attribute vec2 position;
|
|
33
|
+
void main() {
|
|
34
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const fragmentShaderSource = `
|
|
39
|
+
precision highp float;
|
|
40
|
+
uniform vec2 resolution;
|
|
41
|
+
uniform float time;
|
|
42
|
+
|
|
43
|
+
vec3 plasma(vec2 uv, float time) {
|
|
44
|
+
float v = 0.0;
|
|
45
|
+
vec2 c = uv;
|
|
46
|
+
|
|
47
|
+
v += sin((c.x + time) * 2.0);
|
|
48
|
+
v += sin((c.y + time) * 3.0);
|
|
49
|
+
v += sin((c.x + c.y + time) * 2.0);
|
|
50
|
+
|
|
51
|
+
c += vec2(sin(time * 0.5) * 2.0, cos(time * 0.3) * 2.0);
|
|
52
|
+
v += sin(sqrt(c.x * c.x + c.y * c.y + 1.0) + time);
|
|
53
|
+
|
|
54
|
+
return vec3(
|
|
55
|
+
sin(v * 3.14159),
|
|
56
|
+
sin(v * 3.14159 + 2.094),
|
|
57
|
+
sin(v * 3.14159 + 4.188)
|
|
58
|
+
) * 0.5 + 0.5;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
void main() {
|
|
62
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * resolution.xy) / resolution.y;
|
|
63
|
+
uv *= 2.0;
|
|
64
|
+
|
|
65
|
+
vec3 color = plasma(uv, time * 0.8);
|
|
66
|
+
|
|
67
|
+
// Add some glow effect
|
|
68
|
+
float glow = 1.0 - length(uv) * 0.3;
|
|
69
|
+
color *= glow;
|
|
70
|
+
|
|
71
|
+
// Purple-pink gradient overlay
|
|
72
|
+
vec3 purpleGradient = mix(
|
|
73
|
+
vec3(0.4, 0.1, 0.8),
|
|
74
|
+
vec3(0.8, 0.2, 0.6),
|
|
75
|
+
(uv.y + 1.0) * 0.5
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
color = mix(color, purpleGradient, 0.3);
|
|
79
|
+
|
|
80
|
+
gl_FragColor = vec4(color, 0.9);
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
|
|
85
|
+
const shader = gl.createShader(type);
|
|
86
|
+
if (!shader) return null;
|
|
87
|
+
|
|
88
|
+
gl.shaderSource(shader, source);
|
|
89
|
+
gl.compileShader(shader);
|
|
90
|
+
|
|
91
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
92
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
93
|
+
gl.deleteShader(shader);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return shader;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
100
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
101
|
+
|
|
102
|
+
if (!vertexShader || !fragmentShader) return;
|
|
103
|
+
|
|
104
|
+
const program = gl.createProgram();
|
|
105
|
+
if (!program) return;
|
|
106
|
+
|
|
107
|
+
gl.attachShader(program, vertexShader);
|
|
108
|
+
gl.attachShader(program, fragmentShader);
|
|
109
|
+
gl.linkProgram(program);
|
|
110
|
+
|
|
111
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
112
|
+
console.error('Program link error:', gl.getProgramInfoLog(program));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
programRef.current = program;
|
|
117
|
+
|
|
118
|
+
const positionBuffer = gl.createBuffer();
|
|
119
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
120
|
+
const positions = new Float32Array([
|
|
121
|
+
-1, -1,
|
|
122
|
+
1, -1,
|
|
123
|
+
-1, 1,
|
|
124
|
+
1, 1
|
|
125
|
+
]);
|
|
126
|
+
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
|
|
127
|
+
|
|
128
|
+
const positionLocation = gl.getAttribLocation(program, 'position');
|
|
129
|
+
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
|
|
130
|
+
const timeLocation = gl.getUniformLocation(program, 'time');
|
|
131
|
+
|
|
132
|
+
gl.enable(gl.BLEND);
|
|
133
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
134
|
+
|
|
135
|
+
const render = (time: number) => {
|
|
136
|
+
time *= 0.001;
|
|
137
|
+
|
|
138
|
+
gl.clearColor(0, 0, 0, 0);
|
|
139
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
140
|
+
gl.useProgram(program);
|
|
141
|
+
|
|
142
|
+
gl.enableVertexAttribArray(positionLocation);
|
|
143
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
144
|
+
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
145
|
+
|
|
146
|
+
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
|
147
|
+
gl.uniform1f(timeLocation, time);
|
|
148
|
+
|
|
149
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
150
|
+
|
|
151
|
+
animationRef.current = requestAnimationFrame(render);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
animationRef.current = requestAnimationFrame(render);
|
|
155
|
+
|
|
156
|
+
return () => {
|
|
157
|
+
window.removeEventListener('resize', resizeCanvas);
|
|
158
|
+
if (animationRef.current) {
|
|
159
|
+
cancelAnimationFrame(animationRef.current);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}, []);
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<div className="absolute inset-0 w-full h-full bg-black overflow-hidden">
|
|
166
|
+
<canvas
|
|
167
|
+
ref={canvasRef}
|
|
168
|
+
className="absolute top-0 left-0 w-full h-full pointer-events-none opacity-95"
|
|
169
|
+
/>
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export default PlasmaShader;
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useRef, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
const SilkFlowShader: 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
|
+
float hash(vec3 p) {
|
|
40
|
+
p = fract(p * 0.3183099 + 0.1);
|
|
41
|
+
p *= 17.0;
|
|
42
|
+
return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
float noise(vec3 x) {
|
|
46
|
+
vec3 p = floor(x);
|
|
47
|
+
vec3 f = fract(x);
|
|
48
|
+
f = f * f * (3.0 - 2.0 * f);
|
|
49
|
+
|
|
50
|
+
return mix(
|
|
51
|
+
mix(mix(hash(p), hash(p + vec3(1,0,0)), f.x),
|
|
52
|
+
mix(hash(p + vec3(0,1,0)), hash(p + vec3(1,1,0)), f.x), f.y),
|
|
53
|
+
mix(mix(hash(p + vec3(0,0,1)), hash(p + vec3(1,0,1)), f.x),
|
|
54
|
+
mix(hash(p + vec3(0,1,1)), hash(p + vec3(1,1,1)), f.x), f.y),
|
|
55
|
+
f.z);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
float fbm(vec3 p) {
|
|
59
|
+
float value = 0.0;
|
|
60
|
+
float amplitude = 0.5;
|
|
61
|
+
|
|
62
|
+
for(int i = 0; i < 6; i++) {
|
|
63
|
+
value += amplitude * noise(p);
|
|
64
|
+
p *= 2.0;
|
|
65
|
+
amplitude *= 0.5;
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Vertical silk ribbons
|
|
71
|
+
float silkRibbon(vec2 p, float offset, float time) {
|
|
72
|
+
float xPos = offset;
|
|
73
|
+
|
|
74
|
+
// Vertical flowing motion
|
|
75
|
+
float flow = p.y - time * 0.5;
|
|
76
|
+
|
|
77
|
+
// Wavy horizontal displacement
|
|
78
|
+
float wave = sin(flow * 3.0 + offset * 5.0) * 0.15;
|
|
79
|
+
wave += sin(flow * 5.0 - offset * 3.0) * 0.08;
|
|
80
|
+
|
|
81
|
+
// Distance from ribbon center
|
|
82
|
+
float dist = abs(p.x - (xPos + wave));
|
|
83
|
+
|
|
84
|
+
// Ribbon width
|
|
85
|
+
float width = 0.12 + sin(flow * 2.0 + offset) * 0.03;
|
|
86
|
+
|
|
87
|
+
return smoothstep(width, width * 0.3, dist);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
void main() {
|
|
91
|
+
vec2 uv = gl_FragCoord.xy / resolution.xy;
|
|
92
|
+
vec2 p = (uv - 0.5) * 2.0;
|
|
93
|
+
p.x *= resolution.x / resolution.y;
|
|
94
|
+
|
|
95
|
+
float t = time * 0.4;
|
|
96
|
+
|
|
97
|
+
// Add subtle noise distortion
|
|
98
|
+
vec3 noisePos = vec3(p * 2.0, t * 0.3);
|
|
99
|
+
float noiseVal = fbm(noisePos) - 0.5;
|
|
100
|
+
vec2 distorted = p + vec2(noiseVal * 0.1);
|
|
101
|
+
|
|
102
|
+
// Create multiple silk ribbons
|
|
103
|
+
vec3 finalColor = vec3(0.0);
|
|
104
|
+
float totalMask = 0.0;
|
|
105
|
+
|
|
106
|
+
float ribbonOffsets[7];
|
|
107
|
+
ribbonOffsets[0] = -0.9;
|
|
108
|
+
ribbonOffsets[1] = -0.6;
|
|
109
|
+
ribbonOffsets[2] = -0.3;
|
|
110
|
+
ribbonOffsets[3] = 0.0;
|
|
111
|
+
ribbonOffsets[4] = 0.3;
|
|
112
|
+
ribbonOffsets[5] = 0.6;
|
|
113
|
+
ribbonOffsets[6] = 0.9;
|
|
114
|
+
|
|
115
|
+
for(int i = 0; i < 7; i++) {
|
|
116
|
+
float offset = ribbonOffsets[i];
|
|
117
|
+
float fi = float(i);
|
|
118
|
+
|
|
119
|
+
// Calculate ribbon with individual time offset
|
|
120
|
+
float ribbon = silkRibbon(distorted, offset, t + fi * 0.3);
|
|
121
|
+
|
|
122
|
+
// Flow position for color
|
|
123
|
+
float flowPos = distorted.y - t * 0.5 + fi * 0.5;
|
|
124
|
+
|
|
125
|
+
// Color gradient - blue to magenta
|
|
126
|
+
vec3 blueColor = vec3(0.0, 0.3, 1.0); // Bright blue
|
|
127
|
+
vec3 cyanColor = vec3(0.0, 0.7, 1.0); // Cyan
|
|
128
|
+
vec3 magentaColor = vec3(1.0, 0.0, 0.8); // Magenta
|
|
129
|
+
vec3 purpleColor = vec3(0.6, 0.1, 1.0); // Purple
|
|
130
|
+
|
|
131
|
+
// Vertical gradient based on flow
|
|
132
|
+
float colorPhase = fract(flowPos * 0.5);
|
|
133
|
+
vec3 color = mix(blueColor, cyanColor, colorPhase);
|
|
134
|
+
color = mix(color, magentaColor, smoothstep(0.3, 0.7, colorPhase));
|
|
135
|
+
color = mix(color, purpleColor, smoothstep(0.7, 1.0, colorPhase));
|
|
136
|
+
|
|
137
|
+
// Add position-based variation
|
|
138
|
+
float posVariation = sin(offset * 10.0 + t) * 0.5 + 0.5;
|
|
139
|
+
color = mix(color, magentaColor, posVariation * 0.3);
|
|
140
|
+
|
|
141
|
+
// Silk sheen effect - bright highlights
|
|
142
|
+
float sheen = pow(abs(sin(flowPos * 8.0 + offset * 5.0)), 6.0);
|
|
143
|
+
vec3 sheenColor = vec3(0.8, 0.9, 1.0);
|
|
144
|
+
color += sheenColor * sheen * ribbon * 0.5;
|
|
145
|
+
|
|
146
|
+
// Edge glow
|
|
147
|
+
float edgeDist = ribbon * (1.0 - ribbon) * 4.0;
|
|
148
|
+
vec3 edgeColor = mix(cyanColor, magentaColor, posVariation);
|
|
149
|
+
color += edgeColor * edgeDist * 0.4;
|
|
150
|
+
|
|
151
|
+
// Translucent layering
|
|
152
|
+
finalColor = mix(finalColor, color, ribbon * 0.85);
|
|
153
|
+
totalMask += ribbon * 0.3;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add flowing particles/streaks
|
|
157
|
+
float streaks = 0.0;
|
|
158
|
+
for(int i = 0; i < 5; i++) {
|
|
159
|
+
float fi = float(i);
|
|
160
|
+
float streakX = sin(t * 0.7 + fi * 2.0) * 1.5;
|
|
161
|
+
float streakY = fract((distorted.y + t * 0.8 + fi * 0.2) * 0.5) * 4.0 - 2.0;
|
|
162
|
+
|
|
163
|
+
float streakDist = length(distorted - vec2(streakX, streakY));
|
|
164
|
+
streaks += (1.0 - smoothstep(0.0, 0.05, streakDist)) * 0.3;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
finalColor += vec3(0.6, 0.8, 1.0) * streaks;
|
|
168
|
+
|
|
169
|
+
// Subtle shimmer
|
|
170
|
+
float shimmer = fbm(vec3(distorted * 6.0, t * 2.0));
|
|
171
|
+
shimmer = pow(shimmer, 5.0);
|
|
172
|
+
finalColor += vec3(0.7, 0.6, 1.0) * shimmer * totalMask * 0.2;
|
|
173
|
+
|
|
174
|
+
// Vignette
|
|
175
|
+
float vignette = 1.0 - length(vec2(uv.x - 0.5, (uv.y - 0.5) * 0.7)) * 0.5;
|
|
176
|
+
finalColor *= vignette;
|
|
177
|
+
|
|
178
|
+
// Enhance colors
|
|
179
|
+
finalColor *= 1.15;
|
|
180
|
+
|
|
181
|
+
gl_FragColor = vec4(finalColor, 1.0);
|
|
182
|
+
}
|
|
183
|
+
`;
|
|
184
|
+
|
|
185
|
+
const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
|
|
186
|
+
const shader = gl.createShader(type);
|
|
187
|
+
if (!shader) return null;
|
|
188
|
+
|
|
189
|
+
gl.shaderSource(shader, source);
|
|
190
|
+
gl.compileShader(shader);
|
|
191
|
+
|
|
192
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
193
|
+
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
|
|
194
|
+
gl.deleteShader(shader);
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return shader;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
202
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
|
|
203
|
+
|
|
204
|
+
if (!vertexShader || !fragmentShader) return;
|
|
205
|
+
|
|
206
|
+
const program = gl.createProgram();
|
|
207
|
+
if (!program) return;
|
|
208
|
+
|
|
209
|
+
gl.attachShader(program, vertexShader);
|
|
210
|
+
gl.attachShader(program, fragmentShader);
|
|
211
|
+
gl.linkProgram(program);
|
|
212
|
+
|
|
213
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
214
|
+
console.error('Program link error:', gl.getProgramInfoLog(program));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const positionBuffer = gl.createBuffer();
|
|
219
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
220
|
+
gl.bufferData(
|
|
221
|
+
gl.ARRAY_BUFFER,
|
|
222
|
+
new Float32Array([
|
|
223
|
+
-1, -1,
|
|
224
|
+
1, -1,
|
|
225
|
+
-1, 1,
|
|
226
|
+
1, 1,
|
|
227
|
+
]),
|
|
228
|
+
gl.STATIC_DRAW
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const positionLocation = gl.getAttribLocation(program, 'position');
|
|
232
|
+
const resolutionLocation = gl.getUniformLocation(program, 'resolution');
|
|
233
|
+
const timeLocation = gl.getUniformLocation(program, 'time');
|
|
234
|
+
|
|
235
|
+
let startTime = Date.now();
|
|
236
|
+
|
|
237
|
+
const render = () => {
|
|
238
|
+
if (!gl || !canvas) return;
|
|
239
|
+
|
|
240
|
+
gl.clearColor(0, 0, 0, 1);
|
|
241
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
242
|
+
|
|
243
|
+
gl.useProgram(program);
|
|
244
|
+
|
|
245
|
+
gl.enableVertexAttribArray(positionLocation);
|
|
246
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
247
|
+
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
|
|
248
|
+
|
|
249
|
+
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
|
|
250
|
+
gl.uniform1f(timeLocation, (Date.now() - startTime) / 1000);
|
|
251
|
+
|
|
252
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
253
|
+
|
|
254
|
+
animationRef.current = requestAnimationFrame(render);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
render();
|
|
258
|
+
|
|
259
|
+
return () => {
|
|
260
|
+
window.removeEventListener('resize', resizeCanvas);
|
|
261
|
+
if (animationRef.current) {
|
|
262
|
+
cancelAnimationFrame(animationRef.current);
|
|
263
|
+
}
|
|
264
|
+
gl.deleteProgram(program);
|
|
265
|
+
gl.deleteShader(vertexShader);
|
|
266
|
+
gl.deleteShader(fragmentShader);
|
|
267
|
+
gl.deleteBuffer(positionBuffer);
|
|
268
|
+
};
|
|
269
|
+
}, []);
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<div ref={containerRef} className="absolute inset-0 w-full h-full bg-black overflow-hidden">
|
|
273
|
+
<canvas
|
|
274
|
+
ref={canvasRef}
|
|
275
|
+
className="absolute top-0 left-0 w-full h-full"
|
|
276
|
+
/>
|
|
277
|
+
</div>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
export default SilkFlowShader;
|