diff --git a/UI/Web/src/app/_services/gradient-animation.service.ts b/UI/Web/src/app/_services/gradient-animation.service.ts index 850b331f9..4c842482c 100644 --- a/UI/Web/src/app/_services/gradient-animation.service.ts +++ b/UI/Web/src/app/_services/gradient-animation.service.ts @@ -29,7 +29,7 @@ export class GradientAnimationService { constructor(private cssVariableService: CssVariableService) {} - startAnimation(canvas: HTMLCanvasElement, isReducedMotion: boolean = false): void { + startAnimation(canvas: HTMLCanvasElement, isReducedMotion: boolean = false, isStaticMode: boolean = false): void { if (!canvas) return; // Stop any existing animation @@ -48,12 +48,23 @@ export class GradientAnimationService { this.canvasHeight = window.innerHeight; canvas.width = this.canvasWidth; canvas.height = this.canvasHeight; + + // If static mode, render once and stop + if (isStaticMode) { + this.renderStaticGradients(ctx); + return; + } }; this.resizeHandler = resizeCanvas; resizeCanvas(); window.addEventListener('resize', this.resizeHandler, { passive: true }); + // If static mode requested, don't start animation loop + if (isStaticMode) { + return; + } + // Handle window focus/blur this.blurHandler = () => { this.isWindowFocused = false; }; this.focusHandler = () => { this.isWindowFocused = true; }; @@ -69,9 +80,9 @@ export class GradientAnimationService { const gradientColor3 = this.cssVariableService.getVariableAsRgb('--gradient-color-3') || { r: 255, g: 215, b: 0 }; const gradientColor4 = this.cssVariableService.getVariableAsRgb('--gradient-color-4') || { r: 255, g: 20, b: 147 }; - // Slightly faster but still very subtle movement - const baseSpeed = isReducedMotion ? 0.00015 : 0.001; // Slightly increased from ultra-slow - const speedVariation = 0.0001; // Small increase in variation + // Respect accessibility preferences - much slower or static for reduced motion + const baseSpeed = isReducedMotion ? 0.00001 : 0.0003; // Nearly static for reduced motion + const speedVariation = isReducedMotion ? 0.000005 : 0.0001; // Minimal variation for reduced motion const gradientPoints: GradientPoint[] = [ { @@ -80,7 +91,7 @@ export class GradientAnimationService { vx: baseSpeed + speedVariation * 0.5, vy: (baseSpeed + speedVariation) * 1.2, color: gradientColor1, - size: 1 // Reduced but still large + size: 1.4 // Reduced but still large }, { x: 0.95, // Moved closer to edge @@ -88,7 +99,7 @@ export class GradientAnimationService { vx: -(baseSpeed + speedVariation * 0.8), vy: baseSpeed + speedVariation * 0.6, color: gradientColor2, - size: 1.2 // Reduced but still large + size: 1.5 // Reduced but still large }, { x: 0.5, // Center position @@ -183,7 +194,7 @@ export class GradientAnimationService { this.animationId = requestAnimationFrame(animate); } catch (error) { - console.error('Animation error:', error); + // Silently handle animation errors and stop animation this.stopAnimation(); } }; @@ -192,6 +203,59 @@ export class GradientAnimationService { this.animationId = requestAnimationFrame(animate); } + private renderStaticGradients(ctx: CanvasRenderingContext2D): void { + // Get colors from CSS variables with fallbacks + const gradientColor1 = this.cssVariableService.getVariableAsRgb('--gradient-color-1') || { r: 73, g: 197, b: 147 }; + const gradientColor2 = this.cssVariableService.getVariableAsRgb('--gradient-color-2') || { r: 138, g: 43, b: 226 }; + const gradientColor3 = this.cssVariableService.getVariableAsRgb('--gradient-color-3') || { r: 255, g: 215, b: 0 }; + const gradientColor4 = this.cssVariableService.getVariableAsRgb('--gradient-color-4') || { r: 255, g: 20, b: 147 }; + + // Static gradient positions (no animation) + const staticGradientPoints = [ + { x: 0.2, y: 0.2, color: gradientColor1, size: 1.4 }, + { x: 0.8, y: 0.3, color: gradientColor2, size: 1.5 }, + { x: 0.5, y: 0.8, color: gradientColor3, size: 1.3 }, + { x: 0.3, y: 0.6, color: gradientColor4, size: 1.4 }, + { x: 0.7, y: 0.7, color: gradientColor1, size: 1.2 } + ]; + + // Pre-calculate background color + const backgroundColor = this.cssVariableService.getVariable('--elevation-layer2-dark-solid') || '#1f2020'; + + // Clear canvas with background color + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); + + // Set blend mode for smoother gradients + ctx.globalCompositeOperation = 'screen'; + + // Render static gradients + staticGradientPoints.forEach(point => { + const pointX = point.x * this.canvasWidth; + const pointY = point.y * this.canvasHeight; + const radius = Math.min(this.canvasWidth, this.canvasHeight) * 0.9 * point.size; + + const gradient = ctx.createRadialGradient( + pointX, pointY, 0, + pointX, pointY, radius + ); + + const { r, g, b } = point.color; + gradient.addColorStop(0, `rgba(${r}, ${g}, ${b}, 0.25)`); + gradient.addColorStop(0.15, `rgba(${r}, ${g}, ${b}, 0.18)`); + gradient.addColorStop(0.35, `rgba(${r}, ${g}, ${b}, 0.12)`); + gradient.addColorStop(0.6, `rgba(${r}, ${g}, ${b}, 0.06)`); + gradient.addColorStop(0.8, `rgba(${r}, ${g}, ${b}, 0.03)`); + gradient.addColorStop(1, `rgba(${r}, ${g}, ${b}, 0)`); + + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); + }); + + // Reset composite operation + ctx.globalCompositeOperation = 'source-over'; + } + stopAnimation(): void { if (this.animationId !== undefined) { cancelAnimationFrame(this.animationId); diff --git a/UI/Web/src/app/registration/_components/splash-container/splash-container.component.ts b/UI/Web/src/app/registration/_components/splash-container/splash-container.component.ts index 97dce367c..d03a9f63e 100644 --- a/UI/Web/src/app/registration/_components/splash-container/splash-container.component.ts +++ b/UI/Web/src/app/registration/_components/splash-container/splash-container.component.ts @@ -33,7 +33,6 @@ export class SplashContainerComponent implements OnInit, OnDestroy, AfterViewIni tiltElement!: ElementRef; ngOnInit() { - // Initialize CSS variables with default values this.initializeCssVariables(); } @@ -53,12 +52,10 @@ export class SplashContainerComponent implements OnInit, OnDestroy, AfterViewIni '--shadow-intensity': '0.5' }; - // Batch set all variables at once to minimize DOM operations this.cssVariableService.setVariablesBatch(defaultVariables); } ngAfterViewInit() { - // Use requestAnimationFrame for better performance and Zone.js integration requestAnimationFrame(() => { this.initializeAnimations(); }); @@ -71,32 +68,26 @@ export class SplashContainerComponent implements OnInit, OnDestroy, AfterViewIni private initializeAnimations(): void { try { - console.log('Initializing animations...'); - console.log('Canvas element:', this.gradientCanvas?.nativeElement); - console.log('Tilt element:', this.tiltElement?.nativeElement); - const isReducedMotion = this.tiltService.shouldReduceMotion(); - console.log('Reduced motion detected:', isReducedMotion); + + // For maximum accessibility, offer completely static gradients for reduced motion + // You can change this to `false` if you want very slow animation instead + const useStaticGradients = isReducedMotion; - // Always initialize gradient animation (but slower for reduced motion) + // Initialize gradient animation if (this.gradientCanvas?.nativeElement) { - console.log('Starting gradient animation'); - this.gradientService.startAnimation(this.gradientCanvas.nativeElement, isReducedMotion); - } else { - console.warn('Gradient canvas element not found'); + this.gradientService.startAnimation( + this.gradientCanvas.nativeElement, + isReducedMotion, + useStaticGradients + ); } - // Only initialize tilt tracking if reduced motion is not enabled + // Initialize tilt tracking only if reduced motion is not enabled if (!isReducedMotion && this.tiltElement?.nativeElement) { - console.log('Starting tilt tracking'); this.tiltService.initializeMouseTracking(this.tiltElement.nativeElement); - } else if (isReducedMotion) { - console.log('Skipping tilt tracking due to reduced motion preference'); - } else { - console.warn('Tilt element not found'); } } catch (error) { - console.error('Error initializing animations:', error); // Clean up any partially initialized services this.cleanupServices(); // Fallback: try to initialize with a delay @@ -111,26 +102,23 @@ export class SplashContainerComponent implements OnInit, OnDestroy, AfterViewIni this.gradientService.stopAnimation(); this.tiltService.cleanup(); } catch (error) { - console.error('Error during service cleanup:', error); + // Silent cleanup - errors here are not critical } } private initializeAnimationsFallback(): void { - console.log('Trying fallback initialization...'); - const isReducedMotion = this.tiltService.shouldReduceMotion(); + const useStaticGradients = isReducedMotion; // Try to find elements by ID as fallback const canvas = document.getElementById('gradient-canvas') as HTMLCanvasElement; const tiltElement = document.querySelector('.tilt') as HTMLElement; if (canvas && !this.gradientService.isAnimating()) { - console.log('Fallback: Starting gradient animation'); - this.gradientService.startAnimation(canvas, isReducedMotion); + this.gradientService.startAnimation(canvas, isReducedMotion, useStaticGradients); } if (tiltElement && !isReducedMotion) { - console.log('Fallback: Starting tilt tracking'); this.tiltService.initializeMouseTracking(tiltElement); } }