shaderz 1.0.0 → 1.0.1

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/dist/cli.js CHANGED
@@ -62,30 +62,43 @@ var SHADERS = [
62
62
  description: "Space-themed nebula shader",
63
63
  file: "CosmicNebulaShader"
64
64
  },
65
- {
66
- name: "glossy-ribbon",
67
- title: "Glossy Ribbon",
68
- description: "Glossy ribbon flow shader",
69
- file: "GlossyRibbonShader"
70
- },
71
65
  {
72
66
  name: "silk-flow",
73
67
  title: "Silk Flow",
74
68
  description: "Smooth silk flow shader",
75
69
  file: "SilkFlowShader"
76
70
  },
77
- {
78
- name: "glass-twist",
79
- title: "Glass Twist",
80
- description: "Glass twist effect shader",
81
- file: "GlassTwistShader"
82
- },
83
71
  {
84
72
  name: "plasma",
85
73
  title: "Plasma",
86
74
  description: "Classic plasma shader",
87
75
  file: "PlasmaShader"
88
76
  },
77
+ {
78
+ name: "plasma-v2",
79
+ title: "Plasma V2",
80
+ description: "Enhanced plasma shader with more colors",
81
+ file: "PlasmaV2Shader"
82
+ },
83
+ {
84
+ name: "dark-veil",
85
+ title: "Dark Veil",
86
+ description: "Mysterious dark veil with blue/purple gradient",
87
+ file: "DarkVeilShader"
88
+ },
89
+ {
90
+ name: "liquid-motion",
91
+ title: "Liquid Motion",
92
+ description: "Advanced fluid simulation with Three.js",
93
+ file: "LiquidMotionShader",
94
+ hasCss: true
95
+ },
96
+ {
97
+ name: "frothy-galaxy",
98
+ title: "Frothy Galaxy",
99
+ description: "Galactic frothy effect shader",
100
+ file: "FrothyGalaxyShader"
101
+ },
89
102
  {
90
103
  name: "glossy-film",
91
104
  title: "Glossy Film (Video)",
@@ -93,6 +106,14 @@ var SHADERS = [
93
106
  file: "VideoBackground",
94
107
  isVideo: true,
95
108
  videoFile: "glossy-film.mp4"
109
+ },
110
+ {
111
+ name: "nova-silk",
112
+ title: "Nova Silk (Video)",
113
+ description: "Elegant flowing silk video background",
114
+ file: "VideoBackground",
115
+ isVideo: true,
116
+ videoFile: "nova-silk.mp4"
96
117
  }
97
118
  ];
98
119
  async function addShaders() {
@@ -167,7 +188,14 @@ No components directory found. Will create: ${componentsBase}/shaders/`));
167
188
  const sourceFile = import_path.default.join(__dirname, "..", "shaders", `${shader.file}.tsx`);
168
189
  const targetFile = import_path.default.join(componentsDir, `${shader.file}${fileExtension}`);
169
190
  await import_fs_extra.default.copy(sourceFile, targetFile);
170
- spinner.succeed(`Added ${import_chalk.default.green(shader.title)}`);
191
+ if (shader.hasCss) {
192
+ const sourceCss = import_path.default.join(__dirname, "..", "shaders", "LiqMotion.css");
193
+ const targetCss = import_path.default.join(componentsDir, "LiqMotion.css");
194
+ await import_fs_extra.default.copy(sourceCss, targetCss);
195
+ spinner.succeed(`Added ${import_chalk.default.green(shader.title)} (with CSS file)`);
196
+ } else {
197
+ spinner.succeed(`Added ${import_chalk.default.green(shader.title)}`);
198
+ }
171
199
  spinner.start();
172
200
  }
173
201
  spinner.stop();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shaderz",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI tool to add beautiful WebGL shaders to your React/Next.js project",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -48,4 +48,4 @@
48
48
  "url": "https://github.com/harsh-and-shubham/shaderz/issues"
49
49
  },
50
50
  "homepage": "https://shaderz.vercel.app"
51
- }
51
+ }
@@ -0,0 +1,337 @@
1
+ 'use client';
2
+ import { useEffect, useRef, useCallback } from 'react';
3
+
4
+ function DarkVeil() {
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
+ const isContextLostRef = useRef(false);
10
+
11
+ const createRenderer = useCallback(() => {
12
+ const canvas = canvasRef.current;
13
+ if (!canvas) return null;
14
+
15
+ const gl = canvas.getContext('webgl', {
16
+ preserveDrawingBuffer: true,
17
+ powerPreference: 'high-performance',
18
+ failIfMajorPerformanceCaveat: false,
19
+ });
20
+
21
+ if (!gl) {
22
+ console.error('WebGL not supported');
23
+ return null;
24
+ }
25
+
26
+ return gl;
27
+ }, []);
28
+
29
+ const compileShaderProgram = useCallback((gl: WebGLRenderingContext) => {
30
+ const vertexShaderSource = `
31
+ attribute vec2 position;
32
+ void main() {
33
+ gl_Position = vec4(position, 0.0, 1.0);
34
+ }
35
+ `;
36
+
37
+ const fragmentShaderSource = `
38
+ precision highp float;
39
+ uniform vec2 resolution;
40
+ uniform float time;
41
+
42
+ // Organic procedural pattern generation
43
+ float seedPoint(vec2 p) {
44
+ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
45
+ }
46
+
47
+ float organicBlend(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 = seedPoint(i);
53
+ float b = seedPoint(i + vec2(1.0, 0.0));
54
+ float c = seedPoint(i + vec2(0.0, 1.0));
55
+ float d = seedPoint(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
+ void main() {
61
+ vec2 uv = gl_FragCoord.xy / resolution.xy;
62
+ vec2 center = uv - 0.5;
63
+ center.x *= resolution.x / resolution.y;
64
+
65
+ // Floating movement - smooth and organic
66
+ float floatX = sin(time * 0.3) * 0.15 + cos(time * 0.2) * 0.1;
67
+ float floatY = cos(time * 0.25) * 0.12 + sin(time * 0.35) * 0.08;
68
+ center -= vec2(floatX, floatY);
69
+
70
+ // Distance from center
71
+ float dist = length(center);
72
+
73
+ // Smooth noise-based distortion (no sharp angles)
74
+ float n1 = organicBlend(center * 3.0 + time * 0.2) * 0.1;
75
+ float n2 = organicBlend(center * 5.0 - time * 0.15) * 0.05;
76
+ dist += n1 + n2;
77
+
78
+ // Very soft gradient falloff - blurred edges
79
+ float gradient = 1.0 - smoothstep(0.0, 0.8, dist);
80
+ gradient = pow(gradient, 0.8); // Softer power for blur effect
81
+
82
+ // Smooth the center completely - no sharp point
83
+ float centerBlur = smoothstep(0.0, 0.15, dist);
84
+ gradient *= centerBlur * 0.5 + 0.5;
85
+
86
+ // Blue to Purple gradient based on smooth organicBlend
87
+ vec3 blue = vec3(0.2, 0.4, 0.9);
88
+ vec3 purple = vec3(0.6, 0.2, 0.8);
89
+ vec3 magenta = vec3(0.8, 0.1, 0.6);
90
+
91
+ // Smooth color mixing based on organicBlend (not angle)
92
+ float colorVariation = organicBlend(center * 2.0 + time * 0.1);
93
+ float colorVariation2 = organicBlend(center * 1.5 - time * 0.08);
94
+
95
+ vec3 gradientColor = mix(blue, purple, colorVariation);
96
+ gradientColor = mix(gradientColor, magenta, colorVariation2 * 0.4);
97
+
98
+ // Apply gradient strength
99
+ vec3 col = gradientColor * gradient;
100
+
101
+ // Soft outer glow
102
+ float glow = 1.0 - smoothstep(0.0, 1.2, dist);
103
+ glow = pow(glow, 2.5) * 0.2;
104
+ col += gradientColor * glow;
105
+
106
+ // Pure black background
107
+ gl_FragColor = vec4(col, 1.0);
108
+ }
109
+ `;
110
+
111
+ const buildGLShader = (gl: WebGLRenderingContext, type: number, source: string) => {
112
+ const shader = gl.createShader(type);
113
+ if (!shader) return null;
114
+
115
+ gl.shaderSource(shader, source);
116
+ gl.compileShader(shader);
117
+
118
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
119
+ console.error('Shader compile error:', gl.getShaderInfoLog(shader));
120
+ gl.deleteShader(shader);
121
+ return null;
122
+ }
123
+ return shader;
124
+ };
125
+
126
+ const vertexShader = buildGLShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
127
+ const fragmentShader = buildGLShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
128
+
129
+ if (!vertexShader || !fragmentShader) return null;
130
+
131
+ const program = gl.createProgram();
132
+ if (!program) return null;
133
+
134
+ gl.attachShader(program, vertexShader);
135
+ gl.attachShader(program, fragmentShader);
136
+ gl.linkProgram(program);
137
+
138
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
139
+ console.error('Program link error:', gl.getProgramInfoLog(program));
140
+ return null;
141
+ }
142
+
143
+ return program;
144
+ }, []);
145
+
146
+ useEffect(() => {
147
+ const canvas = canvasRef.current;
148
+ if (!canvas) return;
149
+
150
+ let gl = createRenderer();
151
+ if (!gl) return;
152
+
153
+ glRef.current = gl;
154
+
155
+ const updateCanvasSize = () => {
156
+ if (!canvas || !gl || isContextLostRef.current) return;
157
+ const parent = canvas.parentElement;
158
+ if (parent) {
159
+ canvas.width = parent.clientWidth;
160
+ canvas.height = parent.clientHeight;
161
+ } else {
162
+ canvas.width = window.innerWidth;
163
+ canvas.height = window.innerHeight;
164
+ }
165
+ gl.viewport(0, 0, canvas.width, canvas.height);
166
+ };
167
+
168
+ updateCanvasSize();
169
+ window.addEventListener('resize', updateCanvasSize);
170
+
171
+ let program = compileShaderProgram(gl);
172
+ if (!program) return;
173
+
174
+ programRef.current = program;
175
+
176
+ const positionBuffer = gl.createBuffer();
177
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
178
+ const positions = new Float32Array([
179
+ -1, -1,
180
+ 1, -1,
181
+ -1, 1,
182
+ 1, 1
183
+ ]);
184
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
185
+
186
+ let positionLocation = gl.getAttribLocation(program, 'position');
187
+ let resolutionLocation = gl.getUniformLocation(program, 'resolution');
188
+ let timeLocation = gl.getUniformLocation(program, 'time');
189
+
190
+ const startTime = performance.now();
191
+
192
+ const drawFrame = () => {
193
+ if (isContextLostRef.current || !gl || !program) {
194
+ animationRef.current = requestAnimationFrame(drawFrame);
195
+ return;
196
+ }
197
+
198
+ const elapsedTime = (performance.now() - startTime) * 0.001;
199
+
200
+ gl.clearColor(0.0, 0.0, 0.0, 1.0); // Pure black
201
+ gl.clear(gl.COLOR_BUFFER_BIT);
202
+ gl.useProgram(program);
203
+
204
+ gl.enableVertexAttribArray(positionLocation);
205
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
206
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
207
+
208
+ gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
209
+ gl.uniform1f(timeLocation, elapsedTime);
210
+
211
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
212
+
213
+ animationRef.current = requestAnimationFrame(drawFrame);
214
+ };
215
+
216
+ const onContextLost = (event: Event) => {
217
+ event.preventDefault();
218
+ isContextLostRef.current = true;
219
+ };
220
+
221
+ const onContextRestored = () => {
222
+ isContextLostRef.current = false;
223
+ gl = createRenderer();
224
+ if (!gl) return;
225
+ glRef.current = gl;
226
+ updateCanvasSize();
227
+ program = compileShaderProgram(gl);
228
+ if (!program) return;
229
+ programRef.current = program;
230
+
231
+ const newBuffer = gl.createBuffer();
232
+ gl.bindBuffer(gl.ARRAY_BUFFER, newBuffer);
233
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
234
+
235
+ positionLocation = gl.getAttribLocation(program, 'position');
236
+ resolutionLocation = gl.getUniformLocation(program, 'resolution');
237
+ timeLocation = gl.getUniformLocation(program, 'time');
238
+ };
239
+
240
+ const onVisibilityChange = () => {
241
+ if (document.visibilityState === 'visible' && !isContextLostRef.current) {
242
+ updateCanvasSize();
243
+ }
244
+ };
245
+
246
+ canvas.addEventListener('webglcontextlost', onContextLost);
247
+ canvas.addEventListener('webglcontextrestored', onContextRestored);
248
+ document.addEventListener('visibilitychange', onVisibilityChange);
249
+
250
+ animationRef.current = requestAnimationFrame(drawFrame);
251
+
252
+ return () => {
253
+ window.removeEventListener('resize', updateCanvasSize);
254
+ canvas.removeEventListener('webglcontextlost', onContextLost);
255
+ canvas.removeEventListener('webglcontextrestored', onContextRestored);
256
+ document.removeEventListener('visibilitychange', onVisibilityChange);
257
+ if (animationRef.current) {
258
+ cancelAnimationFrame(animationRef.current);
259
+ }
260
+ };
261
+ }, [createRenderer, compileShaderProgram]);
262
+
263
+ return (
264
+ <div className="absolute inset-0 w-full h-full bg-black overflow-hidden">
265
+ <canvas
266
+ ref={canvasRef}
267
+ className="absolute top-0 left-0 w-full h-full pointer-events-none"
268
+ />
269
+ </div>
270
+ );
271
+ }
272
+
273
+ // Export the fragment shader for ShaderPreview compatibility
274
+ export const fragment = `
275
+ precision highp float;
276
+ uniform vec2 resolution;
277
+ uniform float time;
278
+
279
+ float seedPoint(vec2 p) {
280
+ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
281
+ }
282
+
283
+ float organicBlend(vec2 p) {
284
+ vec2 i = floor(p);
285
+ vec2 f = fract(p);
286
+ f = f * f * (3.0 - 2.0 * f);
287
+
288
+ float a = seedPoint(i);
289
+ float b = seedPoint(i + vec2(1.0, 0.0));
290
+ float c = seedPoint(i + vec2(0.0, 1.0));
291
+ float d = seedPoint(i + vec2(1.0, 1.0));
292
+
293
+ return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
294
+ }
295
+
296
+ void main() {
297
+ vec2 uv = gl_FragCoord.xy / resolution.xy;
298
+ vec2 center = uv - 0.5;
299
+ center.x *= resolution.x / resolution.y;
300
+
301
+ float floatX = sin(time * 0.3) * 0.15 + cos(time * 0.2) * 0.1;
302
+ float floatY = cos(time * 0.25) * 0.12 + sin(time * 0.35) * 0.08;
303
+ center -= vec2(floatX, floatY);
304
+
305
+ float dist = length(center);
306
+
307
+ float n1 = organicBlend(center * 3.0 + time * 0.2) * 0.1;
308
+ float n2 = organicBlend(center * 5.0 - time * 0.15) * 0.05;
309
+ dist += n1 + n2;
310
+
311
+ float gradient = 1.0 - smoothstep(0.0, 0.8, dist);
312
+ gradient = pow(gradient, 0.8);
313
+
314
+ float centerBlur = smoothstep(0.0, 0.15, dist);
315
+ gradient *= centerBlur * 0.5 + 0.5;
316
+
317
+ vec3 blue = vec3(0.2, 0.4, 0.9);
318
+ vec3 purple = vec3(0.6, 0.2, 0.8);
319
+ vec3 magenta = vec3(0.8, 0.1, 0.6);
320
+
321
+ float colorVariation = organicBlend(center * 2.0 + time * 0.1);
322
+ float colorVariation2 = organicBlend(center * 1.5 - time * 0.08);
323
+
324
+ vec3 gradientColor = mix(blue, purple, colorVariation);
325
+ gradientColor = mix(gradientColor, magenta, colorVariation2 * 0.4);
326
+
327
+ vec3 col = gradientColor * gradient;
328
+
329
+ float glow = 1.0 - smoothstep(0.0, 1.2, dist);
330
+ glow = pow(glow, 2.5) * 0.2;
331
+ col += gradientColor * glow;
332
+
333
+ gl_FragColor = vec4(col, 1.0);
334
+ }
335
+ `;
336
+
337
+ export default DarkVeil;
@@ -0,0 +1,216 @@
1
+ 'use client';
2
+ import React, { useRef, useEffect } from 'react';
3
+
4
+ const FrothyGalaxyShader: 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(vec2 p) {
40
+ p = fract(p * vec2(123.34, 456.21));
41
+ p += dot(p, p + 45.32);
42
+ return fract(p.x * p.y);
43
+ }
44
+
45
+ float noise(vec2 p) {
46
+ vec2 i = floor(p);
47
+ vec2 f = fract(p);
48
+ f = f * f * (3.0 - 2.0 * f);
49
+
50
+ float a = hash(i);
51
+ float b = hash(i + vec2(1.0, 0.0));
52
+ float c = hash(i + vec2(0.0, 1.0));
53
+ float d = hash(i + vec2(1.0, 1.0));
54
+
55
+ return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
56
+ }
57
+
58
+ float fbm(vec2 p) {
59
+ float value = 0.0;
60
+ float amplitude = 0.5;
61
+ float frequency = 1.0;
62
+
63
+ for(int i = 0; i < 5; i++) {
64
+ value += amplitude * noise(p * frequency);
65
+ frequency *= 2.0;
66
+ amplitude *= 0.5;
67
+ }
68
+ return value;
69
+ }
70
+
71
+ void main() {
72
+ vec2 uv = gl_FragCoord.xy / resolution.xy;
73
+ vec2 p = (uv - 0.5) * 2.0;
74
+ p.x *= resolution.x / resolution.y;
75
+
76
+ // Smooth flowing waves
77
+ float wave1 = sin(p.x * 2.0 + time * 0.5) * 0.3;
78
+ float wave2 = sin(p.x * 1.5 - p.y * 0.8 + time * 0.4) * 0.2;
79
+ float wave3 = sin(p.x * 3.0 + p.y * 1.5 + time * 0.6) * 0.15;
80
+ float waves = wave1 + wave2 + wave3;
81
+
82
+ // Add noise detail
83
+ waves += fbm(p * 2.0 + vec2(time * 0.1, 0.0)) * 0.2;
84
+
85
+ // Normalized wave height
86
+ float h = waves * 0.5 + 0.5;
87
+
88
+ // Beautiful gradient colors
89
+ vec3 color1 = vec3(0.1, 0.3, 0.6); // Deep blue
90
+ vec3 color2 = vec3(0.2, 0.5, 0.8); // Medium blue
91
+ vec3 color3 = vec3(0.4, 0.7, 0.9); // Light blue
92
+ vec3 color4 = vec3(0.6, 0.85, 0.95); // Pale blue
93
+
94
+ // Smooth color transitions
95
+ vec3 color;
96
+ if (h < 0.33) {
97
+ color = mix(color1, color2, h * 3.0);
98
+ } else if (h < 0.66) {
99
+ color = mix(color2, color3, (h - 0.33) * 3.0);
100
+ } else {
101
+ color = mix(color3, color4, (h - 0.66) * 3.0);
102
+ }
103
+
104
+ // Add shimmer
105
+ float shimmer = fbm(p * 6.0 + vec2(time * 0.3, time * 0.2));
106
+ shimmer = pow(shimmer, 2.0) * 0.3;
107
+ color += vec3(shimmer);
108
+
109
+ // Depth fade
110
+ color = mix(color, color1 * 0.8, (1.0 - uv.y) * 0.4);
111
+
112
+ // Subtle vignette
113
+ float dist = length(uv - 0.5);
114
+ color *= 1.0 - dist * 0.3;
115
+
116
+ gl_FragColor = vec4(color, 1.0);
117
+ }
118
+ `;
119
+
120
+ const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
121
+ const shader = gl.createShader(type);
122
+ if (!shader) return null;
123
+
124
+ gl.shaderSource(shader, source);
125
+ gl.compileShader(shader);
126
+
127
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
128
+ console.error('Shader compile error:', gl.getShaderInfoLog(shader));
129
+ gl.deleteShader(shader);
130
+ return null;
131
+ }
132
+
133
+ return shader;
134
+ };
135
+
136
+ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
137
+ const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
138
+
139
+ if (!vertexShader || !fragmentShader) return;
140
+
141
+ const program = gl.createProgram();
142
+ if (!program) return;
143
+
144
+ gl.attachShader(program, vertexShader);
145
+ gl.attachShader(program, fragmentShader);
146
+ gl.linkProgram(program);
147
+
148
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
149
+ console.error('Program link error:', gl.getProgramInfoLog(program));
150
+ return;
151
+ }
152
+
153
+ const positionBuffer = gl.createBuffer();
154
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
155
+ gl.bufferData(
156
+ gl.ARRAY_BUFFER,
157
+ new Float32Array([
158
+ -1, -1,
159
+ 1, -1,
160
+ -1, 1,
161
+ 1, 1,
162
+ ]),
163
+ gl.STATIC_DRAW
164
+ );
165
+
166
+ const positionLocation = gl.getAttribLocation(program, 'position');
167
+ const resolutionLocation = gl.getUniformLocation(program, 'resolution');
168
+ const timeLocation = gl.getUniformLocation(program, 'time');
169
+
170
+ let startTime = Date.now();
171
+
172
+ const render = () => {
173
+ if (!gl || !canvas) return;
174
+
175
+ gl.clearColor(0, 0, 0, 1);
176
+ gl.clear(gl.COLOR_BUFFER_BIT);
177
+
178
+ gl.useProgram(program);
179
+
180
+ gl.enableVertexAttribArray(positionLocation);
181
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
182
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
183
+
184
+ gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
185
+ gl.uniform1f(timeLocation, (Date.now() - startTime) / 1000);
186
+
187
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
188
+
189
+ animationRef.current = requestAnimationFrame(render);
190
+ };
191
+
192
+ render();
193
+
194
+ return () => {
195
+ window.removeEventListener('resize', resizeCanvas);
196
+ if (animationRef.current) {
197
+ cancelAnimationFrame(animationRef.current);
198
+ }
199
+ gl.deleteProgram(program);
200
+ gl.deleteShader(vertexShader);
201
+ gl.deleteShader(fragmentShader);
202
+ gl.deleteBuffer(positionBuffer);
203
+ };
204
+ }, []);
205
+
206
+ return (
207
+ <div ref={containerRef} className="absolute inset-0 w-full h-full bg-black overflow-hidden">
208
+ <canvas
209
+ ref={canvasRef}
210
+ className="absolute top-0 left-0 w-full h-full"
211
+ />
212
+ </div>
213
+ );
214
+ };
215
+
216
+ export default FrothyGalaxyShader;
@@ -0,0 +1,13 @@
1
+ .liquid-ether-container {
2
+ position: absolute;
3
+ inset: 0;
4
+ width: 100%;
5
+ height: 100%;
6
+ overflow: hidden;
7
+ }
8
+
9
+ .liquid-ether-container canvas {
10
+ display: block;
11
+ width: 100%;
12
+ height: 100%;
13
+ }