SOURCE

console 命令行工具 X clear

                    
>
console
// 创建容器元素
const container = document.createElement('div');
container.id = 'container';
container.style.position = 'relative';
container.style.width = '400px';
container.style.height = '400px';
container.style.margin = '0 auto';

// 创建六边形元素
const hexagon = document.createElement('div');
hexagon.id = 'hexagon';
hexagon.style.position = 'absolute';
hexagon.style.width = '100%';
hexagon.style.height = '100%';
hexagon.style.backgroundColor = '#333';
hexagon.style.clipPath = 'polygon(25% 5%, 75% 5%, 95% 50%, 75% 95%, 25% 95%, 5% 50%)';
hexagon.style.transformOrigin = 'center';

// 创建球元素
const ball = document.createElement('div');
ball.id = 'ball';
ball.style.position = 'absolute';
ball.style.width = '30px';
ball.style.height = '30px';
ball.style.backgroundColor = '#e74c3c';
ball.style.borderRadius = '50%';
ball.style.transformOrigin = 'center';

// 添加到容器和DOM
container.appendChild(hexagon);
container.appendChild(ball);
document.body.appendChild(container);

// 设置页面样式
document.body.style.margin = '0';
document.body.style.overflow = 'hidden';
document.body.style.display = 'flex';
document.body.style.justifyContent = 'center';
document.body.style.alignItems = 'center';
document.body.style.height = '100vh';
document.body.style.backgroundColor = '#f0f0f0';

// 六边形参数
const hexagonSize = 400;
const hexagonPoints = [
    {x: 100, y: 20},    // 左上
    {x: 300, y: 20},    // 右上
    {x: 380, y: 200},   // 右
    {x: 300, y: 380},   // 右下
    {x: 100, y: 380},   // 左下
    {x: 20, y: 200}     // 左
];

// 球参数
const ballSize = 30;
let ballPos = {x: 200, y: 200};
let ballVel = {x: 0, y: 0};

// 物理参数
const gravity = 0.2;
const friction = 0.99;
const bounceFactor = 0.8;
const rotationSpeed = 0.5;
let rotationAngle = 0;

// 获取旋转后的六边形顶点
function getRotatedHexagonPoints() {
    const centerX = hexagonSize / 2;
    const centerY = hexagonSize / 2;
    
    return hexagonPoints.map(point => {
        // 转换为以中心为原点的坐标
        const x = point.x - centerX;
        const y = point.y - centerY;
        
        // 旋转
        const rotatedX = x * Math.cos(rotationAngle) - y * Math.sin(rotationAngle);
        const rotatedY = x * Math.sin(rotationAngle) + y * Math.cos(rotationAngle);
        
        // 转换回绝对坐标
        return {
            x: rotatedX + centerX,
            y: rotatedY + centerY
        };
    });
}

// 检查球与六边形边的碰撞
function checkCollision() {
    const points = getRotatedHexagonPoints();
    
    for (let i = 0; i < points.length; i++) {
        const p1 = points[i];
        const p2 = points[(i + 1) % points.length];
        
        // 计算边的向量
        const edge = {
            x: p2.x - p1.x,
            y: p2.y - p1.y
        };
        
        // 边的法向量(指向六边形内部)
        const normal = {
            x: -edge.y,
            y: edge.x
        };
        
        // 归一化法向量
        const length = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
        normal.x /= length;
        normal.y /= length;
        
        // 球中心到边的距离
        const ballToEdge = {
            x: ballPos.x - p1.x,
            y: ballPos.y - p1.y
        };
        
        // 计算投影距离
        const distance = ballToEdge.x * normal.x + ballToEdge.y * normal.y;
        
        // 如果距离小于球半径,则发生碰撞
        if (distance < ballSize / 2 && distance > -ballSize / 2) {
            // 检查球是否在边的范围内
            const edgeLength = Math.sqrt(edge.x * edge.x + edge.y * edge.y);
            const edgeDir = {
                x: edge.x / edgeLength,
                y: edge.y / edgeLength
            };
            
            const projection = ballToEdge.x * edgeDir.x + ballToEdge.y * edgeDir.y;
            
            if (projection >= 0 && projection <= edgeLength) {
                // 碰撞响应
                const penetration = ballSize / 2 - distance;
                
                // 移动球以避免穿透
                ballPos.x += normal.x * penetration;
                ballPos.y += normal.y * penetration;
                
                // 计算速度在法向量上的投影
                const velocityProjection = ballVel.x * normal.x + ballVel.y * normal.y;
                
                // 如果球正在向边移动(避免粘滞)
                if (velocityProjection < 0) {
                    // 反弹 - 反转法线方向的速度分量
                    ballVel.x -= (1 + bounceFactor) * velocityProjection * normal.x;
                    ballVel.y -= (1 + bounceFactor) * velocityProjection * normal.y;
                    
                    // 添加摩擦力 - 只影响切线方向的速度
                    const tangentVel = {
                        x: ballVel.x - velocityProjection * normal.x,
                        y: ballVel.y - velocityProjection * normal.y
                    };
                    
                    ballVel.x = tangentVel.x * friction + velocityProjection * normal.x * bounceFactor;
                    ballVel.y = tangentVel.y * friction + velocityProjection * normal.y * bounceFactor;
                }
                
                return true;
            }
        }
    }
    
    return false;
}

// 动画循环
function animate() {
    // 旋转六边形
    rotationAngle += rotationSpeed * Math.PI / 500;
    hexagon.style.transform = `rotate(${rotationAngle}rad)`;
    
    // 应用重力
    ballVel.y += gravity;
    
    // 更新球位置
    ballPos.x += ballVel.x;
    ballPos.y += ballVel.y;
    
    // 检查碰撞
    checkCollision();
    
    // 更新球的位置
    ball.style.left = `${ballPos.x - ballSize / 2}px`;
    ball.style.top = `${ballPos.y - ballSize / 2}px`;
    
    requestAnimationFrame(animate);
}

// 初始化球位置和速度
ballPos = {x: 200, y: 250};
ballVel = {x: 2, y: 0};

// 开始动画
animate();
<!-- <!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.1/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.1/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />

  </head>
  <body>
    <main>
    </main>
    <script src="gTnKp.js"></script>
  </body>
</html> -->

<!-- <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>震撼3D粒子交互动画</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #000;
        }
        canvas {
            display: block;
        }
        .info {
            position: absolute;
            top: 20px;
            left: 20px;
            color: white;
            font-family: Arial, sans-serif;
            pointer-events: none;
            text-shadow: 0 0 5px #000;
        }
    </style>
</head>
<body>
    <div class="info">移动鼠标与粒子互动</div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
    <script>
        // 初始化场景、相机和渲染器
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        document.body.appendChild(renderer.domElement);

        // 添加环境光和点光源
        const ambientLight = new THREE.AmbientLight(0x404040);
        scene.add(ambientLight);
        
        const pointLight = new THREE.PointLight(0xffffff, 1, 100);
        pointLight.position.set(10, 10, 10);
        scene.add(pointLight);

        // 创建粒子系统
        const particleCount = 15000;
        const particles = new THREE.BufferGeometry();
        const positions = new Float32Array(particleCount * 3);
        const colors = new Float32Array(particleCount * 3);
        const sizes = new Float32Array(particleCount);

        // 随机位置、颜色和大小
        for (let i = 0; i < particleCount; i++) {
            // 初始位置在一个球体内
            const radius = 20;
            const theta = Math.random() * Math.PI * 2;
            const phi = Math.random() * Math.PI;
            
            positions[i * 3] = radius * Math.sin(phi) * Math.cos(theta);
            positions[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
            positions[i * 3 + 2] = radius * Math.cos(phi);
            
            // 随机颜色
            colors[i * 3] = Math.random() * 0.5 + 0.5; // 红色分量
            colors[i * 3 + 1] = Math.random() * 0.3 + 0.2; // 绿色分量
            colors[i * 3 + 2] = Math.random() * 0.5 + 0.5; // 蓝色分量
            
            // 随机大小
            sizes[i] = Math.random() * 0.5 + 0.5;
        }

        particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        particles.setAttribute('color', new THREE.BufferAttribute(colors, 3));
        particles.setAttribute('size', new THREE.BufferAttribute(sizes, 1));

        // 创建粒子材质
        const particleMaterial = new THREE.PointsMaterial({
            size: 0.2,
            vertexColors: true,
            transparent: true,
            opacity: 0.8,
            blending: THREE.AdditiveBlending,
            sizeAttenuation: true
        });

        // 创建粒子系统
        const particleSystem = new THREE.Points(particles, particleMaterial);
        scene.add(particleSystem);

        // 鼠标交互变量
        const mouse = new THREE.Vector2();
        const mouseTarget = new THREE.Vector2();
        const windowHalf = new THREE.Vector2(window.innerWidth / 2, window.innerHeight / 2);

        // 鼠标移动事件
        document.addEventListener('mousemove', (event) => {
            mouse.x = (event.clientX - windowHalf.x) / windowHalf.x;
            mouse.y = (event.clientY - windowHalf.y) / windowHalf.y;
            
            // 平滑跟随鼠标
            mouseTarget.x = (event.clientX - windowHalf.x) / windowHalf.x;
            mouseTarget.y = (event.clientY - windowHalf.y) / windowHalf.y;
        });

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

        // 动画变量
        let time = 0;
        const originalPositions = particles.attributes.position.array.slice();
        const noise = new Float32Array(particleCount * 3);

        // 生成一些随机噪声
        for (let i = 0; i < particleCount * 3; i++) {
            noise[i] = Math.random() * 2 - 1;
        }

        // 相机位置
        camera.position.z = 30;

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            
            time += 0.005;
            
            // 平滑鼠标移动
            mouse.x += (mouseTarget.x - mouse.x) * 0.05;
            mouse.y += (mouseTarget.y - mouse.y) * 0.05;
            
            // 更新粒子位置
            const positions = particles.attributes.position.array;
            
            for (let i = 0; i < particleCount; i++) {
                const i3 = i * 3;
                
                // 原始位置
                const ox = originalPositions[i3];
                const oy = originalPositions[i3 + 1];
                const oz = originalPositions[i3 + 2];
                
                // 鼠标影响
                const dx = mouse.x * 10;
                const dy = mouse.y * 10;
                
                // 距离计算
                const dist = Math.sqrt(
                    Math.pow(positions[i3] - dx, 2) + 
                    Math.pow(positions[i3 + 1] - dy, 2)
                );
                
                // 鼠标排斥力
                const force = Math.max(0, 1 - dist / 15);
                const angle = Math.atan2(positions[i3 + 1] - dy, positions[i3] - dx);
                
                // 应用各种力
                positions[i3] = ox + 
                    Math.sin(time + oz * 0.1) * 2 + 
                    noise[i3] * 0.3 + 
                    Math.cos(angle) * force * 10;
                
                positions[i3 + 1] = oy + 
                    Math.cos(time + ox * 0.1) * 2 + 
                    noise[i3 + 1] * 0.3 + 
                    Math.sin(angle) * force * 10;
                
                positions[i3 + 2] = oz + 
                    Math.sin(time + oy * 0.1) * 2 + 
                    noise[i3 + 2] * 0.3;
            }
            
            particles.attributes.position.needsUpdate = true;
            
            // 旋转粒子系统
            particleSystem.rotation.x = time * 0.1;
            particleSystem.rotation.y = time * 0.15;
            
            // 渲染场景
            renderer.render(scene, camera);
        }

        animate();
    </script>
</body>
</html> -->