<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Universal Morphing Background - Positionable Element</title>
   <style>
       body {
           margin: 0;
           background-color: #000000;
           font-family: sans-serif;
           color: #c0c0c0;
           /* Centering properties have been removed */
       }
       #animationWindow {
           position: relative;
           width: 1000px;
           height: 1000px;
           background-color: rgba(0, 0, 0, 0.8);
           border: 1px solid #c0c0c0;
       }
       canvas {
           display: block;
           position: absolute;
           top: 0;
           left: 0;
       }
   </style>
</head>
<body>
   <div id="animationWindow">
       <canvas id="bgCanvas"></canvas>
   </div>

   <script>
       const animationWindow = document.getElementById('animationWindow');
       const canvas = document.getElementById('bgCanvas');
       const ctx = canvas.getContext('2d');
       let particles = [];
       let shapes = [];
       let currentShapeIndex, targetShapeIndex;
       let currentShapeData, targetShapeData;
       let progress = 0;
       let morphSpeed = 0.004;
       let angleX = 0;
       let angleY = 0;
       let particleCount = 25000;

       class Particle {
           constructor(x, y, z) {
               this.x = x;
               this.y = y;
               this.z = z;
               this.projectedX = 0;
               this.projectedY = 0;
               this.size = 1;
           }

           project(x, y, z) {
               const fov = 1000; 
               const dist = fov + z;
               this.projectedX = (x * fov) / dist + canvas.width / 2;
               this.projectedY = (y * fov) / dist + canvas.height / 2;
               this.size = Math.max(0, (1 - z / 1000) * 1.5);
           }

           draw() {
               if (this.projectedX < 0 || this.projectedX > canvas.width || this.projectedY < 0 || this.projectedY > canvas.height) {
                   return;
               }
               ctx.beginPath();
               ctx.arc(this.projectedX, this.projectedY, this.size, 0, Math.PI * 2);
               ctx.fillStyle = `rgba(192, 192, 192, ${this.size / 1.5})`;
               ctx.fill();
           }
       }
       
       // --- Shape Generation ---

       function generateShapes() {
           shapes.push(createTrefoilKnot);
           shapes.push(createFigureEightKnot);
           shapes.push(createCinquefoilKnot);
           shapes.push(createGrannyKnot);
           shapes.push(createSierpinskiTetrahedron);
           shapes.push(createSierpinskiPyramid);
           shapes.push(createMengerSponge);
           shapes.push(createCantorDust3D);
           shapes.push(createBlackHole);
           shapes.push(createCube);
       }

       function createFigureEightKnot() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 8;
           for (let i = 0; i < particleCount; i++) {
               const t = (i / particleCount) * Math.PI * 4;
               const r = 2 + Math.sin(1.5 * t);
               const x = Math.cos(t) * r * scaleFactor;
               const y = Math.sin(t) * r * scaleFactor;
               const z = Math.cos(1.5 * t) * scaleFactor * 2;
               tempParticles.push({x, y, z});
           }
           return tempParticles;
       }

       function createTrefoilKnot() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 8;
           for (let i = 0; i < particleCount; i++) {
               const t = (i / particleCount) * Math.PI * 2;
               const x = (Math.sin(t) + 2 * Math.sin(2 * t)) * scaleFactor;
               const y = (Math.cos(t) - 2 * Math.cos(2 * t)) * scaleFactor;
               const z = -Math.sin(3 * t) * scaleFactor;
               tempParticles.push({x, y, z});
           }
           return tempParticles;
       }

       function createCinquefoilKnot() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 10;
           for (let i = 0; i < particleCount; i++) {
               const t = (i / particleCount) * Math.PI * 2;
               const x = (2 + Math.cos(5 * t)) * Math.cos(2 * t) * scaleFactor;
               const y = (2 + Math.cos(5 * t)) * Math.sin(2 * t) * scaleFactor;
               const z = -Math.sin(5 * t) * scaleFactor;
               tempParticles.push({x, y, z});
           }
           return tempParticles;
       }

       function createGrannyKnot() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 5;
           for (let i = 0; i < particleCount; i++) {
               const t = (i / particleCount) * Math.PI * 2;
               const x = (-Math.cos(t) - 0.5 * Math.cos(5*t) - 0.5 * Math.cos(7*t)) * scaleFactor;
               const y = (Math.sin(t) - 0.5 * Math.sin(5*t) + 0.5 * Math.sin(7*t)) * scaleFactor;
               const z = (Math.cos(2*t) + 0.5 * Math.cos(6*t)) * scaleFactor;
               tempParticles.push({x, y, z});
           }
           return tempParticles;
       }
       
       function createSierpinskiTetrahedron() {
           const tempParticles = [];
           const scale = Math.min(canvas.width, canvas.height) / 2;
           const v = [
               {x: scale, y: scale, z: scale},
               {x: -scale, y: -scale, z: scale},
               {x: -scale, y: scale, z: -scale},
               {x: scale, y: -scale, z: -scale}
           ];
           let p = {x: 0, y: 0, z: 0};
           for (let i = 0; i < particleCount; i++) {
               const targetVertex = v[Math.floor(Math.random() * 4)];
               p.x = (p.x + targetVertex.x) / 2;
               p.y = (p.y + targetVertex.y) / 2;
               p.z = (p.z + targetVertex.z) / 2;
               tempParticles.push({x: p.x, y: p.y, z: p.z});
           }
           return tempParticles;
       }

       function createSierpinskiPyramid() {
           const tempParticles = [];
           const scale = Math.min(canvas.width, canvas.height) / 2;
           const v = [
               {x: 0, y: scale, z: 0},
               {x: scale, y: -scale, z: scale},
               {x: -scale, y: -scale, z: scale},
               {x: 0, y: -scale, z: -scale}
           ];
           let p = {x: 0, y: 0, z: 0};
           for (let i = 0; i < particleCount; i++) {
               const targetVertex = v[Math.floor(Math.random() * 4)];
               p.x = (p.x + targetVertex.x) / 2;
               p.y = (p.y + targetVertex.y) / 2;
               p.z = (p.z + targetVertex.z) / 2;
               tempParticles.push({x: p.x, y: p.y, z: p.z});
           }
           return tempParticles;
       }

       function createMengerSponge() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 2;
           let p = { x: Math.random() - 0.5, y: Math.random() - 0.5, z: Math.random() - 0.5 };

           const translations = [];
           for (let i = -1; i <= 1; i++) {
               for (let j = -1; j <= 1; j++) {
                   for (let k = -1; k <= 1; k++) {
                       if (Math.abs(i) + Math.abs(j) + Math.abs(k) > 1) {
                           translations.push({ x: i, y: j, z: k });
                       }
                   }
               }
           }

           for (let i = 0; i < particleCount; i++) {
               const t = translations[Math.floor(Math.random() * translations.length)];
               p.x = (p.x + t.x) / 3;
               p.y = (p.y + t.y) / 3;
               p.z = (p.z + t.z) / 3;
               tempParticles.push({ x: p.x * scaleFactor, y: p.y * scaleFactor, z: p.z * scaleFactor });
           }
           return tempParticles;
       }

       function createCantorDust3D() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 2.5;
           let p = { x: 0, y: 0, z: 0 };

           const translations = [];
           for (let i = -1; i <= 1; i += 2) {
               for (let j = -1; j <= 1; j += 2) {
                   for (let k = -1; k <= 1; k += 2) {
                       translations.push({ x: i, y: j, z: k });
                   }
               }
           }
           for (let i = 0; i < particleCount; i++) {
               const t = translations[Math.floor(Math.random() * translations.length)];
               p.x = (p.x + t.x) / 3;
               p.y = (p.y + t.y) / 3;
               p.z = (p.z + t.z) / 3;
               tempParticles.push({ x: p.x * scaleFactor, y: p.y * scaleFactor, z: p.z * scaleFactor });
           }
           return tempParticles;
       }

       function createBlackHole() {
           const tempParticles = [];
           const scaleFactor = Math.min(canvas.width, canvas.height) / 4;
           const diskRadius = 1.2 * scaleFactor;
           for (let i = 0; i < particleCount; i++) {
               const r = Math.cbrt(Math.random()) * diskRadius;
               const theta = Math.random() * Math.PI * 2;
               const x = r * Math.cos(theta);
               const y = (Math.random() - 0.5) * r * 0.05;
               const z = r * Math.sin(theta);
               tempParticles.push({x, y, z});
           }
           return tempParticles;
       }

       function createCube() {
           const tempParticles = [];
           const size = Math.min(canvas.width, canvas.height) / 3;
           for (let i = 0; i < particleCount; i++) {
               const x = Math.random() * size - size / 2;
               const y = Math.random() * size - size / 2;
               const z = Math.random() * size - size / 2;
               tempParticles.push({x, y, z});
           }
           return tempParticles;
       }
       
       // --- Core Logic ---

       function morph() {
           progress += morphSpeed;
           if (progress >= 1) {
               progress = 0;
               currentShapeIndex = targetShapeIndex;
               do {
                   targetShapeIndex = Math.floor(Math.random() * shapes.length);
               } while (targetShapeIndex === currentShapeIndex);
               currentShapeData = shapes[currentShapeIndex]();
               targetShapeData = shapes[targetShapeIndex]();
           }

           for (let i = 0; i < particleCount; i++) {
               const p = particles[i];
               const start = currentShapeData[i];
               const end = targetShapeData[i];
               p.x = start.x + (end.x - start.x) * progress;
               p.y = start.y + (end.y - start.y) * progress;
               p.z = start.z + (end.z - start.z) * progress;
           }
       }

       function animate() {
           requestAnimationFrame(animate);
           ctx.clearRect(0, 0, canvas.width, canvas.height);

           morph();
           angleX += 0.001;
           angleY += 0.002;

           const cosX = Math.cos(angleX);
           const sinX = Math.sin(angleX);
           const cosY = Math.cos(angleY);
           const sinY = Math.sin(angleY);

           particles.forEach(p => {
               const x1 = p.x * cosY - p.z * sinY;
               const z1 = p.x * sinY + p.z * cosY;
               const y2 = p.y * cosX - z1 * sinX;
               const z2 = p.y * sinX + z1 * cosX;
               
               p.project(x1, y2, z2);
               p.draw();
           });
       }

       function initialize() {
           canvas.width = animationWindow.clientWidth;
           canvas.height = animationWindow.clientHeight;
           
           particles = [];
           shapes = [];

           generateShapes();
           currentShapeIndex = Math.floor(Math.random() * shapes.length);
           do {
               targetShapeIndex = Math.floor(Math.random() * shapes.length);
           } while (targetShapeIndex === currentShapeIndex);

           currentShapeData = shapes[currentShapeIndex]();
           targetShapeData = shapes[targetShapeIndex]();
           
           for (let i = 0; i < particleCount; i++) {
               particles.push(new Particle(currentShapeData[i].x, currentShapeData[i].y, currentShapeData[i].z));
           }
       }

       window.onload = () => {
           initialize();
           animate();
       };
   </script>
</body>
</html>

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.