import { Component, ChangeDetectionStrategy, input, inject, ElementRef, afterNextRender, DestroyRef, signal, } from '@angular/core'; import { ReducedMotionService } from '../../services/reduced-motion.service'; import { AnimationLoopService } from '../../services/animation-loop.service'; @Component({ selector: 'fl-ambient-light', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
`, styleUrl: './fl-ambient-light.component.scss', host: { 'class': 'fl-ambient-light', }, }) export class FlAmbientLightComponent { private el = inject(ElementRef); private reducedMotion = inject(ReducedMotionService); private animationLoop = inject(AnimationLoopService); private destroyRef = inject(DestroyRef); // Inputs readonly colors = input(['#3b82f6', '#8b5cf6', '#ec4899']); readonly speed = input(1); readonly blur = input(100); readonly opacity = input(0.5); // Internal private elapsed = 0; private loopCleanup: (() => void) | null = null; // Signals for layer backgrounds readonly layer1 = signal(''); readonly layer2 = signal(''); readonly layer3 = signal(''); constructor() { afterNextRender(() => { if (this.reducedMotion.reduced()) { this.setStaticGradients(); return; } const id = `ambient-light-${Math.random().toString(36).slice(2)}`; this.loopCleanup = this.animationLoop.registerWithElement(id, this.el.nativeElement, (delta) => this.tick(delta)); }); this.destroyRef.onDestroy(() => { this.loopCleanup?.(); }); } private tick(delta: number): void { this.elapsed += delta * this.speed(); this.updateGradients(); } private updateGradients(): void { const host = this.el.nativeElement as HTMLElement; const width = host.offsetWidth; const height = host.offsetHeight; const colors = this.colors(); const blur = this.blur(); const opacity = this.opacity(); // Layer 1 const x1 = 50 + Math.sin(this.elapsed * 0.3) * 30; const y1 = 50 + Math.cos(this.elapsed * 0.2) * 30; const color1 = colors[0] || '#3b82f6'; this.layer1.set(`radial-gradient(circle at ${x1}% ${y1}%, ${color1} 0%, transparent ${blur}%)`); // Layer 2 const x2 = 50 + Math.sin(this.elapsed * 0.4 + Math.PI) * 25; const y2 = 50 + Math.cos(this.elapsed * 0.3 + Math.PI) * 25; const color2 = colors[1] || '#8b5cf6'; this.layer2.set(`radial-gradient(circle at ${x2}% ${y2}%, ${color2} 0%, transparent ${blur}%)`); // Layer 3 const x3 = 50 + Math.sin(this.elapsed * 0.5 + Math.PI * 0.5) * 20; const y3 = 50 + Math.cos(this.elapsed * 0.4 + Math.PI * 0.5) * 20; const color3 = colors[2] || '#ec4899'; this.layer3.set(`radial-gradient(circle at ${x3}% ${y3}%, ${color3} 0%, transparent ${blur}%)`); } private setStaticGradients(): void { const colors = this.colors(); const blur = this.blur(); this.layer1.set(`radial-gradient(circle at 50% 50%, ${colors[0] || '#3b82f6'} 0%, transparent ${blur}%)`); this.layer2.set(`radial-gradient(circle at 30% 70%, ${colors[1] || '#8b5cf6'} 0%, transparent ${blur}%)`); this.layer3.set(`radial-gradient(circle at 70% 30%, ${colors[2] || '#ec4899'} 0%, transparent ${blur}%)`); } }