new page :3
All checks were successful
Homepage Build and Deploy / Build Homepage Image (push) Successful in 26s
Homepage Build and Deploy / Deploy Homepage (push) Successful in 4s

This commit is contained in:
2026-07-10 10:49:11 -03:00
parent df8932fc01
commit 367ecfa876
14 changed files with 1231 additions and 582 deletions

View File

@@ -4,6 +4,11 @@ class MatrixBackground {
this.ctx = this.canvas.getContext('2d');
this.dots = [];
this.connections = [];
this.mouse = { x: -9999, y: -9999, active: false };
this.rafId = null;
this.isRunning = true;
this.prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
this.config = {
dotCount: this.getMobileDotCount(),
dotSpeed: 0.2,
@@ -11,15 +16,18 @@ class MatrixBackground {
connectionChance: 0.0002,
maxConnections: this.getMobileMaxConnections(),
dotSize: 3,
mouseRadius: 110,
mouseForce: 0.6,
// Palette synced to the UI accent tokens
colors: {
dotDefault: 'rgba(255, 255, 255, 0.8)',
dotDefaultGlow: 'rgba(255, 255, 255, 0.4)',
dotConnected: 'rgba(100, 149, 237, 0.8)',
dotConnectedGlow: 'rgba(100, 149, 237, 0.6)',
dotDefault: 'rgba(230, 240, 255, 0.78)',
dotDefaultGlow: 'rgba(180, 220, 255, 0.40)',
dotConnected: 'rgba(120, 190, 245, 0.85)',
dotConnectedGlow: 'rgba(79, 195, 247, 0.55)',
connection: {
start: 'rgba(100, 149, 237, 0.2)',
middle: 'rgba(138, 43, 226, 0.6)',
end: 'rgba(100, 149, 237, 0.2)'
start: 'rgba(102, 126, 234, 0.22)',
middle: 'rgba(118, 75, 162, 0.62)',
end: 'rgba(79, 195, 247, 0.22)'
}
}
};
@@ -28,14 +36,13 @@ class MatrixBackground {
}
getMobileDotCount() {
// Reduce dot count on mobile devices for better performance
if (window.innerWidth <= 480) return 25;
if (window.innerWidth <= 768) return 35;
if (window.innerWidth <= 480) return 35;
if (window.innerWidth <= 768) return 45;
if (window.innerWidth >= 2100) return 100;
return 50;
}
getMobileMaxConnections() {
// Reduce max connections on mobile devices for better performance
if (window.innerWidth <= 480) return 4;
if (window.innerWidth <= 768) return 6;
return 8;
@@ -43,20 +50,61 @@ class MatrixBackground {
init() {
this.handleResize();
this.bindEvents();
this.animate();
}
// Prevent resizing for mobile performance reasons
// window.addEventListener('resize', () => this.handleResize());
bindEvents() {
// Pointer reactivity — push dots away from cursor for a "matrix repel" feel.
// Touch devices are included; the dot pushes happen only while touched.
window.addEventListener('pointermove', (e) => {
this.mouse.x = e.clientX;
this.mouse.y = e.clientY;
this.mouse.active = true;
}, { passive: true });
window.addEventListener('pointerout', () => {
this.mouse.active = false;
this.mouse.x = -9999;
this.mouse.y = -9999;
});
// Pause the rAF loop when the tab is hidden to save CPU / battery.
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.stop();
} else {
this.start();
}
});
// Resize is debounced via rAF; disabled on mobile for perf parity with original.
if (window.innerWidth > 768) {
let resizeRaf = null;
window.addEventListener('resize', () => {
if (resizeRaf) cancelAnimationFrame(resizeRaf);
resizeRaf = requestAnimationFrame(() => this.handleResize());
});
}
}
start() {
if (this.rafId || !this.isRunning) return;
this.animate();
}
stop() {
if (this.rafId) {
cancelAnimationFrame(this.rafId);
this.rafId = null;
}
}
handleResize() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
// Update mobile-specific configurations
this.config.dotCount = this.getMobileDotCount();
this.config.maxConnections = this.getMobileMaxConnections();
this.createDots();
}
@@ -71,51 +119,54 @@ class MatrixBackground {
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);
velocityX = Math.cos(angle) * speed;
velocityY = Math.sin(angle) * speed;
attempts++;
}
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 angle = Math.random() * Math.PI * 2;
const speed = this.config.dotSpeed * (0.8 + Math.random() * 0.4);
const baseVelocityX = Math.cos(angle) * speed;
const baseVelocityY = Math.sin(angle) * speed;
this.dots.push({
x: startX,
y: startY,
vx: velocityX,
vy: velocityY,
vx: baseVelocityX,
vy: baseVelocityY,
baseVx: baseVelocityX,
baseVy: baseVelocityY,
wanderPhase: Math.random() * Math.PI * 2,
wanderSpeed: 0.01 + Math.random() * 0.01,
opacity: Math.random() * 0.3 + 0.7,
size: this.config.dotSize + Math.random() * 2,
connectionCount: 0,
stuckFrames: 0
connectionCount: 0
});
}
updateDots() {
const radius = this.config.mouseRadius;
const radiusSq = radius * radius;
const force = this.config.mouseForce;
this.dots.forEach(dot => {
// Mouse repulsion
if (this.mouse.active) {
const dx = dot.x - this.mouse.x;
const dy = dot.y - this.mouse.y;
const distSq = dx * dx + dy * dy;
if (distSq < radiusSq && distSq > 0.5) {
const dist = Math.sqrt(distSq);
const strength = (1 - dist / radius) * force;
dot.vx += (dx / dist) * strength;
dot.vy += (dy / dist) * strength;
}
}
dot.x += dot.vx;
dot.y += dot.vy;
if (Math.abs(dot.vx) < 0.03 && Math.abs(dot.vy) < 0.03) {
dot.stuckFrames++;
} else {
dot.stuckFrames = 0;
}
if (dot.stuckFrames > 30) {
const angle = Math.random() * Math.PI * 2;
const speed = this.config.dotSpeed * (0.8 + Math.random() * 0.4);
dot.vx = Math.cos(angle) * speed;
dot.vy = Math.sin(angle) * speed;
dot.stuckFrames = 0;
} else {
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;
}
// Ease back to a gentle autonomous drift after pointer interaction.
dot.wanderPhase += dot.wanderSpeed;
const wanderX = Math.cos(dot.wanderPhase) * 0.03;
const wanderY = Math.sin(dot.wanderPhase * 0.8) * 0.03;
dot.vx += (dot.baseVx + wanderX - dot.vx) * 0.02;
dot.vy += (dot.baseVy + wanderY - dot.vy) * 0.02;
const maxX = this.canvas.width - dot.size;
const maxY = this.canvas.height - dot.size;
@@ -175,7 +226,7 @@ class MatrixBackground {
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 opacity = Math.min(1, elapsed / 500);
const gradient = this.ctx.createLinearGradient(dot1.x, dot1.y, dot2.x, dot2.y);
gradient.addColorStop(0, this.config.colors.connection.start);
@@ -185,15 +236,14 @@ class MatrixBackground {
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
const pulse = (Math.sin((elapsed / 2000) * Math.PI * 2) + 1) / 2;
this.ctx.shadowBlur = 4 + pulse * 6;
this.ctx.shadowColor = 'rgba(138, 43, 226, 0.4)';
this.ctx.shadowColor = 'rgba(118, 75, 162, 0.5)';
this.ctx.stroke();
});
@@ -229,17 +279,19 @@ class MatrixBackground {
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.updateDots();
this.updateConnections();
this.tryCreateConnections();
if (!this.prefersReducedMotion) {
this.updateDots();
this.updateConnections();
this.tryCreateConnections();
}
this.drawConnections();
this.drawDots();
requestAnimationFrame(() => this.animate());
this.rafId = requestAnimationFrame(() => this.animate());
}
}
document.addEventListener('DOMContentLoaded', () => {
new MatrixBackground();
});
});