Skip to content

Commit 1d1748e

Browse files
authored
Merge pull request #315 from Pseudo-Lab/feat/getcloser/frontend/react-bits
feat(getcloser): apply react bits
2 parents dba4617 + ae6f2b0 commit 1d1748e

File tree

10 files changed

+492
-101
lines changed

10 files changed

+492
-101
lines changed

getcloser/frontend/package-lock.json

Lines changed: 25 additions & 90 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

getcloser/frontend/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
"lint": "eslint"
1010
},
1111
"dependencies": {
12+
"@gsap/react": "^2.1.2",
1213
"@radix-ui/react-label": "^2.1.7",
1314
"@radix-ui/react-slot": "^1.2.3",
1415
"@tanstack/react-query": "^5.90.2",
1516
"boring-avatars": "^2.0.4",
1617
"class-variance-authority": "^0.7.1",
1718
"clsx": "^2.1.1",
19+
"gsap": "^3.14.2",
1820
"js-cookie": "^3.0.5",
1921
"lucide-react": "^0.544.0",
2022
"next": "15.5.9",
23+
"ogl": "^1.0.11",
2124
"react": "19.2.1",
2225
"react-dom": "19.2.1",
2326
"tailwind-merge": "^3.3.1",
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import { useEffect, useRef } from 'react';
2+
import { Renderer, Program, Mesh, Color, Triangle } from 'ogl';
3+
4+
const VERT = `#version 300 es
5+
in vec2 position;
6+
void main() {
7+
gl_Position = vec4(position, 0.0, 1.0);
8+
}
9+
`;
10+
11+
const FRAG = `#version 300 es
12+
precision highp float;
13+
14+
uniform float uTime;
15+
uniform float uAmplitude;
16+
uniform vec3 uColorStops[3];
17+
uniform vec2 uResolution;
18+
uniform float uBlend;
19+
20+
out vec4 fragColor;
21+
22+
vec3 permute(vec3 x) {
23+
return mod(((x * 34.0) + 1.0) * x, 289.0);
24+
}
25+
26+
float snoise(vec2 v){
27+
const vec4 C = vec4(
28+
0.211324865405187, 0.366025403784439,
29+
-0.577350269189626, 0.024390243902439
30+
);
31+
vec2 i = floor(v + dot(v, C.yy));
32+
vec2 x0 = v - i + dot(i, C.xx);
33+
vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
34+
vec4 x12 = x0.xyxy + C.xxzz;
35+
x12.xy -= i1;
36+
i = mod(i, 289.0);
37+
38+
vec3 p = permute(
39+
permute(i.y + vec3(0.0, i1.y, 1.0))
40+
+ i.x + vec3(0.0, i1.x, 1.0)
41+
);
42+
43+
vec3 m = max(
44+
0.5 - vec3(
45+
dot(x0, x0),
46+
dot(x12.xy, x12.xy),
47+
dot(x12.zw, x12.zw)
48+
),
49+
0.0
50+
);
51+
m = m * m;
52+
m = m * m;
53+
54+
vec3 x = 2.0 * fract(p * C.www) - 1.0;
55+
vec3 h = abs(x) - 0.5;
56+
vec3 ox = floor(x + 0.5);
57+
vec3 a0 = x - ox;
58+
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
59+
60+
vec3 g;
61+
g.x = a0.x * x0.x + h.x * x0.y;
62+
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
63+
return 130.0 * dot(m, g);
64+
}
65+
66+
struct ColorStop {
67+
vec3 color;
68+
float position;
69+
};
70+
71+
#define COLOR_RAMP(colors, factor, finalColor) { \
72+
int index = 0; \
73+
for (int i = 0; i < 2; i++) { \
74+
ColorStop currentColor = colors[i]; \
75+
bool isInBetween = currentColor.position <= factor; \
76+
index = int(mix(float(index), float(i), float(isInBetween))); \
77+
} \
78+
ColorStop currentColor = colors[index]; \
79+
ColorStop nextColor = colors[index + 1]; \
80+
float range = nextColor.position - currentColor.position; \
81+
float lerpFactor = (factor - currentColor.position) / range; \
82+
finalColor = mix(currentColor.color, nextColor.color, lerpFactor); \
83+
}
84+
85+
void main() {
86+
vec2 uv = gl_FragCoord.xy / uResolution;
87+
88+
ColorStop colors[3];
89+
colors[0] = ColorStop(uColorStops[0], 0.0);
90+
colors[1] = ColorStop(uColorStops[1], 0.5);
91+
colors[2] = ColorStop(uColorStops[2], 1.0);
92+
93+
vec3 rampColor;
94+
COLOR_RAMP(colors, uv.x, rampColor);
95+
96+
float height = snoise(vec2(uv.x * 2.0 + uTime * 0.1, uTime * 0.25)) * 0.5 * uAmplitude;
97+
height = exp(height);
98+
height = (uv.y * 2.0 - height + 0.2);
99+
float intensity = 0.6 * height;
100+
101+
float midPoint = 0.20;
102+
float auroraAlpha = smoothstep(midPoint - uBlend * 0.5, midPoint + uBlend * 0.5, intensity);
103+
104+
vec3 auroraColor = intensity * rampColor;
105+
106+
fragColor = vec4(auroraColor * auroraAlpha, auroraAlpha);
107+
}
108+
`;
109+
110+
interface AuroraProps {
111+
colorStops?: string[];
112+
amplitude?: number;
113+
blend?: number;
114+
time?: number;
115+
speed?: number;
116+
}
117+
118+
export default function Aurora(props: AuroraProps) {
119+
const { colorStops = ['#5227FF', '#7cff67', '#5227FF'], amplitude = 1.0, blend = 0.5 } = props;
120+
const propsRef = useRef<AuroraProps>(props);
121+
propsRef.current = props;
122+
123+
const ctnDom = useRef<HTMLDivElement>(null);
124+
125+
useEffect(() => {
126+
const ctn = ctnDom.current;
127+
if (!ctn) return;
128+
129+
const renderer = new Renderer({
130+
alpha: true,
131+
premultipliedAlpha: true,
132+
antialias: true
133+
});
134+
const gl = renderer.gl;
135+
gl.clearColor(0, 0, 0, 0);
136+
gl.enable(gl.BLEND);
137+
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
138+
gl.canvas.style.backgroundColor = 'transparent';
139+
140+
const program = new Program(gl, {
141+
vertex: VERT,
142+
fragment: FRAG,
143+
uniforms: {
144+
uTime: { value: 0 },
145+
uAmplitude: { value: amplitude },
146+
uColorStops: { value: colorStops },
147+
uResolution: { value: [ctn.offsetWidth, ctn.offsetHeight] },
148+
uBlend: { value: blend }
149+
}
150+
});
151+
152+
const mesh = new Mesh(gl, { geometry: new Triangle(gl), program });
153+
ctn.appendChild(gl.canvas);
154+
155+
function resize() {
156+
if (!ctn) return;
157+
const width = ctn.offsetWidth;
158+
const height = ctn.offsetHeight;
159+
renderer.setSize(width, height);
160+
program.uniforms.uResolution.value = [width, height];
161+
}
162+
window.addEventListener('resize', resize);
163+
164+
let animateId = 0;
165+
const update = (t: number) => {
166+
animateId = requestAnimationFrame(update);
167+
const { time = t * 0.01, speed = 1.0 } = propsRef.current;
168+
if (program) {
169+
program.uniforms.uTime.value = time * speed * 0.1;
170+
program.uniforms.uAmplitude.value = propsRef.current.amplitude ?? 1.0;
171+
program.uniforms.uBlend.value = propsRef.current.blend ?? blend;
172+
const stops = propsRef.current.colorStops ?? colorStops;
173+
program.uniforms.uColorStops.value = stops.map((hex: string) => {
174+
const c = new Color(hex);
175+
return [c.r, c.g, c.b];
176+
});
177+
renderer.render({ scene: mesh });
178+
}
179+
};
180+
animateId = requestAnimationFrame(update);
181+
182+
resize();
183+
184+
return () => {
185+
cancelAnimationFrame(animateId);
186+
window.removeEventListener('resize', resize);
187+
if (ctn && gl.canvas.parentNode === ctn) {
188+
ctn.removeChild(gl.canvas);
189+
}
190+
gl.getExtension('WEBGL_lose_context')?.loseContext();
191+
};
192+
}, [amplitude, blend, colorStops]);
193+
194+
return <div ref={ctnDom} className="w-full h-full" />;
195+
}

0 commit comments

Comments
 (0)