2hr HTML5 Tetris

I’ve taken an interest in limited time game competitions recently and figured I’d better practice up. So as an exercise I tried to make Tetris in 1hr in Pixie. Except for the blocks getting stuck in the walls and that one thing about the lines, it was pretty good for an hour.

I decided that I got pretty close to a “working” game and forked the app to do the 2hr version. I learned that some beveled block graphics really make a difference! As well as actually removing completed lines. There is one bug where sometimes blocks overlap or won’t move into what appears to be empty space, as well as the “choice” of rotation points, but hey, times up.

Using Google Font API to Render Inconsolata in HTML5 Canvas

In Contrasaurus we wanted some cooler fonts to add some extra ambiance to the game. I knew that adding a custom font from Google Font API was easy for classic HTML elements, but would it be easy for HTML5 Canvas elements? 5 minutes later I knew the answer… Yes!

// In the <head> tag
<link href='http://fonts.googleapis.com/css?family=Inconsolata' rel='stylesheet' type='text/css'>
 
// In your js code
context.font = "bold 1.2em 'Inconsolata'";

New Pixie Color Palette

On Pixie we recently redesigned our color palette.

It’s important to choose a good default color palette for your application. For most people the color palette is one of their first impressions of your product, and the palette will largely determine the kinds of things they can make. In addition less than half the people who interact with your product for the first time will even use a custom color, or a different tool. That makes the default choice doubly important.

Let’s say you were stranded on a desert island and only got to take 10 crayons, what would you take? Answering that question is very similar to answering the default palette question.

Since prehistoric times people have enjoyed drawing what they see in their environment. I have a friend, and he wears a blue shirt, so I need the color Shirt Blue. Sometimes he eats apples; I’d better also have Apple Red. The apple came from an apple tree, good thing there’s Leaf Green, and Tree Brown.

Modularity and context are also important. Each of these colors shouldn’t only be a uni-tasker. Shirt Blue can double as Lake Blue when drawn on the ground. Hair Blonde or Hay-bale Yellow? Same color, but it depends on the context. Remember, you’re trapped on an island and need to make these colors count.

The classic defaults are pretty weak. If they had crayola names they’d be something like Maximum Red, Maximum Green, Maximum Blue, Horrendo Cyan, Staring into the Sun Yellow and Good God Man Make it Stop Magenta.

Maybe your friend eats GMO Apples (for maximum redness), as well as wearing outrageous clothing. Mine usually don’t, that’s why I developed the Best Friend’s Apple / Desert Island default color palette.

PrettyCoolGuy.info Launched

I think that the tired old “pretty cool guy” meme is a pretty cool guy. eh keeps going years later and doesn’t afraid of anything.

That’s why I launched prettycoolguy.info. A place to collect all the pretty coolest guys in the world. It’s a site where you can “ask questions” like: “I think Bob Saget is a pretty cool guy” and then vote on answers like: “ehs the father of the olsen twins and doesnt afraid of anything.”

So please go check it out. And add to it. This will be a valuable wealth of internet information soon.

Real testimonial:

Daniel:
if you or someone you know is into “pretty cool guy” internet memes, then this site is for you: prettycoolguy.info

Kyle:
I dont know what a meme is

Daniel:
it’s like a joke that runs rampant on the internet

me: prettycoolguy.info

Jeff: this isn’t a .biz address

I’m uninterested

me: it’s got all the info about the pretty coolest guys

or it will one day

this will be an incredible internet resource

Jeff: it definitely does

dude

why is “Pimp” cut off in your profiel pic

me: for the G rating

and to leave something to the imagination

Jeff: did you make this website?

me: a gentleman never asks and a lady never tells

me: prettycoolguy.info
are you familiar with pretty cool guy?

David: I am not.

me: it’s an internet meme
where someone says: I think Halo is a pretty cool guy. eh kills lots of aleins and doesnt afraid of anything.
so I made a site to collect all of those

David: I noticed when I went to the site.

me: the secret is the use of metonymy
Where ‘Halo’ stands in for ‘Master Chief’

David: I think it would be metonymy if “Master Chief” stood in for “Halo”. I’m not sure what to call the whole standing in for the part though.
I did enjoy learning about Jimmy Carter’s rabbit attack though.

Simple Tutorial to Make a Chrome Extension that uses jQuery UI

Google Chrome has had extensions for a while now, but because the Linux client is a little farther behind I never got farther than the simple hello world tutorial. Today, however, I am pleased to announce that Chrome extensions are totally boss, and it is extremely easy to get a jQuery UI skinned template app going in 15 minutes, just by following three easy steps.

Step 1 – Brushing up on the Hello World Extension Tutorial

Follow the Getting Started (Hello World) tutorial. The tutorial is very well written and will help you get your bearings about what extensions can do and the minimum you need to get started. A key part is the manifest.json

{
  "name": "My First Extension",
  "version": "1.0",
  "description": "The first extension that I made.",
  "browser_action": {
    "default_icon": "icon.png"
  },
  "permissions": [
    "http://api.flickr.com/"
  ]
}

The name, version, and description fields are all self explanatory. The browser action one is interesting. It means that your extension will add a button to the browser (right after the address bar) with the specified icon. So far as I can tell the only thing that the button can do now is display a popup, though this popup can communicate with other parts of your extension. Permissions are also important, they specify what domains you can access via xmlhttprequests.

At this point you should have a working hello world tutorial, if not please continue to follow the rest of the directions on the full tutorial page, I’ll wait.

Step 2 jQuerying it up

After you finish the tutorial you may come to feel that raw JS is pretty harsh stuff and it would be great to get a little jQuery action in there. No need to fear, just add this to your “popup.html” file:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>

You don’t even need to add a file anywhere in your extension. Neat! Now you can rewrite the part of the tutorial that connects to the Flickr API like so:

$.get("http://api.flickr.com/services/rest/", {
    method: "flickr.photos.search",
    api_key: "90485e931f687a9b9c2a66bf58a3861a",
    text: "hello world",
    safe_search: 1,
    content_type: 1,
    sort: "relevance",
    per_page: 20
  }, function(data, status, request) {
    var photos = request.responseXML.getElementsByTagName("photo");
 
    for (var i = 0, photo; photo = photos[i]; i++) {
      var img = document.createElement("image");
      img.src = constructImageURL(photo);
      document.body.appendChild(img);
    }
  }
);

Love that fresh jQuery scent. Note that I left the constructImageURL function unchanged, so you’ll still need it if you want the extension to continue working.

Step 3 Adding jQuery UI (It’s Easy!)

This is the easy part. Go to the jQuery UI custom build your own download. Keep all the UI stuff checked and choose your favorite theme, you’ll have plenty of time later to choose exactly what you want or need, but for now just focus on seeing how easy it is to integrate. Now download the zip and extract in into your extensions root directory.

You can go to chrome-extension://extensionId/index.html and see all the magic of the jQuery UI demo, but working from inside a Chrome Extension. Of course extensionId is whatever that giant random string of characters that Chrome assigned to your extension was, something like opnnhifacfpohionnikhlecfgheooenk. (Learn more here)

Congratulations!

Although getting a simple skeleton/hello world extension up only takes a short amount of time, learning about all the possibilities and actually making an extension that does great things will take much longer. I hope that with this tutorial that starting will be very easy and nothing will stand in the way of your dreams.

Peace!

Ruby Quiz Summary Cry For Help

Salutations! As you know I’m maintaining the latest incarnation of Ruby Quiz over at rubyquiz.strd6.com. Also as you know I’m furiously behind on the summaries. So, I’ve turned to you, my noble reader, to see if you would be interested in this amazing opportunity: write a guest summary of one of the recent quizzes.

The task is to write a brief summary showcasing some of the solutions. I can hook you up with all the solutions and link you to the thread as well as some examples of great summaries from the good old days.

So what do you say? I’ll bake you cookies… or cook you up an amazing omlette from my amazing omlette bar.

Also it is a great learning experience.

Add your inquiries in the comments.

Pixie: A jQuery Plugin port of Pixie

That’s right, my idea of a great Saturday afternoon is porting my own code! I wanted to use Pixie in my new Dog Seeder game. It seemed easy enough.

At first I was thinking, “I shouldn’t have to rewrite this”. But then it actually turned out to be unusable. That’s right completely unusable. Well… un-reusable. The first problem was that the code tightly coupled with the specific page html. Referencing certain divs with certain ids. If I wanted to embed it into a new page I’d need to copy all that HTML over. Related to those specific divs the editor was all over the global namespace. There was one `canvas` object and that’s THE canvas, and THE canvas is div#canvas. Ouch…

This was also problematic for extending functionality and adding tools. Each tool was hardcoded into the page. The tools were in div#toolbox and had hardcoded onclick events to call things like `canvas.setTool(pencil)`. More globals… So the mission of extracting that to be useful in another page was too great. It was easier to just rewrite it all with all these good practices in mind, embedability, and extensibility. The long and short of it is that you, gentle reader, really lucked out because now Pixie is way, way better.

Let’s take a look at what’s needed to create a Pixie pixel editor on a new page:

$('#pixie').pixie();

And #pixie is just an empty div! Ok, you do need to include a couple javascript files and some image directories if you want it to work or look good, but nothing special in the HTML itself.

But what if I want to make a new save button that saves the image into Dog Seeder instead locally. I’d need to dig deep into the internals in the old Pixie, but not anymore!

    $("#pixie").pixie({
      initializer: function(canvas) {
        canvas.addAction({
          name: "Save to Creature",
          perform: function(canvas) {
            images[$('#img_path').val()] = canvas.toDataURL();
            $.each(gameObjects, function() {
              $(this).trigger('changed');
            });
          }
        });
      }
    });

Wow, that sure was easy. Maybe I can challenge myself by adding a new tool instead:

          $("#pixie").pixie({
            initializer: function(canvas) {
              var partyPaint = function() {
                this.color(this.canvas.color(rand(2) === 0));
 
                $.each(this.canvas.getNeighbors(this.x, this.y), function(i, neighbor) {
                  if(neighbor) {
                    neighbor.color(neighbor.canvas.color(rand(2) === 0));
                  }
                });
              }
 
              canvas.addTool({
                name: "Party Brush",
                hotkeys: ['Y'],
                mousedown: partyPaint,
                mouseenter: partyPaint
              });
            }
          });

That was pretty easy too. Just to save everyone the shame of asking: “Yes, it’s all easy. Yes you can add as many tools and actions as you want. What, icons? Yes, that’s easy too.” Don’t worry, I’ll post some all the examples I have at the end of the post.

And don’t worry about having to muck with the internals, all the standard tools are written using the same API, so anything the pencil tool or clone stamp tool does you can do too. And a lot more. The opportunities are endless.

Speaking of the API, although I feel that it is pretty good, there may be room for improvement. This is a new release and there may be changes in the future. What I’m trying to say is don’t be afraid to suggest improvements and also don’t be surprised if the API changes in a future version.

So what are some of the amazing possibilities for tool extensions? Let’s take a look at what exists so far:

  var tools = {
    pencil: {
      name: "Pencil",
      hotkeys: ['P'],
      icon: imageDir + "pencil.png",
      cursor: "url(" + imageDir + "pencil.png) 4 14, default",
      mousedown: function(e, color) {
        this.color(color);
      },
      mouseenter: function(e, color) {
        this.color(color);
      }
    },
 
    brush: {
      name: "Brush",
      hotkeys: ['B'],
      icon: imageDir + "paintbrush.png",
      cursor: "url(" + imageDir + "paintbrush.png) 4 14, default",
      mousedown: function(e, color) {
        this.color(color);
 
        $.each(this.canvas.getNeighbors(this.x, this.y), function(i, neighbor) {
          if(neighbor) {
            neighbor.color(color);
          }
        });
      },
      mouseenter: function(e, color) {
        this.color(color);
 
        $.each(this.canvas.getNeighbors(this.x, this.y), function(i, neighbor) {
          if(neighbor) {
            neighbor.color(color);
          }
        });
      }
    },
 
    dropper: {
      name: "Dropper",
      hotkeys: ['I'],
      icon: imageDir + "dropper.png",
      cursor: "url(" + imageDir + "dropper.png) 13 13, default",
      mousedown: function() {
        this.canvas.color(this.color());
        this.canvas.setTool(tools.pencil);
      }
    },
 
    eraser: {
      name: "Eraser",
      hotkeys: ['E'],
      icon: imageDir + "eraser.png",
      cursor: "url(" + imageDir + "eraser.png) 4 11, default",
      mousedown: function() {
        this.color(null);
      },
      mouseenter: function() {
        this.color(null);
      }
    },
 
    fill: {
      name: "Fill",
      hotkeys: ['F'],
      icon: imageDir + "fill.png",
      cursor: "url(" + imageDir + "fill.png) 12 13, default",
      mousedown: function(e, newColor, pixel) {
        // Store original pixel's color here
        var originalColor = this.color();
 
        // Return if original color is same as currentColor
        if(newColor === originalColor) {
          return;
        }
 
        var q = new Array();
        pixel.color(newColor);
        q.push(pixel);
 
        while(q.length > 0) {
          pixel = q.pop();
 
          // Add neighboring pixels to the queue
          var neighbors = this.canvas.getNeighbors(pixel.x, pixel.y);
 
          $.each(neighbors, function(index, neighbor) {
            if(neighbor && neighbor.css("backgroundColor") === originalColor) {
              neighbor.color(newColor);
              q.push(neighbor);
            }
          });
        }
      }
    }
  };

Most of these are pretty simple. Also notice how easy it is to set a hotkey and icon/cursor. The mousedown and mouseenter are the standard tool workhorse methods. They are called with `this` bound to the pixel that the event occurred in. The pixel object is an extended jQuery object, so methods like this.css(someprop, somevalue) also work. The extended part provides utilities like `x`, `y` and `canvas` properties, as well as a color() getter/setter shortcut. Take a look and if it’s not immediately obvious leave a comment so that I can fix my failure and make it clear.

We can also rock a closure to add advanced tools like a clone tool:

  var CloneTool = function() {
    var cloneX, cloneY, targetX, targetY;
 
    return {
      name: "Clone",
      hotkeys: ['C'],
      icon: imageDir + "clone.png",
      cursor: "url("+ imageDir +"clone.png) 0 0, default",
      mousedown: function(e) {
        if(e.shiftKey) {
          cloneX = this.x;
          cloneY = this.y;
        } else {
          targetX = this.x;
          targetY = this.y;
          var selection = this.canvas.getPixel(cloneX, cloneY);
 
          if(selection) {
            this.color(selection.color());
          }
        }
      },
      mouseenter: function(e) {
        var deltaX = this.x - targetX;
        var deltaY = this.y - targetY;
        var selection = this.canvas.getPixel(cloneX + deltaX, cloneY + deltaY);
 
        if(selection) {
          this.color(selection.color());
        }
      }
    };
  };
 
  tools.clone = CloneTool();

The closure keeps track of the state of the tool with shared variables. This allows the source position to be set when shift is held and the mouse is clicked. Then remembered when the tool is used again at a distant location. Ideally we would also set some sort of marker on the source pixel so we can assist the user to see where we are cloning from. This can be done with setting some CSS properties on the pixels, but I will leave that for another day.

Let’s wrap this up with a heads up: there is going to be a contest to create the best tool for Pixie coming up, so it’s never too early to start preparing. The winning tools may even appear in the next version.

So until next time, stay pixelated.

Source on github.

jqcolor: A jQuery Plugin port of jscolor

That’s right, my idea of a great Sunday afternoon is porting someone else’s code!

At first I was thinking, “I should email this guy and tell him to make a jQuery plugin”. But then I thought, “I’m the one who needs the jQuery plugin…” so I made it. Maybe now I’ll email him and say “I made a jQuery plugin for your color picker”.

Usage:

jQuery(‘input.color’).colorPicker();

This port is from the 1.0.9 version. jscolor was completely rewritten in 1.1.0 and looked like it had some regressions though it is at 1.2.3 now. The newer version is twice as big, still not a jQuery plugin, and also still missing hundreds of semi-colons, so I decided to stick to what I know and work on the smaller version.

So now it is a clunky jQuery plugin. There are still several spots where the syntax could be improved to take advantage of jQuery, but since there are no tests, and I don’t have a bunch of different browers to QA on, I decided to leave it alone as much as possible.

Source on github.