SOURCE

console 命令行工具 X clear

                    
>
console
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>粒子跳动爱心</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        body {
            background: #000;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <canvas id="heartCanvas"></canvas>
    <script>
        const canvas = document.getElementById('heartCanvas');
        const ctx = canvas.getContext('2d');

        // 画布自适应窗口大小
        function resize() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }
        resize();
        window.addEventListener('resize', resize);

        let points = [];
        let edgePoints = [];
        let centerPoints = [];
        let haloPoints = [];
        const enlarge = 11;

        // 爱心函数
        function heartFunc(t) {
            let x = 16 * Math.pow(Math.sin(t), 3);
            let y = -(13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t));
            x *= enlarge;
            y *= enlarge;
            x += canvas.width / 2;
            y += canvas.height / 2;
            return { x, y }
        }

        // 内部随机扩散
        function scatter(x, y, beta) {
            let rx = -beta * Math.log(Math.random());
            let ry = -beta * Math.log(Math.random());
            let dx = rx * (x - canvas.width / 2);
            let dy = ry * (y - canvas.height / 2);
            return { x: x - dx, y: y - dy }
        }

        function shrinkPoint(x, y, ratio) {
            let dis = Math.pow(Math.pow(x - canvas.width / 2, 2) + Math.pow(y - canvas.height / 2, 2), 0.6);
            let force = -1 / dis;
            let dx = ratio * force * (x - canvas.width / 2);
            let dy = ratio * force * (y - canvas.height / 2);
            return { x: x - dx, y: y - dy }
        }

        function curve(p) {
            return 2 * (2 * Math.sin(4 * p)) / (2 * Math.PI)
        }

        // 构建爱心粒子
        function build() {
            for (let i = 0; i < 2000; i++) {
                let t = Math.random() * 2 * Math.PI;
                let p = heartFunc(t);
                points.push(p);
            }
            for (let p of points) {
                for (let j = 0; j < 3; j++) {
                    let np = scatter(p.x, p.y, 0.05);
                    edgePoints.push(np);
                }
            }
            let plist = [...points];
            for (let i = 0; i < 4000; i++) {
                let p = plist[Math.floor(Math.random() * plist.length)];
                let np = scatter(p.x, p.y, 0.27);
                centerPoints.push(np);
            }
        }
        build();

        let frame = 0;

        function calcPos(x, y, ratio) {
            let dis = Math.pow(Math.pow(x - canvas.width / 2, 2) + Math.pow(y - canvas.height / 2, 2), 0.42);
            let force = 1 / dis;
            let dx = ratio * force * (x - canvas.width / 2) + (Math.random() > 0.5 ? 1 : -1);
            let dy = ratio * force * (y - canvas.height / 2) + (Math.random() > 0.5 ? 1 : -1);
            return { x: x - dx, y: y - dy }
        }

        // 动画循环
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            let rat = 10 * curve(frame / 10 * Math.PI);
            let haloR = 4 + 6 * (1 + curve(frame / 10 * Math.PI));
            let haloNum = 3000 + 4000 * Math.pow(Math.abs(curve(frame / 10 * Math.PI)), 2);
            haloPoints = [];

            for (let i = 0; i < haloNum; i++) {
                let t = Math.random() * 2 * Math.PI;
                let p = heartFunc(t, 11.6);
                let sp = shrinkPoint(p.x, p.y, haloR);
                sp.x += Math.floor(Math.random() * 28 - 14);
                sp.y += Math.floor(Math.random() * 28 - 14);
                haloPoints.push(sp);
            }

            // 绘制所有粒子,粉色 #ff88bb
            for (let p of haloPoints) {
                let np = calcPos(p.x, p.y, rat);
                ctx.fillStyle = "#ff88bb";
                ctx.fillRect(np.x, np.y, 2, 2);
            }
            for (let p of points) {
                let np = calcPos(p.x, p.y, rat);
                ctx.fillStyle = "#ff88bb";
                ctx.fillRect(np.x, np.y, 2, 2);
            }
            for (let p of edgePoints) {
                let np = calcPos(p.x, p.y, rat);
                ctx.fillStyle = "#ff88bb";
                ctx.fillRect(np.x, np.y, 2, 2);
            }
            for (let p of centerPoints) {
                let np = calcPos(p.x, p.y, rat);
                ctx.fillStyle = "#ff88bb";
                ctx.fillRect(np.x, np.y, 2, 2);
            }
            frame++;
            requestAnimationFrame(draw);
        }
        draw();
    </script>
</body>
</html>