mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-04-21 17:44:39 -06:00
1 line
9.0 KiB
JSON
1 line
9.0 KiB
JSON
{"name":"LineWaves","title":"LineWaves","description":"Animated line wave pattern with colorful warped distortion.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<script setup lang=\"ts\">\nimport { Renderer, Program, Mesh, Triangle } from 'ogl';\nimport { onBeforeUnmount, onMounted, useTemplateRef, watch } from 'vue';\n\ninterface LineWavesProps {\n speed?: number;\n innerLineCount?: number;\n outerLineCount?: number;\n warpIntensity?: number;\n rotation?: number;\n edgeFadeWidth?: number;\n colorCycleSpeed?: number;\n brightness?: number;\n color1?: string;\n color2?: string;\n color3?: string;\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 uInnerLines;\nuniform float uOuterLines;\nuniform float uWarpIntensity;\nuniform float uRotation;\nuniform float uEdgeFadeWidth;\nuniform float uColorCycleSpeed;\nuniform float uBrightness;\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform vec3 uColor3;\nuniform vec2 uMouse;\nuniform float uMouseInfluence;\nuniform bool uEnableMouse;\n\n#define HALF_PI 1.5707963\n\nfloat hashF(float n) {\n return fract(sin(n * 127.1) * 43758.5453123);\n}\n\nfloat smoothNoise(float x) {\n float i = floor(x);\n float f = fract(x);\n float u = f * f * (3.0 - 2.0 * f);\n return mix(hashF(i), hashF(i + 1.0), u);\n}\n\nfloat displaceA(float coord, float t) {\n float result = sin(coord * 2.123) * 0.2;\n result += sin(coord * 3.234 + t * 4.345) * 0.1;\n result += sin(coord * 0.589 + t * 0.934) * 0.5;\n return result;\n}\n\nfloat displaceB(float coord, float t) {\n float result = sin(coord * 1.345) * 0.3;\n result += sin(coord * 2.734 + t * 3.345) * 0.2;\n result += sin(coord * 0.189 + t * 0.934) * 0.3;\n return result;\n}\n\nvec2 rotate2D(vec2 p, float angle) {\n float c = cos(angle);\n float s = sin(angle);\n return vec2(p.x * c - p.y * s, p.x * s + p.y * c);\n}\n\nvoid main() {\n vec2 coords = gl_FragCoord.xy / uResolution.xy;\n coords = coords * 2.0 - 1.0;\n coords = rotate2D(coords, uRotation);\n\n float halfT = uTime * uSpeed * 0.5;\n float fullT = uTime * uSpeed;\n\n float mouseWarp = 0.0;\n if (uEnableMouse) {\n vec2 mPos = rotate2D(uMouse * 2.0 - 1.0, uRotation);\n float mDist = length(coords - mPos);\n mouseWarp = uMouseInfluence * exp(-mDist * mDist * 4.0);\n }\n\n float warpAx = coords.x + displaceA(coords.y, halfT) * uWarpIntensity + mouseWarp;\n float warpAy = coords.y - displaceA(coords.x * cos(fullT) * 1.235, halfT) * uWarpIntensity;\n float warpBx = coords.x + displaceB(coords.y, halfT) * uWarpIntensity + mouseWarp;\n float warpBy = coords.y - displaceB(coords.x * sin(fullT) * 1.235, halfT) * uWarpIntensity;\n\n vec2 fieldA = vec2(warpAx, warpAy);\n vec2 fieldB = vec2(warpBx, warpBy);\n vec2 blended = mix(fieldA, fieldB, mix(fieldA, fieldB, 0.5));\n\n float fadeTop = smoothstep(uEdgeFadeWidth, uEdgeFadeWidth + 0.4, blended.y);\n float fadeBottom = smoothstep(-uEdgeFadeWidth, -(uEdgeFadeWidth + 0.4), blended.y);\n float vMask = 1.0 - max(fadeTop, fadeBottom);\n\n float tileCount = mix(uOuterLines, uInnerLines, vMask);\n float scaledY = blended.y * tileCount;\n float nY = smoothNoise(abs(scaledY));\n\n float ridge = pow(\n step(abs(nY - blended.x) * 2.0, HALF_PI) * cos(2.0 * (nY - blended.x)),\n 5.0\n );\n\n float lines = 0.0;\n for (float i = 1.0; i < 3.0; i += 1.0) {\n lines += pow(max(fract(scaledY), fract(-scaledY)), i * 2.0);\n }\n\n float pattern = vMask * lines;\n\n float cycleT = fullT * uColorCycleSpeed;\n float rChannel = (pattern + lines * ridge) * (cos(blended.y + cycleT * 0.234) * 0.5 + 1.0);\n float gChannel = (pattern + vMask * ridge) * (sin(blended.x + cycleT * 1.745) * 0.5 + 1.0);\n float bChannel = (pattern + lines * ridge) * (cos(blended.x + cycleT * 0.534) * 0.5 + 1.0);\n\n vec3 col = (rChannel * uColor1 + gChannel * uColor2 + bChannel * uColor3) * uBrightness;\n float alpha = clamp(length(col), 0.0, 1.0);\n\n gl_FragColor = vec4(col, alpha);\n}\n`;\n\nconst props = withDefaults(defineProps<LineWavesProps>(), {\n speed: 0.3,\n innerLineCount: 32.0,\n outerLineCount: 36.0,\n warpIntensity: 1.0,\n rotation: -45,\n edgeFadeWidth: 0.0,\n colorCycleSpeed: 1.0,\n brightness: 0.2,\n color1: '#ffffff',\n color2: '#ffffff',\n color3: '#ffffff',\n enableMouseInteraction: true,\n mouseInfluence: 2.0\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 rotationRad = (props.rotation * Math.PI) / 180;\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 uInnerLines: { value: props.innerLineCount },\n uOuterLines: { value: props.outerLineCount },\n uWarpIntensity: { value: props.warpIntensity },\n uRotation: { value: rotationRad },\n uEdgeFadeWidth: { value: props.edgeFadeWidth },\n uColorCycleSpeed: { value: props.colorCycleSpeed },\n uBrightness: { value: props.brightness },\n uColor1: { value: hexToVec3(props.color1) },\n uColor2: { value: hexToVec3(props.color2) },\n uColor3: { value: hexToVec3(props.color3) },\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.innerLineCount,\n props.outerLineCount,\n props.warpIntensity,\n props.rotation,\n props.edgeFadeWidth,\n props.colorCycleSpeed,\n props.brightness,\n props.color1,\n props.color2,\n props.color3,\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":"LineWaves/LineWaves.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"ogl","version":"^1.0.11"}],"devDependencies":[],"categories":["Backgrounds"]} |