终极烟花模拟器edit icon

作者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>超级烟花模拟器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(135deg, #0a0a0a, #1a1a2e, #0f0f23);
            overflow: hidden;
            user-select: none;
        }

        canvas {
            display: block;
            cursor: crosshair;
            background: radial-gradient(ellipse at center, #000428 0%, #004e92 100%);
        }

        .ui-overlay {
            position: fixed;
            top: 20px;
            left: 20px;
            z-index: 1000;
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        .ui-panel {
            background: rgba(0, 0, 0, 0.8);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 12px;
            padding: 15px;
            color: white;
            min-width: 200px;
        }

        .control-group {
            margin-bottom: 15px;
        }

        .control-group label {
            display: block;
            margin-bottom: 5px;
            font-size: 12px;
            color: #ccc;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        .control-row {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 8px;
        }

        input[type="range"] {
            flex: 1;
            height: 4px;
            border-radius: 2px;
            background: #333;
            outline: none;
            -webkit-appearance: none;
        }

        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
            cursor: pointer;
            box-shadow: 0 0 10px rgba(255, 107, 107, 0.5);
        }

        .value-display {
            min-width: 30px;
            font-size: 11px;
            color: #4ecdc4;
            text-align: right;
        }

        button {
            background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
            border: none;
            border-radius: 6px;
            color: white;
            padding: 8px 12px;
            cursor: pointer;
            font-size: 12px;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 1px;
        }

        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }

        button.active {
            background: linear-gradient(45deg, #ff6b6b, #ee5a24);
            box-shadow: 0 0 20px rgba(255, 107, 107, 0.6);
        }

        .firework-type-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 5px;
            margin-top: 10px;
        }

        .firework-type-btn {
            padding: 6px 8px;
            font-size: 10px;
            background: rgba(255, 255, 255, 0.1);
            border: 1px solid rgba(255, 255, 255, 0.2);
        }

        .firework-type-btn.active {
            background: linear-gradient(45deg, #4ecdc4, #44a08d);
        }

        .performance-indicator {
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.8);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 8px;
            padding: 10px;
            color: white;
            font-size: 11px;
            z-index: 1000;
        }

        .fps-counter {
            color: #4ecdc4;
            font-weight: bold;
        }

        .particle-count {
            color: #ff6b6b;
        }

        .text-display {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 999;
            pointer-events: none;
            font-size: 60px;
            font-weight: bold;
            text-align: center;
            text-shadow: 0 0 20px rgba(255, 255, 255, 0.8);
            opacity: 0;
            transition: all 1s ease;
        }

        .preset-buttons {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            margin-top: 10px;
        }

        .preset-btn {
            flex: 1;
            min-width: 60px;
            font-size: 10px;
            padding: 5px;
        }

        .color-palette {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 5px;
            margin-top: 10px;
        }

        .color-btn {
            width: 30px;
            height: 30px;
            border-radius: 50%;
            border: 2px solid transparent;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .color-btn.active {
            border-color: white;
            box-shadow: 0 0 15px rgba(255, 255, 255, 0.8);
        }

        .auto-mode-controls {
            display: flex;
            gap: 5px;
            margin-top: 10px;
        }

        @keyframes textPulse {
            0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
            50% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
            100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
        }

        .text-display.show {
            animation: textPulse 3s ease-in-out;
        }
    </style>
</head>
<body>
    <canvas id="fireworksCanvas"></canvas>
    
    <div class="ui-overlay">
        <div class="ui-panel">
            <h3 style="margin-bottom: 15px; color: #4ecdc4; font-size: 14px;">🎆 烟花控制台</h3>
            
            <div class="control-group">
                <label>烟花类型</label>
                <div class="firework-type-grid">
                    <button class="firework-type-btn active" data-type="burst">爆裂</button>
                    <button class="firework-type-btn" data-type="ring">环形</button>
                    <button class="firework-type-btn" data-type="heart">心形</button>
                    <button class="firework-type-btn" data-type="star">星形</button>
                    <button class="firework-type-btn" data-type="spiral">螺旋</button>
                    <button class="firework-type-btn" data-type="fountain">喷泉</button>
                </div>
            </div>

            <div class="control-group">
                <label>强度设置</label>
                <div class="control-row">
                    <span style="font-size: 10px;">粒子数</span>
                    <input type="range" id="particleCount" min="20" max="200" value="80">
                    <span class="value-display" id="particleCountValue">80</span>
                </div>
                <div class="control-row">
                    <span style="font-size: 10px;">爆炸力</span>
                    <input type="range" id="explosionForce" min="1" max="10" value="5" step="0.1">
                    <span class="value-display" id="explosionForceValue">5.0</span>
                </div>
                <div class="control-row">
                    <span style="font-size: 10px;">重力</span>
                    <input type="range" id="gravity" min="0" max="1" value="0.3" step="0.01">
                    <span class="value-display" id="gravityValue">0.30</span>
                </div>
            </div>

            <div class="control-group">
                <label>视觉效果</label>
                <div class="control-row">
                    <span style="font-size: 10px;">拖尾长度</span>
                    <input type="range" id="trailLength" min="0.1" max="1" value="0.95" step="0.01">
                    <span class="value-display" id="trailLengthValue">0.95</span>
                </div>
                <div class="control-row">
                    <span style="font-size: 10px;">发光强度</span>
                    <input type="range" id="glowIntensity" min="0" max="50" value="20">
                    <span class="value-display" id="glowIntensityValue">20</span>
                </div>
            </div>

            <div class="control-group">
                <label>颜色主题</label>
                <div class="color-palette">
                    <div class="color-btn active" style="background: linear-gradient(45deg, #ff6b6b, #feca57)" data-colors="#ff6b6b,#feca57,#48dbfb,#ff9ff3"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #00d2ff, #3a7bd5)" data-colors="#00d2ff,#3a7bd5,#74b9ff,#0984e3"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #a8edea, #fed6e3)" data-colors="#a8edea,#fed6e3,#ffeaa7,#fab1a0"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #ff9a9e, #fecfef)" data-colors="#ff9a9e,#fecfef,#ffecd2,#fcb69f"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #667eea, #764ba2)" data-colors="#667eea,#764ba2,#f093fb,#f5576c"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #4ecdc4, #44a08d)" data-colors="#4ecdc4,#44a08d,#96fbc4,#f9ca24"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #ffeaa7, #fab1a0)" data-colors="#ffeaa7,#fab1a0,#ff7675,#fd79a8"></div>
                    <div class="color-btn" style="background: linear-gradient(45deg, #a29bfe, #6c5ce7)" data-colors="#a29bfe,#6c5ce7,#fd79a8,#fdcb6e"></div>
                </div>
            </div>
        </div>

        <div class="ui-panel">
            <h3 style="margin-bottom: 15px; color: #4ecdc4; font-size: 14px;">🎮 播放模式</h3>
            
            <div class="control-group">
                <button id="autoMode" style="width: 100%; margin-bottom: 10px;">自动模式</button>
                <div class="auto-mode-controls">
                    <button class="preset-btn" onclick="showText('新年快乐')">新年快乐</button>
                    <button class="preset-btn" onclick="showText('生日快乐')">生日快乐</button>
                    <button class="preset-btn" onclick="showText('恭喜发财')">恭喜发财</button>
                </div>
                <div class="auto-mode-controls">
                    <button class="preset-btn" onclick="showText('I ❤️ U')">I ❤️ U</button>
                    <button class="preset-btn" onclick="showText('HAPPY')">HAPPY</button>
                    <button class="preset-btn" onclick="showText('🎉')">🎉</button>
                </div>
            </div>

            <div class="preset-buttons">
                <button class="preset-btn" onclick="setPreset('romantic')">浪漫</button>
                <button class="preset-btn" onclick="setPreset('celebration')">庆典</button>
                <button class="preset-btn" onclick="setPreset('gentle')">温柔</button>
                <button class="preset-btn" onclick="setPreset('intense')">激烈</button>
            </div>

            <button onclick="clearCanvas()" style="width: 100%; margin-top: 10px; background: linear-gradient(45deg, #ff7675, #d63031);">清空画面</button>
        </div>
    </div>

    <div class="performance-indicator">
        <div class="fps-counter">FPS: <span id="fpsCounter">60</span></div>
        <div class="particle-count">粒子: <span id="particleCounter">0</span></div>
        <div style="color: #ffeaa7;">内存: <span id="memoryUsage">0MB</span></div>
    </div>

    <div class="text-display" id="textDisplay"></div>

    <script>
        class FireworkSimulator {
            constructor() {
                this.canvas = document.getElementById('fireworksCanvas');
                this.ctx = this.canvas.getContext('2d');
                this.particles = [];
                this.trails = [];
                this.settings = {
                    particleCount: 80,
                    explosionForce: 5,
                    gravity: 0.3,
                    trailLength: 0.95,
                    glowIntensity: 20,
                    currentType: 'burst',
                    colors: ['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3']
                };
                
                this.performance = {
                    fps: 0,
                    frameCount: 0,
                    lastTime: performance.now(),
                    particlePool: [],
                    maxParticles: 5000
                };

                this.autoMode = false;
                this.autoInterval = null;
                
                this.init();
                this.setupEventListeners();
                this.animate();
                this.updatePerformanceStats();
            }

            init() {
                this.resizeCanvas();
                window.addEventListener('resize', () => this.resizeCanvas());
                
                // 预创建粒子池以优化性能
                for (let i = 0; i < this.performance.maxParticles; i++) {
                    this.performance.particlePool.push(this.createParticle(0, 0, 0, 0, '#ffffff'));
                }
            }

            resizeCanvas() {
                this.canvas.width = window.innerWidth;
                this.canvas.height = window.innerHeight;
            }

            setupEventListeners() {
                // 鼠标点击事件
                this.canvas.addEventListener('click', (e) => {
                    if (!this.autoMode) {
                        const rect = this.canvas.getBoundingClientRect();
                        const x = e.clientX - rect.left;
                        const y = e.clientY - rect.top;
                        this.createFirework(x, y);
                    }
                });

                // 控制面板事件
                this.setupControlListeners();
            }

            setupControlListeners() {
                // 范围滑块
                ['particleCount', 'explosionForce', 'gravity', 'trailLength', 'glowIntensity'].forEach(id => {
                    const slider = document.getElementById(id);
                    const valueDisplay = document.getElementById(id + 'Value');
                    
                    slider.addEventListener('input', (e) => {
                        const value = parseFloat(e.target.value);
                        this.settings[id] = value;
                        valueDisplay.textContent = id === 'explosionForce' || id === 'gravity' || id === 'trailLength' ? 
                            value.toFixed(2) : Math.round(value);
                    });
                });

                // 烟花类型按钮
                document.querySelectorAll('.firework-type-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        document.querySelectorAll('.firework-type-btn').forEach(b => b.classList.remove('active'));
                        e.target.classList.add('active');
                        this.settings.currentType = e.target.dataset.type;
                    });
                });

                // 颜色主题按钮
                document.querySelectorAll('.color-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        document.querySelectorAll('.color-btn').forEach(b => b.classList.remove('active'));
                        e.target.classList.add('active');
                        this.settings.colors = e.target.dataset.colors.split(',');
                    });
                });

                // 自动模式按钮
                document.getElementById('autoMode').addEventListener('click', () => {
                    this.toggleAutoMode();
                });
            }

            createParticle(x, y, vx, vy, color) {
                return {
                    x, y, vx, vy, color,
                    life: 1,
                    decay: Math.random() * 0.02 + 0.01,
                    size: Math.random() * 3 + 1,
                    alpha: 1,
                    trail: []
                };
            }

            getParticleFromPool() {
                return this.performance.particlePool.pop() || this.createParticle(0, 0, 0, 0, '#ffffff');
            }

            returnParticleToPool(particle) {
                // 重置粒子属性
                particle.trail = [];
                particle.life = 1;
                particle.alpha = 1;
                this.performance.particlePool.push(particle);
            }

            createFirework(x, y) {
                const colors = this.settings.colors;
                const particleCount = this.settings.particleCount;
                const force = this.settings.explosionForce;

                // 发射阶段 - 创建上升的火箭
                const rocket = this.getParticleFromPool();
                Object.assign(rocket, {
                    x: x,
                    y: this.canvas.height,
                    vx: (Math.random() - 0.5) * 2,
                    vy: -15,
                    color: colors[Math.floor(Math.random() * colors.length)],
                    isRocket: true,
                    targetY: y,
                    life: 1,
                    decay: 0.005,
                    size: 3,
                    alpha: 1,
                    trail: []
                });
                
                this.particles.push(rocket);
            }

            explodeFirework(x, y) {
                const colors = this.settings.colors;
                const particleCount = this.settings.particleCount;
                const force = this.settings.explosionForce;
                const type = this.settings.currentType;

                for (let i = 0; i < particleCount; i++) {
                    const particle = this.getParticleFromPool();
                    const color = colors[Math.floor(Math.random() * colors.length)];
                    
                    let vx, vy;
                    
                    switch (type) {
                        case 'burst':
                            const angle = (Math.PI * 2 * i) / particleCount;
                            const speed = Math.random() * force + 2;
                            vx = Math.cos(angle) * speed;
                            vy = Math.sin(angle) * speed;
                            break;
                            
                        case 'ring':
                            const ringAngle = (Math.PI * 2 * i) / particleCount;
                            const ringSpeed = force * 0.8;
                            vx = Math.cos(ringAngle) * ringSpeed;
                            vy = Math.sin(ringAngle) * ringSpeed;
                            break;
                            
                        case 'heart':
                            const t = (i / particleCount) * Math.PI * 2;
                            const heartX = 16 * Math.pow(Math.sin(t), 3);
                            const heartY = -(13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t));
                            vx = heartX * force * 0.1;
                            vy = heartY * force * 0.1;
                            break;
                            
                        case 'star':
                            const starAngle = (Math.PI * 2 * i) / particleCount;
                            const starSpeed = (i % 2 === 0) ? force * 1.2 : force * 0.6;
                            vx = Math.cos(starAngle) * starSpeed;
                            vy = Math.sin(starAngle) * starSpeed;
                            break;
                            
                        case 'spiral':
                            const spiralAngle = (Math.PI * 4 * i) / particleCount;
                            const spiralRadius = (i / particleCount) * force;
                            vx = Math.cos(spiralAngle) * spiralRadius;
                            vy = Math.sin(spiralAngle) * spiralRadius;
                            break;
                            
                        case 'fountain':
                            vx = (Math.random() - 0.5) * force * 0.5;
                            vy = -Math.random() * force * 1.5;
                            break;
                            
                        default:
                            vx = (Math.random() - 0.5) * force * 2;
                            vy = (Math.random() - 0.5) * force * 2;
                    }

                    Object.assign(particle, {
                        x, y, vx, vy, color,
                        life: 1,
                        decay: Math.random() * 0.02 + 0.01,
                        size: Math.random() * 3 + 1,
                        alpha: 1,
                        trail: [],
                        isRocket: false
                    });
                    
                    this.particles.push(particle);
                }
            }

            updateParticles() {
                // 使用倒序循环以安全删除元素
                for (let i = this.particles.length - 1; i >= 0; i--) {
                    const particle = this.particles[i];
                    
                    if (particle.isRocket) {
                        // 火箭上升逻辑
                        particle.x += particle.vx;
                        particle.y += particle.vy;
                        particle.vy += 0.2; // 重力影响
                        
                        // 添加拖尾
                        particle.trail.push({ x: particle.x, y: particle.y, alpha: particle.alpha });
                        if (particle.trail.length > 10) {
                            particle.trail.shift();
                        }
                        
                        // 到达目标高度或开始下降时爆炸
                        if (particle.y <= particle.targetY || particle.vy >= 0) {
                            this.explodeFirework(particle.x, particle.y);
                            this.returnParticleToPool(particle);
                            this.particles.splice(i, 1);
                            continue;
                        }
                    } else {
                        // 普通粒子逻辑
                        particle.x += particle.vx;
                        particle.y += particle.vy;
                        particle.vy += this.settings.gravity * 0.1;
                        particle.vx *= 0.99; // 空气阻力
                        
                        particle.life -= particle.decay;
                        particle.alpha = particle.life;
                        
                        // 添加拖尾
                        particle.trail.push({ x: particle.x, y: particle.y, alpha: particle.alpha });
                        if (particle.trail.length > 20) {
                            particle.trail.shift();
                        }
                        
                        // 移除死亡粒子
                        if (particle.life <= 0 || particle.y > this.canvas.height + 50) {
                            this.returnParticleToPool(particle);
                            this.particles.splice(i, 1);
                        }
                    }
                }
            }

            renderParticles() {
                this.ctx.globalCompositeOperation = 'lighter';
                
                for (const particle of this.particles) {
                    // 绘制拖尾
                    if (particle.trail.length > 1) {
                        this.ctx.beginPath();
                        this.ctx.moveTo(particle.trail[0].x, particle.trail[0].y);
                        
                        for (let i = 1; i < particle.trail.length; i++) {
                            const point = particle.trail[i];
                            const alpha = point.alpha * (i / particle.trail.length) * this.settings.trailLength;
                            this.ctx.globalAlpha = alpha;
                            this.ctx.strokeStyle = particle.color;
                            this.ctx.lineWidth = particle.size * 0.5;
                            this.ctx.lineTo(point.x, point.y);
                            this.ctx.stroke();
                            this.ctx.beginPath();
                            this.ctx.moveTo(point.x, point.y);
                        }
                    }
                    
                    // 绘制粒子本体
                    this.ctx.globalAlpha = particle.alpha;
                    
                    // 发光效果
                    if (this.settings.glowIntensity > 0) {
                        this.ctx.shadowColor = particle.color;
                        this.ctx.shadowBlur = this.settings.glowIntensity;
                    }
                    
                    this.ctx.fillStyle = particle.color;
                    this.ctx.beginPath();
                    this.ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
                    this.ctx.fill();
                    
                    // 重置阴影
                    this.ctx.shadowBlur = 0;
                }
                
                this.ctx.globalCompositeOperation = 'source-over';
                this.ctx.globalAlpha = 1;
            }

            clearCanvas() {
                // 使用部分透明度创建拖尾效果
                this.ctx.fillStyle = `rgba(0, 4, 40, ${1 - this.settings.trailLength})`;
                this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
            }

            toggleAutoMode() {
                this.autoMode = !this.autoMode;
                const btn = document.getElementById('autoMode');
                
                if (this.autoMode) {
                    btn.classList.add('active');
                    btn.textContent = '停止自动';
                    this.startAutoMode();
                } else {
                    btn.classList.remove('active');
                    btn.textContent = '自动模式';
                    this.stopAutoMode();
                }
            }

            startAutoMode() {
                this.autoInterval = setInterval(() => {
                    const x = Math.random() * this.canvas.width;
                    const y = Math.random() * this.canvas.height * 0.6 + this.canvas.height * 0.1;
                    this.createFirework(x, y);
                }, 1000 + Math.random() * 2000);
            }

            stopAutoMode() {
                if (this.autoInterval) {
                    clearInterval(this.autoInterval);
                    this.autoInterval = null;
                }
            }

            updatePerformanceStats() {
                setInterval(() => {
                    const now = performance.now();
                    this.performance.fps = Math.round(1000 / (now - this.performance.lastTime));
                    this.performance.lastTime = now;
                    
                    document.getElementById('fpsCounter').textContent = this.performance.fps;
                    document.getElementById('particleCounter').textContent = this.particles.length;
                    
                    // 简单的内存使用估算
                    const memoryUsage = (this.particles.length * 0.001).toFixed(1);
                    document.getElementById('memoryUsage').textContent = memoryUsage;
                }, 1000);
            }

            animate() {
                this.clearCanvas();
                this.updateParticles();
                this.renderParticles();
                
                this.performance.frameCount++;
                requestAnimationFrame(() => this.animate());
            }
        }

        // 全局函数
        function setPreset(type) {
            const simulator = window.fireworkSimulator;
            
            switch (type) {
                case 'romantic':
                    simulator.settings.colors = ['#ff9a9e', '#fecfef', '#ffecd2', '#fcb69f'];
                    simulator.settings.particleCount = 60;
                    simulator.settings.explosionForce = 3;
                    simulator.settings.gravity = 0.2;
                    document.querySelector('[data-type="heart"]').click();
                    break;
                case 'celebration':
                    simulator.settings.colors = ['#ff6b6b', '#feca57', '#48dbfb', '#ff9ff3'];
                    simulator.settings.particleCount = 120;
                    simulator.settings.explosionForce = 7;
                    simulator.settings.gravity = 0.4;
                    document.querySelector('[data-type="burst"]').click();
                    break;
                case 'gentle':
                    simulator.settings.colors = ['#a8edea', '#fed6e3', '#ffeaa7', '#fab1a0'];
                    simulator.settings.particleCount = 40;
                    simulator.settings.explosionForce = 2;
                    simulator.settings.gravity = 0.1;
                    document.querySelector('[data-type="ring"]').click();
                    break;
                case 'intense':
                    simulator.settings.colors = ['#667eea', '#764ba2', '#f093fb', '#f5576c'];
                    simulator.settings.particleCount = 200;
                    simulator.settings.explosionForce = 10;
                    simulator.settings.gravity = 0.6;
                    document.querySelector('[data-type="star"]').click();
                    break;
            }
            
            // 更新UI显示
            updateSliderValues();
        }

        function updateSliderValues() {
            const simulator = window.fireworkSimulator;
            const settings = simulator.settings;
            
            ['particleCount', 'explosionForce', 'gravity', 'trailLength', 'glowIntensity'].forEach(key => {
                const slider = document.getElementById(key);
                const valueDisplay = document.getElementById(key + 'Value');
                
                if (slider && settings[key] !== undefined) {
                    slider.value = settings[key];
                    valueDisplay.textContent = ['explosionForce', 'gravity', 'trailLength'].includes(key) ? 
                        settings[key].toFixed(2) : Math.round(settings[key]);
                }
            });
        }

        function showText(text) {
            const textDisplay = document.getElementById('textDisplay');
            textDisplay.textContent = text;
            textDisplay.classList.remove('show');
            
            // 触发重排以重置动画
            textDisplay.offsetHeight;
            textDisplay.classList.add('show');
            
            // 同时创建特殊烟花效果
            const simulator = window.fireworkSimulator;
            const canvas = simulator.canvas;
            
            // 创建文字形状的烟花
            setTimeout(() => {
                for (let i = 0; i < 5; i++) {
                    setTimeout(() => {
                        const x = canvas.width * 0.2 + Math.random() * canvas.width * 0.6;
                        const y = canvas.height * 0.2 + Math.random() * canvas.height * 0.4;
                        simulator.createFirework(x, y);
                    }, i * 200);
                }
            }, 500);
        }

        function clearCanvas() {
            const simulator = window.fireworkSimulator;
            simulator.particles = [];
            simulator.ctx.fillStyle = 'rgba(0, 4, 40, 1)';
            simulator.ctx.fillRect(0, 0, simulator.canvas.width, simulator.canvas.height);
        }

        // 高级特效类
        class AdvancedEffects {
            constructor(simulator) {
                this.simulator = simulator;
                this.backgroundParticles = [];
                this.musicMode = false;
                this.shakeIntensity = 0;
            }

            // 背景星空效果
            createStarField() {
                for (let i = 0; i < 100; i++) {
                    this.backgroundParticles.push({
                        x: Math.random() * this.simulator.canvas.width,
                        y: Math.random() * this.simulator.canvas.height,
                        size: Math.random() * 2,
                        twinkle: Math.random() * 0.02 + 0.005,
                        alpha: Math.random()
                    });
                }
            }

            updateStarField() {
                const ctx = this.simulator.ctx;
                ctx.globalCompositeOperation = 'lighter';
                
                for (const star of this.backgroundParticles) {
                    star.alpha += star.twinkle;
                    if (star.alpha > 1 || star.alpha < 0) {
                        star.twinkle = -star.twinkle;
                    }
                    
                    ctx.globalAlpha = Math.abs(star.alpha) * 0.3;
                    ctx.fillStyle = '#ffffff';
                    ctx.beginPath();
                    ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
                    ctx.fill();
                }
                
                ctx.globalCompositeOperation = 'source-over';
                ctx.globalAlpha = 1;
            }

            // 屏幕震动效果
            screenShake(intensity = 5) {
                this.shakeIntensity = intensity;
                const canvas = this.simulator.canvas;
                
                const animate = () => {
                    if (this.shakeIntensity > 0) {
                        const shakeX = (Math.random() - 0.5) * this.shakeIntensity;
                        const shakeY = (Math.random() - 0.5) * this.shakeIntensity;
                        
                        canvas.style.transform = `translate(${shakeX}px, ${shakeY}px)`;
                        this.shakeIntensity *= 0.9;
                        
                        requestAnimationFrame(animate);
                    } else {
                        canvas.style.transform = 'translate(0, 0)';
                    }
                };
                
                animate();
            }

            // 音乐可视化模式
            toggleMusicMode() {
                this.musicMode = !this.musicMode;
                if (this.musicMode) {
                    this.startMusicVisualization();
                }
            }

            startMusicVisualization() {
                // 模拟音频数据创建节拍同步烟花
                const beatInterval = setInterval(() => {
                    if (!this.musicMode) {
                        clearInterval(beatInterval);
                        return;
                    }
                    
                    const intensity = Math.random() * 0.8 + 0.2;
                    const count = Math.floor(intensity * 3) + 1;
                    
                    for (let i = 0; i < count; i++) {
                        const x = this.simulator.canvas.width * (0.2 + Math.random() * 0.6);
                        const y = this.simulator.canvas.height * (0.1 + Math.random() * 0.5);
                        this.simulator.createFirework(x, y);
                    }
                    
                    if (intensity > 0.7) {
                        this.screenShake(8);
                    }
                }, 600 + Math.random() * 400);
            }
        }

        // 粒子系统优化类
        class ParticleSystemOptimizer {
            constructor(simulator) {
                this.simulator = simulator;
                this.cullingEnabled = true;
                this.lodEnabled = true;
                this.maxParticlesPerFrame = 300;
            }

            // 视锥剔除
            cullParticles() {
                if (!this.cullingEnabled) return;
                
                const canvas = this.simulator.canvas;
                const margin = 50;
                
                this.simulator.particles = this.simulator.particles.filter(particle => {
                    return particle.x > -margin && 
                           particle.x < canvas.width + margin &&
                           particle.y > -margin && 
                           particle.y < canvas.height + margin;
                });
            }

            // 细节层次(LOD)系统
            applyLOD() {
                if (!this.lodEnabled) return;
                
                const canvas = this.simulator.canvas;
                const centerX = canvas.width / 2;
                const centerY = canvas.height / 2;
                
                for (const particle of this.simulator.particles) {
                    const distance = Math.sqrt(
                        Math.pow(particle.x - centerX, 2) + 
                        Math.pow(particle.y - centerY, 2)
                    );
                    
                    const maxDistance = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height) / 2;
                    const lodLevel = distance / maxDistance;
                    
                    // 根据距离调整粒子细节
                    if (lodLevel > 0.8) {
                        particle.size *= 0.5;
                        particle.trail = particle.trail.slice(-5); // 减少拖尾长度
                    } else if (lodLevel > 0.6) {
                        particle.trail = particle.trail.slice(-10);
                    }
                }
            }

            // 动态质量调整
            adjustQuality() {
                const fps = this.simulator.performance.fps;
                const particleCount = this.simulator.particles.length;
                
                if (fps < 30 && particleCount > 200) {
                    // 降低质量
                    this.simulator.settings.trailLength = Math.max(0.8, this.simulator.settings.trailLength - 0.05);
                    this.simulator.settings.glowIntensity = Math.max(5, this.simulator.settings.glowIntensity - 2);
                } else if (fps > 55 && particleCount < 100) {
                    // 提高质量
                    this.simulator.settings.trailLength = Math.min(0.98, this.simulator.settings.trailLength + 0.02);
                    this.simulator.settings.glowIntensity = Math.min(30, this.simulator.settings.glowIntensity + 1);
                }
            }
        }

        // 初始化模拟器
        document.addEventListener('DOMContentLoaded', () => {
            window.fireworkSimulator = new FireworkSimulator();
            window.advancedEffects = new AdvancedEffects(window.fireworkSimulator);
            window.optimizer = new ParticleSystemOptimizer(window.fireworkSimulator);
            
            // 创建星空背景
            window.advancedEffects.createStarField();
            
            // 添加高级特效到动画循环
            const originalAnimate = window.fireworkSimulator.animate;
            window.fireworkSimulator.animate = function() {
                this.clearCanvas();
                
                // 绘制星空背景
                window.advancedEffects.updateStarField();
                
                this.updateParticles();
                this.renderParticles();
                
                // 应用优化
                window.optimizer.cullParticles();
                window.optimizer.applyLOD();
                window.optimizer.adjustQuality();
                
                this.performance.frameCount++;
                requestAnimationFrame(() => this.animate());
            };
            
            // 添加键盘快捷键
            document.addEventListener('keydown', (e) => {
                switch(e.key) {
                    case ' ':
                        e.preventDefault();
                        document.getElementById('autoMode').click();
                        break;
                    case 'c':
                        clearCanvas();
                        break;
                    case 'm':
                        window.advancedEffects.toggleMusicMode();
                        break;
                    case '1':
                        document.querySelector('[data-type="burst"]').click();
                        break;
                    case '2':
                        document.querySelector('[data-type="ring"]').click();
                        break;
                    case '3':
                        document.querySelector('[data-type="heart"]').click();
                        break;
                    case '4':
                        document.querySelector('[data-type="star"]').click();
                        break;
                    case '5':
                        document.querySelector('[data-type="spiral"]').click();
                        break;
                    case '6':
                        document.querySelector('[data-type="fountain"]').click();
                        break;
                }
            });
            
            // 添加触摸支持
            let touchStartTime;
            window.fireworkSimulator.canvas.addEventListener('touchstart', (e) => {
                e.preventDefault();
                touchStartTime = Date.now();
            });
            
            window.fireworkSimulator.canvas.addEventListener('touchend', (e) => {
                e.preventDefault();
                const touchDuration = Date.now() - touchStartTime;
                
                if (touchDuration < 500) { // 短触摸
                    const touch = e.changedTouches[0];
                    const rect = e.target.getBoundingClientRect();
                    const x = touch.clientX - rect.left;
                    const y = touch.clientY - rect.top;
                    window.fireworkSimulator.createFirework(x, y);
                }
            });
            
            // 性能监控
            setInterval(() => {
                const memoryInfo = performance.memory;
                if (memoryInfo) {
                    const memoryUsage = (memoryInfo.usedJSHeapSize / 1024 / 1024).toFixed(1);
                    document.getElementById('memoryUsage').textContent = memoryUsage + 'MB';
                }
            }, 2000);
            
            console.log('🎆 Super Fireworks Simulator Loaded!');
            console.log('快捷键: 空格键(自动模式), C(清屏), M(音乐模式), 1-6(切换类型)');
        });

        // 导出配置功能
        function exportSettings() {
            const settings = window.fireworkSimulator.settings;
            const dataStr = JSON.stringify(settings, null, 2);
            const dataBlob = new Blob([dataStr], {type:'application/json'});
            
            const link = document.createElement('a');
            link.href = URL.createObjectURL(dataBlob);
            link.download = 'fireworks-settings.json';
            link.click();
        }

        // 导入配置功能
        function importSettings(event) {
            const file = event.target.files[0];
            if (!file) return;
            
            const reader = new FileReader();
            reader.onload = function(e) {
                try {
                    const settings = JSON.parse(e.target.result);
                    Object.assign(window.fireworkSimulator.settings, settings);
                    updateSliderValues();
                    console.log('设置已导入成功!');
                } catch (error) {
                    console.error('导入设置失败:', error);
                }
            };
            reader.readAsText(file);
        }

        // 截图功能
        function captureScreenshot() {
            const canvas = window.fireworkSimulator.canvas;
            const link = document.createElement('a');
            link.download = `fireworks-${Date.now()}.png`;
            link.href = canvas.toDataURL();
            link.click();
        }
    </script>
</body>

        
编辑器加载中
预览
控制台