分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TRIZ 理想解 - 逆向脉冲防糊网系统</title>
    <style>
        :root {
            --bg-color: #050508;
            --panel-bg: rgba(15, 20, 30, 0.75);
            --panel-border: rgba(6, 182, 212, 0.3);
            --text-main: #e2e8f0;
            --text-muted: #94a3b8;
            --accent-cyan: #06b6d4;
            --accent-green: #10b981;
            --accent-yellow: #f59e0b;
            --accent-red: #ef4444;
            --mesh-color: #475569;
            --fluid-dirty: rgba(245, 158, 11, 0.4);
            --fluid-clean: rgba(16, 185, 129, 0.4);
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
            overflow: hidden;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: 
                linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
                linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
            background-size: 40px 40px;
        }

        /* 绝对定位的信息面板,严格控制尺寸和位置,避免遮挡 */
        .info-panel {
            position: absolute;
            top: 24px;
            left: 24px;
            width: 280px;
            background: var(--panel-bg);
            backdrop-filter: blur(12px);
            -webkit-backdrop-filter: blur(12px);
            border: 1px solid var(--panel-border);
            border-radius: 8px;
            padding: 16px;
            z-index: 10;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
        }

        .info-panel h1 {
            font-size: 14px;
            font-weight: 600;
            color: var(--accent-cyan);
            margin-bottom: 12px;
            letter-spacing: 1px;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .info-panel h1::before {
            content: '';
            display: block;
            width: 6px;
            height: 6px;
            background-color: var(--accent-cyan);
            border-radius: 50%;
            box-shadow: 0 0 8px var(--accent-cyan);
        }

        .info-list {
            list-style: none;
            font-size: 11px;
            line-height: 1.6;
            color: var(--text-muted);
            font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
        }

        .info-list li {
            margin-bottom: 8px;
            padding-bottom: 8px;
            border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
        }
        .info-list li:last-child {
            border-bottom: none;
            margin-bottom: 0;
            padding-bottom: 0;
        }

        .highlight {
            color: var(--text-main);
            font-weight: 500;
        }

        /* 状态指示器 */
        .status-indicator {
            position: absolute;
            bottom: 24px;
            left: 24px;
            display: flex;
            align-items: center;
            gap: 16px;
            background: var(--panel-bg);
            border: 1px solid rgba(255,255,255,0.1);
            padding: 10px 16px;
            border-radius: 30px;
            font-family: 'JetBrains Mono', monospace;
            font-size: 11px;
            z-index: 10;
        }

        .timer-circle {
            width: 24px;
            height: 24px;
            transform: rotate(-90deg);
        }
        
        .timer-circle circle {
            fill: none;
            stroke-width: 3;
        }
        .timer-bg { stroke: rgba(255,255,255,0.1); }
        .timer-progress {
            stroke: var(--accent-cyan);
            stroke-dasharray: 63; /* 2 * pi * r (approx r=10) */
            stroke-dashoffset: 0;
            transition: stroke-dashoffset 0.1s linear;
        }

        .status-text {
            color: var(--accent-cyan);
            text-transform: uppercase;
            letter-spacing: 1px;
            min-width: 80px;
        }

        /* 动画容器 */
        .anim-container {
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        svg {
            width: 85%;
            max-width: 1200px;
            height: auto;
            max-height: 85vh;
            filter: drop-shadow(0 0 30px rgba(6, 182, 212, 0.05));
        }

        /* 粒子和流体样式 */
        .particle {
            fill: #94a3b8;
            transition: fill 0.3s ease;
        }
        .particle.stuck {
            fill: var(--accent-red);
            filter: drop-shadow(0 0 4px var(--accent-red));
        }
        
        .blast-wave {
            fill: url(#blast-grad);
            opacity: 0;
            mix-blend-mode: screen;
            transform-origin: bottom center;
        }

        /* CSS 动画类 */
        .pulse-active .blast-wave {
            animation: blast-anim 0.5s cubic-bezier(0.1, 0.9, 0.2, 1) forwards;
        }

        @keyframes blast-anim {
            0% { opacity: 0; transform: scaleY(0.1); }
            20% { opacity: 0.9; transform: scaleY(1.2); }
            80% { opacity: 0.5; transform: scaleY(1); }
            100% { opacity: 0; transform: scaleY(0.8); }
        }

        .nozzle-glow {
            fill: var(--accent-cyan);
            opacity: 0;
            transition: opacity 0.1s;
        }
        .pulse-active .nozzle-glow {
            opacity: 0.8;
            filter: blur(4px);
        }

        .valve-indicator {
            fill: #333;
            transition: fill 0.1s;
        }
        .pulse-active .valve-indicator {
            fill: var(--accent-cyan);
        }

        /* 扫描线效果增加科技感 */
        .scanline {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, 0.25) 51%);
            background-size: 100% 4px;
            pointer-events: none;
            z-index: 999;
            opacity: 0.3;
        }
    </style>
</head>
<body>

    <div class="scanline"></div>

    <!-- 信息面板 (紧凑, 边缘) -->
    <div class="info-panel">
        <h1>TRIZ 理想解: 逆向脉冲清网</h1>
        <ul class="info-list">
            <li><span class="highlight">最终理想解 (IFR):</span> 系统利用筛网下部的冗余空间与流体介质,自行清除孔隙堵塞,维持 100% 理想透液率。</li>
            <li><span class="highlight">核心机理:</span> 周期性高压脉冲射流 (0.4-0.6MPa) 从底层向上冲击,克服颗粒卡滞力。</li>
            <li><span class="highlight">资源利用:</span> 巧用下方死区布置 2mm 雾化排管,极少增加体积复杂度解决“透液”与“糊网”的物理矛盾。</li>
            <li><span class="highlight">参数设定:</span> 脉冲周期 10s (动画以 4s 演示), 爆发持续 0.5s。</li>
        </ul>
    </div>

    <!-- 底部状态指示 -->
    <div class="status-indicator">
        <svg class="timer-circle" viewBox="0 0 24 24">
            <circle class="timer-bg" cx="12" cy="12" r="10"></circle>
            <circle class="timer-progress" cx="12" cy="12" r="10" id="timerProgress"></circle>
        </svg>
        <div class="status-text" id="statusText">SYS.NORMAL</div>
        <div style="color: var(--text-muted);">P: <span id="pressureVal">0.1</span> MPa</div>
    </div>

    <!-- 核心动画区 -->
    <div class="anim-container">
        <svg viewBox="0 0 1000 500" preserveAspectRatio="xMidYMid meet" id="mainSvg">
            <defs>
                <!-- 渐变与滤镜 -->
                <linearGradient id="blast-grad" x1="0" y1="1" x2="0" y2="0">
                    <stop offset="0%" stop-color="#06b6d4" stop-opacity="0.9"/>
                    <stop offset="50%" stop-color="#2dd4bf" stop-opacity="0.5"/>
                    <stop offset="100%" stop-color="#fff" stop-opacity="0"/>
                </linearGradient>

                <linearGradient id="slurry-grad" x1="0" y1="0" x2="1" y2="0">
                    <stop offset="0%" stop-color="#f59e0b" stop-opacity="0.8"/>
                    <stop offset="100%" stop-color="#f59e0b" stop-opacity="0.1"/>
                </linearGradient>

                <linearGradient id="clean-grad" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="0%" stop-color="#10b981" stop-opacity="0.6"/>
                    <stop offset="100%" stop-color="#10b981" stop-opacity="0.0"/>
                </linearGradient>

                <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="6" result="blur" />
                    <feComposite in="SourceGraphic" in2="blur" operator="over" />
                </filter>
                
                <filter id="mesh-shadow" x="-10%" y="-10%" width="120%" height="120%">
                    <feDropShadow dx="0" dy="4" stdDeviation="4" flood-color="#000" flood-opacity="0.6"/>
                </filter>

                <!-- 网格图案 -->
                <pattern id="mesh-pattern" width="20" height="20" patternUnits="userSpaceOnUse">
                    <rect width="20" height="20" fill="none" />
                    <path d="M 20 0 L 0 0 0 20" fill="none" stroke="#64748b" stroke-width="2" />
                    <circle cx="0" cy="0" r="1.5" fill="#94a3b8" />
                </pattern>
                
                <!-- 喷嘴形状复用 -->
                <g id="nozzle">
                    <rect x="-6" y="0" width="12" height="15" fill="#334155" rx="2"/>
                    <polygon points="-4,0 4,0 2,-6 -2,-6" fill="#94a3b8" />
                    <circle cx="0" cy="8" r="3" fill="#1e293b" />
                    <!-- 喷嘴发光底座 -->
                    <circle cx="0" cy="-6" r="4" class="nozzle-glow" />
                </g>
            </defs>

            <!-- 背景辅助线 -->
            <g stroke="rgba(255,255,255,0.05)" stroke-width="1" stroke-dasharray="4 4">
                <line x1="100" y1="100" x2="900" y2="100" />
                <line x1="100" y1="400" x2="900" y2="400" />
            </g>

            <!-- 上层脏浆流体背景区 -->
            <path d="M 50 180 Q 250 170 450 185 T 950 180 L 950 240 L 50 240 Z" fill="url(#slurry-grad)" opacity="0.3">
                <animate attributeName="d" 
                    values="M 50 180 Q 250 170 450 185 T 950 180 L 950 240 L 50 240 Z;
                            M 50 185 Q 250 195 450 175 T 950 185 L 950 240 L 50 240 Z;
                            M 50 180 Q 250 170 450 185 T 950 180 L 950 240 L 50 240 Z" 
                    dur="3s" repeatCount="indefinite"/>
            </path>

            <!-- 下层透液流体背景区 -->
            <rect x="150" y="260" width="700" height="150" fill="url(#clean-grad)" opacity="0.4" />
            <!-- 透液波纹动画 -->
            <g opacity="0.2" stroke="#10b981" stroke-width="2" fill="none">
                <path d="M 200 300 Q 220 320 200 340"><animate attributeName="stroke-dashoffset" values="40;0" dur="1s" repeatCount="indefinite" stroke-dasharray="40"/></path>
                <path d="M 500 280 Q 520 310 500 350"><animate attributeName="stroke-dashoffset" values="50;0" dur="1.2s" repeatCount="indefinite" stroke-dasharray="50"/></path>
                <path d="M 800 320 Q 820 340 800 360"><animate attributeName="stroke-dashoffset" values="30;0" dur="0.8s" repeatCount="indefinite" stroke-dasharray="30"/></path>
            </g>

            <!-- 中间核心筛网结构 -->
            <g transform="translate(100, 240)" filter="url(#mesh-shadow)">
                <!-- 筛网框架 -->
                <rect x="0" y="0" width="800" height="20" fill="#1e293b" rx="4" stroke="#475569" stroke-width="2"/>
                <!-- 筛网网孔面 -->
                <rect x="10" y="0" width="780" height="8" fill="url(#mesh-pattern)" />
            </g>

            <!-- 脉冲装置与管道 (筛网下方) -->
            <g transform="translate(100, 380)">
                <!-- 进气/水主管道 -->
                <path d="M -50 0 L 820 0" stroke="#334155" stroke-width="16" stroke-linecap="round"/>
                <path d="M -50 0 L 820 0" stroke="#64748b" stroke-width="6" stroke-linecap="round"/>
                
                <!-- 电磁脉冲阀 (左侧) -->
                <rect x="-20" y="-15" width="30" height="30" fill="#1e293b" rx="4" stroke="#475569" stroke-width="2"/>
                <circle cx="-5" cy="0" r="8" class="valve-indicator" />
                <text x="-5" y="4" font-size="10" font-family="monospace" fill="#050508" text-anchor="middle" font-weight="bold">V</text>

                <!-- 喷嘴阵列与气流脉冲爆发区 (使用循环生成) -->
                <g transform="translate(100, -8)"><use href="#nozzle" /></g>
                <g transform="translate(250, -8)"><use href="#nozzle" /></g>
                <g transform="translate(400, -8)"><use href="#nozzle" /></g>
                <g transform="translate(550, -8)"><use href="#nozzle" /></g>
                <g transform="translate(700, -8)"><use href="#nozzle" /></g>
            </g>

            <!-- 脉冲爆发流场 (隐藏,在脉冲时显示) -->
            <g id="pulseLayer" transform="translate(100, 360)">
                <!-- 对应喷嘴位置的向上射流 -->
                <path d="M 80 0 L 120 0 L 150 -130 L 50 -130 Z" class="blast-wave" />
                <path d="M 230 0 L 270 0 L 300 -130 L 200 -130 Z" class="blast-wave" />
                <path d="M 380 0 L 420 0 L 450 -130 L 350 -130 Z" class="blast-wave" />
                <path d="M 530 0 L 570 0 L 600 -130 L 500 -130 Z" class="blast-wave" />
                <path d="M 680 0 L 720 0 L 750 -130 L 650 -130 Z" class="blast-wave" />
            </g>

            <!-- 动态粒子层,JS将在此注入粒子 -->
            <g id="particlesLayer"></g>

            <!-- UI 标尺与参数标识,增强工程感 -->
            <g font-family="monospace" font-size="10" fill="#64748b" opacity="0.8">
                <text x="50" y="245">SLURRY IN</text>
                <text x="920" y="245">SOLIDS OUT</text>
                <line x1="90" y1="250" x2="50" y2="250" stroke="#64748b" stroke-width="1" marker-end="url(#arrow)"/>
                <line x1="910" y1="250" x2="950" y2="250" stroke="#64748b" stroke-width="1" marker-end="url(#arrow)"/>
                
                <text x="50" y="420">PULSE MEDIA</text>
                <path d="M 50 405 L 80 405 L 80 380" stroke="#06b6d4" stroke-width="1" fill="none" opacity="0.5"/>
                
                <text x="920" y="340">FILTRATE</text>
                <line x1="900" y1="337" x2="950" y2="337" stroke="#10b981" stroke-width="1" stroke-dasharray="2 2"/>
            </g>
            
            <defs>
                <marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="4" markerHeight="4" orient="auto-start-reverse">
                    <path d="M 0 0 L 10 5 L 0 10 z" fill="#64748b" />
                </marker>
            </defs>
        </svg>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const svg = document.getElementById('mainSvg');
            const particlesLayer = document.getElementById('particlesLayer');
            const pulseLayer = document.getElementById('pulseLayer');
            const timerProgress = document.getElementById('timerProgress');
            const statusText = document.getElementById('statusText');
            const pressureVal = document.getElementById('pressureVal');
            
            // 系统参数设定
            const CYCLE_DURATION = 4000; // 总周期 4秒 (加速演示)
            const PULSE_DURATION = 500;  // 脉冲爆发 0.5秒
            const MAX_PRESSURE = 0.6;
            
            // 粒子状态存储
            let particles = [];
            let isPulsing = false;
            let cycleStartTime = performance.now();

            // 生成随机数
            const random = (min, max) => Math.random() * (max - min) + min;

            // 创建粒子
            function spawnParticle() {
                // 限制最大粒子数量以保证性能
                if (particles.length > 80) return;

                const isStuckType = Math.random() > 0.6; // 40% 的概率产生会糊网的大颗粒
                const r = isStuckType ? random(4, 7) : random(1.5, 3);
                const startY = random(180, 220);
                
                const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
                circle.setAttribute("cx", 50);
                circle.setAttribute("cy", startY);
                circle.setAttribute("r", r);
                circle.setAttribute("class", "particle");
                
                particlesLayer.appendChild(circle);

                const particleData = {
                    el: circle,
                    x: 50,
                    y: startY,
                    vx: random(1.5, 3), // 水平流速
                    vy: 0,
                    r: r,
                    isStuckType: isStuckType,
                    state: 'flowing' // flowing, stuck, blasted, falling
                };
                
                particles.push(particleData);
            }

            // 动画主循环
            function animateSystem(timestamp) {
                // 1. 周期时间计算
                let elapsed = timestamp - cycleStartTime;
                if (elapsed >= CYCLE_DURATION) {
                    cycleStartTime = timestamp;
                    elapsed = 0;
                    triggerPulse();
                }

                // UI 更新: 倒计时环
                const progressRatio = elapsed / CYCLE_DURATION;
                const dashoffset = 63 * (1 - progressRatio);
                timerProgress.style.strokeDashoffset = isPulsing ? 0 : dashoffset;
                
                // 压力表模拟
                if (isPulsing) {
                    pressureVal.innerText = (0.4 + Math.random()*0.2).toFixed(2);
                } else {
                    // 缓慢充能
                    const p = 0.1 + (0.3 * progressRatio);
                    pressureVal.innerText = p.toFixed(2);
                }

                // 2. 持续生成粒子
                if (!isPulsing && Math.random() > 0.4) {
                    spawnParticle();
                }

                // 3. 更新粒子物理状态
                const meshY = 236; // 筛网表面高度
                
                for (let i = particles.length - 1; i >= 0; i--) {
                    let p = particles[i];

                    if (p.state === 'flowing') {
                        // 在流体中向右运动,同时受到重力缓慢下沉
                        p.x += p.vx;
                        p.y += 0.3; // 重力下沉倾向

                        // 碰到筛网
                        if (p.y + p.r >= meshY) {
                            if (p.isStuckType) {
                                // 大颗粒糊网
                                p.y = meshY - p.r;
                                p.state = 'stuck';
                                p.el.classList.add('stuck');
                            } else {
                                // 小颗粒透网
                                p.state = 'falling';
                                p.vy = random(1, 3);
                            }
                        }
                        // 正常流出屏幕右侧
                        if (p.x > 950) p.state = 'dead';

                    } else if (p.state === 'stuck') {
                        // 糊网颗粒,随筛网微小震动缓慢右移 (模拟实际振动筛)
                        p.x += 0.2;
                        if (p.x > 900) p.state = 'dead'; // 最终排渣

                    } else if (p.state === 'falling') {
                        // 透网后加速下落
                        p.y += p.vy;
                        p.vy += 0.1; // 重力加速度
                        p.el.style.fill = '#10b981'; // 变色表示干净液体
                        p.el.style.opacity = '0.5';
                        if (p.y > 450) p.state = 'dead';

                    } else if (p.state === 'blasted') {
                        // 被脉冲吹起
                        p.x += p.vx;
                        p.y += p.vy;
                        p.vy += 0.2; // 重新受重力
                        p.el.classList.remove('stuck');
                        
                        // 重新落回流体层变为 flowing,或者直接吹出
                        if (p.y >= meshY - p.r && p.vy > 0) {
                             p.state = 'flowing';
                             p.y = meshY - p.r - 2; // 防止穿模
                        }
                    }

                    // 应用位置
                    if (p.state !== 'dead') {
                        p.el.setAttribute("cx", p.x);
                        p.el.setAttribute("cy", p.y);
                    } else {
                        // 移除死亡粒子
                        p.el.remove();
                        particles.splice(i, 1);
                    }
                }

                requestAnimationFrame(animateSystem);
            }

            // 触发反向脉冲
            function triggerPulse() {
                if (isPulsing) return;
                isPulsing = true;
                
                // UI 状态
                statusText.innerText = "SYS.PULSE";
                statusText.style.color = "var(--accent-red)";
                timerProgress.style.stroke = "var(--accent-red)";
                svg.classList.add('pulse-active');

                // 物理影响:吹飞卡住的颗粒
                particles.forEach(p => {
                    if (p.state === 'stuck') {
                        // 赋予向上的爆炸初速度和随机水平偏移
                        p.state = 'blasted';
                        p.vy = random(-8, -12);
                        p.vx = p.vx + random(0, 2); 
                    }
                });

                // 结束脉冲
                setTimeout(() => {
                    isPulsing = false;
                    statusText.innerText = "SYS.NORMAL";
                    statusText.style.color = "var(--accent-cyan)";
                    timerProgress.style.stroke = "var(--accent-cyan)";
                    svg.classList.remove('pulse-active');
                }, PULSE_DURATION);
            }

            // 启动引擎
            requestAnimationFrame(animateSystem);
        });
    </script>
</body>
</html>
积分规则:每轮对话扣10分