Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                -# I love haml and sass - what can I say
.main-container
  .msg 
    %h1 Setup Complete!
  .time-displays
    #instance-label.time-label vid1 Time: 
    .current-time
    .time-label Master Timeline: 
    .master-time
  .container
    %video#vid1{src: "https://player.vimeo.com/external/205431131.sd.mp4?s=bd606a4c91d1242486fa6432110172d3b9301f6e&profile_id=164"}
    %video#vid2{src: "https://player.vimeo.com/external/205431131.sd.mp4?s=bd606a4c91d1242486fa6432110172d3b9301f6e&profile_id=164"}
    %video#vid3{src: "https://player.vimeo.com/external/205431131.sd.mp4?s=bd606a4c91d1242486fa6432110172d3b9301f6e&profile_id=164"}
  #slider
  .buttons
    %button#reset RESET
    %button#play PLAY
    %button#rewind REWIND

              
            
!

CSS

              
                .main-container
  width: 640px
  margin: 10px auto
  position: relative
  .time-displays
    position: relative
    height: 30px
    div
      display: inline-block
      padding: 0 10px
.container
  position: relative
  width: 640px
  height: 360px
  background: black
  video
    position: absolute
    top: 0
    left: 0
    opacity: 0
.msg
  position: absolute
  width: 640px
  height: 360px
  top: 0
  left: 0
  display: flex
  flex-flow: row nowrap
  justify-content: center
  align-items: center
  background: transparent
  opacity: 0
  z-index: 20
  h1
    color: green
    font-size: 40px
.buttons
  margin: 10px 0
#slider
  margin: 10px

              
            
!

JS

              
                console.clear();
/***
The video included here is around 10 seconds long and was used to aid in testing. 
It's a clock face so easy to see where you are in each video instance. 
You could use any video(s) you like and as many as you like to experiment with this script.

Credit for the video: http://www.digiproductvideo.com
a Couple of others: 
https://player.vimeo.com/external/205431120.sd.mp4?s=16d1a07e1e5c1050e567e4f1e88afe3827057af7&profile_id=164
https://player.vimeo.com/external/205431139.sd.mp4?s=4ce32116028f028438c8423c4715d3f975ef4943&profile_id=164

To play with the start and end times for each instance of the video, 
change the values of the startAt and endAt properties in the vidArr object elements. 
Only plays forward so can't set a startAt time beyond the endAt time and expect it to work.
And, of course, you can't set an endAt value that's greater than the rawDuration of the video.

PROPERTIES:
rawDuration:  Number - the video's actual total duration - snagged in the initVideoData method
startAt:      Number - where you want the video to start playing
endAt:        Number - where you want the video to stop playing before moving on to the next video
wait:         Number - The delay on the master timeline (videoTL) before the video starts playing. Is set when each of the video's timelines are created.
active:       Boolean - Set to true at the beginning of each video's timeline and fase at the end. This is used to find the video that's currently 'active'
loaded:       Boolean - Stupid I know, but a setInterval is used to see when all of the videos have finished loading and are ready to play.

NOTE! Using Lodash to find the active video -> _.find(vidArr, {active: true})
      If you aren't using Lodash, you'll need to find an alternative way of handling that, like a loop.
***/

var videoTL = new TimelineMax({paused: true, onUpdate: updateSlider}),
    myTimer,
    vidArr = [
      vid1 = {el: document.getElementById('vid1'), rawDuration: null, startAt: 6, endAt: 9, wait: null, active: false, loaded: false},
      vid2 = {el: document.getElementById('vid2'), rawDuration: null, startAt: 1, endAt: 3, wait: null, active: false, loaded: false},
      vid3 = {el: document.getElementById('vid3'), rawDuration: null, startAt: 0, endAt: 4, wait: null, active: false, loaded: false}
      ];

function doSetup() {
  if(videoTL.duration() > 0) { videoTL.clear().pause(); }
  for( let vid of vidArr ) {
    
    var tl = new TimelineMax({
      onStart:startVideo, onStartParams:[vid],
      onComplete:pauseVideo, onCompleteParams:[vid]
    });

    tl.set(vid.el, {currentTime:vid.startAt}, 0)
    tl.set(vid, {active:true, wait:videoTL.duration(), immediateRender:false}, 0)
      .to(vid.el, 0.1, {opacity:1}, 0)
      .set(vid.el, {opacity:0}, vid.endAt-vid.startAt)
      .set(vid, {active:false}, vid.endAt-vid.startAt);

    vid.wait = videoTL.duration();
    videoTL.add(tl,vid.wait);
  }
  // just briefly showing the 'Setup Complete' message
  TweenMax.to('.msg', 1, {opacity:1});
  TweenMax.to('.msg', 1, {opacity:0, delay:1});
}

function startVideo(vid) { 
  vid.el.play();
}

function pauseVideo(vid) {
  vid.el.pause();
}

function seekActiveVideo() {
  var vid = activeVideo();
  if( vid === undefined ) return;
  vid.el.pause();
  var pos = videoTL.time() - vid.wait + vid.startAt;
  TweenMax.set(vid.el, {currentTime:pos});
}

function activeVideo() {
  return _.find(vidArr, {active: true});
}

function initVideoData(vid) {
  vid.rawDuration = vid.el.duration;
  vid.startAt = vid.startAt === null ? 0 : vid.startAt;
  vid.endAt = vid.endAt == null ? vid.rawDuration - vid.startAt : vid.endAt;
}

// utility stuff ////////////////////////////////////////////

function resetData() {
  console.clear();
  for( let vid of vidArr ) { initVideoData(vid) }
  doSetup();
}

function resetStartTimes() {
  for( let vid of vidArr ) {
    TweenMax.set(vid.el,{currentTime: vid.startAt});
  }
}

function onLoaded() {
  for( let vid of vidArr ) {
    vid.el.oncanplaythrough = function() {
      initVideoData(vid);
      vid.loaded = true;
    };
  }
}

$('#play').on("click", function(){ videoTL.play() });

$('#reset').on("click", function(){ resetData() });

$('#rewind').on("click", function(){
  videoTL.pause().seek(0);
  resetStartTimes();
  updateSlider();
});

function updateSlider() { 
  $("#slider").slider("value", videoTL.progress() *100);
  $('.master-time').html(parseFloat(videoTL.time().toFixed(2)));
  var vid = activeVideo();
  console.log(vid);
  if( vid === undefined ) return;
  $('#instance-label').html(`${$(vid.el).attr('id')} Time:`)
  $('.current-time').html(parseFloat(vid.el.currentTime).toFixed(2));
}

function initSlider() {
  $("#slider").slider({min:0, max:100, step:0.005,
    slide: function ( event, ui ) {
      videoTL.pause();
      videoTL.progress( ui.value/100 );
    }
  })
  .on( "slide", function( event, ui ) {
    // only called when the slider is being dragged
    seekActiveVideo();
  });
}

onLoaded();
initSlider();

myTimer = setInterval(function(){ 
  numLoaded = 0;
  for( let vid of vidArr ) {
    numLoaded += vid.loaded ? 1 : 0;
  }
  if( numLoaded == vidArr.length ) {
    clearInterval(myTimer);
    doSetup();
  }
}, 100);

              
            
!
999px

Console