昨晚被很多 AI 博主关于 Google 推出了最新一代的 Gemini 3 Pro 刷屏了。今天恰好有时间就做了一下体验。真的很强大,这就给大家两个例子体会一下。

1. 台球小游戏HTML

Prompt

黑八才十六台球游戏网页,完整实现对局功能,支持双人对局,通过仿真球杆操作

第一次的 prompt 生成的代码出现了两个 bug,进行第二次对话:

我测试了,遇到几个问题:
1. 超过台球桌的范围就无法操控,不便于进行不同力度的打击;
2. 进了一球以后就无法进行后续操作

Gemini 3 Pro 给出的代码

可以创建一个 html 文件,然后一键复制以下代码,进行尝试。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Web 黑八台球 v2.0</title>
    <style>
        body {
            margin: 0;
            background-color: #1a1a1a;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            color: white;
            user-select: none; /* 防止拖拽选中文本 */
            overflow: hidden; /* 防止拖拽出滚动条 */
        }
        h2 { margin-bottom: 15px; letter-spacing: 2px; }
        #game-wrapper {
            position: relative;
            padding: 20px;
            background: #5c3a21; /* 木纹底色 */
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.8);
        }
        canvas {
            background-color: #0b6623;
            border: 4px solid #3e2714;
            border-radius: 4px;
            cursor: default; /* 鼠标样式交由JS控制 */
            display: block;
        }
        #ui-layer {
            margin-top: 20px;
            width: 840px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .player-card {
            padding: 10px 25px;
            background: #333;
            border-radius: 8px;
            border: 3px solid transparent;
            text-align: center;
            min-width: 100px;
            transition: all 0.3s;
        }
        .active-turn {
            border-color: #f1c40f;
            background: #444;
            box-shadow: 0 0 15px rgba(241, 196, 15, 0.4);
            transform: scale(1.05);
        }
        .score { font-size: 24px; font-weight: bold; margin-top: 5px; display: block; }
        .controls { text-align: center; color: #888; font-size: 12px; }
        .btn {
            margin-top: 5px;
            padding: 8px 20px;
            background: #e74c3c;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: bold;
        }
        .btn:hover { background: #c0392b; }
        
        /* 悬浮提示框 */
        #toast {
            position: absolute;
            top: 40%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.85);
            color: #fff;
            padding: 20px 40px;
            border-radius: 10px;
            font-size: 24px;
            font-weight: bold;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s;
            border: 2px solid #f1c40f;
            z-index: 10;
        }
    </style>
</head>
<body>

    <h2>🎱 仿真黑八台球</h2>

    <div id="game-wrapper">
        <canvas id="poolCanvas" width="800" height="400"></canvas>
        <div id="toast">提示信息</div>
    </div>

    <div id="ui-layer">
        <div id="p1-card" class="player-card active-turn">
            玩家 1 (实心)<br><span class="score" id="p1-score">0</span>
        </div>
        <div class="controls">
            <p>移动鼠标瞄准 | 按住左键拖拽蓄力 | 松开击球</p>
            <p>支持鼠标移出桌面进行大力度拉杆</p>
            <button class="btn" onclick="game.reset()">重置比赛</button>
        </div>
        <div id="p2-card" class="player-card">
            玩家 2 (花色)<br><span class="score" id="p2-score">0</span>
        </div>
    </div>

<script>
// --- 基础数学库 ---
const Vector = {
    new: (x, y) => ({x, y}),
    add: (v1, v2) => ({x: v1.x + v2.x, y: v1.y + v2.y}),
    sub: (v1, v2) => ({x: v1.x - v2.x, y: v1.y - v2.y}),
    mult: (v, n) => ({x: v.x * n, y: v.y * n}),
    dot: (v1, v2) => v1.x * v2.x + v1.y * v2.y,
    mag: (v) => Math.sqrt(v.x * v.x + v.y * v.y),
    normalize: (v) => {
        let m = Math.sqrt(v.x * v.x + v.y * v.y);
        return m === 0 ? {x:0, y:0} : {x: v.x/m, y: v.y/m};
    },
    dist: (v1, v2) => Math.sqrt((v1.x-v2.x)**2 + (v1.y-v2.y)**2)
};

// --- 游戏配置 ---
const CONFIG = {
    WIDTH: 800,
    HEIGHT: 400,
    BALL_R: 10,
    POCKET_R: 22,
    FRICTION: 0.988, // 地面摩擦
    WALL_BOUNCE: 0.85, // 墙壁弹性
    MAX_POWER: 25, // 最大力度
    POWER_SCALE: 0.15 // 拉杆距离转力度的比例
};

// --- 游戏状态管理 ---
const game = {
    canvas: document.getElementById('poolCanvas'),
    ctx: null,
    balls: [],
    whiteBall: null,
    pockets: [],
    
    // 状态标志
    state: {
        isMoving: false, // 球是否在滚动
        isAiming: false, // 是否在瞄准(鼠标未按下)
        isCharging: false, // 是否在蓄力(鼠标按下)
        turn: 1, // 当前玩家 1 或 2
        p1Score: 0,
        p2Score: 0,
        gameOver: false,
        turnInfo: {
            pottedAny: false, // 本回合是否进球
            foul: false // 本回合是否犯规
        }
    },

    // 鼠标输入
    input: {
        x: 0,
        y: 0,
        mouseDownX: 0,
        mouseDownY: 0
    },

    init() {
        this.ctx = this.canvas.getContext('2d');
        this.setupInputs();
        this.setupPockets();
        this.reset();
        this.loop();
    },

    setupPockets() {
        // 6个球袋位置
        this.pockets = [
            Vector.new(0, 0), Vector.new(CONFIG.WIDTH/2, 0), Vector.new(CONFIG.WIDTH, 0),
            Vector.new(0, CONFIG.HEIGHT), Vector.new(CONFIG.WIDTH/2, CONFIG.HEIGHT), Vector.new(CONFIG.WIDTH, CONFIG.HEIGHT)
        ];
    },

    // 重点修复:鼠标事件绑定到 window 以支持出界操作
    setupInputs() {
        window.addEventListener('mousemove', (e) => {
            const rect = this.canvas.getBoundingClientRect();
            // 即使移出canvas,也要计算相对于canvas的坐标
            this.input.x = e.clientX - rect.left;
            this.input.y = e.clientY - rect.top;
        });

        window.addEventListener('mousedown', (e) => {
            if (this.state.isMoving || this.state.gameOver) return;
            // 只有当鼠标在canvas范围内按下时才开始蓄力,或者放宽限制?
            // 最好是:只要还没开始动,点击哪里都可以开始拖拽,或者限制在桌内。
            // 这里限制:必须在canvas内部按下才能开始蓄力,但可以拖出去。
            const rect = this.canvas.getBoundingClientRect();
            const inX = e.clientX - rect.left;
            const inY = e.clientY - rect.top;
            
            if (inX >= 0 && inX <= CONFIG.WIDTH && inY >= 0 && inY <= CONFIG.HEIGHT) {
                this.state.isCharging = true;
                this.state.isAiming = false;
            }
        });

        window.addEventListener('mouseup', (e) => {
            if (this.state.isCharging) {
                this.shoot();
                this.state.isCharging = false;
            }
        });
    },

    reset() {
        this.balls = [];
        this.state.p1Score = 0;
        this.state.p2Score = 0;
        this.state.turn = 1;
        this.state.gameOver = false;
        this.state.isMoving = false;
        this.updateUI();
        this.hideToast();

        // 白球
        this.whiteBall = { x: 200, y: 200, vx: 0, vy: 0, color: '#fff', id: 0, active: true };
        this.balls.push(this.whiteBall);

        // 生成台球堆 (简单的金字塔)
        const startX = 600;
        const startY = 200;
        const r = CONFIG.BALL_R;
        const rows = 5;
        let idCounter = 1;

        // 简化的颜色/ID逻辑:8号球必须在中间,其他随意混排
        // 这里为了简单,不严格区分花色位置,只保证8号球位置
        // 实际规则中:角球通常一花一色
        
        let positions = [];
        for(let i=0; i<rows; i++) {
            for(let j=0; j<=i; j++) {
                let x = startX + i * (r * 1.732) + Math.random(); // 加微小抖动防止物理死锁
                let y = startY - i * r + j * (r * 2) + Math.random();
                positions.push({x, y});
            }
        }

        // 分配ID
        // 8号球是第5个位置 (索引4,第三排中间)
        let ids = [1, 9, 2, 10, 8, 3, 11, 7, 14, 4, 5, 13, 15, 6, 12]; 
        
        positions.forEach((pos, index) => {
            let id = ids[index];
            let color = this.getBallColor(id);
            this.balls.push({
                x: pos.x, y: pos.y,
                vx: 0, vy: 0,
                color: color,
                id: id,
                active: true
            });
        });
    },

    getBallColor(id) {
        if(id === 8) return '#000';
        if(id === 0) return '#fff';
        const colors = ['#e6b333', '#3498db', '#e74c3c', '#9b59b6', '#e67e22', '#2ecc71', '#800000'];
        return colors[(id - 1) % 7];
    },

    shoot() {
        if (!this.whiteBall.active) return;

        // 计算力度向量
        // 逻辑:鼠标当前位置 -> 白球位置 = 施力方向
        // 距离 = 力度
        let mouseV = Vector.new(this.input.x, this.input.y);
        let ballV = Vector.new(this.whiteBall.x, this.whiteBall.y);
        
        let aimDir = Vector.sub(ballV, mouseV); // 方向:鼠标指向白球
        let dist = Vector.mag(aimDir);
        
        // 限制最大力度
        let power = dist * CONFIG.POWER_SCALE;
        if (power > CONFIG.MAX_POWER) power = CONFIG.MAX_POWER;
        if (power < 0.2) return; // 防止误触

        let normalDir = Vector.normalize(aimDir);
        let velocity = Vector.mult(normalDir, power);

        this.whiteBall.vx = velocity.x;
        this.whiteBall.vy = velocity.y;

        // 重置回合状态
        this.state.turnInfo.pottedAny = false;
        this.state.turnInfo.foul = false;
    },

    update() {
        let moving = false;

        // 1. 物理更新
        this.balls.forEach(b => {
            if (!b.active) return;

            // 移动
            b.x += b.vx;
            b.y += b.vy;

            // 摩擦力
            b.vx *= CONFIG.FRICTION;
            b.vy *= CONFIG.FRICTION;

            // 停止阈值
            if (Math.abs(b.vx) < 0.05 && Math.abs(b.vy) < 0.05) {
                b.vx = 0; b.vy = 0;
            } else {
                moving = true;
            }

            // 墙壁碰撞
            if (b.x < CONFIG.BALL_R) { b.x = CONFIG.BALL_R; b.vx *= -CONFIG.WALL_BOUNCE; }
            if (b.x > CONFIG.WIDTH - CONFIG.BALL_R) { b.x = CONFIG.WIDTH - CONFIG.BALL_R; b.vx *= -CONFIG.WALL_BOUNCE; }
            if (b.y < CONFIG.BALL_R) { b.y = CONFIG.BALL_R; b.vy *= -CONFIG.WALL_BOUNCE; }
            if (b.y > CONFIG.HEIGHT - CONFIG.BALL_R) { b.y = CONFIG.HEIGHT - CONFIG.BALL_R; b.vy *= -CONFIG.WALL_BOUNCE; }
        });

        // 2. 球球碰撞 (多次迭代以提高稳定性)
        for(let iter=0; iter<8; iter++) {
            for (let i = 0; i < this.balls.length; i++) {
                for (let j = i + 1; j < this.balls.length; j++) {
                    let b1 = this.balls[i];
                    let b2 = this.balls[j];
                    if (!b1.active || !b2.active) continue;

                    let dx = b2.x - b1.x;
                    let dy = b2.y - b1.y;
                    let dist = Math.sqrt(dx*dx + dy*dy);

                    if (dist < CONFIG.BALL_R * 2) {
                        // 碰撞发生
                        let angle = Math.atan2(dy, dx);
                        let sin = Math.sin(angle);
                        let cos = Math.cos(angle);

                        // 旋转坐标系
                        let pos1 = {x: 0, y: 0};
                        let pos2 = {x: dx * cos + dy * sin, y: dy * cos - dx * sin};
                        let vel1 = {x: b1.vx * cos + b1.vy * sin, y: b1.vy * cos - b1.vx * sin};
                        let vel2 = {x: b2.vx * cos + b2.vy * sin, y: b2.vy * cos - b2.vx * sin};

                        // 碰撞反应 (一维弹性碰撞)
                        let vxTotal = vel1.x - vel2.x;
                        vel1.x = ((vel1.x - vel2.x) + vel2.x); // 简化:等质量交换速度
                        // 实际上等质量完全弹性碰撞:v1_new = v2, v2_new = v1
                        let temp = vel1.x;
                        vel1.x = vel2.x;
                        vel2.x = temp;

                        // 修正重叠 (防止粘连)
                        let absV = Math.abs(vel1.x) + Math.abs(vel2.x);
                        let overlap = (CONFIG.BALL_R * 2 - dist) + 0.5; // 加一点额外推力
                        // 简单的位置修正
                        let posCorrection = overlap / 2;
                        pos1.x -= posCorrection;
                        pos2.x += posCorrection;

                        // 旋转回原坐标系
                        let pos1F = {x: pos1.x * cos - pos1.y * sin, y: pos1.y * cos + pos1.x * sin};
                        let pos2F = {x: pos2.x * cos - pos2.y * sin, y: pos2.y * cos + pos2.x * sin};
                        
                        // 注意:这里不能直接改 pos,因为 pos 是相对的。
                        // 更简单的防重叠:直接把两个球推开
                        let normal = {x: dx/dist, y: dy/dist};
                        b1.x -= normal.x * (overlap/2);
                        b1.y -= normal.y * (overlap/2);
                        b2.x += normal.x * (overlap/2);
                        b2.y += normal.y * (overlap/2);

                        b1.vx = vel1.x * cos - vel1.y * sin;
                        b1.vy = vel1.y * cos + vel1.x * sin;
                        b2.vx = vel2.x * cos - vel2.y * sin;
                        b2.vy = vel2.y * cos + vel2.x * sin;
                    }
                }
            }
        }

        // 3. 进袋检测 (每帧都做)
        this.balls.forEach(b => {
            if (!b.active) return;
            for (let p of this.pockets) {
                if (Vector.dist(Vector.new(b.x, b.y), p) < CONFIG.POCKET_R) {
                    this.handlePot(b);
                }
            }
        });

        // 4. 状态流转
        // 检测到从“运动”变为“静止”的瞬间
        if (this.state.isMoving && !moving) {
            this.onTurnEnd();
        }
        this.state.isMoving = moving;
    },

    handlePot(ball) {
        ball.active = false;
        
        if (ball.id === 0) {
            // 白球进袋
            this.state.turnInfo.foul = true;
            this.showToast("白球进袋!犯规!");
            // 延迟复位白球,以便视觉上它先消失
            setTimeout(() => {
                this.whiteBall.active = true;
                this.whiteBall.x = 200;
                this.whiteBall.y = 200;
                this.whiteBall.vx = 0;
                this.whiteBall.vy = 0;
                // 防止复位时重叠
                // (简单起见不检测重叠,真实游戏需检测)
            }, 500);
        } else if (ball.id === 8) {
            // 黑8进袋
            let myScore = this.state.turn === 1 ? this.state.p1Score : this.state.p2Score;
            // 简单规则:如果不满7球进黑8判负,满了判胜
            // 这里简化:进了黑8游戏结束
            if (myScore < 7) {
                this.showToast(`黑8提前进袋!玩家 ${this.state.turn} 判负!`);
            } else {
                this.showToast(`恭喜!玩家 ${this.state.turn} 获胜!`);
            }
            this.state.gameOver = true;
        } else {
            // 普通球
            this.state.turnInfo.pottedAny = true;
            if (this.state.turn === 1) this.state.p1Score++;
            else this.state.p2Score++;
        }
        this.updateUI();
    },

    onTurnEnd() {
        if (this.state.gameOver) return;

        // 回合逻辑判断
        let switchTurn = true;

        if (this.state.turnInfo.foul) {
            switchTurn = true; // 犯规一定换人
        } else if (this.state.turnInfo.pottedAny) {
            switchTurn = false; // 进球且没犯规,连杆
            this.showToast(`漂亮!玩家 ${this.state.turn} 继续击球`);
        }

        if (switchTurn) {
            this.state.turn = this.state.turn === 1 ? 2 : 1;
            this.updateUI();
        }
    },

    draw() {
        this.ctx.clearRect(0, 0, CONFIG.WIDTH, CONFIG.HEIGHT);

        // 绘制球袋
        this.ctx.fillStyle = '#111';
        this.pockets.forEach(p => {
            this.ctx.beginPath();
            this.ctx.arc(p.x, p.y, CONFIG.POCKET_R, 0, Math.PI*2);
            this.ctx.fill();
        });

        // 绘制球杆/瞄准线 (仅当静止且白球在场且未结束)
        if (!this.state.isMoving && this.whiteBall.active && !this.state.gameOver) {
            this.drawCue();
        }

        // 绘制球
        this.balls.forEach(b => {
            if(b.active) this.drawBall(b);
        });
    },

    drawBall(b) {
        this.ctx.beginPath();
        this.ctx.arc(b.x, b.y, CONFIG.BALL_R, 0, Math.PI*2);
        this.ctx.fillStyle = b.color;
        this.ctx.fill();
        
        // 简单的球体阴影/高光
        this.ctx.strokeStyle = "rgba(0,0,0,0.3)";
        this.ctx.lineWidth = 1;
        this.ctx.stroke();
        
        this.ctx.beginPath();
        this.ctx.arc(b.x - 3, b.y - 3, 2, 0, Math.PI*2);
        this.ctx.fillStyle = "rgba(255,255,255,0.5)";
        this.ctx.fill();

        // 花色球条纹 (ID > 8)
        if (b.id > 8) {
            this.ctx.beginPath();
            this.ctx.arc(b.x, b.y, CONFIG.BALL_R - 2, 0, Math.PI*2);
            this.ctx.strokeStyle = "rgba(255,255,255,0.8)";
            this.ctx.lineWidth = 2;
            this.ctx.stroke();
        }

        if (b.id !== 0) {
            this.ctx.fillStyle = (b.id === 8 || b.color === '#000') ? 'white' : 'black';
            this.ctx.font = "10px Arial";
            this.ctx.textAlign = "center";
            this.ctx.textBaseline = "middle";
            this.ctx.fillText(b.id, b.x, b.y);
        }
    },

    drawCue() {
        let mouseV = Vector.new(this.input.x, this.input.y);
        let ballV = Vector.new(this.whiteBall.x, this.whiteBall.y);
        
        // 计算角度:鼠标指向白球
        let angle = Math.atan2(ballV.y - mouseV.y, ballV.x - mouseV.x);
        
        this.ctx.save();
        this.ctx.translate(this.whiteBall.x, this.whiteBall.y);
        this.ctx.rotate(angle);

        // 1. 瞄准线 (向前延伸)
        this.ctx.beginPath();
        this.ctx.strokeStyle = "rgba(255, 255, 255, 0.4)";
        this.ctx.setLineDash([4, 4]);
        this.ctx.moveTo(0, 0);
        this.ctx.lineTo(800, 0); // 瞄准线
        this.ctx.stroke();
        this.ctx.setLineDash([]);

        // 2. 球杆绘制
        // 如果正在蓄力,计算拉杆距离
        let pullDist = 0;
        if (this.state.isCharging) {
            // 计算鼠标到白球的距离作为力度参考
            let dist = Vector.dist(mouseV, ballV);
            // 限制视觉上的最大拉杆距离
            let power = dist * CONFIG.POWER_SCALE;
            if (power > CONFIG.MAX_POWER) power = CONFIG.MAX_POWER;
            // 将力度转换为像素偏移,使得球杆后退
            pullDist = power * 5; // 视觉放大系数
            
            // 绘制力度条
            this.ctx.fillStyle = this.getPowerColor(power);
            this.ctx.fillRect(-10, -20, power * 4, 5); // 简易力度条
        }

        // 绘制球杆本体 (在白球后方,即负x方向)
        const cueOffset = 15 + pullDist; 
        // 注意:canvas旋转后,x正方向是瞄准方向。球杆应该在 x 负方向。
        
        this.ctx.beginPath();
        this.ctx.fillStyle = "#8d5524"; // 杆身
        this.ctx.fillRect(-300 - cueOffset, -4, 300, 8);
        
        this.ctx.fillStyle = "#ecf0f1"; // 杆头
        this.ctx.fillRect(-5 - cueOffset, -4, 5, 8);
        
        this.ctx.fillStyle = "#e67e22"; // 握把装饰
        this.ctx.fillRect(-300 - cueOffset, -4, 80, 8);

        this.ctx.restore();
    },

    getPowerColor(power) {
        let p = power / CONFIG.MAX_POWER;
        if (p < 0.5) return `rgb(${p*2*255}, 255, 0)`;
        return `rgb(255, ${(1-p)*2*255}, 0)`;
    },

    loop() {
        game.update();
        game.draw();
        requestAnimationFrame(() => game.loop());
    },

    showToast(msg) {
        const t = document.getElementById('toast');
        t.innerText = msg;
        t.style.opacity = 1;
        clearTimeout(this.toastTimer);
        this.toastTimer = setTimeout(() => t.style.opacity = 0, 2000);
    },
    
    hideToast() {
        document.getElementById('toast').style.opacity = 0;
    },

    updateUI() {
        document.getElementById('p1-score').innerText = this.state.p1Score;
        document.getElementById('p2-score').innerText = this.state.p2Score;
        const p1Card = document.getElementById('p1-card');
        const p2Card = document.getElementById('p2-card');
        
        if (this.state.turn === 1) {
            p1Card.classList.add('active-turn');
            p2Card.classList.remove('active-turn');
        } else {
            p2Card.classList.add('active-turn');
            p1Card.classList.remove('active-turn');
        }
    }
};

// 启动游戏
game.init();

</script>
</body>
</html>

效果

在这里插入图片描述

2. 半导体二极管知识教学HTML

Prompt

我是一名计算机专业教师,正在授课《电子电路技术》。目前授课到半导体部分。

现在设计并创建一个非常有创意的网页。能展示常见的半导体二极管元器件,能进行 3d 的旋转和放大;二极管的基本结构和类型;二极管的伏安特性;二极管的应用举例;

可以使用任何库来完成我需要的效果,但要确保我能把所有内容黏贴到一个单独的 HTML 文件中,并直接在 Chrome 中打开。

我将给你 PPT 和教案做参考。

第一次的对话,自动调用了 Canvas 工具,不过没有预览出效果。
让 Gemini 修复了大概 3 次后,出现了第一次的效果。
认为出现的效果不佳,因此提出修改意见

有一些问题:
1. 授课对象是 xxxx
2. 3d 虚拟元件库上的出现了带叉的方块,是不是字符集没有识别
3. 3d 虚拟元件库增加检波管、检波管、检波管、光电二极管
4. 增加二极管的符号介绍;增加二极管的整流;增加二极管的限幅

Gemini 3 Pro 给出的代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>电子电路技术 - 半导体二极管 3D 交互教学</title>
    <!-- 引入 Tailwind CSS 用于美观的 UI -->
    <script src="https://cdn.tailwindcss.com"></script>
    
    <!-- 配置 Import Map 以便在浏览器中直接使用 React 和 Three.js 模块 -->
    <script type="importmap">
    {
        "imports": {
            "react": "https://esm.sh/react@18.2.0",
            "react-dom": "https://esm.sh/react-dom@18.2.0",
            "react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
            "three": "https://esm.sh/three@0.160.0",
            "@react-three/fiber": "https://esm.sh/@react-three/fiber@8.15.14?external=react,react-dom,three",
            "@react-three/drei": "https://esm.sh/@react-three/drei@9.96.1?external=react,react-dom,three,@react-three/fiber",
            "recharts": "https://esm.sh/recharts@2.10.4?external=react,react-dom",
            "lucide-react": "https://esm.sh/lucide-react@0.309.0?external=react,react-dom"
        }
    }
    </script>
    <!-- 引入 Babel 用于在浏览器中编译 JSX -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    
    <style>
        body { margin: 0; background-color: #f8fafc; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
        .glass-panel {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
        }
        /* 自定义滚动条 */
        ::-webkit-scrollbar { width: 8px; }
        ::-webkit-scrollbar-track { background: #f1f1f1; }
        ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
        ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
        
        /* 简单的淡入动画 */
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        .animate-fadeIn {
            animation: fadeIn 0.5s ease-out forwards;
        }
    </style>
</head>
<body>
    <div id="root"></div>

    <script type="text/babel" data-type="module">
        import React, { useState, useRef, useEffect, useMemo } from 'react';
        import { createRoot } from 'react-dom/client';
        import * as THREE from 'three';
        import { Canvas, useFrame } from '@react-three/fiber';
        import { OrbitControls, Text, Environment, ContactShadows, Float } from '@react-three/drei';
        import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ReferenceLine, ResponsiveContainer, ReferenceArea } from 'recharts';
        import { Zap, BookOpen, Activity, PenTool, Power, ChevronRight, RotateCw, Info, PlayCircle, RefreshCcw, Waves, Scissors, Sun } from 'lucide-react';

        // --- 3D 模型组件 ---
        // 注意:3D场景内的文字标签全部改为英文,以修复中文字符集显示乱码的问题。

        // 1. 整流二极管 (1N4007 风格)
        const RectifierDiode = (props) => {
            return (
                <group {...props}>
                    {/* 管体 - 黑色圆柱 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0, 0, 0]}>
                        <cylinderGeometry args={[0.6, 0.6, 2.5, 32]} />
                        <meshStandardMaterial color="#1a1a1a" roughness={0.4} metalness={0.1} />
                    </mesh>
                    {/* 银色色环 (阴极) */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0.8, 0, 0]}>
                        <cylinderGeometry args={[0.61, 0.61, 0.4, 32]} />
                        <meshStandardMaterial color="#e2e8f0" roughness={0.3} metalness={0.8} />
                    </mesh>
                    {/* 引脚 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[-2.25, 0, 0]}>
                        <cylinderGeometry args={[0.1, 0.1, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} roughness={0.1} />
                    </mesh>
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[2.25, 0, 0]}>
                        <cylinderGeometry args={[0.1, 0.1, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} roughness={0.1} />
                    </mesh>
                    {/* 英文标签 */}
                    <Text position={[-1.5, 1, 0]} fontSize={0.3} color="#334155">Anode (+)</Text>
                    <Text position={[1.5, 1, 0]} fontSize={0.3} color="#334155">Cathode (-)</Text>
                </group>
            );
        };

        // 2. 发光二极管 (LED)
        const LED = ({ color = "#ef4444", active }) => {
            return (
                <group rotation={[0, 0, 0]} position={[0, -0.5, 0]}>
                    {/* 灯体 */}
                    <mesh position={[0, 1, 0]}>
                        <cylinderGeometry args={[0.8, 0.8, 1.5, 32]} />
                        <meshPhysicalMaterial 
                            color={color} 
                            transparent 
                            opacity={0.8} 
                            transmission={0.5} 
                            roughness={0.1} 
                            emissive={active ? color : "#000"}
                            emissiveIntensity={active ? 2 : 0}
                        />
                    </mesh>
                    {/* 顶部圆顶 */}
                    <mesh position={[0, 1.75, 0]}>
                        <sphereGeometry args={[0.8, 32, 16, 0, Math.PI * 2, 0, Math.PI / 2]} />
                        <meshPhysicalMaterial 
                            color={color} 
                            transparent 
                            opacity={0.8} 
                            transmission={0.5} 
                            roughness={0.1}
                            emissive={active ? color : "#000"}
                            emissiveIntensity={active ? 2 : 0}
                        />
                    </mesh>
                    {/* 底部边缘 */}
                    <mesh position={[0, 0.2, 0]}>
                         <cylinderGeometry args={[0.9, 0.9, 0.2, 32]} />
                         <meshPhysicalMaterial color={color} transparent opacity={0.9} />
                    </mesh>
                    {/* 引脚 (长脚阳极,短脚阴极) */}
                    <mesh position={[0.3, -1.5, 0]}>
                        <cylinderGeometry args={[0.08, 0.08, 3.5, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} roughness={0.1} />
                    </mesh>
                    <mesh position={[-0.3, -1.25, 0]}>
                        <cylinderGeometry args={[0.08, 0.08, 3, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} roughness={0.1} />
                    </mesh>
                     <Text position={[1.2, -1, 0]} fontSize={0.25} color="#334155">Long: Pos (+)</Text>
                     <Text position={[-1.2, -1, 0]} fontSize={0.25} color="#334155">Short: Neg (-)</Text>
                </group>
            );
        };

        // 3. 稳压二极管 (玻璃封装)
        const ZenerDiode = (props) => {
            return (
                <group {...props}>
                    {/* 玻璃管体 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0, 0, 0]}>
                        <cylinderGeometry args={[0.4, 0.4, 1.8, 32]} />
                        <meshPhysicalMaterial color="#fca5a5" transmission={0.8} opacity={0.6} transparent roughness={0.1} />
                    </mesh>
                    {/* 内部黑环 (阴极) */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0.5, 0, 0]}>
                        <cylinderGeometry args={[0.38, 0.38, 0.4, 32]} />
                         <meshStandardMaterial color="#000000" />
                    </mesh>
                    {/* 引脚 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[-1.9, 0, 0]}>
                        <cylinderGeometry args={[0.08, 0.08, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} />
                    </mesh>
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[1.9, 0, 0]}>
                        <cylinderGeometry args={[0.08, 0.08, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} />
                    </mesh>
                    <Text position={[0, -1, 0]} fontSize={0.3} color="#ef4444">Zener Diode</Text>
                    <Text position={[1.2, 0.8, 0]} fontSize={0.2} color="gray">Cathode</Text>
                </group>
            );
        };

        // 4. 检波二极管 (Detector Diode - 点接触型,玻璃封装)
        const DetectorDiode = (props) => {
            return (
                <group {...props}>
                    {/* 玻璃管体 - 更透明细长 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0, 0, 0]}>
                        <cylinderGeometry args={[0.3, 0.3, 1.6, 32]} />
                        <meshPhysicalMaterial color="#e0f2fe" transmission={0.9} opacity={0.4} transparent roughness={0.05} />
                    </mesh>
                    {/* 内部触须 (点接触特征) */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[-0.2, 0, 0]}>
                         <cylinderGeometry args={[0.02, 0.02, 0.8, 8]} />
                         <meshStandardMaterial color="#fbbf24" />
                    </mesh>
                    {/* 晶片 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0.3, 0, 0]}>
                        <boxGeometry args={[0.1, 0.2, 0.2]} />
                        <meshStandardMaterial color="#334155" />
                    </mesh>
                    {/* 阴极标记环 - 绿色 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[0.5, 0, 0]}>
                        <cylinderGeometry args={[0.305, 0.305, 0.2, 32]} />
                         <meshStandardMaterial color="#22c55e" />
                    </mesh>
                    {/* 引脚 */}
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[-1.8, 0, 0]}>
                        <cylinderGeometry args={[0.06, 0.06, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} />
                    </mesh>
                    <mesh rotation={[0, 0, Math.PI / 2]} position={[1.8, 0, 0]}>
                        <cylinderGeometry args={[0.06, 0.06, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} />
                    </mesh>
                    <Text position={[0, -1, 0]} fontSize={0.3} color="#22c55e">Detector</Text>
                </group>
            );
        };

        // 5. 光电二极管 (Photodiode - 顶部受光)
        const Photodiode = (props) => {
            return (
                <group {...props} rotation={[Math.PI/4, 0, 0]} position={[0, -0.5, 0]}>
                    {/* 黑色方形底座 */}
                    <mesh position={[0, 0, 0]}>
                        <boxGeometry args={[1.0, 0.2, 1.0]} />
                        <meshStandardMaterial color="#1e293b" />
                    </mesh>
                    {/* 黑色圆柱体外壳 */}
                    <mesh position={[0, 0.5, 0]}>
                        <cylinderGeometry args={[0.4, 0.4, 0.8, 32]} />
                        <meshStandardMaterial color="#1e293b" />
                    </mesh>
                    {/* 顶部受光窗口 (深蓝色/黑色玻璃) */}
                    <mesh position={[0, 0.91, 0]}>
                        <cylinderGeometry args={[0.35, 0.35, 0.05, 32]} />
                        <meshPhysicalMaterial color="#1e3a8a" transmission={0.2} roughness={0.1} metalness={0.8} />
                    </mesh>
                    {/* 引脚 */}
                    <mesh position={[0.2, -1.0, 0]}>
                        <cylinderGeometry args={[0.05, 0.05, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} />
                    </mesh>
                    <mesh position={[-0.2, -1.0, 0]}>
                        <cylinderGeometry args={[0.05, 0.05, 2, 16]} />
                        <meshStandardMaterial color="#cbd5e1" metalness={0.9} />
                    </mesh>
                    <Text position={[0, -1.5, 0]} fontSize={0.3} color="#3b82f6">Photodiode</Text>
                </group>
            );
        };


        // --- 功能组件 ---

        // 伏安特性曲线图表
        const VIChart = () => {
            // 模拟硅二极管的 V-I 数据 (结合PPT中的死区0.5V,导通0.7V)
            const data = [
                { u: -10, i: -50, region: '击穿区' },
                { u: -8, i: -5, region: '反向击穿' }, 
                { u: -5, i: -0.1, region: '反向截止' },
                { u: -2, i: 0, region: '反向截止' },
                { u: 0, i: 0, region: '死区' },
                { u: 0.2, i: 0, region: '死区' },
                { u: 0.5, i: 0.1, region: '死区' }, 
                { u: 0.6, i: 2, region: '导通区' },
                { u: 0.7, i: 15, region: '导通区' }, 
                { u: 0.8, i: 40, region: '导通区' },
                { u: 0.9, i: 80, region: '导通区' },
            ];

            return (
                <div className="w-full h-80 bg-white rounded-lg p-4 shadow-sm border border-slate-100">
                    <h3 className="text-lg font-bold mb-2 text-slate-700 flex items-center gap-2">
                        <Activity className="w-5 h-5 text-blue-500"/>
                        二极管伏安特性曲线 (硅管)
                    </h3>
                    <ResponsiveContainer width="100%" height="100%">
                        <LineChart data={data} margin={{ top: 5, right: 20, bottom: 20, left: 0 }}>
                            <CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
                            <XAxis dataKey="u" type="number" domain={[-10, 1]} label={{ value: '电压 U (V)', position: 'insideBottomRight', offset: -5 }} />
                            <YAxis label={{ value: '电流 I (mA)', angle: -90, position: 'insideLeft' }} />
                            <Tooltip 
                                contentStyle={{ backgroundColor: 'rgba(255,255,255,0.95)', borderRadius: '8px', border: '1px solid #e2e8f0', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)' }}
                                formatter={(value, name) => [value + (name === 'i' ? ' mA' : ' V'), name === 'i' ? '电流' : '电压']}
                            />
                            <ReferenceLine x={0} stroke="#94a3b8" strokeWidth={2}/>
                            <ReferenceLine y={0} stroke="#94a3b8" strokeWidth={2}/>
                            
                            {/* 区域标注 */}
                            <ReferenceArea x1={0} x2={0.5} stroke="none" fill="#fee2e2" fillOpacity={0.3} label={{ value: "死区(0-0.5V)", position: 'insideTop', fill: '#ef4444', fontSize: 12 }} />
                            <ReferenceArea x1={0.5} x2={1} stroke="none" fill="#dbeafe" fillOpacity={0.3} label={{ value: "正向导通", position: 'insideTop', fill: '#3b82f6', fontSize: 12 }} />
                            <ReferenceArea x1={-8} x2={-10} stroke="none" fill="#ffedd5" fillOpacity={0.5} label={{ value: "反向击穿", position: 'insideBottom', fill: '#f97316', fontSize: 12 }} />
                            
                            <Line type="monotone" dataKey="i" stroke="#3b82f6" strokeWidth={3} dot={{ r: 4 }} activeDot={{ r: 8 }} />
                        </LineChart>
                    </ResponsiveContainer>
                    <div className="flex flex-wrap justify-center gap-4 text-sm text-slate-500 mt-2">
                        <span className="flex items-center gap-1"><div className="w-3 h-3 bg-red-200 rounded-sm"></div> 死区: 电压太低无法导通</span>
                        <span className="flex items-center gap-1"><div className="w-3 h-3 bg-blue-200 rounded-sm"></div> 导通区: 电流随电压迅速增大</span>
                    </div>
                </div>
            );
        };

        // 电路仿真组件
        const CircuitSimulation = () => {
            const [powerOn, setPowerOn] = useState(false);
            const [diodeDirection, setDiodeDirection] = useState('forward'); // forward (正向), reverse (反向)

            // 判断灯是否亮:开关闭合 且 二极管正向
            const isLit = powerOn && diodeDirection === 'forward';

            return (
                <div className="bg-slate-800 p-6 rounded-xl text-white shadow-lg">
                    <div className="flex justify-between items-center mb-4">
                        <h3 className="text-lg font-bold flex items-center gap-2">
                            <Zap className="w-5 h-5 text-yellow-400"/>
                            仿真实验:单向导电性
                        </h3>
                        <div className="text-xs bg-slate-700 px-2 py-1 rounded text-slate-300">
                            点击开关和元件进行操作
                        </div>
                    </div>
                    
                    {/* 电路可视化区域 */}
                    <div className="relative bg-slate-900/50 rounded-xl p-8 border border-slate-700 flex flex-col md:flex-row items-center justify-between gap-8 overflow-hidden">
                        
                        {/* 导线 - 连接线 */}
                        <div className="absolute inset-0 pointer-events-none">
                             <svg className="w-full h-full" style={{zIndex: 0}}>
                                <path d="M 80 80 L 80 40 L 200 40" stroke={powerOn ? "#facc15" : "#475569"} strokeWidth="4" fill="none" className="transition-colors duration-300"/>
                                <path d="M 280 40 L 400 40" stroke={powerOn ? "#facc15" : "#475569"} strokeWidth="4" fill="none" className="transition-colors duration-300"/>
                                <path d="M 480 40 L 600 40 L 600 80" stroke={powerOn && diodeDirection === 'forward' ? "#facc15" : "#475569"} strokeWidth="4" fill="none" className="transition-colors duration-300"/>
                             </svg>
                        </div>

                        {/* 1. 电源 */}
                        <div className="flex flex-col items-center z-10">
                            <div className="w-16 h-20 bg-slate-200 rounded-md border-4 border-slate-400 flex flex-col items-center justify-center relative shadow-md">
                                <div className="w-8 h-2 bg-slate-400 absolute -top-2 rounded-t"></div>
                                <div className="text-2xl font-bold text-slate-700">DC</div>
                                <div className="text-xs text-slate-500">5V</div>
                                <div className="absolute -left-4 top-2 text-red-400 font-bold text-xl">+</div>
                            </div>
                            <span className="mt-2 text-sm text-slate-300">直流电源</span>
                        </div>

                        {/* 2. 开关 */}
                        <div 
                            className="flex flex-col items-center z-10 cursor-pointer group"
                            onClick={() => setPowerOn(!powerOn)}
                        >
                            <div className="w-20 h-12 bg-slate-700 border-2 border-slate-500 rounded flex items-center justify-center relative hover:border-blue-400 transition-colors shadow-md">
                                {/* 开关闸刀 */}
                                <div 
                                    className={`w-12 h-1 bg-white absolute transition-transform duration-300 origin-left ${powerOn ? 'rotate-0' : '-rotate-[30deg]'}`} 
                                    style={{left: '20%', top: '50%'}}
                                ></div>
                                <div className="w-2 h-2 bg-slate-400 rounded-full absolute left-4 top-1/2 -translate-y-1/2"></div>
                                <div className="w-2 h-2 bg-slate-400 rounded-full absolute right-4 top-1/2 -translate-y-1/2"></div>
                            </div>
                            <span className="mt-2 text-sm text-slate-300 group-hover:text-blue-300 transition-colors flex items-center gap-1">
                                开关 S <PlayCircle className="w-3 h-3"/>
                            </span>
                        </div>

                        {/* 3. 二极管 (可翻转) */}
                        <div 
                            className="flex flex-col items-center z-10 cursor-pointer group"
                            onClick={() => setDiodeDirection(prev => prev === 'forward' ? 'reverse' : 'forward')}
                        >
                            <div className="w-24 h-12 bg-slate-700 border-2 border-slate-500 rounded flex items-center justify-center hover:border-blue-400 transition-colors shadow-md relative">
                                <div className={`transition-transform duration-500 ${diodeDirection === 'reverse' ? 'rotate-180' : ''}`}>
                                    {/* 二极管符号 SVG */}
                                    <svg width="50" height="30" viewBox="0 0 50 30" fill="none">
                                        <path d="M0 15 H15 M35 15 H50" stroke="white" strokeWidth="2"/>
                                        <path d="M15 5 L15 25 L35 15 Z" fill="#ef4444" stroke="none"/> {/* 三角形 P区 */}
                                        <line x1="35" y1="5" x2="35" y2="25" stroke="white" strokeWidth="3"/> {/* 竖线 N区 */}
                                    </svg>
                                </div>
                            </div>
                            <span className="mt-2 text-sm text-slate-300 group-hover:text-blue-300 transition-colors flex items-center gap-1">
                                <RefreshCcw className="w-3 h-3"/>
                                {diodeDirection === 'forward' ? '正向接法' : '反向接法'}
                            </span>
                        </div>

                        {/* 4. 灯泡 */}
                        <div className="flex flex-col items-center z-10">
                            <div className={`w-16 h-16 rounded-full border-4 flex items-center justify-center transition-all duration-300 ${isLit ? 'bg-yellow-200 border-yellow-400 shadow-[0_0_40px_rgba(250,204,21,0.8)]' : 'bg-slate-800 border-slate-600'}`}>
                                <Zap className={`w-8 h-8 ${isLit ? 'text-yellow-600 fill-yellow-600' : 'text-slate-600'}`} />
                            </div>
                            <span className="mt-2 text-sm text-slate-300">负载 (灯泡)</span>
                        </div>
                    </div>

                    {/* 实验结论反馈 */}
                    <div className="mt-4 bg-slate-700/50 p-4 rounded-lg border-l-4 border-blue-500 transition-all">
                        <p className="font-bold text-sm text-blue-300 mb-1">实验现象分析:</p>
                        <div className="text-sm text-slate-300">
                            {powerOn ? (
                                diodeDirection === 'forward' ? 
                                "✅ 电路导通:二极管正向偏置(阳极接正,阴极接负),电阻极小,灯泡发光。" : 
                                "❌ 电路截止:二极管反向偏置(阳极接负,阴极接正),电阻极大,灯泡不亮。"
                            ) : "⚠️ 电路断开:请先闭合开关 S。"}
                        </div>
                    </div>
                </div>
            );
        };

        // 主组件
        const App = () => {
            const [activeModel, setActiveModel] = useState('rectifier'); // rectifier, led, zener, detector, photodiode
            const [activeTab, setActiveTab] = useState('types'); // structure, theory, types

            // 预设的模型信息
            const modelInfo = {
                rectifier: { title: "普通整流二极管", desc: "黑色圆柱体,银色色环代表负极(阴极)。主要用于将交流电变为直流电。" },
                led: { title: "发光二极管 (LED)", desc: "长引脚为正极,短引脚为负极。通电后发光,常用于指示灯和照明。" },
                zener: { title: "稳压二极管", desc: "通常为玻璃封装,黑色环标记负极。工作在反向击穿区,用于稳定电压。" },
                detector: { title: "检波二极管", desc: "点接触型,结电容小。用于从高频信号中检出音频信号(检波)。" },
                photodiode: { title: "光电二极管", desc: "受光照控制的反向偏置二极管。光照越强,反向电流(光电流)越大。用于光控开关。" }
            };

            return (
                <div className="min-h-screen pb-10">
                    {/* 页眉 */}
                    <header className="bg-gradient-to-r from-blue-700 to-indigo-800 text-white p-6 shadow-lg sticky top-0 z-50">
                        <div className="container mx-auto flex flex-col md:flex-row justify-between items-center">
                            <div>
                                <h1 className="text-2xl md:text-3xl font-bold flex items-center gap-3">
                                    <BookOpen className="w-8 h-8"/>
                                    电子电路技术基础
                                </h1>
                                <p className="text-blue-200 mt-2 text-sm md:text-base">第六章:半导体及其常用器件 —— 二极管</p>
                            </div>
                            <div className="mt-4 md:mt-0 bg-white/10 px-4 py-2 rounded-full text-xs md:text-sm backdrop-blur-sm border border-white/20">
                                授课对象:xxxx
                            </div>
                        </div>
                    </header>

                    <main className="container mx-auto px-4 mt-8 grid grid-cols-1 lg:grid-cols-12 gap-8">
                        
                        {/* 左侧区域:3D 观察与仿真 (LG: 5 cols) */}
                        <div className="lg:col-span-5 flex flex-col gap-6">
                            {/* 3D 展示卡片 */}
                            <div className="glass-panel rounded-2xl overflow-hidden flex flex-col h-[600px] relative shadow-xl">
                                <div className="absolute top-4 left-4 z-10 bg-white/90 backdrop-blur px-3 py-1 rounded-full text-sm font-bold text-slate-700 shadow-sm flex items-center gap-2">
                                    <RotateCw className="w-4 h-4 text-blue-500"/> 3D 虚拟元件库
                                </div>
                                
                                {/* 模型切换按钮 - 更新布局以适应更多按钮 */}
                                <div className="absolute top-4 right-4 z-10 flex flex-col gap-2">
                                    {['rectifier', 'led', 'zener', 'detector', 'photodiode'].map(key => (
                                        <button 
                                            key={key}
                                            onClick={() => setActiveModel(key)}
                                            className={`px-3 py-1.5 text-xs font-medium rounded-lg shadow-sm transition-all text-left border ${activeModel === key ? 'bg-blue-600 text-white border-blue-600' : 'bg-white/90 text-slate-600 border-slate-200 hover:bg-slate-50'}`}
                                        >
                                            {modelInfo[key].title}
                                        </button>
                                    ))}
                                </div>

                                <div className="flex-1 bg-gradient-to-b from-slate-100 to-slate-200 cursor-move">
                                    <Canvas camera={{ position: [0, 1, 4], fov: 50 }}>
                                        <Environment preset="city" />
                                        <ambientLight intensity={0.6} />
                                        <pointLight position={[10, 10, 10]} intensity={0.8} />
                                        <pointLight position={[-10, -10, -10]} intensity={0.5} />
                                        
                                        <Float speed={2} rotationIntensity={0.5} floatIntensity={0.5}>
                                            {activeModel === 'rectifier' && <RectifierDiode />}
                                            {activeModel === 'led' && <LED active={true} />}
                                            {activeModel === 'zener' && <ZenerDiode />}
                                            {activeModel === 'detector' && <DetectorDiode />}
                                            {activeModel === 'photodiode' && <Photodiode />}
                                        </Float>
                                        
                                        <ContactShadows position={[0, -1.5, 0]} opacity={0.4} scale={10} blur={2.5} far={4} />
                                        <OrbitControls enableZoom={true} minPolarAngle={Math.PI/4} maxPolarAngle={Math.PI/1.5} />
                                    </Canvas>
                                </div>
                                
                                {/* 模型说明信息 */}
                                <div className="absolute bottom-0 left-0 right-0 bg-white/90 backdrop-blur-md p-4 border-t border-slate-100">
                                    <h4 className="font-bold text-slate-800 flex items-center gap-2">
                                        <Info className="w-4 h-4 text-blue-500"/>
                                        {modelInfo[activeModel].title}
                                    </h4>
                                    <p className="text-xs text-slate-500 mt-1">{modelInfo[activeModel].desc}</p>
                                </div>
                            </div>

                            {/* 电路仿真卡片 */}
                            <CircuitSimulation />
                        </div>

                        {/* 右侧区域:理论知识与图表 (LG: 7 cols) */}
                        <div className="lg:col-span-7 flex flex-col gap-6">
                            
                            {/* 选项卡导航 */}
                            <div className="flex p-1 bg-slate-200/50 rounded-xl">
                                {[
                                    { id: 'types', label: '类型与应用', icon: <PenTool className="w-4 h-4"/> },
                                    { id: 'theory', label: '伏安特性', icon: <Activity className="w-4 h-4"/> },
                                    { id: 'structure', label: '结构与原理', icon: <BoxIcon /> },
                                ].map(tab => (
                                    <button
                                        key={tab.id}
                                        onClick={() => setActiveTab(tab.id)}
                                        className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-lg text-sm font-bold transition-all ${activeTab === tab.id ? 'bg-white text-blue-600 shadow-sm ring-1 ring-black/5' : 'text-slate-500 hover:text-slate-700 hover:bg-white/50'}`}
                                    >
                                        {tab.icon}
                                        {tab.label}
                                    </button>
                                ))}
                            </div>

                            {/* 内容显示区 */}
                            <div className="bg-white rounded-2xl p-6 shadow-sm border border-slate-100 min-h-[600px] overflow-y-auto max-h-[calc(100vh-200px)]">
                                
                                {/* 1. 类型与应用 (包含新增的整流与限幅) */}
                                {activeTab === 'types' && (
                                    <div className="space-y-8 animate-fadeIn">
                                        <section>
                                            <h2 className="text-xl font-bold text-slate-800 border-l-4 border-green-500 pl-3 mb-4">符号与分类</h2>
                                            
                                            {/* 符号展示 */}
                                            <div className="flex justify-around bg-slate-50 p-4 rounded-xl border border-slate-100 mb-6">
                                                <div className="text-center">
                                                    <svg width="60" height="40" viewBox="0 0 60 40" className="mx-auto mb-1">
                                                        <line x1="0" y1="20" x2="20" y2="20" stroke="black" strokeWidth="2"/>
                                                        <path d="M20 10 L20 30 L40 20 Z" fill="none" stroke="black" strokeWidth="2"/>
                                                        <line x1="40" y1="10" x2="40" y2="30" stroke="black" strokeWidth="2"/>
                                                        <line x1="40" y1="20" x2="60" y2="20" stroke="black" strokeWidth="2"/>
                                                        <text x="5" y="10" fontSize="10" fill="gray">+</text>
                                                    </svg>
                                                    <span className="text-xs text-slate-600 font-bold">普通二极管</span>
                                                </div>
                                                <div className="text-center">
                                                    <svg width="60" height="40" viewBox="0 0 60 40" className="mx-auto mb-1">
                                                        <line x1="0" y1="20" x2="20" y2="20" stroke="black" strokeWidth="2"/>
                                                        <path d="M20 10 L20 30 L40 20 Z" fill="none" stroke="black" strokeWidth="2"/>
                                                        <polyline points="36,10 40,10 40,30 44,30" fill="none" stroke="black" strokeWidth="2"/>
                                                        <line x1="40" y1="20" x2="60" y2="20" stroke="black" strokeWidth="2"/>
                                                    </svg>
                                                    <span className="text-xs text-slate-600 font-bold">稳压二极管</span>
                                                </div>
                                                <div className="text-center">
                                                    <svg width="60" height="40" viewBox="0 0 60 40" className="mx-auto mb-1">
                                                        <line x1="0" y1="20" x2="20" y2="20" stroke="black" strokeWidth="2"/>
                                                        <path d="M20 10 L20 30 L40 20 Z" fill="none" stroke="black" strokeWidth="2"/>
                                                        <line x1="40" y1="10" x2="40" y2="30" stroke="black" strokeWidth="2"/>
                                                        <line x1="40" y1="20" x2="60" y2="20" stroke="black" strokeWidth="2"/>
                                                        <path d="M25 12 L15 2 M30 12 L20 2" stroke="black" strokeWidth="1.5" markerEnd="url(#arrow)"/>
                                                    </svg>
                                                    <span className="text-xs text-slate-600 font-bold">发光二极管</span>
                                                </div>
                                            </div>

                                            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                                                <TypeCard 
                                                    title="整流二极管" 
                                                    desc="利用单向导电性,将交流电(AC)变为脉动直流电(DC)。"
                                                    icon={<Power className="text-slate-500"/>}
                                                    tags={['面接触型', '低频']}
                                                    color="bg-slate-50"
                                                />
                                                <TypeCard 
                                                    title="稳压二极管" 
                                                    desc="工作在反向击穿区。只要电流限制在允许范围内,电压基本不变。"
                                                    icon={<Activity className="text-orange-500"/>}
                                                    tags={['反向工作', '电压基准']}
                                                    color="bg-orange-50"
                                                />
                                                <TypeCard 
                                                    title="检波二极管" 
                                                    desc="点接触型,结电容极小。用于从高频调幅信号中取出调制信号。"
                                                    icon={<Waves className="text-blue-500"/>}
                                                    tags={['点接触', '高频', '小电流']}
                                                    color="bg-blue-50"
                                                />
                                                <TypeCard 
                                                    title="光电二极管" 
                                                    desc="反向偏置工作。光照越强,反向电流(光电流)越大。"
                                                    icon={<Sun className="text-yellow-500"/>}
                                                    tags={['光控开关', '光信号接收']}
                                                    color="bg-yellow-50"
                                                />
                                            </div>
                                        </section>

                                        {/* 新增:整流电路 */}
                                        <section>
                                            <h2 className="text-xl font-bold text-slate-800 border-l-4 border-blue-500 pl-3 mb-4">应用一:整流电路</h2>
                                            <div className="bg-white p-4 border rounded-xl flex flex-col md:flex-row gap-6 items-center">
                                                <div className="flex-1">
                                                    <p className="text-sm text-slate-600 mb-2">利用二极管的<strong>单向导电性</strong>,把正负交变的交流电变成单方向的脉动直流电。</p>
                                                    <div className="h-24 flex items-center justify-center bg-slate-50 rounded border border-slate-200 relative overflow-hidden">
                                                        {/* 简单的正弦波转半波示意 */}
                                                        <svg viewBox="0 0 200 60" className="w-full h-full">
                                                            <path d="M10 30 Q 30 5 50 30 T 90 30 T 130 30" fill="none" stroke="#94a3b8" strokeWidth="2" strokeDasharray="4 2"/>
                                                            <path d="M10 30 Q 30 5 50 30 L 90 30 Q 110 5 130 30" fill="none" stroke="#ef4444" strokeWidth="3"/>
                                                            <text x="140" y="35" fontSize="10" fill="#ef4444">输出半波</text>
                                                        </svg>
                                                    </div>
                                                </div>
                                                <div className="w-32 text-xs text-slate-500 bg-slate-100 p-2 rounded">
                                                    <strong>半波整流:</strong><br/>正半周导通,负半周截止。效率较低。
                                                </div>
                                            </div>
                                        </section>

                                        {/* 新增:限幅电路 */}
                                        <section>
                                            <h2 className="text-xl font-bold text-slate-800 border-l-4 border-red-500 pl-3 mb-4">应用二:限幅电路</h2>
                                            <div className="bg-white p-4 border rounded-xl flex flex-col md:flex-row gap-6 items-center">
                                                <div className="flex-1">
                                                    <p className="text-sm text-slate-600 mb-2">利用二极管导通后<strong>电压恒定</strong>(约0.7V)的特性,将信号限制在一定幅度内。</p>
                                                    <div className="h-24 flex items-center justify-center bg-slate-50 rounded border border-slate-200 relative overflow-hidden">
                                                         <svg viewBox="0 0 200 60" className="w-full h-full">
                                                            <path d="M10 30 L 30 5 L 50 30 L 70 55 L 90 30" fill="none" stroke="#94a3b8" strokeWidth="2" strokeDasharray="4 2"/>
                                                            <path d="M10 30 L 20 15 H 40 L 50 30 L 60 45 H 80 L 90 30" fill="none" stroke="#3b82f6" strokeWidth="3"/>
                                                            <line x1="0" y1="15" x2="200" y2="15" stroke="#ef4444" strokeWidth="1" strokeDasharray="2"/>
                                                            <text x="100" y="12" fontSize="8" fill="#ef4444">限制电压 +E</text>
                                                        </svg>
                                                    </div>
                                                </div>
                                                <div className="w-32 text-xs text-slate-500 bg-slate-100 p-2 rounded">
                                                    <strong>双向限幅:</strong><br/>两个二极管反向并联,可限制信号的正负幅值。
                                                </div>
                                            </div>
                                        </section>
                                    </div>
                                )}

                                {/* 2. 伏安特性 */}
                                {activeTab === 'theory' && (
                                    <div className="space-y-6 animate-fadeIn">
                                        <h2 className="text-xl font-bold text-slate-800 border-l-4 border-blue-500 pl-3">二极管伏安特性曲线</h2>
                                        <p className="text-sm text-slate-600">
                                            将鼠标悬停在曲线上,观察不同电压下的电流变化。注意<strong>死区</strong><strong>反向击穿</strong></p>
                                        
                                        <VIChart />

                                        <div className="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
                                            <div className="bg-blue-50 p-5 rounded-xl border border-blue-100">
                                                <h4 className="font-bold text-blue-800 mb-3 flex items-center gap-2">
                                                    <ChevronRight className="w-4 h-4"/> 正向特性 (右半轴)
                                                </h4>
                                                <ul className="text-sm text-slate-700 space-y-2">
                                                    <li><strong>死区:</strong>电压较小时( &lt; 0.5V ),电流极小,二极管截止。硅管死区电压约 0.5V,锗管约 0.1V。</li>
                                                    <li><strong>导通区:</strong>电压超过死区后,电流迅速增大。</li>
                                                    <li><strong>导通压降:</strong>导通后两端电压基本恒定。硅管约 <span className="font-bold text-blue-600">0.6~0.7V</span>,锗管约 0.2~0.3V。</li>
                                                </ul>
                                            </div>
                                            <div className="bg-orange-50 p-5 rounded-xl border border-orange-100">
                                                <h4 className="font-bold text-orange-800 mb-3 flex items-center gap-2">
                                                    <ChevronRight className="w-4 h-4"/> 反向特性 (左半轴)
                                                </h4>
                                                <ul className="text-sm text-slate-700 space-y-2">
                                                    <li><strong>截止区:</strong>反向电流极小(漏电流),通常微安级别,可视为开路。</li>
                                                    <li><strong>击穿区:</strong>反向电压超过 <span className="font-mono font-bold">U(BR)</span> 时,电流剧增。</li>
                                                    <li><strong>应用:</strong>稳压二极管就是工作在反向击穿区的特殊二极管。</li>
                                                </ul>
                                            </div>
                                        </div>
                                    </div>
                                )}

                                {/* 3. 结构与原理 */}
                                {activeTab === 'structure' && (
                                    <div className="space-y-8 animate-fadeIn">
                                        <section>
                                            <h2 className="text-xl font-bold text-slate-800 border-l-4 border-purple-500 pl-3 mb-4">半导体基础</h2>
                                            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                                                <div className="bg-slate-50 p-4 rounded-lg border border-slate-100">
                                                    <h3 className="font-bold text-slate-700 mb-2">本征半导体</h3>
                                                    <p className="text-sm text-slate-600 leading-relaxed">纯净的半导体(如硅 Si、锗 Ge)。导电能力介于导体和绝缘体之间。受热或光照会产生电子-空穴对。</p>
                                                </div>
                                                <div className="bg-slate-50 p-4 rounded-lg border border-slate-100">
                                                    <h3 className="font-bold text-slate-700 mb-2">杂质半导体</h3>
                                                    <ul className="text-sm text-slate-600 space-y-2">
                                                        <li className="flex items-start gap-2"><span className="bg-blue-100 text-blue-800 text-xs font-bold px-1.5 py-0.5 rounded">N</span> 掺入五价元素(磷),自由电子为多子。</li>
                                                        <li className="flex items-start gap-2"><span className="bg-red-100 text-red-800 text-xs font-bold px-1.5 py-0.5 rounded">P</span> 掺入三价元素(硼),空穴为多子。</li>
                                                    </ul>
                                                </div>
                                            </div>
                                        </section>

                                        <section>
                                            <h2 className="text-xl font-bold text-slate-800 border-l-4 border-purple-500 pl-3 mb-4">PN 结的形成</h2>
                                            <div className="flex flex-col items-center bg-gradient-to-r from-red-50 to-blue-50 p-6 rounded-xl border border-slate-200">
                                                <div className="flex w-full max-w-md h-32 rounded-lg overflow-hidden shadow-inner border-2 border-slate-300 relative">
                                                    {/* P区 */}
                                                    <div className="flex-1 bg-red-200 flex items-center justify-center relative group">
                                                        <span className="text-4xl font-black text-red-500 opacity-20 group-hover:opacity-40 transition-opacity">P</span>
                                                        <div className="absolute inset-0 p-2 flex flex-wrap justify-center items-center gap-2 opacity-60">
                                                            {Array(8).fill(0).map((_,i) => <div key={i} className="w-3 h-3 rounded-full border-2 border-red-600" title="空穴"></div>)}
                                                        </div>
                                                    </div>
                                                    {/* 耗尽层 */}
                                                    <div className="w-16 bg-slate-300/50 backdrop-blur-sm border-x border-slate-400/30 flex items-center justify-center flex-col">
                                                        <span className="text-[10px] text-slate-600 font-bold text-center">空间电荷区</span>
                                                        <div className="flex gap-1 mt-1">
                                                            <span className="text-xs text-red-600">-</span><span className="text-xs text-blue-600">+</span>
                                                        </div>
                                                    </div>
                                                    {/* N区 */}
                                                    <div className="flex-1 bg-blue-200 flex items-center justify-center relative group">
                                                        <span className="text-4xl font-black text-blue-500 opacity-20 group-hover:opacity-40 transition-opacity">N</span>
                                                        <div className="absolute inset-0 p-2 flex flex-wrap justify-center items-center gap-2 opacity-60">
                                                            {Array(8).fill(0).map((_,i) => <div key={i} className="w-3 h-3 rounded-full bg-blue-600" title="电子"></div>)}
                                                        </div>
                                                    </div>
                                                </div>
                                                <p className="mt-4 text-sm text-slate-700 text-center max-w-lg">
                                                    P型半导体和N型半导体交界面形成<strong>空间电荷区</strong>(耗尽层)。<br/>
                                                    内电场方向:<span className="text-blue-600 font-bold">N</span><span className="text-red-600 font-bold">P</span>,阻碍多子扩散,利于少子漂移。
                                                </p>
                                            </div>
                                        </section>
                                    </div>
                                )}

                            </div>
                        </div>
                    </main>
                    
                    <footer className="text-center text-slate-400 py-8 text-sm">
                         © 2024 电子电路技术课程教学辅助系统
                    </footer>
                </div>
            );
        };

        // 辅助组件:类型卡片
        const TypeCard = ({ title, desc, icon, tags, color }) => (
            <div className={`${color} p-5 rounded-xl border border-slate-100 shadow-sm hover:shadow-md transition-all hover:-translate-y-1 cursor-default`}>
                <div className="flex items-center gap-3 mb-3">
                    <div className="p-2 bg-white rounded-lg shadow-sm">{icon}</div>
                    <h3 className="font-bold text-slate-700">{title}</h3>
                </div>
                <p className="text-sm text-slate-600 mb-4 leading-relaxed">{desc}</p>
                <div className="flex flex-wrap gap-2">
                    {tags.map((tag, i) => (
                        <span key={i} className="px-2 py-1 bg-white/60 text-slate-600 text-xs font-medium rounded-md border border-slate-200/50">{tag}</span>
                    ))}
                </div>
            </div>
        );
        
        // 简单的图标占位符
        const BoxIcon = () => (
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
                <polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
                <line x1="12" y1="22.08" x2="12" y2="12"></line>
            </svg>
        );

        // 渲染应用
        const root = createRoot(document.getElementById('root'));
        root.render(<App />);
    </script>
</body>
</html>

效果

在这里插入图片描述

3D 元器件效果

3D 元器件可以放大、旋转。在元器件下方,有关于该元器件的简单介绍。
在这里插入图片描述

在这里插入图片描述

概念介绍

针对半导体二极管的类型与应用伏安特性结构与原理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

仿真实验

关于半导体的正向偏置和反向偏置,有一个小交互。

  1. 开关断开
    在这里插入图片描述

  2. 正向偏置,电灯可以点亮。
    在这里插入图片描述

  3. 反向偏置,电灯没法点亮。
    在这里插入图片描述

写在最后

引用 AI 大博主卡兹克在他的文章中的一句话结束本篇文章吧。
此即未来
谢谢大家。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐