Jayd Saucedo

Blog

The Spiraling Fan Video
About a month ago I posted the following video to youtube:

This video now has over a million views. In response, I made the following program: located here

My original intention was to put some sort of animation on the ceiling fan, my first attempts failed so I tried a spiral and it seemed to work. I wanted to show my brother, who I had been discussing the physics of rapidly rotating objects with (rotational velocity and the like) so I made that video. Of course, I went and looked for other examples before attempting my own. Shortly after showing my friends and family the video I realized I had created something unique, and so posted it to Reddit. On Reddit it exploded, it got to the front page within an hour and from there took off. The initial popularity of the video was shocking, within 12 hours I had people emailing me with licensing agreements (which I did, so maybe one day I'll get a paycheck in the mail).

I attempted to steer the discussion on Reddit towards design and implementation suggestions. Most of the discussion was about how I said "cooooool" and my voice, which was also an interesting topic of conversation, but I wanted people to go and try it themselves and see what kind of improvements could be made. I quickly realized that the process of trial and error was too much for people. Nobody wanted to do stuff to their fan blades, reattach them, and then see that it didn't work right. So I decided to make a program to help people with this. It's something that I just quickly hacked together and it did get some attention on Reddit, but I think the fact that I ceased development for a while when school started made it so I couldn't release it in a timeframe when people still remembered my video.

Anyway, I wanted to talk about how I made a program to do just that. Eliminate the tedious process of trial and error. I made this program using javascript and the HTML5 canvas, this might not have been the best option as far as getting realistic results go, but I wanted the accessibility of being able to host it on a webpage and the convenience of doing client side calculations.

So my first task was to get the image actually spinning, which I did pretty easily using the CSS rotate function. Once I got it spinning I realized that it needed a blur effect. I accomplished this by duplicating the original image several times (n times actually) and then slightly rotating image consecutive image and making it semi-transparent. This got the exact effect that I want. Here is the base image I used:

You can see it in action here, but keep in mind, this is "alpha 1". Here's some of the code if you don't want to click the link:

//let's create our different images
  //have to do this i=blurs times
  for(i=0; i$lt;=blurs; i++){
      //create blur img object
      blur = $('');
      //set css, width, opacity, and position
      blur.css({width: 400, opacity : opacity, position: 'absolute', left: 7});
      //set img object to display fan
      blur.attr('src', src);
      //append img object to the document body for display
      $(document.body).append(blur);
      //put that img object in array
      //second variable in array is an individual tracker for degrees so we can have offsets
      imgs.push([blur, 0]);
    
    //set deg difference from previous blade, if there is one.
    imgs[i][1] = imgs.length>1 ? imgs[i-1][1]+blurDegDif : 0;
  }
  
  //this is called by the javascript timer
  function rotate(imgs) { 
    //loop through our images
    for(i=0; i<imgs.length; i++)
   {
      //rotate image using css
      $(imgs[i][0]).css({ transform: 'rotate(' + imgs[i][1] + 'deg)'});
      //this will be how much the image is rotated next loop
      imgs[i][1]=imgs[i][1]+turnDeg;
    }
  }

Now, the next thing I needed to do was allow the ability to create the base image yourself. This is when things got crazy and where I started stepping into uncharted territory. I don't know if I took the best approach, I kind of feel like it's hacked together. With that said I was only ever testing it in Chrome, so it might not work that great in Firefox or IE.

So, I thought long and hard about what I needed to do (and trust me this was still summer so I had TONS of time to think), and I decided that if I had five canvases that you could draw on individually. I could take those canvases, stick them onto a larger canvas, and rotate them around the center so it would simulate a ceiling fan. Sounds crazy right?

Well, you do all sorts of crazy stuff when it's the middle of August and school is looming on the horizon. So I buckled down and did it. It didn't even take that long, a few days of experimentation and I pretty much got this result.

This is what the whole post is about, so click here.

I sent the link with all the code, because that's what I'm talking about, but for a cleaner result click the html, javascript, and css buttons to maximize the output window.

Now, the code is pretty hideous. It's hideous because I hacked it together. It needs major refactoring. Some parts use Jquery, some parts should be using jquery but don't for some reason. This is the result of charting unexplored territory and pasting together snippets of code that I found. I understand it all, and I could definitely refactor it, but I'd rather move onto a new project.

That said, here's the part of the program that brings it all together. The copying and rotation of the individual canvases onto a bigger canvas.

// this function is recursive, it goes until the canvas array is empty
//@canvases an array of canvas IDs
function make_base(canvases)
{ 
   canvas = document.getElementById('viewport');
   context = canvas.getContext('2d');
    //we're done, start rotation!
   if(!canvases.length) {start_rotation($('#spinspin'), '400'); return;}
  //save context, then translate
   context.save();
   context.translate( canvas.width/2, canvas.height/2 );
   //rotate that shit, working our way from 2pi
   context.rotate(2*Math.PI/5*canvases.length);
  //remove last canvas from array and at same time pngify it
   imgcv = document.getElementById(canvases.pop());
   d=imgcv.toDataURL("image/png");
   img = new Image();
   img.src = d;
   context.translate( -img.width/2, -img.height-radius);
  //draw canvas onto rendering canvas
   context.drawImage(img, 0, 0);
  //restore context
   context.restore();
  //move onto next canvas!
   make_base(canvases);
}

Basically, I turned each small canvas into an image, rotated the large canvas, and then pasted the images of the smaller canvas onto the large canvas. Good stuff.

So, even though the project is kind of useless, it's stuff like this that makes programming and computer science fun. Being able to think about how a computer could improve a process, and then developing a unique way to go about it.