;
+
+ private ctx!: CanvasRenderingContext2D;
+ private particles: any[] = [];
+ private animationFrameId: number = 0;
+
+ // --- Configuration ---
+ private readonly numParticles = 80;
+ private readonly maxDistance = 150;
+ private readonly particleSpeed = 0.8;
+
+ constructor(private ngZone: NgZone) {}
+
+ ngAfterViewInit(): void {
+ const canvas = this.canvasRef.nativeElement;
+ this.ctx = canvas.getContext('2d')!;
+
+ this.resizeCanvas();
+ this.initParticles();
+
+ this.ngZone.runOutsideAngular(() => {
+ this.animate();
+ });
+ }
+
+ ngOnDestroy(): void {
+ cancelAnimationFrame(this.animationFrameId);
+ }
+
+ @HostListener('window:resize')
+ resizeCanvas(): void {
+ const canvas = this.canvasRef.nativeElement;
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ }
+
+ private initParticles(): void {
+ this.particles = [];
+ const canvas = this.canvasRef.nativeElement;
+
+ for (let i = 0; i < this.numParticles; i++) {
+ this.particles.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ vx: (Math.random() - 0.5) * this.particleSpeed,
+ vy: (Math.random() - 0.5) * this.particleSpeed,
+ radius: Math.random() * 1.5 + 0.5
+ });
+ }
+ }
+
+ private animate = (): void => {
+ const canvas = this.canvasRef.nativeElement;
+
+ this.ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ for (let i = 0; i < this.numParticles; i++) {
+ let p = this.particles[i];
+
+ p.x += p.vx;
+ p.y += p.vy;
+
+ if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
+ if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
+
+ this.ctx.beginPath();
+ this.ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
+ this.ctx.fillStyle = 'rgba(120, 150, 170, 0.4)';
+ this.ctx.fill();
+
+ for (let j = i + 1; j < this.numParticles; j++) {
+ let p2 = this.particles[j];
+
+ let dx = p.x - p2.x;
+ let dy = p.y - p2.y;
+ let distance = Math.sqrt(dx * dx + dy * dy);
+
+ if (distance < this.maxDistance) {
+ this.ctx.beginPath();
+ this.ctx.moveTo(p.x, p.y);
+ this.ctx.lineTo(p2.x, p2.y);
+
+ let opacity = (1 - (distance / this.maxDistance)) * 0.5;
+ this.ctx.strokeStyle = `rgba(120, 150, 170, ${opacity})`;
+ this.ctx.lineWidth = 1;
+ this.ctx.stroke();
+ }
+ }
+ }
+
+ this.animationFrameId = requestAnimationFrame(this.animate);
+ };
+}
diff --git a/src/app/shared/components/particles-background/particles-background.html b/src/app/shared/components/particles-background/particles-background.html
deleted file mode 100644
index 39134d1..0000000
--- a/src/app/shared/components/particles-background/particles-background.html
+++ /dev/null
@@ -1 +0,0 @@
-particles-background works!
diff --git a/src/app/shared/components/particles-background/particles-background.scss b/src/app/shared/components/particles-background/particles-background.scss
deleted file mode 100644
index e69de29..0000000
diff --git a/src/app/shared/components/particles-background/particles-background.ts b/src/app/shared/components/particles-background/particles-background.ts
deleted file mode 100644
index 4d2d3d7..0000000
--- a/src/app/shared/components/particles-background/particles-background.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-particles-background',
- imports: [],
- templateUrl: './particles-background.html',
- styleUrl: './particles-background.scss',
-})
-export class ParticlesBackground {
-
-}
diff --git a/src/styles.scss b/src/styles.scss
index febb19c..d4a918e 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -407,9 +407,15 @@ app-root {
min-height: 100vh;
}
+.app-container {
+ width: 100%;
+ max-width: var(--app-maxWidth);
+ margin: 1rem auto;
+
+}
+
.app-surface {
flex-grow: 1;
- background: var(--app-bg);
color: var(--app-fg);
transition: background-color 220ms ease, color 220ms ease;
}