Using video scrubber to control timeline

I’m a newby to JS and need some help with a project. I would like the embedded video controller/scrubber to be able to control 2 timelines at the same time: the document’s main timeline and symbol’s timeline. Thanks for the help.

The starting point to learn to do this is that the Hype API has methods that can control where you’re at in a timeline like hypeDocument.goToTimeInTimelineNamed() and symbol instance versions.

<video> elements themselves have a currentTime property to get the time value, which could be fed into those APIs. Alternatively as your timelines may have a different time, you can divide by the .duration value to get a percent complete, and then multiple by the hypeDocument.durationForTimelineNamed() API to get a scaled time int that timeline.

The trickier part is knowing when the time in the video has updated. Videos do havea “timeupdate” event, but this typically is only fired at a rate of 4 FPS, so won’t make a smooth animation. Instead it is better to listen to the play and paused events and have your own code called at a high framerate to make smooth animations. JavaScript has a window.setTimeout() function that can do this, but when screen drawing like with a Hype document is involved, it is better to use window.requestAnimationFrame() that lets the browser manage an appropriate time to draw.

Basic code that you could add to an On Scene Load handler would look something like:

// get the video element
var videoElement = hypeDocument.getElementById("myVideoId");

// setup a function that will sync the time in the video to the two timelines, "Other Timeline" and a symbol's "Main Timeline"
var syncTimelines = (function () {
	// put in a try block since the play event may happen before we have a duration, which would fail
	try {
		// get the percent complete so we can make this relative to the time in the other timelines
		var videoPercentComplete = videoElement.currentTime / videoElement.duration;
	
		// figure out the actual time in the other timeline based on the percent complete
		var currentTimeForOtherTimeline = videoPercentComplete * hypeDocument.durationForTimelineNamed("Other Timeline");
		
		// set the time
		hypeDocument.goToTimeInTimelineNamed(currentTimeForOtherTimeline, "Other Timeline");
	
		// get the symbol based on an ID
		var symbolInstance = hypeDocument.getSymbolInstanceById("mySymbolId");
		
		// likewise now figure out the appropriate time and set it on the symbol instance
		var currentTimeForSymbolTimeline = videoPercentComplete * symbolInstance.durationForTimelineNamed("Main Timeline");
		symbolInstance.goToTimeInTimelineNamed(currentTimeForSymbolTimeline, "Main Timeline");
	} catch {}
	
	
	// call back to this function if we are still playing so it constantly updates, but don't if we are paused to prevent wasteful CPU usage
	if(!videoElement.paused) {
		window.requestAnimationFrame(syncTimelines);
	}
});

// hook up event listeners for major changes to say to sync
videoElement.addEventListener('play', syncTimelines);
videoElement.addEventListener('paused', syncTimelines);
videoElement.addEventListener('timeupdate', function () {
	// only use this event listener if we are paused, since it represents the user manually seeking
	if(videoElement.paused) {
		syncTimelines();
	}
});	

Here’s my example file:

SyncVideo.hype.zip (1.7 MB)

One small note is that while you want to animate the main timeline, the duration of the main timeline include the video itself. So if the video is longer than your other animations the scaling won’t work. For this example, I put the animation on an “Other Timeline”. If you do want to use the main timeline, you could instead hardcode the duration instead of using the hypeDocument.durationForTimelineNamed() API.

There’s also a lot of other examples on the forums using this basic technique if you search for “video sync” or “timeupdate”.

2 Likes

Thank you for taking the time to reply, Jonathan! This is quite helpful. I’ll try it out.

1 Like