apex-ui-kit 2.0.5
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/Licence.md +21 -0
- package/ReadMe.md +75 -0
- package/dist/ApexUI-Kit/templates/Avatar/Avatar.jsx +81 -0
- package/dist/ApexUI-Kit/templates/BeamBar/BeamBar.jsx +101 -0
- package/dist/ApexUI-Kit/templates/Cards/BasicCard.jsx +60 -0
- package/dist/ApexUI-Kit/templates/Carousel/Carousel.jsx +95 -0
- package/dist/ApexUI-Kit/templates/Carousel/DragCarousel.jsx +105 -0
- package/dist/ApexUI-Kit/templates/Carousel/ParallaxCarousel.jsx +161 -0
- package/dist/ApexUI-Kit/templates/DragCarousel/DragCarousel.jsx +105 -0
- package/dist/ApexUI-Kit/templates/EdgeGlowForm/EdgeGlowFrom.jsx +297 -0
- package/dist/ApexUI-Kit/templates/FlipProfile/FlipProfile.jsx +125 -0
- package/dist/ApexUI-Kit/templates/GlareCard/GlareCard.jsx +146 -0
- package/dist/ApexUI-Kit/templates/GlassCardStack/GlassCardStack.jsx +111 -0
- package/dist/ApexUI-Kit/templates/HoverText/HoverText.jsx +371 -0
- package/dist/ApexUI-Kit/templates/HyperCard/HyperCard.jsx +183 -0
- package/dist/ApexUI-Kit/templates/KineticThreadsBackground/KineticThreadBackground.jsx +249 -0
- package/dist/ApexUI-Kit/templates/LensFlareBackground/LensFlareBackground.jsx +268 -0
- package/dist/ApexUI-Kit/templates/LuminousParticleOcean/LuminousParticleOcean.jsx +155 -0
- package/dist/ApexUI-Kit/templates/NavDropDown/NavDropDown.jsx +114 -0
- package/dist/ApexUI-Kit/templates/NavMenu/NavMenu.jsx +153 -0
- package/dist/ApexUI-Kit/templates/OrbsBackground/FloatingOrbs.jsx +96 -0
- package/dist/ApexUI-Kit/templates/ParallaxCard/ParallaxCard.jsx +127 -0
- package/dist/ApexUI-Kit/templates/ParallaxCarousel/ParallaxCarousel.jsx +161 -0
- package/dist/ApexUI-Kit/templates/ParallaxProfile/ParallaxProfile.jsx +107 -0
- package/dist/ApexUI-Kit/templates/PointerFollower/PointerFollower.jsx +126 -0
- package/dist/ApexUI-Kit/templates/RainBackground/RainBackground.jsx +109 -0
- package/dist/ApexUI-Kit/templates/RippleBackground/RippleBackground.jsx +160 -0
- package/dist/ApexUI-Kit/templates/ScrollMarquee/ScrollMarquee.jsx +174 -0
- package/dist/ApexUI-Kit/templates/SmartGridCard/SmartGridCard.jsx +241 -0
- package/dist/ApexUI-Kit/templates/SmokeBackground/SmokeBackground.jsx +216 -0
- package/dist/ApexUI-Kit/templates/Testimonials/Testimonials.jsx +117 -0
- package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeAnimation.js +252 -0
- package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeConfig.js +8 -0
- package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeToggle.css +560 -0
- package/dist/ApexUI-Kit/templates/ThemeToggle/ThemeToggle.jsx +118 -0
- package/dist/ApexUI-Kit/templates/ToolTip/ToolTip.jsx +85 -0
- package/dist/ApexUI-Kit/templates/WaterDropReveal/WaterDropReveal.jsx +151 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +145 -0
- package/package.json +56 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
|
|
4
|
+
// --- GLSL Shader Code ---
|
|
5
|
+
// Vertex shader (simple, just positions the plane)
|
|
6
|
+
const vertexShader = `
|
|
7
|
+
varying vec2 vUv;
|
|
8
|
+
void main() {
|
|
9
|
+
vUv = uv;
|
|
10
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
// Fragment shader "Kinetic Threads" ke liye
|
|
15
|
+
const fragmentShader = `
|
|
16
|
+
precision highp float;
|
|
17
|
+
|
|
18
|
+
uniform float uTime;
|
|
19
|
+
uniform vec2 uResolution;
|
|
20
|
+
uniform vec3 uColor;
|
|
21
|
+
uniform float uAmplitude;
|
|
22
|
+
uniform float uDistance;
|
|
23
|
+
uniform vec2 uMouse;
|
|
24
|
+
uniform int u_line_count; // Line count ab uniform hai
|
|
25
|
+
|
|
26
|
+
#define PI 3.1415926538
|
|
27
|
+
|
|
28
|
+
const float u_line_width = 7.0;
|
|
29
|
+
const float u_line_blur = 10.0;
|
|
30
|
+
|
|
31
|
+
// Perlin Noise function for organic movement
|
|
32
|
+
float Perlin2D(vec2 P) {
|
|
33
|
+
vec2 Pi = floor(P);
|
|
34
|
+
vec4 Pf_Pfmin1 = P.xyxy - vec4(Pi, Pi + 1.0);
|
|
35
|
+
vec4 Pt = vec4(Pi.xy, Pi.xy + 1.0);
|
|
36
|
+
Pt = Pt - floor(Pt * (1.0 / 71.0)) * 71.0;
|
|
37
|
+
Pt += vec2(26.0, 161.0).xyxy;
|
|
38
|
+
Pt *= Pt;
|
|
39
|
+
Pt = Pt.xzxz * Pt.yyww;
|
|
40
|
+
vec4 hash_x = fract(Pt * (1.0 / 951.135664));
|
|
41
|
+
vec4 hash_y = fract(Pt * (1.0 / 642.949883));
|
|
42
|
+
vec4 grad_x = hash_x - 0.49999;
|
|
43
|
+
vec4 grad_y = hash_y - 0.49999;
|
|
44
|
+
vec4 grad_results = inversesqrt(grad_x * grad_x + grad_y * grad_y)
|
|
45
|
+
* (grad_x * Pf_Pfmin1.xzxz + grad_y * Pf_Pfmin1.yyww);
|
|
46
|
+
grad_results *= 1.4142135623730950;
|
|
47
|
+
vec2 blend = Pf_Pfmin1.xy * Pf_Pfmin1.xy * Pf_Pfmin1.xy
|
|
48
|
+
* (Pf_Pfmin1.xy * (Pf_Pfmin1.xy * 6.0 - 15.0) + 10.0);
|
|
49
|
+
vec4 blend2 = vec4(blend, vec2(1.0 - blend));
|
|
50
|
+
return dot(grad_results, blend2.zxzx * blend2.wwyy);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
float pixel(float count, vec2 resolution) {
|
|
54
|
+
return (1.0 / max(resolution.x, resolution.y)) * count;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Function to draw a single animated line
|
|
58
|
+
float lineFn(vec2 st, float width, float perc, float offset, vec2 mouse, float time, float amplitude, float distance) {
|
|
59
|
+
float split_offset = (perc * 0.4);
|
|
60
|
+
float split_point = 0.1 + split_offset;
|
|
61
|
+
|
|
62
|
+
float amplitude_normal = smoothstep(split_point, 0.7, st.x);
|
|
63
|
+
float amplitude_strength = 0.5;
|
|
64
|
+
float finalAmplitude = amplitude_normal * amplitude_strength
|
|
65
|
+
* amplitude * (1.0 + (mouse.y - 0.5) * 0.2);
|
|
66
|
+
|
|
67
|
+
float time_scaled = time / 10.0 + (mouse.x - 0.5) * 1.0;
|
|
68
|
+
float blur = smoothstep(split_point, split_point + 0.05, st.x) * perc;
|
|
69
|
+
|
|
70
|
+
float xnoise = mix(
|
|
71
|
+
Perlin2D(vec2(time_scaled, st.x + perc) * 2.5),
|
|
72
|
+
Perlin2D(vec2(time_scaled, st.x + time_scaled) * 3.5) / 1.5,
|
|
73
|
+
st.x * 0.3
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
float y = 0.5 + (perc - 0.5) * distance + xnoise / 2.0 * finalAmplitude;
|
|
77
|
+
|
|
78
|
+
float line_start = smoothstep(
|
|
79
|
+
y + (width / 2.0) + (u_line_blur * pixel(1.0, uResolution.xy) * blur),
|
|
80
|
+
y,
|
|
81
|
+
st.y
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
float line_end = smoothstep(
|
|
85
|
+
y,
|
|
86
|
+
y - (width / 2.0) - (u_line_blur * pixel(1.0, uResolution.xy) * blur),
|
|
87
|
+
st.y
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return clamp(
|
|
91
|
+
(line_start - line_end) * (1.0 - smoothstep(0.0, 1.0, pow(perc, 0.3))),
|
|
92
|
+
0.0,
|
|
93
|
+
1.0
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void main() {
|
|
98
|
+
vec2 uv = gl_FragCoord.xy / uResolution.xy;
|
|
99
|
+
float line_strength1 = 1.0;
|
|
100
|
+
for (int i = 0; i < u_line_count; i++) {
|
|
101
|
+
float p = float(i) / float(u_line_count);
|
|
102
|
+
line_strength1 *= (1.0 - lineFn(
|
|
103
|
+
uv,
|
|
104
|
+
u_line_width * pixel(1.0, uResolution.xy) * (1.0 - p),
|
|
105
|
+
p,
|
|
106
|
+
(PI * 1.0) * p,
|
|
107
|
+
uMouse,
|
|
108
|
+
uTime,
|
|
109
|
+
uAmplitude,
|
|
110
|
+
uDistance
|
|
111
|
+
));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
float line_strength2 = 1.0;
|
|
115
|
+
vec2 mirroredUv = vec2(1.0 - uv.x, uv.y);
|
|
116
|
+
vec2 mirroredMouse = vec2(1.0 - uMouse.x, uMouse.y);
|
|
117
|
+
for (int i = 0; i < u_line_count; i++) {
|
|
118
|
+
float p = float(i) / float(u_line_count);
|
|
119
|
+
line_strength2 *= (1.0 - lineFn(
|
|
120
|
+
mirroredUv,
|
|
121
|
+
u_line_width * pixel(1.0, uResolution.xy) * (1.0 - p),
|
|
122
|
+
p,
|
|
123
|
+
(PI * 1.0) * p,
|
|
124
|
+
mirroredMouse,
|
|
125
|
+
uTime,
|
|
126
|
+
uAmplitude,
|
|
127
|
+
uDistance
|
|
128
|
+
));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
float final_strength = line_strength1 * line_strength2;
|
|
132
|
+
float colorVal = 1.0 - final_strength;
|
|
133
|
+
gl_FragColor = vec4(uColor * colorVal, colorVal);
|
|
134
|
+
}
|
|
135
|
+
`;
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
// --- KineticThreadsBackground Component ---
|
|
139
|
+
const KineticThreadsBackground = ({
|
|
140
|
+
color = "#a3e635", // lime
|
|
141
|
+
amplitude = 1.0,
|
|
142
|
+
distance = 0.5,
|
|
143
|
+
speed = 1.0,
|
|
144
|
+
mouseInteraction = true,
|
|
145
|
+
}) => {
|
|
146
|
+
const mountRef = useRef(null);
|
|
147
|
+
const mouseRef = useRef({ x: 0.5, y: 0.5 });
|
|
148
|
+
const targetMouseRef = useRef({ x: 0.5, y: 0.5 });
|
|
149
|
+
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
const mountNode = mountRef.current;
|
|
152
|
+
|
|
153
|
+
// Scene, Camera, Renderer
|
|
154
|
+
const scene = new THREE.Scene();
|
|
155
|
+
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
156
|
+
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
|
157
|
+
mountNode.appendChild(renderer.domElement);
|
|
158
|
+
|
|
159
|
+
// Shader Material
|
|
160
|
+
const uniforms = {
|
|
161
|
+
uTime: { value: 0 },
|
|
162
|
+
uResolution: { value: new THREE.Vector2() },
|
|
163
|
+
uMouse: { value: new THREE.Vector2(0.5, 0.5) },
|
|
164
|
+
uColor: { value: new THREE.Color(color) },
|
|
165
|
+
uAmplitude: { value: amplitude },
|
|
166
|
+
uDistance: { value: distance },
|
|
167
|
+
u_line_count: { value: 40 } // Default line count
|
|
168
|
+
};
|
|
169
|
+
const material = new THREE.ShaderMaterial({
|
|
170
|
+
vertexShader,
|
|
171
|
+
fragmentShader,
|
|
172
|
+
uniforms,
|
|
173
|
+
transparent: true,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Fullscreen Plane
|
|
177
|
+
const geometry = new THREE.PlaneGeometry(2, 2);
|
|
178
|
+
const plane = new THREE.Mesh(geometry, material);
|
|
179
|
+
scene.add(plane);
|
|
180
|
+
|
|
181
|
+
// Mouse move handler
|
|
182
|
+
const handleMouseMove = (event) => {
|
|
183
|
+
if (!mouseInteraction) return;
|
|
184
|
+
const rect = mountNode.getBoundingClientRect();
|
|
185
|
+
targetMouseRef.current.x = (event.clientX - rect.left) / rect.width;
|
|
186
|
+
targetMouseRef.current.y = 1.0 - (event.clientY - rect.top) / rect.height;
|
|
187
|
+
};
|
|
188
|
+
const handleMouseLeave = () => {
|
|
189
|
+
targetMouseRef.current.x = 0.5;
|
|
190
|
+
targetMouseRef.current.y = 0.5;
|
|
191
|
+
};
|
|
192
|
+
if (mouseInteraction) {
|
|
193
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
194
|
+
window.addEventListener('mouseleave', handleMouseLeave);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Resize handler with mobile optimization
|
|
198
|
+
const handleResize = () => {
|
|
199
|
+
const { clientWidth, clientHeight } = mountNode;
|
|
200
|
+
renderer.setSize(clientWidth, clientHeight);
|
|
201
|
+
|
|
202
|
+
// --- Mobile Optimization ---
|
|
203
|
+
const isMobile = clientWidth < 768;
|
|
204
|
+
|
|
205
|
+
// 1. Adjust pixel ratio for performance on small screens
|
|
206
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, isMobile ? 1.5 : 2));
|
|
207
|
+
|
|
208
|
+
// 2. Reduce shader complexity (line count) on mobile
|
|
209
|
+
uniforms.u_line_count.value = isMobile ? 20 : 40;
|
|
210
|
+
|
|
211
|
+
uniforms.uResolution.value.set(clientWidth, clientHeight);
|
|
212
|
+
};
|
|
213
|
+
window.addEventListener('resize', handleResize);
|
|
214
|
+
handleResize(); // Initial call
|
|
215
|
+
|
|
216
|
+
// Animation loop
|
|
217
|
+
const clock = new THREE.Clock();
|
|
218
|
+
let animationFrameId;
|
|
219
|
+
const animate = () => {
|
|
220
|
+
uniforms.uTime.value = clock.getElapsedTime() * speed;
|
|
221
|
+
|
|
222
|
+
// Smoothly update mouse position (lerping)
|
|
223
|
+
mouseRef.current.x += (targetMouseRef.current.x - mouseRef.current.x) * 0.05;
|
|
224
|
+
mouseRef.current.y += (targetMouseRef.current.y - mouseRef.current.y) * 0.05;
|
|
225
|
+
uniforms.uMouse.value.set(mouseRef.current.x, mouseRef.current.y);
|
|
226
|
+
|
|
227
|
+
renderer.render(scene, camera);
|
|
228
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
229
|
+
};
|
|
230
|
+
animate();
|
|
231
|
+
|
|
232
|
+
// Cleanup function
|
|
233
|
+
return () => {
|
|
234
|
+
cancelAnimationFrame(animationFrameId);
|
|
235
|
+
window.removeEventListener('resize', handleResize);
|
|
236
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
237
|
+
window.removeEventListener('mouseleave', handleMouseLeave);
|
|
238
|
+
if (mountNode && renderer.domElement) {
|
|
239
|
+
mountNode.removeChild(renderer.domElement);
|
|
240
|
+
}
|
|
241
|
+
geometry.dispose();
|
|
242
|
+
material.dispose();
|
|
243
|
+
renderer.dispose();
|
|
244
|
+
};
|
|
245
|
+
}, [color, amplitude, distance, speed, mouseInteraction]);
|
|
246
|
+
|
|
247
|
+
return <div ref={mountRef} className="absolute inset-0 z-0 w-full h-full -translate-y-20"/>;
|
|
248
|
+
};
|
|
249
|
+
export default KineticThreadsBackground;
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
import { react, useRef, useEffect } from "react";
|
|
3
|
+
import * as THREE from "three";
|
|
4
|
+
const hexToRgb = (hex) => {
|
|
5
|
+
const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
6
|
+
return m
|
|
7
|
+
? [
|
|
8
|
+
parseInt(m[1], 16) / 255,
|
|
9
|
+
parseInt(m[2], 16) / 255,
|
|
10
|
+
parseInt(m[3], 16) / 255,
|
|
11
|
+
]
|
|
12
|
+
: [1, 1, 1];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const getAnchorAndDir = (w, h) => {
|
|
16
|
+
// Always center for this effect
|
|
17
|
+
return { anchor: [0.5 * w, 0.2 * h], dir: [0, 3] };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Only add the selected props for lens flare effect, no other changes
|
|
21
|
+
const LensFlareBackground = ({
|
|
22
|
+
flareColor = "#fbbf24", // Main color of the lens flare
|
|
23
|
+
intensity = 1.0, // Intensity of the flare
|
|
24
|
+
animationSpeed = 1.0, // Animation speed
|
|
25
|
+
rayLengthValue = 1,
|
|
26
|
+
}) => {
|
|
27
|
+
const mountRef = useRef();
|
|
28
|
+
const uniformsRef = useRef();
|
|
29
|
+
const mouseRef = useRef({ x: 0.5, y: 0.5 });
|
|
30
|
+
const smoothMouseRef = useRef({ x: 0.5, y: 0.5 });
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (!mountRef.current) return;
|
|
34
|
+
let renderer, scene, camera, material, mesh, frameId;
|
|
35
|
+
let dpr = Math.min(window.devicePixelRatio, 2);
|
|
36
|
+
|
|
37
|
+
const getDims = () => {
|
|
38
|
+
if (!mountRef.current) return [0, 0];
|
|
39
|
+
return [mountRef.current.clientWidth * dpr, mountRef.current.clientHeight * dpr];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const setupRenderer = () => {
|
|
43
|
+
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
|
|
44
|
+
renderer.setClearColor(0x000000, 0);
|
|
45
|
+
if (mountRef.current) {
|
|
46
|
+
renderer.setSize(mountRef.current.clientWidth, mountRef.current.clientHeight, false);
|
|
47
|
+
mountRef.current.appendChild(renderer.domElement);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const setupScene = () => {
|
|
52
|
+
camera = new THREE.OrthographicCamera(0, 1, 1, 0, -1, 1);
|
|
53
|
+
scene = new THREE.Scene();
|
|
54
|
+
const geometry = new THREE.PlaneGeometry(1, 2);
|
|
55
|
+
const [w, h] = getDims();
|
|
56
|
+
const uniforms = {
|
|
57
|
+
iTime: { value: 0 },
|
|
58
|
+
iResolution: { value: new THREE.Vector2(w, h) },
|
|
59
|
+
rayPos: { value: new THREE.Vector2(0, 0) },
|
|
60
|
+
rayDir: { value: new THREE.Vector2(0, 1) },
|
|
61
|
+
raysColor: { value: new THREE.Color(...hexToRgb(flareColor)) },
|
|
62
|
+
raysSpeed: { value: animationSpeed },
|
|
63
|
+
lightSpread: { value: 4 },
|
|
64
|
+
rayLength: { value: 1 },
|
|
65
|
+
pulsating: { value: 0.0 },
|
|
66
|
+
fadeDistance: { value: 1.0 },
|
|
67
|
+
saturation: { value: 1.0 },
|
|
68
|
+
mousePos: { value: new THREE.Vector2(0.5, 0.5) },
|
|
69
|
+
mouseInfluence: { value: 0.1 },
|
|
70
|
+
noiseAmount: { value: 0.0 },
|
|
71
|
+
distortion: { value: 0.0 },
|
|
72
|
+
intensity: { value: intensity },
|
|
73
|
+
};
|
|
74
|
+
uniformsRef.current = uniforms;
|
|
75
|
+
|
|
76
|
+
const vertexShader = `
|
|
77
|
+
varying vec2 vUv;
|
|
78
|
+
void main() {
|
|
79
|
+
vUv = uv;
|
|
80
|
+
gl_Position = vec4(position, 1.0);
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
const fragmentShader = `
|
|
85
|
+
precision highp float;
|
|
86
|
+
uniform float iTime;
|
|
87
|
+
uniform vec2 iResolution;
|
|
88
|
+
uniform vec2 rayPos;
|
|
89
|
+
uniform vec2 rayDir;
|
|
90
|
+
uniform vec3 raysColor;
|
|
91
|
+
uniform float raysSpeed;
|
|
92
|
+
uniform float lightSpread;
|
|
93
|
+
uniform float rayLength;
|
|
94
|
+
uniform float pulsating;
|
|
95
|
+
uniform float fadeDistance;
|
|
96
|
+
uniform float saturation;
|
|
97
|
+
uniform vec2 mousePos;
|
|
98
|
+
uniform float mouseInfluence;
|
|
99
|
+
uniform float noiseAmount;
|
|
100
|
+
uniform float distortion;
|
|
101
|
+
uniform float intensity;
|
|
102
|
+
varying vec2 vUv;
|
|
103
|
+
|
|
104
|
+
float noise(vec2 st) {
|
|
105
|
+
return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
float rayStrength(vec2 raySource, vec2 rayRefDirection, vec2 coord,
|
|
109
|
+
float seedA, float seedB, float speed) {
|
|
110
|
+
vec2 sourceToCoord = coord - raySource;
|
|
111
|
+
vec2 dirNorm = normalize(sourceToCoord);
|
|
112
|
+
float cosAngle = dot(dirNorm, rayRefDirection);
|
|
113
|
+
float distortedAngle = cosAngle + distortion * sin(iTime * 2.0 + length(sourceToCoord) * 0.01) * 0.2;
|
|
114
|
+
float spreadFactor = pow(max(distortedAngle, 0.0), 1.0 / max(lightSpread, 0.001));
|
|
115
|
+
float distance = length(sourceToCoord);
|
|
116
|
+
float maxDistance = iResolution.x * rayLength;
|
|
117
|
+
float lengthFalloff = clamp((maxDistance - distance) / maxDistance, 0.0, 1.0);
|
|
118
|
+
float fadeFalloff = clamp((iResolution.x * fadeDistance - distance) / (iResolution.x * fadeDistance), 0.5, 1.0);
|
|
119
|
+
float pulse = pulsating > 0.5 ? (0.8 + 0.2 * sin(iTime * speed * 3.0)) : 1.0;
|
|
120
|
+
float baseStrength = clamp(
|
|
121
|
+
(0.45 + 0.15 * sin(distortedAngle * seedA + iTime * speed)) +
|
|
122
|
+
(0.3 + 0.2 * cos(-distortedAngle * seedB + iTime * speed)),
|
|
123
|
+
0.0, 1.0
|
|
124
|
+
);
|
|
125
|
+
return baseStrength * lengthFalloff * fadeFalloff * spreadFactor * pulse;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
float dotGlow(vec2 uv, vec2 pos, float size) {
|
|
129
|
+
float d = length(uv - pos);
|
|
130
|
+
return exp(-pow(d / size, 2.5));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
void main() {
|
|
134
|
+
vec2 fragCoord = vUv * iResolution.xy;
|
|
135
|
+
vec2 coord = vec2(fragCoord.x, iResolution.y - fragCoord.y);
|
|
136
|
+
vec2 finalRayDir = rayDir;
|
|
137
|
+
|
|
138
|
+
if (mouseInfluence > 0.0) {
|
|
139
|
+
vec2 mouseScreenPos = mousePos * iResolution.xy;
|
|
140
|
+
vec2 mouseDirection = normalize(mouseScreenPos - rayPos);
|
|
141
|
+
finalRayDir = normalize(mix(rayDir, mouseDirection, mouseInfluence));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
vec4 rays1 = vec4(1.0) * rayStrength(rayPos, finalRayDir, coord, 36.2214, 21.11349, 1.5 * raysSpeed);
|
|
145
|
+
vec4 rays2 = vec4(1.0) * rayStrength(rayPos, finalRayDir, coord, 22.3991, 18.0234, 1.1 * raysSpeed);
|
|
146
|
+
vec4 fragColor = (rays1 * 0.7 + rays2 * 0.6) * 1.5;
|
|
147
|
+
|
|
148
|
+
if (noiseAmount > 0.0) {
|
|
149
|
+
float n = noise(coord * 0.01 + iTime * 0.1);
|
|
150
|
+
fragColor.rgb *= (1.0 - noiseAmount + noiseAmount * n);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
float brightness = 1.0 - (coord.y / iResolution.y);
|
|
154
|
+
fragColor.x *= 0.1 + brightness * 0.8;
|
|
155
|
+
fragColor.y *= 0.3 + brightness * 0.6;
|
|
156
|
+
fragColor.z *= 0.5 + brightness * 0.5;
|
|
157
|
+
|
|
158
|
+
if (saturation != 1.0) {
|
|
159
|
+
float gray = dot(fragColor.rgb, vec3(0.299, 0.587, 0.114));
|
|
160
|
+
fragColor.rgb = mix(vec3(gray), fragColor.rgb, saturation);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fragColor.rgb *= raysColor;
|
|
164
|
+
fragColor.rgb *= intensity;
|
|
165
|
+
|
|
166
|
+
float t = iTime;
|
|
167
|
+
vec2 uvNorm = fragCoord / iResolution.xy;
|
|
168
|
+
float dots = 0.0;
|
|
169
|
+
dots += dotGlow(uvNorm, vec2(0.3 + 0.1 * sin(t), 0.4 + 0.1 * cos(t)), 0.04 + 0.01 * sin(t * 1.2));
|
|
170
|
+
dots += dotGlow(uvNorm, vec2(0.7 + 0.08 * cos(t * 1.1), 0.6 + 0.09 * sin(t * 0.9)), 0.035 + 0.01 * cos(t * 1.3));
|
|
171
|
+
dots += dotGlow(uvNorm, vec2(0.5 + 0.12 * sin(t * 0.7), 0.7 + 0.07 * cos(t * 1.5)), 0.03 + 0.01 * sin(t * 1.7));
|
|
172
|
+
dots += dotGlow(uvNorm, vec2(0.4 + 0.09 * cos(t * 1.4), 0.3 + 0.08 * sin(t * 1.1)), 0.025 + 0.01 * cos(t * 1.9));
|
|
173
|
+
dots += dotGlow(uvNorm, vec2(0.6 + 0.07 * sin(t * 1.6), 0.5 + 0.1 * cos(t * 1.2)), 0.03 + 0.01 * sin(t * 1.5));
|
|
174
|
+
vec3 dotColor = vec3(1.0, 0.95, 0.8);
|
|
175
|
+
fragColor.rgb += dots * dotColor * 0.7 * intensity;
|
|
176
|
+
|
|
177
|
+
gl_FragColor = fragColor;
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
|
|
181
|
+
material = new THREE.ShaderMaterial({
|
|
182
|
+
uniforms,
|
|
183
|
+
vertexShader,
|
|
184
|
+
fragmentShader,
|
|
185
|
+
transparent: true,
|
|
186
|
+
depthWrite: false,
|
|
187
|
+
});
|
|
188
|
+
mesh = new THREE.Mesh(geometry, material);
|
|
189
|
+
scene.add(mesh);
|
|
190
|
+
return { uniforms };
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
let uniforms;
|
|
194
|
+
setupRenderer();
|
|
195
|
+
({ uniforms } = setupScene());
|
|
196
|
+
|
|
197
|
+
const updatePlacement = () => {
|
|
198
|
+
dpr = Math.min(window.devicePixelRatio, 2);
|
|
199
|
+
if (!mountRef.current) return;
|
|
200
|
+
const w = mountRef.current.clientWidth * dpr;
|
|
201
|
+
const h = mountRef.current.clientHeight * dpr;
|
|
202
|
+
renderer.setSize(mountRef.current.clientWidth, mountRef.current.clientHeight, false);
|
|
203
|
+
uniforms.iResolution.value.set(w, h);
|
|
204
|
+
const { anchor, dir } = getAnchorAndDir(w, h);
|
|
205
|
+
uniforms.rayPos.value.set(anchor[0], anchor[1]);
|
|
206
|
+
uniforms.rayDir.value.set(dir[0], dir[1]);
|
|
207
|
+
};
|
|
208
|
+
updatePlacement();
|
|
209
|
+
window.addEventListener("resize", updatePlacement);
|
|
210
|
+
|
|
211
|
+
const handleMouseMove = (e) => {
|
|
212
|
+
if (!mountRef.current) return;
|
|
213
|
+
const rect = mountRef.current.getBoundingClientRect();
|
|
214
|
+
const x = (e.clientX - rect.left) / rect.width;
|
|
215
|
+
const y = (e.clientY - rect.top) / rect.height;
|
|
216
|
+
mouseRef.current = { x, y };
|
|
217
|
+
};
|
|
218
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
219
|
+
|
|
220
|
+
const animate = (now) => {
|
|
221
|
+
uniforms.iTime.value = now * 0.001;
|
|
222
|
+
const smoothing = 0.92;
|
|
223
|
+
smoothMouseRef.current.x =
|
|
224
|
+
smoothMouseRef.current.x * smoothing + mouseRef.current.x * (1 - smoothing);
|
|
225
|
+
smoothMouseRef.current.y =
|
|
226
|
+
smoothMouseRef.current.y * smoothing + mouseRef.current.y * (1 - smoothing);
|
|
227
|
+
uniforms.mousePos.value.set(smoothMouseRef.current.x, smoothMouseRef.current.y);
|
|
228
|
+
renderer.render(scene, camera);
|
|
229
|
+
frameId = requestAnimationFrame(animate);
|
|
230
|
+
};
|
|
231
|
+
frameId = requestAnimationFrame(animate);
|
|
232
|
+
|
|
233
|
+
return () => {
|
|
234
|
+
if (frameId) cancelAnimationFrame(frameId);
|
|
235
|
+
window.removeEventListener("resize", updatePlacement);
|
|
236
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
237
|
+
renderer.dispose();
|
|
238
|
+
if (mountRef.current && renderer.domElement.parentNode === mountRef.current) {
|
|
239
|
+
mountRef.current.removeChild(renderer.domElement);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}, [flareColor, intensity, animationSpeed]);
|
|
243
|
+
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
if (!uniformsRef.current) return;
|
|
246
|
+
uniformsRef.current.raysColor.value.set(...hexToRgb(flareColor));
|
|
247
|
+
uniformsRef.current.raysSpeed.value = animationSpeed;
|
|
248
|
+
uniformsRef.current.intensity.value = intensity;
|
|
249
|
+
}, [flareColor, animationSpeed, intensity]);
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<div
|
|
253
|
+
ref={mountRef}
|
|
254
|
+
// Corrected the className and ensured overflow is hidden
|
|
255
|
+
className="pointer-events-none w-[135vw] overflow-hidden"
|
|
256
|
+
style={{
|
|
257
|
+
position: "absolute",
|
|
258
|
+
bottom: 0,
|
|
259
|
+
height: "100vh",
|
|
260
|
+
// Add these two lines to center the element horizontally
|
|
261
|
+
left: "50%",
|
|
262
|
+
transform: "translateX(-50%)",
|
|
263
|
+
}}
|
|
264
|
+
/>
|
|
265
|
+
);
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export default LensFlareBackground;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import React, { useRef, useMemo } from 'react';
|
|
2
|
+
import { Canvas, useFrame } from '@react-three/fiber';
|
|
3
|
+
import * as THREE from 'three';
|
|
4
|
+
// Helper function to convert hex color to rgba for CSS
|
|
5
|
+
function hexToRgba(hex, alpha) {
|
|
6
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
7
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
8
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
9
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Internal component to create and animate the flowing spheres
|
|
13
|
+
function FlowingSpheres({ count, sep, color, pushStrength }) {
|
|
14
|
+
const instancedMeshRef = useRef();
|
|
15
|
+
|
|
16
|
+
// A dummy object to reuse for matrix calculations for performance
|
|
17
|
+
const dummy = useMemo(() => new THREE.Object3D(), []);
|
|
18
|
+
|
|
19
|
+
// Generate the initial positions and data for each instance
|
|
20
|
+
const particles = useMemo(() => {
|
|
21
|
+
const temp = [];
|
|
22
|
+
for (let xi = 0; xi < count; xi++) {
|
|
23
|
+
for (let zi = 0; zi < count; zi++) {
|
|
24
|
+
const x = sep * (xi - count / 2);
|
|
25
|
+
const z = sep * (zi - count / 2);
|
|
26
|
+
temp.push({ x, y: 0, z });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return temp;
|
|
30
|
+
}, [count, sep]);
|
|
31
|
+
|
|
32
|
+
// useFrame runs on every rendered frame
|
|
33
|
+
useFrame(({ clock, mouse }) => {
|
|
34
|
+
if (!instancedMeshRef.current) return;
|
|
35
|
+
const elapsedTime = clock.getElapsedTime();
|
|
36
|
+
|
|
37
|
+
// Map mouse position (-1 to 1) to the grid's world coordinates
|
|
38
|
+
const mouseXWorld = mouse.x * (count * sep / 4);
|
|
39
|
+
const mouseZWorld = -mouse.y * (count * sep / 4);
|
|
40
|
+
|
|
41
|
+
// Animate each sphere's y-position and update its matrix
|
|
42
|
+
particles.forEach((particle, i) => {
|
|
43
|
+
const { x, z } = particle;
|
|
44
|
+
|
|
45
|
+
// --- 1. Wave Animation ---
|
|
46
|
+
const timeFactor = Math.sin(elapsedTime * 0.5);
|
|
47
|
+
const wave1 = Math.sin(x * 0.15 + timeFactor * Math.PI);
|
|
48
|
+
const wave2 = Math.sin(z * 1 + timeFactor * Math.PI);
|
|
49
|
+
let y = (wave1 + wave2) * 7;
|
|
50
|
+
|
|
51
|
+
// --- 2. Mouse Movement Interaction ---
|
|
52
|
+
const dx = x - mouseXWorld;
|
|
53
|
+
const dz = z - mouseZWorld;
|
|
54
|
+
const distance = Math.sqrt(dx * dx + dz * dz);
|
|
55
|
+
|
|
56
|
+
const maxDist = 50; // The radius of the interaction effect
|
|
57
|
+
|
|
58
|
+
const pushFactor = Math.max(0, 1 - distance / maxDist);
|
|
59
|
+
const smoothPush = Math.pow(pushFactor, 3);
|
|
60
|
+
|
|
61
|
+
y -= smoothPush * pushStrength;
|
|
62
|
+
|
|
63
|
+
dummy.position.set(x, y, z);
|
|
64
|
+
dummy.updateMatrix();
|
|
65
|
+
|
|
66
|
+
instancedMeshRef.current.setMatrixAt(i, dummy.matrix);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
instancedMeshRef.current.instanceMatrix.needsUpdate = true;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<group rotation={[0, 0, 0]}>
|
|
74
|
+
<instancedMesh
|
|
75
|
+
ref={instancedMeshRef}
|
|
76
|
+
args={[null, null, count * count]}
|
|
77
|
+
>
|
|
78
|
+
<sphereGeometry args={[0.2, 19, 19]} />
|
|
79
|
+
<meshStandardMaterial
|
|
80
|
+
color={color}
|
|
81
|
+
emissive={color}
|
|
82
|
+
emissiveIntensity={1.5}
|
|
83
|
+
roughness={0.4}
|
|
84
|
+
metalness={0.1}
|
|
85
|
+
/>
|
|
86
|
+
</instancedMesh>
|
|
87
|
+
</group>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// The main component, now named LuminousParticleOcean
|
|
92
|
+
// You can pass props to this component to customize the background
|
|
93
|
+
const LuminousParticleOcean = ({
|
|
94
|
+
sphereCount = 100,
|
|
95
|
+
sphereColor = "#00aaff",
|
|
96
|
+
interactionStrength = 15,
|
|
97
|
+
separation = 4,
|
|
98
|
+
bgColor1 = "#010a2d",
|
|
99
|
+
bgColor2 = "#001133",
|
|
100
|
+
|
|
101
|
+
}) => {
|
|
102
|
+
|
|
103
|
+
const lightColorRgba = useMemo(() => hexToRgba(sphereColor, 0.5), [sphereColor]);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div
|
|
107
|
+
className="relative w-screen h-[60vh] lg:h-[80vh] overflow-hidden"
|
|
108
|
+
style={{
|
|
109
|
+
background: `linear-gradient(to bottom, ${bgColor1}, ${bgColor2})`
|
|
110
|
+
}}
|
|
111
|
+
>
|
|
112
|
+
{/* Sunlight Effect: Now uses the sphereColor prop */}
|
|
113
|
+
<div
|
|
114
|
+
className="absolute -top-10 left-0 w-full h-1/2 z-[999]"
|
|
115
|
+
style={{
|
|
116
|
+
background: `radial-gradient(circle at top center, ${lightColorRgba} 0%, transparent 90%)`,
|
|
117
|
+
filter: 'blur(40px)',
|
|
118
|
+
pointerEvents: 'none',
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
121
|
+
|
|
122
|
+
{/* Vignette Effect */}
|
|
123
|
+
<div
|
|
124
|
+
className="absolute inset-0"
|
|
125
|
+
style={{
|
|
126
|
+
boxShadow: 'inset 0 0 150px rgba(0,0,0,0.7)',
|
|
127
|
+
pointerEvents: 'none',
|
|
128
|
+
}}
|
|
129
|
+
/>
|
|
130
|
+
|
|
131
|
+
<Canvas
|
|
132
|
+
camera={{ position: [0, 60, 150], fov: 55 }}
|
|
133
|
+
>
|
|
134
|
+
{/* Sunlight: Also uses the sphereColor prop */}
|
|
135
|
+
<pointLight
|
|
136
|
+
color={sphereColor}
|
|
137
|
+
intensity={4000}
|
|
138
|
+
distance={300}
|
|
139
|
+
position={[-150, 100, -100]}
|
|
140
|
+
/>
|
|
141
|
+
<ambientLight intensity={0.2} />
|
|
142
|
+
|
|
143
|
+
{/* Render the animated flowing spheres component with the passed props */}
|
|
144
|
+
<FlowingSpheres
|
|
145
|
+
count={sphereCount}
|
|
146
|
+
sep={separation}
|
|
147
|
+
color={sphereColor}
|
|
148
|
+
pushStrength={interactionStrength}
|
|
149
|
+
/>
|
|
150
|
+
</Canvas>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default LuminousParticleOcean;
|