mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 14:39:30 -07:00
1 line
21 KiB
JSON
1 line
21 KiB
JSON
{"name":"LaserFlow","title":"LaserFlow","description":"Dynamic laser light that flows onto a surface, customizable effect.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<script setup lang=\"ts\">\nimport * as THREE from 'three';\nimport { onBeforeUnmount, onMounted, ref, useTemplateRef, watch, type CSSProperties } from 'vue';\n\ntype Props = {\n className?: string;\n style?: CSSProperties;\n wispDensity?: number;\n dpr?: number;\n mouseSmoothTime?: number;\n mouseTiltStrength?: number;\n horizontalBeamOffset?: number;\n verticalBeamOffset?: number;\n flowSpeed?: number;\n verticalSizing?: number;\n horizontalSizing?: number;\n fogIntensity?: number;\n fogScale?: number;\n wispSpeed?: number;\n wispIntensity?: number;\n flowStrength?: number;\n decay?: number;\n falloffStart?: number;\n fogFallSpeed?: number;\n color?: string;\n};\n\nconst VERT = `\nprecision highp float;\nattribute vec3 position;\nvoid main(){\n gl_Position = vec4(position, 1.0);\n}\n`;\n\nconst FRAG = `\n#ifdef GL_ES\n#extension GL_OES_standard_derivatives : enable\n#endif\nprecision highp float;\nprecision mediump int;\n\nuniform float iTime;\nuniform vec3 iResolution;\nuniform vec4 iMouse;\nuniform float uWispDensity;\nuniform float uTiltScale;\nuniform float uFlowTime;\nuniform float uFogTime;\nuniform float uBeamXFrac;\nuniform float uBeamYFrac;\nuniform float uFlowSpeed;\nuniform float uVLenFactor;\nuniform float uHLenFactor;\nuniform float uFogIntensity;\nuniform float uFogScale;\nuniform float uWSpeed;\nuniform float uWIntensity;\nuniform float uFlowStrength;\nuniform float uDecay;\nuniform float uFalloffStart;\nuniform float uFogFallSpeed;\nuniform vec3 uColor;\nuniform float uFade;\n\n// Core beam/flare shaping and dynamics\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n#define EPS 1e-6\n#define EDGE_SOFT (DT_LOCAL*4.0)\n#define DT_LOCAL 0.0038\n#define TAP_RADIUS 6\n#define R_H 150.0\n#define R_V 150.0\n#define FLARE_HEIGHT 16.0\n#define FLARE_AMOUNT 8.0\n#define FLARE_EXP 2.0\n#define TOP_FADE_START 0.1\n#define TOP_FADE_EXP 1.0\n#define FLOW_PERIOD 0.5\n#define FLOW_SHARPNESS 1.5\n\n// Wisps (animated micro-streaks) that travel along the beam\n#define W_BASE_X 1.5\n#define W_LAYER_GAP 0.25\n#define W_LANES 10\n#define W_SIDE_DECAY 0.5\n#define W_HALF 0.01\n#define W_AA 0.15\n#define W_CELL 20.0\n#define W_SEG_MIN 0.01\n#define W_SEG_MAX 0.55\n#define W_CURVE_AMOUNT 15.0\n#define W_CURVE_RANGE (FLARE_HEIGHT - 3.0)\n#define W_BOTTOM_EXP 10.0\n\n// Volumetric fog controls\n#define FOG_ON 1\n#define FOG_CONTRAST 1.2\n#define FOG_SPEED_U 0.1\n#define FOG_SPEED_V -0.1\n#define FOG_OCTAVES 5\n#define FOG_BOTTOM_BIAS 0.8\n#define FOG_TILT_TO_MOUSE 0.05\n#define FOG_TILT_DEADZONE 0.01\n#define FOG_TILT_MAX_X 0.35\n#define FOG_TILT_SHAPE 1.5\n#define FOG_BEAM_MIN 0.0\n#define FOG_BEAM_MAX 0.75\n#define FOG_MASK_GAMMA 0.5\n#define FOG_EXPAND_SHAPE 12.2\n#define FOG_EDGE_MIX 0.5\n\n// Horizontal vignette for the fog volume\n#define HFOG_EDGE_START 0.20\n#define HFOG_EDGE_END 0.98\n#define HFOG_EDGE_GAMMA 1.4\n#define HFOG_Y_RADIUS 25.0\n#define HFOG_Y_SOFT 60.0\n\n// Beam extents and edge masking\n#define EDGE_X0 0.22\n#define EDGE_X1 0.995\n#define EDGE_X_GAMMA 1.25\n#define EDGE_LUMA_T0 0.0\n#define EDGE_LUMA_T1 2.0\n#define DITHER_STRENGTH 1.0\n\n float g(float x){return x<=0.00031308?12.92*x:1.055*pow(x,1.0/2.4)-0.055;}\n float bs(vec2 p,vec2 q,float powr){\n float d=distance(p,q),f=powr*uFalloffStart,r=(f*f)/(d*d+EPS);\n return powr*min(1.0,r);\n }\n float bsa(vec2 p,vec2 q,float powr,vec2 s){\n vec2 d=p-q; float dd=(d.x*d.x)/(s.x*s.x)+(d.y*d.y)/(s.y*s.y),f=powr*uFalloffStart,r=(f*f)/(dd+EPS);\n return powr*min(1.0,r);\n }\n float tri01(float x){float f=fract(x);return 1.0-abs(f*2.0-1.0);}\n float tauWf(float t,float tmin,float tmax){float a=smoothstep(tmin,tmin+EDGE_SOFT,t),b=1.0-smoothstep(tmax-EDGE_SOFT,tmax,t);return max(0.0,a*b);}\n float h21(vec2 p){p=fract(p*vec2(123.34,456.21));p+=dot(p,p+34.123);return fract(p.x*p.y);}\n float vnoise(vec2 p){\n vec2 i=floor(p),f=fract(p);\n float a=h21(i),b=h21(i+vec2(1,0)),c=h21(i+vec2(0,1)),d=h21(i+vec2(1,1));\n vec2 u=f*f*(3.0-2.0*f);\n return mix(mix(a,b,u.x),mix(c,d,u.x),u.y);\n }\n float fbm2(vec2 p){\n float v=0.0,amp=0.6; mat2 m=mat2(0.86,0.5,-0.5,0.86);\n for(int i=0;i<FOG_OCTAVES;++i){v+=amp*vnoise(p); p=m*p*2.03+17.1; amp*=0.52;}\n return v;\n }\n float rGate(float x,float l){float a=smoothstep(0.0,W_AA,x),b=1.0-smoothstep(l,l+W_AA,x);return max(0.0,a*b);}\n float flareY(float y){float t=clamp(1.0-(clamp(y,0.0,FLARE_HEIGHT)/max(FLARE_HEIGHT,EPS)),0.0,1.0);return pow(t,FLARE_EXP);}\n\n float vWisps(vec2 uv,float topF){\n float y=uv.y,yf=(y+uFlowTime*uWSpeed)/W_CELL;\n float dRaw=clamp(uWispDensity,0.0,2.0),d=dRaw<=0.0?1.0:dRaw;\n float lanesF=floor(float(W_LANES)*min(d,1.0)+0.5); // WebGL1-safe\n int lanes=int(max(1.0,lanesF));\n float sp=min(d,1.0),ep=max(d-1.0,0.0);\n float fm=flareY(max(y,0.0)),rm=clamp(1.0-(y/max(W_CURVE_RANGE,EPS)),0.0,1.0),cm=fm*rm;\n const float G=0.05; float xS=1.0+(FLARE_AMOUNT*W_CURVE_AMOUNT*G)*cm;\n float sPix=clamp(y/R_V,0.0,1.0),bGain=pow(1.0-sPix,W_BOTTOM_EXP),sum=0.0;\n for(int s=0;s<2;++s){\n float sgn=s==0?-1.0:1.0;\n for(int i=0;i<W_LANES;++i){\n if(i>=lanes) break;\n float off=W_BASE_X+float(i)*W_LAYER_GAP,xc=sgn*(off*xS);\n float dx=abs(uv.x-xc),lat=1.0-smoothstep(W_HALF,W_HALF+W_AA,dx),amp=exp(-off*W_SIDE_DECAY);\n float seed=h21(vec2(off,sgn*17.0)),yf2=yf+seed*7.0,ci=floor(yf2),fy=fract(yf2);\n float seg=mix(W_SEG_MIN,W_SEG_MAX,h21(vec2(ci,off*2.3)));\n float spR=h21(vec2(ci,off+sgn*31.0)),seg1=rGate(fy,seg)*step(spR,sp);\n if(ep>0.0){float spR2=h21(vec2(ci*3.1+7.0,off*5.3+sgn*13.0)); float f2=fract(fy+0.5); seg1+=rGate(f2,seg*0.9)*step(spR2,ep);}\n sum+=amp*lat*seg1;\n }\n }\n float span=smoothstep(-3.0,0.0,y)*(1.0-smoothstep(R_V-6.0,R_V,y));\n return uWIntensity*sum*topF*bGain*span;\n}\n\nvoid mainImage(out vec4 fc,in vec2 frag){\n vec2 C=iResolution.xy*.5; float invW=1.0/max(C.x,1.0);\n float sc=512.0/iResolution.x*.4;\n vec2 uv=(frag-C)*sc,off=vec2(uBeamXFrac*iResolution.x*sc,uBeamYFrac*iResolution.y*sc);\n vec2 uvc = uv - off;\n float a=0.0,b=0.0;\n float basePhase=1.5*PI+uDecay*.5; float tauMin=basePhase-uDecay; float tauMax=basePhase;\n float cx=clamp(uvc.x/(R_H*uHLenFactor),-1.0,1.0),tH=clamp(TWO_PI-acos(cx),tauMin,tauMax);\n for(int k=-TAP_RADIUS;k<=TAP_RADIUS;++k){\n float tu=tH+float(k)*DT_LOCAL,wt=tauWf(tu,tauMin,tauMax); if(wt<=0.0) continue;\n float spd=max(abs(sin(tu)),0.02),u=clamp((basePhase-tu)/max(uDecay,EPS),0.0,1.0),env=pow(1.0-abs(u*2.0-1.0),0.8);\n vec2 p=vec2((R_H*uHLenFactor)*cos(tu),0.0);\n a+=wt*bs(uvc,p,env*spd);\n }\n float yPix=uvc.y,cy=clamp(-yPix/(R_V*uVLenFactor),-1.0,1.0),tV=clamp(TWO_PI-acos(cy),tauMin,tauMax);\n for(int k=-TAP_RADIUS;k<=TAP_RADIUS;++k){\n float tu=tV+float(k)*DT_LOCAL,wt=tauWf(tu,tauMin,tauMax); if(wt<=0.0) continue;\n float yb=(-R_V)*cos(tu),s=clamp(yb/R_V,0.0,1.0),spd=max(abs(sin(tu)),0.02);\n float env=pow(1.0-s,0.6)*spd;\n float cap=1.0-smoothstep(TOP_FADE_START,1.0,s); cap=pow(cap,TOP_FADE_EXP); env*=cap;\n float ph=s/max(FLOW_PERIOD,EPS)+uFlowTime*uFlowSpeed;\n float fl=pow(tri01(ph),FLOW_SHARPNESS);\n env*=mix(1.0-uFlowStrength,1.0,fl);\n float yp=(-R_V*uVLenFactor)*cos(tu),m=pow(smoothstep(FLARE_HEIGHT,0.0,yp),FLARE_EXP),wx=1.0+FLARE_AMOUNT*m;\n vec2 sig=vec2(wx,1.0),p=vec2(0.0,yp);\n float mask=step(0.0,yp);\n b+=wt*bsa(uvc,p,mask*env,sig);\n }\n float sPix=clamp(yPix/R_V,0.0,1.0),topA=pow(1.0-smoothstep(TOP_FADE_START,1.0,sPix),TOP_FADE_EXP);\n float L=a+b*topA;\n float w=vWisps(vec2(uvc.x,yPix),topA);\n float fog=0.0;\n#if FOG_ON\n vec2 fuv=uvc*uFogScale;\n float mAct=step(1.0,length(iMouse.xy)),nx=((iMouse.x-C.x)*invW)*mAct;\n float ax = abs(nx);\n float stMag = mix(ax, pow(ax, FOG_TILT_SHAPE), 0.35);\n float st = sign(nx) * stMag * uTiltScale;\n st = clamp(st, -FOG_TILT_MAX_X, FOG_TILT_MAX_X);\n vec2 dir=normalize(vec2(st,1.0));\n fuv+=uFogTime*uFogFallSpeed*dir;\n vec2 prp=vec2(-dir.y,dir.x);\n fuv+=prp*(0.08*sin(dot(uvc,prp)*0.08+uFogTime*0.9));\n float n=fbm2(fuv+vec2(fbm2(fuv+vec2(7.3,2.1)),fbm2(fuv+vec2(-3.7,5.9)))*0.6);\n n=pow(clamp(n,0.0,1.0),FOG_CONTRAST);\n float pixW = 1.0 / max(iResolution.y, 1.0);\n#ifdef GL_OES_standard_derivatives\n float wL = max(fwidth(L), pixW);\n#else\n float wL = pixW;\n#endif\n float m0=pow(smoothstep(FOG_BEAM_MIN - wL, FOG_BEAM_MAX + wL, L),FOG_MASK_GAMMA);\n float bm=1.0-pow(1.0-m0,FOG_EXPAND_SHAPE); bm=mix(bm*m0,bm,FOG_EDGE_MIX);\n float yP=1.0-smoothstep(HFOG_Y_RADIUS,HFOG_Y_RADIUS+HFOG_Y_SOFT,abs(yPix));\n float nxF=abs((frag.x-C.x)*invW),hE=1.0-smoothstep(HFOG_EDGE_START,HFOG_EDGE_END,nxF); hE=pow(clamp(hE,0.0,1.0),HFOG_EDGE_GAMMA);\n float hW=mix(1.0,hE,clamp(yP,0.0,1.0));\n float bBias=mix(1.0,1.0-sPix,FOG_BOTTOM_BIAS);\n float browserFogIntensity = uFogIntensity;\n browserFogIntensity *= 1.8;\n\n float radialFade = 1.0 - smoothstep(0.0, 0.7, length(uvc) / 120.0);\n float safariFog = n * browserFogIntensity * bBias * bm * hW * radialFade;\n fog = safariFog;\n#endif\n float LF=L+fog;\n float dith=(h21(frag)-0.5)*(DITHER_STRENGTH/255.0);\n float tone=g(LF+w);\n vec3 col=tone*uColor+dith;\n float alpha=clamp(g(L+w*0.6)+dith*0.6,0.0,1.0);\n float nxE=abs((frag.x-C.x)*invW),xF=pow(clamp(1.0-smoothstep(EDGE_X0,EDGE_X1,nxE),0.0,1.0),EDGE_X_GAMMA);\n float scene=LF+max(0.0,w)*0.5,hi=smoothstep(EDGE_LUMA_T0,EDGE_LUMA_T1,scene);\n float eM=mix(xF,1.0,hi);\n col*=eM; alpha*=eM;\n col*=uFade; alpha*=uFade;\n fc=vec4(col,alpha);\n}\n\nvoid main(){\n vec4 fc;\n mainImage(fc, gl_FragCoord.xy);\n gl_FragColor = fc;\n}\n`;\n\nconst props = withDefaults(defineProps<Props>(), {\n wispDensity: 1,\n mouseSmoothTime: 0.0,\n mouseTiltStrength: 0.01,\n horizontalBeamOffset: 0.1,\n verticalBeamOffset: 0.0,\n flowSpeed: 0.35,\n verticalSizing: 2.0,\n horizontalSizing: 0.5,\n fogIntensity: 0.45,\n fogScale: 0.3,\n wispSpeed: 15.0,\n wispIntensity: 5.0,\n flowStrength: 0.25,\n decay: 1.1,\n falloffStart: 1.2,\n fogFallSpeed: 0.6,\n color: '#A0FFBC'\n});\n\nconst mountRef = useTemplateRef('mountRef');\nconst rendererRef = ref<THREE.WebGLRenderer | null>(null);\nconst uniformsRef = ref<any>(null);\nconst hasFadedRef = ref(false);\nconst rectRef = ref<DOMRect | null>(null);\nconst baseDprRef = ref<number>(1);\nconst currentDprRef = ref<number>(1);\nconst fpsSamplesRef = ref<number[]>([]);\nconst lastFpsCheckRef = ref<number>(performance.now());\nconst emaDtRef = ref<number>(16.7); // ms\nconst pausedRef = ref<boolean>(false);\nconst inViewRef = ref<boolean>(true);\n\nconst hexToRGB = (hex: string) => {\n let c = hex.trim();\n if (c[0] === '#') c = c.slice(1);\n if (c.length === 3)\n c = c\n .split('')\n .map(x => x + x)\n .join('');\n const n = parseInt(c, 16) || 0xffffff;\n return { r: ((n >> 16) & 255) / 255, g: ((n >> 8) & 255) / 255, b: (n & 255) / 255 };\n};\n\nlet cleanup: (() => void) | null = null;\n\nconst setup = () => {\n const mount = mountRef.value!;\n const renderer = new THREE.WebGLRenderer({\n antialias: false,\n alpha: false,\n depth: false,\n stencil: false,\n powerPreference: 'high-performance',\n premultipliedAlpha: false,\n preserveDrawingBuffer: false,\n failIfMajorPerformanceCaveat: false,\n logarithmicDepthBuffer: false\n });\n\n rendererRef.value = renderer;\n\n baseDprRef.value = Math.min(props.dpr ?? (window.devicePixelRatio || 1), 2);\n currentDprRef.value = baseDprRef.value;\n\n renderer.setPixelRatio(currentDprRef.value);\n renderer.shadowMap.enabled = false;\n renderer.outputColorSpace = THREE.SRGBColorSpace;\n renderer.setClearColor(0x000000, 1);\n const canvas = renderer.domElement;\n canvas.style.width = '100%';\n canvas.style.height = '100%';\n canvas.style.display = 'block';\n mount.appendChild(canvas);\n\n const scene = new THREE.Scene();\n const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n\n const geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]), 3));\n\n const { r, g, b } = hexToRGB(props.color || '#FFFFFF');\n\n const uniforms = {\n iTime: { value: 0 },\n iResolution: { value: new THREE.Vector3(1, 1, 1) },\n iMouse: { value: new THREE.Vector4(0, 0, 0, 0) },\n uWispDensity: { value: props.wispDensity },\n uTiltScale: { value: props.mouseTiltStrength },\n uFlowTime: { value: 0 },\n uFogTime: { value: 0 },\n uBeamXFrac: { value: props.horizontalBeamOffset },\n uBeamYFrac: { value: props.verticalBeamOffset },\n uFlowSpeed: { value: props.flowSpeed },\n uVLenFactor: { value: props.verticalSizing },\n uHLenFactor: { value: props.horizontalSizing },\n uFogIntensity: { value: props.fogIntensity },\n uFogScale: { value: props.fogScale },\n uWSpeed: { value: props.wispSpeed },\n uWIntensity: { value: props.wispIntensity },\n uFlowStrength: { value: props.flowStrength },\n uDecay: { value: props.decay },\n uFalloffStart: { value: props.falloffStart },\n uFogFallSpeed: { value: props.fogFallSpeed },\n uColor: { value: new THREE.Vector3(r, g, b) },\n uFade: { value: hasFadedRef.value ? 1 : 0 }\n };\n uniformsRef.value = uniforms;\n\n const material = new THREE.RawShaderMaterial({\n vertexShader: VERT,\n fragmentShader: FRAG,\n uniforms,\n transparent: false,\n depthTest: false,\n depthWrite: false,\n blending: THREE.NormalBlending\n });\n\n const mesh = new THREE.Mesh(geometry, material);\n mesh.frustumCulled = false;\n scene.add(mesh);\n\n const clock = new THREE.Clock();\n let prevTime = 0;\n\n let fade = hasFadedRef.value ? 1 : 0;\n const mouseTarget = new THREE.Vector2(0, 0);\n const mouseSmooth = new THREE.Vector2(0, 0);\n\n const setSizeNow = () => {\n const w = mount.clientWidth || 1;\n const h = mount.clientHeight || 1;\n const pr = currentDprRef.value;\n renderer.setPixelRatio(pr);\n renderer.setSize(w, h, false);\n uniforms.iResolution.value.set(w * pr, h * pr, pr);\n rectRef.value = canvas.getBoundingClientRect();\n };\n\n let resizeRaf = 0;\n const scheduleResize = () => {\n if (resizeRaf) cancelAnimationFrame(resizeRaf);\n resizeRaf = requestAnimationFrame(setSizeNow);\n };\n\n setSizeNow();\n const ro = new ResizeObserver(scheduleResize);\n ro.observe(mount);\n\n const io = new IntersectionObserver(\n entries => {\n inViewRef.value = entries[0]?.isIntersecting ?? true;\n },\n { root: null, threshold: 0 }\n );\n io.observe(mount);\n\n const onVis = () => {\n pausedRef.value = document.hidden;\n };\n document.addEventListener('visibilitychange', onVis, { passive: true });\n\n const updateMouse = (clientX: number, clientY: number) => {\n const rect = rectRef.value;\n if (!rect) return;\n const x = clientX - rect.left;\n const y = clientY - rect.top;\n const ratio = currentDprRef.value;\n const hb = rect.height * ratio;\n mouseTarget.set(x * ratio, hb - y * ratio);\n };\n\n const onMove = (ev: PointerEvent | MouseEvent) => updateMouse(ev.clientX, ev.clientY);\n const onLeave = () => mouseTarget.set(0, 0);\n\n canvas.addEventListener('pointermove', onMove as any, { passive: true });\n canvas.addEventListener('pointerdown', onMove as any, { passive: true });\n canvas.addEventListener('pointerenter', onMove as any, { passive: true });\n canvas.addEventListener('pointerleave', onLeave as any, { passive: true });\n\n const onCtxLost = (e: Event) => {\n e.preventDefault();\n pausedRef.value = true;\n };\n const onCtxRestored = () => {\n pausedRef.value = false;\n scheduleResize();\n };\n canvas.addEventListener('webglcontextlost', onCtxLost, false);\n canvas.addEventListener('webglcontextrestored', onCtxRestored, false);\n\n let raf = 0;\n const clamp = (v: number, lo: number, hi: number) => Math.max(lo, Math.min(hi, v));\n const dprFloor = 0.6;\n const lowerThresh = 50;\n const upperThresh = 58;\n\n const adjustDprIfNeeded = (now: number) => {\n const elapsed = now - lastFpsCheckRef.value;\n if (elapsed < 750) return;\n\n const samples = fpsSamplesRef.value;\n if (samples.length === 0) {\n lastFpsCheckRef.value = now;\n return;\n }\n const avgFps = samples.reduce((a, b) => a + b, 0) / samples.length;\n\n let next = currentDprRef.value;\n const base = baseDprRef.value;\n\n if (avgFps < lowerThresh) {\n next = clamp(currentDprRef.value * 0.9, dprFloor, base);\n } else if (avgFps > upperThresh && currentDprRef.value < base) {\n next = clamp(currentDprRef.value * 1.05, dprFloor, base);\n }\n\n if (Math.abs(next - currentDprRef.value) > 0.01) {\n currentDprRef.value = next;\n setSizeNow();\n }\n\n fpsSamplesRef.value = [];\n lastFpsCheckRef.value = now;\n };\n\n const animate = () => {\n raf = requestAnimationFrame(animate);\n if (pausedRef.value || !inViewRef.value) return;\n\n const t = clock.getElapsedTime();\n const dt = Math.max(0, t - prevTime);\n prevTime = t;\n\n const dtMs = dt * 1000;\n emaDtRef.value = emaDtRef.value * 0.9 + dtMs * 0.1;\n const instFps = 1000 / Math.max(1, emaDtRef.value);\n fpsSamplesRef.value.push(instFps);\n\n uniforms.iTime.value = t;\n\n const cdt = Math.min(0.033, Math.max(0.001, dt));\n (uniforms.uFlowTime.value as number) += cdt;\n (uniforms.uFogTime.value as number) += cdt;\n\n if (!hasFadedRef.value) {\n const fadeDur = 1.0;\n fade = Math.min(1, fade + cdt / fadeDur);\n uniforms.uFade.value = fade;\n if (fade >= 1) hasFadedRef.value = true;\n }\n\n const tau = Math.max(1e-3, props.mouseSmoothTime);\n const alpha = 1 - Math.exp(-cdt / tau);\n mouseSmooth.lerp(mouseTarget, alpha);\n uniforms.iMouse.value.set(mouseSmooth.x, mouseSmooth.y, 0, 0);\n\n renderer.render(scene, camera);\n\n adjustDprIfNeeded(performance.now());\n };\n\n animate();\n\n cleanup = () => {\n cancelAnimationFrame(raf);\n ro.disconnect();\n io.disconnect();\n document.removeEventListener('visibilitychange', onVis);\n canvas.removeEventListener('pointermove', onMove as any);\n canvas.removeEventListener('pointerdown', onMove as any);\n canvas.removeEventListener('pointerenter', onMove as any);\n canvas.removeEventListener('pointerleave', onLeave as any);\n canvas.removeEventListener('webglcontextlost', onCtxLost);\n canvas.removeEventListener('webglcontextrestored', onCtxRestored);\n geometry.dispose();\n material.dispose();\n renderer.dispose();\n if (mount.contains(canvas)) mount.removeChild(canvas);\n };\n};\n\nonMounted(() => {\n setup();\n});\n\nonBeforeUnmount(() => {\n cleanup?.();\n});\n\nwatch(\n () => [props.dpr],\n () => {\n cleanup?.();\n setup();\n },\n { deep: true }\n);\n\nwatch(\n () => [\n props.wispDensity,\n props.mouseTiltStrength,\n props.horizontalBeamOffset,\n props.verticalBeamOffset,\n props.flowSpeed,\n props.verticalSizing,\n props.horizontalSizing,\n props.fogIntensity,\n props.fogScale,\n props.wispSpeed,\n props.wispIntensity,\n props.flowStrength,\n props.decay,\n props.falloffStart,\n props.fogFallSpeed,\n props.color\n ],\n () => {\n const uniforms = uniformsRef.value;\n if (!uniforms) return;\n\n uniforms.uWispDensity.value = props.wispDensity;\n uniforms.uTiltScale.value = props.mouseTiltStrength;\n uniforms.uBeamXFrac.value = props.horizontalBeamOffset;\n uniforms.uBeamYFrac.value = props.verticalBeamOffset;\n uniforms.uFlowSpeed.value = props.flowSpeed;\n uniforms.uVLenFactor.value = props.verticalSizing;\n uniforms.uHLenFactor.value = props.horizontalSizing;\n uniforms.uFogIntensity.value = props.fogIntensity;\n uniforms.uFogScale.value = props.fogScale;\n uniforms.uWSpeed.value = props.wispSpeed;\n uniforms.uWIntensity.value = props.wispIntensity;\n uniforms.uFlowStrength.value = props.flowStrength;\n uniforms.uDecay.value = props.decay;\n uniforms.uFalloffStart.value = props.falloffStart;\n uniforms.uFogFallSpeed.value = props.fogFallSpeed;\n\n const { r, g, b } = hexToRGB(props.color || '#FFFFFF');\n console.log(props.color);\n uniforms.uColor.value.set(r, g, b);\n },\n { deep: true }\n);\n</script>\n\n<template>\n <div ref=\"mountRef\" :class=\"['w-full h-full relative', className]\" :style=\"style\" />\n</template>\n","path":"LaserFlow/LaserFlow.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"three","version":"^0.178.0"}],"devDependencies":[],"categories":["Animations"]} |