SOURCE

console 命令行工具 X clear

                    
>
console
class RGBLightArray {
    constructor() {
        this.size = 140;
        this.rows = 8;
        this.cols = 9;
        this.gap = 6;
        this.values = [];
        for (let r = 0; r < this.rows; r++) {
            this.values.push([]);
            for (let c = 0; c < this.cols; c++) {
                this.values[r].push(0);
            }
        }

        this.el = document.getElementById('light-array');
        let el = this.el;
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                let cell = document.createElement('div');
                cell.className = 'light-array__cell';
                el.appendChild(cell);
            }
        }
        this.resize();
        this.draw();
    }

    calcCellSize() {
        return (this.size - this.gap * (this.cols - 1)) / this.cols;
    }

    setValue(row, col, val) {
        this.values[row][col] = val;
        this.drawCellLight(row, col);
    }

    resize(newSize) {
        this.size = newSize || this.size;
        let { el, size, gap } = this;
        const cellSize = this.calcCellSize();
        
        el.style.width = size + 'px';
        //el.style.height = height + 'px';
        el.style.gridGap = gap + 'px';
        el.style.padding = gap + 'px';
        el.style.gridTemplateRows = `repeat(${this.rows}, ${cellSize}px)`;
        el.style.gridTemplateColumns = `repeat(${this.cols}, ${cellSize}px)`;
        Array.prototype.slice.call(this.el.children, 0).forEach(function(cell) {
            cell.style.width = cellSize + 'px';
            cell.style.height = cellSize + 'px';
        });
    }
    
    draw() {
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                this.drawCellLight(r, c);
            }
        }
    }
    
    drawCellLight(r, c) {
        let value = this.values[r][c];
        let cell = this.el.children[r * this.cols + c];
        cell.style.backgroundColor = value ? '#FFAAAA' : 'transparent';
        if (value) {
            cell.style.boxShadow = '#FF0000 0px 0px 40px 8px';
        }
    }
}

window.onload = function() {
    let lightArray = new RGBLightArray();

    const heart = [
        '000000000',
        '001101100',
        '011111110',
        '011111110',
        '001111100',
        '000111000',
        '000010000',
        '000000000',
    ];

    setTimeout(function() {
        for (let r = 0; r < lightArray.rows; r++) {
            for (let c = 0; c < lightArray.cols; c++) {
                lightArray.setValue(r, c, +heart[r][c]);
            }
        }
    }, 500);

    setTimeout(function() {
        document.body.style.backgroundColor = '#000';
    }, 1500);

    
    setTimeout(function() {
        const minSize = 70;
        const maxSize = lightArray.size;
        let size = maxSize;
        let sign = -1;
        requestAnimationFrame(function() {
            lightArray.resize(size);
            requestAnimationFrame(arguments.callee);
            size += sign;
            if (size == maxSize) {
                size = maxSize;
                sign = -1;
            }
            if (size == minSize) {
                size = minSize;
                sign = +2;
            }
        });
    }, 2500);

}
<div id="light-array"></div>
html,body {
    display: flex;
    justify-content: center;
    place-items: center;
    width: 100%;
    height: 100%;
    padding: 0px;
    padding-bottom: 100px;
    margin: 0px;
    background-color: #eee;
    transition: 1s all ease-out;
    overflow: hidden;
}
#light-array {
    display: grid;
    border-radius: 2px;
    background-color: #000;
    box-shadow: rgba(0, 0, 0, 0.42) 0px 2px 4px,
     rgba(0, 0, 0, 0.44) 0px 0px 6px;
}
.light-array__cell {
    border-radius: 100%;
    background-color: transparent;
}