Friday, September 28, 2012

fullscreen iOS html5 apps and pretty clouds

Recently I remade an old art project of mine, "Virtual Sisyphus", as an html5 canvas work using Processing.js:

The viewer plays the role of Sisyphus, condemned to drag a rock up a mountain for eternity. Every time you try and fail to do so, the rock scores a point. (It's an existentialist joke, and like the PHB in the Dilbert cartoon series said, it has a certain sense of playfulness, if you look at it from the rock's point of view.)

I exhibited this as a work at my company's employee art show by using an iPad as a kind of virtual frame, you can see it on the left here:

I programmed the piece to have adjustable width and height, so it could fill its container, and scale itself to make good use of the space. Then, to make it as a nice fullscreen app (and make sure all the finger moving got interpreted as clicks and mouse drags in the Sisyphus world, rather than as scaling or resize) I did the following:

In the processing.js code setup, I started with:
size(document.documentElement.clientWidth, document.documentElement.clientHeight);

Then in the html file I had the following meta tags:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name = "format-detection" content = "telephone=no"/>
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" />
<meta name="apple-mobile-web-app-capable" content="yes" />

Just to be sure, I set padding and margin to 0px for both the body and the canvas tag processing.js uses.

(The apple-specific tag is kind of neat, adding that meant I could send the webpage to the homescreen from Safari, and then when I launch it from the home screen, it just has a minimal black bar at top, and skips the usual Safari address bar and what not.)

I ended up being pleased with how nicely my cloud algorithm came out, using stretched ovals to get  a nicely organic/cartoony feel. Here was my Cloud class:

class Cloud {
  float x,y;
 ArrayList<Fluff> fluffs; 
      y = random(0,height * 3 / 8);
      fluffs = new ArrayList();
      int count = round(random(2,8));
      for(int i = 0; i < count; i++){
      fluffs.add(new Fluff());
      x = width - getLeftmost();
   void move(){
      x -= random(.1,.5);
   float getLeftmost(){
       float lowest = 9999;
     for(Fluff f : fluffs){
       float side = f.getLeftmost();
       if(side < lowest) lowest = side;
     return lowest;
   float getRightmost(){
       float highest = -9999;
     for(Fluff f : fluffs){
       float side = f.getRightmost();
       if(side > highest) highest = side;
     return highest;
   void draw(){
   for(Fluff f : fluffs){

class Fluff{
  float w,h,x,y;   
          w = random(width/9,width /3);
     h = random(height/24, height / 8);  
     x = random(-w/3,w/3);
     y = random(-h/3,h/3);
   float getLeftmost(){
     return x-w/2;
   float getRightmost(){
     return x+w/2;
  void draw(){
   w += random(-.1,.1);  
   h += random(-.1,.1);  
   x += random(-.1,.1);  
   y += random(-.1,.1);  


(Much  of the code was just getting the maximum left and right extents, so I would know when it was safe to remove a cloud from the world, and making sure it appeared off the right side of the screen.)

My main cloud generating loop was:

Cloud cloudToKill = null;

  for(Cloud c : clouds){
    if(c.x + c.getRightmost() < 0){
     cloudToKill = c; //only one but it doesn't matter
  if(cloudToKill != null) clouds.remove(cloudToKill);
  if(clouds.size() < 5){
     if(random(250) < 1){
        clouds.add(new Cloud());
It could only remove one cloud per frame, but that wasn't such a problem. And it maxed out at 5 clouds at a time.

So, that was it! Let me know if you ever manage to drag that rock to the top!

No comments:

Post a Comment