Files
vue-bits/public/r/Aurora.json
David Haz e621971723 jsrepo v3
2025-12-15 23:50:24 +02:00

1 line
8.3 KiB
JSON

{"name":"Aurora","title":"Aurora","description":"Flowing aurora gradient background.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<template>\n <div ref=\"containerRef\" :class=\"className\" :style=\"style\" class=\"relative\"></div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, onUnmounted, watch, type CSSProperties, useTemplateRef } from 'vue';\nimport { Renderer, Program, Mesh, Color, Triangle } from 'ogl';\n\ninterface AuroraProps {\n colorStops?: string[];\n amplitude?: number;\n blend?: number;\n time?: number;\n speed?: number;\n intensity?: number;\n className?: string;\n style?: CSSProperties;\n}\n\nconst props = withDefaults(defineProps<AuroraProps>(), {\n colorStops: () => ['#7cff67', '#171D22', '#7cff67'],\n amplitude: 1.0,\n blend: 0.5,\n speed: 1.0,\n intensity: 1.0,\n className: '',\n style: () => ({})\n});\n\nconst containerRef = useTemplateRef<HTMLDivElement>('containerRef');\n\nconst VERT = `#version 300 es\nin vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst FRAG = `#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform float uAmplitude;\nuniform vec3 uColorStops[3];\nuniform vec2 uResolution;\nuniform float uBlend;\nuniform float uIntensity;\n\nout vec4 fragColor;\n\nvec3 permute(vec3 x) {\n return mod(((x * 34.0) + 1.0) * x, 289.0);\n}\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(\n 0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439\n );\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n\n vec3 p = permute(\n permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0)\n );\n\n vec3 m = max(\n 0.5 - vec3(\n dot(x0, x0),\n dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)\n ), \n 0.0\n );\n m = m * m;\n m = m * m;\n\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);\n\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nstruct ColorStop {\n vec3 color;\n float position;\n};\n\n#define COLOR_RAMP(colors, factor, finalColor) { \\\n int index = 0; \\\n for (int i = 0; i < 2; i++) { \\\n ColorStop currentColor = colors[i]; \\\n bool isInBetween = currentColor.position <= factor; \\\n index = int(mix(float(index), float(i), float(isInBetween))); \\\n } \\\n ColorStop currentColor = colors[index]; \\\n ColorStop nextColor = colors[index + 1]; \\\n float range = nextColor.position - currentColor.position; \\\n float lerpFactor = (factor - currentColor.position) / range; \\\n finalColor = mix(currentColor.color, nextColor.color, lerpFactor); \\\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n \n ColorStop colors[3];\n colors[0] = ColorStop(uColorStops[0], 0.0);\n colors[1] = ColorStop(uColorStops[1], 0.5);\n colors[2] = ColorStop(uColorStops[2], 1.0);\n \n vec3 rampColor;\n COLOR_RAMP(colors, uv.x, rampColor);\n \n float height = snoise(vec2(uv.x * 2.0 + uTime * 0.1, uTime * 0.25)) * 0.5 * uAmplitude;\n height = exp(height);\n height = (uv.y * 2.0 - height + 0.2);\n float intensity = 0.6 * height;\n \n float midPoint = 0.20;\n float auroraAlpha = smoothstep(midPoint - uBlend * 0.5, midPoint + uBlend * 0.5, intensity);\n \n vec3 auroraColor = rampColor;\n \n float finalAlpha = auroraAlpha * smoothstep(0.0, 0.5, intensity) * uIntensity;\n \n fragColor = vec4(auroraColor * finalAlpha, finalAlpha);\n}\n`;\n\nlet renderer: Renderer | null = null;\nlet animateId = 0;\n\nconst initAurora = () => {\n const container = containerRef.value;\n if (!container) return;\n\n renderer = new Renderer({\n alpha: true,\n premultipliedAlpha: true,\n antialias: true\n });\n\n const gl = renderer.gl;\n gl.clearColor(0, 0, 0, 0);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.canvas.style.backgroundColor = 'transparent';\n\n // eslint-disable-next-line prefer-const\n let program: Program | undefined;\n\n const resize = () => {\n if (!container) return;\n\n const parentWidth = container.parentElement?.offsetWidth || container.offsetWidth || window.innerWidth;\n const parentHeight = container.parentElement?.offsetHeight || container.offsetHeight || window.innerHeight;\n\n const width = Math.max(parentWidth, 300);\n const height = Math.max(parentHeight, 300);\n\n renderer!.setSize(width, height);\n if (program) {\n program.uniforms.uResolution.value = [width, height];\n }\n };\n\n window.addEventListener('resize', resize);\n\n const geometry = new Triangle(gl);\n if (geometry.attributes.uv) {\n delete geometry.attributes.uv;\n }\n\n const colorStopsArray = props.colorStops.map(hex => {\n const c = new Color(hex);\n return [c.r, c.g, c.b];\n });\n\n program = new Program(gl, {\n vertex: VERT,\n fragment: FRAG,\n uniforms: {\n uTime: { value: 0 },\n uAmplitude: { value: props.amplitude },\n uColorStops: { value: colorStopsArray },\n uResolution: {\n value: [\n Math.max(container.parentElement?.offsetWidth || container.offsetWidth || window.innerWidth, 300),\n Math.max(container.parentElement?.offsetHeight || container.offsetHeight || window.innerHeight, 300)\n ]\n },\n uBlend: { value: props.blend },\n uIntensity: { value: props.intensity }\n }\n });\n\n const mesh = new Mesh(gl, { geometry, program });\n container.appendChild(gl.canvas);\n\n gl.canvas.style.width = '100%';\n gl.canvas.style.height = '100%';\n gl.canvas.style.display = 'block';\n gl.canvas.style.position = 'absolute';\n gl.canvas.style.top = '0';\n gl.canvas.style.left = '0';\n\n const update = (t: number) => {\n animateId = requestAnimationFrame(update);\n const time = props.time ?? t * 0.01;\n const speed = props.speed ?? 1.0;\n if (program) {\n program.uniforms.uTime.value = time * speed * 0.1;\n program.uniforms.uAmplitude.value = props.amplitude ?? 1.0;\n program.uniforms.uBlend.value = props.blend ?? 0.5;\n program.uniforms.uIntensity.value = props.intensity ?? 1.0;\n const stops = props.colorStops ?? ['#27FF64', '#7cff67', '#27FF64'];\n program.uniforms.uColorStops.value = stops.map((hex: string) => {\n const c = new Color(hex);\n return [c.r, c.g, c.b];\n });\n renderer!.render({ scene: mesh });\n }\n };\n animateId = requestAnimationFrame(update);\n\n resize();\n\n return () => {\n cancelAnimationFrame(animateId);\n window.removeEventListener('resize', resize);\n if (container && gl.canvas.parentNode === container) {\n container.removeChild(gl.canvas);\n }\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n };\n};\n\nconst cleanup = () => {\n if (animateId) {\n cancelAnimationFrame(animateId);\n }\n if (renderer) {\n const gl = renderer.gl;\n const container = containerRef.value;\n if (container && gl.canvas.parentNode === container) {\n container.removeChild(gl.canvas);\n }\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n }\n renderer = null;\n};\n\nonMounted(() => {\n initAurora();\n});\n\nonUnmounted(() => {\n cleanup();\n});\n\nwatch(\n () => [props.amplitude, props.intensity],\n () => {\n cleanup();\n initAurora();\n }\n);\n</script>\n\n<style scoped>\ndiv {\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n width: 100% !important;\n height: 100% !important;\n}\n\n:deep(canvas) {\n position: absolute !important;\n top: 0 !important;\n left: 0 !important;\n width: 100% !important;\n height: 100% !important;\n}\n</style>\n","path":"Aurora/Aurora.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"ogl","version":"^1.0.11"}],"devDependencies":[],"categories":["Backgrounds"]}