<div class="blackhole-container" style="width: 1000px; height: 1000px; position: relative; background-color: #000;">
   <canvas style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
   <script>
       // Self-executing function to encapsulate the code and keep it from interfering with other scripts.
       (function() {
           // This makes the element self-contained. It finds the canvas inside its own container.
           const container = document.currentScript.parentElement;
           const canvas = container.querySelector('canvas');
           if (!container || !canvas) return;

           const ctx = canvas.getContext('2d');
           
           let particles = [];
           const particleCount = 50000;
           const triangleParticleCount = 35000;

           const angleX = Math.PI / 2; 
           const cosX = Math.cos(angleX);
           const sinX = Math.sin(angleX);

           const singularityRadius = 100;
           const photonSphereRadius = 100;

           // --- ORIGINAL PARTICLE CLASS (UNCHANGED) ---
           class Particle {
               constructor(diskType) {
                   this.diskType = diskType; // 'main' or 'perpendicular'
                   this.reset();
               }

               reset() {
                   let radius;
                   if (this.diskType === 'main') {
                       radius = photonSphereRadius + Math.random() * (350 / 25);
                   } else {
                       radius = photonSphereRadius + Math.random() * 350;
                   }
                   
                   const angle = Math.random() * Math.PI * 2;
                   const tubeRadius = 15 * (1 - Math.pow(radius / 450, 2));
                   const tubeAngle = Math.random() * Math.PI * 2;
                   
                   if (this.diskType === 'main') {
                       this.x = (radius + Math.cos(tubeAngle) * tubeRadius) * Math.cos(angle);
                       this.z = (radius + Math.cos(tubeAngle) * tubeRadius) * Math.sin(angle);
                       this.y = Math.sin(tubeAngle) * tubeRadius;
                   } else {
                       this.x = (radius + Math.cos(tubeAngle) * tubeRadius) * Math.cos(angle);
                       this.y = (radius + Math.cos(tubeAngle) * tubeRadius) * Math.sin(angle);
                       this.z = Math.sin(tubeAngle) * tubeRadius;
                   }

                   this.speed = (0.001 + (1 / radius) * 0.2) * 10;
                   this.angle = angle;
                   this.radius = radius;
                   this.life = Math.random() * 200 + 100;
                   this.age = 0;
               }
               
               update() {
                   this.age++;
                   this.angle += this.speed;

                   if (this.diskType === 'main') {
                        this.x = this.radius * Math.cos(this.angle);
                        this.z = this.radius * Math.sin(this.angle);
                   } else {
                        this.x = this.radius * Math.cos(this.angle);
                        this.y = this.radius * Math.sin(this.angle);
                   }

                   if (this.age >= this.life || this.radius < photonSphereRadius) {
                       this.reset();
                   }
               }

               project(rotX, rotY, rotZ) {
                   const fov = 1000;
                   let dist = fov + rotZ;
                   this.isBehind = rotZ > 0;
                   
                   if (dist > 0) {
                       this.projectedX = (rotX * fov) / dist + centerX;
                       this.projectedY = (rotY * fov) / dist + centerY;
                       this.size = Math.max(0, (2 - rotZ / 500) * 0.6);
                   } else {
                       this.size = -1;
                   }
               }

               draw() {
                   if (this.size <= 0) return;
                   const opacity = (1 - (this.age / this.life)) * 0.9;
                   ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
                   ctx.fillRect(this.projectedX, this.projectedY, this.size, this.size);
               }
           }
           
           // --- FINAL WORKING PARTICLE CLASS for Z-AXIS TRIANGLES ---
           class TriangleParticle {
               constructor(side) {
                   this.side = side; // 'left' or 'right'
                   this.reset();
               }

               reset() {
                   const radius = 100;
                   const extension = 300; 
                   const joinZMax = 90;

                   const vertexX = radius + extension;
                   const joinX = Math.sqrt(Math.max(0, radius * radius - joinZMax * joinZMax));
                   const parabola_a = joinZMax * joinZMax / (joinX - vertexX);

                   let x, z;
                   let valid = false;
                   while(!valid) {
                       z = (Math.random() - 0.5) * (2 * joinZMax);
                       const inner_sqrt_arg = radius * radius - z * z;
                       if (inner_sqrt_arg < 0) continue;

                       const x_inner_boundary = Math.sqrt(inner_sqrt_arg);
                       const x_outer_boundary = (z * z / parabola_a) + vertexX;
                       if(x_outer_boundary > x_inner_boundary){
                           x = x_outer_boundary - Math.random() * (x_outer_boundary - x_inner_boundary) * 0.1;
                           valid = true;
                       }
                   }
                   
                   this.x = x;
                   this.z = z;

                   if (this.side === 'left') {
                       this.x = -this.x;
                   }

                   this.y = (Math.random() - 0.5) * 15;
                   this.age = 0;
                   this.life = 100;
                   
                   // Enforce inward speed
                   this.speedX = (this.side === 'left' ? 1 : -1) * (1 + Math.random() * 2.5);
                   this.speedY = (Math.random() - 0.5) * 2.5;
                   this.speedZ = (Math.random() - 0.5) * 2.5;
               }

               update() {
                   this.age++;
                   
                   // Apply a constant inward pull on all axes
                   const dx = 0 - this.x;
                   const dy = 0 - this.y;
                   const dz = 0 - this.z;

                   const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
                   
                   if (distance > 0) {
                     this.speedX = (dx / distance) * 2.5;
                     this.speedY = (dy / distance) * 2.5;
                     this.speedZ = (dz / distance) * 2.5;
                   }

                   this.x += this.speedX;
                   this.y += this.speedY;
                   this.z += this.speedZ;
                   
                   // Reset if the particle reaches the center
                   if (distance < singularityRadius) {
                       this.reset();
                   }
               }

               project(rotX, rotY, rotZ) {
                   const fov = 1000;
                   let dist = fov + rotZ;
                   this.isBehind = rotZ > 0;
                   
                   if (dist > 0) {
                       this.projectedX = (rotX * fov) / dist + centerX;
                       this.projectedY = (rotY * fov) / dist + centerY;
                       this.size = Math.max(0, (2 - rotZ / 500) * 0.6);
                   } else {
                       this.size = -1;
                   }
               }

               draw() {
                   if (this.size <= 0) return;
                   // Fade out as they move inward
                   const opacity = (1 - (this.age / this.life)) * 0.9;
                   ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
                   ctx.fillRect(this.projectedX, this.projectedY, this.size, this.size);
               }
           }
           
           let centerX, centerY;
           function init() {
               canvas.width = container.clientWidth;
               canvas.height = container.clientHeight;
               centerX = canvas.width / 2;
               centerY = canvas.height / 2;
               
               particles = [];
               for (let i = 0; i < particleCount; i++) {
                   particles.push(new Particle(i < particleCount / 2 ? 'main' : 'perpendicular'));
               }
               
               for (let i = 0; i < triangleParticleCount; i++) {
                   particles.push(new TriangleParticle(i < triangleParticleCount / 2 ? 'left' : 'right'));
               }
               
               animate();
           }

           function drawSingularity() {
               ctx.beginPath();
               ctx.arc(centerX, centerY, singularityRadius, 0, Math.PI * 2);
               ctx.fillStyle = '#000';
               ctx.fill();
           }

           function animate() {
               requestAnimationFrame(animate);
               ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
               ctx.fillRect(0, 0, canvas.width, canvas.height);
               
               const foregroundParticles = [];
               const backgroundParticles = [];

               particles.forEach(p => {
                   p.update();

                   const y_rotated = p.y * cosX - p.z * sinX;
                   const z_rotated = p.y * sinX + p.z * cosX;
                   
                   const x_final = p.x;
                   const y_final = y_rotated;
                   const z_final = z_rotated;

                   p.project(x_final, y_final, z_final);

                   if (p.isBehind) backgroundParticles.push(p);
                   else foregroundParticles.push(p);
               });
               
               ctx.shadowBlur = 8;
               ctx.shadowColor = "rgba(255, 255, 255, 0.2)";
               backgroundParticles.forEach(p => p.draw());
               
               ctx.shadowBlur = 0;
               drawSingularity();
               
               ctx.shadowBlur = 8;
               ctx.shadowColor = "rgba(255, 255, 255, 0.2)";
               foregroundParticles.forEach(p => p.draw());

               ctx.shadowBlur = 0;
           }
           
           init();

       })();
   </script>
</div>
 

We need your consent to load the translations

We use a third-party service to translate the website content that may collect data about your activity. Please review the details in the privacy policy and accept the service to view the translations.