Tim Benniks

Senior web developer at AKQA

github.com/timbenniks

@timbenniks

Agenda

The Project

Technical challenges

Pragmatic solutions

Questions

Interactive TV commercial

Choose to cross the line

Emphasis on intense moments

Technical challenges

Performance

Animations

Animating with clips

Animating masks on moving parts

Video

Streaming or pre-loading?

Time-based events

Interactive 3D scene

Sound

Async / event based

Five weeks
One web-developer

Let's do this!

Performance

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

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()
    {
      showFrame(~~sequenceData.frame);
    },

    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)
{
  context.drawImage(
    frames[frameNo].tag,
    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
    showFrame(currentFrame);
  }
});
				

This will tween the path and show frames


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

  context.beginPath();
  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.closePath();

  context.clip();

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

See it in action

Video

Some emotions

Huh?

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

Sound

All sound is loaded async

Also for movies

Hear it in action

Dinahmoe

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...

Questions?