Tim Benniks

Senior web developer at AKQA




The Project

Technical challenges

Pragmatic solutions


Interactive TV commercial

Choose to cross the line

Emphasis on intense moments

Technical challenges



Animating with clips

Animating masks on moving parts


Streaming or pre-loading?

Time-based events

Interactive 3D scene


Async / event based

Five weeks
One web-developer

Let's do this!


Pre-load assets in groups

Only load what you need

Load during idle time

Garbage collect

The obvious stuff

Use a CDN with versioned content

Concat and minify JavaScript and CSS in the build

Use GZIP compression


Animations with video

Videos have a time-based api. We needed a frame-based api.

We needed looping and tweening over frames in time

Reinventing the wheel of video playing

Simple tweening, seperate frame images, canvas

Canvas renders frames for time

var toFframe = 100,
    callback = function() { alert('What would Chuck Norris do?'); };

tweenToFrame(toFframe, callback);

// {Number} toFrame
// {Function} callback
tweenToFrame = function(toFrame, callback)
  // object with property to tween
  var sequenceData = { frame: currentFrame },
      time = 500; // time in ms

  tween.to(sequenceData, time,
    value: toFrame,
    onUpdate: function()

    onComplete: function()
      if(callback) callback();

// List of frames (created by the pre-loader)
var frames =
  { url: 'image.jpg', tag: 'HTMLIMAGEElement' },
  { url: 'image2.jpg', tag: 'HTMLIMAGEElement' }

showFrame = function (frameNo)
    0, 0, 1100, 618, 0, 0, 1100, 618

See it in action

Animating masks on moving parts

Canvas path masks image

var pathPoints =
  topLeftX: 86,
  topLeftY: 0,

  topRightX: 593,
  topRightY: 0,

  bottomRightX: 507,
  bottomRightY: 618,

  bottomLeftX: 0,
  bottomLeftY: 618

Tween the path points

// Automatically updates pathPoints object with tween
Tween.to(pathPoints, time,
  topRightX: 454,
  bottomRightX: 368,
  ease: 'Expo.EaseInOut',
  onUpdate: function()
    // currentFrame is a global var set by the
    // mouseover function which plays the sequence

This will tween the path and show frames

showFrame = function (frame)
  context.clearRect(0, 0, 1100, 618);

  context.moveTo(pathPoints.topLeftX, pathPoints.topLeftY);
  context.lineTo(pathPoints.topRightX, pathPoints.topRightY);
  context.lineTo(pathPoints.bottomRightX, pathPoints.bottomRightY);
  context.lineTo(pathPoints.bottomLeftX, pathPoints.bottomLeftY);
  context.lineTo(pathPoints.topLeftX, pathPoints.topLeftY);


  context.drawImage(frames[frame].tag, 0, 0, 1100, 618, 0, 0, 1100, 618);

See it in action


Some emotions


Pre-loading a video only sometimes works

No matter how you encode it

It also depends on how it's served from the CDN

I think...

Obviously it worked fine on my machine

As it turns out

Streaming is awesome

Server sends chunks of film with 206 partial content header

It's more stable than pre-loading

Just whack the video tag into the DOM and be happy

Time based events

We needed subtitles, timed accolades, sound triggers, analytics triggers

Cue points on video timeupdate event

cuePoint(videotag, 2.1, function() { triggerEvent('sound::play', 'engine1'); });
cuePoint(videotag, 2.4, function() { triggerEvent('sound::stop', 'engine1'); });

Interactive 3D scene

Yay, let's do WebGL!

Couldn't get assets for 3 scenes in 5 weeks

Pragmatic solution

Output screenshots from the game

360 cameras around an intense moment

Render in CANVAS

Same approach as the choice page

Tween through frames by clicking on a hotspot

Information overlay is another mask animation with canvas

See it in action


All sound is loaded async

Also for movies

Hear it in action


Partner for sound design and JS library

Their JS library played the sounds via our events system

These guys rock

Big thanks to the team

This is only half of them though

Like what you saw?

I'm off to Paris next week

If you want my job, come chat to us...