Files

1 line
9.5 KiB
JSON

{"name":"SoftAurora","title":"SoftAurora","description":"Soft aurora borealis shader with 3D Perlin noise and cosine gradient palettes.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<script setup lang=\"ts\">\nimport { Mesh, Program, Renderer, Triangle } from 'ogl';\nimport { onBeforeUnmount, onMounted, useTemplateRef, watch } from 'vue';\n\ninterface SoftAuroraProps {\n speed?: number;\n scale?: number;\n brightness?: number;\n color1?: string;\n color2?: string;\n noiseFrequency?: number;\n noiseAmplitude?: number;\n bandHeight?: number;\n bandSpread?: number;\n octaveDecay?: number;\n layerOffset?: number;\n colorSpeed?: number;\n enableMouseInteraction?: boolean;\n mouseInfluence?: number;\n}\n\nfunction hexToVec3(hex: string): [number, number, number] {\n const h = hex.replace('#', '');\n return [parseInt(h.slice(0, 2), 16) / 255, parseInt(h.slice(2, 4), 16) / 255, parseInt(h.slice(4, 6), 16) / 255];\n}\n\nconst vertexShader = `\nattribute vec2 uv;\nattribute vec2 position;\nvarying vec2 vUv;\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position, 0, 1);\n}\n`;\n\nconst fragmentShader = `\nprecision highp float;\n\nuniform float uTime;\nuniform vec3 uResolution;\nuniform float uSpeed;\nuniform float uScale;\nuniform float uBrightness;\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform float uNoiseFreq;\nuniform float uNoiseAmp;\nuniform float uBandHeight;\nuniform float uBandSpread;\nuniform float uOctaveDecay;\nuniform float uLayerOffset;\nuniform float uColorSpeed;\nuniform vec2 uMouse;\nuniform float uMouseInfluence;\nuniform bool uEnableMouse;\n\n#define TAU 6.28318\n\nvec3 gradientHash(vec3 p) {\n p = vec3(\n dot(p, vec3(127.1, 311.7, 234.6)),\n dot(p, vec3(269.5, 183.3, 198.3)),\n dot(p, vec3(169.5, 283.3, 156.9))\n );\n vec3 h = fract(sin(p) * 43758.5453123);\n float phi = acos(2.0 * h.x - 1.0);\n float theta = TAU * h.y;\n return vec3(cos(theta) * sin(phi), sin(theta) * cos(phi), cos(phi));\n}\n\nfloat quinticSmooth(float t) {\n float t2 = t * t;\n float t3 = t * t2;\n return 6.0 * t3 * t2 - 15.0 * t2 * t2 + 10.0 * t3;\n}\n\nvec3 cosineGradient(float t, vec3 a, vec3 b, vec3 c, vec3 d) {\n return a + b * cos(TAU * (c * t + d));\n}\n\nfloat perlin3D(float amplitude, float frequency, float px, float py, float pz) {\n float x = px * frequency;\n float y = py * frequency;\n\n float fx = floor(x); float fy = floor(y); float fz = floor(pz);\n float cx = ceil(x); float cy = ceil(y); float cz = ceil(pz);\n\n vec3 g000 = gradientHash(vec3(fx, fy, fz));\n vec3 g100 = gradientHash(vec3(cx, fy, fz));\n vec3 g010 = gradientHash(vec3(fx, cy, fz));\n vec3 g110 = gradientHash(vec3(cx, cy, fz));\n vec3 g001 = gradientHash(vec3(fx, fy, cz));\n vec3 g101 = gradientHash(vec3(cx, fy, cz));\n vec3 g011 = gradientHash(vec3(fx, cy, cz));\n vec3 g111 = gradientHash(vec3(cx, cy, cz));\n\n float d000 = dot(g000, vec3(x - fx, y - fy, pz - fz));\n float d100 = dot(g100, vec3(x - cx, y - fy, pz - fz));\n float d010 = dot(g010, vec3(x - fx, y - cy, pz - fz));\n float d110 = dot(g110, vec3(x - cx, y - cy, pz - fz));\n float d001 = dot(g001, vec3(x - fx, y - fy, pz - cz));\n float d101 = dot(g101, vec3(x - cx, y - fy, pz - cz));\n float d011 = dot(g011, vec3(x - fx, y - cy, pz - cz));\n float d111 = dot(g111, vec3(x - cx, y - cy, pz - cz));\n\n float sx = quinticSmooth(x - fx);\n float sy = quinticSmooth(y - fy);\n float sz = quinticSmooth(pz - fz);\n\n float lx00 = mix(d000, d100, sx);\n float lx10 = mix(d010, d110, sx);\n float lx01 = mix(d001, d101, sx);\n float lx11 = mix(d011, d111, sx);\n\n float ly0 = mix(lx00, lx10, sy);\n float ly1 = mix(lx01, lx11, sy);\n\n return amplitude * mix(ly0, ly1, sz);\n}\n\nfloat auroraGlow(float t, vec2 shift) {\n vec2 uv = gl_FragCoord.xy / uResolution.y;\n uv += shift;\n\n float noiseVal = 0.0;\n float freq = uNoiseFreq;\n float amp = uNoiseAmp;\n vec2 samplePos = uv * uScale;\n\n for (float i = 0.0; i < 3.0; i += 1.0) {\n noiseVal += perlin3D(amp, freq, samplePos.x, samplePos.y, t);\n amp *= uOctaveDecay;\n freq *= 2.0;\n }\n\n float yBand = uv.y * 10.0 - uBandHeight * 10.0;\n return 0.3 * max(exp(uBandSpread * (1.0 - 1.1 * abs(noiseVal + yBand))), 0.0);\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution.xy;\n float t = uSpeed * 0.4 * uTime;\n\n vec2 shift = vec2(0.0);\n if (uEnableMouse) {\n shift = (uMouse - 0.5) * uMouseInfluence;\n }\n\n vec3 col = vec3(0.0);\n col += 0.99 * auroraGlow(t, shift) * cosineGradient(uv.x + uTime * uSpeed * 0.2 * uColorSpeed, vec3(0.5), vec3(0.5), vec3(1.0), vec3(0.3, 0.20, 0.20)) * uColor1;\n col += 0.99 * auroraGlow(t + uLayerOffset, shift) * cosineGradient(uv.x + uTime * uSpeed * 0.1 * uColorSpeed, vec3(0.5), vec3(0.5), vec3(2.0, 1.0, 0.0), vec3(0.5, 0.20, 0.25)) * uColor2;\n\n col *= uBrightness;\n float alpha = clamp(length(col), 0.0, 1.0);\n gl_FragColor = vec4(col, alpha);\n}\n`;\n\nconst props = withDefaults(defineProps<SoftAuroraProps>(), {\n speed: 0.6,\n scale: 1.5,\n brightness: 1.0,\n color1: '#f7f7f7',\n color2: '#27FF64',\n noiseFrequency: 2.5,\n noiseAmplitude: 1.0,\n bandHeight: 0.5,\n bandSpread: 1.0,\n octaveDecay: 0.1,\n layerOffset: 0,\n colorSpeed: 1.0,\n enableMouseInteraction: true,\n mouseInfluence: 0.25\n});\n\nconst containerRef = useTemplateRef<HTMLDivElement>('containerRef');\n\nlet cleanup: (() => void) | null = null;\nconst setup = () => {\n if (!containerRef.value) return;\n const container = containerRef.value;\n const renderer = new Renderer({ alpha: true, premultipliedAlpha: false });\n const gl = renderer.gl;\n gl.clearColor(0, 0, 0, 0);\n\n const currentMouse = [0.5, 0.5];\n let targetMouse = [0.5, 0.5];\n\n function handleMouseMove(e: MouseEvent) {\n const rect = gl.canvas.getBoundingClientRect();\n targetMouse = [(e.clientX - rect.left) / rect.width, 1.0 - (e.clientY - rect.top) / rect.height];\n }\n\n function handleMouseLeave() {\n targetMouse = [0.5, 0.5];\n }\n\n renderer.setSize(container.offsetWidth, container.offsetHeight);\n\n const geometry = new Triangle(gl);\n const program = new Program(gl, {\n vertex: vertexShader,\n fragment: fragmentShader,\n uniforms: {\n uTime: { value: 0 },\n uResolution: { value: [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height] },\n uSpeed: { value: props.speed },\n uScale: { value: props.scale },\n uBrightness: { value: props.brightness },\n uColor1: { value: hexToVec3(props.color1) },\n uColor2: { value: hexToVec3(props.color2) },\n uNoiseFreq: { value: props.noiseFrequency },\n uNoiseAmp: { value: props.noiseAmplitude },\n uBandHeight: { value: props.bandHeight },\n uBandSpread: { value: props.bandSpread },\n uOctaveDecay: { value: props.octaveDecay },\n uLayerOffset: { value: props.layerOffset },\n uColorSpeed: { value: props.colorSpeed },\n uMouse: { value: new Float32Array([0.5, 0.5]) },\n uMouseInfluence: { value: props.mouseInfluence },\n uEnableMouse: { value: props.enableMouseInteraction }\n }\n });\n\n function resize() {\n renderer.setSize(container.offsetWidth, container.offsetHeight);\n program.uniforms.uResolution.value = [gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height];\n }\n window.addEventListener('resize', resize);\n\n const mesh = new Mesh(gl, { geometry, program });\n container.appendChild(gl.canvas);\n\n if (props.enableMouseInteraction) {\n gl.canvas.addEventListener('mousemove', handleMouseMove);\n gl.canvas.addEventListener('mouseleave', handleMouseLeave);\n }\n\n let animationFrameId: number;\n\n function update(time: number) {\n animationFrameId = requestAnimationFrame(update);\n program.uniforms.uTime.value = time * 0.001;\n\n if (props.enableMouseInteraction) {\n currentMouse[0] += 0.05 * (targetMouse[0] - currentMouse[0]);\n currentMouse[1] += 0.05 * (targetMouse[1] - currentMouse[1]);\n program.uniforms.uMouse.value[0] = currentMouse[0];\n program.uniforms.uMouse.value[1] = currentMouse[1];\n } else {\n program.uniforms.uMouse.value[0] = 0.5;\n program.uniforms.uMouse.value[1] = 0.5;\n }\n\n renderer.render({ scene: mesh });\n }\n animationFrameId = requestAnimationFrame(update);\n\n cleanup = () => {\n cancelAnimationFrame(animationFrameId);\n window.removeEventListener('resize', resize);\n if (props.enableMouseInteraction) {\n gl.canvas.removeEventListener('mousemove', handleMouseMove);\n gl.canvas.removeEventListener('mouseleave', handleMouseLeave);\n }\n container.removeChild(gl.canvas);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n };\n};\n\nonMounted(() => {\n setup();\n});\n\nonBeforeUnmount(() => {\n cleanup?.();\n});\n\nwatch(\n () => [\n props.speed,\n props.scale,\n props.brightness,\n props.color1,\n props.color2,\n props.noiseFrequency,\n props.noiseAmplitude,\n props.bandHeight,\n props.bandSpread,\n props.octaveDecay,\n props.layerOffset,\n props.colorSpeed,\n props.enableMouseInteraction,\n props.mouseInfluence\n ],\n () => {\n cleanup?.();\n setup();\n }\n);\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"w-full h-full\" />\n</template>\n","path":"SoftAurora/SoftAurora.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"ogl","version":"^1.0.11"}],"devDependencies":[],"categories":["Backgrounds"]}