mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-04-21 17:44:39 -06:00
1 line
7.6 KiB
JSON
1 line
7.6 KiB
JSON
{"name":"Radar","title":"Radar","description":"Radar sweep effect with concentric rings, radial spokes, and a rotating beam.","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 RadarProps {\n speed?: number;\n scale?: number;\n ringCount?: number;\n spokeCount?: number;\n ringThickness?: number;\n spokeThickness?: number;\n sweepSpeed?: number;\n sweepWidth?: number;\n sweepLobes?: number;\n color?: string;\n backgroundColor?: string;\n falloff?: number;\n brightness?: 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 uRingCount;\nuniform float uSpokeCount;\nuniform float uRingThickness;\nuniform float uSpokeThickness;\nuniform float uSweepSpeed;\nuniform float uSweepWidth;\nuniform float uSweepLobes;\nuniform vec3 uColor;\nuniform vec3 uBgColor;\nuniform float uFalloff;\nuniform float uBrightness;\nuniform vec2 uMouse;\nuniform float uMouseInfluence;\nuniform bool uEnableMouse;\n\n#define TAU 6.28318530718\n#define PI 3.14159265359\n\nvoid main() {\n vec2 st = gl_FragCoord.xy / uResolution.xy;\n st = st * 2.0 - 1.0;\n st.x *= uResolution.x / uResolution.y;\n\n if (uEnableMouse) {\n vec2 mShift = (uMouse * 2.0 - 1.0);\n mShift.x *= uResolution.x / uResolution.y;\n st -= mShift * uMouseInfluence;\n }\n\n st *= uScale;\n\n float dist = length(st);\n float theta = atan(st.y, st.x);\n float t = uTime * uSpeed;\n\n float ringPhase = dist * uRingCount - t;\n float ringDist = abs(fract(ringPhase) - 0.5);\n float ringGlow = 1.0 - smoothstep(0.0, uRingThickness, ringDist);\n\n float spokeAngle = abs(fract(theta * uSpokeCount / TAU + 0.5) - 0.5) * TAU / uSpokeCount;\n float arcDist = spokeAngle * dist;\n float spokeGlow = (1.0 - smoothstep(0.0, uSpokeThickness, arcDist)) * smoothstep(0.0, 0.1, dist);\n\n float sweepPhase = t * uSweepSpeed;\n float sweepBeam = pow(max(0.5 * sin(uSweepLobes * theta + sweepPhase) + 0.5, 0.0), uSweepWidth);\n\n float fade = smoothstep(1.05, 0.85, dist) * pow(max(1.0 - dist, 0.0), uFalloff);\n\n float intensity = max((ringGlow + spokeGlow + sweepBeam) * fade * uBrightness, 0.0);\n vec3 col = uColor * intensity + uBgColor;\n\n float alpha = clamp(length(col), 0.0, 1.0);\n gl_FragColor = vec4(col, alpha);\n}\n`;\n\nconst props = withDefaults(defineProps<RadarProps>(), {\n speed: 1.0,\n scale: 0.5,\n ringCount: 10.0,\n spokeCount: 10.0,\n ringThickness: 0.05,\n spokeThickness: 0.01,\n sweepSpeed: 1.0,\n sweepWidth: 2.0,\n sweepLobes: 1.0,\n color: '#27FF64',\n backgroundColor: '#000000',\n falloff: 2.0,\n brightness: 1.0,\n enableMouseInteraction: true,\n mouseInfluence: 0.1\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 uRingCount: { value: props.ringCount },\n uSpokeCount: { value: props.spokeCount },\n uRingThickness: { value: props.ringThickness },\n uSpokeThickness: { value: props.spokeThickness },\n uSweepSpeed: { value: props.sweepSpeed },\n uSweepWidth: { value: props.sweepWidth },\n uSweepLobes: { value: props.sweepLobes },\n uColor: { value: hexToVec3(props.color) },\n uBgColor: { value: hexToVec3(props.backgroundColor) },\n uFalloff: { value: props.falloff },\n uBrightness: { value: props.brightness },\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.ringCount,\n props.spokeCount,\n props.ringThickness,\n props.spokeThickness,\n props.sweepSpeed,\n props.sweepWidth,\n props.sweepLobes,\n props.color,\n props.backgroundColor,\n props.falloff,\n props.brightness,\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":"Radar/Radar.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"ogl","version":"^1.0.11"}],"devDependencies":[],"categories":["Backgrounds"]} |