mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 06:29:30 -07:00
1 line
5.3 KiB
JSON
1 line
5.3 KiB
JSON
{"name":"Iridescence","title":"Iridescence","description":"Slick iridescent shader with shifting waves.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<template>\n <div ref=\"containerRef\" class=\"w-full h-full\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';\nimport { Renderer, Program, Mesh, Color, Triangle } from 'ogl';\nimport type { OGLRenderingContext } from 'ogl';\n\ninterface Props {\n color?: [number, number, number];\n speed?: number;\n amplitude?: number;\n mouseReact?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n color: () => [1, 1, 1] as [number, number, number],\n speed: 1.0,\n amplitude: 0.1,\n mouseReact: true\n});\n\nconst containerRef = useTemplateRef<HTMLDivElement>('containerRef');\nconst mousePos = ref({ x: 0.5, y: 0.5 });\n\nlet renderer: Renderer | null = null;\nlet gl: OGLRenderingContext | null = null;\nlet program: Program | null = null;\nlet mesh: Mesh | null = null;\nlet animationId: number | null = null;\n\nconst vertexShader = `\nattribute vec2 uv;\nattribute vec2 position;\n\nvarying vec2 vUv;\n\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 uColor;\nuniform vec3 uResolution;\nuniform vec2 uMouse;\nuniform float uAmplitude;\nuniform float uSpeed;\n\nvarying vec2 vUv;\n\nvoid main() {\n float mr = min(uResolution.x, uResolution.y);\n vec2 uv = (vUv.xy * 2.0 - 1.0) * uResolution.xy / mr;\n\n uv += (uMouse - vec2(0.5)) * uAmplitude;\n\n float d = -uTime * 0.5 * uSpeed;\n float a = 0.0;\n for (float i = 0.0; i < 8.0; ++i) {\n a += cos(i - d - a * uv.x);\n d += sin(uv.y * i + a);\n }\n d += uTime * 0.5 * uSpeed;\n vec3 col = vec3(cos(uv * vec2(d, a)) * 0.6 + 0.4, cos(a + d) * 0.5 + 0.5);\n col = cos(col * cos(vec3(d, a, 2.5)) * 0.5 + 0.5) * uColor;\n gl_FragColor = vec4(col, 1.0);\n}\n`;\n\nconst resize = () => {\n if (!containerRef.value || !renderer || !program || !gl) return;\n\n const container = containerRef.value;\n const scale = 1;\n renderer.setSize(container.offsetWidth * scale, container.offsetHeight * scale);\n\n if (program) {\n program.uniforms.uResolution.value = new Color(\n gl.canvas.width,\n gl.canvas.height,\n gl.canvas.width / gl.canvas.height\n );\n }\n};\n\nconst handleMouseMove = (e: MouseEvent) => {\n if (!containerRef.value || !program) return;\n\n const rect = containerRef.value.getBoundingClientRect();\n const x = (e.clientX - rect.left) / rect.width;\n const y = 1.0 - (e.clientY - rect.top) / rect.height;\n\n mousePos.value = { x, y };\n if (program.uniforms.uMouse.value) {\n program.uniforms.uMouse.value[0] = x;\n program.uniforms.uMouse.value[1] = y;\n }\n};\n\nconst update = (t: number) => {\n if (!program || !renderer || !mesh) return;\n\n animationId = requestAnimationFrame(update);\n program.uniforms.uTime.value = t * 0.001;\n renderer.render({ scene: mesh });\n};\n\nconst initializeScene = () => {\n if (!containerRef.value) return;\n\n cleanup();\n\n const container = containerRef.value;\n renderer = new Renderer();\n gl = renderer.gl;\n gl.clearColor(1, 1, 1, 1);\n\n const geometry = new Triangle(gl);\n program = new Program(gl, {\n vertex: vertexShader,\n fragment: fragmentShader,\n uniforms: {\n uTime: { value: 0 },\n uColor: { value: new Color(...props.color) },\n uResolution: {\n value: new Color(gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height)\n },\n uMouse: { value: new Float32Array([mousePos.value.x, mousePos.value.y]) },\n uAmplitude: { value: props.amplitude },\n uSpeed: { value: props.speed }\n }\n });\n\n mesh = new Mesh(gl, { geometry, program });\n\n const canvas = gl.canvas as HTMLCanvasElement;\n canvas.style.width = '100%';\n canvas.style.height = '100%';\n canvas.style.display = 'block';\n\n container.appendChild(canvas);\n\n window.addEventListener('resize', resize);\n if (props.mouseReact) {\n container.addEventListener('mousemove', handleMouseMove);\n }\n\n resize();\n animationId = requestAnimationFrame(update);\n};\n\nconst cleanup = () => {\n if (animationId) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n\n window.removeEventListener('resize', resize);\n\n if (containerRef.value) {\n containerRef.value.removeEventListener('mousemove', handleMouseMove);\n\n const canvas = containerRef.value.querySelector('canvas');\n if (canvas) {\n containerRef.value.removeChild(canvas);\n }\n }\n\n if (gl) {\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n }\n\n renderer = null;\n gl = null;\n program = null;\n mesh = null;\n};\n\nonMounted(() => {\n initializeScene();\n});\n\nonUnmounted(() => {\n cleanup();\n});\n\nwatch(\n [() => props.color, () => props.speed, () => props.amplitude, () => props.mouseReact],\n () => {\n initializeScene();\n },\n { deep: true }\n);\n</script>\n","path":"Iridescence/Iridescence.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"ogl","version":"^1.0.11"}],"devDependencies":[],"categories":["Backgrounds"]} |