Another short demo before we move on to more complex applications. In this one I wanted to do something with the HTML5 video element; I had probably seen something about kaleidoscopes recently so I thought about doing a video kaleidoscope. Something that would like the screenshot below... That should be easy!

Kaleidoscope screenshot

Actually, it wasn’t too bad. Although I suspect that it could be done more concisely in SVG (something for a next episode, I guess) this implementation based on video and canvas, with an additional help of CSS 2D Transforms, is really simple conceptually. And it will exercise your processor quite a bit in the process...

Sampling video

As the screenshot above shows, our kaleidoscope is a circle rotating on its own or following the cursor, divided in six “slices”, where each slice contains the same picture, rotating on its own, and flipped. A first approach was to have six video elements playing the same content at once, but it proved clearly impractical to synchronize, and without looking too much into it, masking and overlaying different videos seemed pretty tricky.

Fortunately, we can easily sample the video by drawing the current frame in a canvas element (with the drawImage() method of a 2D drawing context, and using a video element as the first argument.) We can draw our kaleidoscope in a canvas element, with a single video playing in the background. The video is playing behind the canvas so that we don’t see it but can still hear it and of course sample it. And although we could draw all six slices in the same canvas, I have chosen to draw the same picture in six different canvases and let CSS do the rest. We can describe the full process in four steps.

  1. Set up a video element, and wait for it to start (see below.)
  2. Set up six canvas elements. For each canvas, we’ll have an initial clipping mask which will produce the shape of the slice. This needs to be done only once as it operates on the drawing context of the canvas. The tricky part here is to understand how to use the arcTo() drawing primitive, and honestly I’m not quite sure that I do but it seems to work out well enough.
  3. At a given rate (something like 15-30 frames per seconds, which is sufficient for video), draw the current video image in every canvas. We set a new context before drawing where we apply a rotation incrementally so that the image in each slice appears to rotate on its own.
  4. Set the transform style property (or rather -webkit-transform property) of each canvas element to rotate by increments 60 degrees, and flip around the X-axis for every other canvas (so that the symmetry is respected.) Since the whole kaleidoscope rotates, we add the current rotation angle of the kaleidoscope to every slice to achieve global rotation.

Cross-browser issues

The current demo only supports Safari. I haven’t had much success playing audio or video in Chrome, so maybe some day it will work. Firefox should work, but needs a few fixes:

  • The main issue is that Safari and Firefox do not support the same media formats. This means that a fallback OGG video is necessary for Firefox.
  • Media elements generate an awful lot of events, and because they can be quite large it means that we need to wait for enough data to be available before we can start playback. It may take a while even knowing what the size of the video is, which is necessary to set up the canvases, drawing contexts, &c. In the current implementation I wait for the canplaythrough event before starting playback, which means that the whole video should be playable. Unfortunately I wasn’t able to catch that event in Firefox. I will write a bit more on this topic later and hopefully fix this demo to work in Firefox.
  • As in the poetry magnets demo, we need to add support for the -moz-transform style property for CSS transforms.

That’s all for now; on the next episode we’ll see more canvas animation action.

Update: these issues have now been addressed.