{
  "case_id": "D3",
  "case_name": "核聚变过程模拟",
  "prompt": "创建核聚变过程的3D可视化教学动画，要求：\n1. 氢原子核聚变成氦的完整过程\n2. 显示：\n   - 质子和中子的运动\n   - 强核力的作用范围\n   - 能量释放的光效\n   - 质量亏损转化为能量\n3. 可暂停并查看每个步骤的解释\n4. 添加背景音乐提示\n5. 单文件HTML，使用Three.js",
  "result": {
    "success": true,
    "content": "这是一个完整的单文件HTML解决方案。它使用了Three.js库来创建一个交互式的3D场景，演示氘（Deuterium）和氚（Tritium）聚变成氦（Helium）的过程（这是最常见且视觉效果最明显的核聚变示例）。\n\n### 功能特点：\n1.  **3D 渲染**：包含质子（红色）、中子（灰色）、光晕特效。\n2.  **分步演示**：自动播放，包含四个关键阶段（克服斥力、强核力捕获、聚变释放能量、产物生成）。\n3.  **交互控制**：可以暂停/播放，旋转视角，重置动画。\n4.  **视觉特效**：\n    *   **强核力**：当原子核靠近时，显示透明的力场球体。\n    *   **能量爆发**：聚变瞬间产生巨大的光效（模拟 $E=mc^2$）。\n5.  **教学注解**：屏幕下方实时更新当前步骤的物理学解释。\n\n将以下代码保存为 `.html` 文件（例如 `fusion_demo.html`），然后用浏览器打开即可。\n\n```html\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>3D 核聚变可视化教学 (Three.js)</title>\n    <style>\n        body { margin: 0; overflow: hidden; background-color: #000; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: white; }\n        #canvas-container { width: 100vw; height: 100vh; }\n        \n        /* UI Overlay Styles */\n        #ui-layer {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            pointer-events: none;\n            display: flex;\n            flex-direction: column;\n            justify-content: space-between;\n        }\n\n        #header {\n            padding: 20px;\n            background: linear-gradient(to bottom, rgba(0,0,0,0.8), transparent);\n            text-align: center;\n        }\n\n        h1 { margin: 0; font-size: 24px; color: #4db8ff; text-shadow: 0 0 10px #4db8ff; }\n        p.subtitle { margin: 5px 0 0; font-size: 14px; color: #aaa; }\n\n        #controls-area {\n            padding: 20px;\n            background: linear-gradient(to top, rgba(0,0,0,0.9), transparent);\n            pointer-events: auto;\n            text-align: center;\n        }\n\n        #info-box {\n            background: rgba(20, 30, 50, 0.8);\n            border: 1px solid #4db8ff;\n            border-radius: 8px;\n            padding: 15px;\n            margin: 0 auto 15px auto;\n            max-width: 600px;\n            min-height: 60px;\n            transition: all 0.3s;\n        }\n\n        #step-title { color: #ffcc00; font-weight: bold; font-size: 18px; margin-bottom: 5px; }\n        #step-desc { font-size: 14px; line-height: 1.4; }\n\n        button {\n            background: #4db8ff;\n            border: none;\n            padding: 10px 20px;\n            border-radius: 5px;\n            color: #000;\n            font-weight: bold;\n            cursor: pointer;\n            margin: 0 5px;\n            transition: background 0.2s;\n        }\n        button:hover { background: #fff; box-shadow: 0 0 15px #4db8ff; }\n        \n        #music-hint {\n            position: absolute;\n            top: 20px;\n            right: 20px;\n            font-size: 12px;\n            color: #666;\n            border: 1px solid #333;\n            padding: 5px 10px;\n            border-radius: 20px;\n        }\n\n        /* Legend */\n        #legend {\n            position: absolute;\n            top: 80px;\n            left: 20px;\n            background: rgba(0,0,0,0.5);\n            padding: 10px;\n            border-radius: 5px;\n        }\n        .legend-item { display: flex; align-items: center; margin-bottom: 5px; font-size: 12px; }\n        .dot { width: 12px; height: 12px; border-radius: 50%; margin-right: 8px; display: inline-block; }\n    </style>\n    <!-- Import Three.js -->\n    <script type=\"importmap\">\n        {\n            \"imports\": {\n                \"three\": \"https://unpkg.com/three@0.160.0/build/three.module.js\",\n                \"three/addons/\": \"https://unpkg.com/three@0.160.0/examples/jsm/\"\n            }\n        }\n    </script>\n</head>\n<body>\n\n    <div id=\"canvas-container\"></div>\n\n    <div id=\"ui-layer\">\n        <div id=\"header\">\n            <h1>核聚变可视化: 氘 + 氚 &rarr; 氦 + 中子</h1>\n            <p class=\"subtitle\">拖动鼠标旋转视角 | 滚轮缩放</p>\n            <div id=\"music-hint\">🎵 建议背景音乐: 史诗/科幻风格 (请自行播放)</div>\n        </div>\n\n        <div id=\"legend\">\n            <div class=\"legend-item\"><span class=\"dot\" style=\"background: #ff3333; box-shadow: 0 0 5px red;\"></span>质子 (Proton)</div>\n            <div class=\"legend-item\"><span class=\"dot\" style=\"background: #888888; box-shadow: 0 0 5px grey;\"></span>中子 (Neutron)</div>\n            <div class=\"legend-item\"><span class=\"dot\" style=\"border: 1px solid gold; background: transparent;\"></span>强核力范围</div>\n        </div>\n\n        <div id=\"controls-area\">\n            <div id=\"info-box\">\n                <div id=\"step-title\">准备就绪</div>\n                <div id=\"step-desc\">点击“播放”开始观察聚变过程。</div>\n            </div>\n            <button id=\"btn-play\">播放 / 暂停</button>\n            <button id=\"btn-reset\">重置演示</button>\n        </div>\n    </div>\n\n    <script type=\"module\">\n        import * as THREE from 'three';\n        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';\n\n        // --- 配置参数 ---\n        const CONFIG = {\n            protonColor: 0xff3333,\n            neutronColor: 0x888888,\n            glowColor: 0xffff00,\n            strongForceColor: 0x00ffff,\n            particleSize: 1.2,\n            animationSpeed: 1.0 // 这里的速度乘数\n        };\n\n        // --- 场景初始化 ---\n        const container = document.getElementById('canvas-container');\n        const scene = new THREE.Scene();\n        // 星空背景\n        scene.background = new THREE.Color(0x050505);\n        \n        const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);\n        camera.position.set(0, 10, 30);\n\n        const renderer = new THREE.WebGLRenderer({ antialias: true });\n        renderer.setSize(window.innerWidth, window.innerHeight);\n        renderer.setPixelRatio(window.devicePixelRatio);\n        container.appendChild(renderer.domElement);\n\n        const controls = new OrbitControls(camera, renderer.domElement);\n        controls.enableDamping = true;\n\n        // --- 灯光 ---\n        const ambientLight = new THREE.AmbientLight(0x404040, 2);\n        scene.add(ambientLight);\n        const pointLight = new THREE.PointLight(0xffffff, 3, 100);\n        pointLight.position.set(10, 10, 10);\n        scene.add(pointLight);\n\n        // --- 辅助函数：创建发光纹理 ---\n        function createGlowTexture() {\n            const canvas = document.createElement('canvas');\n            canvas.width = 64;\n            canvas.height = 64;\n            const context = canvas.getContext('2d');\n            const gradient = context.createRadialGradient(32, 32, 0, 32, 32, 32);\n            gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');\n            gradient.addColorStop(0.2, 'rgba(255, 255, 0, 0.6)');\n            gradient.addColorStop(0.5, 'rgba(255, 100, 0, 0.2)');\n            gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');\n            context.fillStyle = gradient;\n            context.fillRect(0,0,64,64);\n            return new THREE.CanvasTexture(canvas);\n        }\n\n        const glowMaterial = new THREE.SpriteMaterial({ \n            map: createGlowTexture(), \n            color: 0xffaa00, \n            transparent: true, \n            opacity: 0,\n            blending: THREE.AdditiveBlending\n        });\n\n        // --- 创建粒子对象 ---\n        const sphereGeo = new THREE.SphereGeometry(CONFIG.particleSize, 32, 32);\n        const protonMat = new THREE.MeshStandardMaterial({ \n            color: CONFIG.protonColor, roughness: 0.4, metalness: 0.1, emissive: 0x330000 \n        });\n        const neutronMat = new THREE.MeshStandardMaterial({ \n            color: CONFIG.neutronColor, roughness: 0.4, metalness: 0.1 \n        });\n\n        // 氘核 (Deuterium): 1质子 + 1中子\n        const deuteriumGroup = new THREE.Group();\n        const d_p1 = new THREE.Mesh(sphereGeo, protonMat);\n        const d_n1 = new THREE.Mesh(sphereGeo, neutronMat);\n        d_p1.position.set(-0.8, 0, 0);\n        d_n1.position.set(0.8, 0, 0);\n        deuteriumGroup.add(d_p1, d_n1);\n        \n        // 氚核 (Tritium): 1质子 + 2中子\n        const tritiumGroup = new THREE.Group();\n        const t_p1 = new THREE.Mesh(sphereGeo, protonMat);\n        const t_n1 = new THREE.Mesh(sphereGeo, neutronMat);\n        const t_n2 = new THREE.Mesh(sphereGeo, neutronMat);\n        // 三角形排列\n        t_p1.position.set(0, 1, 0);\n        t_n1.position.set(-0.9, -0.5, 0);\n        t_n2.position.set(0.9, -0.5, 0);\n        tritiumGroup.add(t_p1, t_n1, t_n2);\n\n        scene.add(deuteriumGroup);\n        scene.add(tritiumGroup);\n\n        // 强核力场 (透明球)\n        const forceGeo = new THREE.SphereGeometry(4, 32, 32);\n        const forceMat = new THREE.MeshBasicMaterial({ \n            color: CONFIG.strongForceColor, \n            transparent: true, \n            opacity: 0.0, \n            wireframe: true \n        });\n        const forceField = new THREE.Mesh(forceGeo, forceMat);\n        scene.add(forceField);\n\n        // 能量爆发 Sprite\n        const explosionSprite = new THREE.Sprite(glowMaterial);\n        explosionSprite.scale.set(30, 30, 1);\n        scene.add(explosionSprite);\n\n        // 自由中子 (生成物)\n        const freeNeutron = new THREE.Mesh(sphereGeo, neutronMat);\n        freeNeutron.visible = false;\n        scene.add(freeNeutron);\n\n        // --- 动画状态管理 ---\n        let animationTime = 0;\n        let isPaused = true;\n        let state = 'start'; // start, approach, interaction, fusion, ejection\n\n        // 初始位置\n        function resetPositions() {\n            animationTime = 0;\n            state = 'start';\n            \n            // 左右分开\n            deuteriumGroup.position.set(-12, 0, 0);\n            tritiumGroup.position.set(12, 0, 0);\n            \n            deuteriumGroup.visible = true;\n            tritiumGroup.visible = true;\n            \n            // 重置旋转\n            deuteriumGroup.rotation.set(0,0,0);\n            tritiumGroup.rotation.set(0,0,0);\n\n            // 隐藏特效\n            forceField.material.opacity = 0;\n            explosionSprite.material.opacity = 0;\n            freeNeutron.visible = false;\n            \n            // 重新组合粒子到组里 (因为聚变时我们会打乱它们)\n            // 简化处理：我们不真正改变场景图结构，而是通过移动整个组来模拟\n            // 聚变后，我们隐藏D和T组，显示一个预制的He4组和中子\n            updateUI(\"准备就绪\", \"点击播放开始。我们将看到氘（左）和氚（右）在高能状态下碰撞。\");\n        }\n\n        resetPositions();\n\n        // --- UI 更新逻辑 ---\n        const uiTitle = document.getElementById('step-title');\n        const uiDesc = document.getElementById('step-desc');\n        \n        function updateUI(title, desc) {\n            uiTitle.innerText = title;\n            uiDesc.innerText = desc;\n        }\n\n        // --- 动画循环逻辑 ---\n        function animateLogic(delta) {\n            if (isPaused) return;\n\n            animationTime += delta * CONFIG.animationSpeed;\n            const t = animationTime;\n\n            // 1. 接近阶段 (0s - 3s)\n            if (t < 3) {\n                if (state !== 'approach') {\n                    state = 'approach';\n                    updateUI(\"1. 克服静电斥力\", \"原子核都带正电，互相排斥。需要极高的温度（速度）和压力才能让它们靠得足够近。\");\n                }\n                \n                // 移动\n                const progress = t / 3; // 0 to 1\n                // 缓动函数 easeIn\n                const xPos = 12 * (1 - progress); \n                deuteriumGroup.position.set(-xPos, 0, 0);\n                tritiumGroup.position.set(xPos, 0, 0);\n\n                // 旋转增加动感\n                deuteriumGroup.rotation.z += 2 * delta;\n                tritiumGroup.rotation.z -= 2 * delta;\n            }\n            \n            // 2. 强核力作用 (3s - 4s)\n            else if (t < 4.5) {\n                if (state !== 'interaction') {\n                    state = 'interaction';\n                    updateUI(\"2. 强核力捕获\", \"当距离小于 10^-15 米时，短程但极强的“强核力”战胜了电磁斥力，将核子拉在一起。\");\n                }\n\n                // 距离非常近，震动模拟不稳定性\n                deuteriumGroup.position.set(-0.5 + (Math.random()*0.2), Math.random()*0.2, Math.random()*0.2);\n                tritiumGroup.position.set(0.5 + (Math.random()*0.2), Math.random()*0.2, Math.random()*0.2);\n                \n                // 显示力场\n                const forceProgress = (t - 3) / 1.5;\n                forceField.material.opacity = Math.sin(forceProgress * Math.PI) * 0.8;\n                forceField.scale.setScalar(1 + Math.sin(t * 10)*0.1); // 脉动\n            }\n\n            // 3. 聚变与能量释放 (4.5s - 5s)\n            else if (t < 5.5) {\n                if (state !== 'fusion') {\n                    state = 'fusion';\n                    updateUI(\"3. 质量亏损 -> 能量\", \"核聚变发生！部分质量转化为巨大的能量 (E=mc²)。产生耀眼的光芒（伽马射线）。\");\n                }\n\n                // 闪光\n                const flashProgress = (t - 4.5) / 1.0;\n                // 快速变亮再变暗\n                let opacity = 0;\n                if (flashProgress < 0.2) opacity = flashProgress * 5; \n                else opacity = 1 - (flashProgress - 0.2) * 1.2;\n                \n                explosionSprite.material.opacity = Math.max(0, opacity);\n                explosionSprite.scale.setScalar(20 + flashProgress * 20);\n\n                // 粒子位置重组为 Helium-4 结构 (在中心)\n                // 简单起见，我们在中心让它们混在一起旋转\n                deuteriumGroup.position.set(0,0,0);\n                tritiumGroup.position.set(0,0,0);\n                deuteriumGroup.rotation.x += 10 * delta;\n                tritiumGroup.rotation.y += 10 * delta;\n            }\n\n            // 4. 产物射出 (5.5s +)\n            else if (t < 9) {\n                if (state !== 'ejection') {\n                    state = 'ejection';\n                    updateUI(\"4. 产物生成\", \"生成一个稳定的氦核 (He-4) 和一个高能中子。中子携带了大部分能量飞出（这是聚变发电的关键）。\");\n                    \n                    // 此时，我们需要视觉上的“魔术”。\n                    // 实际上D和T已经重叠。我们让D+T中的一部分变成氦，单独一个中子飞出。\n                    // 这种“切换”在光效最强时做最好，但这里我们简单模拟：\n                    // 氦核留在中间，自由中子飞走。\n                    freeNeutron.visible = true;\n                    freeNeutron.position.set(0,0,0);\n                }\n\n                // 氦核 (由原本的D和T组模拟，稍微调整位置让它们看起来像一团)\n                deuteriumGroup.position.set(0,0,0);\n                tritiumGroup.position.set(0,0,0);\n                // 减慢旋转\n                deuteriumGroup.rotation.x += 1 * delta;\n                \n                // 自由中子高速飞出\n                const ejectTime = t - 5.5;\n                freeNeutron.position.set(ejectTime * 8, ejectTime * 4, 0);\n                \n                // 能量余辉\n                explosionSprite.material.opacity *= 0.95;\n\n            } else {\n                // 结束\n                isPaused = true;\n                document.getElementById('btn-play').innerText = \"重播\";\n                updateUI(\"演示结束\", \"点击重置再次观看。\");\n            }\n        }\n\n        // --- 主循环 ---\n        const clock = new THREE.Clock();\n\n        function animate() {\n            requestAnimationFrame(animate);\n            \n            const delta = clock.getDelta();\n            animateLogic(delta);\n            \n            controls.update();\n            \n            // 简单的背景粒子浮动效果\n            // (省略以保持代码简洁，仅依靠OrbitControls)\n\n            renderer.render(scene, camera);\n        }\n\n        animate();\n\n        // --- 事件监听 ---\n        window.addEventListener('resize', () => {\n            camera.aspect = window.innerWidth / window.innerHeight;\n            camera.updateProjectionMatrix();\n            renderer.setSize(window.innerWidth, window.innerHeight);\n        });\n\n        document.getElementById('btn-play').addEventListener('click', (e) => {\n            if (animationTime >= 9) {\n                resetPositions();\n                isPaused = false;\n                e.target.innerText = \"暂停\";\n            } else {\n                isPaused = !isPaused;\n                e.target.innerText = isPaused ? \"播放\" : \"暂停\";\n            }\n        });\n\n        document.getElementById('btn-reset').addEventListener('click', () => {\n            resetPositions();\n            isPaused = true;\n            document.getElementById('btn-play').innerText = \"播放\";\n        });\n\n    </script>\n</body>\n</html>\n```\n\n### 使用说明：\n\n1.  **复制**：将上面的代码块完整复制。\n2.  **保存**：在你的电脑上创建一个新文件，命名为 `fusion.html`。\n3.  **运行**：双击该文件，它会在你的默认浏览器（Chrome, Edge, Firefox等）中打开。\n\n### 动画流程解释（代码逻辑）：\n\n*   **0-3秒 (接近)**：\n    *   左侧是氘（1质子1中子），右侧是氚（1质子2中子）。\n    *   它们向中心移动，并在Z轴旋转。\n    *   *物理含义*：模拟高温高压下，粒子获得足够动能，克服正电荷之间的库仑斥力。\n*   **3-4.5秒 (强核力捕获)**：\n    *   粒子到达中心，开始剧烈震动。\n    *   出现青色的线框球体。\n    *   *物理含义*：当距离极近（约 $10^{-15}m$）时，强核力介入，将核子吸附在一起。\n*   **4.5-5.5秒 (聚变闪光)**：\n    *   屏幕中心爆发强烈的橙黄色光芒。\n    *   *物理含义*：根据 $E=mc^2$，聚变后总质量略微减小，亏损的质量转化为巨大的能量释放。\n*   **5.5秒后 (产物)**：\n    *   中心留下一团紧密的粒子（氦核/Alpha粒子）。\n    *   一颗灰色的粒子（中子）高速向右上方飞出。\n    *   *物理含义*：生成稳定的氦-4，多余的中子携带了大部分动能被释放出来。",
    "model": "gemini-3-pro-preview",
    "usage": {
      "prompt_tokens": 123,
      "completion_tokens": 7188,
      "total_tokens": 7311
    },
    "timestamp": "2025-11-19 13:27:26"
  },
  "needs_screenshot": true,
  "needs_manual_test": true
}