Synchronizing MLK’s speech with PopcornJS, Skrollr and Google Docs


On August 28, 1963, Martin Luther King Jr. delivered his famous “I have a dream speech” at the March on Washington. As part of VOA’s 50th anniversary coverage, ODDI decided to transform archival footage of King’s speech into an interactive video with subtitles and synchronized interactive content to help provide context for the speech for an international audience.

In the end we weren’t able to secure the rights to the entire speech. As a result, this abridged version of the project is meant as a proof of concept and an inspiration for future stories (currently the project works best in Google Chrome). The JavaScript libraries we used support modern browsers and mobile devices, but for this demo we decided to limit the time we spent making it work across browsers and devices.

Making More Popcorn

One of our goals this year is to help international journalists create more interactive audio and video stories. We’re approaching this challenge on three different levels:

  • Quick turn video projects where journalists want to add simple context.
  • Medium-scale projects with more interactivity and more layers of information.
  • Larger scale, custom built projects that require a designer and developer.

For the smaller and medium scale projects, we’re currently forking a version of the Popcorn Maker project for the specific needs of journalists. We’re restyling the look and feel, adding new plugins to reduce the time to publish and building in translation support to promote sharing across language services.

For larger custom audio and video stories, like the “I have a dream” project, we’re using the Popcorn.js library to synchronize media with layers of context and interactive elements.


We added popup explanations and links throughout the speech.


We were definitely inspired by NPR’s “Lost and Found” project, created by Claire O’Neill and Wes Lindamood. “Lost and Found” tells the story of the obscure but masterful photographer Charles Cushman by synchronizing a radio story with a portfolio of Cushman’s photos.

The project used Popcorn.js to synchronize the audio with photographs and text. According to the website, “Popcorn.js is an HTML5 media framework written in JavaScript for filmmakers, web developers, and anyone who wants to create time-based interactive media on the web.”

Using Popcorn.js you can include a variety of plugins for synchronizing different types of content—like images, wikipedia articles and maps—with audio or video. For this project I stuck with the popcorn.code.js plugin, which allows you to easily execute JavaScript at specific times during the audio or video.

var p = Popcorn( "#video" )
  start: 3,
  end: 8,
  onStart: function( options ) {
  alert('Insert your JavaScript magic here');

When the video reaches the 3-second mark, the browser executes whatever JavaScript you’ve included.

Scrolling with Skrollr

A parallax site features different elements appearing on the screen and moving at different speeds as the user scrolls down the page. Over the last year, we’ve seen a number of journalism stories told with parallax scrolling, from ESPN’s story on Dock Ellis to La Tercera’s story on the 40th anniversary of the Chilean military coup.

At ODDI, we’ve also been interested in using parallax scrolling for storytelling. As an added challenge, we decided to create a story where the scrolling was driven by the video.

We experimented with a number of different parallax libraries. Ultimately we decided on Skrollr.js for the following reasons:

  • It has a proven track record for professional projects (inside journalism and out).
  • It played nicely with our CMS.
  • It supports mobile (which wasn’t a priority for this project, but it’s nice to know for the future).
  • Several tutorials are available here, here and here.
  • It has a simple, familiar syntax (most of the action is handled by CSS-like attributes).

The animation is defined by “data-#” attributes in the HTML tags. Any CSS attribute can be animated over time.

< div id="king_cutout" data-100="opacity:0;top:-100px;" data-500="opacity:1;top:50px;">
    < img src="../img/photo.png"/>

In this example, when the the scroll position is 100 (“data-100″), the opacity is 0 (invisible) and the position is -100px (off screen). As the user scrolls to 500 (“data-500″) the image fades in to an opacity value of 1 and moves down to 50px from the top of browser. Positions can be described in pixels or percentages, but you’ll need to use consistent units across the entire animation.


We used PopcornJS to synchronize subtitles and kinetic type.

Creating Subtitles with TabletopJS + GoogleDocs

One of our major goals for this project was to include subtitles for King’s speech. I wrote about using Google spreadsheets and TabletopJS to support translations in a previous post. The idea here is very similar.

I started off with a spreadsheet page in English that includes the speech broken up into sentences. I added a column to timecode each block of text by seconds. I then create a separate page for each translation.

There’s a quick and dirty solution for translating a spreadsheet. You can use Google Translate to translate cells in a google spreadsheet.


“English” = the name of the spreadsheet page source (optional)
“B3″ = the cell source of the text
“en” = English, the language you’re translating from
“zh-CN” = the language code for the language we’re translating into (simplified Chinese)

This technique offers varying degrees of success. Google Translate appears to work better for western languages (Here’s a link to the Spanish version translated by Google). But regardless, it offers a starting point and is a very quick way of translating the speech into dozens of languages. For a public facing project we would still rely on human translator to provide an accurate translation.


Map overlays were used to show the path of the protesters and places mentioned in King’s speech.

…But Wait, There’s More

Since we’re already loading in a Google spreadsheet, I decided to use a spreadsheet page to handle the timing and locations for the scrolling.

Rather than manually creating a separate popcorn.code.js event for each scroll, I added a spreadsheet page with the start times, end times, scroll position and length of time for each scroll. Then I created a loop that runs through the page to create the code events. This made it significantly easier to add and edit times without having to update the JavaScript file.

var numberOfScrolls = scrollData.length;
//scrollData is the data that was loaded in by TabletopJS
var scrolls_array = [];
for (i=0;i<numberOfScrolls;i++){
 var startTime=Number(scrollData[i].starttime);
 var endTime=Number(scrollData[i].endtime);
 var scrollPosition=Number(scrollData[i].scrollpos);
  start: startTime,
  end: endTime,
  paragraphID: scrolls_array[i],
  scrollPos: scrollPosition,
   var currentElem = options.paragraphID;
   s.animateTo(options.scrollPos, {duration:1000});

Future Storytelling Opportunities

There was definitely a learning curve trying to integrate Popcorn.js and Skrollr into a project that runs in our CMS. But we were able to resolve most of the technical issues, and now we’re looking forward to working with language services at the BBG to find new stories that could benefit from this treatment.

What do you like about this project and what suggestions do you have? Please comment!

The following two tabs change content below.
Brian Williamson

Brian Williamson

Brian Williamson is the senior UX designer for the Office of Digital & Design Innovation. Follow him on Twitter: @drawinghands.

Leave a Reply

Your email address will not be published. Required fields are marked *

* Copy This Password *

* Type Or Paste Password Here *