JSFiddle - React, Tailwind, and code Playground

HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="record">Record</button>
    <canvas id="canvas" width="200" height="200"></canvas>
    <video id="video" controls></video>
</body>

</html>
<script>

    const recordButton = document.getElementById('record');
    const video = document.getElementById('video');
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    let mediaRecorder;
    let stream;

    var gradient = ctx.createLinearGradient(0, 0, 200, 0);
    gradient.addColorStop(0, 'cyan');
    gradient.addColorStop(1, 'magenta');

    recordButton.onclick = () => {
        stream = canvas.captureStream(); // 抓取canvas流
        mediaRecorder = new MediaRecorder(stream);

        let chunks = [];
        mediaRecorder.ondataavailable = e => {
            if (e.data.size) {
                chunks.push(e.data);
            }
        };

        mediaRecorder.onstop = e => {
            let blob = new Blob(chunks, { 'type': 'video/mp4' });
            chunks = [];
            let videoURL = URL.createObjectURL(blob);
            video.src = videoURL;
        };

        mediaRecorder.start();

        animateRect();
    };

    function animateRect() {
        var startTime = null;

        function roll(timestamp) {
            if (!startTime) startTime = timestamp;
            let progress = timestamp - startTime;
            let step = progress / 1000; // 1 s

            // Draw rectangle
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, 200 * step, 200 * step);

            if (step <= 1) {
                window.requestAnimationFrame(roll);
            } else {
                mediaRecorder.stop();
            }
        }

        window.requestAnimationFrame(roll);
    }


</script>