Search code examples
javascripthtmlanimationexportpowerpoint

Exporting JS Animation of Text Content in HTML to an animated gif or a PowerPoint importable canvas object


My goal is to import a JS animation into PowerPoint for use with a slide deck. How do I accomplish this?

I am not looking for the work to be done on my behalf. I need some suggestions on techniques to accomplish this task.

Slide Background (to be behind transparent background animation)

Slide Background

Here is the HTML/JS animation.

// ——————————————————————————————————————————————————
        // TextScramble
        // ——————————————————————————————————————————————————

        class TextScramble {
            constructor(elm, numWords) {
                this.el = el
                this.numWords = numWords;
                this.chars = '!\\<>-_\\/[]{}—=+*^?#1234567890________'
                this.update = this.update.bind(this)
            }
            setText(newText) {
                const oldText = this.el.innerText
                const length = Math.max(oldText.length, newText.length)
                const promise = new Promise((resolve) => this.resolve = resolve)
                this.queue = []
                for (let i = 0; i < length; i++) {
                    const from = oldText[i] || ''
                    const to = newText[i] || ''
                    const start = Math.floor(Math.random() * 40)
                    const end = start + Math.floor(Math.random() * 40)
                    this.queue.push({ from, to, start, end })
                }
                cancelAnimationFrame(this.frameRequest)
                this.frame = 0
                this.update()
                return promise
            }
            update = () => {
                let output = ''
                let complete = 0
                for (let i = 0, n = this.queue.length; i < n; i++) {
                    let { from, to, start, end, char } = this.queue[i]
                    if (this.frame >= end) {
                        complete++
                        output += to
                    } else if (this.frame >= start) {
                        if (!char || Math.random() < 0.28) {
                            char = this.randomChar()
                            this.queue[i].char = char
                        }
                        output += `<span class="span">${char}</span>`
                    } else {
                        output += from
                    }
                }
                this.el.innerHTML = output
                if (complete === this.queue.length) {
                    this.resolve()
                } 
                else {
                    this.frameRequest = requestAnimationFrame(this.update)
                    this.frame++
                }
            }
            randomChar() {
                return this.chars[Math.floor(Math.random() * this.chars.length)]
            }
        }

        // ——————————————————————————————————————————————————
        // Example
        // ——————————————————————————————————————————————————

        const phrases = {
            'Programming' : 'none',
            'With' : 'none',
            'Ali': 'none',
            '<pwa/>': 'none',
            'Programming With Ali' : 'fade'
        }
        let phraseValues = Object.keys(phrases);
        const el = document.querySelector('.text')
        const fx = new TextScramble(el, phraseValues.length)

        let counter = 0
        let animation = phraseValues[0];

        let animate = (callback) => {
            debugger;
            callback();
            return function() {
                document.querySelector(".text").animate([
                   // keyframes
                   { opacity: '0' },
                   { opacity: '1' }
                ], {
                    // timing options
                    duration: 3500
                });
            }
        }   

        const next = () => {
        fx.setText(phraseValues[counter]).then(() => {
                if (counter < phraseValues.length-1)
                    setTimeout(next, 800)
                else {
                    setTimeout(() => {next, animate(next, fx.update)()}, 800)
                }
            })
            counter = (counter + 1) % phraseValues.length
        }
        next()
  html, body {
            font-family: 'Roboto Mono', monospace;
            background: #212121;
            height: 100%;
        }
        .container {
            height: 100%;
            width: 100%;
            justify-content: center;
            align-items: center;
            display: flex;
        }
        .text {
            font-weight: 100;
            font-size: 28px;
            color: #FAFAFA;
        }
        .dud {
            color: #757575;
        }
 <div class="container">
        <div class="text"></div>
    </div>


Solution

  • I have recently faced a similar issue, I wanted to make an animation for my Youtube video. I ended up using Puppeteer, performing animation step-by-step and exporting each frame as a separate image with await page.screenshot({ path: screenshotFilename });, then combining these images into an animation.

    I know this is not much, but hopefully this answer will be helpful to you.