Create beautiful movie posters using pure JavaScript

Scott Cook
3 min readFeb 26, 2020

--

Inspiration

I was inspired to figure out how the beautiful prints of thecolorsofmotion.com were created. These images are created by plotting a time series of the average colors of frames through the duration of a movie. It’s a beautiful and simple way to depict the feeling and mood that a movie creates.

Can you guess which movies these Colors of Motion are from (below)?

answers at end of article

Make it yourself, using pure Javascript!

Javascript to the rescue. I’m not going to get into too much of the implementation details here because it’s rather advanced, but I will walk through the high level process to do this using pure JS.

Javascript is able to pull image data and frame data from media using the HTML Canvas. The Canvas has access to pixel level information in media, so you can ask, “what color is the 4th pixel from the top in this image?” and it will return “light blue”. That is the basis for creating the Movie in Motion graphics.

What you can create with JS…

Let’s walk through how to create the below graphic using the excellent Spring Movie from Blender Foundation.

Create this ️😍
From this: https://bit.ly/2Tdg6rL

The script details…

  1. HTML Video element for loading and streaming the video
  2. One HTML Canvas for reading video stream data and calculating average frame colors
  3. Second HTML Canvas for painting color splices (final result)

I’ll chat a bit about each below, then let you play with the script!

HTML Video — load and stream video

Video is loaded to native HTML Video and use a seek function to set current time and seek to position. Setting current time + seek sets frame that can be scanned in HTML Canvas.

// Load Video
var video = document.querySelector('video')
video.src = URL.createObjectURL(e.target.files[0]);
// Seek
video.currentTime = currentTime;
await new Promise(r => seekResolve = r);

First HTML Canvas — calculate average frame color

This script accepts a frame and scans it by visiting every 5th pixel, sums the total RGB values (0–255) to itself and then divides by the number of observations to get the average color for each channel over the entirety of the frame.

function getAverageRGB(video) {
...
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r / count);
rgb.g = ~~(rgb.g / count);
rgb.b = ~~(rgb.b / count);
return rgb;
}

Second HTML Canvas — draw final graphic

The final graphic is comprised of slivers of color that represent the average color of a frame. The length of the video is divided by numSlices which means the sample rate will be video.duration/numSlices which is also the number of slivers in the final graphic output.

// add sliver to second canvas
ctx2.beginPath();
ctx2.fillStyle = 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'
ctx2.fillRect(widthInterval * currentSplice, 0, widthInterval, h2);

Try it out:

If you need a video, download Big Buck Bunny (another Blender Video)

Full code available here: https://jsfiddle.net/6b4ev8un/

Answers:

Titanic — Spider Man: Into the Spider Verse — Mad Max: Fury Road

Thanks for reading :)

--

--