分享图
动画工坊
引擎就绪
<!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: #07090f;
            --grid-color: rgba(255, 255, 255, 0.04);
            --accent-cyan: #00f0ff;
            --accent-orange: #ff5500;
            --accent-blue: #3a86ff;
            --panel-bg: rgba(10, 14, 23, 0.85);
            --text-main: #e2e8f0;
            --text-muted: #64748b;
        }

        body {
            margin: 0;
            padding: 0;
            background-color: var(--bg-color);
            color: var(--text-main);
            font-family: 'SF Pro Display', -apple-system, 'Segoe UI', Roboto, Helvetica, sans-serif;
            overflow: hidden;
            width: 100vw;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: 
                radial-gradient(circle at center, #111827 0%, #000000 100%),
                linear-gradient(0deg, var(--grid-color) 1px, transparent 1px),
                linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
            background-size: 100% 100%, 40px 40px, 40px 40px;
            background-blend-mode: overlay;
        }

        /* 绝对遵循:精简且极小的角落文字说明,不遮挡中央 */
        .hud-corner {
            position: absolute;
            z-index: 100;
            background: var(--panel-bg);
            border: 1px solid rgba(255, 255, 255, 0.1);
            padding: 12px 16px;
            border-radius: 6px;
            backdrop-filter: blur(10px);
            pointer-events: none;
            max-width: 280px;
        }

        .top-left { top: 20px; left: 20px; border-left: 3px solid var(--accent-cyan); }
        .bottom-right { bottom: 20px; right: 20px; border-right: 3px solid var(--accent-orange); text-align: right; }

        .hud-title {
            font-size: 13px;
            font-weight: 700;
            margin: 0 0 4px 0;
            color: #fff;
            letter-spacing: 1px;
        }

        .hud-desc {
            font-size: 11px;
            color: var(--text-muted);
            margin: 0;
            line-height: 1.5;
        }

        .status-badge {
            display: inline-block;
            font-family: monospace;
            font-size: 11px;
            padding: 3px 8px;
            background: rgba(255,255,255,0.05);
            border-radius: 3px;
            color: var(--accent-cyan);
            margin-top: 6px;
        }

        #timer-bar-container {
            width: 100%;
            height: 2px;
            background: rgba(255,255,255,0.1);
            margin-top: 8px;
            border-radius: 1px;
            overflow: hidden;
        }

        #timer-bar {
            height: 100%;
            width: 0%;
            background: var(--accent-cyan);
            transition: width 0.1s linear;
        }

        /* SVG 动画容器,确保充分居中且足够大 */
        .svg-container {
            position: relative;
            width: 90vmin;
            height: 90vmin;
            max-width: 1000px;
            max-height: 1000px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        svg {
            width: 100%;
            height: 100%;
            overflow: visible;
        }

        /* 核心部件过渡效果 */
        #rotary-table {
            transform-origin: 0 0;
            /* JS 动态控制 transform,此处设定平滑贝塞尔曲线表现机械旋转的惯性 */
            transition: transform 2.5s cubic-bezier(0.65, 0, 0.35, 1);
        }

        #pressure-beam {
            transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .workpiece {
            transition: fill 1s;
        }

        /* 呼吸光效与动作态 */
        @keyframes pulse-cyan {
            0%, 100% { opacity: 0.2; transform: scale(1); }
            50% { opacity: 0.8; transform: scale(1.05); }
        }
        
        @keyframes cool-down {
            0% { opacity: 0.8; fill: #60a5fa; }
            100% { opacity: 0.1; fill: #1e3a8a; }
        }

        .loading-aura {
            animation: pulse-cyan 2s infinite ease-in-out;
            transform-origin: center;
        }
        
        .cooling-aura {
            transition: opacity 1s, fill 4s linear;
        }

    </style>
</head>
<body>

    <!-- 左上角极简说明 -->
    <div class="hud-corner top-left">
        <h1 class="hud-title">TRIZ 理想解 (IFR)</h1>
        <p class="hud-desc">原直线工域转换为环形二维工域。巧妙利用回转支撑空间,通过 120° 分度实现装配、焊接、冷却三工位并行无缝协同,消除空间与时间冲突。</p>
    </div>

    <!-- 右下角极简状态监控 -->
    <div class="hud-corner bottom-right">
        <h1 class="hud-title">系统实时状态监控</h1>
        <p class="hud-desc" id="status-text">初始化...</p>
        <div class="status-badge" id="status-phase">PHASE 00</div>
        <div id="timer-bar-container"><div id="timer-bar"></div></div>
    </div>

    <!-- 中央核心动画区 -->
    <div class="svg-container">
        <svg viewBox="-500 -500 1000 1000">
            <defs>
                <!-- 滤镜与发光效果 -->
                <filter id="glow-orange" x="-30%" y="-30%" width="160%" height="160%">
                    <feGaussianBlur stdDeviation="8" result="blur1" />
                    <feGaussianBlur stdDeviation="15" result="blur2" />
                    <feMerge>
                        <feMergeNode in="blur2" />
                        <feMergeNode in="blur1" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>
                <filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
                    <feGaussianBlur stdDeviation="5" result="blur" />
                    <feMerge>
                        <feMergeNode in="blur" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>
                
                <!-- 材质渐变 -->
                <radialGradient id="metal-base" cx="50%" cy="50%" r="50%">
                    <stop offset="0%" stop-color="#2a303c" />
                    <stop offset="80%" stop-color="#151922" />
                    <stop offset="100%" stop-color="#0b0f19" />
                </radialGradient>
                <linearGradient id="metal-frame" x1="0%" y1="0%" x2="100%" y2="100%">
                    <stop offset="0%" stop-color="#475569" />
                    <stop offset="50%" stop-color="#1e293b" />
                    <stop offset="100%" stop-color="#0f172a" />
                </linearGradient>

                <!-- 轨道纹理 -->
                <pattern id="track-pattern" width="20" height="20" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
                    <line x1="0" y1="0" x2="0" y2="20" stroke="rgba(255,255,255,0.05)" stroke-width="2"/>
                </pattern>
            </defs>

            <!-- 底层背景环境环 -->
            <g id="environment" stroke="rgba(255,255,255,0.1)" stroke-width="1" fill="none">
                <circle cx="0" cy="0" r="450" stroke-dasharray="4 8" />
                <circle cx="0" cy="0" r="400" />
                <!-- 120度工位分割引导线 -->
                <line x1="0" y1="0" x2="0" y2="-450" stroke="rgba(255,255,255,0.2)" />
                <line x1="0" y1="0" x2="389.7" y2="225" stroke="rgba(255,255,255,0.2)" />
                <line x1="0" y1="0" x2="-389.7" y2="225" stroke="rgba(255,255,255,0.2)" />
            </g>

            <!-- 静态工位标识 (极简) -->
            <g font-size="12" fill="var(--text-muted)" font-family="monospace" letter-spacing="2" text-anchor="middle">
                <!-- 焊接区 (上方 -90°) -->
                <text x="0" y="-465" fill="var(--accent-orange)">[ ST-2: WELDING / 焊接作业区 ]</text>
                <!-- 冷却区 (右下 30°) -->
                <text x="360" y="270" fill="var(--accent-blue)">[ ST-3: COOLING / 冷却下料 ]</text>
                <!-- 装配区 (左下 150°) -->
                <text x="-360" y="270" fill="var(--accent-cyan)">[ ST-1: ASSEMBLY / 装配上料 ]</text>
            </g>

            <!-- 旋转分度盘核心结构 -->
            <g id="rotary-table">
                <!-- 盘底 -->
                <circle cx="0" cy="0" r="350" fill="url(#metal-base)" stroke="#334155" stroke-width="4"/>
                <circle cx="0" cy="0" r="330" fill="url(#track-pattern)" />
                <circle cx="0" cy="0" r="100" fill="#1e293b" stroke="#00f0ff" stroke-width="1" stroke-dasharray="5 5"/>
                
                <!-- 中心转轴 -->
                <circle cx="0" cy="0" r="30" fill="#cbd5e1" />
                <circle cx="0" cy="0" r="15" fill="#0f172a" />

                <!-- 120度隔离支架 -->
                <path d="M 0 0 L 0 -350" stroke="#0f172a" stroke-width="12" stroke-linecap="round"/>
                <path d="M 0 0 L 303.1 175" stroke="#0f172a" stroke-width="12" stroke-linecap="round"/>
                <path d="M 0 0 L -303.1 175" stroke="#0f172a" stroke-width="12" stroke-linecap="round"/>

                <!-- 随动钣金件 (3块) -->
                <!-- 钣金件 1 -->
                <g transform="rotate(-90) translate(220, 0) rotate(90)">
                    <rect class="workpiece" id="wp-1" x="-80" y="-50" width="160" height="100" rx="10" fill="#94a3b8" stroke="#cbd5e1" stroke-width="2"/>
                    <rect x="-60" y="-30" width="120" height="60" rx="5" fill="#64748b" />
                    <!-- 焊缝路径 -->
                    <line x1="-50" y1="0" x2="50" y2="0" stroke="#334155" stroke-width="2" stroke-dasharray="4 2"/>
                </g>
                <!-- 钣金件 2 -->
                <g transform="rotate(30) translate(220, 0) rotate(-30)">
                    <rect class="workpiece" id="wp-2" x="-80" y="-50" width="160" height="100" rx="10" fill="#94a3b8" stroke="#cbd5e1" stroke-width="2"/>
                    <rect x="-60" y="-30" width="120" height="60" rx="5" fill="#64748b" />
                    <line x1="-50" y1="0" x2="50" y2="0" stroke="#334155" stroke-width="2" stroke-dasharray="4 2"/>
                </g>
                <!-- 钣金件 3 -->
                <g transform="rotate(150) translate(220, 0) rotate(-150)">
                    <rect class="workpiece" id="wp-3" x="-80" y="-50" width="160" height="100" rx="10" fill="#94a3b8" stroke="#cbd5e1" stroke-width="2"/>
                    <rect x="-60" y="-30" width="120" height="60" rx="5" fill="#64748b" />
                    <line x1="-50" y1="0" x2="50" y2="0" stroke="#334155" stroke-width="2" stroke-dasharray="4 2"/>
                </g>
            </g>

            <!-- === 静态工位工作效果层 (不随盘旋转) === -->
            
            <!-- ST-1 装配区光效 (左下) -->
            <g id="fx-assembly" transform="rotate(150) translate(220, 0) rotate(-150)" opacity="0">
                <rect x="-90" y="-60" width="180" height="120" rx="15" fill="none" stroke="var(--accent-cyan)" stroke-width="3" stroke-dasharray="10 5" class="loading-aura"/>
                <path d="M -20 -80 L 0 -50 L 20 -80 Z" fill="var(--accent-cyan)" opacity="0.8">
                    <animate attributeName="transform" values="translate(0, -10); translate(0, 0); translate(0, -10)" dur="1s" repeatCount="indefinite" />
                </path>
            </g>

            <!-- ST-3 冷却区光效 (右下) -->
            <g id="fx-cooling" transform="rotate(30) translate(220, 0) rotate(-30)" opacity="0">
                <rect x="-85" y="-55" width="170" height="110" rx="12" fill="var(--accent-blue)" class="cooling-aura" opacity="0.3" filter="url(#glow-cyan)"/>
                <!-- 散发的热气动画将在 JS 中生成 -->
            </g>

            <!-- ST-2 焊接区与压力架 (上方) -->
            <g id="fx-welding">
                <!-- 重载压力架桥墩 (两侧) -->
                <rect x="-160" y="-320" width="40" height="100" rx="5" fill="url(#metal-frame)" stroke="#0f172a" stroke-width="2"/>
                <rect x="120" y="-320" width="40" height="100" rx="5" fill="url(#metal-frame)" stroke="#0f172a" stroke-width="2"/>
                
                <!-- 动态升降压力架横梁 -->
                <g id="pressure-beam" transform="translate(0, 0)">
                    <!-- 横梁主体 -->
                    <rect x="-180" y="-300" width="360" height="40" rx="8" fill="url(#metal-frame)" stroke="#475569" stroke-width="1"/>
                    <!-- 压紧气缸/液压杆 -->
                    <rect x="-100" y="-260" width="20" height="40" fill="#94a3b8" />
                    <rect x="80" y="-260" width="20" height="40" fill="#94a3b8" />
                    <!-- 压紧触头 -->
                    <path d="M -115 -220 L -85 -220 L -90 -200 L -110 -200 Z" fill="#b91c1c" />
                    <path d="M 85 -220 L 115 -220 L 110 -200 L 90 -200 Z" fill="#b91c1c" />
                    <!-- 自动焊枪头 -->
                    <rect x="-15" y="-260" width="30" height="30" fill="#334155" />
                    <path d="M -5 -230 L 5 -230 L 2 -200 L -2 -200 Z" fill="#eab308" />
                </g>

                <!-- 焊接火花粒子容器 -->
                <g id="spark-container"></g>
            </g>

            <!-- 坐标辅助十字线 (最上层细线) -->
            <path d="M 0 -80 L 0 80 M -80 0 L 80 0" stroke="rgba(255,255,255,0.15)" stroke-width="1" />
        </svg>
    </div>

    <script>
        document.addEventListener("DOMContentLoaded", () => {
            // DOM 元素引用
            const rotaryTable = document.getElementById('rotary-table');
            const pressureBeam = document.getElementById('pressure-beam');
            const sparkContainer = document.getElementById('spark-container');
            const fxAssembly = document.getElementById('fx-assembly');
            const fxCooling = document.getElementById('fx-cooling');
            const coolingAura = fxCooling.querySelector('.cooling-aura');
            
            const statusText = document.getElementById('status-text');
            const statusPhase = document.getElementById('status-phase');
            const timerBar = document.getElementById('timer-bar');

            // 核心参数设定
            let currentAngle = 0;
            let sparkInterval = null;
            let timerInterval = null;

            // 状态机时序定义 (毫秒)
            const timings = {
                work: 4000,   // 装配、焊接、冷却并行作业时间
                lift: 1000,   // 焊接结束,压力架抬起时间
                rotate: 2000, // 回转盘120度旋转时间 (<15s的理想化极速展示)
                press: 1000   // 旋转到位,压力架下压锁紧时间
            };

            // 辅助:进度条控制
            function startTimerBar(duration) {
                clearInterval(timerInterval);
                timerBar.style.transition = 'none';
                timerBar.style.width = '0%';
                
                // 强制重绘
                void timerBar.offsetWidth; 
                
                timerBar.style.transition = `width ${duration}ms linear`;
                timerBar.style.width = '100%';
            }

            // 辅助:火花粒子生成器 (仅在焊接阶段激活)
            function createSpark() {
                const spark = document.createElementNS("http://www.w3.org/2000/svg", "circle");
                // 焊枪位置近似 (0, -200)
                const startX = (Math.random() - 0.5) * 10;
                const startY = -200;
                
                spark.setAttribute("cx", startX);
                spark.setAttribute("cy", startY);
                spark.setAttribute("r", Math.random() * 2 + 1);
                spark.setAttribute("fill", Math.random() > 0.5 ? "#fbbf24" : "#ffedd5");
                spark.setAttribute("filter", "url(#glow-orange)");

                sparkContainer.appendChild(spark);

                // 物理抛射动画
                const angle = (Math.random() * Math.PI) - (Math.PI / 2); // 向上和两侧飞散
                const velocity = Math.random() * 80 + 40;
                const tx = startX + Math.sin(angle) * velocity;
                const ty = startY - Math.cos(angle) * velocity;

                const anim = spark.animate([
                    { transform: `translate(0px, 0px) scale(1)`, opacity: 1 },
                    { transform: `translate(${tx}px, ${ty + 50}px) scale(0)`, opacity: 0 }
                ], {
                    duration: Math.random() * 500 + 300,
                    easing: 'cubic-bezier(0.25, 1, 0.5, 1)',
                    fill: 'forwards'
                });

                anim.onfinish = () => spark.remove();
            }

            function startSparks() {
                if (sparkInterval) return;
                sparkInterval = setInterval(() => {
                    for(let i=0; i<3; i++) createSpark();
                }, 30);
            }

            function stopSparks() {
                clearInterval(sparkInterval);
                sparkInterval = null;
            }

            // 模拟冷却站烟雾
            function createSteam() {
                const steam = document.createElementNS("http://www.w3.org/2000/svg", "circle");
                steam.setAttribute("cx", (Math.random() - 0.5) * 80);
                steam.setAttribute("cy", (Math.random() - 0.5) * 40 - 20);
                steam.setAttribute("r", Math.random() * 10 + 5);
                steam.setAttribute("fill", "#60a5fa");
                steam.setAttribute("opacity", "0.4");
                steam.setAttribute("filter", "url(#glow-cyan)");
                fxCooling.appendChild(steam);

                const anim = steam.animate([
                    { transform: `translate(0px, 0px) scale(1)`, opacity: 0.4 },
                    { transform: `translate(${(Math.random() - 0.5)*50}px, -100px) scale(3)`, opacity: 0 }
                ], {
                    duration: 2000,
                    easing: 'linear',
                    fill: 'forwards'
                });

                anim.onfinish = () => steam.remove();
            }

            let steamInterval = null;

            // ================= 核心状态机动画循环 =================
            async function wait(ms) {
                return new Promise(resolve => setTimeout(resolve, ms));
            }

            async function runCycle() {
                // [ PHASE 1: 锁紧与并行作业 ]
                statusPhase.innerText = "PHASE 01: 并行作业";
                statusText.innerHTML = "压力架已锁紧<br/>装配、焊接、冷却三工位同时运行中";
                statusText.style.color = "var(--accent-cyan)";
                startTimerBar(timings.work);
                
                // UI 表现
                pressureBeam.style.transform = "translate(0, 0)"; // 下压锁紧态
                fxAssembly.style.opacity = "1";
                fxCooling.style.opacity = "1";
                coolingAura.style.fill = "#60a5fa"; // 初始高温
                coolingAura.style.opacity = "0.8";
                
                startSparks();
                steamInterval = setInterval(createSteam, 200);

                // 模拟冷却过程的颜色渐变
                setTimeout(() => {
                    coolingAura.style.fill = "#1e3a8a";
                    coolingAura.style.opacity = "0.1";
                }, 100);

                await wait(timings.work);

                // [ PHASE 2: 动作完成,解脱干涉 ]
                statusPhase.innerText = "PHASE 02: 机构解脱";
                statusText.innerHTML = "本节拍动作完成,焊接停止<br/>发出信号,压力架自动微抬起避让";
                statusText.style.color = "var(--accent-orange)";
                startTimerBar(timings.lift);

                // UI 表现
                stopSparks();
                clearInterval(steamInterval);
                fxAssembly.style.opacity = "0";
                fxCooling.style.opacity = "0";
                pressureBeam.style.transform = "translate(0, -60px)"; // 向上抬起60px

                await wait(timings.lift);

                // [ PHASE 3: 回转盘分度旋转 ]
                statusPhase.innerText = "PHASE 03: 分度切换";
                statusText.innerHTML = "回转盘快速旋转 120°<br/>工件平滑流转至下一工位";
                statusText.style.color = "var(--text-main)";
                startTimerBar(timings.rotate);

                // UI 表现
                currentAngle += 120;
                rotaryTable.style.transform = `rotate(${currentAngle}deg)`;

                await wait(timings.rotate);

                // [ PHASE 4: 到位锁紧 ]
                statusPhase.innerText = "PHASE 04: 定位锁紧";
                statusText.innerHTML = "到达 120° 预定工位,机械定位<br/>压力架下压锁紧,准备进入下一节拍";
                statusText.style.color = "var(--text-muted)";
                startTimerBar(timings.press);

                // UI 表现
                pressureBeam.style.transform = "translate(0, 0)"; // 再次下压

                await wait(timings.press);

                // 循环迭代
                requestAnimationFrame(runCycle);
            }

            // 初始化后稍微延迟启动,让用户看清初始状态
            setTimeout(runCycle, 500);
        });
    </script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分