From 63be3a4dd50947029f3a5c38bb665eb675cc0c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Henrique?= Date: Mon, 18 Aug 2025 17:47:01 -0300 Subject: [PATCH] improving looks & background --- css/main.css | 3 +- css/matrix.css | 43 ------- css/variables.css | 6 +- index.html | 2 +- js/matrix.js | 284 ++++++++++++++++------------------------------ 5 files changed, 103 insertions(+), 235 deletions(-) diff --git a/css/main.css b/css/main.css index c0bfef8..fe622ca 100644 --- a/css/main.css +++ b/css/main.css @@ -44,7 +44,8 @@ img { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border-radius: var(--border-radius); - border: 1px solid var(--glass-border); + border-top: 1px solid var(--glass-border); + border-bottom: 1px solid var(--glass-border); box-shadow: var(--box-shadow), var(--inset-shadow); } diff --git a/css/matrix.css b/css/matrix.css index f904b6a..0db27cb 100644 --- a/css/matrix.css +++ b/css/matrix.css @@ -12,46 +12,3 @@ filter: brightness(0.55); } -.matrix-dot { - position: absolute; - background: rgba(255, 255, 255, 0.8); - border-radius: 50%; - box-shadow: 0 0 6px rgba(255, 255, 255, 0.4), 0 0 12px rgba(255, 255, 255, 0.2); - transition: all 0.3s ease; - pointer-events: none; -} - -.connection-line { - position: absolute; - height: 2px; - background: linear-gradient(90deg, - rgba(100, 149, 237, 0) 0%, - rgba(138, 43, 226, 0.8) 50%, - rgba(100, 149, 237, 0) 100%); - transform-origin: left center; - opacity: 0; - transition: opacity 0.5s ease-in-out; - pointer-events: none; - z-index: -1; - box-shadow: 0 0 4px rgba(138, 43, 226, 0.4); -} - -.connection-line.active { - opacity: 1; - animation: connectionPulse 2s ease-in-out infinite; -} - -@keyframes connectionPulse { - 0% { - filter: brightness(1); - box-shadow: 0 0 4px rgba(138, 43, 226, 0.4); - } - 50% { - filter: brightness(1.5); - box-shadow: 0 0 8px rgba(138, 43, 226, 0.6), 0 0 16px rgba(100, 149, 237, 0.3); - } - 100% { - filter: brightness(1); - box-shadow: 0 0 4px rgba(138, 43, 226, 0.4); - } -} \ No newline at end of file diff --git a/css/variables.css b/css/variables.css index 5295951..02e4a37 100644 --- a/css/variables.css +++ b/css/variables.css @@ -11,7 +11,7 @@ --background-color: #000000; --glass-background: rgba(20, 20, 20, 0.125); --glass-border: rgba(255, 255, 255, 0.18); - --glass-shadow: rgba(31, 38, 135, 0.37); + --glass-shadow: rgba(31, 38, 135, 0.30); --text-color: #ffffff; --text-color-light: rgba(255, 255, 255, 0.8); @@ -22,6 +22,6 @@ --border-radius: 16px; --border-radius-large: 24px; - --box-shadow: 0 8px 32px 0 var(--glass-shadow); - --inset-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); + --box-shadow: 0 8px 36px 0px var(--glass-shadow); + --inset-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); } diff --git a/index.html b/index.html index c51df74..144dadc 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,7 @@ -
+
diff --git a/js/matrix.js b/js/matrix.js index a47ff01..668e5ef 100644 --- a/js/matrix.js +++ b/js/matrix.js @@ -1,14 +1,15 @@ class MatrixBackground { constructor() { this.canvas = document.getElementById('matrixCanvas'); + this.ctx = this.canvas.getContext('2d'); this.dots = []; this.connections = []; this.config = { dotCount: 50, - dotSpeed: 0.2, // pixels per frame - connectionDuration: { min: 2000, max: 6000 }, // milliseconds - connectionChance: 0.0002, // chance per frame per dot pair - maxConnections: 8, // maximum simultaneous connections + dotSpeed: 0.2, + connectionDuration: { min: 2000, max: 6000 }, + connectionChance: 0.0002, + maxConnections: 8, dotSize: 3, colors: { dotDefault: 'rgba(255, 255, 255, 0.8)', @@ -22,40 +23,22 @@ class MatrixBackground { } } }; - + this.init(); } init() { - this.createDots(); - this.animate(); this.handleResize(); - - // Handle window resize + this.animate(); window.addEventListener('resize', () => this.handleResize()); } handleResize() { - // Recreate dots with new screen dimensions - // Clear previous DOM elements to avoid orphan/sticky dots - this.clearCanvas(); + this.canvas.width = window.innerWidth; + this.canvas.height = window.innerHeight; this.createDots(); } - clearCanvas() { - // Remove all dot and connection elements from the canvas - try { - while (this.canvas.firstChild) { - this.canvas.removeChild(this.canvas.firstChild); - } - } catch (e) { - // ignore - } - // Reset arrays - this.dots = []; - this.connections = []; - } - createDots() { this.dots = []; for (let i = 0; i < this.config.dotCount; i++) { @@ -64,65 +47,44 @@ class MatrixBackground { } createDot() { - const dot = document.createElement('div'); - dot.className = 'matrix-dot'; - - // Random starting position within screen bounds - const startX = Math.random() * (window.innerWidth - 20) + 10; - const startY = Math.random() * (window.innerHeight - 20) + 10; - - // Random movement direction (flying in all directions) + const startX = Math.random() * (this.canvas.width - 20) + 10; + const startY = Math.random() * (this.canvas.height - 20) + 10; + let velocityX = 0, velocityY = 0; let attempts = 0; while ((Math.abs(velocityX) < 0.15 || Math.abs(velocityY) < 0.15) && attempts < 10) { const angle = Math.random() * Math.PI * 2; - const speed = this.config.dotSpeed * (0.8 + Math.random() * 0.4); // Ensure minimum speed + const speed = this.config.dotSpeed * (0.8 + Math.random() * 0.4); velocityX = Math.cos(angle) * speed; velocityY = Math.sin(angle) * speed; attempts++; } - // Final fallback if still too low if (Math.abs(velocityX) < 0.15) velocityX = velocityX < 0 ? -0.15 : 0.15; if (Math.abs(velocityY) < 0.15) velocityY = velocityY < 0 ? -0.15 : 0.15; - const dotData = { - element: dot, + + this.dots.push({ x: startX, y: startY, vx: velocityX, vy: velocityY, opacity: Math.random() * 0.3 + 0.7, size: this.config.dotSize + Math.random() * 2, - isConnected: false, connectionCount: 0, - stuckFrames: 0 // Track how long dot is stuck - }; - - // Set initial styles (white by default) - dot.style.left = startX + 'px'; - dot.style.top = startY + 'px'; - dot.style.width = dotData.size + 'px'; - dot.style.height = dotData.size + 'px'; - dot.style.opacity = dotData.opacity; - dot.style.background = this.config.colors.dotDefault; - dot.style.boxShadow = `0 0 6px ${this.config.colors.dotDefaultGlow}, 0 0 12px rgba(255, 255, 255, 0.2)`; - - this.canvas.appendChild(dot); - this.dots.push(dotData); + stuckFrames: 0 + }); } updateDots() { - this.dots.forEach((dot, index) => { - // Update position + this.dots.forEach(dot => { dot.x += dot.vx; dot.y += dot.vy; - // Track if dot is stuck (velocity very low for several frames) if (Math.abs(dot.vx) < 0.03 && Math.abs(dot.vy) < 0.03) { - dot.stuckFrames = (dot.stuckFrames || 0) + 1; + dot.stuckFrames++; } else { dot.stuckFrames = 0; } - // If stuck for more than 30 frames, give a strong nudge + if (dot.stuckFrames > 30) { const angle = Math.random() * Math.PI * 2; const speed = this.config.dotSpeed * (0.8 + Math.random() * 0.4); @@ -130,18 +92,12 @@ class MatrixBackground { dot.vy = Math.sin(angle) * speed; dot.stuckFrames = 0; } else { - // Prevent dots from getting stuck - add small random nudge if velocity is too low - if (Math.abs(dot.vx) < 0.05) { - dot.vx += (Math.random() - 0.5) * 0.1; - } - if (Math.abs(dot.vy) < 0.05) { - dot.vy += (Math.random() - 0.5) * 0.1; - } + if (Math.abs(dot.vx) < 0.05) dot.vx += (Math.random() - 0.5) * 0.1; + if (Math.abs(dot.vy) < 0.05) dot.vy += (Math.random() - 0.5) * 0.1; } - // Bounce off screen edges (consider dot size so centers stay inside) - const maxX = window.innerWidth - dot.size; - const maxY = window.innerHeight - dot.size; + const maxX = this.canvas.width - dot.size; + const maxY = this.canvas.height - dot.size; if (dot.x <= 0 || dot.x >= maxX) { dot.vx = -dot.vx; dot.x = Math.max(0, Math.min(maxX, dot.x)); @@ -150,146 +106,96 @@ class MatrixBackground { dot.vy = -dot.vy; dot.y = Math.max(0, Math.min(maxY, dot.y)); } - - // Update DOM element position (top-left) - dot.element.style.left = dot.x + 'px'; - dot.element.style.top = dot.y + 'px'; - - // Update dot color based on connection status - if (dot.connectionCount > 0 && !dot.isConnected) { - dot.isConnected = true; - dot.element.style.background = this.config.colors.dotConnected; - dot.element.style.boxShadow = `0 0 6px ${this.config.colors.dotConnectedGlow}, 0 0 12px rgba(100, 149, 237, 0.3)`; - } else if (dot.connectionCount === 0 && dot.isConnected) { - dot.isConnected = false; - dot.element.style.background = this.config.colors.dotDefault; - dot.element.style.boxShadow = `0 0 6px ${this.config.colors.dotDefaultGlow}, 0 0 12px rgba(255, 255, 255, 0.2)`; - } }); } + drawDots() { + this.dots.forEach(dot => { + const isConnected = dot.connectionCount > 0; + this.ctx.beginPath(); + this.ctx.arc(dot.x, dot.y, dot.size / 2, 0, Math.PI * 2); + this.ctx.fillStyle = isConnected ? this.config.colors.dotConnected : this.config.colors.dotDefault; + this.ctx.globalAlpha = dot.opacity; + this.ctx.shadowBlur = 6; + this.ctx.shadowColor = isConnected ? this.config.colors.dotConnectedGlow : this.config.colors.dotDefaultGlow; + this.ctx.fill(); + }); + this.ctx.globalAlpha = 1; + this.ctx.shadowBlur = 0; + } + createConnection(dot1, dot2) { - if (this.connections.length >= this.config.maxConnections) { - return; - } + if (this.connections.length >= this.config.maxConnections) return; - const connection = document.createElement('div'); - connection.className = 'connection-line'; - - // Calculate center positions of dots - const dot1Rect = dot1.element.getBoundingClientRect(); - const dot2Rect = dot2.element.getBoundingClientRect(); - const canvasRect = this.canvas.getBoundingClientRect(); - const dot1CenterX = dot1Rect.left - canvasRect.left + dot1Rect.width / 2; - const dot1CenterY = dot1Rect.top - canvasRect.top + dot1Rect.height / 2; - const dot2CenterX = dot2Rect.left - canvasRect.left + dot2Rect.width / 2; - const dot2CenterY = dot2Rect.top - canvasRect.top + dot2Rect.height / 2; + dot1.connectionCount++; + dot2.connectionCount++; - const dx = dot2CenterX - dot1CenterX; - const dy = dot2CenterY - dot1CenterY; - const distance = Math.sqrt(dx * dx + dy * dy); - const angle = Math.atan2(dy, dx) * (180 / Math.PI); - - // Position and style the connection line from center to center - const lineHalf = 1; - connection.style.left = Math.round(dot1CenterX) + 'px'; - connection.style.top = Math.round(dot1CenterY - lineHalf) + 'px'; - connection.style.width = Math.round(distance) + 'px'; - connection.style.transformOrigin = '0 50%'; - connection.style.transform = `rotate(${angle}deg)`; - connection.style.background = `linear-gradient(90deg, - ${this.config.colors.connection.start} 0%, - ${this.config.colors.connection.middle} 50%, - ${this.config.colors.connection.end} 100%)`; - - this.canvas.appendChild(connection); - - // Fade in - setTimeout(() => { - connection.classList.add('active'); - }, 50); - - const connectionData = { - element: connection, + this.connections.push({ dot1: dot1, dot2: dot2, startTime: Date.now(), duration: Math.random() * (this.config.connectionDuration.max - this.config.connectionDuration.min) + this.config.connectionDuration.min - }; - - // Mark dots as connected - dot1.connectionCount++; - dot2.connectionCount++; - - this.connections.push(connectionData); - } - - updateConnections() { - this.connections.forEach((connection, index) => { - const elapsed = Date.now() - connection.startTime; - - // Update connection position as dots move (using center positions) - const dot1Rect = connection.dot1.element.getBoundingClientRect(); - const dot2Rect = connection.dot2.element.getBoundingClientRect(); - const canvasRect = this.canvas.getBoundingClientRect(); - const dot1CenterX = dot1Rect.left - canvasRect.left + dot1Rect.width / 2; - const dot1CenterY = dot1Rect.top - canvasRect.top + dot1Rect.height / 2; - const dot2CenterX = dot2Rect.left - canvasRect.left + dot2Rect.width / 2; - const dot2CenterY = dot2Rect.top - canvasRect.top + dot2Rect.height / 2; - - const dx = dot2CenterX - dot1CenterX; - const dy = dot2CenterY - dot1CenterY; - const distance = Math.sqrt(dx * dx + dy * dy); - const angle = Math.atan2(dy, dx) * (180 / Math.PI); - - const lineHalf = 1; - connection.element.style.left = Math.round(dot1CenterX) + 'px'; - connection.element.style.top = Math.round(dot1CenterY - lineHalf) + 'px'; - connection.element.style.width = Math.round(distance) + 'px'; - connection.element.style.transformOrigin = '0 50%'; - connection.element.style.transform = `rotate(${angle}deg)`; - - // Remove expired connections - if (elapsed > connection.duration) { - connection.element.classList.remove('active'); - - // Mark dots as no longer connected - connection.dot1.connectionCount--; - connection.dot2.connectionCount--; - - setTimeout(() => { - connection.element.remove(); - }, 500); // Wait for fade out - this.connections.splice(index, 1); - } }); } + updateConnections() { + this.connections = this.connections.filter(conn => { + const elapsed = Date.now() - conn.startTime; + if (elapsed > conn.duration) { + conn.dot1.connectionCount--; + conn.dot2.connectionCount--; + return false; + } + return true; + }); + } + + drawConnections() { + this.connections.forEach(conn => { + const { dot1, dot2, startTime, duration } = conn; + const elapsed = Date.now() - startTime; + const opacity = Math.min(1, elapsed / 500); // Fade in + + const gradient = this.ctx.createLinearGradient(dot1.x, dot1.y, dot2.x, dot2.y); + gradient.addColorStop(0, this.config.colors.connection.start); + gradient.addColorStop(0.5, this.config.colors.connection.middle); + gradient.addColorStop(1, this.config.colors.connection.end); + + this.ctx.beginPath(); + this.ctx.moveTo(dot1.x, dot1.y); + this.ctx.lineTo(dot2.x, dot2.y); + + this.ctx.strokeStyle = gradient; + this.ctx.lineWidth = 2; + this.ctx.globalAlpha = opacity; + + // Pulsing effect + const pulse = (Math.sin((elapsed / 2000) * Math.PI * 2) + 1) / 2; // 2-second pulse cycle + this.ctx.shadowBlur = 4 + pulse * 6; + this.ctx.shadowColor = 'rgba(138, 43, 226, 0.4)'; + + this.ctx.stroke(); + }); + this.ctx.globalAlpha = 1; + this.ctx.shadowBlur = 0; + } + tryCreateConnections() { - // Randomly try to create connections between nearby dots for (let i = 0; i < this.dots.length; i++) { for (let j = i + 1; j < this.dots.length; j++) { if (Math.random() < this.config.connectionChance) { const dot1 = this.dots[i]; const dot2 = this.dots[j]; - - // Calculate distance between dot centers - const dot1CenterX = dot1.x + dot1.size / 2; - const dot1CenterY = dot1.y + dot1.size / 2; - const dot2CenterX = dot2.x + dot2.size / 2; - const dot2CenterY = dot2.y + dot2.size / 2; - - const dx = dot2CenterX - dot1CenterX; - const dy = dot2CenterY - dot1CenterY; + + const dx = dot2.x - dot1.x; + const dy = dot2.y - dot1.y; const distance = Math.sqrt(dx * dx + dy * dy); - + if (distance < 150 && distance > 30) { - // Check if these dots are already connected - const alreadyConnected = this.connections.some(conn => + const alreadyConnected = this.connections.some(conn => (conn.dot1 === dot1 && conn.dot2 === dot2) || (conn.dot1 === dot2 && conn.dot2 === dot1) ); - if (!alreadyConnected) { this.createConnection(dot1, dot2); } @@ -300,15 +206,19 @@ class MatrixBackground { } animate() { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.updateDots(); this.updateConnections(); this.tryCreateConnections(); - + + this.drawConnections(); + this.drawDots(); + requestAnimationFrame(() => this.animate()); } } -// Initialize the matrix background when the DOM is loaded document.addEventListener('DOMContentLoaded', () => { new MatrixBackground(); -}); +}); \ No newline at end of file