🐑 分享个 编辑/查看 HTML 源码的小页面 ↺ 天气卡 #

(\ _ /)
( ・-・)
/っ :hot_beverage:   天气卡火爆那段时间糊的,可以比 新建文件 贴进去少点步骤。

吃灰了一整年的 7 系 Serv00:

  • 数据存储在浏览器 LocalStorage,刷新不丢失
  • URL 后缀加上 ?edit 时即为编辑状态,一般是先进入编辑页
  • ↑ 所以渲染之后要回到编辑页就点浏览器左上 或 快捷键 Alt +

测 试 源 码 :down_left_arrow:

Claude 4.5 の 莫比乌斯环
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>酷炫莫比乌斯环 - Three.js</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            overflow: hidden;
            background: #000;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        canvas {
            display: block;
        }
        
        .info {
            position: fixed;
            top: 20px;
            left: 20px;
            color: white;
            background: rgba(0, 0, 0, 0.7);
            padding: 20px;
            border-radius: 15px;
            font-size: 14px;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.1);
            z-index: 10;
        }
        
        .info h3 {
            margin: 0 0 10px 0;
            font-size: 18px;
            background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        
        .info p {
            margin: 5px 0;
            opacity: 0.9;
        }
        
        .controls {
            position: fixed;
            bottom: 20px;
            right: 20px;
            display: flex;
            gap: 10px;
            z-index: 10;
        }
        
        .btn {
            background: rgba(255, 255, 255, 0.1);
            border: 1px solid rgba(255, 255, 255, 0.2);
            color: white;
            padding: 12px 24px;
            border-radius: 25px;
            cursor: pointer;
            font-size: 14px;
            backdrop-filter: blur(10px);
            transition: all 0.3s;
        }
        
        .btn:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(255, 255, 255, 0.3);
        }
    </style>
</head>
<body>
    <div class="info">
        <h3>✨ 3D 莫比乌斯环</h3>
        <p>🖱️ 拖动旋转 | 滚轮缩放</p>
        <p>🌈 动态彩虹材质</p>
        <p>💫 粒子特效环绕</p>
    </div>
    
    <div class="controls">
        <button class="btn" id="toggleBtn">⏸️ 暂停</button>
        <button class="btn" id="resetBtn">🔄 重置</button>
        <button class="btn" id="effectBtn">✨ 切换特效</button>
    </div>

    <!-- 使用 importmap 方式引入 Three.js -->
    <script type="importmap">
    {
        "imports": {
            "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
            "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/"
        }
    }
    </script>

    <script type="module">
        import * as THREE from 'three';
        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

        // 场景设置
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x0a0a0a);
        scene.fog = new THREE.Fog(0x0a0a0a, 10, 50);

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 3, 8);

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        document.body.appendChild(renderer.domElement);

        // 轨道控制器
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        controls.autoRotate = true;
        controls.autoRotateSpeed = 1.5;

        // 创建莫比乌斯环几何体
        function createMobiusGeometry(radius = 3, width = 1.2, segments = 200, strips = 40) {
            const geometry = new THREE.BufferGeometry();
            const vertices = [];
            const indices = [];
            const uvs = [];
            const colors = [];

            for (let i = 0; i <= segments; i++) {
                const u = (i / segments) * Math.PI * 2;
                for (let j = 0; j <= strips; j++) {
                    const v = ((j / strips) - 0.5) * width;
                    
                    // 莫比乌斯环参数方程
                    const x = (radius + v * Math.cos(u / 2)) * Math.cos(u);
                    const y = (radius + v * Math.cos(u / 2)) * Math.sin(u);
                    const z = v * Math.sin(u / 2);
                    
                    vertices.push(x, y, z);
                    uvs.push(i / segments, j / strips);
                    
                    // 彩虹色
                    const hue = (i / segments);
                    const color = new THREE.Color().setHSL(hue, 1, 0.6);
                    colors.push(color.r, color.g, color.b);
                }
            }

            // 生成索引
            for (let i = 0; i < segments; i++) {
                for (let j = 0; j < strips; j++) {
                    const a = i * (strips + 1) + j;
                    const b = a + strips + 1;
                    indices.push(a, b, a + 1);
                    indices.push(b, b + 1, a + 1);
                }
            }

            geometry.setIndex(indices);
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
            geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
            geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
            geometry.computeVertexNormals();

            return geometry;
        }

        // 创建莫比乌斯环
        const mobiusGeometry = createMobiusGeometry();
        const mobiusMaterial = new THREE.MeshPhongMaterial({
            vertexColors: true,
            side: THREE.DoubleSide,
            shininess: 100,
            specular: 0x444444,
            emissive: 0x111111
        });
        const mobius = new THREE.Mesh(mobiusGeometry, mobiusMaterial);
        scene.add(mobius);

        // 添加发光边缘
        const edgeGeometry = new THREE.EdgesGeometry(mobiusGeometry, 15);
        const edgeMaterial = new THREE.LineBasicMaterial({ 
            color: 0xffffff, 
            transparent: true, 
            opacity: 0.3 
        });
        const edges = new THREE.LineSegments(edgeGeometry, edgeMaterial);
        mobius.add(edges);

        // 粒子系统
        const particlesGeometry = new THREE.BufferGeometry();
        const particlesCount = 2000;
        const positions = new Float32Array(particlesCount * 3);
        const particleColors = new Float32Array(particlesCount * 3);

        for (let i = 0; i < particlesCount; i++) {
            const u = Math.random() * Math.PI * 2;
            const v = (Math.random() - 0.5) * 1.5;
            const radius = 3 + Math.random() * 2;
            
            positions[i * 3] = (radius + v * Math.cos(u / 2)) * Math.cos(u);
            positions[i * 3 + 1] = (radius + v * Math.cos(u / 2)) * Math.sin(u);
            positions[i * 3 + 2] = v * Math.sin(u / 2);
            
            const color = new THREE.Color().setHSL(Math.random(), 1, 0.7);
            particleColors[i * 3] = color.r;
            particleColors[i * 3 + 1] = color.g;
            particleColors[i * 3 + 2] = color.b;
        }

        particlesGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        particlesGeometry.setAttribute('color', new THREE.BufferAttribute(particleColors, 3));

        const particlesMaterial = new THREE.PointsMaterial({
            size: 0.05,
            vertexColors: true,
            transparent: true,
            opacity: 0.8,
            blending: THREE.AdditiveBlending
        });

        const particles = new THREE.Points(particlesGeometry, particlesMaterial);
        scene.add(particles);

        // 灯光
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
        scene.add(ambientLight);

        const pointLight1 = new THREE.PointLight(0xff00ff, 1, 100);
        pointLight1.position.set(5, 5, 5);
        scene.add(pointLight1);

        const pointLight2 = new THREE.PointLight(0x00ffff, 1, 100);
        pointLight2.position.set(-5, -5, 5);
        scene.add(pointLight2);

        // 动态光源
        const movingLight = new THREE.PointLight(0xffffff, 1.5, 50);
        scene.add(movingLight);

        // 控制变量
        let autoRotate = true;
        let effectMode = 0;
        let time = 0;

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            time += 0.01;

            // 更新粒子动画
            const positions = particles.geometry.attributes.position.array;
            for (let i = 0; i < particlesCount; i++) {
                positions[i * 3 + 1] += Math.sin(time + i * 0.1) * 0.002;
            }
            particles.geometry.attributes.position.needsUpdate = true;
            particles.rotation.y = time * 0.1;

            // 动态光源运动
            movingLight.position.x = Math.sin(time) * 8;
            movingLight.position.z = Math.cos(time) * 8;
            movingLight.position.y = Math.sin(time * 0.7) * 3;

            // 特效模式
            if (effectMode === 1) {
                mobius.rotation.x = Math.sin(time * 0.3) * 0.2;
                mobius.rotation.z = Math.cos(time * 0.5) * 0.2;
            }

            controls.update();
            renderer.render(scene, camera);
        }

        // 按钮事件
        document.getElementById('toggleBtn').addEventListener('click', function() {
            autoRotate = !autoRotate;
            controls.autoRotate = autoRotate;
            this.textContent = autoRotate ? '⏸️ 暂停' : '▶️ 播放';
        });

        document.getElementById('resetBtn').addEventListener('click', () => {
            camera.position.set(0, 3, 8);
            controls.reset();
            controls.autoRotate = true;
            autoRotate = true;
            effectMode = 0;
            document.getElementById('toggleBtn').textContent = '⏸️ 暂停';
        });

        document.getElementById('effectBtn').addEventListener('click', function() {
            effectMode = (effectMode + 1) % 2;
            this.textContent = effectMode === 0 ? '✨ 切换特效' : '🌀 波动模式';
            if (effectMode === 0) {
                mobius.rotation.x = 0;
                mobius.rotation.z = 0;
            }
        });

        // 窗口调整
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        animate();
    </script>
</body>
</html>
8 个赞

好东西,学习了~
话说这个波动模式没看出有什么区别啊

1 个赞

:distorted_face: 只是问完即删的一次性 Demo,不要在意那些细节.jpg

1 个赞

这有点厉害了,这个开源吗 大佬

就一个单页… 你直接 右键查看源码 就是全部源码了。。Ctrl+S 到本地就行。

1 个赞