lightswind
Version:
A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.
160 lines (146 loc) • 5.85 kB
JavaScript
// @ts-nocheck
"use client";
import { jsx as _jsx } from "react/jsx-runtime";
import { useEffect, useRef } from "react";
import { Renderer, Program, Mesh, Color, Triangle } from "ogl";
const VERTEX_SHADER = `#version 300 es
in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}`;
const FRAGMENT_SHADER = `#version 300 es
precision highp float;
uniform float uTime;
uniform float uAmplitude;
uniform vec3 uColorStops[3];
uniform vec2 uResolution;
uniform float uBlend;
uniform vec2 uMouse;
out vec4 fragColor;
vec3 permute(vec3 x){return mod(((x*34.0)+1.0)*x,289.0);}
float snoise(vec2 v){
const vec4 C=vec4(0.211324865405187,0.366025403784439,-0.577350269189626,0.024390243902439);
vec2 i=floor(v+dot(v,C.yy));
vec2 x0=v-i+dot(i,C.xx);
vec2 i1=(x0.x>x0.y)?vec2(1.0,0.0):vec2(0.0,1.0);
vec4 x12=x0.xyxy+C.xxzz;
x12.xy-=i1;
i=mod(i,289.0);
vec3 p=permute(permute(i.y+vec3(0.0,i1.y,1.0))+i.x+vec3(0.0,i1.x,1.0));
vec3 m=max(0.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),dot(x12.zw,x12.zw)),0.0);
m=m*m; m=m*m;
vec3 x=2.0*fract(p*C.www)-1.0;
vec3 h=abs(x)-0.5;
vec3 ox=floor(x+0.5);
vec3 a0=x-ox;
m*=1.79284291400159-0.85373472095314*(a0*a0+h*h);
vec3 g; g.x=a0.x*x0.x+h.x*x0.y; g.yz=a0.yz*x12.xz+h.yz*x12.yw;
return 130.0*dot(m,g);
}
struct ColorStop { vec3 color; float position; };
#define COLOR_RAMP(colors,factor,finalColor){ \
int index=0; \
for(int i=0;i<2;i++){ \
ColorStop currentColor=colors[i]; \
bool inBetween=currentColor.position<=factor; \
index=int(mix(float(index),float(i),float(inBetween))); \
} \
ColorStop currentColor=colors[index]; \
ColorStop nextColor=colors[index+1]; \
float range=nextColor.position-currentColor.position; \
float lerpFactor=(factor-currentColor.position)/range; \
finalColor=mix(currentColor.color,nextColor.color,lerpFactor); \
}
void main(){
vec2 uv=gl_FragCoord.xy/uResolution;
vec2 m = uMouse / uResolution;
ColorStop colors[3];
colors[0]=ColorStop(uColorStops[0],0.0);
colors[1]=ColorStop(uColorStops[1],0.5);
colors[2]=ColorStop(uColorStops[2],1.0);
vec3 rampColor;
COLOR_RAMP(colors, uv.x, rampColor);
// Apply noise to create the wave shape
float noise = snoise(vec2(uv.x * 3.0, uTime * 0.2 + m.x * 0.5));
float waveHeight = uv.y - (noise * 0.15 * uAmplitude);
// Fade the wave out at the bottom
float fade = smoothstep(0.0, 0.4, uv.y);
waveHeight = mix(uv.y, waveHeight, fade);
// Define the core of the aurora
float core = 0.5;
float intensity = smoothstep(core - uBlend, core + uBlend, waveHeight);
vec3 auroraColor = intensity * rampColor;
float auroraAlpha = intensity;
fragColor = vec4(auroraColor * auroraAlpha, auroraAlpha);
}
`;
export default function AuroraShader({ colorStops = ["#5227FF", "#7cff67", "#5227FF"], amplitude = 1.0, blend = 0.5, speed = 1.0, }) {
const containerRef = useRef(null);
const mouseRef = useRef({ x: 0, y: 0 });
useEffect(() => {
const container = containerRef.current;
if (!container)
return;
const renderer = new Renderer({ alpha: true, antialias: true });
const gl = renderer.gl;
gl.clearColor(0, 0, 0, 0);
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
const geometry = new Triangle(gl);
if (geometry.attributes.uv)
delete geometry.attributes.uv;
const program = new Program(gl, {
vertex: VERTEX_SHADER,
fragment: FRAGMENT_SHADER,
uniforms: {
uTime: { value: 0 },
uAmplitude: { value: amplitude },
uBlend: { value: blend },
uResolution: { value: [container.offsetWidth, container.offsetHeight] },
uColorStops: {
value: colorStops.map((hex) => {
const c = new Color(hex);
return [c.r, c.g, c.b];
}),
},
uMouse: { value: [0, 0] },
},
});
const mesh = new Mesh(gl, { geometry, program });
container.appendChild(gl.canvas);
const resize = () => {
const width = container.offsetWidth;
const height = container.offsetHeight;
renderer.setSize(width, height);
program.uniforms.uResolution.value = [width, height];
};
window.addEventListener("resize", resize);
resize();
const onMouseMove = (e) => {
// Smooth lerp for mouse
mouseRef.current.x += (e.clientX - mouseRef.current.x) * 0.05;
mouseRef.current.y += (e.clientY - mouseRef.current.y) * 0.05;
};
window.addEventListener("mousemove", onMouseMove);
let animationId;
const animate = (t) => {
animationId = requestAnimationFrame(animate);
// Smooth interpolation
program.uniforms.uTime.value = t * 0.001 * speed;
program.uniforms.uAmplitude.value = amplitude;
program.uniforms.uBlend.value = blend;
program.uniforms.uMouse.value = [mouseRef.current.x, mouseRef.current.y];
renderer.render({ scene: mesh });
};
animate(0);
return () => {
cancelAnimationFrame(animationId);
window.removeEventListener("resize", resize);
window.removeEventListener("mousemove", onMouseMove);
if (gl.canvas.parentNode === container)
container.removeChild(gl.canvas);
gl.getExtension("WEBGL_lose_context")?.loseContext();
};
}, [amplitude, blend, colorStops, speed]);
return _jsx("div", { ref: containerRef, className: "w-full h-full absolute bottom-0" });
}