Switching between the master and instrument videos involved considerations regarding tech, user experience, and user interface. I wanted users to be able to select any video at anytime but have the current time stay synced. Let’s start with the technical solution. First, you’ll want an array of videos like so:

videos: [

{

id: "master",

name: "Master",

url: URL

}, {

id: "drums",

name: "Drums",

url: URL

}

]

As I mentioned earlier, Plyr has a source setter that allows us to change the source video in real time. This video could be from YouTube, Vimeo, or in our case, a hosted URL.

player.source = {

type: 'video',

sources: [

{

src: URL,

type: 'video/mp4'

}

]

}

Simple stuff. It’s then up to you to decide how the user initiates that video change. After exploring various UX experiments, I decided on the most straight-forward option: a drop-down select. There’s just something insanely practical about having the choices fan out from the initial user touch point. Choosing a new video then simply requires a short mouse movement and click.

Using Vue.js, I can easily generate an option select from an array of videos using a combination of v-for (to generate a list of options) and v-model (to keep track of the selected video.)

<select v-model="selectedVideoId">

<option v-for="video in videos" v-bind:value="video.id">

{{ video.name }}

</option>

</select>

I then use this selectedVideoId to power a computed property which finds the current selected video from my video array. This gives me access to the video’s name and url in addition to it’s id.

selectedVideo() {

return this.videos.find((video) => {

return video.id == this.selectedVideoId

})

}

I can then use a Vue watcher to listen for changes to the selectedVideoId and finally called Plyr’s source setter.

watch: {

selectedVideoId(val) {

player.source = {

type: 'video',

sources: [

src:

]

}

}

}

It goes without saying that Vue’s solution to this problem is simple, elegant, and well documented. Thank you Vue.

The final hurdle is educating users that this functionality even exists within the interface. An option select, by default, will simply state the currently selected choice and since our default choice is “Master” this can be pretty obscure and uninviting to most users. It certainly doesn’t scream, “click me to watch Dave play drums.” I figured if I could simply label the select with the phrase “Choose Video,” that would greatly increase interaction. The problem? I just hate those little tutorial elements. You know the ones. A little floating div with an arrow. Hell, a hand drawn arrow with hand written type… After designing all of these solutions on a throw away Figma board, I decided to take on the issue live in the code with a FRESH POT of coffee first thing in the morning.

I began by creating the semantic label element and giving it the text of “Choose video.” Without styling, this label broke my design immediately so I just gave it a position of absolute to keep it under control. This faithful styling placed the label right on top of my select and gave me a thought. How are things labeled in a studio? Masking tape and sharpie. What if I styled this element like a piece of masking tape which revealed the functionality on hover? All it took was the background color #FCF7DD , a bit of padding, and a method to hide on hover. I didn’t hate this solution and we ended up pushing it live.

The final issue involved keeping track of the player’s position. Sadly this isn’t as easy as simply setting the currentTime when a new video gets loaded as the video may not be ready to change position when you call that function. Your safest bet is to change the currentTime once the player begins to play. Plyr offers us an onplay event but we’ll want to understand if our player is in the process of switching tracks so it isn’t jumping around every time a user plays something. To solve this, I simply created a boolean called switching . When the selectedVideoId watcher is called above, I set switching to true. And then, within the play event, the real magic occurs:

player.on('play', event => {

if (this.switching) {

if (this.isMaster) {

player.currentTime = this.globalTime + this.introDuration

} else {

player.currentTime = this.globalTime

} this.switching = false

}

})

I’m sure you noticed the two additional properties: isMaster and introDuration Since my master video is a different length, I’ve created a computed property to help me check if the currently selected video is the master. When it is, I’ll need to shift the current time by the duration of the intro, which I also have stored. Oh wait, I’m dumb. Here’s how you actually update globalTime using Plyr’s ontimeupdate event… which is called each time currentTime is changed.

player.on('timeupdate', event => {

if (this.isMaster) {

this.globalTime = this.player.currentTime - this.introDuration

} else {

this.globalTime = this.player.currentTime

}

})

Again, this code could have been greatly simplified if we would have split up the intro and performance videos. However, I would have then extended this tutorial to cover checking to see if the intro ended before starting the performance. It’s okay, Plyr has that event also. It’s called ended . Thanks to the synergy between Vue and Plyr, a little bit of code goes a long way.

One last thing. I was curious which instruments user’s might focus on so I integrated a few vue-analytics tracking events. Here’s the current breakdown.

Breakdown of instrument selections

Collapsing