diff --git a/src/components/AnimatedBackground.tsx b/src/components/AnimatedBackground.tsx index 1c33f83..28de948 100644 --- a/src/components/AnimatedBackground.tsx +++ b/src/components/AnimatedBackground.tsx @@ -222,7 +222,6 @@ const AnimatedBackground: React.FC = () => { const particleCount = 500; const gridSize = 50; // Spatial partitioning grid size const mouseRadius = 800; - const mouseRadiusSquared = mouseRadius * mouseRadius; const maxLineLength = 95; const maxLineLengthSquared = maxLineLength * maxLineLength; const propagationRadius = 40; // Valor mais realista para propagação visível @@ -242,20 +241,49 @@ const AnimatedBackground: React.FC = () => { const opacityCache = new OpacityCache(); const mouse = { x: -1000, y: -1000 }; + let globalOpacity = 0; + let targetOpacity = 0; + const opacitySpeed = 0.01; // Velocidade suave de fade + let effectiveRadius = 0; + let targetRadius = 0; + const radiusSpeed = 0.005; // Velocidade de shrink/implode mais lenta + + const checkMouseInHero = (x: number, y: number) => { + if (x === -1000 || y === -1000) return false; + const elementUnderMouse = document.elementFromPoint(x, y); + return elementUnderMouse?.closest(".hero") !== null; + }; const handleMouseMove = (e: MouseEvent) => { - mouse.x = e.clientX; - mouse.y = e.clientY; - opacityCache.updateMouse(mouse.x, mouse.y, mouseRadius); + const isInHero = checkMouseInHero(e.clientX, e.clientY); + if (isInHero) { + mouse.x = e.clientX; + mouse.y = e.clientY; + opacityCache.updateMouse(mouse.x, mouse.y, mouseRadius); + targetOpacity = 1; + targetRadius = mouseRadius; + } else { + // Não setar mouse.x = -1000 imediatamente, deixar o raio controlar + targetOpacity = 0; + targetRadius = 0; + } }; const handleMouseLeave = () => { - mouse.x = -1000; - mouse.y = -1000; + targetOpacity = 0; + targetRadius = 0; + }; + + const handleScroll = () => { + if (!checkMouseInHero(mouse.x, mouse.y)) { + targetOpacity = 0; + targetRadius = 0; + } }; window.addEventListener("mousemove", handleMouseMove, { passive: true }); window.addEventListener("mouseleave", handleMouseLeave, { passive: true }); + window.addEventListener("scroll", handleScroll, { passive: true }); const particles: Particle[] = []; for (let i = 0; i < particleCount; i++) { @@ -268,6 +296,16 @@ const AnimatedBackground: React.FC = () => { const animate = () => { frameCount++; + // Update global opacity and effective radius for smooth transitions + globalOpacity += (targetOpacity - globalOpacity) * opacitySpeed; + effectiveRadius += (targetRadius - effectiveRadius) * radiusSpeed; + + // Stop animation when radius reaches zero + if (effectiveRadius <= 1) { + mouse.x = -1000; + mouse.y = -1000; + } + // Clear canvas ctx.fillStyle = "#000000"; ctx.fillRect(0, 0, canvas.width, canvas.height); @@ -293,11 +331,12 @@ const AnimatedBackground: React.FC = () => { ? spatialGrid.getNeighbors(mouseGridX, mouseGridY, mouseRadius) : []; - // Filter particles within mouse radius + // Filter particles within effective radius + const effectiveRadiusSquared = effectiveRadius * effectiveRadius; const connectedParticles: Particle[] = []; for (const p of nearbyParticles) { const distSquared = distanceCache.get(mouse.x, mouse.y, p.x, p.y); - if (distSquared < mouseRadiusSquared) { + if (distSquared < effectiveRadiusSquared) { p.layer = 0; // Partículas conectadas diretamente ao mouse = camada 0 connectedParticles.push(p); } @@ -306,6 +345,7 @@ const AnimatedBackground: React.FC = () => { if (connectedParticles.length > 0) { ctx.save(); ctx.globalCompositeOperation = "lighter"; + ctx.globalAlpha = globalOpacity; const processedSet = new Set(connectedParticles); @@ -565,12 +605,24 @@ const AnimatedBackground: React.FC = () => { window.removeEventListener("resize", resize); window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseleave", handleMouseLeave); + window.removeEventListener("scroll", handleScroll); cancelAnimationFrame(animationFrameId); }; }, []); return ( -
+
); diff --git a/src/sections/About.scss b/src/sections/About.scss index 299d5fd..5fb1439 100644 --- a/src/sections/About.scss +++ b/src/sections/About.scss @@ -9,6 +9,9 @@ display: flex; flex-direction: column; align-items: center; + background: rgba(0, 0, 0, 0.85); // Contraste com o background animado + padding: 2rem; + border-radius: 10px; @media (max-width: 1500px) { width: 1100px; diff --git a/src/sections/Contact.scss b/src/sections/Contact.scss index f276a91..b4ce4c7 100644 --- a/src/sections/Contact.scss +++ b/src/sections/Contact.scss @@ -13,6 +13,9 @@ justify-content: center; z-index: 10; margin-bottom: 10rem; + background: rgba(0, 0, 0, 0.85); // Contraste com o background animado + padding: 2rem; + border-radius: 10px; @media (max-width: 700px) { width: 400px; diff --git a/src/sections/Experience.scss b/src/sections/Experience.scss index 48d5fcc..c04883c 100644 --- a/src/sections/Experience.scss +++ b/src/sections/Experience.scss @@ -19,6 +19,9 @@ width: 1300px; margin-left: auto; margin-right: auto; + background: rgba(0, 0, 0, 0.85); // Contraste com o background animado + padding: 2rem; + border-radius: 10px; display: flex; flex-direction: column; align-items: center; diff --git a/src/sections/Hero.tsx b/src/sections/Hero.tsx index 344d737..a71f772 100644 --- a/src/sections/Hero.tsx +++ b/src/sections/Hero.tsx @@ -1,6 +1,5 @@ import { ArrowRight, Download } from "lucide-react"; import { Helmet } from "react-helmet-async"; -import AnimatedBackground from "../components/AnimatedBackground"; import "./Hero.scss"; const Hero: React.FC = () => { @@ -13,7 +12,6 @@ const Hero: React.FC = () => { content="Portfólio de Matheus Caiser, desenvolvedor web Full Stack especialista em criar soluções modernas e performáticas com React, Node.js, TypeScript e outras tecnologias de ponta." /> -

diff --git a/vercel.json b/vercel.json index db46a80..4ae9f15 100644 --- a/vercel.json +++ b/vercel.json @@ -1,5 +1,8 @@ { "buildCommand": "npx pnpm@10 build", "installCommand": "npx pnpm@10 install", - "devCommand": "npx pnpm@10 dev" + "devCommand": "npx pnpm@10 dev", + "git": { + "deploymentEnabled": false + } } \ No newline at end of file