Static gradients, no tilt or shine when reduce motion

This commit is contained in:
Robbie Davis 2025-08-02 14:45:27 -04:00
parent 438fbcc603
commit ffb5f1dc1a
2 changed files with 85 additions and 33 deletions

View File

@ -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);

View File

@ -33,7 +33,6 @@ export class SplashContainerComponent implements OnInit, OnDestroy, AfterViewIni
tiltElement!: ElementRef<HTMLElement>;
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);
}
}