()
| 118 | useEffect(() => { |
| 119 | let rafId; |
| 120 | const animate = () => { |
| 121 | mouseRef.current.x += (cursorRef.current.x - mouseRef.current.x) / 15; |
| 122 | mouseRef.current.y += (cursorRef.current.y - mouseRef.current.y) / 15; |
| 123 | |
| 124 | if (titleRef.current) { |
| 125 | const titleRect = titleRef.current.getBoundingClientRect(); |
| 126 | const maxDist = titleRect.width / 2; |
| 127 | |
| 128 | spansRef.current.forEach(span => { |
| 129 | if (!span) return; |
| 130 | |
| 131 | const rect = span.getBoundingClientRect(); |
| 132 | const charCenter = { |
| 133 | x: rect.x + rect.width / 2, |
| 134 | y: rect.y + rect.height / 2 |
| 135 | }; |
| 136 | |
| 137 | const d = dist(mouseRef.current, charCenter); |
| 138 | |
| 139 | const wdth = width ? Math.floor(getAttr(d, maxDist, 5, 200)) : 100; |
| 140 | const wght = weight ? Math.floor(getAttr(d, maxDist, 100, 900)) : 400; |
| 141 | const italVal = italic ? getAttr(d, maxDist, 0, 1).toFixed(2) : 0; |
| 142 | const alphaVal = alpha ? getAttr(d, maxDist, 0, 1).toFixed(2) : 1; |
| 143 | |
| 144 | const newFontVariationSettings = `'wght' ${wght}, 'wdth' ${wdth}, 'ital' ${italVal}`; |
| 145 | |
| 146 | if (span.style.fontVariationSettings !== newFontVariationSettings) { |
| 147 | span.style.fontVariationSettings = newFontVariationSettings; |
| 148 | } |
| 149 | if (alpha && span.style.opacity !== alphaVal) { |
| 150 | span.style.opacity = alphaVal; |
| 151 | } |
| 152 | }); |
| 153 | } |
| 154 | |
| 155 | rafId = requestAnimationFrame(animate); |
| 156 | }; |
| 157 | |
| 158 | animate(); |
| 159 | return () => cancelAnimationFrame(rafId); |
no test coverage detected