SOURCE

console 命令行工具 X clear

                    
>
console

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener("resize", resizeCanvas);


function drawFire(radius = 10) {
    const x = 100;
    const y = 100;
    const size = 2;
    let count = 10; // 粒子数量
    for (let i = 0; i < count; i++) {
        let angle = 360 / count * i;
        let radians = angle * Math.PI / 180;
        let moveX = x + Math.cos(radians) * radius;
        let moveY = y + Math.sin(radians) * radius;
        ctx.beginPath();
        ctx.arc(moveX, moveY, 2, Math.PI * 2, false);
        ctx.closePath();
        ctx.fillStyle = '#ff0000';
        ctx.fill();
    }
}

function tick(size = 10) {
    drawFire(0);
    requestAnimationFrame(() => {
        tick
    });
}
tick();

class Animation {
  constructor(canvasId) {
    this.canvas = document.getElementById(canvasId);
    this.ctx = this.canvas.getContext('2d');
    this.objects = [];
    this.lastFrameTime = 0;
    this.isRunning = false;
  }

  addObject(object) {
    this.objects.push(object);
  }

  removeObject(object) {
    const index = this.objects.indexOf(object);
    if (index > -1) {
      this.objects.splice(index, 1);
    }
  }

  start() {
    if (!this.isRunning) {
      this.isRunning = true;
      this.lastFrameTime = performance.now();
      this.update();
    }
  }

  stop() {
    this.isRunning = false;
  }

  update() {
    const currentTime = performance.now();
    const deltaTime = currentTime - this.lastFrameTime;

    //this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);


    // 设置拖影
    this.ctx.globalCompositeOperation = 'destination-out';
    //this.ctx.fillStyle = 'rgba(0,0,0,' + 10 / 100 + ')';
    //this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);

    this.objects.forEach((object) => {
      object.update(deltaTime);
      object.draw(this.ctx);
    });

    this.lastFrameTime = currentTime;

    if (this.isRunning) {
      requestAnimationFrame(this.update.bind(this));
    }
  }
}

class AnimatedObject {
  constructor(x, y, size, color) {
    this.x = x;
    this.y = y;
    this.size = 100;
    this.radius = 1;
    this.count = 20;
    this.color = color;
    this.speed = 0.1;
    this.opacity = 1;
  }

  update(deltaTime) {
    if (this.radius < this.size) {
        this.radius += this.speed * deltaTime;
    } else if (this.opacity > 0) {
        this.opacity = Math.max(0, this.opacity - deltaTime * 0.001);
    }
    // console.log(this.radius)
  }

  draw(ctx) {
    const x = this.x;
    const y = this.y;
    const radius = this.radius;
    const count = this.count;
    ctx.globalAlpha = this.opacity;
    for (let i = 0; i < count; i++) {
        let angle = 360 / count * i;
        let radians = angle * Math.PI / 180;
        let moveX = x + Math.cos(radians) * radius;
        let moveY = y + Math.sin(radians) * radius;
        ctx.beginPath();
        ctx.arc(moveX, moveY, 2, Math.PI * 2, false);
        ctx.closePath();
        ctx.fillStyle = this.color || '#ff0000';
        ctx.fill();
    }
    ctx.globalAlpha = 1;
  }
}

// 使用示例

const animation = new Animation('canvas');
const object1 = new AnimatedObject(50, 50, 100, 'red');
const object2 = new AnimatedObject(200, 200, 50, 'blue');
animation.addObject(object1);
animation.addObject(object2);

animation.start();

<canvas id="canvas" />
body {
    background: #000;
    margin: 0;
}