Animating with audio playback


by Jeremy Caudle
code

Today I wanted to try animating text based on the time elapsed within an audio element. I was wondering if animating a transcript for a podcast could be an entertaining way to provide a more visual presentation for readers of a podcast's transcripts. Making animation an option and not a default would be how I would approach it. Adding in some animations could help add the podcasters' personalities to the transcripts. Now I just need to figure out how to load in a transcript to help with the animation process. What I did today was far too tedious and not ideal for a 30-plus minute podcast.

The words below should animate as the audio plays.

 

This is a test of the HTML audio element.

View the code:

HTML and JS
<section class="code-block">
                <h5>The words below should animate as the audio plays.</h5>
                <p id="audioTime" class="hide"> </p>
                <audio id="audioPlayer" controls preload="auto">
                    <source src="https://jeremycaudle.com/ast/testaudio.mp3" type="audio/mpeg">
                    Your browser does not appear to support the <code>audio</code> element. I'm sorry. :(
                </audio>
                
                <p id="audio-transcript"><span id="wordThis">This</span> <span id="wordIs">is</span> <span id="wordA">a</span> <span id="wordTest">test</span> <span id="wordOf">of</span> <span id="wordThe">the</span> <span id="wordHTML">HTML</span> <span id="wordAudio">audio</span> <span id="wordElement">element</span>.</p>
        </section>
        <script>
            /* Variables */
            const audio = document.getElementById('audioPlayer');
            let audioTime = document.getElementById('audioTime');
            const wordThis = document.getElementById('wordThis');
            const wordIs = document.getElementById('wordIs');
            const wordA = document.getElementById('wordA');
            const wordTest = document.getElementById('wordTest');
            const wordOf = document.getElementById('wordOf');
            const wordThe = document.getElementById('wordThe');
            const wordHTML = document.getElementById('wordHTML');
            const wordAudio = document.getElementById('wordAudio');
            const wordElement = document.getElementById('wordElement');
            let time = audio.currentTime;

            /* Functions */

            function clearWordStyles(object) {
                wordThis.style.fontWeight = 300;
                wordIs.style.fontWeight = 300;
                wordA.style.fontWeight = 300;
                wordTest.style.fontWeight = 300;
                wordOf.style.fontWeight = 300;
                wordThe.style.fontWeight = 300;
                wordHTML.style.fontWeight = 300;
                wordAudio.style.fontWeight = 300;
                wordElement.style.fontWeight = 300;
            }

            /* Events */

            audio.addEventListener('playing', (e) => {
                audioTime.setAttribute('class', 'show');
                audioTime.textContent=`Audio playback currently at: ${Number.parseFloat(time).toFixed(2)}`;
            });

            audio.addEventListener('play', (e) => {
                console.log('Playback has started.')
            });

            audio.addEventListener('pause', (e) => {
                console.log('Playback has paused.')
            });

            audio.addEventListener('timeupdate', (e) => {
                time = audio.currentTime;
                audioTime.textContent=`Audio playback currently at: ${Number.parseFloat(time).toFixed(2)}`;
                if (time < 1.48) {
                    clearWordStyles();
                } else if (time > 1.48 && time < 2.02){
                clearWordStyles();
                wordThis.style.fontWeight = 900;
                } else if (time > 2.02 && time < 2.24){
                clearWordStyles();
                wordIs.style.fontWeight = 900;
                } else if (time > 2.24 && time < 2.34){
                clearWordStyles();
                wordA.style.fontWeight = 900;
                } else if (time > 2.34 && time < 3.01){
                clearWordStyles();
                wordTest.style.fontWeight = 900;
                } else if (time > 3.01 && time < 3.25){
                clearWordStyles();
                wordOf.style.fontWeight = 900;
                } else if (time > 3.25 && time < 3.5){
                clearWordStyles();
                wordThe.style.fontWeight = 900;
                } else if (time > 3.5 && time < 4.53){
                clearWordStyles();
                wordHTML.style.fontWeight = 900;
                } else if (time > 4.53 && time < 5.05){
                clearWordStyles();
                wordAudio.style.fontWeight = 900;
                } else if (time > 5.05 && time < 6.2){
                clearWordStyles();
                wordElement.style.fontWeight = 900;
                } else if (time > 6.2){
                clearWordStyles();
                }
            }); 

        </script>
CSS
section.code-block {
                max-width: 30em;
                margin: 1rem auto;
                font-family: Helvetica, Arial, sans-serif;
                padding: 1rem;
                background-color: rgb(168, 230, 214);
                border-radius: 1rem;
            }

            .code-block p, .code-block h5 {
                text-align: center;
            }

            #audioTime {
                color: red;
                transition: opacity .5s ease-out, font-weight .125s ease-out;
                z-index: 4;
            }

            audio {
                width: 100%;
                max-width: 30em;
                margin-bottom: 1rem;
            }

            .hide {
                opacity: 0;
            }

            .show {
                opacity: 1;
            }