<!DOCTYPE html> <html lang="ko"> <head>

   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
   <title>Vibrant Math Tree</title>
   <style>
       @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap');
       body {
           margin: 0;
           overflow: hidden;
           background-color: #020205;
           font-family: 'Fira Code', monospace;
           cursor: move;
       }
       canvas {
           display: block;
       }
   </style>

</head> <body>

</html>

<canvas id="canvas"></canvas> <script>

   const canvas = document.getElementById('canvas');
   const ctx = canvas.getContext('2d');
   const _0x5a1 = [70, 76, 65, 71, 123, 84, 119, 105, 110, 107, 108, 105, 110, 103, 95, 76, 105, 103, 104, 116, 115, 95, 65, 110, 100, 95, 66, 114, 105, 103, 104, 116, 95, 79, 114, 110, 97, 109, 101, 110, 116, 115, 125];
   const hiddenPathChars = _0x5a1.map(c => String.fromCharCode(c));
   let width, height;
   let particles = [];
   let snowParticles = [];
   
   let angleY = 0;
   let targetAngleY = 0;
   let isDragging = false;
   let lastMouseX = 0;
   let cameraZ = 550;
   let mathDecorations = [
       "x", "y", "z", "i", "e", "π", "ω", "t", "s", "f", "g",
       "sin", "cos", "tan", "log", "ln", "lim", "det", "max", "min",
       "f(t)", "F(ω)", "L(s)", "dy/dx", "x²+y²", "e^x", "sin(x)",
       "ℱ{f}", "ℒ{f}", "∫e⁻ˢᵗ", "∫e⁻ⁱωᵗ",
       "E=mc²", "F=ma", "V=IR", "A=πr²", "∇∙F", "∇×F",
       "e^(iπ)+1=0", "sin²θ+cos²θ=1", "d/dx(e^x)=e^x",
       "x=(-b±√D)/2a", "PV=nRT", "S=klogW"
   ];
   mathDecorations.sort((a, b) => a.length - b.length);
   const treeGreens = ["#00FF00", "#32CD32", "#00FA9A", "#98FB98", "#7CFC00"];
   const ornamentColors = ["#FF0000", "#FFD700", "#FF00FF", "#00FFFF"];
   const lightColors = ["#FF5555", "#55FF55", "#5555FF", "#FFFF55", "#FF55FF", "#55FFFF"];
   const snowSymbols = ["+", "-", "×", "÷", "=", "≠"];
   class Particle {
       constructor(x, y, z, text, color, type = 'leaf') {
           this.x = x;
           this.y = y;
           this.z = z;
           this.text = text;
           this.color = color;
           this.type = type;
           
           if (this.type === 'star') this.baseSize = 60;
           else if (this.type === 'light') this.baseSize = 24;
           else if (this.type === 'ornament') this.baseSize = 20;
           else if (this.type === 'trunk') this.baseSize = 14;
           else this.baseSize = 14;
           this.projX = 0;
           this.projY = 0;
           this.projScale = 0;
           this.visible = false;
           this.depth = 0;
           this.alpha = Math.random() * 0.5 + 0.5;
           this.blinkPhase = Math.random() * Math.PI * 2;
           
           if (this.type === 'light') {
               this.lightColor = lightColors[Math.floor(Math.random() * lightColors.length)];
           }
       }
       project(cx, cy, angle) {
           const cos = Math.cos(angle);
           const sin = Math.sin(angle);
           const rx = this.x * cos - this.z * sin;
           const rz = this.x * sin + this.z * cos;
           const focalLength = 450;
           const scale = focalLength / (focalLength + rz + cameraZ);
           this.projScale = scale;
           this.projX = rx * scale + cx;
           this.projY = this.y * scale + cy;
           this.visible = (scale > 0 && rz > -cameraZ);
           this.depth = rz;
       }
       draw(ctx) {
           if (!this.visible) return;
           
           let alpha = this.alpha;
           if (this.type === 'trunk') alpha = Math.max(alpha, 0.8);
           
           let drawAlpha = Math.max(0.1, Math.min(1, alpha * this.projScale));
           
           if(this.type === 'star' || this.type === 'light' || this.type === 'ornament') {
               drawAlpha = 1;
           }
           ctx.globalAlpha = drawAlpha;
           const fontSize = this.baseSize * this.projScale;
           ctx.font = `bold ${fontSize}px 'Fira Code', monospace`;
           if (this.type === 'star') {
               ctx.shadowBlur = 40 + Math.abs(Math.sin(Date.now() * 0.002)) * 20;
               ctx.shadowColor = "#FFD700"; 
               ctx.fillStyle = "#FFFF00"; 
           } 
           else if (this.type === 'light') {
               const time = Date.now() * 0.005 + this.blinkPhase;
               let twinkle = Math.pow(Math.sin(time) * 0.5 + 0.5, 4); 
               
               ctx.globalAlpha = 0.4 + twinkle * 0.6; 
               ctx.shadowBlur = 10 + twinkle * 25;
               ctx.shadowColor = this.lightColor;
               ctx.fillStyle = "#FFFFFF"; 
           }
           else if (this.type === 'ornament') {
               ctx.shadowBlur = 15;
               ctx.shadowColor = this.color;
               ctx.fillStyle = this.color;
           }
           else if (this.projScale > 0.6) {
               ctx.shadowBlur = 5;
               ctx.shadowColor = this.color;
               ctx.fillStyle = this.color;
           } else {
               ctx.shadowBlur = 0;
               ctx.fillStyle = this.color;
           }
           ctx.fillText(this.text, this.projX, this.projY);
           ctx.globalAlpha = 1;
           ctx.shadowBlur = 0;
       }
   }
   class SnowParticle {
       constructor() {
           this.reset();
           this.y = Math.random() * height - height / 2;
       }
       reset() {
           this.x = (Math.random() - 0.5) * width * 1.5;
           this.y = -height / 2 - Math.random() * 200;
           this.z = (Math.random() - 0.5) * 1000;
           this.text = snowSymbols[Math.floor(Math.random() * snowSymbols.length)];
           this.color = "#FFFFFF";
           this.speed = Math.random() * 2 + 1;
           this.size = Math.random() * 10 + 8;
           this.drift = Math.random() * 0.5 - 0.25;
       }
       update() {
           this.y += this.speed;
           this.x += this.drift;
           if (this.y > height / 2 + 100) {
               this.reset();
           }
       }
       project(cx, cy, angle) {
           const cos = Math.cos(angle * 0.1);
           const sin = Math.sin(angle * 0.1);
           const rx = this.x * cos - this.z * sin;
           const rz = this.x * sin + this.z * cos;
           const focalLength = 450;
           const scale = focalLength / (focalLength + rz + cameraZ);
           this.projScale = scale;
           this.projX = rx * scale + cx;
           this.projY = this.y * scale + cy;
           this.visible = (scale > 0 && rz > -cameraZ);
       }
       draw(ctx) {
           if (!this.visible) return;
           ctx.globalAlpha = Math.min(1, this.projScale * 0.7);
           ctx.font = `${this.size * this.projScale}px 'Fira Code', monospace`;
           ctx.fillStyle = this.color;
           if (this.projScale > 0.7) {
                ctx.shadowBlur = 5;
                ctx.shadowColor = "#FFFFFF";
           }
           ctx.fillText(this.text, this.projX, this.projY);
           ctx.globalAlpha = 1;
           ctx.shadowBlur = 0;
       }
   }
   function createTree() {
       particles = [];
       const treeHeight = 650;
       const maxRadius = 280;
       const leafCount = 600;
       const phi = Math.PI * (3 - Math.sqrt(5));
       for (let i = 0; i < leafCount; i++) {
           const y = - (treeHeight / 2) + (i / leafCount) * treeHeight - 80;
           const radius = (i / leafCount) * maxRadius;
           const theta = phi * i;
           const x = Math.cos(theta) * radius;
           const z = Math.sin(theta) * radius;
           const progress = i / leafCount; 
           const centerIndex = progress * (mathDecorations.length - 1);
           const noise = (Math.random() - 0.5) * 8; 
           let index = Math.floor(centerIndex + noise);
           index = Math.max(0, Math.min(mathDecorations.length - 1, index));
           const text = mathDecorations[index];
           
           let color, type;
           if (Math.random() < 0.15) {
               color = ornamentColors[Math.floor(Math.random() * ornamentColors.length)];
               type = 'ornament';
           } else {
               color = treeGreens[Math.floor(Math.random() * treeGreens.length)];
               type = 'leaf';
           }
           particles.push(new Particle(x, y, z, text, color, type));
       }
       const flagLen = hiddenPathChars.length;
       for (let i = 0; i < flagLen; i++) {
           const y = - (treeHeight / 2) + (i / flagLen) * (treeHeight * 0.8) - 60;
           const radius = ((i + 2) / (flagLen + 5)) * maxRadius * 0.95; 
           const theta = (i * 1.5) + 0; 
           const x = Math.cos(theta) * radius;
           const z = Math.sin(theta) * radius;
           particles.push(new Particle(x, y, z, hiddenPathChars[i], "#FFFFFF", 'light'));
       }
       const trunkH = 160;
       const trunkW = 70;
       const trunkCount = 120;
       const trunkStartY = (treeHeight / 2) - 60;
       for(let i=0; i<trunkCount; i++) {
           const h = Math.random() * trunkH;
           const angle = Math.random() * Math.PI * 2;
           const r = trunkW;
           const x = Math.cos(angle) * r;
           const z = Math.sin(angle) * r;
           const y = trunkStartY + h;
           const text = Math.random() > 0.5 ? "1" : "0";
           particles.push(new Particle(x, y, z, text, "#D2691E", 'trunk'));
       }
       
       particles.push(new Particle(0, -treeHeight/2 - 120, 0, "★", "#FFFF00", 'star'));
   }
   function createSnow() {
       snowParticles = [];
       const snowCount = 200;
       for (let i = 0; i < snowCount; i++) {
           snowParticles.push(new SnowParticle());
       }
   }
   function resize() {
       width = canvas.width = window.innerWidth;
       height = canvas.height = window.innerHeight;
   }
   function animate() {
       ctx.fillStyle = "#020205";
       ctx.fillRect(0, 0, width, height);
       if (!isDragging) targetAngleY += 0.002;
       angleY += (targetAngleY - angleY) * 0.1;
       snowParticles.forEach(p => {
           p.update();
           p.project(width / 2, height / 2, angleY);
           p.draw(ctx);
       });
       particles.forEach(p => p.project(width / 2, height / 2, angleY));
       particles.sort((a, b) => b.depth - a.depth);
       ctx.textAlign = 'center';
       ctx.textBaseline = 'middle';
       particles.forEach(p => p.draw(ctx));
       
       requestAnimationFrame(animate);
   }
   window.addEventListener('resize', resize);
   window.addEventListener('wheel', (e) => {
       cameraZ += e.deltaY * 0.5;
       cameraZ = Math.max(200, Math.min(1000, cameraZ));
   });
   const onStart = (x) => { isDragging = true; lastMouseX = x; };
   const onMove = (x) => {
       if (!isDragging) return;
       const delta = (x - lastMouseX) * 0.005;
       targetAngleY += delta;
       angleY += delta;
       lastMouseX = x;
   };
   const onEnd = () => { isDragging = false; };
   canvas.addEventListener('mousedown', e => onStart(e.clientX));
   window.addEventListener('mousemove', e => onMove(e.clientX));
   window.addEventListener('mouseup', onEnd);
   canvas.addEventListener('touchstart', e => onStart(e.touches[0].clientX));
   window.addEventListener('touchmove', e => onMove(e.touches[0].clientX));
   window.addEventListener('touchend', onEnd);
   resize();
   createTree();
   createSnow();
   animate();

</script>