@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Orbitron', monospace;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 50%, #16213e 100%);
min-height: 100vh;
overflow-x: hidden;
position: relative;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.1) 0%, transparent 50%);
pointer-events: none;
z-index: -1;
}
.particle-menu {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000;
background: rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.particle-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
}
.menu-container {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 40px;
max-width: 1200px;
margin: 0 auto;
z-index: 2;
}
.brand-logo {
position: relative;
display: flex;
align-items: center;
cursor: pointer;
}
.brand-text {
font-size: 1.8rem;
font-weight: 900;
color: #ffffff;
text-shadow:
0 0 10px rgba(120, 219, 255, 0.5),
0 0 20px rgba(120, 219, 255, 0.3),
0 0 30px rgba(120, 219, 255, 0.2);
letter-spacing: 3px;
position: relative;
z-index: 3;
}
.logo-particles {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 40px;
pointer-events: none;
}
.logo-glow {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 120px;
height: 60px;
background: radial-gradient(ellipse, rgba(120, 219, 255, 0.2) 0%, transparent 70%);
border-radius: 50%;
animation: logo-pulse 3s ease-in-out infinite;
}
.menu-items {
display: flex;
list-style: none;
gap: 30px;
margin: 0;
padding: 0;
}
.menu-item {
position: relative;
}
.menu-link {
position: relative;
display: block;
color: #ffffff;
text-decoration: none;
font-weight: 500;
font-size: 1rem;
padding: 12px 20px;
border-radius: 8px;
transition: all 0.3s ease;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);
}
.link-text {
position: relative;
z-index: 3;
transition: all 0.3s ease;
}
.link-particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
}
.particle-trail {
position: absolute;
top: 50%;
left: 0;
width: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #78dbff, transparent);
transform: translateY(-50%);
transition: width 0.4s ease;
}
.menu-link:hover {
color: #78dbff;
border-color: rgba(120, 219, 255, 0.5);
box-shadow:
0 0 20px rgba(120, 219, 255, 0.3),
inset 0 0 20px rgba(120, 219, 255, 0.1);
transform: translateY(-2px);
}
.menu-link:hover .link-particles {
opacity: 1;
}
.menu-link:hover .particle-trail {
width: 100%;
}
.menu-link:hover .link-text {
text-shadow:
0 0 10px rgba(120, 219, 255, 0.8),
0 0 20px rgba(120, 219, 255, 0.4);
}
.particle-toggle {
position: relative;
}
.toggle-btn {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff;
padding: 10px 20px;
border-radius: 25px;
cursor: pointer;
font-family: 'Orbitron', monospace;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.toggle-particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.toggle-text {
position: relative;
z-index: 2;
}
.toggle-btn:hover {
background: rgba(120, 219, 255, 0.2);
border-color: rgba(120, 219, 255, 0.5);
box-shadow: 0 0 20px rgba(120, 219, 255, 0.3);
transform: scale(1.05);
}
.toggle-btn.active {
background: rgba(120, 219, 255, 0.3);
border-color: #78dbff;
color: #78dbff;
box-shadow:
0 0 30px rgba(120, 219, 255, 0.5),
inset 0 0 20px rgba(120, 219, 255, 0.2);
}
.ambient-particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
}
@keyframes logo-pulse {
0%, 100% {
opacity: 0.3;
transform: translate(-50%, -50%) scale(1);
}
50% {
opacity: 0.6;
transform: translate(-50%, -50%) scale(1.1);
}
}
@keyframes particle-float {
0% {
transform: translateY(0px) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) rotate(360deg);
opacity: 0;
}
}
@keyframes particle-glow {
0%, 100% {
box-shadow: 0 0 5px currentColor;
}
50% {
box-shadow: 0 0 20px currentColor, 0 0 30px currentColor;
}
}
@media (max-width: 768px) {
.menu-container {
flex-direction: column;
gap: 20px;
padding: 20px;
}
.menu-items {
gap: 15px;
flex-wrap: wrap;
justify-content: center;
}
.menu-link {
padding: 10px 15px;
font-size: 0.9rem;
}
.brand-text {
font-size: 1.5rem;
letter-spacing: 2px;
}
}
@media (max-width: 480px) {
.menu-items {
flex-direction: column;
width: 100%;
}
.menu-link {
text-align: center;
width: 100%;
}
.particle-toggle {
width: 100%;
}
.toggle-btn {
width: 100%;
}
}
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');
const menuLinks = document.querySelectorAll('.menu-link');
const toggleBtn = document.getElementById('particleToggle');
const brandLogo = document.querySelector('.brand-logo');
let particles = [];
let animationId;
let particlesEnabled = true;
// Configuración del canvas
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = document.querySelector('.particle-menu').offsetHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Clase Particle
class Particle {
constructor(x, y, color = '#78dbff', size = 2) {
this.x = x;
this.y = y;
this.vx = (Math.random() - 0.5) * 2;
this.vy = (Math.random() - 0.5) * 2;
this.size = size;
this.color = color;
this.life = 1;
this.decay = Math.random() * 0.02 + 0.005;
this.gravity = Math.random() * 0.1 + 0.05;
}
update() {
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.life -= this.decay;
this.size *= 0.99;
}
draw() {
ctx.save();
ctx.globalAlpha = this.life;
ctx.fillStyle = this.color;
ctx.shadowBlur = 10;
ctx.shadowColor = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
isDead() {
return this.life <= 0 || this.size <= 0.1;
}
}
// Esquemas de colores para diferentes elementos del menú
const colorSchemes = {
blue: ['#78dbff', '#4fc3f7', '#29b6f6'],
purple: ['#ba68c8', '#ab47bc', '#9c27b0'],
green: ['#66bb6a', '#4caf50', '#388e3c'],
orange: ['#ff9800', '#f57c00', '#ef6c00'],
red: ['#f44336', '#e53935', '#d32f2f']
};
// Crear partículas
function createParticles(x, y, count = 5, colors = colorSchemes.blue) {
if (!particlesEnabled) return;
for (let i = 0; i < count; i++) {
const color = colors[Math.floor(Math.random() * colors.length)];
const size = Math.random() * 3 + 1;
particles.push(new Particle(x, y, color, size));
}
}
// Crear partículas de rastro
function createTrailParticles(element, colors) {
if (!particlesEnabled) return;
const rect = element.getBoundingClientRect();
const menuRect = document.querySelector('.particle-menu').getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top - menuRect.top + rect.height / 2;
createParticles(x, y, 3, colors);
}
// Bucle de animación
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Actualizar y dibujar partículas
for (let i = particles.length - 1; i >= 0; i--) {
const particle = particles[i];
particle.update();
particle.draw();
if (particle.isDead()) {
particles.splice(i, 1);
}
}
animationId = requestAnimationFrame(animate);
}
// Iniciar animación
animate();
// Interacciones de enlaces del menú
menuLinks.forEach(link => {
const particleType = link.getAttribute('data-particles');
const colors = colorSchemes[particleType] || colorSchemes.blue;
link.addEventListener('mouseenter', function() {
createTrailParticles(this, colors);
// Crear partículas continuas mientras se mantiene el hover
this.particleInterval = setInterval(() => {
createTrailParticles(this, colors);
}, 100);
});
link.addEventListener('mouseleave', function() {
if (this.particleInterval) {
clearInterval(this.particleInterval);
}
});
link.addEventListener('click', function(e) {
e.preventDefault();
// Crear efecto de explosión
const rect = this.getBoundingClientRect();
const menuRect = document.querySelector('.particle-menu').getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top - menuRect.top + rect.height / 2;
createParticles(x, y, 20, colors);
// Agregar efecto de vibración de pantalla
document.body.style.animation = 'shake 0.3s ease-in-out';
setTimeout(() => {
document.body.style.animation = '';
}, 300);
});
});
// Interacción del logo de marca
brandLogo.addEventListener('click', function() {
const rect = this.getBoundingClientRect();
const menuRect = document.querySelector('.particle-menu').getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top - menuRect.top + rect.height / 2;
// Crear explosión arcoíris
const rainbowColors = ['#ff0000', '#ff7f00', '#ffff00', '#00ff00', '#0000ff', '#4b0082', '#9400d3'];
for (let i = 0; i < 30; i++) {
const color = rainbowColors[Math.floor(Math.random() * rainbowColors.length)];
particles.push(new Particle(x, y, color, Math.random() * 4 + 2));
}
});
// Funcionalidad del botón de alternancia
toggleBtn.addEventListener('click', function() {
particlesEnabled = !particlesEnabled;
this.classList.toggle('active');
if (particlesEnabled) {
this.querySelector('.toggle-text').textContent = 'Efectos';
animate();
} else {
this.querySelector('.toggle-text').textContent = 'Deshabilitado';
particles = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (animationId) {
cancelAnimationFrame(animationId);
}
}
});
// Partículas ambientales
function createAmbientParticles() {
if (!particlesEnabled) return;
const x = Math.random() * canvas.width;
const y = canvas.height;
const colors = ['#78dbff', '#ba68c8', '#66bb6a', '#ff9800'];
const color = colors[Math.floor(Math.random() * colors.length)];
particles.push(new Particle(x, y, color, Math.random() * 2 + 0.5));
}
// Crear partículas ambientales periódicamente
setInterval(createAmbientParticles, 500);
// Efecto de rastro del mouse
let mouseTrailTimeout;
document.addEventListener('mousemove', function(e) {
if (!particlesEnabled) return;
const menuRect = document.querySelector('.particle-menu').getBoundingClientRect();
if (e.clientY >= menuRect.top && e.clientY <= menuRect.bottom) {
clearTimeout(mouseTrailTimeout);
mouseTrailTimeout = setTimeout(() => {
const x = e.clientX;
const y = e.clientY - menuRect.top;
if (Math.random() < 0.3) {
particles.push(new Particle(x, y, '#ffffff', 1));
}
}, 50);
}
});
// Agregar CSS para animación de vibración
const style = document.createElement('style');
style.textContent = `
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-2px); }
75% { transform: translateX(2px); }
}
`;
document.head.appendChild(style);
// Optimización de rendimiento
let lastTime = 0;
const targetFPS = 60;
const frameInterval = 1000 / targetFPS;
function optimizedAnimate(currentTime) {
if (currentTime - lastTime >= frameInterval) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Limitar el número de partículas para el rendimiento
if (particles.length > 200) {
particles = particles.slice(-150);
}
// Actualizar y dibujar partículas
for (let i = particles.length - 1; i >= 0; i--) {
const particle = particles[i];
particle.update();
particle.draw();
if (particle.isDead()) {
particles.splice(i, 1);
}
}
lastTime = currentTime;
}
if (particlesEnabled) {
animationId = requestAnimationFrame(optimizedAnimate);
}
}
// Reemplazar la función de animación original con la versión optimizada
if (animationId) {
cancelAnimationFrame(animationId);
}
optimizedAnimate(0);
});