One of the great things about Framer is that it supports HTML5 video. In this tutorial I’ll show you how to prototype a video player with simple controls inside Framer Studio.
Setting up the video.
To start, let’s get a video playing inside Framer Studio with no controls. Download a short mp4 from Vimeo ‐ I used this one.
Once you have your video, create a new fullscreen Framer Studio project, save it, and place the video file inside the images folder. Then copy paste this code into the editor:
# setup a container to hold everything videoContainer = new Layer width:640 height:360 backgroundColor:'#fff' shadowBlur:2 shadowColor:'rgba(0,0,0,0.24)' # create the video layer videoLayer = new VideoLayer width: 640 height: 360 video: "images/your_video.mp4" superLayer: videoContainer # center everything on screen videoContainer.center()
Make sure you replace your_video.mp4 with the one you downloaded. You should now see your video centered on screen. Pretty easy so far :)
Next, let’s have our video start and stop on click. All you need for this is a simple conditional statement to check if the video is already paused or playing:
# when the video is clicked videoLayer.on Events.Click, -> # check if the player is paused if videoLayer.player.paused == true # if true call the play method on the video layer videoLayer.player.play() else # else pause the video videoLayer.player.pause()
Now you should be able to start and stop the video on click!
The player.play() and player.pause() methods are part of the HTMLMediaElement Interface. This is a common interface for working with media content in HTML5. You can view the full list of properties and methods here.
Adding basic controls.
Next, let’s add some controls. For a basic player we’re going to need:
- a play/pause button
- a mute button
- a timeline and progress bar
- a scrubber to move to a specific time
To keep things organized let’s create a container to hold our controls and position it towards the bottom of the video.
# control bar to hold buttons and timeline controlBar = new Layer width:videoLayer.width - 20 height:48 backgroundColor:'rgba(0,0,0,0.75)' clip:false borderRadius:'8px' superLayer:videoContainer # center the control bar controlBar.center() # position control bar towards the bottom of the video controlBar.y = videoLayer.maxY - controlBar.height - 10
Once the control bar is in place we can start adding the actual controls. Let’s start with the play, pause, and volume buttons. Copy paste this code right after the last line:
# play button playButton = new Layer width:48 height:48 image:'images/play.png' superLayer:controlBar # on/off volume button volumeButton = new Layer width:48 height:48 image:'images/volume_on.png' superLayer:controlBar # position the volume button to the right of play volumeButton.x = playButton.maxX
In the above code we’re adding two image layers as sublayers of the controlBar. For the icons I used Google’s Material Design Icon Set.
Now that we’ve added our buttons, let’s setup the click behavior. For this we’ll need two more click event handlers similar to the one we wrote earlier.
# Function to handle play/pause button playButton.on Events.Click, -> if videoLayer.player.paused == true videoLayer.player.play() playButton.image = "images/pause.png" else videoLayer.player.pause() playButton.image = "images/play.png" # simple bounce effect on click playButton.scale = 1.15 playButton.animate properties: scale:1 time:0.1 curve:'spring(900,30,0)' # Volume on/off toggle volumeButton.on Events.Click, -> if videoLayer.player.muted == false videoLayer.player.muted = true volumeButton.image = "images/volume_off.png" else videoLayer.player.muted = false volumeButton.image = "images/volume_on.png" # simple bounce effect on click volumeButton.scale = 1.15 volumeButton.animate properties: scale:1 time:0.1 curve:'spring(900,30,0)'
You’ll notice that this time we’re also changing the image source for each button depending on whether the conditional is true or false.
We also need to go back in our code and make this happens in the first videoLayer click handler. The videoLayer click event should now look like this:
# when the video is clicked videoLayer.on Events.Click, -> # check if the player is paused if videoLayer.player.paused == true # if true call the play method on the video layer videoLayer.player.play() playButton.image = 'images/pause.png' else # else pause the video videoLayer.player.pause() playButton.image = 'images/play.png' # simple bounce effect on click playButton.scale = 1.15 playButton.animate properties: scale:1 time:0.1 curve:'spring(900,30,0)'
Adding a timeline and scrubber.
The last thing we need to do is add a timeline to our control bar. The timeline consists of three parts:
- the timeline
- a progress bar
- a scrubber
The code to create these layers looks like this:
# white timeline bar timeline = new Layer width:494 height:10 y:volumeButton.midY - 5 x:volumeButton.maxX + 10 borderRadius:'10px' backgroundColor:'#fff' clip:false superLayer: controlBar # progress bar to indicate elapsed time progress = new Layer width:0 height:timeline.height borderRadius:'10px' backgroundColor:'#03A9F4' superLayer: timeline # scrubber to change current time scrubber = new Layer width:18 height:18 y:-4 borderRadius:'50%' backgroundColor:'#fff' shadowBlur:10 shadowColor:'rgba(0,0,0,0.75)' superLayer: timeline # make scrubber draggable scrubber.draggable.enabled = true # limit dragging along x-axis scrubber.draggable.speedY = 0 # prevent scrubber from dragging outside of timeline scrubber.draggable.constraints = x:0 y:timeline.midY width:timeline.width height:-10 # Disable dragging beyond constraints scrubber.draggable.overdrag = false
In the above code we’ve enabled dragging on our scrubber and limited movement along the x-axis by setting the speedY property to zero. We also set the scrubber constraints so dragging is confined to inside the timeline.
The final step is to hook up the progress bar and scrubber so that they update as the video plays, or when the scrubber is moved. Copy and paste the following code into the editor:
# Update the progress bar and scrubber as video plays videoLayer.player.addEventListener "timeupdate", -> # Calculate progress bar position newPos = (timeline.width / videoLayer.player.duration) * videoLayer.player.currentTime # Update progress bar and scrubber scrubber.x = newPos progress.width = newPos + 10 # Pause the video at start of drag scrubber.on Events.DragStart, -> videoLayer.player.pause() # Update Video Layer to current frame when scrubber is moved scrubber.on Events.DragMove, -> progress.width = scrubber.x + 10 # When finished dragging set currentTime and play video scrubber.on Events.DragEnd, -> newTime = Utils.round(videoLayer.player.duration * (scrubber.x / timeline.width),0); videoLayer.player.currentTime = newTime videoLayer.player.play() playButton.image = "images/pause.png"
As the timeupdate event is fired we calculate the new width of the progress bar based on the currentTime property.
The timeupdate event is fired when the currentTime property changes as part of normal playback.
The last three events handle the dragging behavior for the scrubber. At the start of the drag we pause the video. While the scrubber is being moved the DragMove event updates the progress bar width so that it stays attached to the scrubber. When the scrubber is released the DragEnd event fires and figures out the new time to start playing the video from.
If you followed all the steps you should have a basic video player working. Now you can take things further by customizing the controls or adding interactions when the video ends. To detect the end of the video all you need is:
videoLayer.player.on "ended", -> print "video ended"
If you enjoyed this post please share it! For more tutorials like this one Follow me on Twitter.