From cb6508a385fb8f4dbaccba1cf03ccb6eed8317f5 Mon Sep 17 00:00:00 2001 From: zejzejzej3 Date: Thu, 17 Jul 2025 23:44:26 -0400 Subject: [PATCH 1/2] feat: Update Styling and Add Responsiveness - Updated particle colors and handle scrolling events - Balanced and softened light theme --- src/controllers/galaxy_controller.js | 76 ++++++++++++++++++++++------ src/layouts/main.astro | 4 +- src/pages/index.astro | 16 +++--- src/styles/global.css | 8 ++- 4 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/controllers/galaxy_controller.js b/src/controllers/galaxy_controller.js index 5c4c612..9bcf932 100644 --- a/src/controllers/galaxy_controller.js +++ b/src/controllers/galaxy_controller.js @@ -12,6 +12,12 @@ export default class extends Controller { this.handleResize = this.handleResize.bind(this) window.addEventListener('resize', this.handleResize) + // Handle scroll events for performance + this.isScrolling = false + this.scrollTimeout = null + this.handleScroll = this.handleScroll.bind(this) + window.addEventListener('scroll', this.handleScroll, { passive: true }) + // Handle theme changes this.handleThemeChange = this.handleThemeChange.bind(this) const observer = new MutationObserver(this.handleThemeChange) @@ -27,6 +33,10 @@ export default class extends Controller { cancelAnimationFrame(this.animationId) } window.removeEventListener('resize', this.handleResize) + window.removeEventListener('scroll', this.handleScroll) + if (this.scrollTimeout) { + clearTimeout(this.scrollTimeout) + } if (this.themeObserver) { this.themeObserver.disconnect() } @@ -62,12 +72,19 @@ export default class extends Controller { resizeCanvas() { if (!this.canvas) return - this.canvas.width = window.innerWidth - this.canvas.height = window.innerHeight + // Use element's client dimensions for better mobile viewport handling + const container = this.canvas.parentElement + this.canvas.width = container.clientWidth || window.innerWidth + this.canvas.height = container.clientHeight || window.innerHeight } createParticles() { - const particleCount = Math.floor((this.canvas.width * this.canvas.height) / 8000) + // Reduce particle count on mobile devices for better performance + const isMobile = window.innerWidth <= 768 + const baseArea = this.canvas.width * this.canvas.height + const divisor = isMobile ? 12000 : 8000 + const particleCount = Math.floor(baseArea / divisor) + this.particles = [] for (let i = 0; i < particleCount; i++) { @@ -79,7 +96,7 @@ export default class extends Controller { const isDark = document.documentElement.classList.contains('dark') const colors = isDark ? ['#ffffff', '#f8fafc', '#e2e8f0', '#cbd5e1', '#fbbf24', '#fde047'] - : ['#1e293b', '#334155', '#475569', '#64748b', '#0f172a', '#1e40af'] + : ['#7c3aed', '#ec4899', '#f59e0b', '#ef4444', '#8b5cf6', '#d946ef'] // Random distribution across the sky const x = Math.random() * this.canvas.width @@ -99,17 +116,17 @@ export default class extends Controller { if (starType < 0.1) { // Bright stars (10%) baseRadius = brightness * 2.5 + 1.5 - baseOpacity = isDark ? 0.9 : 0.8 + baseOpacity = isDark ? 0.9 : 1.0 twinkleSpeed = 0.03 } else if (starType < 0.3) { // Medium stars (20%) baseRadius = brightness * 1.5 + 0.8 - baseOpacity = isDark ? 0.7 : 0.6 + baseOpacity = isDark ? 0.7 : 1.0 twinkleSpeed = 0.02 } else { // Dim stars (70%) baseRadius = brightness * 0.8 + 0.3 - baseOpacity = isDark ? 0.4 : 0.3 + baseOpacity = isDark ? 0.4 : 0.9 twinkleSpeed = 0.015 } @@ -121,8 +138,8 @@ export default class extends Controller { radius: baseRadius, baseRadius: baseRadius, color: colors[Math.floor(Math.random() * colors.length)], - opacity: baseOpacity * (0.7 + Math.random() * 0.3), - baseOpacity: baseOpacity * (0.7 + Math.random() * 0.3), + opacity: isDark ? baseOpacity * (0.7 + Math.random() * 0.3) : 1.0, + baseOpacity: isDark ? baseOpacity * (0.7 + Math.random() * 0.3) : 1.0, twinkleSpeed: twinkleSpeed + (Math.random() - 0.5) * 0.01, twinklePhase: Math.random() * Math.PI * 2, brightness: brightness, @@ -142,7 +159,7 @@ export default class extends Controller { updateParticles() { this.time += 0.01 - this.particles.forEach((particle, index) => { + this.particles.forEach((particle) => { // Gentle drifting motion particle.x += particle.vx particle.y += particle.vy @@ -154,7 +171,8 @@ export default class extends Controller { // Twinkling effect particle.twinklePhase += particle.twinkleSpeed const twinkleFactor = Math.sin(particle.twinklePhase) * 0.3 + 0.7 - particle.currentOpacity = particle.baseOpacity * twinkleFactor + const isDark = document.documentElement.classList.contains('dark') + particle.currentOpacity = isDark ? particle.baseOpacity * twinkleFactor : 1.0 // Size twinkling for brighter stars if (particle.starType < 0.1) { @@ -193,14 +211,21 @@ export default class extends Controller { this.ctx.save() // Create glow effect for bright stars + const isDark = document.documentElement.classList.contains('dark') if (particle.starType < 0.1) { this.ctx.shadowColor = particle.color - this.ctx.shadowBlur = particle.radius * 4 + this.ctx.shadowBlur = isDark ? particle.radius * 4 : particle.radius * 6 this.ctx.shadowOffsetX = 0 this.ctx.shadowOffsetY = 0 } else if (particle.starType < 0.3) { this.ctx.shadowColor = particle.color - this.ctx.shadowBlur = particle.radius * 2 + this.ctx.shadowBlur = isDark ? particle.radius * 2 : particle.radius * 4 + this.ctx.shadowOffsetX = 0 + this.ctx.shadowOffsetY = 0 + } else if (!isDark) { + // Add glow to all particles in light mode for visibility + this.ctx.shadowColor = particle.color + this.ctx.shadowBlur = particle.radius * 3 this.ctx.shadowOffsetX = 0 this.ctx.shadowOffsetY = 0 } @@ -276,6 +301,12 @@ export default class extends Controller { } animate() { + // Skip animation during scroll for better performance + if (this.isScrolling) { + this.animationId = requestAnimationFrame(() => this.animate()) + return + } + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) this.updateParticles() @@ -290,10 +321,11 @@ export default class extends Controller { const isDark = document.documentElement.classList.contains('dark') const colors = isDark ? ['#ffffff', '#a855f7', '#ec4899', '#3b82f6', '#10b981'] - : ['#1f2937', '#7c3aed', '#be185d', '#1d4ed8', '#047857'] + : ['#7c3aed', '#ec4899', '#f59e0b', '#ef4444', '#8b5cf6'] particle.color = colors[Math.floor(Math.random() * colors.length)] - particle.opacity = isDark ? Math.random() * 0.8 + 0.2 : Math.random() * 0.9 + 0.4 + particle.opacity = isDark ? Math.random() * 0.8 + 0.2 : 1.0 + particle.baseOpacity = isDark ? Math.random() * 0.8 + 0.2 : 1.0 }) } @@ -302,6 +334,20 @@ export default class extends Controller { this.createParticles() } + handleScroll() { + this.isScrolling = true + + // Clear previous timeout + if (this.scrollTimeout) { + clearTimeout(this.scrollTimeout) + } + + // Resume animation after scroll ends + this.scrollTimeout = setTimeout(() => { + this.isScrolling = false + }, 150) + } + handleThemeChange() { // Update particle colors when theme changes this.updateParticleColors() diff --git a/src/layouts/main.astro b/src/layouts/main.astro index fcc5b8b..6b2245a 100644 --- a/src/layouts/main.astro +++ b/src/layouts/main.astro @@ -32,7 +32,7 @@ const navLinks = [ --- - + @@ -44,7 +44,7 @@ const navLinks = [ - + {showNavbar && }
diff --git a/src/pages/index.astro b/src/pages/index.astro index 4aaf59e..d672b8f 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -33,7 +33,7 @@ Lux # For Neovim`;
@@ -42,7 +42,7 @@ Lux # For Neovim`;
@@ -79,7 +79,7 @@ Lux # For Neovim`;
@@ -226,7 +226,7 @@ Lux # For Neovim`;
Vim or Neovim (recent versions)
  • diff --git a/src/styles/global.css b/src/styles/global.css index ed695d7..76148a5 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -5,8 +5,10 @@ /* Galaxy background styles */ #galaxy-background, #galaxy-background-cta { - background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 25%, #a5b4fc 50%, #8b5cf6 75%, #7c3aed 100%); + background: linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 15%, #d8b4fe 35%, #c084fc 55%, #a855f7 75%, #7c3aed 100%); transition: background 0.3s ease; + will-change: scroll-position; + contain: layout style paint; } .dark #galaxy-background, .dark #galaxy-background-cta { @@ -14,11 +16,13 @@ } /* Canvas styling */ -#galaxy-canvas { +#galaxy-canvas, #galaxy-canvas-cta { display: block; width: 100%; height: 100%; cursor: crosshair; + will-change: transform; + transform: translateZ(0); } /* Smooth transitions for theme changes */ From b957a59f419af19da71b322c79dedcff0508c929 Mon Sep 17 00:00:00 2001 From: zejzejzej3 Date: Tue, 5 Aug 2025 20:54:38 -0400 Subject: [PATCH 2/2] fix: improve mobile responsiveness for galaxy canvas - Fix canvas sizing on mobile to prevent horizontal white bars - Add device pixel ratio scaling for crisp rendering on high-DPI displays - Improve particle animation during scroll by reducing update frequency instead of pausing - Add mobile-specific CSS to prevent viewport overflow - Reduce hero padding on small screens for better mobile layout --- src/controllers/galaxy_controller.js | 49 ++++++++++++++++++++-------- src/pages/index.astro | 2 +- src/styles/global.css | 19 +++++++++++ 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/controllers/galaxy_controller.js b/src/controllers/galaxy_controller.js index 9bcf932..02f08d6 100644 --- a/src/controllers/galaxy_controller.js +++ b/src/controllers/galaxy_controller.js @@ -72,10 +72,25 @@ export default class extends Controller { resizeCanvas() { if (!this.canvas) return - // Use element's client dimensions for better mobile viewport handling + // Use container dimensions but ensure they don't exceed viewport const container = this.canvas.parentElement - this.canvas.width = container.clientWidth || window.innerWidth - this.canvas.height = container.clientHeight || window.innerHeight + const containerWidth = container.clientWidth + const containerHeight = container.clientHeight + + // On mobile, ensure canvas doesn't exceed viewport width + const isMobile = window.innerWidth <= 768 + const width = isMobile ? Math.min(containerWidth, window.innerWidth) : containerWidth + const height = containerHeight + + // Set canvas size with device pixel ratio for crisp rendering + const dpr = window.devicePixelRatio || 1 + this.canvas.width = width * dpr + this.canvas.height = height * dpr + this.ctx.scale(dpr, dpr) + + // Set CSS size to maintain proper display + this.canvas.style.width = width + 'px' + this.canvas.style.height = height + 'px' } createParticles() { @@ -301,17 +316,19 @@ export default class extends Controller { } animate() { - // Skip animation during scroll for better performance - if (this.isScrolling) { - this.animationId = requestAnimationFrame(() => this.animate()) - return - } - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) - this.updateParticles() + // Reduce update frequency during scroll for better performance + const shouldUpdate = !this.isScrolling || (performance.now() - (this.lastScrollUpdate || 0)) > 100 + + if (shouldUpdate) { + this.updateParticles() + if (this.isScrolling) { + this.lastScrollUpdate = performance.now() + } + } + this.drawParticles() - this.animationId = requestAnimationFrame(() => this.animate()) } @@ -335,17 +352,21 @@ export default class extends Controller { } handleScroll() { - this.isScrolling = true + // Don't pause animation completely - instead reduce update frequency + if (!this.isScrolling) { + this.isScrolling = true + this.scrollStartTime = performance.now() + } // Clear previous timeout if (this.scrollTimeout) { clearTimeout(this.scrollTimeout) } - // Resume animation after scroll ends + // Resume normal animation after scroll ends this.scrollTimeout = setTimeout(() => { this.isScrolling = false - }, 150) + }, 100) } handleThemeChange() { diff --git a/src/pages/index.astro b/src/pages/index.astro index d672b8f..bda8439 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -38,7 +38,7 @@ Lux # For Neovim`;
    -
    +