문서 편집 권한이 없습니다. 다음 이유를 확인해주세요: 요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다: 사용자. 문서의 원본을 보거나 복사할 수 있습니다. <!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> <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> </body> </html> 크리스마스 트리 문서로 돌아갑니다.