12 days of CreativeJS – CreativeJS http://creativejs.com The very best of creative JavaScript and HTML5 Wed, 03 Jun 2015 20:19:39 +0000 en-US hourly 1 https://wordpress.org/?v=4.4.1 Day 12 — 3D pixel particles http://creativejs.com/2012/01/day-12-3d-pixel-particles/ http://creativejs.com/2012/01/day-12-3d-pixel-particles/#comments Thu, 05 Jan 2012 09:00:17 +0000 http://creativejs.com/?p=2200 Continue reading ]]>

The Christmas season is pretty much over, but before you take the tree down, and return your baubles to the musty box in the cupboard, we have one final 12 days of CreativeJS post for you.

And it’s a goodie! Today, I’m going to explain a magic formula that can figure out where a 3D point would be on your 2D canvas. Once we know that we can make some 3D pixel particles!

A 3D point has an x, y and z position, where z is how far away it is from you. If a point is at 0,0,0 then we are going to render it right in the middle of the screen. Let’s call our 3D co-ordinates x3d, y3d, and z3d.

The first part of the formula tells us how big or small things should appear at a given z distance :

var scale = fov/(z3d+fov);

Where fov is a notional field of view, in other words, how zoomed-in or wide-angled our virtual lens is1.

Now we know how big things are at that distance, we just multiply our 3D x and y by that scale factor to get our 2D x and y.

var x2d = x3d * scale; 
var y2d = y3d * scale;

If you think about it, this kinda makes sense. Let’s say our particle is 5 pixels over to the right, and it moves towards us. As it gets nearer, the particle moves further to the right in the 2D space. We’re multiplying our x3d (which is 5) by a growing scale factor to get our x2d. And our particle will move further right as it comes towards us.

There’s just one more thing though – this formula assumes that the 2D co-ordinate system also has its 0,0 point in the middle of the screen. So we need to add half the width and height of our canvas to the result to offset this.

var x2d = (x3d * scale) + halfWidth; 
var y2d = (y3d * scale) + halfHeight;

Get it? Great! You should also watch out what happens if points go behind the camera, because if you try to render them they’ll be all inverted. We’re not worrying about that in our simple code here, but if you wanted to implement that then just check to see if z is less than –fov and if it is, don’t draw it.

And that’s all there is to it. Who’d have thought it’d take so few lines of code to make a simple 3D pixel renderer?

1It’s not an actual field of view as an angle, it’s just an arbitrary value that the formula requires. I usually use around 150 – 250, but you can experiment to see what results you get.

So now if we combine it with Paul King’s day 3 post about setting pixels in a canvas, we can now colour the relevant 2D pixel for the 3D point.

So let’s make a whole bunch of 3D points! :

var pixels = []; 
for(var x = -250; x<250; x+=5) { 
	for(var z = -250; z<250; z+=5) { 
		var pixel = {x:x, y:40, z:z};
		pixels.push(pixel); 
	}
}

You can see here we’re creating a horizontal grid of 3D point objects with x, y and z properties. Here’s what it looks like when we render it :

Now let’s look at our render function, called 30 times a second :

function render() { 
 
	// clear the canvas
	context.clearRect(0,0,width, height); 
	// and get the imagedata out of it
	var imagedata = context.getImageData(0, 0, canvas.width, canvas.height);
 
	// iterate through every point in the array
	var i=pixels.length; 
	while(i--){
		var pixel = pixels[i]; 
 
		// here's the 3D to 2D formula, first work out 
		// scale for that pixel's z position (distance from 
		// camera)
		var scale = fov/(fov+pixel.z); 
 
		// and multiply our 3D x and y to get our
		// 2D x and y. Add halfWidth and halfHeight
		// so that our 2D origin is in the middle of 
		// the screen.
		var x2d = (pixel.x * scale) + halfWidth; 
		var y2d = (pixel.y * scale) + halfHeight; 
 
		// and set that 2D pixel to be green
		setPixel(imagedata, x2d, y2d, 0, 255, 60); 
 
		// add 1 to the z position to bring it a little 
		// closer to the camera each frame
		pixel.z-=1;
 
		// if it's now too close to the camera, 
		// move it to the back
		if(pixel.z<-fov) pixel.z += (fov*2);
 
	}
 
	// and write all those pixel values into the canvas
	context.putImageData(imagedata,0,0); 
 
}

So we’re iterating through each 3D point object, converting it into 2D and setting the pixel for that 2D position. Then we’re moving each point forward towards the camera by decrementing z, and once it gets too close we’re moving it to the back.

Play with it here on JSFiddle.

How about this version where we create 3D pixels in undulating waves using Math.sin(…), and we have now declared a custom Pixel3D object in which to store our 3D x, y and z.

Or this version that has pixels in a big doughnut shape (or torus if you want to sound extra posh). Note that we’re now rotating every point around the origin relative to the mouse position – using the newly added rotateX and rotateY functions in our Pixel3D object. And instead of just setting a pixel colour, we’re adding the colour values onto what’s already there (this is known as additive blending and it causes the particles on top of each other to burn out to white).

And finally, here’s a strange attractor, copied from Paul’s example from a while back. This version has a trails effect, and also a pulsating colour for each pixel based on a sine wave.

So clearly there are a few techniques in these examples that I haven’t explained in great detail, mainly to do with setting up 3D points and rotating them. But at least once you have x, y and z values for 3D points, you now know how to draw them in 2D. And for me that was the largest stumbling block to getting started in 3D.

I hope you enjoy your new 3D explorations, and I hope you’ve enjoyed the 12 days of CreativeJS! We’d love to hear what you think, so please leave a comment.

]]>
http://creativejs.com/2012/01/day-12-3d-pixel-particles/feed/ 9
Day 11 – Animating with sprite sheets http://creativejs.com/2012/01/day-11-sprite-sheets/ http://creativejs.com/2012/01/day-11-sprite-sheets/#comments Wed, 04 Jan 2012 10:00:26 +0000 http://creativejs.com/?p=2198 Continue reading ]]>

The holidays are over and we’re all back at the office getting back to the regular routine and feeling a bit like robots. No? OK, that’s maybe a stretch. Hopefully you at least like robots though, because we’re about to animate a little robot heart using sprite sheets twice: one using canvas and one using a div.

Animating with a sprite sheet is like moving a connected series of images past a set viewing area. Think of a viewmaster or a film strip if you’re old enough.

The image below shows you approximately what’s going on behind the scenes. We have one big image that contains every frame of the robot animation (the sprite sheet) and we display one at a time, moving along and down our list of images as we progress through the animation. Do this fast enough and you have animation :)

The sprite sheet

We’ll be using the same sprite sheet image (this one) for both variations. I won’t get into how to create a sprite sheet here, but there are a number of ways to make them and you certainly don’t have to put them together all by hand. I’ve used Keith Peter’s SWFSheet to export the sprite sheet I’m using here from a SWF.

First up, the canvas version

Once we’ve done our initial file set up, the first thing to do is load in our sprite sheet image. When we know our image has loaded, we set an interval to call our loop function 30 times a second, which is where everything happens.

	//load the image
	image = new Image();
	image.src = "robot2.png";
 
	image.onload = function() {
            //we're ready for the loop
            setInterval(loop, 1000 / 30);
        }

Great! we’re ready to actually make something happen. The loop function starts out easily enough with a call to clearRect(…) to clear our canvas. But what’s with that excessively long drawImage(…) function? It’s a bit ugly.

c.drawImage(image, xpos, ypos, frameSize, frameSize, 0, 0, frameSize, frameSize);

All those extra arguments are there because we are defining two different rectangles The first rectangle (xpos, ypos, frameSize, frameSize) defines the rectangle in our source image that we want to copy from. This will change every frame because we are updating the xpos and ypos values each time. The second rectangle (0, 0, frameSize, frameSize) defines where in our canvas we are drawing to. For this example that will never change. (You might also notice that both my width and height are being set to frameSize. To keep things simple, I’m using a square image area.)

Next up, we do a little bit of math to figure out exactly which part of our sprite sheet we should draw from to display the correct frame:

//each time around we add the frame size to our xpos, moving along the source image
xpos += frameSize;
//increase the index so we know which frame of our animation we are currently on
index += 1;
 
//if our index is higher than our total number of frames, we're at the end and better start over
if (index >= numFrames) {
	xpos =0;
	ypos =0;
	index=0;	
//if we've gotten to the limit of our source image's width, we need to move down one row of frames				
} else if (xpos + frameSize > image.width){
	xpos =0;
	ypos += frameSize;
}

We add our frameSize to our xpos to move along our sprite sheet horizontally (remember, our images our square). We also increment an index counter to keep track of what frame we’re on. If our index is higher than the total number of frames we have, it’s time to start over. If our next horizontal move would have us going past the width of our sprite sheet, we move down to the next row. This repeats over and over, creating our animation. Play with it here on JSFiddle.

One down!

Once more, with divs

I think you’re getting the hang of it now, so I’ll do a little less explaining for this one. We’re going to do pretty much the exact same thing except this time we’re calculating how to move the background image of a div so that the correct frame in the animation is visible.

The first notable difference is in our small block of CSS:

#anim {
	width:200px;
	height:200px;
	background-image: url(robot2.png);
}

We’re identifying our target div anim, setting its height and width (our viewable area), and assigning its background image (our sprite sheet).

Our loop function looks incredibly similar, or you might even say nicer since it doesn’t have nearly as many lines of comments. The only real difference is the first line:

div.style.backgroundPosition = (-xpos)+"px "+(-ypos)+"px";

We’re repositioning #anim‘s background image every frame. The calculations to determine the xpos and ypos values are the same as in the canvas version so the rest of the function should look very familiar. But you can see we’re using -xpos and -ypos – this is because we want to move the background image up and to the left to reveal the next frame.

So there you have it, the same sprite sheet animation two ways! Hopefully it was even a bit fun :)

And with that, we wrap up Day 11 of the 12 days of CreativeJS. Only one more to go!

]]>
http://creativejs.com/2012/01/day-11-sprite-sheets/feed/ 19
Day 10 – Drawing rotated images into canvas http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/ http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/#comments Tue, 03 Jan 2012 09:00:32 +0000 http://creativejs.com/?p=2195 Continue reading ]]>

The room may still be spinning after the New Year celebrations but at least after this, you’ll be able to rotate your images to counter the effects!

You probably know we have this handy canvas context function drawImage :

context.drawImage(image, x, y);

where image is a DOM image (or another canvas), and x and y is the top left of the image. There are several other optional parameters, but I’m not using them today. (You can take a look at the canvas cheat sheet we posted yesterday if you’re curious.)

What’s not that obvious is how to draw a rotated image. You’d think there’d just be a nice rotation angle built in to drawImage, right? But no, instead, you have to rotate the entire co-ordinate system before you draw stuff!

Check this example out, we already have a canvas context set up, and we have logoImage loaded and ready to use :

context.drawImage(logoImage, 50, 35);

We’re drawing our logo from the top left at 50 pixels across and 35 pixels down which gives you this :

rotated image 1

All straightforward so far, but what if we rotate our co-ordinate system first?

context.rotate(0.5); 
context.drawImage(logoImage, 50, 35);

Whoa, what happened? Well, the entire co-ordinate system rotated by 0.5 radians (roughly 30º) around the top-left corner of the canvas before we drew the image. So if you think about it, 50 across and 35 down isn’t the same as place as it used to be.

So how do we rotate our image and keep it in the same place? Well before we call rotate we need to move the origin of our canvas to where we want to draw our image, and we can do this using context.translate(x,y).

context.translate(50, 35); 
context.drawImage(logoImage, 0, 0);

The translate function moves the entire co-ordinate system; context.translate(50, 35) moves the origin across by 50 and down 35. Now if we draw our image at 0,0 it’s actually at the new position of the origin :

Remember that context.rotate rotates around the origin. So if we move the origin to the 50,35, the image will be rotated around that point :

context.translate(50, 35); 
context.rotate(0.5); 
context.drawImage(logoImage, 0, 0);

All good so far, but what if we want to rotate around the centre of the image? Well we have to move the origin into the middle of where we want to draw the image, and then draw the image up and left half its width and height.

Confused? This example will make it clearer :

// move the origin to 50, 35   
context.translate(50, 35); 
 
// now move across and down half the 
// width and height of the image (which is 128 x 128)
context.translate(64, 64); 
 
// rotate around this point
context.rotate(0.5); 
 
// then draw the image back and up
context.drawImage(logoImage, -64, -64);

So, to re-iterate, we’re moving the origin to the middle of where we want the image to be drawn, then rotating around that point, and then drawing the image left and up in our newly rotated co-ordinate system.

The only thing left to understand is radians, but we explained all about that on our day 4 post. You did see that, right? :)

One final thing: at the end of all our translating and rotating, our co-ordinate system is all screwed up and there’s no way to get it back (don’t even think about resizing the canvas to reset it!). But we can save it first :

// save the context's co-ordinate system before 
// we screw with it
context.save(); 
 
// move the origin to 50, 35   
context.translate(50, 35); 
 
// now move across and down half the 
// width and height of the image (which is 128 x 128)
context.translate(64, 64); 
 
// rotate around this point
context.rotate(0.5); 
 
// then draw the image back and up
context.drawImage(logoImage, -64, -64); 
 
// and restore the co-ordinate system to its default
// top left origin with no rotation
context.restore();

Now we know how to draw centred and rotated images, so why not package this up into a nice function?

var TO_RADIANS = Math.PI/180; 
function drawRotatedImage(image, x, y, angle) { 
 
	// save the current co-ordinate system 
	// before we screw with it
	context.save(); 
 
	// move to the middle of where we want to draw our image
	context.translate(x, y);
 
	// rotate around that point, converting our 
	// angle from degrees to radians 
	context.rotate(angle * TO_RADIANS);
 
	// draw it up and to the left by half the width
	// and height of the image 
	context.drawImage(image, -(image.width/2), -(image.height/2));
 
	// and restore the co-ords to how they were when we began
	context.restore(); 
}

Check out this example to see it in action.

It’s worth taking the time to properly understand translation, rotation and saving and restoring the draw state stack – it’s incredibly powerful. And who knows, maybe the room will stop spinning in time for tomorrow’s post. :)

]]>
http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/feed/ 14
Day 9 – It’s okay to cheat http://creativejs.com/2012/01/day-9-its-okay-to-cheat/ Mon, 02 Jan 2012 04:00:54 +0000 http://creativejs.com/?p=2191 Continue reading ]]>

No matter how much you’ve worked with canvas, you could always use a little reminder all those attributes and methods you don’t use everyday. The canvas cheat sheet is a great thing for exactly that.

It’s a quick reference sheet that covers working with paths, pixel manipulation, line style, and lots more from Jacob Seidelin. It’s a whole lot easier to read than the WHATWG specs and it comes in two handy formats: PDF and PNG. Bookmark it and keep it handy for later!

]]>
Day 8 – Photo fun with CamanJS http://creativejs.com/2012/01/camanjs/ Sun, 01 Jan 2012 05:00:00 +0000 http://creativejs.com/?p=1966 Continue reading ]]>

CamanJS (short for Canvas Manipulation JavaScript) is a great micro JS library for applying filters and effects to images using canvas. It has a very clean jQuery-like ‘chainable’ API, but is independent of any JS framework. It’s open source and extensible, so more custom effects can be easily added. Multiple filters can be applied at the same time too to create that hipsterish Instagram-style effect, should you so desire!

So have a go! Download the source code from GitHub or check out the examples on the CamanJS website. Oh, and happy new year! May your 2012 be filled with many geeky delights :)

]]>
Day 7 – Fireworks! http://creativejs.com/2011/12/day-7-fireworks/ http://creativejs.com/2011/12/day-7-fireworks/#comments Sat, 31 Dec 2011 06:00:00 +0000 http://creativejs.com/?p=2189 Continue reading ]]>

Well it’s New Year’s Eve, and you can be absolutely sure that all over the world people will be celebrating with fireworks. What better way to usher in a new digital year than with a canvas-based equivalent? I tell you, there surely is no finer thing!

It’s something of a bumper “tip” this one, so much so that we popped it in to our tutorials section. So head over there and discover how you can make your own firework display using the HTML5 canvas tag.

All together now: “OooooH! … AaaaaAHH!”

Check out the Fireworks Effect and our tutorial: Make an explosive firework display

]]>
http://creativejs.com/2011/12/day-7-fireworks/feed/ 6
Day 6 – Getting canvas in on the web fonts fun http://creativejs.com/2011/12/day-6-webfonts-canvas/ Fri, 30 Dec 2011 09:00:54 +0000 http://creativejs.com/?p=2185 Continue reading ]]>

It’s no secret that canvas leaves a lot to be desired when it comes to even the most basic typography. But at least we can still use more than just the usual web safe font suspects! This installment of our snack-sized tips is all about how to use your web font(s) of choice in canvas reliably.

Just like any content, fonts need to load before you can use them. If you want to be absolutely sure that your fonts are there, or want better control over what happens if they’re not, your best bet is using font events.

My web font service of choice, Typekit, provides a font loading events system that makes this extra easy. Turns out they’re also nice folks and have open sourced this system as the Google WebFont Loader. So you can use this technique no matter how you prefer to source your web fonts. Something for everyone! It is Christmas, after all :)

We’re going to take advantage of the same font events that are usually used to prevent the FOUT (Flash Of Unstyled Text) to delay our call to fillText() until we know our web fonts are available. If we call fillText() before our font has loaded we’ll get a lovely line default serif text instead. That could really mess things up.

Let’s look at what it takes to create this simple example of displaying a line of text in Proxima Nova Soft in canvas. For the sake of simplicity, this example assumes you’re using Typekit. (The Google WebFont Loader docs provide instructions on how to set up the API with other services.)

First, we need to add the code to listen for the active font event. That’s the one that fires when the font(s) are available for use. Then, set the displayText() function to be called when the active event is fired.

try {
   Typekit.load({
     active: function() {
       // Javascript to execute when fonts become active
       displayText();
     }
   })
} catch(e) {}

So now, when the web fonts are active, my displayText() function will be called. In this basic example there’s really not much to it. I’m just telling my canvas to fillText with the parameters I’ve already defined:

function displayText() {
     dcontext.fillText(words, textOffsetLeft, textAscent);   
}

All the parameters for my font properties, including the reference to the web font, were assigned in my initial set up. I’ve used the shortform to define the weight, size, and font-family a few lines up from the displayText() function:

 dcontext.font = "400 162px proxima-nova-soft";

If you’re wondering, canvas uses font weights the same way CSS does (yay!). In this case, I’m using a font weight of 400 which corresponds to the regular weight of Typekit’s Proxima Nova Soft.

In this ever so slightly more complex example, I’ve increased the weight to 700 for Proxima Nova Soft Bold, and doubled up the text to create a bit of a drop shadow.

So there you have it. An easy tip for getting your favourite web fonts to play nice with canvas!

]]>
Day 5 – Blur that canvas! http://creativejs.com/2011/12/day-5-blur-that-canvas/ http://creativejs.com/2011/12/day-5-blur-that-canvas/#comments Thu, 29 Dec 2011 08:00:00 +0000 http://creativejs.com/?p=2161 Continue reading ]]>

Blurring an image with JavaScript should be a simple operation, however doing it in an optimal and fast way is not so easy.

The cheapest way to blur an image is to copy the image and overlay it multiple times in slightly different positions. However, in order to create a better and fast blur you need… Mario Klingemann, aka Quasimondo! Mario has created several different techiniques that suit the type of blurring required, whether you need an accurate algorithm, a super fast algorithm, or a bit of both! Check out these examples:

All the code is open source and available on Mario’s site, including usage examples.

Going forward, we’ll soon have even more options available with CSS filter effects. To use them you’ll need to download a build of WebKit Nightly or the latest Google Chrome Canary, but they’re very promising and allow you to apply any kind of custom filter to any HTML element (not just canvas) using fragment shaders. Exciting times!

Check out the demos using WebKit Nightly or Chrome Canary.

]]>
http://creativejs.com/2011/12/day-5-blur-that-canvas/feed/ 2
Day 4 – Working with these weird radian things http://creativejs.com/2011/12/to-radians/ http://creativejs.com/2011/12/to-radians/#comments Wed, 28 Dec 2011 09:00:00 +0000 http://creativejs.com/?p=2030 Continue reading ]]>

There are often times that we’re forced to supply angles in radians rather than degrees, here’s one you might recognise:

// startAngle and endAngle must be given in radians!
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);

Luckily we can convert between degrees and radians, because one degree is equal to PI / 180 radians:

var one_degree_in_radians = 1 * Math.PI / 180;
var five_degrees_in_radians = 5 * Math.PI / 180;

Conversely, one radian is equal to 180 / PI degrees:

var one_radian_in_degrees = 1 * 180 / Math.PI;
var five_radians_in_degrees = 5 * 180 / Math.PI;

So let’s use this knowledge to create variables that make converting between degrees and radians easier:

// One degree in radians
var TO_RADIANS = Math.PI / 180;
 
// One radian in degrees
var TO_DEGREES = 180 / Math.PI;
 
var three_degrees_in_radians = 3 * TO_RADIANS;
var two_radians_in_degrees = 2 * TO_DEGREES;

Nothing can stop us now…

// 360 degree arc
ctx.arc(10, 10, 50, 0, 360 * TO_RADIANS, false);
 
// Sine, Cosine, etc require angles in radians:
var sineX = Math.sin(90 * TO_RADIANS);

Begone, radians!

]]>
http://creativejs.com/2011/12/to-radians/feed/ 6
Day 3 – Play with your pixels http://creativejs.com/2011/12/day-3-play-with-your-pixels/ http://creativejs.com/2011/12/day-3-play-with-your-pixels/#comments Tue, 27 Dec 2011 09:00:13 +0000 http://creativejs.com/?p=2182 Continue reading ]]>

There’s still a metric tonne of turkey left to eat, so let’s work up an appetite 😉

Canvas provides no obvious way to set an individual pixel, nor read the colour of one… unless you know where to look!

The getImageData() function returns an ImageData object, which contains all the raw pixel data. We can choose which part of the canvas that we’re interested in: the (x,y) co-ordinates of the top-left corner, a width and a height.

// assuming a <canvas> tag with id "canvas"
var canvas = document.getElementById("canvas"),
  context = canvas.getContext("2d"),
  // we're interested in the full area of the canvas
  imagedata = context.getImageData(0, 0, canvas.width, canvas.height),
  // the pixel data buffer
  buffer = imagedata.data;

The buffer is an array of numbers, and there are four for every pixel; one for each of the red, green, blue and alpha channels. An alpha of 0 is fully transparent, 255 is fully opaque.

Hopefully this excellent coder art helps to clarify things:

So, to calculate the index in the array for a given pixel, we multiply the pixel y-coordinate by the width of the buffer, add the pixel x-coordinate, then multiply the whole lot by four:

var index = (y * width + x) * 4;

Knowing this, we can now read the value of a pixel for each of the r, g, b, a bytes:

// read pixel (100, 53)
var index = (53 * imagedata.width + 100) * 4,
  r = imagedata.data[index],
  g = imagedata.data[index+1],
  b = imagedata.data[index+2],
  a = imagedata.data[index+3];

Setting the pixel is much the same, but write rather than read:

// full red
imagedata.data[index] = 255;
// no green
imagedata.data[index+1] = 0;
// no blue
imagedata.data[index+2] = 0;
// fully opaque 
imagedata.data[index+3] = 255;

If the array has been modified, we need to ‘write’ it back to the canvas, using the putImageData() function:

// draw the buffer back, at canvas position (0, 0)
context.putImageData(imagedata, 0, 0);

Let’s wrap this up with a more concrete example:

function setPixel(imagedata, x, y, r, g, b, a) {
  var i = (y * imagedata.width + x) * 4;
  imagedata.data[i++] = r;
  imagedata.data[i++] = g;
  imagedata.data[i++] = b;
  imagedata.data[i] = a;
}
 
function getPixel(imagedata, x, y) {
  var i = (y * imagedata.width + x) * 4;
 
  return {r: imagedata.data[i], g: imagedata.data[i+1], b: imagedata.data[i+2], a: imagedata.data[i+3]};
}
 
var canvas = document.getElementById("canvas");
  canvas.width = 400;
  canvas.height = 300;
 
var context = canvas.getContext("2d");
var imagedata = context.getImageData(0, 0, canvas.width, canvas.height);
 
for( var y = 0 ; y < imagedata.height; y++ ) {
  for( var x = 0 ; x < imagedata.width; x++ ) {
    // set the colour randomly
    setPixel(imagedata, x, y, Math.random() * 255, Math.random() * 255, Math.random() * 255, 255);
  }
}

While these are intentionally trite code snippets, pixel level access allows us to do a ton of cool stuff, including adding filters to images and manipulating html5 video.

Have fun!

]]>
http://creativejs.com/2011/12/day-3-play-with-your-pixels/feed/ 6